Skip to content
Merged

0.46.1 #7968

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions homeassistant/components/cover/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
from homeassistant.components.cover import (
CoverDevice, ATTR_TILT_POSITION, SUPPORT_OPEN_TILT,
SUPPORT_CLOSE_TILT, SUPPORT_STOP_TILT, SUPPORT_SET_TILT_POSITION,
SUPPORT_OPEN, SUPPORT_CLOSE, SUPPORT_STOP, SUPPORT_SET_POSITION)
SUPPORT_OPEN, SUPPORT_CLOSE, SUPPORT_STOP, SUPPORT_SET_POSITION,
ATTR_POSITION)
from homeassistant.exceptions import TemplateError
from homeassistant.const import (
CONF_NAME, CONF_VALUE_TEMPLATE, CONF_OPTIMISTIC, STATE_OPEN,
STATE_CLOSED, STATE_UNKNOWN)
Expand All @@ -29,6 +31,8 @@

CONF_TILT_COMMAND_TOPIC = 'tilt_command_topic'
CONF_TILT_STATUS_TOPIC = 'tilt_status_topic'
CONF_POSITION_TOPIC = 'set_position_topic'
CONF_SET_POSITION_TEMPLATE = 'set_position_template'

CONF_PAYLOAD_OPEN = 'payload_open'
CONF_PAYLOAD_CLOSE = 'payload_close'
Expand All @@ -55,10 +59,17 @@
DEFAULT_TILT_OPTIMISTIC = False
DEFAULT_TILT_INVERT_STATE = False

OPEN_CLOSE_FEATURES = (SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP)
TILT_FEATURES = (SUPPORT_OPEN_TILT | SUPPORT_CLOSE_TILT | SUPPORT_STOP_TILT |
SUPPORT_SET_TILT_POSITION)

PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({
PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_COMMAND_TOPIC, default=None): valid_publish_topic,
vol.Optional(CONF_POSITION_TOPIC, default=None): valid_publish_topic,
vol.Optional(CONF_SET_POSITION_TEMPLATE, default=None): cv.template,
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PAYLOAD_OPEN, default=DEFAULT_PAYLOAD_OPEN): cv.string,
vol.Optional(CONF_PAYLOAD_CLOSE, default=DEFAULT_PAYLOAD_CLOSE): cv.string,
Expand Down Expand Up @@ -87,6 +98,9 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
value_template = config.get(CONF_VALUE_TEMPLATE)
if value_template is not None:
value_template.hass = hass
set_position_template = config.get(CONF_SET_POSITION_TEMPLATE)
if set_position_template is not None:
set_position_template.hass = hass

async_add_devices([MqttCover(
config.get(CONF_NAME),
Expand All @@ -109,6 +123,8 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
config.get(CONF_TILT_MAX),
config.get(CONF_TILT_STATE_OPTIMISTIC),
config.get(CONF_TILT_INVERT_STATE),
config.get(CONF_POSITION_TOPIC),
set_position_template,
)])


Expand All @@ -120,7 +136,7 @@ def __init__(self, name, state_topic, command_topic, tilt_command_topic,
payload_open, payload_close, payload_stop,
optimistic, value_template, tilt_open_position,
tilt_closed_position, tilt_min, tilt_max, tilt_optimistic,
tilt_invert):
tilt_invert, position_topic, set_position_template):
"""Initialize the cover."""
self._position = None
self._state = None
Expand All @@ -145,6 +161,8 @@ def __init__(self, name, state_topic, command_topic, tilt_command_topic,
self._tilt_max = tilt_max
self._tilt_optimistic = tilt_optimistic
self._tilt_invert = tilt_invert
self._position_topic = position_topic
self._set_position_template = set_position_template

@asyncio.coroutine
def async_added_to_hass(self):
Expand Down Expand Up @@ -233,9 +251,11 @@ def current_cover_tilt_position(self):
@property
def supported_features(self):
"""Flag supported features."""
supported_features = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP
supported_features = 0
if self._command_topic is not None:
supported_features = OPEN_CLOSE_FEATURES

if self.current_cover_position is not None:
if self._position_topic is not None:
supported_features |= SUPPORT_SET_POSITION

if self._tilt_command_topic is not None:
Expand Down Expand Up @@ -315,6 +335,22 @@ def async_set_cover_tilt_position(self, **kwargs):
mqtt.async_publish(self.hass, self._tilt_command_topic,
level, self._qos, self._retain)

@asyncio.coroutine
def async_set_cover_position(self, **kwargs):
"""Move the cover to a specific position."""
if ATTR_POSITION in kwargs:
position = kwargs[ATTR_POSITION]
if self._set_position_template is not None:
try:
position = self._set_position_template.async_render(
**kwargs)
except TemplateError as ex:
_LOGGER.error(ex)
self._state = None

mqtt.async_publish(self.hass, self._position_topic,
position, self._qos, self._retain)

def find_percentage_in_range(self, position):
"""Find the 0-100% value within the specified range."""
# the range of motion as defined by the min max values
Expand Down
15 changes: 8 additions & 7 deletions homeassistant/components/media_player/openhome.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from homeassistant.const import (
STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_OFF)

REQUIREMENTS = ['openhomedevice==0.4.0']
REQUIREMENTS = ['openhomedevice==0.4.2']

SUPPORT_OPENHOME = SUPPORT_SELECT_SOURCE | \
SUPPORT_VOLUME_STEP | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET | \
Expand Down Expand Up @@ -60,7 +60,6 @@ def __init__(self, hass, device):
self._track_information = {}
self._in_standby = None
self._transport_state = None
self._track_information = None
self._volume_level = None
self._volume_muted = None
self._supported_features = SUPPORT_OPENHOME
Expand Down Expand Up @@ -173,27 +172,29 @@ def source_list(self):
@property
def media_image_url(self):
"""Image url of current playing media."""
return self._track_information["albumArtwork"]
return self._track_information.get('albumArtwork')

@property
def media_artist(self):
"""Artist of current playing media, music track only."""
return self._track_information["artist"][0]
artists = self._track_information.get('artist')
if artists:
return artists[0]

@property
def media_album_name(self):
"""Album name of current playing media, music track only."""
return self._track_information["albumTitle"]
return self._track_information.get('albumTitle')

@property
def media_title(self):
"""Title of current playing media."""
return self._track_information["title"]
return self._track_information.get('title')

@property
def source(self):
"""Name of the current input source."""
return self._source["name"]
return self._source.get('name')

@property
def volume_level(self):
Expand Down
6 changes: 2 additions & 4 deletions homeassistant/components/media_player/roku.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,7 @@ def name(self):
"""Return the name of the device."""
if self.device_info.userdevicename:
return self.device_info.userdevicename
else:
return "roku_" + self.roku.device_info.sernum
return "Roku {}".format(self.device_info.sernum)

@property
def state(self):
Expand Down Expand Up @@ -158,8 +157,7 @@ def media_content_type(self):
return None
elif self.current_app.name == "Roku":
return None
else:
return MEDIA_TYPE_VIDEO
return MEDIA_TYPE_VIDEO

@property
def media_image_url(self):
Expand Down
7 changes: 3 additions & 4 deletions homeassistant/components/sensor/dsmr.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@

_LOGGER = logging.getLogger(__name__)

REQUIREMENTS = ['dsmr_parser==0.9']

REQUIREMENTS = ['dsmr_parser==0.8']

CONF_DSMR_VERSION = 'dsmr_version'
CONF_RECONNECT_INTERVAL = 'reconnect_interval'
Expand All @@ -61,7 +60,7 @@
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.string,
vol.Optional(CONF_HOST, default=None): cv.string,
vol.Optional(CONF_DSMR_VERSION, default=DEFAULT_DSMR_VERSION): vol.All(
cv.string, vol.In(['5', '4', '2.2'])),
cv.string, vol.In(['4', '2.2'])),
vol.Optional(CONF_RECONNECT_INTERVAL, default=30): int,
})

Expand Down Expand Up @@ -94,7 +93,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
devices = [DSMREntity(name, obis) for name, obis in obis_mapping]

# Protocol version specific obis
if dsmr_version in ('4', '5'):
if dsmr_version == '4':
gas_obis = obis_ref.HOURLY_GAS_METER_READING
else:
gas_obis = obis_ref.GAS_METER_READING
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/sensor/metoffice.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def device_state_attributes(self):
attr['Sensor Id'] = self._condition
attr['Site Id'] = self.site.id
attr['Site Name'] = self.site.name
attr['Last Update'] = self.data.lastupdate
attr['Last Update'] = self.data.data.date
attr[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION
return attr

Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/sensor/wunderground.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,16 +574,16 @@ def _get_attributes(rest):
"Precipitation Intensity in 4 Days", 3, 'qpf_allday', 'in',
LENGTH_INCHES, "mdi:umbrella"),
'precip_1d': WUDailySimpleForecastSensorConfig(
"Percipitation Probability Today", 0, "pop", None, "%",
"Precipitation Probability Today", 0, "pop", None, "%",
"mdi:umbrella"),
'precip_2d': WUDailySimpleForecastSensorConfig(
"Percipitation Probability Tomorrow", 1, "pop", None, "%",
"Precipitation Probability Tomorrow", 1, "pop", None, "%",
"mdi:umbrella"),
'precip_3d': WUDailySimpleForecastSensorConfig(
"Percipitation Probability in 3 Days", 2, "pop", None, "%",
"Precipitation Probability in 3 Days", 2, "pop", None, "%",
"mdi:umbrella"),
'precip_4d': WUDailySimpleForecastSensorConfig(
"Percipitation Probability in 4 Days", 3, "pop", None, "%",
"Precipitation Probability in 4 Days", 3, "pop", None, "%",
"mdi:umbrella"),
}

Expand Down
38 changes: 33 additions & 5 deletions homeassistant/components/zwave/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

from . import api
from . import const
from .const import DOMAIN, DATA_DEVICES, DATA_NETWORK
from .const import DOMAIN, DATA_DEVICES, DATA_NETWORK, DATA_ENTITY_VALUES
from .node_entity import ZWaveBaseEntity, ZWaveNodeEntity
from . import workaround
from .discovery_schemas import DISCOVERY_SCHEMAS
Expand Down Expand Up @@ -74,12 +74,20 @@
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
vol.Required(const.ATTR_NAME): cv.string,
})

RENAME_VALUE_SCHEMA = vol.Schema({
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
vol.Required(const.ATTR_VALUE_ID): vol.Coerce(int),
vol.Required(const.ATTR_NAME): cv.string,
})

SET_CONFIG_PARAMETER_SCHEMA = vol.Schema({
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
vol.Required(const.ATTR_CONFIG_VALUE): vol.Any(vol.Coerce(int), cv.string),
vol.Optional(const.ATTR_CONFIG_SIZE, default=2): vol.Coerce(int)
})

PRINT_CONFIG_PARAMETER_SCHEMA = vol.Schema({
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
Expand Down Expand Up @@ -258,6 +266,7 @@ def setup(hass, config):

network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False)
hass.data[DATA_DEVICES] = {}
hass.data[DATA_ENTITY_VALUES] = []

if use_debug: # pragma: no cover
def log_all(signal, value=None):
Expand All @@ -276,12 +285,10 @@ def log_all(signal, value=None):

dispatcher.connect(log_all, weak=False)

discovered_values = []

def value_added(node, value):
"""Handle new added value to a node on the network."""
# Check if this value should be tracked by an existing entity
for values in discovered_values:
for values in hass.data[DATA_ENTITY_VALUES]:
values.check_value(value)

for schema in DISCOVERY_SCHEMAS:
Expand All @@ -294,7 +301,11 @@ def value_added(node, value):

values = ZWaveDeviceEntityValues(
hass, schema, value, config, device_config)
discovered_values.append(values)

# We create a new list and update the reference here so that
# the list can be safely iterated over in the main thread
new_values = hass.data[DATA_ENTITY_VALUES] + [values]
hass.data[DATA_ENTITY_VALUES] = new_values

component = EntityComponent(_LOGGER, DOMAIN, hass)

Expand Down Expand Up @@ -401,6 +412,18 @@ def rename_node(service):
_LOGGER.info(
"Renamed Z-Wave node %d to %s", node_id, name)

def rename_value(service):
"""Rename a node value."""
node_id = service.data.get(const.ATTR_NODE_ID)
value_id = service.data.get(const.ATTR_VALUE_ID)
node = network.nodes[node_id]
value = node.values[value_id]
name = service.data.get(const.ATTR_NAME)
value.label = name
_LOGGER.info(
"Renamed Z-Wave value (Node %d Value %d) to %s",
node_id, value_id, name)

def remove_failed_node(service):
"""Remove failed node."""
node_id = service.data.get(const.ATTR_NODE_ID)
Expand Down Expand Up @@ -585,6 +608,10 @@ def start_zwave(_service_or_event):
hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node,
descriptions[const.SERVICE_RENAME_NODE],
schema=RENAME_NODE_SCHEMA)
hass.services.register(DOMAIN, const.SERVICE_RENAME_VALUE,
rename_value,
descriptions[const.SERVICE_RENAME_VALUE],
schema=RENAME_VALUE_SCHEMA)
hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER,
set_config_parameter,
descriptions[
Expand Down Expand Up @@ -644,6 +671,7 @@ def start_zwave(_service_or_event):

if 'frontend' in hass.config.components:
register_built_in_panel(hass, 'zwave', 'Z-Wave', 'mdi:nfc')
hass.http.register_view(api.ZWaveNodeValueView)
hass.http.register_view(api.ZWaveNodeGroupView)
hass.http.register_view(api.ZWaveNodeConfigView)
hass.http.register_view(api.ZWaveUserCodeView)
Expand Down
26 changes: 26 additions & 0 deletions homeassistant/components/zwave/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,32 @@
_LOGGER = logging.getLogger(__name__)


class ZWaveNodeValueView(HomeAssistantView):
"""View to return the node values."""

url = r"/api/zwave/values/{node_id:\d+}"
name = "api:zwave:values"

@ha.callback
def get(self, request, node_id):
"""Retrieve groups of node."""
nodeid = int(node_id)
hass = request.app['hass']
values_list = hass.data[const.DATA_ENTITY_VALUES]

values_data = {}
# Return a list of values for this node that are used as a
# primary value for an entity
for entity_values in values_list:
if entity_values.primary.node.node_id != nodeid:
continue

values_data[entity_values.primary.value_id] = {
'label': entity_values.primary.label,
}
return self.json(values_data)


class ZWaveNodeGroupView(HomeAssistantView):
"""View to return the nodes group configuration."""

Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/zwave/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

DATA_DEVICES = 'zwave_devices'
DATA_NETWORK = 'zwave_network'
DATA_ENTITY_VALUES = 'zwave_entity_values'

SERVICE_CHANGE_ASSOCIATION = "change_association"
SERVICE_ADD_NODE = "add_node"
Expand All @@ -38,6 +39,7 @@
SERVICE_STOP_NETWORK = "stop_network"
SERVICE_START_NETWORK = "start_network"
SERVICE_RENAME_NODE = "rename_node"
SERVICE_RENAME_VALUE = "rename_value"
SERVICE_REFRESH_ENTITY = "refresh_entity"
SERVICE_REFRESH_NODE = "refresh_node"
SERVICE_RESET_NODE_METERS = "reset_node_meters"
Expand Down
Loading