mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
commit
c2b7c93375
@ -14,7 +14,9 @@ import homeassistant.components.mqtt as mqtt
|
|||||||
from homeassistant.components.cover import (
|
from homeassistant.components.cover import (
|
||||||
CoverDevice, ATTR_TILT_POSITION, SUPPORT_OPEN_TILT,
|
CoverDevice, ATTR_TILT_POSITION, SUPPORT_OPEN_TILT,
|
||||||
SUPPORT_CLOSE_TILT, SUPPORT_STOP_TILT, SUPPORT_SET_TILT_POSITION,
|
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 (
|
from homeassistant.const import (
|
||||||
CONF_NAME, CONF_VALUE_TEMPLATE, CONF_OPTIMISTIC, STATE_OPEN,
|
CONF_NAME, CONF_VALUE_TEMPLATE, CONF_OPTIMISTIC, STATE_OPEN,
|
||||||
STATE_CLOSED, STATE_UNKNOWN)
|
STATE_CLOSED, STATE_UNKNOWN)
|
||||||
@ -29,6 +31,8 @@ DEPENDENCIES = ['mqtt']
|
|||||||
|
|
||||||
CONF_TILT_COMMAND_TOPIC = 'tilt_command_topic'
|
CONF_TILT_COMMAND_TOPIC = 'tilt_command_topic'
|
||||||
CONF_TILT_STATUS_TOPIC = 'tilt_status_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_OPEN = 'payload_open'
|
||||||
CONF_PAYLOAD_CLOSE = 'payload_close'
|
CONF_PAYLOAD_CLOSE = 'payload_close'
|
||||||
@ -55,10 +59,17 @@ DEFAULT_TILT_MAX = 100
|
|||||||
DEFAULT_TILT_OPTIMISTIC = False
|
DEFAULT_TILT_OPTIMISTIC = False
|
||||||
DEFAULT_TILT_INVERT_STATE = 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 |
|
TILT_FEATURES = (SUPPORT_OPEN_TILT | SUPPORT_CLOSE_TILT | SUPPORT_STOP_TILT |
|
||||||
SUPPORT_SET_TILT_POSITION)
|
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_NAME, default=DEFAULT_NAME): cv.string,
|
||||||
vol.Optional(CONF_PAYLOAD_OPEN, default=DEFAULT_PAYLOAD_OPEN): cv.string,
|
vol.Optional(CONF_PAYLOAD_OPEN, default=DEFAULT_PAYLOAD_OPEN): cv.string,
|
||||||
vol.Optional(CONF_PAYLOAD_CLOSE, default=DEFAULT_PAYLOAD_CLOSE): cv.string,
|
vol.Optional(CONF_PAYLOAD_CLOSE, default=DEFAULT_PAYLOAD_CLOSE): cv.string,
|
||||||
@ -87,6 +98,9 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||||||
value_template = config.get(CONF_VALUE_TEMPLATE)
|
value_template = config.get(CONF_VALUE_TEMPLATE)
|
||||||
if value_template is not None:
|
if value_template is not None:
|
||||||
value_template.hass = hass
|
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(
|
async_add_devices([MqttCover(
|
||||||
config.get(CONF_NAME),
|
config.get(CONF_NAME),
|
||||||
@ -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_MAX),
|
||||||
config.get(CONF_TILT_STATE_OPTIMISTIC),
|
config.get(CONF_TILT_STATE_OPTIMISTIC),
|
||||||
config.get(CONF_TILT_INVERT_STATE),
|
config.get(CONF_TILT_INVERT_STATE),
|
||||||
|
config.get(CONF_POSITION_TOPIC),
|
||||||
|
set_position_template,
|
||||||
)])
|
)])
|
||||||
|
|
||||||
|
|
||||||
@ -120,7 +136,7 @@ class MqttCover(CoverDevice):
|
|||||||
payload_open, payload_close, payload_stop,
|
payload_open, payload_close, payload_stop,
|
||||||
optimistic, value_template, tilt_open_position,
|
optimistic, value_template, tilt_open_position,
|
||||||
tilt_closed_position, tilt_min, tilt_max, tilt_optimistic,
|
tilt_closed_position, tilt_min, tilt_max, tilt_optimistic,
|
||||||
tilt_invert):
|
tilt_invert, position_topic, set_position_template):
|
||||||
"""Initialize the cover."""
|
"""Initialize the cover."""
|
||||||
self._position = None
|
self._position = None
|
||||||
self._state = None
|
self._state = None
|
||||||
@ -145,6 +161,8 @@ class MqttCover(CoverDevice):
|
|||||||
self._tilt_max = tilt_max
|
self._tilt_max = tilt_max
|
||||||
self._tilt_optimistic = tilt_optimistic
|
self._tilt_optimistic = tilt_optimistic
|
||||||
self._tilt_invert = tilt_invert
|
self._tilt_invert = tilt_invert
|
||||||
|
self._position_topic = position_topic
|
||||||
|
self._set_position_template = set_position_template
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_added_to_hass(self):
|
def async_added_to_hass(self):
|
||||||
@ -233,9 +251,11 @@ class MqttCover(CoverDevice):
|
|||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""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
|
supported_features |= SUPPORT_SET_POSITION
|
||||||
|
|
||||||
if self._tilt_command_topic is not None:
|
if self._tilt_command_topic is not None:
|
||||||
@ -315,6 +335,22 @@ class MqttCover(CoverDevice):
|
|||||||
mqtt.async_publish(self.hass, self._tilt_command_topic,
|
mqtt.async_publish(self.hass, self._tilt_command_topic,
|
||||||
level, self._qos, self._retain)
|
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):
|
def find_percentage_in_range(self, position):
|
||||||
"""Find the 0-100% value within the specified range."""
|
"""Find the 0-100% value within the specified range."""
|
||||||
# the range of motion as defined by the min max values
|
# the range of motion as defined by the min max values
|
||||||
|
@ -14,7 +14,7 @@ from homeassistant.components.media_player import (
|
|||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_OFF)
|
STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_OFF)
|
||||||
|
|
||||||
REQUIREMENTS = ['openhomedevice==0.4.0']
|
REQUIREMENTS = ['openhomedevice==0.4.2']
|
||||||
|
|
||||||
SUPPORT_OPENHOME = SUPPORT_SELECT_SOURCE | \
|
SUPPORT_OPENHOME = SUPPORT_SELECT_SOURCE | \
|
||||||
SUPPORT_VOLUME_STEP | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET | \
|
SUPPORT_VOLUME_STEP | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET | \
|
||||||
@ -60,7 +60,6 @@ class OpenhomeDevice(MediaPlayerDevice):
|
|||||||
self._track_information = {}
|
self._track_information = {}
|
||||||
self._in_standby = None
|
self._in_standby = None
|
||||||
self._transport_state = None
|
self._transport_state = None
|
||||||
self._track_information = None
|
|
||||||
self._volume_level = None
|
self._volume_level = None
|
||||||
self._volume_muted = None
|
self._volume_muted = None
|
||||||
self._supported_features = SUPPORT_OPENHOME
|
self._supported_features = SUPPORT_OPENHOME
|
||||||
@ -173,27 +172,29 @@ class OpenhomeDevice(MediaPlayerDevice):
|
|||||||
@property
|
@property
|
||||||
def media_image_url(self):
|
def media_image_url(self):
|
||||||
"""Image url of current playing media."""
|
"""Image url of current playing media."""
|
||||||
return self._track_information["albumArtwork"]
|
return self._track_information.get('albumArtwork')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def media_artist(self):
|
def media_artist(self):
|
||||||
"""Artist of current playing media, music track only."""
|
"""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
|
@property
|
||||||
def media_album_name(self):
|
def media_album_name(self):
|
||||||
"""Album name of current playing media, music track only."""
|
"""Album name of current playing media, music track only."""
|
||||||
return self._track_information["albumTitle"]
|
return self._track_information.get('albumTitle')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def media_title(self):
|
def media_title(self):
|
||||||
"""Title of current playing media."""
|
"""Title of current playing media."""
|
||||||
return self._track_information["title"]
|
return self._track_information.get('title')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def source(self):
|
def source(self):
|
||||||
"""Name of the current input source."""
|
"""Name of the current input source."""
|
||||||
return self._source["name"]
|
return self._source.get('name')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volume_level(self):
|
def volume_level(self):
|
||||||
|
@ -125,8 +125,7 @@ class RokuDevice(MediaPlayerDevice):
|
|||||||
"""Return the name of the device."""
|
"""Return the name of the device."""
|
||||||
if self.device_info.userdevicename:
|
if self.device_info.userdevicename:
|
||||||
return self.device_info.userdevicename
|
return self.device_info.userdevicename
|
||||||
else:
|
return "Roku {}".format(self.device_info.sernum)
|
||||||
return "roku_" + self.roku.device_info.sernum
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
@ -158,8 +157,7 @@ class RokuDevice(MediaPlayerDevice):
|
|||||||
return None
|
return None
|
||||||
elif self.current_app.name == "Roku":
|
elif self.current_app.name == "Roku":
|
||||||
return None
|
return None
|
||||||
else:
|
return MEDIA_TYPE_VIDEO
|
||||||
return MEDIA_TYPE_VIDEO
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def media_image_url(self):
|
def media_image_url(self):
|
||||||
|
@ -40,8 +40,7 @@ import voluptuous as vol
|
|||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
REQUIREMENTS = ['dsmr_parser==0.9']
|
REQUIREMENTS = ['dsmr_parser==0.8']
|
||||||
|
|
||||||
|
|
||||||
CONF_DSMR_VERSION = 'dsmr_version'
|
CONF_DSMR_VERSION = 'dsmr_version'
|
||||||
CONF_RECONNECT_INTERVAL = 'reconnect_interval'
|
CONF_RECONNECT_INTERVAL = 'reconnect_interval'
|
||||||
@ -61,7 +60,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.string,
|
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.string,
|
||||||
vol.Optional(CONF_HOST, default=None): cv.string,
|
vol.Optional(CONF_HOST, default=None): cv.string,
|
||||||
vol.Optional(CONF_DSMR_VERSION, default=DEFAULT_DSMR_VERSION): vol.All(
|
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,
|
vol.Optional(CONF_RECONNECT_INTERVAL, default=30): int,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -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]
|
devices = [DSMREntity(name, obis) for name, obis in obis_mapping]
|
||||||
|
|
||||||
# Protocol version specific obis
|
# Protocol version specific obis
|
||||||
if dsmr_version in ('4', '5'):
|
if dsmr_version == '4':
|
||||||
gas_obis = obis_ref.HOURLY_GAS_METER_READING
|
gas_obis = obis_ref.HOURLY_GAS_METER_READING
|
||||||
else:
|
else:
|
||||||
gas_obis = obis_ref.GAS_METER_READING
|
gas_obis = obis_ref.GAS_METER_READING
|
||||||
|
@ -141,7 +141,7 @@ class MetOfficeCurrentSensor(Entity):
|
|||||||
attr['Sensor Id'] = self._condition
|
attr['Sensor Id'] = self._condition
|
||||||
attr['Site Id'] = self.site.id
|
attr['Site Id'] = self.site.id
|
||||||
attr['Site Name'] = self.site.name
|
attr['Site Name'] = self.site.name
|
||||||
attr['Last Update'] = self.data.lastupdate
|
attr['Last Update'] = self.data.data.date
|
||||||
attr[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION
|
attr[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
|
@ -574,16 +574,16 @@ SENSOR_TYPES = {
|
|||||||
"Precipitation Intensity in 4 Days", 3, 'qpf_allday', 'in',
|
"Precipitation Intensity in 4 Days", 3, 'qpf_allday', 'in',
|
||||||
LENGTH_INCHES, "mdi:umbrella"),
|
LENGTH_INCHES, "mdi:umbrella"),
|
||||||
'precip_1d': WUDailySimpleForecastSensorConfig(
|
'precip_1d': WUDailySimpleForecastSensorConfig(
|
||||||
"Percipitation Probability Today", 0, "pop", None, "%",
|
"Precipitation Probability Today", 0, "pop", None, "%",
|
||||||
"mdi:umbrella"),
|
"mdi:umbrella"),
|
||||||
'precip_2d': WUDailySimpleForecastSensorConfig(
|
'precip_2d': WUDailySimpleForecastSensorConfig(
|
||||||
"Percipitation Probability Tomorrow", 1, "pop", None, "%",
|
"Precipitation Probability Tomorrow", 1, "pop", None, "%",
|
||||||
"mdi:umbrella"),
|
"mdi:umbrella"),
|
||||||
'precip_3d': WUDailySimpleForecastSensorConfig(
|
'precip_3d': WUDailySimpleForecastSensorConfig(
|
||||||
"Percipitation Probability in 3 Days", 2, "pop", None, "%",
|
"Precipitation Probability in 3 Days", 2, "pop", None, "%",
|
||||||
"mdi:umbrella"),
|
"mdi:umbrella"),
|
||||||
'precip_4d': WUDailySimpleForecastSensorConfig(
|
'precip_4d': WUDailySimpleForecastSensorConfig(
|
||||||
"Percipitation Probability in 4 Days", 3, "pop", None, "%",
|
"Precipitation Probability in 4 Days", 3, "pop", None, "%",
|
||||||
"mdi:umbrella"),
|
"mdi:umbrella"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ from homeassistant.components.frontend import register_built_in_panel
|
|||||||
|
|
||||||
from . import api
|
from . import api
|
||||||
from . import const
|
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 .node_entity import ZWaveBaseEntity, ZWaveNodeEntity
|
||||||
from . import workaround
|
from . import workaround
|
||||||
from .discovery_schemas import DISCOVERY_SCHEMAS
|
from .discovery_schemas import DISCOVERY_SCHEMAS
|
||||||
@ -74,12 +74,20 @@ RENAME_NODE_SCHEMA = vol.Schema({
|
|||||||
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
||||||
vol.Required(const.ATTR_NAME): cv.string,
|
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({
|
SET_CONFIG_PARAMETER_SCHEMA = vol.Schema({
|
||||||
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
||||||
vol.Required(const.ATTR_CONFIG_PARAMETER): 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.Required(const.ATTR_CONFIG_VALUE): vol.Any(vol.Coerce(int), cv.string),
|
||||||
vol.Optional(const.ATTR_CONFIG_SIZE, default=2): vol.Coerce(int)
|
vol.Optional(const.ATTR_CONFIG_SIZE, default=2): vol.Coerce(int)
|
||||||
})
|
})
|
||||||
|
|
||||||
PRINT_CONFIG_PARAMETER_SCHEMA = vol.Schema({
|
PRINT_CONFIG_PARAMETER_SCHEMA = vol.Schema({
|
||||||
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
||||||
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
|
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
|
||||||
@ -258,6 +266,7 @@ def setup(hass, config):
|
|||||||
|
|
||||||
network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False)
|
network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False)
|
||||||
hass.data[DATA_DEVICES] = {}
|
hass.data[DATA_DEVICES] = {}
|
||||||
|
hass.data[DATA_ENTITY_VALUES] = []
|
||||||
|
|
||||||
if use_debug: # pragma: no cover
|
if use_debug: # pragma: no cover
|
||||||
def log_all(signal, value=None):
|
def log_all(signal, value=None):
|
||||||
@ -276,12 +285,10 @@ def setup(hass, config):
|
|||||||
|
|
||||||
dispatcher.connect(log_all, weak=False)
|
dispatcher.connect(log_all, weak=False)
|
||||||
|
|
||||||
discovered_values = []
|
|
||||||
|
|
||||||
def value_added(node, value):
|
def value_added(node, value):
|
||||||
"""Handle new added value to a node on the network."""
|
"""Handle new added value to a node on the network."""
|
||||||
# Check if this value should be tracked by an existing entity
|
# 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)
|
values.check_value(value)
|
||||||
|
|
||||||
for schema in DISCOVERY_SCHEMAS:
|
for schema in DISCOVERY_SCHEMAS:
|
||||||
@ -294,7 +301,11 @@ def setup(hass, config):
|
|||||||
|
|
||||||
values = ZWaveDeviceEntityValues(
|
values = ZWaveDeviceEntityValues(
|
||||||
hass, schema, value, config, device_config)
|
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)
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||||
|
|
||||||
@ -401,6 +412,18 @@ def setup(hass, config):
|
|||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"Renamed Z-Wave node %d to %s", node_id, name)
|
"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):
|
def remove_failed_node(service):
|
||||||
"""Remove failed node."""
|
"""Remove failed node."""
|
||||||
node_id = service.data.get(const.ATTR_NODE_ID)
|
node_id = service.data.get(const.ATTR_NODE_ID)
|
||||||
@ -585,6 +608,10 @@ def setup(hass, config):
|
|||||||
hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node,
|
hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node,
|
||||||
descriptions[const.SERVICE_RENAME_NODE],
|
descriptions[const.SERVICE_RENAME_NODE],
|
||||||
schema=RENAME_NODE_SCHEMA)
|
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,
|
hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER,
|
||||||
set_config_parameter,
|
set_config_parameter,
|
||||||
descriptions[
|
descriptions[
|
||||||
@ -644,6 +671,7 @@ def setup(hass, config):
|
|||||||
|
|
||||||
if 'frontend' in hass.config.components:
|
if 'frontend' in hass.config.components:
|
||||||
register_built_in_panel(hass, 'zwave', 'Z-Wave', 'mdi:nfc')
|
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.ZWaveNodeGroupView)
|
||||||
hass.http.register_view(api.ZWaveNodeConfigView)
|
hass.http.register_view(api.ZWaveNodeConfigView)
|
||||||
hass.http.register_view(api.ZWaveUserCodeView)
|
hass.http.register_view(api.ZWaveUserCodeView)
|
||||||
|
@ -9,6 +9,32 @@ from . import const
|
|||||||
_LOGGER = logging.getLogger(__name__)
|
_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):
|
class ZWaveNodeGroupView(HomeAssistantView):
|
||||||
"""View to return the nodes group configuration."""
|
"""View to return the nodes group configuration."""
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ DISCOVERY_DEVICE = 'device'
|
|||||||
|
|
||||||
DATA_DEVICES = 'zwave_devices'
|
DATA_DEVICES = 'zwave_devices'
|
||||||
DATA_NETWORK = 'zwave_network'
|
DATA_NETWORK = 'zwave_network'
|
||||||
|
DATA_ENTITY_VALUES = 'zwave_entity_values'
|
||||||
|
|
||||||
SERVICE_CHANGE_ASSOCIATION = "change_association"
|
SERVICE_CHANGE_ASSOCIATION = "change_association"
|
||||||
SERVICE_ADD_NODE = "add_node"
|
SERVICE_ADD_NODE = "add_node"
|
||||||
@ -38,6 +39,7 @@ SERVICE_SET_WAKEUP = "set_wakeup"
|
|||||||
SERVICE_STOP_NETWORK = "stop_network"
|
SERVICE_STOP_NETWORK = "stop_network"
|
||||||
SERVICE_START_NETWORK = "start_network"
|
SERVICE_START_NETWORK = "start_network"
|
||||||
SERVICE_RENAME_NODE = "rename_node"
|
SERVICE_RENAME_NODE = "rename_node"
|
||||||
|
SERVICE_RENAME_VALUE = "rename_value"
|
||||||
SERVICE_REFRESH_ENTITY = "refresh_entity"
|
SERVICE_REFRESH_ENTITY = "refresh_entity"
|
||||||
SERVICE_REFRESH_NODE = "refresh_node"
|
SERVICE_REFRESH_NODE = "refresh_node"
|
||||||
SERVICE_RESET_NODE_METERS = "reset_node_meters"
|
SERVICE_RESET_NODE_METERS = "reset_node_meters"
|
||||||
|
@ -109,6 +109,19 @@ rename_node:
|
|||||||
description: New Name
|
description: New Name
|
||||||
example: 'kitchen'
|
example: 'kitchen'
|
||||||
|
|
||||||
|
rename_value:
|
||||||
|
description: Set the name of a node value. Value IDs can be queried from /api/zwave/values/{node_id}
|
||||||
|
fields:
|
||||||
|
node_id:
|
||||||
|
description: ID of the node to rename.
|
||||||
|
example: 10
|
||||||
|
value_id:
|
||||||
|
description: ID of the value to rename.
|
||||||
|
example: 72037594255792737
|
||||||
|
name:
|
||||||
|
description: New Name
|
||||||
|
example: 'Luminosity'
|
||||||
|
|
||||||
reset_node_meters:
|
reset_node_meters:
|
||||||
description: Resets the meter counters of a node.
|
description: Resets the meter counters of a node.
|
||||||
fields:
|
fields:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"""Constants used by Home Assistant components."""
|
"""Constants used by Home Assistant components."""
|
||||||
MAJOR_VERSION = 0
|
MAJOR_VERSION = 0
|
||||||
MINOR_VERSION = 46
|
MINOR_VERSION = 46
|
||||||
PATCH_VERSION = '0'
|
PATCH_VERSION = '1'
|
||||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
||||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
||||||
REQUIRED_PYTHON_VER = (3, 4, 2)
|
REQUIRED_PYTHON_VER = (3, 4, 2)
|
||||||
|
@ -162,7 +162,7 @@ dnspython3==1.15.0
|
|||||||
dovado==0.4.1
|
dovado==0.4.1
|
||||||
|
|
||||||
# homeassistant.components.sensor.dsmr
|
# homeassistant.components.sensor.dsmr
|
||||||
dsmr_parser==0.9
|
dsmr_parser==0.8
|
||||||
|
|
||||||
# homeassistant.components.dweet
|
# homeassistant.components.dweet
|
||||||
# homeassistant.components.sensor.dweet
|
# homeassistant.components.sensor.dweet
|
||||||
@ -406,7 +406,7 @@ onkyo-eiscp==1.1
|
|||||||
openevsewifi==0.4
|
openevsewifi==0.4
|
||||||
|
|
||||||
# homeassistant.components.media_player.openhome
|
# homeassistant.components.media_player.openhome
|
||||||
openhomedevice==0.4.0
|
openhomedevice==0.4.2
|
||||||
|
|
||||||
# homeassistant.components.switch.orvibo
|
# homeassistant.components.switch.orvibo
|
||||||
orvibo==1.1.1
|
orvibo==1.1.1
|
||||||
|
@ -37,7 +37,7 @@ aiohttp_cors==0.5.3
|
|||||||
apns2==0.1.1
|
apns2==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.sensor.dsmr
|
# homeassistant.components.sensor.dsmr
|
||||||
dsmr_parser==0.9
|
dsmr_parser==0.8
|
||||||
|
|
||||||
# homeassistant.components.climate.honeywell
|
# homeassistant.components.climate.honeywell
|
||||||
evohomeclient==0.2.5
|
evohomeclient==0.2.5
|
||||||
|
@ -215,6 +215,8 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
'cover.test').attributes
|
'cover.test').attributes
|
||||||
self.assertFalse('current_position' in state_attributes_dict)
|
self.assertFalse('current_position' in state_attributes_dict)
|
||||||
self.assertFalse('current_tilt_position' in state_attributes_dict)
|
self.assertFalse('current_tilt_position' in state_attributes_dict)
|
||||||
|
self.assertFalse(4 & self.hass.states.get(
|
||||||
|
'cover.test').attributes['supported_features'] == 4)
|
||||||
|
|
||||||
fire_mqtt_message(self.hass, 'state-topic', '0')
|
fire_mqtt_message(self.hass, 'state-topic', '0')
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
@ -240,6 +242,119 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
'cover.test').attributes['current_position']
|
'cover.test').attributes['current_position']
|
||||||
self.assertEqual(50, current_cover_position)
|
self.assertEqual(50, current_cover_position)
|
||||||
|
|
||||||
|
def test_set_cover_position(self):
|
||||||
|
"""Test setting cover position."""
|
||||||
|
self.assertTrue(setup_component(self.hass, cover.DOMAIN, {
|
||||||
|
cover.DOMAIN: {
|
||||||
|
'platform': 'mqtt',
|
||||||
|
'name': 'test',
|
||||||
|
'state_topic': 'state-topic',
|
||||||
|
'command_topic': 'command-topic',
|
||||||
|
'set_position_topic': 'position-topic',
|
||||||
|
'payload_open': 'OPEN',
|
||||||
|
'payload_close': 'CLOSE',
|
||||||
|
'payload_stop': 'STOP'
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
state_attributes_dict = self.hass.states.get(
|
||||||
|
'cover.test').attributes
|
||||||
|
self.assertFalse('current_position' in state_attributes_dict)
|
||||||
|
self.assertFalse('current_tilt_position' in state_attributes_dict)
|
||||||
|
|
||||||
|
self.assertTrue(4 & self.hass.states.get(
|
||||||
|
'cover.test').attributes['supported_features'] == 4)
|
||||||
|
|
||||||
|
fire_mqtt_message(self.hass, 'state-topic', '22')
|
||||||
|
self.hass.block_till_done()
|
||||||
|
state_attributes_dict = self.hass.states.get(
|
||||||
|
'cover.test').attributes
|
||||||
|
self.assertTrue('current_position' in state_attributes_dict)
|
||||||
|
self.assertFalse('current_tilt_position' in state_attributes_dict)
|
||||||
|
current_cover_position = self.hass.states.get(
|
||||||
|
'cover.test').attributes['current_position']
|
||||||
|
self.assertEqual(22, current_cover_position)
|
||||||
|
|
||||||
|
def test_set_position_templated(self):
|
||||||
|
"""Test setting cover position via template."""
|
||||||
|
self.assertTrue(setup_component(self.hass, cover.DOMAIN, {
|
||||||
|
cover.DOMAIN: {
|
||||||
|
'platform': 'mqtt',
|
||||||
|
'name': 'test',
|
||||||
|
'state_topic': 'state-topic',
|
||||||
|
'command_topic': 'command-topic',
|
||||||
|
'set_position_topic': 'position-topic',
|
||||||
|
'set_position_template': '{{100-62}}',
|
||||||
|
'payload_open': 'OPEN',
|
||||||
|
'payload_close': 'CLOSE',
|
||||||
|
'payload_stop': 'STOP'
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
cover.set_cover_position(self.hass, 100, 'cover.test')
|
||||||
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
self.assertEqual(('position-topic', '38', 0, False),
|
||||||
|
self.mock_publish.mock_calls[-2][1])
|
||||||
|
|
||||||
|
def test_set_position_untemplated(self):
|
||||||
|
"""Test setting cover position via template."""
|
||||||
|
self.assertTrue(setup_component(self.hass, cover.DOMAIN, {
|
||||||
|
cover.DOMAIN: {
|
||||||
|
'platform': 'mqtt',
|
||||||
|
'name': 'test',
|
||||||
|
'state_topic': 'state-topic',
|
||||||
|
'command_topic': 'command-topic',
|
||||||
|
'set_position_topic': 'position-topic',
|
||||||
|
'payload_open': 'OPEN',
|
||||||
|
'payload_close': 'CLOSE',
|
||||||
|
'payload_stop': 'STOP'
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
cover.set_cover_position(self.hass, 62, 'cover.test')
|
||||||
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
self.assertEqual(('position-topic', 62, 0, False),
|
||||||
|
self.mock_publish.mock_calls[-2][1])
|
||||||
|
|
||||||
|
def test_no_command_topic(self):
|
||||||
|
"""Test with no command topic."""
|
||||||
|
self.assertTrue(setup_component(self.hass, cover.DOMAIN, {
|
||||||
|
cover.DOMAIN: {
|
||||||
|
'platform': 'mqtt',
|
||||||
|
'name': 'test',
|
||||||
|
'qos': 0,
|
||||||
|
'payload_open': 'OPEN',
|
||||||
|
'payload_close': 'CLOSE',
|
||||||
|
'payload_stop': 'STOP',
|
||||||
|
'tilt_command_topic': 'tilt-command',
|
||||||
|
'tilt_status_topic': 'tilt-status'
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
self.assertEqual(240, self.hass.states.get(
|
||||||
|
'cover.test').attributes['supported_features'])
|
||||||
|
|
||||||
|
def test_with_command_topic_and_tilt(self):
|
||||||
|
"""Test with command topic and tilt config."""
|
||||||
|
self.assertTrue(setup_component(self.hass, cover.DOMAIN, {
|
||||||
|
cover.DOMAIN: {
|
||||||
|
'command_topic': 'test',
|
||||||
|
'platform': 'mqtt',
|
||||||
|
'name': 'test',
|
||||||
|
'qos': 0,
|
||||||
|
'payload_open': 'OPEN',
|
||||||
|
'payload_close': 'CLOSE',
|
||||||
|
'payload_stop': 'STOP',
|
||||||
|
'tilt_command_topic': 'tilt-command',
|
||||||
|
'tilt_status_topic': 'tilt-status'
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
self.assertEqual(251, self.hass.states.get(
|
||||||
|
'cover.test').attributes['supported_features'])
|
||||||
|
|
||||||
def test_tilt_defaults(self):
|
def test_tilt_defaults(self):
|
||||||
"""Test the defaults."""
|
"""Test the defaults."""
|
||||||
self.assertTrue(setup_component(self.hass, cover.DOMAIN, {
|
self.assertTrue(setup_component(self.hass, cover.DOMAIN, {
|
||||||
@ -457,7 +572,7 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
mqtt_cover = MqttCover(
|
mqtt_cover = MqttCover(
|
||||||
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
||||||
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
||||||
100, 0, 0, 100, False, False)
|
100, 0, 0, 100, False, False, None, None)
|
||||||
|
|
||||||
self.assertEqual(44, mqtt_cover.find_percentage_in_range(44))
|
self.assertEqual(44, mqtt_cover.find_percentage_in_range(44))
|
||||||
|
|
||||||
@ -466,7 +581,7 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
mqtt_cover = MqttCover(
|
mqtt_cover = MqttCover(
|
||||||
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
||||||
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
||||||
180, 80, 80, 180, False, False)
|
180, 80, 80, 180, False, False, None, None)
|
||||||
|
|
||||||
self.assertEqual(40, mqtt_cover.find_percentage_in_range(120))
|
self.assertEqual(40, mqtt_cover.find_percentage_in_range(120))
|
||||||
|
|
||||||
@ -475,7 +590,7 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
mqtt_cover = MqttCover(
|
mqtt_cover = MqttCover(
|
||||||
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
||||||
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
||||||
100, 0, 0, 100, False, True)
|
100, 0, 0, 100, False, True, None, None)
|
||||||
|
|
||||||
self.assertEqual(56, mqtt_cover.find_percentage_in_range(44))
|
self.assertEqual(56, mqtt_cover.find_percentage_in_range(44))
|
||||||
|
|
||||||
@ -484,7 +599,7 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
mqtt_cover = MqttCover(
|
mqtt_cover = MqttCover(
|
||||||
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
||||||
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
||||||
180, 80, 80, 180, False, True)
|
180, 80, 80, 180, False, True, None, None)
|
||||||
|
|
||||||
self.assertEqual(60, mqtt_cover.find_percentage_in_range(120))
|
self.assertEqual(60, mqtt_cover.find_percentage_in_range(120))
|
||||||
|
|
||||||
@ -493,7 +608,7 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
mqtt_cover = MqttCover(
|
mqtt_cover = MqttCover(
|
||||||
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
||||||
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
||||||
100, 0, 0, 100, False, False)
|
100, 0, 0, 100, False, False, None, None)
|
||||||
|
|
||||||
self.assertEqual(44, mqtt_cover.find_in_range_from_percent(44))
|
self.assertEqual(44, mqtt_cover.find_in_range_from_percent(44))
|
||||||
|
|
||||||
@ -502,7 +617,7 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
mqtt_cover = MqttCover(
|
mqtt_cover = MqttCover(
|
||||||
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
||||||
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
||||||
180, 80, 80, 180, False, False)
|
180, 80, 80, 180, False, False, None, None)
|
||||||
|
|
||||||
self.assertEqual(120, mqtt_cover.find_in_range_from_percent(40))
|
self.assertEqual(120, mqtt_cover.find_in_range_from_percent(40))
|
||||||
|
|
||||||
@ -511,7 +626,7 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
mqtt_cover = MqttCover(
|
mqtt_cover = MqttCover(
|
||||||
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
||||||
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
||||||
100, 0, 0, 100, False, True)
|
100, 0, 0, 100, False, True, None, None)
|
||||||
|
|
||||||
self.assertEqual(44, mqtt_cover.find_in_range_from_percent(56))
|
self.assertEqual(44, mqtt_cover.find_in_range_from_percent(56))
|
||||||
|
|
||||||
@ -520,6 +635,6 @@ class TestCoverMQTT(unittest.TestCase):
|
|||||||
mqtt_cover = MqttCover(
|
mqtt_cover = MqttCover(
|
||||||
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
'cover.test', 'foo', 'bar', 'fooBar', "fooBarBaz", 0, False,
|
||||||
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', False, None,
|
||||||
180, 80, 80, 180, False, True)
|
180, 80, 80, 180, False, True, None, None)
|
||||||
|
|
||||||
self.assertEqual(120, mqtt_cover.find_in_range_from_percent(60))
|
self.assertEqual(120, mqtt_cover.find_in_range_from_percent(60))
|
||||||
|
@ -3,9 +3,38 @@ import asyncio
|
|||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
from homeassistant.components.zwave import DATA_NETWORK, const
|
from homeassistant.components.zwave import DATA_NETWORK, const
|
||||||
from homeassistant.components.zwave.api import (
|
from homeassistant.components.zwave.api import (
|
||||||
ZWaveNodeGroupView, ZWaveNodeConfigView, ZWaveUserCodeView)
|
ZWaveNodeValueView, ZWaveNodeGroupView, ZWaveNodeConfigView,
|
||||||
|
ZWaveUserCodeView)
|
||||||
from tests.common import mock_http_component_app
|
from tests.common import mock_http_component_app
|
||||||
from tests.mock.zwave import MockNode, MockValue
|
from tests.mock.zwave import MockNode, MockValue, MockEntityValues
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_get_values(hass, test_client):
|
||||||
|
"""Test getting values on node."""
|
||||||
|
app = mock_http_component_app(hass)
|
||||||
|
ZWaveNodeValueView().register(app.router)
|
||||||
|
|
||||||
|
node = MockNode(node_id=1)
|
||||||
|
value = MockValue(value_id=123456, node=node, label='Test Label')
|
||||||
|
values = MockEntityValues(primary=value)
|
||||||
|
node2 = MockNode(node_id=2)
|
||||||
|
value2 = MockValue(value_id=234567, node=node2, label='Test Label 2')
|
||||||
|
values2 = MockEntityValues(primary=value2)
|
||||||
|
hass.data[const.DATA_ENTITY_VALUES] = [values, values2]
|
||||||
|
|
||||||
|
client = yield from test_client(app)
|
||||||
|
|
||||||
|
resp = yield from client.get('/api/zwave/values/1')
|
||||||
|
|
||||||
|
assert resp.status == 200
|
||||||
|
result = yield from resp.json()
|
||||||
|
|
||||||
|
assert result == {
|
||||||
|
'123456': {
|
||||||
|
'label': 'Test Label',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
|
@ -868,6 +868,23 @@ class TestZWaveServices(unittest.TestCase):
|
|||||||
|
|
||||||
assert self.zwave_network.nodes[11].name == 'test_name'
|
assert self.zwave_network.nodes[11].name == 'test_name'
|
||||||
|
|
||||||
|
def test_rename_value(self):
|
||||||
|
"""Test zwave rename_value service."""
|
||||||
|
node = MockNode(node_id=14)
|
||||||
|
value = MockValue(index=12, value_id=123456, label="Old Label")
|
||||||
|
node.values = {123456: value}
|
||||||
|
self.zwave_network.nodes = {11: node}
|
||||||
|
|
||||||
|
assert value.label == "Old Label"
|
||||||
|
self.hass.services.call('zwave', 'rename_value', {
|
||||||
|
const.ATTR_NODE_ID: 11,
|
||||||
|
const.ATTR_VALUE_ID: 123456,
|
||||||
|
const.ATTR_NAME: "New Label",
|
||||||
|
})
|
||||||
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
assert value.label == "New Label"
|
||||||
|
|
||||||
def test_remove_failed_node(self):
|
def test_remove_failed_node(self):
|
||||||
"""Test zwave remove_failed_node service."""
|
"""Test zwave remove_failed_node service."""
|
||||||
self.hass.services.call('zwave', 'remove_failed_node', {
|
self.hass.services.call('zwave', 'remove_failed_node', {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user