Remove deprecated (old) Z-Wave integration (#67221)

* Remove deprecated (old) Z-Wave integration

* Mark migration tests as skip, for later cleanup
This commit is contained in:
Franck Nijhof 2022-03-18 13:09:10 +01:00 committed by GitHub
parent 35261a9089
commit 2686be921c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
106 changed files with 6 additions and 13535 deletions

View File

@ -1464,7 +1464,6 @@ omit =
homeassistant/components/ziggo_mediabox_xl/media_player.py
homeassistant/components/zoneminder/*
homeassistant/components/supla/*
homeassistant/components/zwave/util.py
homeassistant/components/zwave_js/discovery.py
homeassistant/components/zwave_js/sensor.py
homeassistant/components/zwave_me/__init__.py

View File

@ -148,7 +148,6 @@ jobs:
sed -i "s|# pySwitchmate|pySwitchmate|g" ${requirement_file}
sed -i "s|# face_recognition|face_recognition|g" ${requirement_file}
sed -i "s|# python-gammu|python-gammu|g" ${requirement_file}
sed -i "s|# homeassistant-pyozw|homeassistant-pyozw|g" ${requirement_file}
done
- name: Build wheels

View File

@ -1179,8 +1179,6 @@ tests/components/zodiac/* @JulienTant
homeassistant/components/zone/* @home-assistant/core
tests/components/zone/* @home-assistant/core
homeassistant/components/zoneminder/* @rohankapoorcom
homeassistant/components/zwave/* @home-assistant/z-wave
tests/components/zwave/* @home-assistant/z-wave
homeassistant/components/zwave_js/* @home-assistant/z-wave
tests/components/zwave_js/* @home-assistant/z-wave
homeassistant/components/zwave_me/* @lawfulchaos @Z-Wave-Me

View File

@ -15,8 +15,7 @@ RUN \
-r homeassistant/requirements.txt --use-deprecated=legacy-resolver
COPY requirements_all.txt homeassistant/
RUN \
sed -i "s|# homeassistant-pyozw|homeassistant-pyozw|g" homeassistant/requirements_all.txt \
&& pip3 install --no-cache-dir --no-index --only-binary=:all: --find-links "${WHEELS_LINKS}" \
pip3 install --no-cache-dir --no-index --only-binary=:all: --find-links "${WHEELS_LINKS}" \
-r homeassistant/requirements_all.txt --use-deprecated=legacy-resolver
## Setup Home Assistant Core

View File

@ -9,7 +9,7 @@ import voluptuous as vol
from homeassistant.components import frontend
from homeassistant.components.http import HomeAssistantView
from homeassistant.const import CONF_ID, EVENT_COMPONENT_LOADED
from homeassistant.core import HomeAssistant, callback
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.typing import ConfigType
from homeassistant.setup import ATTR_COMPONENT
@ -29,7 +29,6 @@ SECTIONS = (
"script",
"scene",
)
ON_DEMAND = ("zwave",)
ACTION_CREATE_UPDATE = "create_update"
ACTION_DELETE = "delete"
@ -53,21 +52,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
key = f"{DOMAIN}.{panel_name}"
hass.bus.async_fire(EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: key})
@callback
def component_loaded(event):
"""Respond to components being loaded."""
panel_name = event.data.get(ATTR_COMPONENT)
if panel_name in ON_DEMAND:
hass.async_create_task(setup_panel(panel_name))
hass.bus.async_listen(EVENT_COMPONENT_LOADED, component_loaded)
tasks = [asyncio.create_task(setup_panel(panel_name)) for panel_name in SECTIONS]
for panel_name in ON_DEMAND:
if panel_name in hass.config.components:
tasks.append(asyncio.create_task(setup_panel(panel_name)))
if tasks:
await asyncio.wait(tasks)

View File

@ -1,259 +0,0 @@
"""Provide configuration end points for Z-Wave."""
from collections import deque
from http import HTTPStatus
import logging
from aiohttp.web import Response
from homeassistant.components.http import HomeAssistantView
from homeassistant.components.zwave import DEVICE_CONFIG_SCHEMA_ENTRY, const
import homeassistant.core as ha
import homeassistant.helpers.config_validation as cv
from . import EditKeyBasedConfigView
_LOGGER = logging.getLogger(__name__)
CONFIG_PATH = "zwave_device_config.yaml"
OZW_LOG_FILENAME = "OZW_Log.txt"
async def async_setup(hass):
"""Set up the Z-Wave config API."""
hass.http.register_view(
EditKeyBasedConfigView(
"zwave",
"device_config",
CONFIG_PATH,
cv.entity_id,
DEVICE_CONFIG_SCHEMA_ENTRY,
)
)
hass.http.register_view(ZWaveNodeValueView)
hass.http.register_view(ZWaveNodeGroupView)
hass.http.register_view(ZWaveNodeConfigView)
hass.http.register_view(ZWaveUserCodeView)
hass.http.register_view(ZWaveLogView)
hass.http.register_view(ZWaveConfigWriteView)
hass.http.register_view(ZWaveProtectionView)
return True
class ZWaveLogView(HomeAssistantView):
"""View to read the ZWave log file."""
url = "/api/zwave/ozwlog"
name = "api:zwave:ozwlog"
# pylint: disable=no-self-use
async def get(self, request):
"""Retrieve the lines from ZWave log."""
try:
lines = int(request.query.get("lines", 0))
except ValueError:
return Response(text="Invalid datetime", status=HTTPStatus.BAD_REQUEST)
hass = request.app["hass"]
response = await hass.async_add_executor_job(self._get_log, hass, lines)
return Response(text="\n".join(response))
def _get_log(self, hass, lines):
"""Retrieve the logfile content."""
logfilepath = hass.config.path(OZW_LOG_FILENAME)
with open(logfilepath, encoding="utf8") as logfile:
data = (line.rstrip() for line in logfile)
if lines == 0:
loglines = list(data)
else:
loglines = deque(data, lines)
return loglines
class ZWaveConfigWriteView(HomeAssistantView):
"""View to save the ZWave configuration to zwcfg_xxxxx.xml."""
url = "/api/zwave/saveconfig"
name = "api:zwave:saveconfig"
@ha.callback
def post(self, request):
"""Save cache configuration to zwcfg_xxxxx.xml."""
hass = request.app["hass"]
if (network := hass.data.get(const.DATA_NETWORK)) is None:
return self.json_message(
"No Z-Wave network data found", HTTPStatus.NOT_FOUND
)
_LOGGER.info("Z-Wave configuration written to file")
network.write_config()
return self.json_message("Z-Wave configuration saved to file")
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,
"index": entity_values.primary.index,
"instance": entity_values.primary.instance,
"poll_intensity": entity_values.primary.poll_intensity,
}
return self.json(values_data)
class ZWaveNodeGroupView(HomeAssistantView):
"""View to return the nodes group configuration."""
url = r"/api/zwave/groups/{node_id:\d+}"
name = "api:zwave:groups"
@ha.callback
def get(self, request, node_id):
"""Retrieve groups of node."""
nodeid = int(node_id)
hass = request.app["hass"]
network = hass.data.get(const.DATA_NETWORK)
if (node := network.nodes.get(nodeid)) is None:
return self.json_message("Node not found", HTTPStatus.NOT_FOUND)
groupdata = node.groups
groups = {}
for key, value in groupdata.items():
groups[key] = {
"associations": value.associations,
"association_instances": value.associations_instances,
"label": value.label,
"max_associations": value.max_associations,
}
return self.json(groups)
class ZWaveNodeConfigView(HomeAssistantView):
"""View to return the nodes configuration options."""
url = r"/api/zwave/config/{node_id:\d+}"
name = "api:zwave:config"
@ha.callback
def get(self, request, node_id):
"""Retrieve configurations of node."""
nodeid = int(node_id)
hass = request.app["hass"]
network = hass.data.get(const.DATA_NETWORK)
if (node := network.nodes.get(nodeid)) is None:
return self.json_message("Node not found", HTTPStatus.NOT_FOUND)
config = {}
for value in node.get_values(
class_id=const.COMMAND_CLASS_CONFIGURATION
).values():
config[value.index] = {
"label": value.label,
"type": value.type,
"help": value.help,
"data_items": value.data_items,
"data": value.data,
"max": value.max,
"min": value.min,
}
return self.json(config)
class ZWaveUserCodeView(HomeAssistantView):
"""View to return the nodes usercode configuration."""
url = r"/api/zwave/usercodes/{node_id:\d+}"
name = "api:zwave:usercodes"
@ha.callback
def get(self, request, node_id):
"""Retrieve usercodes of node."""
nodeid = int(node_id)
hass = request.app["hass"]
network = hass.data.get(const.DATA_NETWORK)
if (node := network.nodes.get(nodeid)) is None:
return self.json_message("Node not found", HTTPStatus.NOT_FOUND)
usercodes = {}
if not node.has_command_class(const.COMMAND_CLASS_USER_CODE):
return self.json(usercodes)
for value in node.get_values(class_id=const.COMMAND_CLASS_USER_CODE).values():
if value.genre != const.GENRE_USER:
continue
usercodes[value.index] = {
"code": value.data,
"label": value.label,
"length": len(value.data),
}
return self.json(usercodes)
class ZWaveProtectionView(HomeAssistantView):
"""View for the protection commandclass of a node."""
url = r"/api/zwave/protection/{node_id:\d+}"
name = "api:zwave:protection"
async def get(self, request, node_id):
"""Retrieve the protection commandclass options of node."""
nodeid = int(node_id)
hass = request.app["hass"]
network = hass.data.get(const.DATA_NETWORK)
def _fetch_protection():
"""Get protection data."""
if (node := network.nodes.get(nodeid)) is None:
return self.json_message("Node not found", HTTPStatus.NOT_FOUND)
protection_options = {}
if not node.has_command_class(const.COMMAND_CLASS_PROTECTION):
return self.json(protection_options)
protections = node.get_protections()
protection_options = {
"value_id": f"{list(protections)[0]:d}",
"selected": node.get_protection_item(list(protections)[0]),
"options": node.get_protection_items(list(protections)[0]),
}
return self.json(protection_options)
return await hass.async_add_executor_job(_fetch_protection)
async def post(self, request, node_id):
"""Change the selected option in protection commandclass."""
nodeid = int(node_id)
hass = request.app["hass"]
network = hass.data.get(const.DATA_NETWORK)
protection_data = await request.json()
def _set_protection():
"""Set protection data."""
node = network.nodes.get(nodeid)
selection = protection_data["selection"]
value_id = int(protection_data[const.ATTR_VALUE_ID])
if node is None:
return self.json_message("Node not found", HTTPStatus.NOT_FOUND)
if not node.has_command_class(const.COMMAND_CLASS_PROTECTION):
return self.json_message(
"No protection commandclass on this node", HTTPStatus.NOT_FOUND
)
state = node.set_protection(value_id, selection)
if not state:
return self.json_message(
"Protection setting did not complete", HTTPStatus.ACCEPTED
)
return self.json_message("Protection setting successfully set")
return await hass.async_add_executor_job(_set_protection)

File diff suppressed because it is too large Load Diff

View File

@ -1,106 +0,0 @@
"""Support for Z-Wave binary sensors."""
import datetime
import logging
from homeassistant.components.binary_sensor import DOMAIN, BinarySensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import track_point_in_time
import homeassistant.util.dt as dt_util
from . import ZWaveDeviceEntity, workaround
from .const import COMMAND_CLASS_SENSOR_BINARY
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave binary sensors from Config Entry."""
@callback
def async_add_binary_sensor(binary_sensor):
"""Add Z-Wave binary sensor."""
async_add_entities([binary_sensor])
async_dispatcher_connect(hass, "zwave_new_binary_sensor", async_add_binary_sensor)
def get_device(values, **kwargs):
"""Create Z-Wave entity device."""
device_mapping = workaround.get_device_mapping(values.primary)
if device_mapping == workaround.WORKAROUND_NO_OFF_EVENT:
return ZWaveTriggerSensor(values, "motion")
if workaround.get_device_component_mapping(values.primary) == DOMAIN:
return ZWaveBinarySensor(values, None)
if values.primary.command_class == COMMAND_CLASS_SENSOR_BINARY:
return ZWaveBinarySensor(values, None)
return None
class ZWaveBinarySensor(BinarySensorEntity, ZWaveDeviceEntity):
"""Representation of a binary sensor within Z-Wave."""
def __init__(self, values, device_class):
"""Initialize the sensor."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self._sensor_type = device_class
self._state = self.values.primary.data
def update_properties(self):
"""Handle data changes for node values."""
self._state = self.values.primary.data
@property
def is_on(self):
"""Return true if the binary sensor is on."""
return self._state
@property
def device_class(self):
"""Return the class of this sensor, from BinarySensorDeviceClass."""
return self._sensor_type
class ZWaveTriggerSensor(ZWaveBinarySensor):
"""Representation of a stateless sensor within Z-Wave."""
def __init__(self, values, device_class):
"""Initialize the sensor."""
super().__init__(values, device_class)
# Set default off delay to 60 sec
self.re_arm_sec = 60
self.invalidate_after = None
def update_properties(self):
"""Handle value changes for this entity's node."""
self._state = self.values.primary.data
_LOGGER.debug("off_delay=%s", self.values.off_delay)
# Set re_arm_sec if off_delay is provided from the sensor
if self.values.off_delay:
_LOGGER.debug("off_delay.data=%s", self.values.off_delay.data)
self.re_arm_sec = self.values.off_delay.data * 8
# only allow this value to be true for re_arm secs
if not self.hass:
return
self.invalidate_after = dt_util.utcnow() + datetime.timedelta(
seconds=self.re_arm_sec
)
track_point_in_time(
self.hass, self.async_update_ha_state, self.invalidate_after
)
@property
def is_on(self):
"""Return true if movement has happened within the rearm time."""
return self._state and (
self.invalidate_after is None or self.invalidate_after > dt_util.utcnow()
)

View File

@ -1,619 +0,0 @@
"""Support for Z-Wave climate devices."""
# Because we do not compile openzwave on CI
from __future__ import annotations
import logging
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
CURRENT_HVAC_COOL,
CURRENT_HVAC_FAN,
CURRENT_HVAC_HEAT,
CURRENT_HVAC_IDLE,
CURRENT_HVAC_OFF,
DOMAIN,
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_DRY,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_HEAT,
HVAC_MODE_HEAT_COOL,
HVAC_MODE_OFF,
PRESET_AWAY,
PRESET_BOOST,
PRESET_NONE,
SUPPORT_AUX_HEAT,
SUPPORT_FAN_MODE,
SUPPORT_PRESET_MODE,
SUPPORT_SWING_MODE,
SUPPORT_TARGET_TEMPERATURE,
SUPPORT_TARGET_TEMPERATURE_RANGE,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import ZWaveDeviceEntity, const
_LOGGER = logging.getLogger(__name__)
CONF_NAME = "name"
DEFAULT_NAME = "Z-Wave Climate"
REMOTEC = 0x5254
REMOTEC_ZXT_120 = 0x8377
REMOTEC_ZXT_120_THERMOSTAT = (REMOTEC, REMOTEC_ZXT_120)
ATTR_OPERATING_STATE = "operating_state"
ATTR_FAN_STATE = "fan_state"
ATTR_FAN_ACTION = "fan_action"
AUX_HEAT_ZWAVE_MODE = "Aux Heat"
# Device is in manufacturer specific mode (e.g. setting the valve manually)
PRESET_MANUFACTURER_SPECIFIC = "Manufacturer Specific"
WORKAROUND_ZXT_120 = "zxt_120"
DEVICE_MAPPINGS = {REMOTEC_ZXT_120_THERMOSTAT: WORKAROUND_ZXT_120}
HVAC_STATE_MAPPINGS = {
"off": HVAC_MODE_OFF,
"heat": HVAC_MODE_HEAT,
"heat mode": HVAC_MODE_HEAT,
"heat (default)": HVAC_MODE_HEAT,
"furnace": HVAC_MODE_HEAT,
"fan only": HVAC_MODE_FAN_ONLY,
"dry air": HVAC_MODE_DRY,
"moist air": HVAC_MODE_DRY,
"cool": HVAC_MODE_COOL,
"heat_cool": HVAC_MODE_HEAT_COOL,
"auto": HVAC_MODE_HEAT_COOL,
"auto changeover": HVAC_MODE_HEAT_COOL,
}
MODE_SETPOINT_MAPPINGS = {
"off": (),
"heat": ("setpoint_heating",),
"cool": ("setpoint_cooling",),
"auto": ("setpoint_heating", "setpoint_cooling"),
"aux heat": ("setpoint_heating",),
"furnace": ("setpoint_furnace",),
"dry air": ("setpoint_dry_air",),
"moist air": ("setpoint_moist_air",),
"auto changeover": ("setpoint_auto_changeover",),
"heat econ": ("setpoint_eco_heating",),
"cool econ": ("setpoint_eco_cooling",),
"away": ("setpoint_away_heating", "setpoint_away_cooling"),
"full power": ("setpoint_full_power",),
# aliases found in xml configs
"comfort": ("setpoint_heating",),
"heat mode": ("setpoint_heating",),
"heat (default)": ("setpoint_heating",),
"dry floor": ("setpoint_dry_air",),
"heat eco": ("setpoint_eco_heating",),
"energy saving": ("setpoint_eco_heating",),
"energy heat": ("setpoint_eco_heating",),
"vacation": ("setpoint_away_heating", "setpoint_away_cooling"),
# for tests
"heat_cool": ("setpoint_heating", "setpoint_cooling"),
}
HVAC_CURRENT_MAPPINGS = {
"idle": CURRENT_HVAC_IDLE,
"heat": CURRENT_HVAC_HEAT,
"pending heat": CURRENT_HVAC_IDLE,
"heating": CURRENT_HVAC_HEAT,
"cool": CURRENT_HVAC_COOL,
"pending cool": CURRENT_HVAC_IDLE,
"cooling": CURRENT_HVAC_COOL,
"fan only": CURRENT_HVAC_FAN,
"vent / economiser": CURRENT_HVAC_FAN,
"off": CURRENT_HVAC_OFF,
}
PRESET_MAPPINGS = {
"away": PRESET_AWAY,
"full power": PRESET_BOOST,
"manufacturer specific": PRESET_MANUFACTURER_SPECIFIC,
}
DEFAULT_HVAC_MODES = [
HVAC_MODE_HEAT_COOL,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_DRY,
HVAC_MODE_OFF,
HVAC_MODE_AUTO,
]
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave Climate device from Config Entry."""
@callback
def async_add_climate(climate):
"""Add Z-Wave Climate Device."""
async_add_entities([climate])
async_dispatcher_connect(hass, "zwave_new_climate", async_add_climate)
def get_device(hass, values, **kwargs):
"""Create Z-Wave entity device."""
temp_unit = hass.config.units.temperature_unit
if values.primary.command_class == const.COMMAND_CLASS_THERMOSTAT_SETPOINT:
return ZWaveClimateSingleSetpoint(values, temp_unit)
if values.primary.command_class == const.COMMAND_CLASS_THERMOSTAT_MODE:
return ZWaveClimateMultipleSetpoint(values, temp_unit)
return None
class ZWaveClimateBase(ZWaveDeviceEntity, ClimateEntity):
"""Representation of a Z-Wave Climate device."""
def __init__(self, values, temp_unit):
"""Initialize the Z-Wave climate device."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self._target_temperature = None
self._target_temperature_range = (None, None)
self._current_temperature = None
self._hvac_action = None
self._hvac_list = None # [zwave_mode]
self._hvac_mapping = None # {ha_mode:zwave_mode}
self._hvac_mode = None # ha_mode
self._aux_heat = None
self._default_hvac_mode = None # ha_mode
self._preset_mapping = None # {ha_mode:zwave_mode}
self._preset_list = None # [zwave_mode]
self._preset_mode = None # ha_mode if exists, else zwave_mode
self._current_fan_mode = None
self._fan_modes = None
self._fan_action = None
self._current_swing_mode = None
self._swing_modes = None
self._unit = temp_unit
_LOGGER.debug("temp_unit is %s", self._unit)
self._zxt_120 = None
# Make sure that we have values for the key before converting to int
if self.node.manufacturer_id.strip() and self.node.product_id.strip():
specific_sensor_key = (
int(self.node.manufacturer_id, 16),
int(self.node.product_id, 16),
)
if (
specific_sensor_key in DEVICE_MAPPINGS
and DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_ZXT_120
):
_LOGGER.debug("Remotec ZXT-120 Zwave Thermostat workaround")
self._zxt_120 = 1
self.update_properties()
def _mode(self) -> None:
"""Return thermostat mode Z-Wave value."""
raise NotImplementedError()
def _current_mode_setpoints(self) -> tuple:
"""Return a tuple of current setpoint Z-Wave value(s)."""
raise NotImplementedError()
@property
def supported_features(self):
"""Return the list of supported features."""
support = SUPPORT_TARGET_TEMPERATURE
if self._hvac_list and HVAC_MODE_HEAT_COOL in self._hvac_list:
support |= SUPPORT_TARGET_TEMPERATURE_RANGE
if self._preset_list and PRESET_AWAY in self._preset_list:
support |= SUPPORT_TARGET_TEMPERATURE_RANGE
if self.values.fan_mode:
support |= SUPPORT_FAN_MODE
if self._zxt_120 == 1 and self.values.zxt_120_swing_mode:
support |= SUPPORT_SWING_MODE
if self._aux_heat:
support |= SUPPORT_AUX_HEAT
if self._preset_list:
support |= SUPPORT_PRESET_MODE
return support
def update_properties(self):
"""Handle the data changes for node values."""
# Operation Mode
self._update_operation_mode()
# Current Temp
self._update_current_temp()
# Fan Mode
self._update_fan_mode()
# Swing mode
self._update_swing_mode()
# Set point
self._update_target_temp()
# Operating state
self._update_operating_state()
# Fan operating state
self._update_fan_state()
def _update_operation_mode(self):
"""Update hvac and preset modes."""
if self._mode():
self._hvac_list = []
self._hvac_mapping = {}
self._preset_list = []
self._preset_mapping = {}
if mode_list := self._mode().data_items:
for mode in mode_list:
ha_mode = HVAC_STATE_MAPPINGS.get(str(mode).lower())
ha_preset = PRESET_MAPPINGS.get(str(mode).lower())
if mode == AUX_HEAT_ZWAVE_MODE:
# Aux Heat should not be included in any mapping
self._aux_heat = True
elif ha_mode and ha_mode not in self._hvac_mapping:
self._hvac_mapping[ha_mode] = mode
self._hvac_list.append(ha_mode)
elif ha_preset and ha_preset not in self._preset_mapping:
self._preset_mapping[ha_preset] = mode
self._preset_list.append(ha_preset)
else:
# If nothing matches
self._preset_list.append(mode)
# Default operation mode
for mode in DEFAULT_HVAC_MODES:
if mode in self._hvac_mapping:
self._default_hvac_mode = mode
break
if self._preset_list:
# Presets are supported
self._preset_list.append(PRESET_NONE)
current_mode = self._mode().data
_LOGGER.debug("current_mode=%s", current_mode)
_hvac_temp = next(
(
key
for key, value in self._hvac_mapping.items()
if value == current_mode
),
None,
)
if _hvac_temp is None:
# The current mode is not a hvac mode
if (
"heat" in current_mode.lower()
and HVAC_MODE_HEAT in self._hvac_mapping
):
# The current preset modes maps to HVAC_MODE_HEAT
_LOGGER.debug("Mapped to HEAT")
self._hvac_mode = HVAC_MODE_HEAT
elif (
"cool" in current_mode.lower()
and HVAC_MODE_COOL in self._hvac_mapping
):
# The current preset modes maps to HVAC_MODE_COOL
_LOGGER.debug("Mapped to COOL")
self._hvac_mode = HVAC_MODE_COOL
else:
# The current preset modes maps to self._default_hvac_mode
_LOGGER.debug("Mapped to DEFAULT")
self._hvac_mode = self._default_hvac_mode
self._preset_mode = next(
(
key
for key, value in self._preset_mapping.items()
if value == current_mode
),
current_mode,
)
else:
# The current mode is a hvac mode
self._hvac_mode = _hvac_temp
self._preset_mode = PRESET_NONE
_LOGGER.debug("self._hvac_mapping=%s", self._hvac_mapping)
_LOGGER.debug("self._hvac_list=%s", self._hvac_list)
_LOGGER.debug("self._hvac_mode=%s", self._hvac_mode)
_LOGGER.debug("self._default_hvac_mode=%s", self._default_hvac_mode)
_LOGGER.debug("self._hvac_action=%s", self._hvac_action)
_LOGGER.debug("self._aux_heat=%s", self._aux_heat)
_LOGGER.debug("self._preset_mapping=%s", self._preset_mapping)
_LOGGER.debug("self._preset_list=%s", self._preset_list)
_LOGGER.debug("self._preset_mode=%s", self._preset_mode)
def _update_current_temp(self):
"""Update current temperature."""
if self.values.temperature:
self._current_temperature = self.values.temperature.data
device_unit = self.values.temperature.units
if device_unit is not None:
self._unit = device_unit
def _update_fan_mode(self):
"""Update fan mode."""
if self.values.fan_mode:
self._current_fan_mode = self.values.fan_mode.data
if fan_modes := self.values.fan_mode.data_items:
self._fan_modes = list(fan_modes)
_LOGGER.debug("self._fan_modes=%s", self._fan_modes)
_LOGGER.debug("self._current_fan_mode=%s", self._current_fan_mode)
def _update_swing_mode(self):
"""Update swing mode."""
if self._zxt_120 == 1:
if self.values.zxt_120_swing_mode:
self._current_swing_mode = self.values.zxt_120_swing_mode.data
swing_modes = self.values.zxt_120_swing_mode.data_items
if swing_modes:
self._swing_modes = list(swing_modes)
_LOGGER.debug("self._swing_modes=%s", self._swing_modes)
_LOGGER.debug("self._current_swing_mode=%s", self._current_swing_mode)
def _update_target_temp(self):
"""Update target temperature."""
current_setpoints = self._current_mode_setpoints()
self._target_temperature = None
self._target_temperature_range = (None, None)
if len(current_setpoints) == 1:
(setpoint,) = current_setpoints
if setpoint is not None:
self._target_temperature = round((float(setpoint.data)), 1)
elif len(current_setpoints) == 2:
(setpoint_low, setpoint_high) = current_setpoints
target_low, target_high = None, None
if setpoint_low is not None:
target_low = round((float(setpoint_low.data)), 1)
if setpoint_high is not None:
target_high = round((float(setpoint_high.data)), 1)
self._target_temperature_range = (target_low, target_high)
def _update_operating_state(self):
"""Update operating state."""
if self.values.operating_state:
mode = self.values.operating_state.data
self._hvac_action = HVAC_CURRENT_MAPPINGS.get(str(mode).lower(), mode)
def _update_fan_state(self):
"""Update fan state."""
if self.values.fan_action:
self._fan_action = self.values.fan_action.data
@property
def fan_mode(self):
"""Return the fan speed set."""
return self._current_fan_mode
@property
def fan_modes(self):
"""Return a list of available fan modes."""
return self._fan_modes
@property
def swing_mode(self):
"""Return the swing mode set."""
return self._current_swing_mode
@property
def swing_modes(self):
"""Return a list of available swing modes."""
return self._swing_modes
@property
def temperature_unit(self):
"""Return the unit of measurement."""
if self._unit == "C":
return TEMP_CELSIUS
if self._unit == "F":
return TEMP_FAHRENHEIT
return self._unit
@property
def current_temperature(self):
"""Return the current temperature."""
return self._current_temperature
@property
def hvac_mode(self):
"""Return hvac operation ie. heat, cool mode.
Need to be one of HVAC_MODE_*.
"""
if self._mode():
return self._hvac_mode
return self._default_hvac_mode
@property
def hvac_modes(self):
"""Return the list of available hvac operation modes.
Need to be a subset of HVAC_MODES.
"""
if self._mode():
return self._hvac_list
return []
@property
def hvac_action(self):
"""Return the current running hvac operation if supported.
Need to be one of CURRENT_HVAC_*.
"""
return self._hvac_action
@property
def is_aux_heat(self):
"""Return true if aux heater."""
if not self._aux_heat:
return None
if self._mode().data == AUX_HEAT_ZWAVE_MODE:
return True
return False
@property
def preset_mode(self):
"""Return preset operation ie. eco, away.
Need to be one of PRESET_*.
"""
if self._mode():
return self._preset_mode
return PRESET_NONE
@property
def preset_modes(self):
"""Return the list of available preset operation modes.
Need to be a subset of PRESET_MODES.
"""
if self._mode():
return self._preset_list
return []
@property
def target_temperature(self):
"""Return the temperature we try to reach."""
return self._target_temperature
@property
def target_temperature_low(self) -> float | None:
"""Return the lowbound target temperature we try to reach."""
return self._target_temperature_range[0]
@property
def target_temperature_high(self) -> float | None:
"""Return the highbound target temperature we try to reach."""
return self._target_temperature_range[1]
def set_temperature(self, **kwargs):
"""Set new target temperature."""
current_setpoints = self._current_mode_setpoints()
if len(current_setpoints) == 1:
(setpoint,) = current_setpoints
target_temp = kwargs.get(ATTR_TEMPERATURE)
if setpoint is not None and target_temp is not None:
_LOGGER.debug("Set temperature to %s", target_temp)
setpoint.data = target_temp
elif len(current_setpoints) == 2:
(setpoint_low, setpoint_high) = current_setpoints
target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW)
target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
if setpoint_low is not None and target_temp_low is not None:
_LOGGER.debug("Set low temperature to %s", target_temp_low)
setpoint_low.data = target_temp_low
if setpoint_high is not None and target_temp_high is not None:
_LOGGER.debug("Set high temperature to %s", target_temp_high)
setpoint_high.data = target_temp_high
def set_fan_mode(self, fan_mode):
"""Set new target fan mode."""
_LOGGER.debug("Set fan mode to %s", fan_mode)
if not self.values.fan_mode:
return
self.values.fan_mode.data = fan_mode
def set_hvac_mode(self, hvac_mode):
"""Set new target hvac mode."""
_LOGGER.debug("Set hvac_mode to %s", hvac_mode)
if not self._mode():
return
operation_mode = self._hvac_mapping.get(hvac_mode)
_LOGGER.debug("Set operation_mode to %s", operation_mode)
self._mode().data = operation_mode
def turn_aux_heat_on(self):
"""Turn auxiliary heater on."""
if not self._aux_heat:
return
operation_mode = AUX_HEAT_ZWAVE_MODE
_LOGGER.debug("Aux heat on. Set operation mode to %s", operation_mode)
self._mode().data = operation_mode
def turn_aux_heat_off(self):
"""Turn auxiliary heater off."""
if not self._aux_heat:
return
if HVAC_MODE_HEAT in self._hvac_mapping:
operation_mode = self._hvac_mapping.get(HVAC_MODE_HEAT)
else:
operation_mode = self._hvac_mapping.get(HVAC_MODE_OFF)
_LOGGER.debug("Aux heat off. Set operation mode to %s", operation_mode)
self._mode().data = operation_mode
def set_preset_mode(self, preset_mode):
"""Set new target preset mode."""
_LOGGER.debug("Set preset_mode to %s", preset_mode)
if not self._mode():
return
if preset_mode == PRESET_NONE:
# Activate the current hvac mode
self._update_operation_mode()
operation_mode = self._hvac_mapping.get(self.hvac_mode)
_LOGGER.debug("Set operation_mode to %s", operation_mode)
self._mode().data = operation_mode
else:
operation_mode = self._preset_mapping.get(preset_mode, preset_mode)
_LOGGER.debug("Set operation_mode to %s", operation_mode)
self._mode().data = operation_mode
def set_swing_mode(self, swing_mode):
"""Set new target swing mode."""
_LOGGER.debug("Set swing_mode to %s", swing_mode)
if self._zxt_120 == 1 and self.values.zxt_120_swing_mode:
self.values.zxt_120_swing_mode.data = swing_mode
@property
def extra_state_attributes(self):
"""Return the optional state attributes."""
data = super().extra_state_attributes
if self._fan_action:
data[ATTR_FAN_ACTION] = self._fan_action
return data
class ZWaveClimateSingleSetpoint(ZWaveClimateBase):
"""Representation of a single setpoint Z-Wave thermostat device."""
def __init__(self, values, temp_unit):
"""Initialize the Z-Wave climate device."""
ZWaveClimateBase.__init__(self, values, temp_unit)
def _mode(self) -> None:
"""Return thermostat mode Z-Wave value."""
return self.values.mode
def _current_mode_setpoints(self) -> tuple:
"""Return a tuple of current setpoint Z-Wave value(s)."""
return (self.values.primary,)
class ZWaveClimateMultipleSetpoint(ZWaveClimateBase):
"""Representation of a multiple setpoint Z-Wave thermostat device."""
def __init__(self, values, temp_unit):
"""Initialize the Z-Wave climate device."""
ZWaveClimateBase.__init__(self, values, temp_unit)
def _mode(self) -> None:
"""Return thermostat mode Z-Wave value."""
return self.values.primary
def _current_mode_setpoints(self) -> tuple:
"""Return a tuple of current setpoint Z-Wave value(s)."""
current_mode = str(self.values.primary.data).lower()
setpoints_names = MODE_SETPOINT_MAPPINGS.get(current_mode, ())
return tuple(getattr(self.values, name, None) for name in setpoints_names)

View File

@ -1,95 +0,0 @@
"""Config flow to configure Z-Wave."""
# pylint: disable=import-error
# pylint: disable=import-outside-toplevel
from collections import OrderedDict
import voluptuous as vol
from homeassistant import config_entries
from .const import (
CONF_NETWORK_KEY,
CONF_USB_STICK_PATH,
DEFAULT_CONF_USB_STICK_PATH,
DOMAIN,
)
class ZwaveFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a Z-Wave config flow."""
VERSION = 1
def __init__(self):
"""Initialize the Z-Wave config flow."""
self.usb_path = CONF_USB_STICK_PATH
async def async_step_user(self, user_input=None):
"""Handle a flow start."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
errors = {}
fields = OrderedDict()
fields[
vol.Required(CONF_USB_STICK_PATH, default=DEFAULT_CONF_USB_STICK_PATH)
] = str
fields[vol.Optional(CONF_NETWORK_KEY)] = str
if user_input is not None:
# Check if USB path is valid
from openzwave.object import ZWaveException
from openzwave.option import ZWaveOption
try:
from functools import partial
option = await self.hass.async_add_executor_job( # noqa: F841 pylint: disable=unused-variable
partial(
ZWaveOption,
user_input[CONF_USB_STICK_PATH],
user_path=self.hass.config.config_dir,
)
)
except ZWaveException:
errors["base"] = "option_error"
return self.async_show_form(
step_id="user", data_schema=vol.Schema(fields), errors=errors
)
if user_input.get(CONF_NETWORK_KEY) is None:
# Generate a random key
from random import choice
key = ""
for i in range(16):
key += "0x"
key += choice("1234567890ABCDEF")
key += choice("1234567890ABCDEF")
if i < 15:
key += ", "
user_input[CONF_NETWORK_KEY] = key
return self.async_create_entry(
title="Z-Wave",
data={
CONF_USB_STICK_PATH: user_input[CONF_USB_STICK_PATH],
CONF_NETWORK_KEY: user_input[CONF_NETWORK_KEY],
},
)
return self.async_show_form(step_id="user", data_schema=vol.Schema(fields))
async def async_step_import(self, info):
"""Import existing configuration from Z-Wave."""
if self._async_current_entries():
return self.async_abort(reason="already_setup")
return self.async_create_entry(
title="Z-Wave (import from configuration.yaml)",
data={
CONF_USB_STICK_PATH: info.get(CONF_USB_STICK_PATH),
CONF_NETWORK_KEY: info.get(CONF_NETWORK_KEY),
},
)

View File

@ -1,395 +0,0 @@
"""Z-Wave Constants."""
DOMAIN = "zwave"
ATTR_NODE_ID = "node_id"
ATTR_TARGET_NODE_ID = "target_node_id"
ATTR_ASSOCIATION = "association"
ATTR_INSTANCE = "instance"
ATTR_GROUP = "group"
ATTR_VALUE_ID = "value_id"
ATTR_MESSAGES = "messages"
ATTR_RETURN_ROUTES = "return_routes"
ATTR_SCENE_ID = "scene_id"
ATTR_SCENE_DATA = "scene_data"
ATTR_BASIC_LEVEL = "basic_level"
ATTR_CONFIG_PARAMETER = "parameter"
ATTR_CONFIG_SIZE = "size"
ATTR_CONFIG_VALUE = "value"
ATTR_POLL_INTENSITY = "poll_intensity"
ATTR_VALUE_INDEX = "value_index"
ATTR_VALUE_INSTANCE = "value_instance"
ATTR_UPDATE_IDS = "update_ids"
NETWORK_READY_WAIT_SECS = 300
NODE_READY_WAIT_SECS = 30
CONF_AUTOHEAL = "autoheal"
CONF_DEBUG = "debug"
CONF_POLLING_INTERVAL = "polling_interval"
CONF_USB_STICK_PATH = "usb_path"
CONF_CONFIG_PATH = "config_path"
CONF_NETWORK_KEY = "network_key"
DEFAULT_CONF_AUTOHEAL = False
DEFAULT_CONF_USB_STICK_PATH = "/zwaveusbstick"
DEFAULT_POLLING_INTERVAL = 60000
DEFAULT_DEBUG = False
DISCOVERY_DEVICE = "device"
DATA_DEVICES = "zwave_devices"
DATA_NETWORK = "zwave_network"
DATA_ENTITY_VALUES = "zwave_entity_values"
DATA_ZWAVE_CONFIG = "zwave_config"
SERVICE_CHANGE_ASSOCIATION = "change_association"
SERVICE_ADD_NODE = "add_node"
SERVICE_ADD_NODE_SECURE = "add_node_secure"
SERVICE_REMOVE_NODE = "remove_node"
SERVICE_CANCEL_COMMAND = "cancel_command"
SERVICE_HEAL_NETWORK = "heal_network"
SERVICE_HEAL_NODE = "heal_node"
SERVICE_SOFT_RESET = "soft_reset"
SERVICE_TEST_NODE = "test_node"
SERVICE_TEST_NETWORK = "test_network"
SERVICE_SET_CONFIG_PARAMETER = "set_config_parameter"
SERVICE_SET_NODE_VALUE = "set_node_value"
SERVICE_REFRESH_NODE_VALUE = "refresh_node_value"
SERVICE_PRINT_CONFIG_PARAMETER = "print_config_parameter"
SERVICE_PRINT_NODE = "print_node"
SERVICE_REMOVE_FAILED_NODE = "remove_failed_node"
SERVICE_REPLACE_FAILED_NODE = "replace_failed_node"
SERVICE_SET_POLL_INTENSITY = "set_poll_intensity"
SERVICE_SET_WAKEUP = "set_wakeup"
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"
EVENT_SCENE_ACTIVATED = "zwave.scene_activated"
EVENT_NODE_EVENT = "zwave.node_event"
EVENT_NETWORK_READY = "zwave.network_ready"
EVENT_NETWORK_COMPLETE = "zwave.network_complete"
EVENT_NETWORK_COMPLETE_SOME_DEAD = "zwave.network_complete_some_dead"
EVENT_NETWORK_START = "zwave.network_start"
EVENT_NETWORK_STOP = "zwave.network_stop"
COMMAND_CLASS_ALARM = 113
COMMAND_CLASS_ANTITHEFT = 93
COMMAND_CLASS_APPLICATION_CAPABILITY = 87
COMMAND_CLASS_APPLICATION_STATUS = 34
COMMAND_CLASS_ASSOCIATION = 133
COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION = 155
COMMAND_CLASS_ASSOCIATION_GRP_INFO = 89
COMMAND_CLASS_BARRIER_OPERATOR = 102
COMMAND_CLASS_BASIC = 32
COMMAND_CLASS_BASIC_TARIFF_INFO = 54
COMMAND_CLASS_BASIC_WINDOW_COVERING = 80
COMMAND_CLASS_BATTERY = 128
COMMAND_CLASS_CENTRAL_SCENE = 91
COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE = 70
COMMAND_CLASS_CLOCK = 129
COMMAND_CLASS_CONFIGURATION = 112
COMMAND_CLASS_CONTROLLER_REPLICATION = 33
COMMAND_CLASS_CRC_16_ENCAP = 86
COMMAND_CLASS_DCP_CONFIG = 58
COMMAND_CLASS_DCP_MONITOR = 59
COMMAND_CLASS_DEVICE_RESET_LOCALLY = 90
COMMAND_CLASS_DOOR_LOCK = 98
COMMAND_CLASS_DOOR_LOCK_LOGGING = 76
COMMAND_CLASS_ENERGY_PRODUCTION = 144
COMMAND_CLASS_ENTRY_CONTROL = 111
COMMAND_CLASS_FIRMWARE_UPDATE_MD = 122
COMMAND_CLASS_GEOGRAPHIC_LOCATION = 140
COMMAND_CLASS_GROUPING_NAME = 123
COMMAND_CLASS_HAIL = 130
COMMAND_CLASS_HRV_CONTROL = 57
COMMAND_CLASS_HRV_STATUS = 55
COMMAND_CLASS_HUMIDITY_CONTROL_MODE = 109
COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE = 110
COMMAND_CLASS_HUMIDITY_CONTROL_SETPOINT = 100
COMMAND_CLASS_INDICATOR = 135
COMMAND_CLASS_IP_ASSOCIATION = 92
COMMAND_CLASS_IP_CONFIGURATION = 14
COMMAND_CLASS_IRRIGATION = 107
COMMAND_CLASS_LANGUAGE = 137
COMMAND_CLASS_LOCK = 118
COMMAND_CLASS_MAILBOX = 105
COMMAND_CLASS_MANUFACTURER_PROPRIETARY = 145
COMMAND_CLASS_MANUFACTURER_SPECIFIC = 114
COMMAND_CLASS_MARK = 239
COMMAND_CLASS_METER = 50
COMMAND_CLASS_METER_PULSE = 53
COMMAND_CLASS_METER_TBL_CONFIG = 60
COMMAND_CLASS_METER_TBL_MONITOR = 61
COMMAND_CLASS_METER_TBL_PUSH = 62
COMMAND_CLASS_MTP_WINDOW_COVERING = 81
COMMAND_CLASS_MULTI_CHANNEL = 96
COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION = 142
COMMAND_CLASS_MULTI_COMMAND = 143
COMMAND_CLASS_NETWORK_MANAGEMENT_BASIC = 77
COMMAND_CLASS_NETWORK_MANAGEMENT_INCLUSION = 52
COMMAND_CLASS_NETWORK_MANAGEMENT_PRIMARY = 84
COMMAND_CLASS_NETWORK_MANAGEMENT_PROXY = 82
COMMAND_CLASS_NO_OPERATION = 0
COMMAND_CLASS_NODE_NAMING = 119
COMMAND_CLASS_NON_INTEROPERABLE = 240
COMMAND_CLASS_NOTIFICATION = 113
COMMAND_CLASS_POWERLEVEL = 115
COMMAND_CLASS_PREPAYMENT = 63
COMMAND_CLASS_PREPAYMENT_ENCAPSULATION = 65
COMMAND_CLASS_PROPRIETARY = 136
COMMAND_CLASS_PROTECTION = 117
COMMAND_CLASS_RATE_TBL_CONFIG = 72
COMMAND_CLASS_RATE_TBL_MONITOR = 73
COMMAND_CLASS_REMOTE_ASSOCIATION_ACTIVATE = 124
COMMAND_CLASS_REMOTE_ASSOCIATION = 125
COMMAND_CLASS_SCENE_ACTIVATION = 43
COMMAND_CLASS_SCENE_ACTUATOR_CONF = 44
COMMAND_CLASS_SCENE_CONTROLLER_CONF = 45
COMMAND_CLASS_SCHEDULE = 83
COMMAND_CLASS_SCHEDULE_ENTRY_LOCK = 78
COMMAND_CLASS_SCREEN_ATTRIBUTES = 147
COMMAND_CLASS_SCREEN_MD = 146
COMMAND_CLASS_SECURITY = 152
COMMAND_CLASS_SECURITY_SCHEME0_MARK = 61696
COMMAND_CLASS_SENSOR_ALARM = 156
COMMAND_CLASS_SENSOR_BINARY = 48
COMMAND_CLASS_SENSOR_CONFIGURATION = 158
COMMAND_CLASS_SENSOR_MULTILEVEL = 49
COMMAND_CLASS_SILENCE_ALARM = 157
COMMAND_CLASS_SIMPLE_AV_CONTROL = 148
COMMAND_CLASS_SUPERVISION = 108
COMMAND_CLASS_SWITCH_ALL = 39
COMMAND_CLASS_SWITCH_BINARY = 37
COMMAND_CLASS_SWITCH_COLOR = 51
COMMAND_CLASS_SWITCH_MULTILEVEL = 38
COMMAND_CLASS_SWITCH_TOGGLE_BINARY = 40
COMMAND_CLASS_SWITCH_TOGGLE_MULTILEVEL = 41
COMMAND_CLASS_TARIFF_TBL_CONFIG = 74
COMMAND_CLASS_TARIFF_TBL_MONITOR = 75
COMMAND_CLASS_THERMOSTAT_FAN_MODE = 68
COMMAND_CLASS_THERMOSTAT_FAN_ACTION = 69
COMMAND_CLASS_THERMOSTAT_MODE = 64
COMMAND_CLASS_THERMOSTAT_OPERATING_STATE = 66
COMMAND_CLASS_THERMOSTAT_SETBACK = 71
COMMAND_CLASS_THERMOSTAT_SETPOINT = 67
COMMAND_CLASS_TIME = 138
COMMAND_CLASS_TIME_PARAMETERS = 139
COMMAND_CLASS_TRANSPORT_SERVICE = 85
COMMAND_CLASS_USER_CODE = 99
COMMAND_CLASS_VERSION = 134
COMMAND_CLASS_WAKE_UP = 132
COMMAND_CLASS_ZIP = 35
COMMAND_CLASS_ZIP_NAMING = 104
COMMAND_CLASS_ZIP_ND = 88
COMMAND_CLASS_ZIP_6LOWPAN = 79
COMMAND_CLASS_ZIP_GATEWAY = 95
COMMAND_CLASS_ZIP_PORTAL = 97
COMMAND_CLASS_ZWAVEPLUS_INFO = 94
COMMAND_CLASS_WHATEVER = None # Match ALL
COMMAND_CLASS_WINDOW_COVERING = 106
GENERIC_TYPE_WHATEVER = None # Match ALL
SPECIFIC_TYPE_WHATEVER = None # Match ALL
SPECIFIC_TYPE_NOT_USED = 0 # Available in all Generic types
GENERIC_TYPE_AV_CONTROL_POINT = 3
SPECIFIC_TYPE_DOORBELL = 18
SPECIFIC_TYPE_SATELLITE_RECEIVER = 4
SPECIFIC_TYPE_SATELLITE_RECEIVER_V2 = 17
GENERIC_TYPE_DISPLAY = 4
SPECIFIC_TYPE_SIMPLE_DISPLAY = 1
GENERIC_TYPE_ENTRY_CONTROL = 64
SPECIFIC_TYPE_DOOR_LOCK = 1
SPECIFIC_TYPE_ADVANCED_DOOR_LOCK = 2
SPECIFIC_TYPE_SECURE_KEYPAD_DOOR_LOCK = 3
SPECIFIC_TYPE_SECURE_KEYPAD_DOOR_LOCK_DEADBOLT = 4
SPECIFIC_TYPE_SECURE_DOOR = 5
SPECIFIC_TYPE_SECURE_GATE = 6
SPECIFIC_TYPE_SECURE_BARRIER_ADDON = 7
SPECIFIC_TYPE_SECURE_BARRIER_OPEN_ONLY = 8
SPECIFIC_TYPE_SECURE_BARRIER_CLOSE_ONLY = 9
SPECIFIC_TYPE_SECURE_LOCKBOX = 10
SPECIFIC_TYPE_SECURE_KEYPAD = 11
GENERIC_TYPE_GENERIC_CONTROLLER = 1
SPECIFIC_TYPE_PORTABLE_CONTROLLER = 1
SPECIFIC_TYPE_PORTABLE_SCENE_CONTROLLER = 2
SPECIFIC_TYPE_PORTABLE_INSTALLER_TOOL = 3
SPECIFIC_TYPE_REMOTE_CONTROL_AV = 4
SPECIFIC_TYPE_REMOTE_CONTROL_SIMPLE = 6
GENERIC_TYPE_METER = 49
SPECIFIC_TYPE_SIMPLE_METER = 1
SPECIFIC_TYPE_ADV_ENERGY_CONTROL = 2
SPECIFIC_TYPE_WHOLE_HOME_METER_SIMPLE = 3
GENERIC_TYPE_METER_PULSE = 48
GENERIC_TYPE_NON_INTEROPERABLE = 255
GENERIC_TYPE_REPEATER_SLAVE = 15
SPECIFIC_TYPE_REPEATER_SLAVE = 1
SPECIFIC_TYPE_VIRTUAL_NODE = 2
GENERIC_TYPE_SECURITY_PANEL = 23
SPECIFIC_TYPE_ZONED_SECURITY_PANEL = 1
GENERIC_TYPE_SEMI_INTEROPERABLE = 80
SPECIFIC_TYPE_ENERGY_PRODUCTION = 1
GENERIC_TYPE_SENSOR_ALARM = 161
SPECIFIC_TYPE_ADV_ZENSOR_NET_ALARM_SENSOR = 5
SPECIFIC_TYPE_ADV_ZENSOR_NET_SMOKE_SENSOR = 10
SPECIFIC_TYPE_BASIC_ROUTING_ALARM_SENSOR = 1
SPECIFIC_TYPE_BASIC_ROUTING_SMOKE_SENSOR = 6
SPECIFIC_TYPE_BASIC_ZENSOR_NET_ALARM_SENSOR = 3
SPECIFIC_TYPE_BASIC_ZENSOR_NET_SMOKE_SENSOR = 8
SPECIFIC_TYPE_ROUTING_ALARM_SENSOR = 2
SPECIFIC_TYPE_ROUTING_SMOKE_SENSOR = 7
SPECIFIC_TYPE_ZENSOR_NET_ALARM_SENSOR = 4
SPECIFIC_TYPE_ZENSOR_NET_SMOKE_SENSOR = 9
SPECIFIC_TYPE_ALARM_SENSOR = 11
GENERIC_TYPE_SENSOR_BINARY = 32
SPECIFIC_TYPE_ROUTING_SENSOR_BINARY = 1
GENERIC_TYPE_SENSOR_MULTILEVEL = 33
SPECIFIC_TYPE_ROUTING_SENSOR_MULTILEVEL = 1
SPECIFIC_TYPE_CHIMNEY_FAN = 2
GENERIC_TYPE_STATIC_CONTROLLER = 2
SPECIFIC_TYPE_PC_CONTROLLER = 1
SPECIFIC_TYPE_SCENE_CONTROLLER = 2
SPECIFIC_TYPE_STATIC_INSTALLER_TOOL = 3
SPECIFIC_TYPE_SET_TOP_BOX = 4
SPECIFIC_TYPE_SUB_SYSTEM_CONTROLLER = 5
SPECIFIC_TYPE_TV = 6
SPECIFIC_TYPE_GATEWAY = 7
GENERIC_TYPE_SWITCH_BINARY = 16
SPECIFIC_TYPE_POWER_SWITCH_BINARY = 1
SPECIFIC_TYPE_SCENE_SWITCH_BINARY = 3
SPECIFIC_TYPE_POWER_STRIP = 4
SPECIFIC_TYPE_SIREN = 5
SPECIFIC_TYPE_VALVE_OPEN_CLOSE = 6
SPECIFIC_TYPE_COLOR_TUNABLE_BINARY = 2
SPECIFIC_TYPE_IRRIGATION_CONTROLLER = 7
GENERIC_TYPE_SWITCH_MULTILEVEL = 17
SPECIFIC_TYPE_CLASS_A_MOTOR_CONTROL = 5
SPECIFIC_TYPE_CLASS_B_MOTOR_CONTROL = 6
SPECIFIC_TYPE_CLASS_C_MOTOR_CONTROL = 7
SPECIFIC_TYPE_MOTOR_MULTIPOSITION = 3
SPECIFIC_TYPE_POWER_SWITCH_MULTILEVEL = 1
SPECIFIC_TYPE_SCENE_SWITCH_MULTILEVEL = 4
SPECIFIC_TYPE_FAN_SWITCH = 8
SPECIFIC_TYPE_COLOR_TUNABLE_MULTILEVEL = 2
GENERIC_TYPE_SWITCH_REMOTE = 18
SPECIFIC_TYPE_REMOTE_BINARY = 1
SPECIFIC_TYPE_REMOTE_MULTILEVEL = 2
SPECIFIC_TYPE_REMOTE_TOGGLE_BINARY = 3
SPECIFIC_TYPE_REMOTE_TOGGLE_MULTILEVEL = 4
GENERIC_TYPE_SWITCH_TOGGLE = 19
SPECIFIC_TYPE_SWITCH_TOGGLE_BINARY = 1
SPECIFIC_TYPE_SWITCH_TOGGLE_MULTILEVEL = 2
GENERIC_TYPE_THERMOSTAT = 8
SPECIFIC_TYPE_SETBACK_SCHEDULE_THERMOSTAT = 3
SPECIFIC_TYPE_SETBACK_THERMOSTAT = 5
SPECIFIC_TYPE_SETPOINT_THERMOSTAT = 4
SPECIFIC_TYPE_THERMOSTAT_GENERAL = 2
SPECIFIC_TYPE_THERMOSTAT_GENERAL_V2 = 6
SPECIFIC_TYPE_THERMOSTAT_HEATING = 1
GENERIC_TYPE_VENTILATION = 22
SPECIFIC_TYPE_RESIDENTIAL_HRV = 1
GENERIC_TYPE_WINDOWS_COVERING = 9
SPECIFIC_TYPE_SIMPLE_WINDOW_COVERING = 1
GENERIC_TYPE_ZIP_NODE = 21
SPECIFIC_TYPE_ZIP_ADV_NODE = 2
SPECIFIC_TYPE_ZIP_TUN_NODE = 1
GENERIC_TYPE_WALL_CONTROLLER = 24
SPECIFIC_TYPE_BASIC_WALL_CONTROLLER = 1
GENERIC_TYPE_NETWORK_EXTENDER = 5
SPECIFIC_TYPE_SECURE_EXTENDER = 1
GENERIC_TYPE_APPLIANCE = 6
SPECIFIC_TYPE_GENERAL_APPLIANCE = 1
SPECIFIC_TYPE_KITCHEN_APPLIANCE = 2
SPECIFIC_TYPE_LAUNDRY_APPLIANCE = 3
GENERIC_TYPE_SENSOR_NOTIFICATION = 7
SPECIFIC_TYPE_NOTIFICATION_SENSOR = 1
GENRE_WHATEVER = None
GENRE_USER = "User"
GENRE_SYSTEM = "System"
TYPE_WHATEVER = None
TYPE_BYTE = "Byte"
TYPE_BOOL = "Bool"
TYPE_DECIMAL = "Decimal"
TYPE_INT = "Int"
TYPE_LIST = "List"
TYPE_STRING = "String"
TYPE_BUTTON = "Button"
DISC_COMMAND_CLASS = "command_class"
DISC_COMPONENT = "component"
DISC_GENERIC_DEVICE_CLASS = "generic_device_class"
DISC_GENRE = "genre"
DISC_INDEX = "index"
DISC_INSTANCE = "instance"
DISC_NODE_ID = "node_id"
DISC_OPTIONAL = "optional"
DISC_PRIMARY = "primary"
DISC_SCHEMAS = "schemas"
DISC_SPECIFIC_DEVICE_CLASS = "specific_device_class"
DISC_TYPE = "type"
DISC_VALUES = "values"
# https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/Alarm.cpp#L49
# See also:
# https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/Alarm.cpp#L275
# https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/Alarm.cpp#L278
INDEX_ALARM_TYPE = 0
INDEX_ALARM_LEVEL = 1
INDEX_ALARM_ACCESS_CONTROL = 9
# https://github.com/OpenZWave/open-zwave/blob/de1c0e60edf1d1bee81f1ae54b1f58e66c6fd8ed/cpp/src/command_classes/BarrierOperator.cpp#L69
INDEX_BARRIER_OPERATOR_LABEL = 1
# https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/DoorLock.cpp#L77
INDEX_DOOR_LOCK_LOCK = 0
# https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/Meter.cpp#L114
# See also:
# https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/Meter.cpp#L279
INDEX_METER_POWER = 8
INDEX_METER_RESET = 33
# https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/SensorMultilevel.cpp#L50
INDEX_SENSOR_MULTILEVEL_TEMPERATURE = 1
INDEX_SENSOR_MULTILEVEL_POWER = 4
# https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/Color.cpp#L109
INDEX_SWITCH_COLOR_COLOR = 0
INDEX_SWITCH_COLOR_CHANNELS = 2
# https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/SwitchMultilevel.cpp#L54
INDEX_SWITCH_MULTILEVEL_LEVEL = 0
INDEX_SWITCH_MULTILEVEL_BRIGHT = 1
INDEX_SWITCH_MULTILEVEL_DIM = 2
INDEX_SWITCH_MULTILEVEL_DURATION = 5

View File

@ -1,216 +0,0 @@
"""Support for Z-Wave covers."""
import logging
from homeassistant.components.cover import (
ATTR_POSITION,
DOMAIN,
SUPPORT_CLOSE,
SUPPORT_OPEN,
CoverDeviceClass,
CoverEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import (
CONF_INVERT_OPENCLOSE_BUTTONS,
CONF_INVERT_PERCENT,
ZWaveDeviceEntity,
workaround,
)
from .const import (
COMMAND_CLASS_BARRIER_OPERATOR,
COMMAND_CLASS_SWITCH_BINARY,
COMMAND_CLASS_SWITCH_MULTILEVEL,
DATA_NETWORK,
)
_LOGGER = logging.getLogger(__name__)
SUPPORT_GARAGE = SUPPORT_OPEN | SUPPORT_CLOSE
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave Cover from Config Entry."""
@callback
def async_add_cover(cover):
"""Add Z-Wave Cover."""
async_add_entities([cover])
async_dispatcher_connect(hass, "zwave_new_cover", async_add_cover)
def get_device(hass, values, node_config, **kwargs):
"""Create Z-Wave entity device."""
invert_buttons = node_config.get(CONF_INVERT_OPENCLOSE_BUTTONS)
invert_percent = node_config.get(CONF_INVERT_PERCENT)
if (
values.primary.command_class == COMMAND_CLASS_SWITCH_MULTILEVEL
and values.primary.index == 0
):
return ZwaveRollershutter(hass, values, invert_buttons, invert_percent)
if values.primary.command_class == COMMAND_CLASS_SWITCH_BINARY:
return ZwaveGarageDoorSwitch(values)
if values.primary.command_class == COMMAND_CLASS_BARRIER_OPERATOR:
return ZwaveGarageDoorBarrier(values)
return None
class ZwaveRollershutter(ZWaveDeviceEntity, CoverEntity):
"""Representation of an Z-Wave cover."""
def __init__(self, hass, values, invert_buttons, invert_percent):
"""Initialize the Z-Wave rollershutter."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self._network = hass.data[DATA_NETWORK]
self._open_id = None
self._close_id = None
self._current_position = None
self._invert_buttons = invert_buttons
self._invert_percent = invert_percent
self._workaround = workaround.get_device_mapping(values.primary)
if self._workaround:
_LOGGER.debug("Using workaround %s", self._workaround)
self.update_properties()
def update_properties(self):
"""Handle data changes for node values."""
# Position value
self._current_position = self.values.primary.data
if (
self.values.open
and self.values.close
and self._open_id is None
and self._close_id is None
):
if self._invert_buttons:
self._open_id = self.values.close.value_id
self._close_id = self.values.open.value_id
else:
self._open_id = self.values.open.value_id
self._close_id = self.values.close.value_id
@property
def is_closed(self):
"""Return if the cover is closed."""
if self.current_cover_position is None:
return None
if self.current_cover_position > 0:
return False
return True
@property
def current_cover_position(self):
"""Return the current position of Zwave roller shutter."""
if self._workaround == workaround.WORKAROUND_NO_POSITION:
return None
if self._current_position is not None:
if self._current_position <= 5:
return 100 if self._invert_percent else 0
if self._current_position >= 95:
return 0 if self._invert_percent else 100
return (
100 - self._current_position
if self._invert_percent
else self._current_position
)
def open_cover(self, **kwargs):
"""Move the roller shutter up."""
self._network.manager.pressButton(self._open_id)
def close_cover(self, **kwargs):
"""Move the roller shutter down."""
self._network.manager.pressButton(self._close_id)
def set_cover_position(self, **kwargs):
"""Move the roller shutter to a specific position."""
self.node.set_dimmer(
self.values.primary.value_id,
(100 - kwargs.get(ATTR_POSITION))
if self._invert_percent
else kwargs.get(ATTR_POSITION),
)
def stop_cover(self, **kwargs):
"""Stop the roller shutter."""
self._network.manager.releaseButton(self._open_id)
class ZwaveGarageDoorBase(ZWaveDeviceEntity, CoverEntity):
"""Base class for a Zwave garage door device."""
def __init__(self, values):
"""Initialize the zwave garage door."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self._state = None
self.update_properties()
def update_properties(self):
"""Handle data changes for node values."""
self._state = self.values.primary.data
_LOGGER.debug("self._state=%s", self._state)
@property
def device_class(self):
"""Return the class of this device, from CoverDeviceClass."""
return CoverDeviceClass.GARAGE
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_GARAGE
class ZwaveGarageDoorSwitch(ZwaveGarageDoorBase):
"""Representation of a switch based Zwave garage door device."""
@property
def is_closed(self):
"""Return the current position of Zwave garage door."""
return not self._state
def close_cover(self, **kwargs):
"""Close the garage door."""
self.values.primary.data = False
def open_cover(self, **kwargs):
"""Open the garage door."""
self.values.primary.data = True
class ZwaveGarageDoorBarrier(ZwaveGarageDoorBase):
"""Representation of a barrier operator Zwave garage door device."""
@property
def is_opening(self):
"""Return true if cover is in an opening state."""
return self._state == "Opening"
@property
def is_closing(self):
"""Return true if cover is in a closing state."""
return self._state == "Closing"
@property
def is_closed(self):
"""Return the current position of Zwave garage door."""
return self._state == "Closed"
def close_cover(self, **kwargs):
"""Close the garage door."""
self.values.primary.data = "Closed"
def open_cover(self, **kwargs):
"""Open the garage door."""
self.values.primary.data = "Opened"

View File

@ -1,416 +0,0 @@
"""Z-Wave discovery schemas."""
from . import const
DEFAULT_VALUES_SCHEMA = {
"power": {
const.DISC_SCHEMAS: [
{
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SENSOR_MULTILEVEL],
const.DISC_INDEX: [const.INDEX_SENSOR_MULTILEVEL_POWER],
},
{
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_METER],
const.DISC_INDEX: [const.INDEX_METER_POWER],
},
],
const.DISC_OPTIONAL: True,
}
}
DISCOVERY_SCHEMAS = [
{
const.DISC_COMPONENT: "binary_sensor",
const.DISC_GENERIC_DEVICE_CLASS: [
const.GENERIC_TYPE_ENTRY_CONTROL,
const.GENERIC_TYPE_SENSOR_ALARM,
const.GENERIC_TYPE_SENSOR_BINARY,
const.GENERIC_TYPE_SWITCH_BINARY,
const.GENERIC_TYPE_METER,
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
const.GENERIC_TYPE_SENSOR_NOTIFICATION,
const.GENERIC_TYPE_THERMOSTAT,
],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SENSOR_BINARY],
const.DISC_TYPE: const.TYPE_BOOL,
const.DISC_GENRE: const.GENRE_USER,
},
"off_delay": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_CONFIGURATION],
const.DISC_INDEX: [9],
const.DISC_OPTIONAL: True,
},
},
),
},
{
const.DISC_COMPONENT: "climate", # thermostat without COMMAND_CLASS_THERMOSTAT_MODE
const.DISC_GENERIC_DEVICE_CLASS: [
const.GENERIC_TYPE_THERMOSTAT,
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
],
const.DISC_SPECIFIC_DEVICE_CLASS: [
const.SPECIFIC_TYPE_THERMOSTAT_HEATING,
const.SPECIFIC_TYPE_SETPOINT_THERMOSTAT,
const.SPECIFIC_TYPE_NOT_USED,
],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT]
},
"temperature": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SENSOR_MULTILEVEL],
const.DISC_INDEX: [const.INDEX_SENSOR_MULTILEVEL_TEMPERATURE],
const.DISC_OPTIONAL: True,
},
"fan_mode": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_FAN_MODE],
const.DISC_OPTIONAL: True,
},
"operating_state": {
const.DISC_COMMAND_CLASS: [
const.COMMAND_CLASS_THERMOSTAT_OPERATING_STATE
],
const.DISC_OPTIONAL: True,
},
"fan_action": {
const.DISC_COMMAND_CLASS: [
const.COMMAND_CLASS_THERMOSTAT_FAN_ACTION
],
const.DISC_OPTIONAL: True,
},
"mode": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_MODE],
const.DISC_OPTIONAL: True,
},
},
),
},
{
const.DISC_COMPONENT: "climate", # thermostat with COMMAND_CLASS_THERMOSTAT_MODE
const.DISC_GENERIC_DEVICE_CLASS: [
const.GENERIC_TYPE_THERMOSTAT,
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
],
const.DISC_SPECIFIC_DEVICE_CLASS: [
const.SPECIFIC_TYPE_THERMOSTAT_GENERAL,
const.SPECIFIC_TYPE_THERMOSTAT_GENERAL_V2,
const.SPECIFIC_TYPE_SETBACK_THERMOSTAT,
],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_MODE]
},
"setpoint_heating": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [1],
const.DISC_OPTIONAL: True,
},
"setpoint_cooling": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [2],
const.DISC_OPTIONAL: True,
},
"setpoint_furnace": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [7],
const.DISC_OPTIONAL: True,
},
"setpoint_dry_air": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [8],
const.DISC_OPTIONAL: True,
},
"setpoint_moist_air": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [9],
const.DISC_OPTIONAL: True,
},
"setpoint_auto_changeover": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [10],
const.DISC_OPTIONAL: True,
},
"setpoint_eco_heating": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [11],
const.DISC_OPTIONAL: True,
},
"setpoint_eco_cooling": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [12],
const.DISC_OPTIONAL: True,
},
"setpoint_away_heating": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [13],
const.DISC_OPTIONAL: True,
},
"setpoint_away_cooling": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [14],
const.DISC_OPTIONAL: True,
},
"setpoint_full_power": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
const.DISC_INDEX: [15],
const.DISC_OPTIONAL: True,
},
"temperature": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SENSOR_MULTILEVEL],
const.DISC_INDEX: [const.INDEX_SENSOR_MULTILEVEL_TEMPERATURE],
const.DISC_OPTIONAL: True,
},
"fan_mode": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_FAN_MODE],
const.DISC_OPTIONAL: True,
},
"operating_state": {
const.DISC_COMMAND_CLASS: [
const.COMMAND_CLASS_THERMOSTAT_OPERATING_STATE
],
const.DISC_OPTIONAL: True,
},
"fan_action": {
const.DISC_COMMAND_CLASS: [
const.COMMAND_CLASS_THERMOSTAT_FAN_ACTION
],
const.DISC_OPTIONAL: True,
},
"zxt_120_swing_mode": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_CONFIGURATION],
const.DISC_INDEX: [33],
const.DISC_OPTIONAL: True,
},
},
),
},
{
const.DISC_COMPONENT: "cover", # Rollershutter
const.DISC_GENERIC_DEVICE_CLASS: [
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
const.GENERIC_TYPE_ENTRY_CONTROL,
],
const.DISC_SPECIFIC_DEVICE_CLASS: [
const.SPECIFIC_TYPE_CLASS_A_MOTOR_CONTROL,
const.SPECIFIC_TYPE_CLASS_B_MOTOR_CONTROL,
const.SPECIFIC_TYPE_CLASS_C_MOTOR_CONTROL,
const.SPECIFIC_TYPE_MOTOR_MULTIPOSITION,
const.SPECIFIC_TYPE_SECURE_BARRIER_ADDON,
const.SPECIFIC_TYPE_SECURE_DOOR,
],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
const.DISC_GENRE: const.GENRE_USER,
},
"open": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
const.DISC_INDEX: [const.INDEX_SWITCH_MULTILEVEL_BRIGHT],
const.DISC_OPTIONAL: True,
},
"close": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
const.DISC_INDEX: [const.INDEX_SWITCH_MULTILEVEL_DIM],
const.DISC_OPTIONAL: True,
},
},
),
},
{
const.DISC_COMPONENT: "cover", # Garage Door Switch
const.DISC_GENERIC_DEVICE_CLASS: [
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
const.GENERIC_TYPE_ENTRY_CONTROL,
],
const.DISC_SPECIFIC_DEVICE_CLASS: [
const.SPECIFIC_TYPE_CLASS_A_MOTOR_CONTROL,
const.SPECIFIC_TYPE_CLASS_B_MOTOR_CONTROL,
const.SPECIFIC_TYPE_CLASS_C_MOTOR_CONTROL,
const.SPECIFIC_TYPE_MOTOR_MULTIPOSITION,
const.SPECIFIC_TYPE_SECURE_BARRIER_ADDON,
const.SPECIFIC_TYPE_SECURE_DOOR,
],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_BINARY],
const.DISC_GENRE: const.GENRE_USER,
}
},
),
},
{
const.DISC_COMPONENT: "cover", # Garage Door Barrier
const.DISC_GENERIC_DEVICE_CLASS: [
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
const.GENERIC_TYPE_ENTRY_CONTROL,
],
const.DISC_SPECIFIC_DEVICE_CLASS: [
const.SPECIFIC_TYPE_CLASS_A_MOTOR_CONTROL,
const.SPECIFIC_TYPE_CLASS_B_MOTOR_CONTROL,
const.SPECIFIC_TYPE_CLASS_C_MOTOR_CONTROL,
const.SPECIFIC_TYPE_MOTOR_MULTIPOSITION,
const.SPECIFIC_TYPE_SECURE_BARRIER_ADDON,
const.SPECIFIC_TYPE_SECURE_DOOR,
],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_BARRIER_OPERATOR],
const.DISC_INDEX: [const.INDEX_BARRIER_OPERATOR_LABEL],
}
},
),
},
{
const.DISC_COMPONENT: "fan",
const.DISC_GENERIC_DEVICE_CLASS: [const.GENERIC_TYPE_SWITCH_MULTILEVEL],
const.DISC_SPECIFIC_DEVICE_CLASS: [const.SPECIFIC_TYPE_FAN_SWITCH],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
const.DISC_INDEX: [const.INDEX_SWITCH_MULTILEVEL_LEVEL],
const.DISC_TYPE: const.TYPE_BYTE,
}
},
),
},
{
const.DISC_COMPONENT: "light",
const.DISC_GENERIC_DEVICE_CLASS: [
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
const.GENERIC_TYPE_SWITCH_REMOTE,
],
const.DISC_SPECIFIC_DEVICE_CLASS: [
const.SPECIFIC_TYPE_POWER_SWITCH_MULTILEVEL,
const.SPECIFIC_TYPE_SCENE_SWITCH_MULTILEVEL,
const.SPECIFIC_TYPE_NOT_USED,
],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
const.DISC_INDEX: [const.INDEX_SWITCH_MULTILEVEL_LEVEL],
const.DISC_TYPE: const.TYPE_BYTE,
},
"dimming_duration": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
const.DISC_INDEX: [const.INDEX_SWITCH_MULTILEVEL_DURATION],
const.DISC_OPTIONAL: True,
},
"color": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_COLOR],
const.DISC_INDEX: [const.INDEX_SWITCH_COLOR_COLOR],
const.DISC_OPTIONAL: True,
},
"color_channels": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_COLOR],
const.DISC_INDEX: [const.INDEX_SWITCH_COLOR_CHANNELS],
const.DISC_OPTIONAL: True,
},
},
),
},
{
const.DISC_COMPONENT: "lock",
const.DISC_GENERIC_DEVICE_CLASS: [const.GENERIC_TYPE_ENTRY_CONTROL],
const.DISC_SPECIFIC_DEVICE_CLASS: [
const.SPECIFIC_TYPE_DOOR_LOCK,
const.SPECIFIC_TYPE_ADVANCED_DOOR_LOCK,
const.SPECIFIC_TYPE_SECURE_KEYPAD_DOOR_LOCK,
const.SPECIFIC_TYPE_SECURE_LOCKBOX,
],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_DOOR_LOCK],
const.DISC_INDEX: [const.INDEX_DOOR_LOCK_LOCK],
},
"access_control": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_ALARM],
const.DISC_INDEX: [const.INDEX_ALARM_ACCESS_CONTROL],
const.DISC_OPTIONAL: True,
},
"alarm_type": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_ALARM],
const.DISC_INDEX: [const.INDEX_ALARM_TYPE],
const.DISC_OPTIONAL: True,
},
"alarm_level": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_ALARM],
const.DISC_INDEX: [const.INDEX_ALARM_LEVEL],
const.DISC_OPTIONAL: True,
},
"v2btze_advanced": {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_CONFIGURATION],
const.DISC_INDEX: [12],
const.DISC_OPTIONAL: True,
},
},
),
},
{
const.DISC_COMPONENT: "sensor",
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [
const.COMMAND_CLASS_SENSOR_MULTILEVEL,
const.COMMAND_CLASS_METER,
const.COMMAND_CLASS_ALARM,
const.COMMAND_CLASS_SENSOR_ALARM,
const.COMMAND_CLASS_INDICATOR,
const.COMMAND_CLASS_BATTERY,
],
const.DISC_GENRE: const.GENRE_USER,
}
},
),
},
{
const.DISC_COMPONENT: "switch",
const.DISC_GENERIC_DEVICE_CLASS: [
const.GENERIC_TYPE_METER,
const.GENERIC_TYPE_SENSOR_ALARM,
const.GENERIC_TYPE_SENSOR_BINARY,
const.GENERIC_TYPE_SWITCH_BINARY,
const.GENERIC_TYPE_ENTRY_CONTROL,
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
const.GENERIC_TYPE_SENSOR_NOTIFICATION,
const.GENERIC_TYPE_GENERIC_CONTROLLER,
const.GENERIC_TYPE_SWITCH_REMOTE,
const.GENERIC_TYPE_REPEATER_SLAVE,
const.GENERIC_TYPE_THERMOSTAT,
const.GENERIC_TYPE_WALL_CONTROLLER,
],
const.DISC_VALUES: dict(
DEFAULT_VALUES_SCHEMA,
**{
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_BINARY],
const.DISC_TYPE: const.TYPE_BOOL,
const.DISC_GENRE: const.GENRE_USER,
}
},
),
},
]

View File

@ -1,86 +0,0 @@
"""Support for Z-Wave fans."""
import math
from homeassistant.components.fan import DOMAIN, SUPPORT_SET_SPEED, FanEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util.percentage import (
int_states_in_range,
percentage_to_ranged_value,
ranged_value_to_percentage,
)
from . import ZWaveDeviceEntity
SUPPORTED_FEATURES = SUPPORT_SET_SPEED
SPEED_RANGE = (1, 99) # off is not included
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave Fan from Config Entry."""
@callback
def async_add_fan(fan):
"""Add Z-Wave Fan."""
async_add_entities([fan])
async_dispatcher_connect(hass, "zwave_new_fan", async_add_fan)
def get_device(values, **kwargs):
"""Create Z-Wave entity device."""
return ZwaveFan(values)
class ZwaveFan(ZWaveDeviceEntity, FanEntity):
"""Representation of a Z-Wave fan."""
def __init__(self, values):
"""Initialize the Z-Wave fan device."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self.update_properties()
def update_properties(self):
"""Handle data changes for node values."""
self._state = self.values.primary.data
def set_percentage(self, percentage):
"""Set the speed percentage of the fan."""
if percentage is None:
# Value 255 tells device to return to previous value
zwave_speed = 255
elif percentage == 0:
zwave_speed = 0
else:
zwave_speed = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage))
self.node.set_dimmer(self.values.primary.value_id, zwave_speed)
def turn_on(self, percentage=None, preset_mode=None, **kwargs):
"""Turn the device on."""
self.set_percentage(percentage)
def turn_off(self, **kwargs):
"""Turn the device off."""
self.node.set_dimmer(self.values.primary.value_id, 0)
@property
def percentage(self):
"""Return the current speed percentage."""
return ranged_value_to_percentage(SPEED_RANGE, self._state)
@property
def speed_count(self) -> int:
"""Return the number of speeds the fan supports."""
return int_states_in_range(SPEED_RANGE)
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORTED_FEATURES

View File

@ -1,407 +0,0 @@
"""Support for Z-Wave lights."""
import logging
from threading import Timer
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_RGB_COLOR,
ATTR_RGBW_COLOR,
ATTR_TRANSITION,
COLOR_MODE_BRIGHTNESS,
COLOR_MODE_COLOR_TEMP,
COLOR_MODE_RGB,
COLOR_MODE_RGBW,
DOMAIN,
SUPPORT_TRANSITION,
LightEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import CONF_REFRESH_DELAY, CONF_REFRESH_VALUE, ZWaveDeviceEntity, const
_LOGGER = logging.getLogger(__name__)
COLOR_CHANNEL_WARM_WHITE = 0x01
COLOR_CHANNEL_COLD_WHITE = 0x02
COLOR_CHANNEL_RED = 0x04
COLOR_CHANNEL_GREEN = 0x08
COLOR_CHANNEL_BLUE = 0x10
# Some bulbs have an independent warm and cool white light LEDs. These need
# to be treated differently, aka the zw098 workaround. Ensure these are added
# to DEVICE_MAPPINGS below.
# (Manufacturer ID, Product ID) from
# https://github.com/OpenZWave/open-zwave/blob/master/config/manufacturer_specific.xml
AEOTEC_ZW098_LED_BULB_LIGHT = (0x86, 0x62)
AEOTEC_ZWA001_LED_BULB_LIGHT = (0x371, 0x1)
AEOTEC_ZWA002_LED_BULB_LIGHT = (0x371, 0x2)
HANK_HKZW_RGB01_LED_BULB_LIGHT = (0x208, 0x4)
ZIPATO_RGB_BULB_2_LED_BULB_LIGHT = (0x131, 0x3)
WORKAROUND_ZW098 = "zw098"
DEVICE_MAPPINGS = {
AEOTEC_ZW098_LED_BULB_LIGHT: WORKAROUND_ZW098,
AEOTEC_ZWA001_LED_BULB_LIGHT: WORKAROUND_ZW098,
AEOTEC_ZWA002_LED_BULB_LIGHT: WORKAROUND_ZW098,
HANK_HKZW_RGB01_LED_BULB_LIGHT: WORKAROUND_ZW098,
ZIPATO_RGB_BULB_2_LED_BULB_LIGHT: WORKAROUND_ZW098,
}
# Generate midpoint color temperatures for bulbs that have limited
# support for white light colors
TEMP_COLOR_MAX = 500 # mireds (inverted)
TEMP_COLOR_MIN = 154
TEMP_MID_HASS = (TEMP_COLOR_MAX - TEMP_COLOR_MIN) / 2 + TEMP_COLOR_MIN
TEMP_WARM_HASS = (TEMP_COLOR_MAX - TEMP_COLOR_MIN) / 3 * 2 + TEMP_COLOR_MIN
TEMP_COLD_HASS = (TEMP_COLOR_MAX - TEMP_COLOR_MIN) / 3 + TEMP_COLOR_MIN
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave Light from Config Entry."""
@callback
def async_add_light(light):
"""Add Z-Wave Light."""
async_add_entities([light])
async_dispatcher_connect(hass, "zwave_new_light", async_add_light)
def get_device(node, values, node_config, **kwargs):
"""Create Z-Wave entity device."""
refresh = node_config.get(CONF_REFRESH_VALUE)
delay = node_config.get(CONF_REFRESH_DELAY)
_LOGGER.debug(
"node=%d value=%d node_config=%s CONF_REFRESH_VALUE=%s"
" CONF_REFRESH_DELAY=%s",
node.node_id,
values.primary.value_id,
node_config,
refresh,
delay,
)
if node.has_command_class(const.COMMAND_CLASS_SWITCH_COLOR):
return ZwaveColorLight(values, refresh, delay)
return ZwaveDimmer(values, refresh, delay)
def brightness_state(value):
"""Return the brightness and state."""
if value.data > 0:
return round((value.data / 99) * 255), STATE_ON
return 0, STATE_OFF
def byte_to_zwave_brightness(value):
"""Convert brightness in 0-255 scale to 0-99 scale.
`value` -- (int) Brightness byte value from 0-255.
"""
if value > 0:
return max(1, round((value / 255) * 99))
return 0
class ZwaveDimmer(ZWaveDeviceEntity, LightEntity):
"""Representation of a Z-Wave dimmer."""
def __init__(self, values, refresh, delay):
"""Initialize the light."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self._brightness = None
self._state = None
self._color_mode = None
self._supported_color_modes = set()
self._supported_features = 0
self._delay = delay
self._refresh_value = refresh
self._zw098 = None
# Enable appropriate workaround flags for our device
# Make sure that we have values for the key before converting to int
if self.node.manufacturer_id.strip() and self.node.product_id.strip():
specific_sensor_key = (
int(self.node.manufacturer_id, 16),
int(self.node.product_id, 16),
)
if (
specific_sensor_key in DEVICE_MAPPINGS
and DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_ZW098
):
_LOGGER.debug("AEOTEC ZW098 workaround enabled")
self._zw098 = 1
# Used for value change event handling
self._refreshing = False
self._timer = None
_LOGGER.debug(
"self._refreshing=%s self.delay=%s", self._refresh_value, self._delay
)
self.value_added()
self.update_properties()
def update_properties(self):
"""Update internal properties based on zwave values."""
# Brightness
self._brightness, self._state = brightness_state(self.values.primary)
def value_added(self):
"""Call when a new value is added to this entity."""
self._supported_color_modes = {COLOR_MODE_BRIGHTNESS}
self._color_mode = COLOR_MODE_BRIGHTNESS
if self.values.dimming_duration is not None:
self._supported_features = SUPPORT_TRANSITION
def value_changed(self):
"""Call when a value for this entity's node has changed."""
if self._refresh_value:
if self._refreshing:
self._refreshing = False
else:
def _refresh_value():
"""Use timer callback for delayed value refresh."""
self._refreshing = True
self.values.primary.refresh()
if self._timer is not None and self._timer.is_alive():
self._timer.cancel()
self._timer = Timer(self._delay, _refresh_value)
self._timer.start()
return
super().value_changed()
@property
def brightness(self):
"""Return the brightness of this light between 0..255."""
return self._brightness
@property
def is_on(self):
"""Return true if device is on."""
return self._state == STATE_ON
@property
def color_mode(self):
"""Return the current color mode."""
return self._color_mode
@property
def supported_color_modes(self):
"""Flag supported color modes."""
return self._supported_color_modes
@property
def supported_features(self):
"""Flag supported features."""
return self._supported_features
def _set_duration(self, **kwargs):
"""Set the transition time for the brightness value.
Zwave Dimming Duration values:
0x00 = instant
0x01-0x7F = 1 second to 127 seconds
0x80-0xFE = 1 minute to 127 minutes
0xFF = factory default
"""
if self.values.dimming_duration is None:
if ATTR_TRANSITION in kwargs:
_LOGGER.debug("Dimming not supported by %s", self.entity_id)
return
if ATTR_TRANSITION not in kwargs:
self.values.dimming_duration.data = 0xFF
return
transition = kwargs[ATTR_TRANSITION]
if transition <= 127:
self.values.dimming_duration.data = int(transition)
elif transition > 7620:
self.values.dimming_duration.data = 0xFE
_LOGGER.warning("Transition clipped to 127 minutes for %s", self.entity_id)
else:
minutes = int(transition / 60)
_LOGGER.debug(
"Transition rounded to %d minutes for %s", minutes, self.entity_id
)
self.values.dimming_duration.data = minutes + 0x7F
def turn_on(self, **kwargs):
"""Turn the device on."""
self._set_duration(**kwargs)
# Zwave multilevel switches use a range of [0, 99] to control
# brightness. Level 255 means to set it to previous value.
if ATTR_BRIGHTNESS in kwargs:
self._brightness = kwargs[ATTR_BRIGHTNESS]
brightness = byte_to_zwave_brightness(self._brightness)
else:
brightness = 255
if self.node.set_dimmer(self.values.primary.value_id, brightness):
self._state = STATE_ON
def turn_off(self, **kwargs):
"""Turn the device off."""
self._set_duration(**kwargs)
if self.node.set_dimmer(self.values.primary.value_id, 0):
self._state = STATE_OFF
class ZwaveColorLight(ZwaveDimmer):
"""Representation of a Z-Wave color changing light."""
def __init__(self, values, refresh, delay):
"""Initialize the light."""
self._color_channels = None
self._rgb = None
self._ct = None
self._white = None
super().__init__(values, refresh, delay)
def value_added(self):
"""Call when a new value is added to this entity."""
if self.values.dimming_duration is not None:
self._supported_features = SUPPORT_TRANSITION
self._supported_color_modes = {COLOR_MODE_RGB}
self._color_mode = COLOR_MODE_RGB
if self._zw098:
self._supported_color_modes.add(COLOR_MODE_COLOR_TEMP)
elif self._color_channels is not None and self._color_channels & (
COLOR_CHANNEL_WARM_WHITE | COLOR_CHANNEL_COLD_WHITE
):
self._supported_color_modes = {COLOR_MODE_RGBW}
self._color_mode = COLOR_MODE_RGBW
def update_properties(self):
"""Update internal properties based on zwave values."""
super().update_properties()
if self.values.color is None:
return
if self.values.color_channels is None:
return
# Color Channels
self._color_channels = self.values.color_channels.data
# Color Data String
data = self.values.color.data
# RGB is always present in the openzwave color data string.
self._rgb = (int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16))
# Parse remaining color channels. Openzwave appends white channels
# that are present.
index = 7
# Warm white
if self._color_channels & COLOR_CHANNEL_WARM_WHITE:
warm_white = int(data[index : index + 2], 16)
index += 2
else:
warm_white = 0
# Cold white
if self._color_channels & COLOR_CHANNEL_COLD_WHITE:
cold_white = int(data[index : index + 2], 16)
index += 2
else:
cold_white = 0
# Color temperature. With the AEOTEC ZW098 bulb, only two color
# temperatures are supported. The warm and cold channel values
# indicate brightness for warm/cold color temperature.
if self._zw098:
if warm_white > 0:
self._ct = TEMP_WARM_HASS
self._color_mode = COLOR_MODE_COLOR_TEMP
elif cold_white > 0:
self._ct = TEMP_COLD_HASS
self._color_mode = COLOR_MODE_COLOR_TEMP
else:
self._color_mode = COLOR_MODE_RGB
elif self._color_channels & COLOR_CHANNEL_WARM_WHITE:
self._white = warm_white
elif self._color_channels & COLOR_CHANNEL_COLD_WHITE:
self._white = cold_white
# If no rgb channels supported, report None.
if not (
self._color_channels & COLOR_CHANNEL_RED
or self._color_channels & COLOR_CHANNEL_GREEN
or self._color_channels & COLOR_CHANNEL_BLUE
):
self._rgb = None
@property
def rgb_color(self):
"""Return the rgb color."""
return self._rgb
@property
def rgbw_color(self):
"""Return the rgbw color."""
if self._rgb is None:
return None
return (*self._rgb, self._white)
@property
def color_temp(self):
"""Return the color temperature."""
return self._ct
def turn_on(self, **kwargs):
"""Turn the device on."""
rgbw = None
if ATTR_COLOR_TEMP in kwargs:
# Color temperature. With the AEOTEC ZW098 bulb, only two color
# temperatures are supported. The warm and cold channel values
# indicate brightness for warm/cold color temperature.
if self._zw098:
self._color_mode = COLOR_MODE_COLOR_TEMP
if kwargs[ATTR_COLOR_TEMP] > TEMP_MID_HASS:
self._ct = TEMP_WARM_HASS
rgbw = "#000000ff00"
else:
self._ct = TEMP_COLD_HASS
rgbw = "#00000000ff"
elif ATTR_RGB_COLOR in kwargs:
self._rgb = kwargs[ATTR_RGB_COLOR]
self._white = 0
elif ATTR_RGBW_COLOR in kwargs:
self._rgb = kwargs[ATTR_RGBW_COLOR][0:3]
self._white = kwargs[ATTR_RGBW_COLOR][3]
if ATTR_RGB_COLOR in kwargs or ATTR_RGBW_COLOR in kwargs:
rgbw = "#"
for colorval in self._rgb:
rgbw += format(colorval, "02x")
if self._white is not None:
rgbw += format(self._white, "02x") + "00"
else:
rgbw += "0000"
if rgbw and self.values.color:
self.values.color.data = rgbw
super().turn_on(**kwargs)

View File

@ -1,390 +0,0 @@
"""Support for Z-Wave door locks."""
import logging
import voluptuous as vol
from homeassistant.components.lock import DOMAIN, LockEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, ServiceCall, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import ZWaveDeviceEntity, const
_LOGGER = logging.getLogger(__name__)
ATTR_NOTIFICATION = "notification"
ATTR_LOCK_STATUS = "lock_status"
ATTR_CODE_SLOT = "code_slot"
ATTR_USERCODE = "usercode"
CONFIG_ADVANCED = "Advanced"
SERVICE_SET_USERCODE = "set_usercode"
SERVICE_GET_USERCODE = "get_usercode"
SERVICE_CLEAR_USERCODE = "clear_usercode"
POLYCONTROL = 0x10E
DANALOCK_V2_BTZE = 0x2
POLYCONTROL_DANALOCK_V2_BTZE_LOCK = (POLYCONTROL, DANALOCK_V2_BTZE)
WORKAROUND_V2BTZE = 1
WORKAROUND_DEVICE_STATE = 2
WORKAROUND_TRACK_MESSAGE = 4
WORKAROUND_ALARM_TYPE = 8
DEVICE_MAPPINGS = {
POLYCONTROL_DANALOCK_V2_BTZE_LOCK: WORKAROUND_V2BTZE,
# Kwikset 914TRL ZW500 99100-078
(0x0090, 0x440): WORKAROUND_DEVICE_STATE,
(0x0090, 0x446): WORKAROUND_DEVICE_STATE,
(0x0090, 0x238): WORKAROUND_DEVICE_STATE,
# Kwikset 888ZW500-15S Smartcode 888
(0x0090, 0x541): WORKAROUND_DEVICE_STATE,
# Kwikset 916
(0x0090, 0x0001): WORKAROUND_DEVICE_STATE,
# Kwikset Obsidian
(0x0090, 0x0742): WORKAROUND_DEVICE_STATE,
# Yale Locks
# Yale YRD210, YRD220, YRL220
(0x0129, 0x0000): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRD210, YRD220
(0x0129, 0x0209): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRL210, YRL220
(0x0129, 0x0409): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRD256
(0x0129, 0x0600): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRD110, YRD120
(0x0129, 0x0800): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRD446
(0x0129, 0x1000): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRL220
(0x0129, 0x2132): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
(0x0129, 0x3CAC): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRD210, YRD220
(0x0129, 0xAA00): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRD220
(0x0129, 0xFFFF): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRL256
(0x0129, 0x0F00): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Yale YRD220 (Older Yale products with incorrect vendor ID)
(0x0109, 0x0000): WORKAROUND_DEVICE_STATE | WORKAROUND_ALARM_TYPE,
# Schlage BE469
(0x003B, 0x5044): WORKAROUND_DEVICE_STATE | WORKAROUND_TRACK_MESSAGE,
# Schlage FE599NX
(0x003B, 0x504C): WORKAROUND_DEVICE_STATE,
}
LOCK_NOTIFICATION = {
"1": "Manual Lock",
"2": "Manual Unlock",
"5": "Keypad Lock",
"6": "Keypad Unlock",
"11": "Lock Jammed",
"254": "Unknown Event",
}
NOTIFICATION_RF_LOCK = "3"
NOTIFICATION_RF_UNLOCK = "4"
LOCK_NOTIFICATION[NOTIFICATION_RF_LOCK] = "RF Lock"
LOCK_NOTIFICATION[NOTIFICATION_RF_UNLOCK] = "RF Unlock"
LOCK_ALARM_TYPE = {
"9": "Deadbolt Jammed",
"16": "Unlocked by Bluetooth ",
"18": "Locked with Keypad by user ",
"19": "Unlocked with Keypad by user ",
"21": "Manually Locked ",
"22": "Manually Unlocked ",
"27": "Auto re-lock",
"33": "User deleted: ",
"112": "Master code changed or User added: ",
"113": "Duplicate PIN code: ",
"130": "RF module, power restored",
"144": "Unlocked by NFC Tag or Card by user ",
"161": "Tamper Alarm: ",
"167": "Low Battery",
"168": "Critical Battery Level",
"169": "Battery too low to operate",
}
ALARM_RF_LOCK = "24"
ALARM_RF_UNLOCK = "25"
LOCK_ALARM_TYPE[ALARM_RF_LOCK] = "Locked by RF"
LOCK_ALARM_TYPE[ALARM_RF_UNLOCK] = "Unlocked by RF"
MANUAL_LOCK_ALARM_LEVEL = {
"1": "by Key Cylinder or Inside thumb turn",
"2": "by Touch function (lock and leave)",
}
TAMPER_ALARM_LEVEL = {"1": "Too many keypresses", "2": "Cover removed"}
LOCK_STATUS = {
"1": True,
"2": False,
"3": True,
"4": False,
"5": True,
"6": False,
"9": False,
"18": True,
"19": False,
"21": True,
"22": False,
"24": True,
"25": False,
"27": True,
}
ALARM_TYPE_STD = ["18", "19", "33", "112", "113", "144"]
SET_USERCODE_SCHEMA = vol.Schema(
{
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
vol.Required(ATTR_CODE_SLOT): vol.Coerce(int),
vol.Required(ATTR_USERCODE): cv.string,
}
)
GET_USERCODE_SCHEMA = vol.Schema(
{
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
vol.Required(ATTR_CODE_SLOT): vol.Coerce(int),
}
)
CLEAR_USERCODE_SCHEMA = vol.Schema(
{
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
vol.Required(ATTR_CODE_SLOT): vol.Coerce(int),
}
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave Lock from Config Entry."""
@callback
def async_add_lock(lock):
"""Add Z-Wave Lock."""
async_add_entities([lock])
async_dispatcher_connect(hass, "zwave_new_lock", async_add_lock)
network = hass.data[const.DATA_NETWORK]
def set_usercode(service: ServiceCall) -> None:
"""Set the usercode to index X on the lock."""
node_id = service.data.get(const.ATTR_NODE_ID)
lock_node = network.nodes[node_id]
code_slot = service.data.get(ATTR_CODE_SLOT)
usercode = service.data.get(ATTR_USERCODE)
for value in lock_node.get_values(
class_id=const.COMMAND_CLASS_USER_CODE
).values():
if value.index != code_slot:
continue
if len(str(usercode)) < 4:
_LOGGER.error(
"Invalid code provided: (%s) "
"usercode must be at least 4 and at most"
" %s digits",
usercode,
len(value.data),
)
break
value.data = str(usercode)
break
def get_usercode(service: ServiceCall) -> None:
"""Get a usercode at index X on the lock."""
node_id = service.data.get(const.ATTR_NODE_ID)
lock_node = network.nodes[node_id]
code_slot = service.data.get(ATTR_CODE_SLOT)
for value in lock_node.get_values(
class_id=const.COMMAND_CLASS_USER_CODE
).values():
if value.index != code_slot:
continue
_LOGGER.info("Usercode at slot %s is: %s", value.index, value.data)
break
def clear_usercode(service: ServiceCall) -> None:
"""Set usercode to slot X on the lock."""
node_id = service.data.get(const.ATTR_NODE_ID)
lock_node = network.nodes[node_id]
code_slot = service.data.get(ATTR_CODE_SLOT)
data = ""
for value in lock_node.get_values(
class_id=const.COMMAND_CLASS_USER_CODE
).values():
if value.index != code_slot:
continue
for i in range(len(value.data)):
data += "\0"
i += 1
_LOGGER.debug("Data to clear lock: %s", data)
value.data = data
_LOGGER.info("Usercode at slot %s is cleared", value.index)
break
hass.services.async_register(
DOMAIN, SERVICE_SET_USERCODE, set_usercode, schema=SET_USERCODE_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_GET_USERCODE, get_usercode, schema=GET_USERCODE_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_CLEAR_USERCODE, clear_usercode, schema=CLEAR_USERCODE_SCHEMA
)
def get_device(node, values, **kwargs):
"""Create Z-Wave entity device."""
return ZwaveLock(values)
class ZwaveLock(ZWaveDeviceEntity, LockEntity):
"""Representation of a Z-Wave Lock."""
def __init__(self, values):
"""Initialize the Z-Wave lock device."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self._state = None
self._notification = None
self._lock_status = None
self._v2btze = None
self._state_workaround = False
self._track_message_workaround = False
self._previous_message = None
self._alarm_type_workaround = False
# Enable appropriate workaround flags for our device
# Make sure that we have values for the key before converting to int
if self.node.manufacturer_id.strip() and self.node.product_id.strip():
specific_sensor_key = (
int(self.node.manufacturer_id, 16),
int(self.node.product_id, 16),
)
if specific_sensor_key in DEVICE_MAPPINGS:
workaround = DEVICE_MAPPINGS[specific_sensor_key]
if workaround & WORKAROUND_V2BTZE:
self._v2btze = 1
_LOGGER.debug("Polycontrol Danalock v2 BTZE workaround enabled")
if workaround & WORKAROUND_DEVICE_STATE:
self._state_workaround = True
_LOGGER.debug("Notification device state workaround enabled")
if workaround & WORKAROUND_TRACK_MESSAGE:
self._track_message_workaround = True
_LOGGER.debug("Message tracking workaround enabled")
if workaround & WORKAROUND_ALARM_TYPE:
self._alarm_type_workaround = True
_LOGGER.debug("Alarm Type device state workaround enabled")
self.update_properties()
def update_properties(self):
"""Handle data changes for node values."""
self._state = self.values.primary.data
_LOGGER.debug("lock state set to %s", self._state)
if self.values.access_control:
notification_data = self.values.access_control.data
self._notification = LOCK_NOTIFICATION.get(str(notification_data))
if self._state_workaround:
self._state = LOCK_STATUS.get(str(notification_data))
_LOGGER.debug("workaround: lock state set to %s", self._state)
if (
self._v2btze
and self.values.v2btze_advanced
and self.values.v2btze_advanced.data == CONFIG_ADVANCED
):
self._state = LOCK_STATUS.get(str(notification_data))
_LOGGER.debug(
"Lock state set from Access Control value and is %s, get=%s",
str(notification_data),
self.state,
)
if self._track_message_workaround:
this_message = self.node.stats["lastReceivedMessage"][5]
if this_message == const.COMMAND_CLASS_DOOR_LOCK:
self._state = self.values.primary.data
_LOGGER.debug("set state to %s based on message tracking", self._state)
if self._previous_message == const.COMMAND_CLASS_DOOR_LOCK:
if self._state:
self._notification = LOCK_NOTIFICATION[NOTIFICATION_RF_LOCK]
self._lock_status = LOCK_ALARM_TYPE[ALARM_RF_LOCK]
else:
self._notification = LOCK_NOTIFICATION[NOTIFICATION_RF_UNLOCK]
self._lock_status = LOCK_ALARM_TYPE[ALARM_RF_UNLOCK]
return
self._previous_message = this_message
if not self.values.alarm_type:
return
alarm_type = self.values.alarm_type.data
if self.values.alarm_level:
alarm_level = self.values.alarm_level.data
else:
alarm_level = None
if not alarm_type:
return
if self._alarm_type_workaround:
self._state = LOCK_STATUS.get(str(alarm_type))
_LOGGER.debug(
"workaround: lock state set to %s -- alarm type: %s",
self._state,
str(alarm_type),
)
if alarm_type == 21:
self._lock_status = (
f"{LOCK_ALARM_TYPE.get(str(alarm_type))}"
f"{MANUAL_LOCK_ALARM_LEVEL.get(str(alarm_level))}"
)
return
if str(alarm_type) in ALARM_TYPE_STD:
self._lock_status = f"{LOCK_ALARM_TYPE.get(str(alarm_type))}{alarm_level}"
return
if alarm_type == 161:
self._lock_status = (
f"{LOCK_ALARM_TYPE.get(str(alarm_type))}"
f"{TAMPER_ALARM_LEVEL.get(str(alarm_level))}"
)
return
if alarm_type != 0:
self._lock_status = LOCK_ALARM_TYPE.get(str(alarm_type))
return
@property
def is_locked(self):
"""Return true if device is locked."""
return self._state
def lock(self, **kwargs):
"""Lock the device."""
self.values.primary.data = True
def unlock(self, **kwargs):
"""Unlock the device."""
self.values.primary.data = False
@property
def extra_state_attributes(self):
"""Return the device specific state attributes."""
data = super().extra_state_attributes
if self._notification:
data[ATTR_NOTIFICATION] = self._notification
if self._lock_status:
data[ATTR_LOCK_STATUS] = self._lock_status
return data

View File

@ -1,9 +0,0 @@
{
"domain": "zwave",
"name": "Z-Wave (deprecated)",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/zwave",
"requirements": ["homeassistant-pyozw==0.1.10", "pydispatcher==2.0.5"],
"codeowners": ["@home-assistant/z-wave"],
"iot_class": "local_push"
}

View File

@ -1,167 +0,0 @@
"""Handle migration from legacy Z-Wave to OpenZWave and Z-Wave JS."""
from __future__ import annotations
from typing import TYPE_CHECKING, TypedDict, cast
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import async_get as async_get_device_registry
from homeassistant.helpers.entity_registry import async_get as async_get_entity_registry
from homeassistant.helpers.singleton import singleton
from homeassistant.helpers.storage import Store
from .const import DOMAIN
from .util import node_device_id_and_name
if TYPE_CHECKING:
from . import ZWaveDeviceEntityValues
LEGACY_ZWAVE_MIGRATION = f"{DOMAIN}_legacy_zwave_migration"
STORAGE_WRITE_DELAY = 30
STORAGE_KEY = f"{DOMAIN}.legacy_zwave_migration"
STORAGE_VERSION = 1
class ZWaveMigrationData(TypedDict):
"""Represent the Z-Wave migration data dict."""
node_id: int
node_instance: int
command_class: int
command_class_label: str
value_index: int
device_id: str
domain: str
entity_id: str
unique_id: str
unit_of_measurement: str | None
@callback
def async_is_ozw_migrated(hass):
"""Return True if migration to ozw is done."""
ozw_config_entries = hass.config_entries.async_entries("ozw")
if not ozw_config_entries:
return False
ozw_config_entry = ozw_config_entries[0] # only one ozw entry is allowed
migrated = bool(ozw_config_entry.data.get("migrated"))
return migrated
@callback
def async_is_zwave_js_migrated(hass):
"""Return True if migration to Z-Wave JS is done."""
zwave_js_config_entries = hass.config_entries.async_entries("zwave_js")
if not zwave_js_config_entries:
return False
migrated = any(
config_entry.data.get("migrated") for config_entry in zwave_js_config_entries
)
return migrated
async def async_add_migration_entity_value(
hass: HomeAssistant,
entity_id: str,
entity_values: ZWaveDeviceEntityValues,
) -> None:
"""Add Z-Wave entity value for legacy Z-Wave migration."""
migration_handler: LegacyZWaveMigration = await get_legacy_zwave_migration(hass)
migration_handler.add_entity_value(entity_id, entity_values)
async def async_get_migration_data(
hass: HomeAssistant, config_entry: ConfigEntry
) -> dict[str, ZWaveMigrationData]:
"""Return Z-Wave migration data."""
migration_handler: LegacyZWaveMigration = await get_legacy_zwave_migration(hass)
return await migration_handler.get_data(config_entry)
@singleton(LEGACY_ZWAVE_MIGRATION)
async def get_legacy_zwave_migration(hass: HomeAssistant) -> LegacyZWaveMigration:
"""Return legacy Z-Wave migration handler."""
migration_handler = LegacyZWaveMigration(hass)
await migration_handler.load_data()
return migration_handler
class LegacyZWaveMigration:
"""Handle the migration from zwave to ozw and zwave_js."""
def __init__(self, hass: HomeAssistant) -> None:
"""Set up migration instance."""
self._hass = hass
self._store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
self._data: dict[str, dict[str, ZWaveMigrationData]] = {}
async def load_data(self) -> None:
"""Load Z-Wave migration data."""
stored = cast(dict, await self._store.async_load())
if stored:
self._data = stored
@callback
def save_data(
self, config_entry_id: str, entity_id: str, data: ZWaveMigrationData
) -> None:
"""Save Z-Wave migration data."""
if config_entry_id not in self._data:
self._data[config_entry_id] = {}
self._data[config_entry_id][entity_id] = data
self._store.async_delay_save(self._data_to_save, STORAGE_WRITE_DELAY)
@callback
def _data_to_save(self) -> dict[str, dict[str, ZWaveMigrationData]]:
"""Return data to save."""
return self._data
@callback
def add_entity_value(
self,
entity_id: str,
entity_values: ZWaveDeviceEntityValues,
) -> None:
"""Add info for one entity and Z-Wave value."""
ent_reg = async_get_entity_registry(self._hass)
dev_reg = async_get_device_registry(self._hass)
node = entity_values.primary.node
entity_entry = ent_reg.async_get(entity_id)
assert entity_entry
device_identifier, _ = node_device_id_and_name(
node, entity_values.primary.instance
)
device_entry = dev_reg.async_get_device({device_identifier}, set())
assert device_entry
# Normalize unit of measurement.
if unit := entity_entry.unit_of_measurement:
unit = unit.lower()
if unit == "":
unit = None
data: ZWaveMigrationData = {
"node_id": node.node_id,
"node_instance": entity_values.primary.instance,
"command_class": entity_values.primary.command_class,
"command_class_label": entity_values.primary.label,
"value_index": entity_values.primary.index,
"device_id": device_entry.id,
"domain": entity_entry.domain,
"entity_id": entity_id,
"unique_id": entity_entry.unique_id,
"unit_of_measurement": unit,
}
self.save_data(entity_entry.config_entry_id, entity_id, data)
async def get_data(
self, config_entry: ConfigEntry
) -> dict[str, ZWaveMigrationData]:
"""Return Z-Wave migration data."""
await self.load_data()
data = self._data.get(config_entry.entry_id)
return data or {}

View File

@ -1,381 +0,0 @@
"""Entity class that represents Z-Wave node."""
# pylint: disable=import-error
# pylint: disable=import-outside-toplevel
from itertools import count
from homeassistant.const import (
ATTR_BATTERY_LEVEL,
ATTR_ENTITY_ID,
ATTR_VIA_DEVICE,
ATTR_WAKEUP,
)
from homeassistant.core import callback
from homeassistant.helpers.device_registry import async_get_registry as get_dev_reg
from homeassistant.helpers.entity import DeviceInfo, Entity
from homeassistant.helpers.entity_registry import async_get_registry
from .const import (
ATTR_BASIC_LEVEL,
ATTR_NODE_ID,
ATTR_SCENE_DATA,
ATTR_SCENE_ID,
COMMAND_CLASS_CENTRAL_SCENE,
COMMAND_CLASS_VERSION,
COMMAND_CLASS_WAKE_UP,
DOMAIN,
EVENT_NODE_EVENT,
EVENT_SCENE_ACTIVATED,
)
from .util import is_node_parsed, node_device_id_and_name, node_name
ATTR_QUERY_STAGE = "query_stage"
ATTR_AWAKE = "is_awake"
ATTR_READY = "is_ready"
ATTR_FAILED = "is_failed"
ATTR_PRODUCT_NAME = "product_name"
ATTR_MANUFACTURER_NAME = "manufacturer_name"
ATTR_NODE_NAME = "node_name"
ATTR_APPLICATION_VERSION = "application_version"
STAGE_COMPLETE = "Complete"
_REQUIRED_ATTRIBUTES = [
ATTR_QUERY_STAGE,
ATTR_AWAKE,
ATTR_READY,
ATTR_FAILED,
"is_info_received",
"max_baud_rate",
"is_zwave_plus",
]
_OPTIONAL_ATTRIBUTES = ["capabilities", "neighbors", "location"]
_COMM_ATTRIBUTES = [
"sentCnt",
"sentFailed",
"retries",
"receivedCnt",
"receivedDups",
"receivedUnsolicited",
"sentTS",
"receivedTS",
"lastRequestRTT",
"averageRequestRTT",
"lastResponseRTT",
"averageResponseRTT",
]
ATTRIBUTES = _REQUIRED_ATTRIBUTES + _OPTIONAL_ATTRIBUTES
class ZWaveBaseEntity(Entity):
"""Base class for Z-Wave Node and Value entities."""
def __init__(self):
"""Initialize the base Z-Wave class."""
self._update_scheduled = False
def maybe_schedule_update(self):
"""Maybe schedule state update.
If value changed after device was created but before setup_platform
was called - skip updating state.
"""
if self.hass and not self._update_scheduled:
self.hass.add_job(self._schedule_update)
@callback
def _schedule_update(self):
"""Schedule delayed update."""
if self._update_scheduled:
return
@callback
def do_update():
"""Really update."""
self.async_write_ha_state()
self._update_scheduled = False
self._update_scheduled = True
self.hass.loop.call_later(0.1, do_update)
def try_remove_and_add(self):
"""Remove this entity and add it back."""
async def _async_remove_and_add():
await self.async_remove(force_remove=True)
self.entity_id = None
await self.platform.async_add_entities([self])
if self.hass and self.platform:
self.hass.add_job(_async_remove_and_add)
async def node_removed(self):
"""Call when a node is removed from the Z-Wave network."""
await self.async_remove(force_remove=True)
registry = await async_get_registry(self.hass)
if self.entity_id not in registry.entities:
return
registry.async_remove(self.entity_id)
class ZWaveNodeEntity(ZWaveBaseEntity):
"""Representation of a Z-Wave node."""
def __init__(self, node, network):
"""Initialize node."""
super().__init__()
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
self._network = network
self.node = node
self.node_id = self.node.node_id
self._name = node_name(self.node)
self._product_name = node.product_name
self._manufacturer_name = node.manufacturer_name
self._unique_id = self._compute_unique_id()
self._application_version = None
self._attributes = {}
self.wakeup_interval = None
self.location = None
self.battery_level = None
dispatcher.connect(
self.network_node_value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED
)
dispatcher.connect(self.network_node_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED)
dispatcher.connect(self.network_node_changed, ZWaveNetwork.SIGNAL_NODE)
dispatcher.connect(self.network_node_changed, ZWaveNetwork.SIGNAL_NOTIFICATION)
dispatcher.connect(self.network_node_event, ZWaveNetwork.SIGNAL_NODE_EVENT)
dispatcher.connect(
self.network_scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT
)
@property
def unique_id(self):
"""Return unique ID of Z-wave node."""
return self._unique_id
@property
def device_info(self) -> DeviceInfo:
"""Return device information."""
identifier, name = node_device_id_and_name(self.node)
info = DeviceInfo(
identifiers={identifier},
manufacturer=self.node.manufacturer_name,
model=self.node.product_name,
name=name,
)
if self.node_id > 1:
info[ATTR_VIA_DEVICE] = (DOMAIN, 1)
return info
def maybe_update_application_version(self, value):
"""Update application version if value is a Command Class Version, Application Value."""
if (
value
and value.command_class == COMMAND_CLASS_VERSION
and value.label == "Application Version"
):
self._application_version = value.data
def network_node_value_added(self, node=None, value=None, args=None):
"""Handle a added value to a none on the network."""
if node and node.node_id != self.node_id:
return
if args is not None and "nodeId" in args and args["nodeId"] != self.node_id:
return
self.maybe_update_application_version(value)
def network_node_changed(self, node=None, value=None, args=None):
"""Handle a changed node on the network."""
if node and node.node_id != self.node_id:
return
if args is not None and "nodeId" in args and args["nodeId"] != self.node_id:
return
# Process central scene activation
if value is not None and value.command_class == COMMAND_CLASS_CENTRAL_SCENE:
self.central_scene_activated(value.index, value.data)
self.maybe_update_application_version(value)
self.node_changed()
def get_node_statistics(self):
"""Retrieve statistics from the node."""
return self._network.manager.getNodeStatistics(
self._network.home_id, self.node_id
)
def node_changed(self):
"""Update node properties."""
attributes = {}
stats = self.get_node_statistics()
for attr in ATTRIBUTES:
value = getattr(self.node, attr)
if attr in _REQUIRED_ATTRIBUTES or value:
attributes[attr] = value
for attr in _COMM_ATTRIBUTES:
attributes[attr] = stats[attr]
if self.node.can_wake_up():
for value in self.node.get_values(COMMAND_CLASS_WAKE_UP).values():
if value.index != 0:
continue
self.wakeup_interval = value.data
break
else:
self.wakeup_interval = None
self.battery_level = self.node.get_battery_level()
self._product_name = self.node.product_name
self._manufacturer_name = self.node.manufacturer_name
self._name = node_name(self.node)
self._attributes = attributes
if not self._unique_id:
self._unique_id = self._compute_unique_id()
if self._unique_id:
# Node info parsed. Remove and re-add
self.try_remove_and_add()
self.maybe_schedule_update()
async def node_renamed(self, update_ids=False):
"""Rename the node and update any IDs."""
identifier, self._name = node_device_id_and_name(self.node)
# Set the name in the devices. If they're customised
# the customisation will not be stored as name and will stick.
dev_reg = await get_dev_reg(self.hass)
device = dev_reg.async_get_device(identifiers={identifier})
dev_reg.async_update_device(device.id, name=self._name)
# update sub-devices too
for i in count(2):
identifier, new_name = node_device_id_and_name(self.node, i)
device = dev_reg.async_get_device(identifiers={identifier})
if not device:
break
dev_reg.async_update_device(device.id, name=new_name)
# Update entity ID.
if update_ids:
ent_reg = await async_get_registry(self.hass)
new_entity_id = ent_reg.async_generate_entity_id(
DOMAIN, self._name, self.platform.entities.keys() - {self.entity_id}
)
if new_entity_id != self.entity_id:
# Don't change the name attribute, it will be None unless
# customised and if it's been customised, keep the
# customisation.
ent_reg.async_update_entity(self.entity_id, new_entity_id=new_entity_id)
return
# else for the above two ifs, update if not using update_entity
self.async_write_ha_state()
def network_node_event(self, node, value):
"""Handle a node activated event on the network."""
if node.node_id == self.node.node_id:
self.node_event(value)
def node_event(self, value):
"""Handle a node activated event for this node."""
if self.hass is None:
return
self.hass.bus.fire(
EVENT_NODE_EVENT,
{
ATTR_ENTITY_ID: self.entity_id,
ATTR_NODE_ID: self.node.node_id,
ATTR_BASIC_LEVEL: value,
},
)
def network_scene_activated(self, node, scene_id):
"""Handle a scene activated event on the network."""
if node.node_id == self.node.node_id:
self.scene_activated(scene_id)
def scene_activated(self, scene_id):
"""Handle an activated scene for this node."""
if self.hass is None:
return
self.hass.bus.fire(
EVENT_SCENE_ACTIVATED,
{
ATTR_ENTITY_ID: self.entity_id,
ATTR_NODE_ID: self.node.node_id,
ATTR_SCENE_ID: scene_id,
},
)
def central_scene_activated(self, scene_id, scene_data):
"""Handle an activated central scene for this node."""
if self.hass is None:
return
self.hass.bus.fire(
EVENT_SCENE_ACTIVATED,
{
ATTR_ENTITY_ID: self.entity_id,
ATTR_NODE_ID: self.node_id,
ATTR_SCENE_ID: scene_id,
ATTR_SCENE_DATA: scene_data,
},
)
@property
def state(self):
"""Return the state."""
if ATTR_READY not in self._attributes:
return None
if self._attributes[ATTR_FAILED]:
return "dead"
if self._attributes[ATTR_QUERY_STAGE] != "Complete":
return "initializing"
if not self._attributes[ATTR_AWAKE]:
return "sleeping"
if self._attributes[ATTR_READY]:
return "ready"
return None
@property
def should_poll(self):
"""No polling needed."""
return False
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def extra_state_attributes(self):
"""Return the device specific state attributes."""
attrs = {
ATTR_NODE_ID: self.node_id,
ATTR_NODE_NAME: self._name,
ATTR_MANUFACTURER_NAME: self._manufacturer_name,
ATTR_PRODUCT_NAME: self._product_name,
}
attrs.update(self._attributes)
if self.battery_level is not None:
attrs[ATTR_BATTERY_LEVEL] = self.battery_level
if self.wakeup_interval is not None:
attrs[ATTR_WAKEUP] = self.wakeup_interval
if self._application_version is not None:
attrs[ATTR_APPLICATION_VERSION] = self._application_version
return attrs
def _compute_unique_id(self):
if is_node_parsed(self.node) or self.node.is_ready:
return f"node-{self.node_id}"
return None

View File

@ -1,124 +0,0 @@
"""Support for Z-Wave sensors."""
from homeassistant.components.sensor import DOMAIN, SensorDeviceClass, SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import ZWaveDeviceEntity, const
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave Sensor from Config Entry."""
@callback
def async_add_sensor(sensor):
"""Add Z-Wave Sensor."""
async_add_entities([sensor])
async_dispatcher_connect(hass, "zwave_new_sensor", async_add_sensor)
def get_device(node, values, **kwargs):
"""Create Z-Wave entity device."""
# Generic Device mappings
if values.primary.command_class == const.COMMAND_CLASS_BATTERY:
return ZWaveBatterySensor(values)
if node.has_command_class(const.COMMAND_CLASS_SENSOR_MULTILEVEL):
return ZWaveMultilevelSensor(values)
if (
node.has_command_class(const.COMMAND_CLASS_METER)
and values.primary.type == const.TYPE_DECIMAL
):
return ZWaveMultilevelSensor(values)
if node.has_command_class(const.COMMAND_CLASS_ALARM) or node.has_command_class(
const.COMMAND_CLASS_SENSOR_ALARM
):
return ZWaveAlarmSensor(values)
return None
class ZWaveSensor(ZWaveDeviceEntity, SensorEntity):
"""Representation of a Z-Wave sensor."""
def __init__(self, values):
"""Initialize the sensor."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self.update_properties()
def update_properties(self):
"""Handle the data changes for node values."""
self._state = self.values.primary.data
self._units = self.values.primary.units
@property
def force_update(self):
"""Return force_update."""
return True
@property
def native_value(self):
"""Return the state of the sensor."""
return self._state
@property
def native_unit_of_measurement(self):
"""Return the unit of measurement the value is expressed in."""
return self._units
class ZWaveMultilevelSensor(ZWaveSensor):
"""Representation of a multi level sensor Z-Wave sensor."""
@property
def native_value(self):
"""Return the state of the sensor."""
if self._units in ("C", "F"):
return round(self._state, 1)
if isinstance(self._state, float):
return round(self._state, 2)
return self._state
@property
def device_class(self):
"""Return the class of this device."""
if self._units in ["C", "F"]:
return SensorDeviceClass.TEMPERATURE
return None
@property
def native_unit_of_measurement(self):
"""Return the unit the value is expressed in."""
if self._units == "C":
return TEMP_CELSIUS
if self._units == "F":
return TEMP_FAHRENHEIT
return self._units
class ZWaveAlarmSensor(ZWaveSensor):
"""Representation of a Z-Wave sensor that sends Alarm alerts.
Examples include certain Multisensors that have motion and vibration
capabilities. Z-Wave defines various alarm types such as Smoke, Flood,
Burglar, CarbonMonoxide, etc.
This wraps these alarms and allows you to use them to trigger things, etc.
COMMAND_CLASS_ALARM is what we get here.
"""
class ZWaveBatterySensor(ZWaveSensor):
"""Representation of Z-Wave device battery level."""
@property
def device_class(self):
"""Return the class of this device."""
return SensorDeviceClass.BATTERY

View File

@ -1,411 +0,0 @@
# Describes the format for available Z-Wave services
change_association:
name: Change association
description: Change an association in the Z-Wave network.
fields:
association:
name: Association
description: Specify add or remove association
required: true
example: add
selector:
text:
node_id:
name: Node ID
description: Node id of the node to set association for.
required: true
selector:
number:
min: 1
max: 255
target_node_id:
name: Target node ID
description: Node id of the node to associate to.
required: true
selector:
number:
min: 1
max: 255
group:
name: Group
description: Group number to set association for.
required: true
selector:
number:
min: 1
max: 5
instance:
name: Instance
description: Instance of multichannel association.
default: 0
selector:
number:
min: 0
max: 255
add_node:
name: Add node
description: Add a new (unsecure) node to the Z-Wave network. Refer to OZW_Log.txt for progress.
add_node_secure:
name: Add node secure
description: Add a new node to the Z-Wave network with secure communications. Secure network key must be set, this process will fallback to add_node (unsecure) for unsupported devices. Note that unsecure devices can't directly talk to secure devices. Refer to OZW_Log.txt for progress.
cancel_command:
name: Cancel command
description: Cancel a running Z-Wave controller command. Use this to exit add_node, if you weren't going to use it but activated it.
heal_network:
name: Heal network
description: Start a Z-Wave network heal. This might take a while and will slow down the Z-Wave network greatly while it is being processed. Refer to OZW_Log.txt for progress.
fields:
return_routes:
name: Return routes
description: Whether or not to update the return routes from the nodes to the controller.
default: false
selector:
boolean:
heal_node:
name: Heal node
description: Start a Z-Wave node heal. Refer to OZW_Log.txt for progress.
fields:
return_routes:
name: Return routes
description: Whether or not to update the return routes from the node to the controller.
default: false
selector:
boolean:
remove_node:
name: Remove node
description: Remove a node from the Z-Wave network. Refer to OZW_Log.txt for progress.
remove_failed_node:
name: Remove failed node
description: This command will remove a failed node from the network. The node should be on the controller's failed nodes list, otherwise this command will fail. Refer to OZW_Log.txt for progress.
fields:
node_id:
name: Node ID
description: Node id of the device to remove.
required: true
selector:
number:
min: 1
max: 255
replace_failed_node:
name: Replace failed node
description: Replace a failed node with another. If the node is not in the controller's failed nodes list, or the node responds, this command will fail. Refer to OZW_Log.txt for progress.
fields:
node_id:
name: Node ID
description: Node id of the device to replace.
required: true
selector:
number:
min: 1
max: 255
set_config_parameter:
name: Set config parameter
description: Set a config parameter to a node on the Z-Wave network.
fields:
node_id:
name: Node ID
description: Node id of the device to set config parameter to.
required: true
selector:
number:
min: 1
max: 255
parameter:
name: Parameter
description: Parameter number to set.
required: true
selector:
number:
min: 1
max: 255
value:
name: Value
description: Value to set for parameter. (String value for list and bool parameters, integer for others).
required: true
selector:
text:
size:
name: Size
description: Set the size of the parameter value. Only needed if no parameters are available.
default: 2
selector:
number:
min: 1
max: 255
set_node_value:
name: Set node value
description: Set the value for a given value_id on a Z-Wave device.
fields:
node_id:
name: Node ID
description: Node id of the device to set the value on.
required: true
selector:
number:
min: 1
max: 255
value_id:
name: Value ID
description: Value id of the value to set (integer or string).
required: true
selector:
text:
value:
name: Value
description: Value to set (integer or string).
required: true
selector:
text:
refresh_node_value:
name: Refresh node value
description: Refresh the value for a given value_id on a Z-Wave device.
fields:
node_id:
name: Node ID
description: Node id of the device to refresh value from.
required: true
selector:
number:
min: 1
max: 255
value_id:
name: Value ID
description: Value id of the value to refresh.
required: true
selector:
text:
set_poll_intensity:
name: Set poll intensity
description: Set the polling interval to a nodes value
fields:
node_id:
name: Node ID
description: ID of the node to set polling to.
required: true
selector:
number:
min: 1
max: 255
value_id:
name: Value ID
description: ID of the value to set polling to.
example: 72037594255792737
required: true
selector:
text:
poll_intensity:
name: Poll intensity
description: The intensity to poll, 0 = disabled, 1 = Every time through list, 2 = Every second time through list...
required: true
selector:
number:
min: 0
max: 100
print_config_parameter:
name: Print configuration parameter
description: Prints a Z-Wave node config parameter value to log.
fields:
node_id:
name: Node ID
description: Node id of the device to print the parameter from.
required: true
selector:
number:
min: 1
max: 255
parameter:
name: Parameter
description: Parameter number to print.
required: true
selector:
number:
min: 1
max: 255
print_node:
name: Print node
description: Print all information about z-wave node.
fields:
node_id:
name: Node ID
description: Node id of the device to print.
required: true
selector:
number:
min: 1
max: 255
refresh_entity:
name: Refresh entity
description: Refresh zwave entity.
fields:
entity_id:
name: Entity
description: Name of the entity to refresh.
required: true
selector:
entity:
integration: zwave
refresh_node:
name: Refresh node
description: Refresh zwave node.
fields:
node_id:
name: Node ID
description: ID of the node to refresh.
required: true
selector:
number:
min: 1
max: 255
set_wakeup:
name: Set wakeup
description: Sets wake-up interval of a node.
fields:
node_id:
name: Node ID
description: Node id of the device to set the wake-up interval for.
required: true
selector:
number:
min: 1
max: 255
value:
name: Value
description: Value of the interval to set.
required: true
selector:
text:
start_network:
name: Start network
description: Start the Z-Wave network. This might take a while, depending on how big your Z-Wave network is.
stop_network:
name: Stop network
description: Stop the Z-Wave network, all updates into Home Assistant will stop.
soft_reset:
name: Soft reset
description: This will reset the controller without removing its data. Use carefully because not all controllers support this. Refer to your controller's manual.
test_network:
name: Test network
description: This will send test to nodes in the Z-Wave network. This will greatly slow down the Z-Wave network while it is being processed. Refer to OZW_Log.txt for progress.
test_node:
name: Test node
description: This will send test messages to a node in the Z-Wave network. This could bring back dead nodes.
fields:
node_id:
name: Node ID
description: ID of the node to send test messages to.
required: true
selector:
number:
min: 1
max: 255
messages:
name: Messages
description: Amount of test messages to send.
default: 1
selector:
number:
min: 1
max: 100
rename_node:
name: Rename node
description: Set the name of a node. This will also affect the IDs of all entities in the node.
fields:
node_id:
name: Node ID
description: ID of the node to rename.
required: true
selector:
number:
min: 1
max: 255
update_ids:
name: Update IDs
description: Rename the entity IDs for entities of this node.
default: false
selector:
boolean:
name:
name: Name
description: New Name
required: true
example: "kitchen"
selector:
text:
rename_value:
name: Rename value
description: Set the name of a node value. This will affect the ID of the value entity. Value IDs can be queried from /api/zwave/values/{node_id}
fields:
node_id:
name: Node ID
description: ID of the node to rename.
required: true
selector:
number:
min: 1
max: 255
value_id:
name: Value ID
description: ID of the value to rename.
example: 72037594255792737
required: true
selector:
text:
update_ids:
name: Update IDs
description: Update the entity ID for this value's entity.
default: false
selector:
boolean:
name:
name: Name
description: New Name
example: "Luminosity"
required: true
selector:
text:
reset_node_meters:
name: Reset node meters
description: Resets the meter counters of a node.
fields:
node_id:
name: Node ID
description: Node id of the device to reset meters for.
required: true
selector:
number:
min: 1
max: 255
instance:
name: Instance
description: Instance of association.
default: 1
selector:
number:
min: 1
max: 100

View File

@ -1,32 +0,0 @@
{
"config": {
"step": {
"user": {
"description": "This integration is no longer maintained. For new installations, use Z-Wave JS instead.\n\nSee https://www.home-assistant.io/docs/z-wave/installation/ for information on the configuration variables",
"data": {
"usb_path": "[%key:common::config_flow::data::usb_path%]",
"network_key": "Network Key (leave blank to auto-generate)"
}
}
},
"error": {
"option_error": "Z-Wave validation failed. Is the path to the USB stick correct?"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
}
},
"state": {
"query_stage": {
"initializing": "[%key:component::zwave::state::_::initializing%]",
"dead": "[%key:component::zwave::state::_::dead%]"
},
"_": {
"initializing": "Initializing",
"dead": "Dead",
"sleeping": "Sleeping",
"ready": "Ready"
}
}
}

View File

@ -1,64 +0,0 @@
"""Support for Z-Wave switches."""
import time
from homeassistant.components.switch import DOMAIN, SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import ZWaveDeviceEntity, workaround
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave Switch from Config Entry."""
@callback
def async_add_switch(switch):
"""Add Z-Wave Switch."""
async_add_entities([switch])
async_dispatcher_connect(hass, "zwave_new_switch", async_add_switch)
def get_device(values, **kwargs):
"""Create zwave entity device."""
return ZwaveSwitch(values)
class ZwaveSwitch(ZWaveDeviceEntity, SwitchEntity):
"""Representation of a Z-Wave switch."""
def __init__(self, values):
"""Initialize the Z-Wave switch device."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self.refresh_on_update = (
workaround.get_device_mapping(values.primary)
== workaround.WORKAROUND_REFRESH_NODE_ON_UPDATE
)
self.last_update = time.perf_counter()
self._state = self.values.primary.data
def update_properties(self):
"""Handle data changes for node values."""
self._state = self.values.primary.data
if self.refresh_on_update and time.perf_counter() - self.last_update > 30:
self.last_update = time.perf_counter()
self.node.request_state()
@property
def is_on(self):
"""Return true if device is on."""
return self._state
def turn_on(self, **kwargs):
"""Turn the device on."""
self.node.set_switch(self.values.primary.value_id, True)
def turn_off(self, **kwargs):
"""Turn the device off."""
self.node.set_switch(self.values.primary.value_id, False)

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "Dood",
"initializing": "Inisialiseer",
"ready": "Gereed",
"sleeping": "Aan die slaap"
},
"query_stage": {
"dead": "Dood ({query_stage})",
"initializing": "Inisialiseer ({query_stage})"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "\u0645\u0641\u0635\u0648\u0644",
"initializing": "\u0642\u064a\u062f \u0627\u0644\u0625\u0646\u0634\u0627\u0621",
"ready": "\u062c\u0627\u0647\u0632",
"sleeping": "\u0646\u0627\u0626\u0645"
},
"query_stage": {
"dead": "\u0645\u0641\u0635\u0648\u0644 ({query_stage})",
"initializing": "\u0642\u064a\u062f \u0627\u0644\u0625\u0646\u0634\u0627\u0621 ( {query_stage} )"
}
}
}

View File

@ -1,31 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Z-Wave \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d"
},
"error": {
"option_error": "\u0412\u0430\u043b\u0438\u0434\u0438\u0440\u0430\u043d\u0435\u0442\u043e \u043d\u0430 Z-Wave \u043d\u0435 \u0431\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e. \u041f\u0440\u0430\u0432\u0438\u043b\u0435\u043d \u043b\u0438 \u0435 \u043f\u044a\u0442\u044f\u0442 \u043a\u044a\u043c USB \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e?"
},
"step": {
"user": {
"data": {
"network_key": "\u041c\u0440\u0435\u0436\u043e\u0432 \u043a\u043b\u044e\u0447 (\u043e\u0441\u0442\u0430\u0432\u0435\u0442\u0435 \u043f\u0440\u0430\u0437\u043d\u043e \u0437\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0430\u043d\u0435)",
"usb_path": "USB \u043f\u044a\u0442"
},
"description": "\u0412\u0438\u0436\u0442\u0435 https://www.home-assistant.io/docs/z-wave/installation/ \u0437\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0442\u043d\u043e\u0441\u043d\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0438\u0442\u0435 \u043f\u0440\u043e\u043c\u0435\u043d\u043b\u0438\u0432\u0438"
}
}
},
"state": {
"_": {
"dead": "\u041c\u044a\u0440\u0442\u044a\u0432",
"initializing": "\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f",
"ready": "\u0413\u043e\u0442\u043e\u0432",
"sleeping": "\u0421\u043f\u044f\u0449"
},
"query_stage": {
"dead": "\u041c\u044a\u0440\u0442\u044a\u0432 ({query_stage})",
"initializing": "\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f ( {query_stage} )"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "Mrtav",
"initializing": "Inicijalizacija",
"ready": "Spreman",
"sleeping": "Spava"
},
"query_stage": {
"dead": "Mrtav ({query_stage})",
"initializing": "Inicijalizacija ( {query_stage} )"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "El dispositiu ja est\u00e0 configurat",
"single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3."
},
"error": {
"option_error": "Ha fallat la validaci\u00f3 de Z-Wave. \u00c9s correcta la ruta al port USB on hi ha connectat el dispositiu?"
},
"step": {
"user": {
"data": {
"network_key": "Clau de xarxa (deixa-ho en blanc per generar-la autom\u00e0ticament)",
"usb_path": "Ruta del dispositiu USB"
},
"description": "Aquesta integraci\u00f3 ja no s'actualitzar\u00e0. Utilitza Z-Wave JS per a instal\u00b7lacions noves.\n\nConsulta https://www.home-assistant.io/docs/z-wave/installation/ per a m\u00e9s informaci\u00f3 sobre les variables de configuraci\u00f3"
}
}
},
"state": {
"_": {
"dead": "No disponible",
"initializing": "Inicialitzant",
"ready": "A punt",
"sleeping": "Dormint"
},
"query_stage": {
"dead": "No disponible",
"initializing": "Inicialitzant"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno",
"single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace."
},
"error": {
"option_error": "Z-Wave ov\u011b\u0159en\u00ed se nezda\u0159ilo. Je cesta k USB za\u0159\u00edzen\u00ed spr\u00e1vn\u011b?"
},
"step": {
"user": {
"data": {
"network_key": "S\u00ed\u0165ov\u00fd kl\u00ed\u010d (ponechte pr\u00e1zdn\u00e9 pro automatick\u00e9 generov\u00e1n\u00ed)",
"usb_path": "Cesta k USB za\u0159\u00edzen\u00ed"
},
"description": "Viz https://www.home-assistant.io/docs/z-wave/installation/ pro informace o konfigura\u010dn\u00edch prom\u011bnn\u00fdch"
}
}
},
"state": {
"_": {
"dead": "Nereaguje",
"initializing": "Inicializace",
"ready": "P\u0159ipraveno",
"sleeping": "\u00dasporn\u00fd re\u017eim"
},
"query_stage": {
"dead": "Nereaguje",
"initializing": "Inicializace"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "Marw",
"initializing": "Ymgychwyn",
"ready": "Barod",
"sleeping": "Cysgu"
},
"query_stage": {
"dead": "Marw ({query_stage})",
"initializing": "Ymgychwyn ( {query_stage} )"
}
}
}

View File

@ -1,31 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Z-Wave er allerede konfigureret"
},
"error": {
"option_error": "Z-Wave-validering mislykkedes. Er stien til USB-enhed korrekt?"
},
"step": {
"user": {
"data": {
"network_key": "Netv\u00e6rksn\u00f8gle (efterlad blank for autogenerering)",
"usb_path": "Sti til USB-enhed"
},
"description": "Se https://www.home-assistant.io/docs/z-wave/installation/ for oplysninger om konfigurationsvariabler"
}
}
},
"state": {
"_": {
"dead": "D\u00f8d",
"initializing": "Initialiserer",
"ready": "Klar",
"sleeping": "Sover"
},
"query_stage": {
"dead": "D\u00f8d ({query_stage})",
"initializing": "Initialiserer ( {query_stage} )"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Ger\u00e4t ist bereits konfiguriert",
"single_instance_allowed": "Bereits konfiguriert. Nur eine einzige Konfiguration m\u00f6glich."
},
"error": {
"option_error": "Z-Wave-Validierung fehlgeschlagen. Ist der Pfad zum USB-Stick korrekt?"
},
"step": {
"user": {
"data": {
"network_key": "Netzwerkschl\u00fcssel (leer lassen, um automatisch zu generieren)",
"usb_path": "USB-Ger\u00e4te-Pfad"
},
"description": "Diese Integration wird nicht mehr gepflegt. Verwende bei Neuinstallationen stattdessen Z-Wave JS.\n\nSiehe https://www.home-assistant.io/docs/z-wave/installation/ f\u00fcr Informationen zu den Konfigurationsvariablen"
}
}
},
"state": {
"_": {
"dead": "Nicht erreichbar",
"initializing": "Initialisierend",
"ready": "Bereit",
"sleeping": "Schlafend"
},
"query_stage": {
"dead": "Nicht erreichbar ({query_stage})",
"initializing": "Initialisierend"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u0397 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03ad\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03c9\u03b8\u03b5\u03af",
"single_instance_allowed": "\u0388\u03c7\u03b5\u03b9 \u03ae\u03b4\u03b7 \u03c1\u03c5\u03b8\u03bc\u03b9\u03c3\u03c4\u03b5\u03af. \u039c\u03cc\u03bd\u03bf \u03bc\u03af\u03b1 \u03b4\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae."
},
"error": {
"option_error": "\u0397 \u03b5\u03c0\u03b9\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 Z-Wave \u03b1\u03c0\u03ad\u03c4\u03c5\u03c7\u03b5. \u0395\u03af\u03bd\u03b1\u03b9 \u03c3\u03c9\u03c3\u03c4\u03ae \u03b7 \u03b4\u03b9\u03b1\u03b4\u03c1\u03bf\u03bc\u03ae \u03c0\u03c1\u03bf\u03c2 \u03c4\u03bf \u03c3\u03c4\u03b9\u03ba\u03ac\u03ba\u03b9 USB;"
},
"step": {
"user": {
"data": {
"network_key": "\u039a\u03bb\u03b5\u03b9\u03b4\u03af \u03b4\u03b9\u03ba\u03c4\u03cd\u03bf\u03c5 (\u03b1\u03c6\u03ae\u03c3\u03c4\u03b5 \u03c4\u03bf \u03ba\u03b5\u03bd\u03cc \u03b3\u03b9\u03b1 \u03b1\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b7 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03af\u03b1)",
"usb_path": "\u0394\u03b9\u03b1\u03b4\u03c1\u03bf\u03bc\u03ae \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae\u03c2 USB"
},
"description": "\u0391\u03c5\u03c4\u03ae \u03b7 \u03b5\u03bd\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03b4\u03b5\u03bd \u03b4\u03b9\u03b1\u03c4\u03b7\u03c1\u03b5\u03af\u03c4\u03b1\u03b9 \u03c0\u03bb\u03ad\u03bf\u03bd. \u0393\u03b9\u03b1 \u03bd\u03ad\u03b5\u03c2 \u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ac\u03c3\u03b5\u03b9\u03c2, \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03bf Z-Wave JS. \n\n \u0394\u03b5\u03af\u03c4\u03b5 https://www.home-assistant.io/docs/z-wave/installation/ \u03b3\u03b9\u03b1 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03c3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac \u03bc\u03b5 \u03c4\u03b9\u03c2 \u03bc\u03b5\u03c4\u03b1\u03b2\u03bb\u03b7\u03c4\u03ad\u03c2 \u03b4\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7\u03c2"
}
}
},
"state": {
"_": {
"dead": "\u039d\u03b5\u03ba\u03c1\u03cc",
"initializing": "\u0391\u03c1\u03c7\u03b9\u03ba\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7",
"ready": "\u0388\u03c4\u03bf\u03b9\u03bc\u03bf",
"sleeping": "\u039a\u03bf\u03b9\u03bc\u03ac\u03c4\u03b1\u03b9"
},
"query_stage": {
"dead": "\u039d\u03b5\u03ba\u03c1\u03cc",
"initializing": "\u0391\u03c1\u03c7\u03b9\u03ba\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Device is already configured",
"single_instance_allowed": "Already configured. Only a single configuration possible."
},
"error": {
"option_error": "Z-Wave validation failed. Is the path to the USB stick correct?"
},
"step": {
"user": {
"data": {
"network_key": "Network Key (leave blank to auto-generate)",
"usb_path": "USB Device Path"
},
"description": "This integration is no longer maintained. For new installations, use Z-Wave JS instead.\n\nSee https://www.home-assistant.io/docs/z-wave/installation/ for information on the configuration variables"
}
}
},
"state": {
"_": {
"dead": "Dead",
"initializing": "Initializing",
"ready": "Ready",
"sleeping": "Sleeping"
},
"query_stage": {
"dead": "Dead",
"initializing": "Initializing"
}
}
}

View File

@ -1,31 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Z-Wave ya est\u00e1 configurado"
},
"error": {
"option_error": "La validaci\u00f3n de Z-Wave fall\u00f3. \u00bfEs correcta la ruta a la memoria USB?"
},
"step": {
"user": {
"data": {
"network_key": "Clave de red (dejar en blanco para auto-generar)",
"usb_path": "Ruta USB"
},
"description": "Consulte https://www.home-assistant.io/docs/z-wave/installation/ para obtener informaci\u00f3n sobre las variables de configuraci\u00f3n"
}
}
},
"state": {
"_": {
"dead": "Desconectado",
"initializing": "Iniciando",
"ready": "Listo",
"sleeping": "Hibernacion"
},
"query_stage": {
"dead": "Desconectado ({query_stage})",
"initializing": "Iniciando ( {query_stage} )"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Z-Wave ya est\u00e1 configurado",
"single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n."
},
"error": {
"option_error": "Z-Wave error de validaci\u00f3n. \u00bfLa ruta de acceso a la memoria USB escorrecta?"
},
"step": {
"user": {
"data": {
"network_key": "Clave de red (d\u00e9jelo en blanco para generar autom\u00e1ticamente)",
"usb_path": "Ruta del dispositivo USB"
},
"description": "Consulta https://www.home-assistant.io/docs/z-wave/installation/ para obtener informaci\u00f3n sobre las variables de configuraci\u00f3n"
}
}
},
"state": {
"_": {
"dead": "No responde",
"initializing": "Inicializando",
"ready": "Listo",
"sleeping": "Ahorro de energ\u00eda"
},
"query_stage": {
"dead": "No responde",
"initializing": "Inicializando"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Seade on juba h\u00e4\u00e4lestatud",
"single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine."
},
"error": {
"option_error": "Z-Wave valideerimine nurjus. Kas USB-m\u00e4lupulga tee on \u00f5ige?"
},
"step": {
"user": {
"data": {
"network_key": "V\u00f5rguv\u00f5ti (j\u00e4ta automaatse genereerimise jaoks t\u00fchjaks)",
"usb_path": "USB seadme rada"
},
"description": "Seda sidumist enam ei hallata. Uueks sidumiseks kasuta Z-Wave JS.\n\nKonfiguratsioonimuutujate kohta leiad teavet https://www.home-assistant.io/docs/z-wave/installation/"
}
}
},
"state": {
"_": {
"dead": "Surnud",
"initializing": "L\u00e4htestan",
"ready": "Valmis",
"sleeping": "Ootel"
},
"query_stage": {
"dead": "Surnud",
"initializing": "L\u00e4htestan"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "Hilda",
"initializing": "Hasieratzen",
"ready": "Prest",
"sleeping": "Lotan"
},
"query_stage": {
"dead": "Ez du erantzuten ({query_stage})",
"initializing": "Hasieratzen ({query_stage})"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "\u0645\u0631\u062f\u0647",
"initializing": "\u062f\u0631 \u062d\u0627\u0644 \u0622\u0645\u0627\u062f\u0647 \u0634\u062f\u0646",
"ready": "\u0622\u0645\u0627\u062f\u0647",
"sleeping": "\u062f\u0631 \u062d\u0627\u0644 \u062e\u0648\u0627\u0628"
},
"query_stage": {
"dead": "\u0645\u0631\u062f\u0647 ({query_stage})",
"initializing": "\u062f\u0631 \u062d\u0627\u0644 \u0622\u0645\u0627\u062f\u0647 \u0634\u062f\u0646 ( {query_stage} )"
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"step": {
"user": {
"data": {
"usb_path": "USB-polku"
}
}
}
},
"state": {
"_": {
"dead": "Kuollut",
"initializing": "Alustaa",
"ready": "Valmis",
"sleeping": "Lepotilassa"
},
"query_stage": {
"dead": "Kuollut ({query_stage})",
"initializing": "Alustaa ( {query_stage} )"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9",
"single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible."
},
"error": {
"option_error": "La validation Z-Wave a \u00e9chou\u00e9. Le chemin d'acc\u00e8s \u00e0 la cl\u00e9 USB est-il correct?"
},
"step": {
"user": {
"data": {
"network_key": "Cl\u00e9 r\u00e9seau (laisser vide pour g\u00e9n\u00e9rer automatiquement)",
"usb_path": "Chemin du p\u00e9riph\u00e9rique USB"
},
"description": "Voir https://www.home-assistant.io/docs/z-wave/installation/ pour plus d'informations sur les variables de configuration."
}
}
},
"state": {
"_": {
"dead": "Morte",
"initializing": "Initialisation",
"ready": "Pr\u00eat",
"sleeping": "En veille"
},
"query_stage": {
"dead": "Morte",
"initializing": "Initialisation"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "Tod",
"initializing": "Inizialisi\u00e4r\u00e4",
"ready": "Parat",
"sleeping": "Schlaf\u00e4"
},
"query_stage": {
"dead": "Tod ({query_stage})",
"initializing": "Inizialisi\u00e4r\u00e4 ( {query_stage} )"
}
}
}

View File

@ -1,27 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u05ea\u05e6\u05d5\u05e8\u05ea \u05d4\u05d4\u05ea\u05e7\u05df \u05db\u05d1\u05e8 \u05e0\u05e7\u05d1\u05e2\u05d4",
"single_instance_allowed": "\u05ea\u05e6\u05d5\u05e8\u05ea\u05d5 \u05db\u05d1\u05e8 \u05e0\u05e7\u05d1\u05e2\u05d4. \u05e8\u05e7 \u05ea\u05e6\u05d5\u05e8\u05d4 \u05d0\u05d7\u05ea \u05d0\u05e4\u05e9\u05e8\u05d9\u05ea."
},
"step": {
"user": {
"data": {
"usb_path": "\u05e0\u05ea\u05d9\u05d1 \u05d4\u05ea\u05e7\u05df USB"
}
}
}
},
"state": {
"_": {
"dead": "\u05de\u05ea",
"initializing": "\u05d0\u05ea\u05d7\u05d5\u05dc",
"ready": "\u05de\u05d5\u05db\u05df",
"sleeping": "\u05d9\u05e9\u05df"
},
"query_stage": {
"dead": "\u05de\u05ea",
"initializing": "\u05d0\u05ea\u05d7\u05d5\u05dc"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "\u092e\u0943\u0924",
"initializing": "\u0906\u0930\u0902\u092d",
"ready": "\u0924\u0948\u092f\u093e\u0930",
"sleeping": "\u0938\u094b\u092f\u093e \u0939\u0941\u0906"
},
"query_stage": {
"dead": " ( {query_stage} )",
"initializing": "\u0906\u0930\u0902\u092d ({query_stage})"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "Mrtav",
"initializing": "Inicijalizacija",
"ready": "Spreman",
"sleeping": "Spavanje"
},
"query_stage": {
"dead": "Mrtav ({query_stage})",
"initializing": "Inicijalizacija ( {query_stage} )"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van",
"single_instance_allowed": "M\u00e1r konfigur\u00e1lva van. Csak egy konfigur\u00e1ci\u00f3 lehets\u00e9ges."
},
"error": {
"option_error": "A Z-Wave \u00e9rv\u00e9nyes\u00edt\u00e9s sikertelen. Az USB-meghajt\u00f3 el\u00e9r\u00e9si \u00fatj\u00e1t helyesen adtad meg?"
},
"step": {
"user": {
"data": {
"network_key": "H\u00e1l\u00f3zati kulcs (hagyja \u00fcresen az automatikus gener\u00e1l\u00e1shoz)",
"usb_path": "USB eszk\u00f6z el\u00e9r\u00e9si \u00fat"
},
"description": "Ezt az integr\u00e1ci\u00f3t m\u00e1r nem tartj\u00e1k fenn. \u00daj telep\u00edt\u00e9sek eset\u00e9n haszn\u00e1lja helyette a Z-Wave JS-t.\n\nA konfigur\u00e1ci\u00f3s v\u00e1ltoz\u00f3kkal kapcsolatos inform\u00e1ci\u00f3k\u00e9rt l\u00e1sd https://www.home-assistant.io/docs/z-wave/installation/."
}
}
},
"state": {
"_": {
"dead": "Nem ad \u00e9letjelet",
"initializing": "Inicializ\u00e1l\u00e1s",
"ready": "K\u00e9sz",
"sleeping": "Alv\u00e1s"
},
"query_stage": {
"dead": "Nem ad \u00e9letjelet",
"initializing": "Inicializ\u00e1l\u00e1s"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "\u0544\u0565\u057c\u0561\u056e",
"initializing": "\u0546\u0561\u056d\u0561\u0571\u0565\u057c\u0576\u0578\u0572",
"ready": "\u054a\u0561\u057f\u0580\u0561\u057d\u057f \u0567",
"sleeping": "\u0554\u0576\u0565\u056c"
},
"query_stage": {
"dead": "\u0544\u0561\u0570\u0561\u0581\u0561\u056e{query_stage})",
"initializing": "\u0546\u0561\u056d\u0561\u0571\u0565\u057c\u0576\u0578\u0582\u0569\u0575\u0578\u0582\u0576({query_stage})"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Perangkat sudah dikonfigurasi",
"single_instance_allowed": "Sudah dikonfigurasi. Hanya satu konfigurasi yang diizinkan."
},
"error": {
"option_error": "Validasi Z-Wave gagal. Apakah jalur ke stik USB sudah benar?"
},
"step": {
"user": {
"data": {
"network_key": "Kunci Jaringan (biarkan kosong untuk dibuat secara otomatis)",
"usb_path": "Jalur Perangkat USB"
},
"description": "Integrasi ini tidak lagi dipertahankan. Untuk instalasi baru, gunakan Z-Wave JS sebagai gantinya.\n\nBaca https://www.home-assistant.io/docs/z-wave/installation/ untuk informasi tentang variabel konfigurasi"
}
}
},
"state": {
"_": {
"dead": "Mati",
"initializing": "Inisialisasi",
"ready": "Siap",
"sleeping": "Tidur"
},
"query_stage": {
"dead": "Mati",
"initializing": "Inisialisasi"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "Dau\u00f0ur",
"initializing": "Frumstilli",
"ready": "Tilb\u00fainn",
"sleeping": "\u00cd dvala"
},
"query_stage": {
"dead": "Dau\u00f0ur ({query_stage})",
"initializing": "Frumstilli ({query_stage})"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato",
"single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione."
},
"error": {
"option_error": "Convalida Z-Wave non riuscita. Il percorso della chiavetta USB \u00e8 corretto?"
},
"step": {
"user": {
"data": {
"network_key": "Chiave di rete (lascia vuoto per generare automaticamente)",
"usb_path": "Percorso del dispositivo USB"
},
"description": "Questa integrazione non viene pi\u00f9 mantenuta. Per le nuove installazioni, usa invece Z-Wave JS. \n\nVedere https://www.home-assistant.io/docs/z-wave/installation/ per informazioni sulle variabili di configurazione"
}
}
},
"state": {
"_": {
"dead": "Disattivo",
"initializing": "In avvio",
"ready": "Pronto",
"sleeping": "Dormiente"
},
"query_stage": {
"dead": "Disattivo",
"initializing": "In avvio"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u30c7\u30d0\u30a4\u30b9\u306f\u3059\u3067\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059",
"single_instance_allowed": "\u3059\u3067\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u5358\u4e00\u306e\u8a2d\u5b9a\u3057\u304b\u3067\u304d\u307e\u305b\u3093\u3002"
},
"error": {
"option_error": "Z-Wave\u306e\u691c\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002USB\u30b9\u30c6\u30a3\u30c3\u30af\u3078\u306e\u30d1\u30b9\u306f\u6b63\u3057\u3044\u3067\u3059\u304b\uff1f"
},
"step": {
"user": {
"data": {
"network_key": "\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u30ad\u30fc(\u7a7a\u767d\u306b\u3059\u308b\u3068\u81ea\u52d5\u751f\u6210\u3055\u308c\u307e\u3059)",
"usb_path": "USB\u30c7\u30d0\u30a4\u30b9\u306e\u30d1\u30b9"
},
"description": "\u3053\u306e\u30a4\u30f3\u30c6\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u306f\u7d42\u4e86\u3057\u307e\u3057\u305f\u3002\u65b0\u898f\u306b\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3059\u308b\u5834\u5408\u306f\u3001\u4ee3\u308f\u308a\u306bZ-Wave JS\u3092\u4f7f\u7528\u3057\u3066\u304f\u3060\u3055\u3044\u3002\n\n\u69cb\u6210\u5909\u6570\u306e\u8a73\u7d30\u306b\u3064\u3044\u3066\u306f\u3001https://www.home-assistant.io/docs/z-wave/installation/ \u3092\u53c2\u7167\u3057\u3066\u304f\u3060\u3055\u3044\u3002"
}
}
},
"state": {
"_": {
"dead": "\u30c7\u30c3\u30c9",
"initializing": "\u521d\u671f\u5316\u4e2d",
"ready": "\u6e96\u5099\u5b8c\u4e86",
"sleeping": "\u30b9\u30ea\u30fc\u30d7"
},
"query_stage": {
"dead": "\u30c7\u30c3\u30c9",
"initializing": "\u521d\u671f\u5316\u4e2d"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4",
"single_instance_allowed": "\uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ud558\ub098\uc758 \uc778\uc2a4\ud134\uc2a4\ub9cc \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4."
},
"error": {
"option_error": "Z-Wave \uc720\ud6a8\uc131 \uac80\uc0ac\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. USB \uc2a4\ud2f1\uc758 \uacbd\ub85c\uac00 \uc815\ud655\ud569\ub2c8\uae4c?"
},
"step": {
"user": {
"data": {
"network_key": "\ub124\ud2b8\uc6cc\ud06c \ud0a4 (\uacf5\ub780\uc73c\ub85c \ube44\uc6cc\ub450\uba74 \uc790\ub3d9 \uc0dd\uc131\ud569\ub2c8\ub2e4)",
"usb_path": "USB \uc7a5\uce58 \uacbd\ub85c"
},
"description": "\uc774 \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\ub294 \ub354 \uc774\uc0c1 \uc9c0\uc6d0\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. \uc0c8\ub85c\uc6b4 \uc124\uce58\uc758 \uacbd\uc6b0 Z-Wave JS \ub97c \uc0ac\uc6a9\ud574\uc8fc\uc138\uc694.\n\n\uad6c\uc131 \ubcc0\uc218\uc5d0 \ub300\ud55c \uc815\ubcf4\ub294 https://www.home-assistant.io/docs/z-wave/installation/ \uc744 \ucc38\uc870\ud574\uc8fc\uc138\uc694"
}
}
},
"state": {
"_": {
"dead": "\uc751\ub2f5\uc5c6\uc74c",
"initializing": "\ucd08\uae30\ud654\uc911",
"ready": "\uc900\ube44",
"sleeping": "\uc808\uc804\ubaa8\ub4dc"
},
"query_stage": {
"dead": "\uc751\ub2f5\uc5c6\uc74c",
"initializing": "\ucd08\uae30\ud654\uc911"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Apparat ass scho konfigur\u00e9iert",
"single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun m\u00e9iglech."
},
"error": {
"option_error": "Z-Wave Validatioun net g\u00eblteg. Ass de Pad zum USB Stick richteg?"
},
"step": {
"user": {
"data": {
"network_key": "Netzwierk Schl\u00ebssel (eidel loossen fir een automatesch z'erstellen)",
"usb_path": "Pad zum USB Apparat"
},
"description": "Lies op https://www.home-assistant.io/docs/z-wave/installation/ fir weider Informatiounen iwwert d'Konfiguratioun vun den Variabelen"
}
}
},
"state": {
"_": {
"dead": "Doud",
"initializing": "Initialis\u00e9iert",
"ready": "Bereet",
"sleeping": "Schl\u00e9ift"
},
"query_stage": {
"dead": "Doud",
"initializing": "Initialis\u00e9iert"
}
}
}

View File

@ -1,8 +0,0 @@
{
"state": {
"query_stage": {
"dead": " ({query_stage})",
"initializing": " ( {query_stage} )"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "Beigta",
"initializing": "Inicializ\u0113",
"ready": "Gatavs",
"sleeping": "Gu\u013c"
},
"query_stage": {
"dead": "Beigta ({query_stage})",
"initializing": "Inicializ\u0113 ({query_stage})"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "D\u00f8d",
"initializing": "Initialiserer",
"ready": "Klar",
"sleeping": "Sover"
},
"query_stage": {
"dead": "D\u00f8d ({query_stage})",
"initializing": "Initialiserer ({query_stage})"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Apparaat is al geconfigureerd",
"single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk."
},
"error": {
"option_error": "Z-Wave-validatie mislukt. Is het pad naar de USB-stick correct?"
},
"step": {
"user": {
"data": {
"network_key": "Netwerksleutel (laat leeg om automatisch te genereren)",
"usb_path": "USB-apparaatpad"
},
"description": "Deze integratie wordt niet langer onderhouden. Voor nieuwe installaties, gebruik Z-Wave JS in plaats daarvan.\n\nZie https://www.home-assistant.io/docs/z-wave/installation/ voor informatie over de configuratievariabelen"
}
}
},
"state": {
"_": {
"dead": "Onbereikbaar",
"initializing": "Initialiseren",
"ready": "Gereed",
"sleeping": "Slaapt"
},
"query_stage": {
"dead": "Onbereikbaar",
"initializing": "Initialiseren"
}
}
}

View File

@ -1,21 +0,0 @@
{
"config": {
"step": {
"user": {
"description": "Sj\u00e5 [www.home-assistant.io/docs/z-wave/installation/](https://www.home-assistant.io/docs/z-wave/installation/) for informasjon om konfigurasjonsvariablene."
}
}
},
"state": {
"_": {
"dead": "D\u00f8d",
"initializing": "Initialiserer",
"ready": "Klar",
"sleeping": "S\u00f8v"
},
"query_stage": {
"dead": "D\u00f8d ({query_stage})",
"initializing": "Initialiserer ({query_stage})"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Enheten er allerede konfigurert",
"single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig."
},
"error": {
"option_error": "Z-Wave-validering mislyktes. Er banen til USB dongel riktig?"
},
"step": {
"user": {
"data": {
"network_key": "Nettverksn\u00f8kkel (la v\u00e6re tom for automatisk oppretting)",
"usb_path": "USB enhetsbane"
},
"description": "Denne integrasjonen opprettholdes ikke lenger. For nye installasjoner, bruk Z-Wave JS i stedet. \n\n Se https://www.home-assistant.io/docs/z-wave/installation/ for informasjon om konfigurasjonsvariablene"
}
}
},
"state": {
"_": {
"dead": "D\u00f8d",
"initializing": "Initialiserer",
"ready": "Klar",
"sleeping": "Sover"
},
"query_stage": {
"dead": "D\u00f8d",
"initializing": "Initialiserer"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane",
"single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja."
},
"error": {
"option_error": "Walidacja Z-Wave si\u0119 nie powiod\u0142a. Czy \u015bcie\u017cka do kontrolera Z-Wave USB jest prawid\u0142owa?"
},
"step": {
"user": {
"data": {
"network_key": "Klucz sieciowy (pozostaw pusty, by generowa\u0107 automatycznie)",
"usb_path": "\u015acie\u017cka urz\u0105dzenia USB"
},
"description": "Ta integracja nie jest ju\u017c wspierana. Dla nowych instalacji, u\u017cyj Z-Wave JS.\n\nPrzejd\u017a na https://www.home-assistant.io/docs/z-wave/installation/, aby uzyska\u0107 informacje na temat zmiennych konfiguracyjnych"
}
}
},
"state": {
"_": {
"dead": "martwy",
"initializing": "inicjalizacja",
"ready": "gotowy",
"sleeping": "u\u015bpiony"
},
"query_stage": {
"dead": "martwy",
"initializing": "inicjalizacja"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Dispositivo j\u00e1 est\u00e1 configurado",
"single_instance_allowed": "J\u00e1 configurado. Apenas uma configura\u00e7\u00e3o \u00e9 poss\u00edvel."
},
"error": {
"option_error": "A valida\u00e7\u00e3o Z-Wave falhou. O caminho para o USB est\u00e1 correto?"
},
"step": {
"user": {
"data": {
"network_key": "Chave de rede (deixe em branco para gerar automaticamente)",
"usb_path": "Caminho do Dispositivo USB"
},
"description": "Consulte https://www.home-assistant.io/docs/z-wave/installation/ para obter informa\u00e7\u00f5es sobre as vari\u00e1veis de configura\u00e7\u00e3o"
}
}
},
"state": {
"_": {
"dead": "Morto",
"initializing": "Iniciando",
"ready": "Pronto",
"sleeping": "Dormindo"
},
"query_stage": {
"dead": "Morto",
"initializing": "Iniciando"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "O Z-Wave j\u00e1 est\u00e1 configurado",
"single_instance_allowed": "J\u00e1 configurado. Apenas uma \u00fanica configura\u00e7\u00e3o \u00e9 poss\u00edvel."
},
"error": {
"option_error": "A valida\u00e7\u00e3o Z-Wave falhou. O caminho para o dispositivo USB est\u00e1 correto?"
},
"step": {
"user": {
"data": {
"network_key": "Network Key (deixe em branco para auto-gera\u00e7\u00e3o)",
"usb_path": "Endere\u00e7o USB"
},
"description": "Consulte https://www.home-assistant.io/docs/z-wave/installation/ para obter informa\u00e7\u00f5es sobre as vari\u00e1veis de configura\u00e7\u00e3o"
}
}
},
"state": {
"_": {
"dead": "Morto",
"initializing": "A inicializar",
"ready": "Pronto",
"sleeping": "Adormecido"
},
"query_stage": {
"dead": "Morto ({query_stage})",
"initializing": "A inicializar ({query_stage})"
}
}
}

View File

@ -1,31 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Z-Wave este deja configurat"
},
"error": {
"option_error": "Validarea Z-Wave a e\u0219uat. Este corect\u0103 calea c\u0103tre stick-ul USB?"
},
"step": {
"user": {
"data": {
"network_key": "Cheie de re\u021bea (l\u0103sa\u021bi necompletat pentru a genera automat)",
"usb_path": "Cale USB"
},
"description": "Vede\u021bi https://www.home-assistant.io/docs/z-wave/installation/ pentru informa\u021bii despre variabilele de configurare"
}
}
},
"state": {
"_": {
"dead": "Inactiv",
"initializing": "Se ini\u021bializeaz\u0103",
"ready": "Disponibil",
"sleeping": "Adormit"
},
"query_stage": {
"dead": "Inactiv ({query_stage})",
"initializing": "Se ini\u021bializeaz\u0103 ({query_stage})"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u042d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 Home Assistant.",
"single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e."
},
"error": {
"option_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 Z-Wave. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043f\u0443\u0442\u044c \u043a USB-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443."
},
"step": {
"user": {
"data": {
"network_key": "\u041a\u043b\u044e\u0447 \u0441\u0435\u0442\u0438 (\u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u0443\u0441\u0442\u044b\u043c \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438)",
"usb_path": "\u041f\u0443\u0442\u044c \u043a USB-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443"
},
"description": "\u042d\u0442\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f. \u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0451 Z-Wave JS.\n\n\u041e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/docs/z-wave/installation/) \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430."
}
}
},
"state": {
"_": {
"dead": "\u041d\u0435\u0438\u0441\u043f\u0440\u0430\u0432\u043d\u043e",
"initializing": "\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f",
"ready": "\u0413\u043e\u0442\u043e\u0432",
"sleeping": "\u0420\u0435\u0436\u0438\u043c \u0441\u043d\u0430"
},
"query_stage": {
"dead": "\u041d\u0435\u0438\u0441\u043f\u0440\u0430\u0432\u043d\u043e",
"initializing": "\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f"
}
}
}

View File

@ -1,19 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Zariadenie u\u017e je nakonfigurovan\u00e9"
}
},
"state": {
"_": {
"dead": "Nereaguje",
"initializing": "Inicializ\u00e1cia",
"ready": "Pripraven\u00e9",
"sleeping": "\u00dasporn\u00fd re\u017eim"
},
"query_stage": {
"dead": "Nereaguje ({query_stage})",
"initializing": "Inicializ\u00e1cia ( {query_stage} )"
}
}
}

View File

@ -1,31 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Z-Wave je \u017ee konfiguriran"
},
"error": {
"option_error": "Potrjevanje Z-Wave ni uspelo. Ali je pot do USB klju\u010da pravilna?"
},
"step": {
"user": {
"data": {
"network_key": "Omre\u017eni klju\u010d (pustite prazno za samodejno generiranje)",
"usb_path": "USB Pot"
},
"description": "Za informacije o konfiguracijskih spremenljivka si oglejte https://www.home-assistant.io/docs/z-wave/installation/"
}
}
},
"state": {
"_": {
"dead": "Mrtva",
"initializing": "Inicializacija",
"ready": "Pripravljen",
"sleeping": "Spi"
},
"query_stage": {
"dead": "Mrtva",
"initializing": "Inicializacija"
}
}
}

View File

@ -1,8 +0,0 @@
{
"state": {
"query_stage": {
"dead": " ({query_stage})",
"initializing": " ( {query_stage} )"
}
}
}

View File

@ -1,11 +0,0 @@
{
"state": {
"_": {
"ready": "Spreman"
},
"query_stage": {
"dead": " ({query_stage})",
"initializing": " ( {query_stage} )"
}
}
}

View File

@ -1,31 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Z-Wave \u00e4r redan konfigurerat"
},
"error": {
"option_error": "Z-Wave-valideringen misslyckades. \u00c4r s\u00f6kv\u00e4gen till USB-minnet korrekt?"
},
"step": {
"user": {
"data": {
"network_key": "N\u00e4tverksnyckel (l\u00e4mna blank f\u00f6r automatisk generering)",
"usb_path": "USB-s\u00f6kv\u00e4g"
},
"description": "Se https://www.home-assistant.io/docs/z-wave/installation/ f\u00f6r information om konfigurationsvariabler"
}
}
},
"state": {
"_": {
"dead": "D\u00f6d",
"initializing": "Initierar",
"ready": "Redo",
"sleeping": "Sovande"
},
"query_stage": {
"dead": "D\u00f6d ({query_stage})",
"initializing": "Initierar ({query_stage})"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "\u0b87\u0bb1\u0ba8\u0bcd\u0ba4\u0bc1\u0bb5\u0bbf\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1",
"initializing": "\u0ba4\u0bc1\u0bb5\u0b95\u0bcd\u0b95\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1",
"ready": "\u0ba4\u0baf\u0bbe\u0bb0\u0bcd",
"sleeping": "\u0ba4\u0bc2\u0b99\u0bcd\u0b95\u0bc1\u0b95\u0bbf\u0ba9\u0bcd\u0bb1\u0ba4\u0bc1"
},
"query_stage": {
"dead": "\u0b87\u0bb1\u0ba8\u0bcd\u0ba4\u0bc1\u0bb5\u0bbf\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1 ({query_stage})",
"initializing": "\u0ba4\u0bc1\u0bb5\u0b95\u0bcd\u0b95\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1 ( {query_stage} )"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "\u0c2e\u0c43\u0c24 \u0c2a\u0c30\u0c3f\u0c15\u0c30\u0c02",
"initializing": "\u0c38\u0c3f\u0c26\u0c4d\u0c27\u0c02 \u0c05\u0c35\u0c41\u0c24\u0c4b\u0c02\u0c26\u0c3f",
"ready": "\u0c30\u0c46\u0c21\u0c40",
"sleeping": "\u0c28\u0c3f\u0c26\u0c4d\u0c30\u0c3f\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f"
},
"query_stage": {
"dead": "\u0c2e\u0c43\u0c24 \u0c2a\u0c30\u0c3f\u0c15\u0c30\u0c02 ({query_stage})",
"initializing": "\u0c38\u0c3f\u0c26\u0c4d\u0c27\u0c02 \u0c05\u0c35\u0c41\u0c24\u0c4b\u0c02\u0c26\u0c3f ( {query_stage} )"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "\u0e44\u0e21\u0e48\u0e1e\u0e23\u0e49\u0e2d\u0e21\u0e43\u0e0a\u0e49\u0e07\u0e32\u0e19",
"initializing": "\u0e01\u0e33\u0e25\u0e31\u0e07\u0e40\u0e23\u0e34\u0e48\u0e21\u0e15\u0e49\u0e19",
"ready": "\u0e1e\u0e23\u0e49\u0e2d\u0e21\u0e43\u0e0a\u0e49\u0e07\u0e32\u0e19",
"sleeping": "\u0e01\u0e33\u0e25\u0e31\u0e07\u0e2b\u0e25\u0e31\u0e1a"
},
"query_stage": {
"dead": "\u0e44\u0e21\u0e48\u0e1e\u0e23\u0e49\u0e2d\u0e21\u0e43\u0e0a\u0e49\u0e07\u0e32\u0e19 ({query_stage})",
"initializing": "\u0e01\u0e33\u0e25\u0e31\u0e07\u0e40\u0e23\u0e34\u0e48\u0e21\u0e15\u0e49\u0e19 ( {query_stage} )"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Cihaz zaten yap\u0131land\u0131r\u0131lm\u0131\u015f",
"single_instance_allowed": "Zaten yap\u0131land\u0131r\u0131lm\u0131\u015f. Yaln\u0131zca tek bir konfig\u00fcrasyon m\u00fcmk\u00fcnd\u00fcr."
},
"error": {
"option_error": "Z-Wave do\u011frulamas\u0131 ba\u015far\u0131s\u0131z oldu. USB stickin yolu do\u011fru mu?"
},
"step": {
"user": {
"data": {
"network_key": "A\u011f Anajtar\u0131 (otomatik \u00fcretilmesi i\u00e7in bo\u015f b\u0131rak\u0131n\u0131z)",
"usb_path": "USB Cihaz Yolu"
},
"description": "Bu entegrasyon art\u0131k korunmuyor. Yeni kurulumlar i\u00e7in bunun yerine Z-Wave JS kullan\u0131n. \n\n Yap\u0131land\u0131rma de\u011fi\u015fkenleri hakk\u0131nda bilgi i\u00e7in https://www.home-assistant.io/docs/z-wave/installation/ adresine bak\u0131n."
}
}
},
"state": {
"_": {
"dead": "\u00d6l\u00fc",
"initializing": "Ba\u015flat\u0131l\u0131yor",
"ready": "Haz\u0131r",
"sleeping": "Uyuyor"
},
"query_stage": {
"dead": "\u00d6l\u00fc",
"initializing": "Ba\u015flat\u0131l\u0131yor"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u0426\u0435\u0439 \u043f\u0440\u0438\u0441\u0442\u0440\u0456\u0439 \u0432\u0436\u0435 \u0434\u043e\u0434\u0430\u043d\u043e \u0432 Home Assistant.",
"single_instance_allowed": "\u0412\u0436\u0435 \u043d\u0430\u043b\u0430\u0448\u0442\u043e\u0432\u0430\u043d\u043e. \u041c\u043e\u0436\u043b\u0438\u0432\u0430 \u043b\u0438\u0448\u0435 \u043e\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0456\u0433\u0443\u0440\u0430\u0446\u0456\u044f."
},
"error": {
"option_error": "\u041f\u043e\u043c\u0438\u043b\u043a\u0430 \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0438 Z-Wave. \u041f\u0435\u0440\u0435\u0432\u0456\u0440\u0442\u0435 \u0448\u043b\u044f\u0445 \u0434\u043e USB-\u043f\u0440\u0438\u0441\u0442\u0440\u043e\u044e."
},
"step": {
"user": {
"data": {
"network_key": "\u041a\u043b\u044e\u0447 \u043c\u0435\u0440\u0435\u0436\u0456 (\u0437\u0430\u043b\u0438\u0448\u0442\u0435 \u043f\u043e\u0440\u043e\u0436\u043d\u0456\u043c \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438)",
"usb_path": "\u0428\u043b\u044f\u0445 \u0434\u043e USB-\u043f\u0440\u0438\u0441\u0442\u0440\u043e\u044e"
},
"description": "\u041e\u0437\u043d\u0430\u0439\u043e\u043c\u0442\u0435\u0441\u044f \u0437 [\u0456\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0456\u044f\u043c\u0438](https://www.home-assistant.io/docs/z-wave/installation/) \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u043c\u0430\u043d\u043d\u044f \u0431\u0456\u043b\u044c\u0448 \u0434\u043e\u043a\u043b\u0430\u0434\u043d\u043e\u0457 \u0456\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0457 \u043f\u0440\u043e \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430."
}
}
},
"state": {
"_": {
"dead": "\u041d\u0435\u0441\u043f\u0440\u0430\u0432\u043d\u0438\u0439",
"initializing": "\u0406\u043d\u0456\u0446\u0456\u0430\u043b\u0456\u0437\u0430\u0446\u0456\u044f",
"ready": "\u0413\u043e\u0442\u043e\u0432\u0438\u0439",
"sleeping": "\u0420\u0435\u0436\u0438\u043c \u0441\u043d\u0443"
},
"query_stage": {
"dead": "\u041d\u0435\u0441\u043f\u0440\u0430\u0432\u043d\u0438\u0439",
"initializing": "\u0406\u043d\u0456\u0446\u0456\u0430\u043b\u0456\u0437\u0430\u0446\u0456\u044f"
}
}
}

View File

@ -1,14 +0,0 @@
{
"state": {
"_": {
"dead": "\u0110\u00e3 t\u1eaft",
"initializing": "Kh\u1edfi t\u1ea1o",
"ready": "S\u1eb5n s\u00e0ng",
"sleeping": "Ng\u1ee7"
},
"query_stage": {
"dead": "\u0110\u00e3 t\u1eaft ({query_stage})",
"initializing": "Kh\u1edfi t\u1ea1o ( {query_stage} )"
}
}
}

View File

@ -1,31 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Z-Wave \u5df2\u914d\u7f6e\u5b8c\u6210"
},
"error": {
"option_error": "Z-Wave \u9a8c\u8bc1\u5931\u8d25\u3002 USB \u68d2\u7684\u8def\u5f84\u662f\u5426\u6b63\u786e\uff1f"
},
"step": {
"user": {
"data": {
"network_key": "\u7f51\u7edc\u5bc6\u94a5\uff08\u7559\u7a7a\u5c06\u81ea\u52a8\u751f\u6210\uff09",
"usb_path": "USB \u8def\u5f84"
},
"description": "\u6709\u5173\u914d\u7f6e\u7684\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 https://www.home-assistant.io/docs/z-wave/installation/"
}
}
},
"state": {
"_": {
"dead": "\u65ad\u5f00",
"initializing": "\u521d\u59cb\u5316",
"ready": "\u5c31\u7eea",
"sleeping": "\u4f11\u7720"
},
"query_stage": {
"dead": "\u65ad\u5f00 ({query_stage})",
"initializing": "\u521d\u59cb\u5316 ({query_stage})"
}
}
}

View File

@ -1,32 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u88dd\u7f6e\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210",
"single_instance_allowed": "\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210\u3001\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u88dd\u7f6e\u3002"
},
"error": {
"option_error": "Z-Wave \u9a57\u8b49\u5931\u6557\uff0c\u8acb\u78ba\u5b9a USB \u96a8\u8eab\u789f\u8def\u5f91\u6b63\u78ba\uff1f"
},
"step": {
"user": {
"data": {
"network_key": "\u7db2\u8def\u91d1\u9470\uff08\u4fdd\u7559\u7a7a\u767d\u5c07\u6703\u81ea\u52d5\u7522\u751f\uff09",
"usb_path": "USB \u88dd\u7f6e\u8def\u5f91"
},
"description": "\u6b64\u6574\u5408\u5df2\u7d93\u4e0d\u518d\u9032\u884c\u7dad\u8b77\uff0c\u8acb\u4f7f\u7528 Z-Wave JS \u53d6\u4ee3\u70ba\u65b0\u5b89\u88dd\u65b9\u5f0f\u3002\n\n\u8acb\u53c3\u95b1 https://www.home-assistant.io/docs/z-wave/installation/ \u4ee5\n\u7372\u5f97\u8a2d\u5b9a\u8b8a\u6578\u8cc7\u8a0a"
}
}
},
"state": {
"_": {
"dead": "\u5931\u53bb\u9023\u7dda",
"initializing": "\u6b63\u5728\u521d\u59cb\u5316",
"ready": "\u6e96\u5099\u5c31\u7dd2",
"sleeping": "\u4f11\u7720\u4e2d"
},
"query_stage": {
"dead": "\u5931\u53bb\u9023\u7dda",
"initializing": "\u6b63\u5728\u521d\u59cb\u5316"
}
}
}

View File

@ -1,129 +0,0 @@
"""Zwave util methods."""
import asyncio
import logging
import homeassistant.util.dt as dt_util
from . import const
_LOGGER = logging.getLogger(__name__)
def check_node_schema(node, schema):
"""Check if node matches the passed node schema."""
if const.DISC_NODE_ID in schema and node.node_id not in schema[const.DISC_NODE_ID]:
_LOGGER.debug(
"node.node_id %s not in node_id %s",
node.node_id,
schema[const.DISC_NODE_ID],
)
return False
if (
const.DISC_GENERIC_DEVICE_CLASS in schema
and node.generic not in schema[const.DISC_GENERIC_DEVICE_CLASS]
):
_LOGGER.debug(
"node.generic %s not in generic_device_class %s",
node.generic,
schema[const.DISC_GENERIC_DEVICE_CLASS],
)
return False
if (
const.DISC_SPECIFIC_DEVICE_CLASS in schema
and node.specific not in schema[const.DISC_SPECIFIC_DEVICE_CLASS]
):
_LOGGER.debug(
"node.specific %s not in specific_device_class %s",
node.specific,
schema[const.DISC_SPECIFIC_DEVICE_CLASS],
)
return False
return True
def check_value_schema(value, schema):
"""Check if the value matches the passed value schema."""
if (
const.DISC_COMMAND_CLASS in schema
and value.command_class not in schema[const.DISC_COMMAND_CLASS]
):
_LOGGER.debug(
"value.command_class %s not in command_class %s",
value.command_class,
schema[const.DISC_COMMAND_CLASS],
)
return False
if const.DISC_TYPE in schema and value.type not in schema[const.DISC_TYPE]:
_LOGGER.debug(
"value.type %s not in type %s", value.type, schema[const.DISC_TYPE]
)
return False
if const.DISC_GENRE in schema and value.genre not in schema[const.DISC_GENRE]:
_LOGGER.debug(
"value.genre %s not in genre %s", value.genre, schema[const.DISC_GENRE]
)
return False
if const.DISC_INDEX in schema and value.index not in schema[const.DISC_INDEX]:
_LOGGER.debug(
"value.index %s not in index %s", value.index, schema[const.DISC_INDEX]
)
return False
if (
const.DISC_INSTANCE in schema
and value.instance not in schema[const.DISC_INSTANCE]
):
_LOGGER.debug(
"value.instance %s not in instance %s",
value.instance,
schema[const.DISC_INSTANCE],
)
return False
if const.DISC_SCHEMAS in schema:
found = False
for schema_item in schema[const.DISC_SCHEMAS]:
found = found or check_value_schema(value, schema_item)
if not found:
return False
return True
def compute_value_unique_id(node, value):
"""Compute unique_id a value would get if it were to get one."""
return f"{node.node_id}-{value.object_id}"
def node_name(node):
"""Return the name of the node."""
if is_node_parsed(node):
return node.name or f"{node.manufacturer_name} {node.product_name}"
return f"Unknown Node {node.node_id}"
def node_device_id_and_name(node, instance=1):
"""Return the name and device ID for the value with the given index."""
name = node_name(node)
if instance == 1:
return ((const.DOMAIN, node.node_id), name)
name = f"{name} ({instance})"
return ((const.DOMAIN, node.node_id, instance), name)
async def check_has_unique_id(entity, ready_callback, timeout_callback):
"""Wait for entity to have unique_id."""
start_time = dt_util.utcnow()
while True:
waited = int((dt_util.utcnow() - start_time).total_seconds())
if entity.unique_id:
ready_callback(waited)
return
if waited >= const.NODE_READY_WAIT_SECS:
# Wait up to NODE_READY_WAIT_SECS seconds for unique_id to appear.
timeout_callback(waited)
return
await asyncio.sleep(1)
def is_node_parsed(node):
"""Check whether the node has been parsed or still waiting to be parsed."""
return bool((node.manufacturer_name and node.product_name) or node.name)

View File

@ -1,90 +0,0 @@
"""Web socket API for Z-Wave."""
import voluptuous as vol
from homeassistant.components import websocket_api
from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.core import callback
from .const import (
CONF_AUTOHEAL,
CONF_DEBUG,
CONF_NETWORK_KEY,
CONF_POLLING_INTERVAL,
CONF_USB_STICK_PATH,
DATA_NETWORK,
DATA_ZWAVE_CONFIG,
)
TYPE = "type"
ID = "id"
@websocket_api.require_admin
@websocket_api.websocket_command({vol.Required(TYPE): "zwave/network_status"})
def websocket_network_status(hass, connection, msg):
"""Get Z-Wave network status."""
network = hass.data[DATA_NETWORK]
connection.send_result(msg[ID], {"state": network.state})
@websocket_api.require_admin
@websocket_api.websocket_command({vol.Required(TYPE): "zwave/get_config"})
def websocket_get_config(hass, connection, msg):
"""Get Z-Wave configuration."""
config = hass.data[DATA_ZWAVE_CONFIG]
connection.send_result(
msg[ID],
{
CONF_AUTOHEAL: config[CONF_AUTOHEAL],
CONF_DEBUG: config[CONF_DEBUG],
CONF_POLLING_INTERVAL: config[CONF_POLLING_INTERVAL],
CONF_USB_STICK_PATH: config[CONF_USB_STICK_PATH],
},
)
@websocket_api.require_admin
@websocket_api.websocket_command({vol.Required(TYPE): "zwave/get_migration_config"})
def websocket_get_migration_config(hass, connection, msg):
"""Get Z-Wave configuration for migration."""
config = hass.data[DATA_ZWAVE_CONFIG]
connection.send_result(
msg[ID],
{
CONF_USB_STICK_PATH: config[CONF_USB_STICK_PATH],
CONF_NETWORK_KEY: config[CONF_NETWORK_KEY],
},
)
@websocket_api.require_admin
@websocket_api.websocket_command(
{vol.Required(TYPE): "zwave/start_zwave_js_config_flow"}
)
@websocket_api.async_response
async def websocket_start_zwave_js_config_flow(hass, connection, msg):
"""Start the Z-Wave JS integration config flow (for migration wizard).
Return data with the flow id of the started Z-Wave JS config flow.
"""
config = hass.data[DATA_ZWAVE_CONFIG]
data = {
"usb_path": config[CONF_USB_STICK_PATH],
"network_key": config[CONF_NETWORK_KEY],
}
result = await hass.config_entries.flow.async_init(
"zwave_js", context={"source": SOURCE_IMPORT}, data=data
)
connection.send_result(
msg[ID],
{"flow_id": result["flow_id"]},
)
@callback
def async_load_websocket_api(hass):
"""Set up the web socket API."""
websocket_api.async_register_command(hass, websocket_network_status)
websocket_api.async_register_command(hass, websocket_get_config)
websocket_api.async_register_command(hass, websocket_get_migration_config)
websocket_api.async_register_command(hass, websocket_start_zwave_js_config_flow)

View File

@ -1,170 +0,0 @@
"""Z-Wave workarounds."""
from . import const
# Manufacturers
FIBARO = 0x010F
GE = 0x0063
PHILIO = 0x013C
SOMFY = 0x0047
WENZHOU = 0x0118
LEVITON = 0x001D
# Product IDs
GE_FAN_CONTROLLER_12730 = 0x3034
GE_FAN_CONTROLLER_14287 = 0x3131
JASCO_FAN_CONTROLLER_14314 = 0x3138
PHILIO_SLIM_SENSOR = 0x0002
PHILIO_3_IN_1_SENSOR_GEN_4 = 0x000D
PHILIO_PAN07 = 0x0005
VIZIA_FAN_CONTROLLER_VRF01 = 0x0334
LEVITON_DECORA_FAN_CONTROLLER_ZW4SF = 0x0002
# Product Types
FGFS101_FLOOD_SENSOR_TYPE = 0x0B00
FGRM222_SHUTTER2 = 0x0301
FGR222_SHUTTER2 = 0x0302
GE_DIMMER = 0x4944
PHILIO_SWITCH = 0x0001
PHILIO_SENSOR = 0x0002
SOMFY_ZRTSI = 0x5A52
VIZIA_DIMMER = 0x1001
LEVITON_DECORA_FAN_CONTROLLER = 0x0038
# Mapping devices
PHILIO_SLIM_SENSOR_MOTION_MTII = (PHILIO, PHILIO_SENSOR, PHILIO_SLIM_SENSOR, 0)
PHILIO_3_IN_1_SENSOR_GEN_4_MOTION_MTII = (
PHILIO,
PHILIO_SENSOR,
PHILIO_3_IN_1_SENSOR_GEN_4,
0,
)
PHILIO_PAN07_MTI_INSTANCE = (PHILIO, PHILIO_SWITCH, PHILIO_PAN07, 1)
WENZHOU_SLIM_SENSOR_MOTION_MTII = (WENZHOU, PHILIO_SENSOR, PHILIO_SLIM_SENSOR, 0)
# Workarounds
WORKAROUND_NO_OFF_EVENT = "trigger_no_off_event"
WORKAROUND_NO_POSITION = "workaround_no_position"
WORKAROUND_REFRESH_NODE_ON_UPDATE = "refresh_node_on_update"
WORKAROUND_IGNORE = "workaround_ignore"
# List of workarounds by (manufacturer_id, product_type, product_id, index)
DEVICE_MAPPINGS_MTII = {
PHILIO_SLIM_SENSOR_MOTION_MTII: WORKAROUND_NO_OFF_EVENT,
PHILIO_3_IN_1_SENSOR_GEN_4_MOTION_MTII: WORKAROUND_NO_OFF_EVENT,
WENZHOU_SLIM_SENSOR_MOTION_MTII: WORKAROUND_NO_OFF_EVENT,
}
# List of workarounds by (manufacturer_id, product_type, product_id, instance)
DEVICE_MAPPINGS_MTI_INSTANCE = {
PHILIO_PAN07_MTI_INSTANCE: WORKAROUND_REFRESH_NODE_ON_UPDATE
}
SOMFY_ZRTSI_CONTROLLER_MT = (SOMFY, SOMFY_ZRTSI)
# List of workarounds by (manufacturer_id, product_type)
DEVICE_MAPPINGS_MT = {SOMFY_ZRTSI_CONTROLLER_MT: WORKAROUND_NO_POSITION}
# Component mapping devices
FIBARO_FGFS101_SENSOR_ALARM = (
FIBARO,
FGFS101_FLOOD_SENSOR_TYPE,
const.COMMAND_CLASS_SENSOR_ALARM,
)
FIBARO_FGRM222_BINARY = (FIBARO, FGRM222_SHUTTER2, const.COMMAND_CLASS_SWITCH_BINARY)
FIBARO_FGR222_BINARY = (FIBARO, FGR222_SHUTTER2, const.COMMAND_CLASS_SWITCH_BINARY)
GE_FAN_CONTROLLER_12730_MULTILEVEL = (
GE,
GE_DIMMER,
GE_FAN_CONTROLLER_12730,
const.COMMAND_CLASS_SWITCH_MULTILEVEL,
)
GE_FAN_CONTROLLER_14287_MULTILEVEL = (
GE,
GE_DIMMER,
GE_FAN_CONTROLLER_14287,
const.COMMAND_CLASS_SWITCH_MULTILEVEL,
)
JASCO_FAN_CONTROLLER_14314_MULTILEVEL = (
GE,
GE_DIMMER,
JASCO_FAN_CONTROLLER_14314,
const.COMMAND_CLASS_SWITCH_MULTILEVEL,
)
VIZIA_FAN_CONTROLLER_VRF01_MULTILEVEL = (
LEVITON,
VIZIA_DIMMER,
VIZIA_FAN_CONTROLLER_VRF01,
const.COMMAND_CLASS_SWITCH_MULTILEVEL,
)
LEVITON_FAN_CONTROLLER_ZW4SF_MULTILEVEL = (
LEVITON,
LEVITON_DECORA_FAN_CONTROLLER,
LEVITON_DECORA_FAN_CONTROLLER_ZW4SF,
const.COMMAND_CLASS_SWITCH_MULTILEVEL,
)
# List of component workarounds by
# (manufacturer_id, product_type, command_class)
DEVICE_COMPONENT_MAPPING = {
FIBARO_FGFS101_SENSOR_ALARM: "binary_sensor",
FIBARO_FGRM222_BINARY: WORKAROUND_IGNORE,
FIBARO_FGR222_BINARY: WORKAROUND_IGNORE,
}
# List of component workarounds by
# (manufacturer_id, product_type, product_id, command_class)
DEVICE_COMPONENT_MAPPING_MTI = {
GE_FAN_CONTROLLER_12730_MULTILEVEL: "fan",
GE_FAN_CONTROLLER_14287_MULTILEVEL: "fan",
JASCO_FAN_CONTROLLER_14314_MULTILEVEL: "fan",
VIZIA_FAN_CONTROLLER_VRF01_MULTILEVEL: "fan",
LEVITON_FAN_CONTROLLER_ZW4SF_MULTILEVEL: "fan",
}
def get_device_component_mapping(value):
"""Get mapping of value to another component."""
if value.node.manufacturer_id.strip() and value.node.product_type.strip():
manufacturer_id = int(value.node.manufacturer_id, 16)
product_type = int(value.node.product_type, 16)
product_id = int(value.node.product_id, 16)
result = DEVICE_COMPONENT_MAPPING.get(
(manufacturer_id, product_type, value.command_class)
)
if result:
return result
result = DEVICE_COMPONENT_MAPPING_MTI.get(
(manufacturer_id, product_type, product_id, value.command_class)
)
if result:
return result
return None
def get_device_mapping(value):
"""Get mapping of value to a workaround."""
if (
value.node.manufacturer_id.strip()
and value.node.product_id.strip()
and value.node.product_type.strip()
):
manufacturer_id = int(value.node.manufacturer_id, 16)
product_type = int(value.node.product_type, 16)
product_id = int(value.node.product_id, 16)
result = DEVICE_MAPPINGS_MTII.get(
(manufacturer_id, product_type, product_id, value.index)
)
if result:
return result
result = DEVICE_MAPPINGS_MTI_INSTANCE.get(
(manufacturer_id, product_type, product_id, value.instance)
)
if result:
return result
return DEVICE_MAPPINGS_MT.get((manufacturer_id, product_type))
return None

View File

@ -394,7 +394,6 @@ FLOWS = [
"youless",
"zerproc",
"zha",
"zwave",
"zwave_js",
"zwave_me"
]

View File

@ -2917,12 +2917,3 @@ ignore_errors = true
[mypy-homeassistant.components.zha.switch]
ignore_errors = true
[mypy-homeassistant.components.zwave]
ignore_errors = true
[mypy-homeassistant.components.zwave.migration]
ignore_errors = true
[mypy-homeassistant.components.zwave.node_entity]
ignore_errors = true

View File

@ -811,9 +811,6 @@ holidays==0.13
# homeassistant.components.frontend
home-assistant-frontend==20220317.0
# homeassistant.components.zwave
# homeassistant-pyozw==0.1.10
# homeassistant.components.home_connect
homeconnect==0.7.0
@ -1424,9 +1421,6 @@ pydelijn==1.0.0
# homeassistant.components.dexcom
pydexcom==0.2.3
# homeassistant.components.zwave
pydispatcher==2.0.5
# homeassistant.components.doods
pydoods==1.0.2

View File

@ -561,9 +561,6 @@ holidays==0.13
# homeassistant.components.frontend
home-assistant-frontend==20220317.0
# homeassistant.components.zwave
# homeassistant-pyozw==0.1.10
# homeassistant.components.home_connect
homeconnect==0.7.0
@ -931,9 +928,6 @@ pydeconz==87
# homeassistant.components.dexcom
pydexcom==0.2.3
# homeassistant.components.zwave
pydispatcher==2.0.5
# homeassistant.components.econet
pyeconet==0.1.15

View File

@ -23,7 +23,6 @@ COMMENT_REQUIREMENTS = (
"decora_wifi",
"evdev",
"face_recognition",
"homeassistant-pyozw",
"opencv-python-headless",
"pybluez",
"pycups",

View File

@ -214,9 +214,6 @@ IGNORED_MODULES: Final[list[str]] = [
"homeassistant.components.zha.sensor",
"homeassistant.components.zha.siren",
"homeassistant.components.zha.switch",
"homeassistant.components.zwave",
"homeassistant.components.zwave.migration",
"homeassistant.components.zwave.node_entity",
]
# Component modules which should set no_implicit_reexport = true.

View File

@ -237,7 +237,7 @@ STATE_REWRITE = {
"[%key:state::lock::unlocked%]": "[%key:common::state::unlocked%]",
}
SKIP_DOMAIN = {"default", "scene"}
STATES_WITH_DEV_CLASS = {"binary_sensor", "zwave"}
STATES_WITH_DEV_CLASS = {"binary_sensor"}
GROUP_DELETE = {"opening", "closing", "stopped"} # They don't exist

View File

@ -1,49 +1,8 @@
"""Test config init."""
from unittest.mock import patch
from homeassistant.components import config
from homeassistant.const import EVENT_COMPONENT_LOADED
from homeassistant.setup import ATTR_COMPONENT, async_setup_component
from tests.common import mock_component
from homeassistant.setup import async_setup_component
async def test_config_setup(hass, loop):
"""Test it sets up hassbian."""
await async_setup_component(hass, "config", {})
assert "config" in hass.config.components
async def test_load_on_demand_already_loaded(hass, aiohttp_client):
"""Test getting suites."""
mock_component(hass, "zwave")
with patch.object(config, "SECTIONS", []), patch.object(
config, "ON_DEMAND", ["zwave"]
), patch(
"homeassistant.components.config.zwave.async_setup", return_value=True
) as stp:
await async_setup_component(hass, "config", {})
await hass.async_block_till_done()
assert stp.called
async def test_load_on_demand_on_load(hass, aiohttp_client):
"""Test getting suites."""
with patch.object(config, "SECTIONS", []), patch.object(
config, "ON_DEMAND", ["zwave"]
):
await async_setup_component(hass, "config", {})
assert "config.zwave" not in hass.config.components
with patch(
"homeassistant.components.config.zwave.async_setup", return_value=True
) as stp:
hass.bus.async_fire(EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: "zwave"})
await hass.async_block_till_done()
assert stp.called

View File

@ -1,542 +0,0 @@
"""Test Z-Wave config panel."""
from http import HTTPStatus
import json
from unittest.mock import MagicMock, patch
import pytest
from homeassistant.bootstrap import async_setup_component
from homeassistant.components import config
from homeassistant.components.zwave import DATA_NETWORK, const
from tests.mock.zwave import MockEntityValues, MockNode, MockValue
VIEW_NAME = "api:config:zwave:device_config"
@pytest.fixture
def client(loop, hass, hass_client):
"""Client to communicate with Z-Wave config views."""
with patch.object(config, "SECTIONS", ["zwave"]):
loop.run_until_complete(async_setup_component(hass, "config", {}))
return loop.run_until_complete(hass_client())
async def test_get_device_config(client):
"""Test getting device config."""
def mock_read(path):
"""Mock reading data."""
return {"hello.beer": {"free": "beer"}, "other.entity": {"do": "something"}}
with patch("homeassistant.components.config._read", mock_read):
resp = await client.get("/api/config/zwave/device_config/hello.beer")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"free": "beer"}
async def test_update_device_config(client):
"""Test updating device config."""
orig_data = {
"hello.beer": {"ignored": True},
"other.entity": {"polling_intensity": 2},
}
def mock_read(path):
"""Mock reading data."""
return orig_data
written = []
def mock_write(path, data):
"""Mock writing data."""
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
):
resp = await client.post(
"/api/config/zwave/device_config/hello.beer",
data=json.dumps({"polling_intensity": 2}),
)
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
orig_data["hello.beer"]["polling_intensity"] = 2
assert written[0] == orig_data
async def test_update_device_config_invalid_key(client):
"""Test updating device config."""
resp = await client.post(
"/api/config/zwave/device_config/invalid_entity",
data=json.dumps({"polling_intensity": 2}),
)
assert resp.status == HTTPStatus.BAD_REQUEST
async def test_update_device_config_invalid_data(client):
"""Test updating device config."""
resp = await client.post(
"/api/config/zwave/device_config/hello.beer",
data=json.dumps({"invalid_option": 2}),
)
assert resp.status == HTTPStatus.BAD_REQUEST
async def test_update_device_config_invalid_json(client):
"""Test updating device config."""
resp = await client.post(
"/api/config/zwave/device_config/hello.beer", data="not json"
)
assert resp.status == HTTPStatus.BAD_REQUEST
async def test_get_values(hass, client):
"""Test getting values on node."""
node = MockNode(node_id=1)
value = MockValue(
value_id=123456,
node=node,
label="Test Label",
instance=1,
index=2,
poll_intensity=4,
)
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]
resp = await client.get("/api/zwave/values/1")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {
"123456": {
"label": "Test Label",
"instance": 1,
"index": 2,
"poll_intensity": 4,
}
}
async def test_get_groups(hass, client):
"""Test getting groupdata on node."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=2)
node.groups.associations = "assoc"
node.groups.associations_instances = "inst"
node.groups.label = "the label"
node.groups.max_associations = "max"
node.groups = {1: node.groups}
network.nodes = {2: node}
resp = await client.get("/api/zwave/groups/2")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {
"1": {
"association_instances": "inst",
"associations": "assoc",
"label": "the label",
"max_associations": "max",
}
}
async def test_get_groups_nogroups(hass, client):
"""Test getting groupdata on node with no groups."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=2)
network.nodes = {2: node}
resp = await client.get("/api/zwave/groups/2")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {}
async def test_get_groups_nonode(hass, client):
"""Test getting groupdata on nonexisting node."""
network = hass.data[DATA_NETWORK] = MagicMock()
network.nodes = {1: 1, 5: 5}
resp = await client.get("/api/zwave/groups/2")
assert resp.status == HTTPStatus.NOT_FOUND
result = await resp.json()
assert result == {"message": "Node not found"}
async def test_get_config(hass, client):
"""Test getting config on node."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=2)
value = MockValue(index=12, command_class=const.COMMAND_CLASS_CONFIGURATION)
value.label = "label"
value.help = "help"
value.type = "type"
value.data = "data"
value.data_items = ["item1", "item2"]
value.max = "max"
value.min = "min"
node.values = {12: value}
network.nodes = {2: node}
node.get_values.return_value = node.values
resp = await client.get("/api/zwave/config/2")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {
"12": {
"data": "data",
"data_items": ["item1", "item2"],
"help": "help",
"label": "label",
"max": "max",
"min": "min",
"type": "type",
}
}
async def test_get_config_noconfig_node(hass, client):
"""Test getting config on node without config."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=2)
network.nodes = {2: node}
node.get_values.return_value = node.values
resp = await client.get("/api/zwave/config/2")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {}
async def test_get_config_nonode(hass, client):
"""Test getting config on nonexisting node."""
network = hass.data[DATA_NETWORK] = MagicMock()
network.nodes = {1: 1, 5: 5}
resp = await client.get("/api/zwave/config/2")
assert resp.status == HTTPStatus.NOT_FOUND
result = await resp.json()
assert result == {"message": "Node not found"}
async def test_get_usercodes_nonode(hass, client):
"""Test getting usercodes on nonexisting node."""
network = hass.data[DATA_NETWORK] = MagicMock()
network.nodes = {1: 1, 5: 5}
resp = await client.get("/api/zwave/usercodes/2")
assert resp.status == HTTPStatus.NOT_FOUND
result = await resp.json()
assert result == {"message": "Node not found"}
async def test_get_usercodes(hass, client):
"""Test getting usercodes on node."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_USER_CODE])
value = MockValue(index=0, command_class=const.COMMAND_CLASS_USER_CODE)
value.genre = const.GENRE_USER
value.label = "label"
value.data = "1234"
node.values = {0: value}
network.nodes = {18: node}
node.get_values.return_value = node.values
resp = await client.get("/api/zwave/usercodes/18")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"0": {"code": "1234", "label": "label", "length": 4}}
async def test_get_usercode_nousercode_node(hass, client):
"""Test getting usercodes on node without usercodes."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=18)
network.nodes = {18: node}
node.get_values.return_value = node.values
resp = await client.get("/api/zwave/usercodes/18")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {}
async def test_get_usercodes_no_genreuser(hass, client):
"""Test getting usercodes on node missing genre user."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_USER_CODE])
value = MockValue(index=0, command_class=const.COMMAND_CLASS_USER_CODE)
value.genre = const.GENRE_SYSTEM
value.label = "label"
value.data = "1234"
node.values = {0: value}
network.nodes = {18: node}
node.get_values.return_value = node.values
resp = await client.get("/api/zwave/usercodes/18")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {}
async def test_save_config_no_network(hass, client):
"""Test saving configuration without network data."""
resp = await client.post("/api/zwave/saveconfig")
assert resp.status == HTTPStatus.NOT_FOUND
result = await resp.json()
assert result == {"message": "No Z-Wave network data found"}
async def test_save_config(hass, client):
"""Test saving configuration."""
network = hass.data[DATA_NETWORK] = MagicMock()
resp = await client.post("/api/zwave/saveconfig")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert network.write_config.called
assert result == {"message": "Z-Wave configuration saved to file"}
async def test_get_protection_values(hass, client):
"""Test getting protection values on node."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_PROTECTION])
value = MockValue(
value_id=123456,
index=0,
instance=1,
command_class=const.COMMAND_CLASS_PROTECTION,
)
value.label = "Protection Test"
value.data_items = [
"Unprotected",
"Protection by Sequence",
"No Operation Possible",
]
value.data = "Unprotected"
network.nodes = {18: node}
node.value = value
node.get_protection_item.return_value = "Unprotected"
node.get_protection_items.return_value = value.data_items
node.get_protections.return_value = {value.value_id: "Object"}
resp = await client.get("/api/zwave/protection/18")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert node.get_protections.called
assert node.get_protection_item.called
assert node.get_protection_items.called
assert result == {
"value_id": "123456",
"selected": "Unprotected",
"options": ["Unprotected", "Protection by Sequence", "No Operation Possible"],
}
async def test_get_protection_values_nonexisting_node(hass, client):
"""Test getting protection values on node with wrong nodeid."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_PROTECTION])
value = MockValue(
value_id=123456,
index=0,
instance=1,
command_class=const.COMMAND_CLASS_PROTECTION,
)
value.label = "Protection Test"
value.data_items = [
"Unprotected",
"Protection by Sequence",
"No Operation Possible",
]
value.data = "Unprotected"
network.nodes = {17: node}
node.value = value
resp = await client.get("/api/zwave/protection/18")
assert resp.status == HTTPStatus.NOT_FOUND
result = await resp.json()
assert not node.get_protections.called
assert not node.get_protection_item.called
assert not node.get_protection_items.called
assert result == {"message": "Node not found"}
async def test_get_protection_values_without_protectionclass(hass, client):
"""Test getting protection values on node without protectionclass."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=18)
value = MockValue(value_id=123456, index=0, instance=1)
network.nodes = {18: node}
node.value = value
resp = await client.get("/api/zwave/protection/18")
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert not node.get_protections.called
assert not node.get_protection_item.called
assert not node.get_protection_items.called
assert result == {}
async def test_set_protection_value(hass, client):
"""Test setting protection value on node."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_PROTECTION])
value = MockValue(
value_id=123456,
index=0,
instance=1,
command_class=const.COMMAND_CLASS_PROTECTION,
)
value.label = "Protection Test"
value.data_items = [
"Unprotected",
"Protection by Sequence",
"No Operation Possible",
]
value.data = "Unprotected"
network.nodes = {18: node}
node.value = value
resp = await client.post(
"/api/zwave/protection/18",
data=json.dumps({"value_id": "123456", "selection": "Protection by Sequence"}),
)
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert node.set_protection.called
assert result == {"message": "Protection setting successfully set"}
async def test_set_protection_value_failed(hass, client):
"""Test setting protection value failed on node."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=18, command_classes=[const.COMMAND_CLASS_PROTECTION])
value = MockValue(
value_id=123456,
index=0,
instance=1,
command_class=const.COMMAND_CLASS_PROTECTION,
)
value.label = "Protection Test"
value.data_items = [
"Unprotected",
"Protection by Sequence",
"No Operation Possible",
]
value.data = "Unprotected"
network.nodes = {18: node}
node.value = value
node.set_protection.return_value = False
resp = await client.post(
"/api/zwave/protection/18",
data=json.dumps({"value_id": "123456", "selection": "Protecton by Sequence"}),
)
assert resp.status == HTTPStatus.ACCEPTED
result = await resp.json()
assert node.set_protection.called
assert result == {"message": "Protection setting did not complete"}
async def test_set_protection_value_nonexisting_node(hass, client):
"""Test setting protection value on nonexisting node."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=17, command_classes=[const.COMMAND_CLASS_PROTECTION])
value = MockValue(
value_id=123456,
index=0,
instance=1,
command_class=const.COMMAND_CLASS_PROTECTION,
)
value.label = "Protection Test"
value.data_items = [
"Unprotected",
"Protection by Sequence",
"No Operation Possible",
]
value.data = "Unprotected"
network.nodes = {17: node}
node.value = value
node.set_protection.return_value = False
resp = await client.post(
"/api/zwave/protection/18",
data=json.dumps({"value_id": "123456", "selection": "Protecton by Sequence"}),
)
assert resp.status == HTTPStatus.NOT_FOUND
result = await resp.json()
assert not node.set_protection.called
assert result == {"message": "Node not found"}
async def test_set_protection_value_missing_class(hass, client):
"""Test setting protection value on node without protectionclass."""
network = hass.data[DATA_NETWORK] = MagicMock()
node = MockNode(node_id=17)
value = MockValue(value_id=123456, index=0, instance=1)
network.nodes = {17: node}
node.value = value
node.set_protection.return_value = False
resp = await client.post(
"/api/zwave/protection/17",
data=json.dumps({"value_id": "123456", "selection": "Protecton by Sequence"}),
)
assert resp.status == HTTPStatus.NOT_FOUND
result = await resp.json()
assert not node.set_protection.called
assert result == {"message": "No protection commandclass on this node"}

View File

@ -1 +0,0 @@
"""Tests for the Z-Wave component."""

View File

@ -1,80 +0,0 @@
"""Fixtures for Z-Wave tests."""
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from homeassistant.components.zwave import const
from tests.components.light.conftest import mock_light_profiles # noqa: F401
from tests.mock.zwave import MockNetwork, MockNode, MockOption, MockValue
@pytest.fixture
def mock_openzwave():
"""Mock out Open Z-Wave."""
base_mock = MagicMock()
libopenzwave = base_mock.libopenzwave
libopenzwave.__file__ = "test"
base_mock.network.ZWaveNetwork = MockNetwork
base_mock.option.ZWaveOption = MockOption
with patch.dict(
"sys.modules",
{
"libopenzwave": libopenzwave,
"openzwave.option": base_mock.option,
"openzwave.network": base_mock.network,
"openzwave.group": base_mock.group,
},
):
yield base_mock
@pytest.fixture
def mock_discovery():
"""Mock discovery."""
discovery = MagicMock()
discovery.async_load_platform = AsyncMock(return_value=None)
yield discovery
@pytest.fixture
def mock_import_module():
"""Mock import module."""
platform = MagicMock()
mock_device = MagicMock()
mock_device.name = "test_device"
platform.get_device.return_value = mock_device
import_module = MagicMock()
import_module.return_value = platform
yield import_module
@pytest.fixture
def mock_values():
"""Mock values."""
node = MockNode()
mock_schema = {
const.DISC_COMPONENT: "mock_component",
const.DISC_VALUES: {
const.DISC_PRIMARY: {const.DISC_COMMAND_CLASS: ["mock_primary_class"]},
"secondary": {const.DISC_COMMAND_CLASS: ["mock_secondary_class"]},
"optional": {
const.DISC_COMMAND_CLASS: ["mock_optional_class"],
const.DISC_OPTIONAL: True,
},
},
}
value_class = MagicMock()
value_class.primary = MockValue(
command_class="mock_primary_class", node=node, value_id=1000
)
value_class.secondary = MockValue(command_class="mock_secondary_class", node=node)
value_class.duplicate_secondary = MockValue(
command_class="mock_secondary_class", node=node
)
value_class.optional = MockValue(command_class="mock_optional_class", node=node)
value_class.no_match_value = MockValue(command_class="mock_bad_class", node=node)
yield (node, value_class, mock_schema)

View File

@ -1,103 +0,0 @@
"""Test Z-Wave binary sensors."""
import datetime
from unittest.mock import patch
import pytest
from homeassistant.components.zwave import binary_sensor, const
from tests.mock.zwave import MockEntityValues, MockNode, MockValue, value_changed
# Integration is disabled
pytest.skip("Integration has been disabled in the manifest", allow_module_level=True)
def test_get_device_detects_none(mock_openzwave):
"""Test device is not returned."""
node = MockNode()
value = MockValue(data=False, node=node)
values = MockEntityValues(primary=value)
device = binary_sensor.get_device(node=node, values=values, node_config={})
assert device is None
def test_get_device_detects_trigger_sensor(mock_openzwave):
"""Test device is a trigger sensor."""
node = MockNode(manufacturer_id="013c", product_type="0002", product_id="0002")
value = MockValue(data=False, node=node)
values = MockEntityValues(primary=value)
device = binary_sensor.get_device(node=node, values=values, node_config={})
assert isinstance(device, binary_sensor.ZWaveTriggerSensor)
assert device.device_class == "motion"
def test_get_device_detects_workaround_sensor(mock_openzwave):
"""Test that workaround returns a binary sensor."""
node = MockNode(manufacturer_id="010f", product_type="0b00")
value = MockValue(
data=False, node=node, command_class=const.COMMAND_CLASS_SENSOR_ALARM
)
values = MockEntityValues(primary=value)
device = binary_sensor.get_device(node=node, values=values, node_config={})
assert isinstance(device, binary_sensor.ZWaveBinarySensor)
def test_get_device_detects_sensor(mock_openzwave):
"""Test that device returns a binary sensor."""
node = MockNode()
value = MockValue(
data=False, node=node, command_class=const.COMMAND_CLASS_SENSOR_BINARY
)
values = MockEntityValues(primary=value)
device = binary_sensor.get_device(node=node, values=values, node_config={})
assert isinstance(device, binary_sensor.ZWaveBinarySensor)
def test_binary_sensor_value_changed(mock_openzwave):
"""Test value changed for binary sensor."""
node = MockNode()
value = MockValue(
data=False, node=node, command_class=const.COMMAND_CLASS_SENSOR_BINARY
)
values = MockEntityValues(primary=value)
device = binary_sensor.get_device(node=node, values=values, node_config={})
assert not device.is_on
value.data = True
value_changed(value)
assert device.is_on
async def test_trigger_sensor_value_changed(hass, mock_openzwave):
"""Test value changed for trigger sensor."""
node = MockNode(manufacturer_id="013c", product_type="0002", product_id="0002")
value = MockValue(data=False, node=node)
value_off_delay = MockValue(data=15, node=node)
values = MockEntityValues(primary=value, off_delay=value_off_delay)
device = binary_sensor.get_device(node=node, values=values, node_config={})
assert not device.is_on
value.data = True
await hass.async_add_executor_job(value_changed, value)
assert device.invalidate_after is None
device.hass = hass
value.data = True
await hass.async_add_executor_job(value_changed, value)
assert device.is_on
test_time = device.invalidate_after - datetime.timedelta(seconds=1)
with patch("homeassistant.util.dt.utcnow", return_value=test_time):
assert device.is_on
test_time = device.invalidate_after
with patch("homeassistant.util.dt.utcnow", return_value=test_time):
assert not device.is_on

View File

@ -1,893 +0,0 @@
"""Test Z-Wave climate devices."""
import pytest
from homeassistant.components.climate.const import (
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
CURRENT_HVAC_COOL,
CURRENT_HVAC_HEAT,
HVAC_MODE_COOL,
HVAC_MODE_HEAT,
HVAC_MODE_HEAT_COOL,
HVAC_MODE_OFF,
HVAC_MODES,
PRESET_AWAY,
PRESET_BOOST,
PRESET_ECO,
PRESET_NONE,
SUPPORT_AUX_HEAT,
SUPPORT_FAN_MODE,
SUPPORT_PRESET_MODE,
SUPPORT_SWING_MODE,
SUPPORT_TARGET_TEMPERATURE,
SUPPORT_TARGET_TEMPERATURE_RANGE,
)
from homeassistant.components.zwave import climate, const
from homeassistant.components.zwave.climate import (
AUX_HEAT_ZWAVE_MODE,
DEFAULT_HVAC_MODES,
)
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
from tests.mock.zwave import MockEntityValues, MockNode, MockValue, value_changed
# Integration is disabled
pytest.skip("Integration has been disabled in the manifest", allow_module_level=True)
@pytest.fixture
def device(hass, mock_openzwave):
"""Fixture to provide a precreated climate device."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data=HVAC_MODE_HEAT,
data_items=[
HVAC_MODE_OFF,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
HVAC_MODE_HEAT_COOL,
],
node=node,
),
setpoint_heating=MockValue(data=1, node=node),
setpoint_cooling=MockValue(data=10, node=node),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data=CURRENT_HVAC_HEAT, node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_zxt_120(hass, mock_openzwave):
"""Fixture to provide a precreated climate device."""
node = MockNode(manufacturer_id="5254", product_id="8377")
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data=HVAC_MODE_HEAT,
data_items=[
HVAC_MODE_OFF,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
HVAC_MODE_HEAT_COOL,
],
node=node,
),
setpoint_heating=MockValue(data=1, node=node),
setpoint_cooling=MockValue(data=10, node=node),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data=CURRENT_HVAC_HEAT, node=node),
fan_action=MockValue(data=7, node=node),
zxt_120_swing_mode=MockValue(data="test3", data_items=[6, 7, 8], node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_mapping(hass, mock_openzwave):
"""Fixture to provide a precreated climate device. Test state mapping."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data="Heat",
data_items=["Off", "Cool", "Heat", "Full Power", "Auto"],
node=node,
),
setpoint_heating=MockValue(data=1, node=node),
setpoint_cooling=MockValue(data=10, node=node),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data="heating", node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_unknown(hass, mock_openzwave):
"""Fixture to provide a precreated climate device. Test state unknown."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data="Heat",
data_items=["Off", "Cool", "Heat", "heat_cool", "Abcdefg"],
node=node,
),
setpoint_heating=MockValue(data=1, node=node),
setpoint_cooling=MockValue(data=10, node=node),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data="test4", node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_heat_cool(hass, mock_openzwave):
"""Fixture to provide a precreated climate device. Test state heat only."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data=HVAC_MODE_HEAT,
data_items=[
HVAC_MODE_OFF,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
"Heat Eco",
"Cool Eco",
],
node=node,
),
setpoint_heating=MockValue(data=1, node=node),
setpoint_cooling=MockValue(data=10, node=node),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data="test4", node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_heat_cool_range(hass, mock_openzwave):
"""Fixture to provide a precreated climate device. Target range mode."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data=HVAC_MODE_HEAT_COOL,
data_items=[
HVAC_MODE_OFF,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
HVAC_MODE_HEAT_COOL,
],
node=node,
),
setpoint_heating=MockValue(data=1, node=node),
setpoint_cooling=MockValue(data=10, node=node),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data="test4", node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_heat_cool_away(hass, mock_openzwave):
"""Fixture to provide a precreated climate device. Target range mode."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data=HVAC_MODE_HEAT_COOL,
data_items=[
HVAC_MODE_OFF,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
HVAC_MODE_HEAT_COOL,
PRESET_AWAY,
],
node=node,
),
setpoint_heating=MockValue(data=2, node=node),
setpoint_cooling=MockValue(data=9, node=node),
setpoint_away_heating=MockValue(data=1, node=node),
setpoint_away_cooling=MockValue(data=10, node=node),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data="test4", node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_heat_eco(hass, mock_openzwave):
"""Fixture to provide a precreated climate device. heat/heat eco."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data=HVAC_MODE_HEAT,
data_items=[HVAC_MODE_OFF, HVAC_MODE_HEAT, "heat econ"],
node=node,
),
setpoint_heating=MockValue(data=2, node=node),
setpoint_eco_heating=MockValue(data=1, node=node),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data="test4", node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_aux_heat(hass, mock_openzwave):
"""Fixture to provide a precreated climate device. aux heat."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data=HVAC_MODE_HEAT,
data_items=[HVAC_MODE_OFF, HVAC_MODE_HEAT, "Aux Heat"],
node=node,
),
setpoint_heating=MockValue(data=2, node=node),
setpoint_eco_heating=MockValue(data=1, node=node),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data="test4", node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_single_setpoint(hass, mock_openzwave):
"""Fixture to provide a precreated climate device.
SETPOINT_THERMOSTAT device class.
"""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_SETPOINT, data=1, node=node
),
mode=None,
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data=CURRENT_HVAC_HEAT, node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
@pytest.fixture
def device_single_setpoint_with_mode(hass, mock_openzwave):
"""Fixture to provide a precreated climate device.
SETPOINT_THERMOSTAT device class with COMMAND_CLASS_THERMOSTAT_MODE command class
"""
node = MockNode()
values = MockEntityValues(
primary=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_SETPOINT, data=1, node=node
),
mode=MockValue(
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
data=HVAC_MODE_HEAT,
data_items=[HVAC_MODE_OFF, HVAC_MODE_HEAT],
node=node,
),
temperature=MockValue(data=5, node=node, units=None),
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
operating_state=MockValue(data=CURRENT_HVAC_HEAT, node=node),
fan_action=MockValue(data=7, node=node),
)
device = climate.get_device(hass, node=node, values=values, node_config={})
yield device
def test_get_device_detects_none(hass, mock_openzwave):
"""Test get_device returns None."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockEntityValues(primary=value)
device = climate.get_device(hass, node=node, values=values, node_config={})
assert device is None
def test_get_device_detects_multiple_setpoint_device(device):
"""Test get_device returns a Z-Wave multiple setpoint device."""
assert isinstance(device, climate.ZWaveClimateMultipleSetpoint)
def test_get_device_detects_single_setpoint_device(device_single_setpoint):
"""Test get_device returns a Z-Wave single setpoint device."""
assert isinstance(device_single_setpoint, climate.ZWaveClimateSingleSetpoint)
def test_default_hvac_modes():
"""Test whether all hvac modes are included in default_hvac_modes."""
for hvac_mode in HVAC_MODES:
assert hvac_mode in DEFAULT_HVAC_MODES
def test_supported_features(device):
"""Test supported features flags."""
assert (
device.supported_features
== SUPPORT_FAN_MODE
+ SUPPORT_TARGET_TEMPERATURE
+ SUPPORT_TARGET_TEMPERATURE_RANGE
)
def test_supported_features_temp_range(device_heat_cool_range):
"""Test supported features flags with target temp range."""
device = device_heat_cool_range
assert (
device.supported_features
== SUPPORT_FAN_MODE
+ SUPPORT_TARGET_TEMPERATURE
+ SUPPORT_TARGET_TEMPERATURE_RANGE
)
def test_supported_features_preset_mode(device_mapping):
"""Test supported features flags with swing mode."""
device = device_mapping
assert (
device.supported_features
== SUPPORT_FAN_MODE
+ SUPPORT_TARGET_TEMPERATURE
+ SUPPORT_TARGET_TEMPERATURE_RANGE
+ SUPPORT_PRESET_MODE
)
def test_supported_features_preset_mode_away(device_heat_cool_away):
"""Test supported features flags with swing mode."""
device = device_heat_cool_away
assert (
device.supported_features
== SUPPORT_FAN_MODE
+ SUPPORT_TARGET_TEMPERATURE
+ SUPPORT_TARGET_TEMPERATURE_RANGE
+ SUPPORT_PRESET_MODE
)
def test_supported_features_swing_mode(device_zxt_120):
"""Test supported features flags with swing mode."""
device = device_zxt_120
assert (
device.supported_features
== SUPPORT_FAN_MODE
+ SUPPORT_TARGET_TEMPERATURE
+ SUPPORT_TARGET_TEMPERATURE_RANGE
+ SUPPORT_SWING_MODE
)
def test_supported_features_aux_heat(device_aux_heat):
"""Test supported features flags with aux heat."""
device = device_aux_heat
assert (
device.supported_features
== SUPPORT_FAN_MODE + SUPPORT_TARGET_TEMPERATURE + SUPPORT_AUX_HEAT
)
def test_supported_features_single_setpoint(device_single_setpoint):
"""Test supported features flags for SETPOINT_THERMOSTAT."""
device = device_single_setpoint
assert device.supported_features == SUPPORT_FAN_MODE + SUPPORT_TARGET_TEMPERATURE
def test_supported_features_single_setpoint_with_mode(device_single_setpoint_with_mode):
"""Test supported features flags for SETPOINT_THERMOSTAT."""
device = device_single_setpoint_with_mode
assert device.supported_features == SUPPORT_FAN_MODE + SUPPORT_TARGET_TEMPERATURE
def test_zxt_120_swing_mode(device_zxt_120):
"""Test operation of the zxt 120 swing mode."""
device = device_zxt_120
assert device.swing_modes == [6, 7, 8]
assert device._zxt_120 == 1
# Test set mode
assert device.values.zxt_120_swing_mode.data == "test3"
device.set_swing_mode("test_swing_set")
assert device.values.zxt_120_swing_mode.data == "test_swing_set"
# Test mode changed
value_changed(device.values.zxt_120_swing_mode)
assert device.swing_mode == "test_swing_set"
device.values.zxt_120_swing_mode.data = "test_swing_updated"
value_changed(device.values.zxt_120_swing_mode)
assert device.swing_mode == "test_swing_updated"
def test_temperature_unit(device):
"""Test temperature unit."""
assert device.temperature_unit == TEMP_CELSIUS
device.values.temperature.units = "F"
value_changed(device.values.temperature)
assert device.temperature_unit == TEMP_FAHRENHEIT
device.values.temperature.units = "C"
value_changed(device.values.temperature)
assert device.temperature_unit == TEMP_CELSIUS
def test_data_lists(device):
"""Test data lists from zwave value items."""
assert device.fan_modes == [3, 4, 5]
assert device.hvac_modes == [
HVAC_MODE_OFF,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
HVAC_MODE_HEAT_COOL,
]
assert device.preset_modes == []
device.values.primary = None
assert device.preset_modes == []
def test_data_lists_single_setpoint(device_single_setpoint):
"""Test data lists from zwave value items."""
device = device_single_setpoint
assert device.fan_modes == [3, 4, 5]
assert device.hvac_modes == []
assert device.preset_modes == []
def test_data_lists_single_setpoint_with_mode(device_single_setpoint_with_mode):
"""Test data lists from zwave value items."""
device = device_single_setpoint_with_mode
assert device.fan_modes == [3, 4, 5]
assert device.hvac_modes == [HVAC_MODE_OFF, HVAC_MODE_HEAT]
assert device.preset_modes == []
def test_data_lists_mapping(device_mapping):
"""Test data lists from zwave value items."""
device = device_mapping
assert device.hvac_modes == ["off", "cool", "heat", "heat_cool"]
assert device.preset_modes == ["boost", "none"]
device.values.primary = None
assert device.preset_modes == []
def test_target_value_set(device):
"""Test values changed for climate device."""
assert device.values.setpoint_heating.data == 1
assert device.values.setpoint_cooling.data == 10
device.set_temperature()
assert device.values.setpoint_heating.data == 1
assert device.values.setpoint_cooling.data == 10
device.set_temperature(**{ATTR_TEMPERATURE: 2})
assert device.values.setpoint_heating.data == 2
assert device.values.setpoint_cooling.data == 10
device.set_hvac_mode(HVAC_MODE_COOL)
value_changed(device.values.primary)
assert device.values.setpoint_heating.data == 2
assert device.values.setpoint_cooling.data == 10
device.set_temperature(**{ATTR_TEMPERATURE: 9})
assert device.values.setpoint_heating.data == 2
assert device.values.setpoint_cooling.data == 9
def test_target_value_set_range(device_heat_cool_range):
"""Test values changed for climate device."""
device = device_heat_cool_range
assert device.values.setpoint_heating.data == 1
assert device.values.setpoint_cooling.data == 10
device.set_temperature()
assert device.values.setpoint_heating.data == 1
assert device.values.setpoint_cooling.data == 10
device.set_temperature(**{ATTR_TARGET_TEMP_LOW: 2})
assert device.values.setpoint_heating.data == 2
assert device.values.setpoint_cooling.data == 10
device.set_temperature(**{ATTR_TARGET_TEMP_HIGH: 9})
assert device.values.setpoint_heating.data == 2
assert device.values.setpoint_cooling.data == 9
device.set_temperature(**{ATTR_TARGET_TEMP_LOW: 3, ATTR_TARGET_TEMP_HIGH: 8})
assert device.values.setpoint_heating.data == 3
assert device.values.setpoint_cooling.data == 8
def test_target_value_set_range_away(device_heat_cool_away):
"""Test values changed for climate device."""
device = device_heat_cool_away
assert device.values.setpoint_heating.data == 2
assert device.values.setpoint_cooling.data == 9
assert device.values.setpoint_away_heating.data == 1
assert device.values.setpoint_away_cooling.data == 10
device.set_preset_mode(PRESET_AWAY)
device.set_temperature(**{ATTR_TARGET_TEMP_LOW: 0, ATTR_TARGET_TEMP_HIGH: 11})
assert device.values.setpoint_heating.data == 2
assert device.values.setpoint_cooling.data == 9
assert device.values.setpoint_away_heating.data == 0
assert device.values.setpoint_away_cooling.data == 11
def test_target_value_set_eco(device_heat_eco):
"""Test values changed for climate device."""
device = device_heat_eco
assert device.values.setpoint_heating.data == 2
assert device.values.setpoint_eco_heating.data == 1
device.set_preset_mode("heat econ")
device.set_temperature(**{ATTR_TEMPERATURE: 0})
assert device.values.setpoint_heating.data == 2
assert device.values.setpoint_eco_heating.data == 0
def test_target_value_set_single_setpoint(device_single_setpoint):
"""Test values changed for climate device."""
device = device_single_setpoint
assert device.values.primary.data == 1
device.set_temperature(**{ATTR_TEMPERATURE: 2})
assert device.values.primary.data == 2
def test_operation_value_set(device):
"""Test values changed for climate device."""
assert device.values.primary.data == HVAC_MODE_HEAT
device.set_hvac_mode(HVAC_MODE_COOL)
assert device.values.primary.data == HVAC_MODE_COOL
device.set_preset_mode(PRESET_ECO)
assert device.values.primary.data == PRESET_ECO
device.set_preset_mode(PRESET_NONE)
assert device.values.primary.data == HVAC_MODE_HEAT_COOL
device.values.primary = None
device.set_hvac_mode("test_set_failes")
assert device.values.primary is None
device.set_preset_mode("test_set_failes")
assert device.values.primary is None
def test_operation_value_set_mapping(device_mapping):
"""Test values changed for climate device. Mapping."""
device = device_mapping
assert device.values.primary.data == "Heat"
device.set_hvac_mode(HVAC_MODE_COOL)
assert device.values.primary.data == "Cool"
device.set_hvac_mode(HVAC_MODE_OFF)
assert device.values.primary.data == "Off"
device.set_preset_mode(PRESET_BOOST)
assert device.values.primary.data == "Full Power"
device.set_preset_mode(PRESET_ECO)
assert device.values.primary.data == "eco"
def test_operation_value_set_unknown(device_unknown):
"""Test values changed for climate device. Unknown."""
device = device_unknown
assert device.values.primary.data == "Heat"
device.set_preset_mode("Abcdefg")
assert device.values.primary.data == "Abcdefg"
device.set_preset_mode(PRESET_NONE)
assert device.values.primary.data == HVAC_MODE_HEAT_COOL
def test_operation_value_set_heat_cool(device_heat_cool):
"""Test values changed for climate device. Heat/Cool only."""
device = device_heat_cool
assert device.values.primary.data == HVAC_MODE_HEAT
device.set_preset_mode("Heat Eco")
assert device.values.primary.data == "Heat Eco"
device.set_preset_mode(PRESET_NONE)
assert device.values.primary.data == HVAC_MODE_HEAT
device.set_preset_mode("Cool Eco")
assert device.values.primary.data == "Cool Eco"
device.set_preset_mode(PRESET_NONE)
assert device.values.primary.data == HVAC_MODE_COOL
def test_fan_mode_value_set(device):
"""Test values changed for climate device."""
assert device.values.fan_mode.data == "test2"
device.set_fan_mode("test_fan_set")
assert device.values.fan_mode.data == "test_fan_set"
device.values.fan_mode = None
device.set_fan_mode("test_fan_set_failes")
assert device.values.fan_mode is None
def test_target_value_changed(device):
"""Test values changed for climate device."""
assert device.target_temperature == 1
device.values.setpoint_heating.data = 2
value_changed(device.values.setpoint_heating)
assert device.target_temperature == 2
device.values.primary.data = HVAC_MODE_COOL
value_changed(device.values.primary)
assert device.target_temperature == 10
device.values.setpoint_cooling.data = 9
value_changed(device.values.setpoint_cooling)
assert device.target_temperature == 9
def test_target_range_changed(device_heat_cool_range):
"""Test values changed for climate device."""
device = device_heat_cool_range
assert device.target_temperature_low == 1
assert device.target_temperature_high == 10
device.values.setpoint_heating.data = 2
value_changed(device.values.setpoint_heating)
assert device.target_temperature_low == 2
assert device.target_temperature_high == 10
device.values.setpoint_cooling.data = 9
value_changed(device.values.setpoint_cooling)
assert device.target_temperature_low == 2
assert device.target_temperature_high == 9
def test_target_changed_preset_range(device_heat_cool_away):
"""Test values changed for climate device."""
device = device_heat_cool_away
assert device.target_temperature_low == 2
assert device.target_temperature_high == 9
device.values.primary.data = PRESET_AWAY
value_changed(device.values.primary)
assert device.target_temperature_low == 1
assert device.target_temperature_high == 10
device.values.setpoint_away_heating.data = 0
value_changed(device.values.setpoint_away_heating)
device.values.setpoint_away_cooling.data = 11
value_changed(device.values.setpoint_away_cooling)
assert device.target_temperature_low == 0
assert device.target_temperature_high == 11
device.values.primary.data = HVAC_MODE_HEAT_COOL
value_changed(device.values.primary)
assert device.target_temperature_low == 2
assert device.target_temperature_high == 9
def test_target_changed_eco(device_heat_eco):
"""Test values changed for climate device."""
device = device_heat_eco
assert device.target_temperature == 2
device.values.primary.data = "heat econ"
value_changed(device.values.primary)
assert device.target_temperature == 1
device.values.setpoint_eco_heating.data = 0
value_changed(device.values.setpoint_eco_heating)
assert device.target_temperature == 0
device.values.primary.data = HVAC_MODE_HEAT
value_changed(device.values.primary)
assert device.target_temperature == 2
def test_target_changed_with_mode(device):
"""Test values changed for climate device."""
assert device.hvac_mode == HVAC_MODE_HEAT
assert device.target_temperature == 1
device.values.primary.data = HVAC_MODE_COOL
value_changed(device.values.primary)
assert device.target_temperature == 10
device.values.primary.data = HVAC_MODE_HEAT_COOL
value_changed(device.values.primary)
assert device.target_temperature_low == 1
assert device.target_temperature_high == 10
def test_target_value_changed_single_setpoint(device_single_setpoint):
"""Test values changed for climate device."""
device = device_single_setpoint
assert device.target_temperature == 1
device.values.primary.data = 2
value_changed(device.values.primary)
assert device.target_temperature == 2
def test_temperature_value_changed(device):
"""Test values changed for climate device."""
assert device.current_temperature == 5
device.values.temperature.data = 3
value_changed(device.values.temperature)
assert device.current_temperature == 3
def test_operation_value_changed(device):
"""Test values changed for climate device."""
assert device.hvac_mode == HVAC_MODE_HEAT
assert device.preset_mode == PRESET_NONE
device.values.primary.data = HVAC_MODE_COOL
value_changed(device.values.primary)
assert device.hvac_mode == HVAC_MODE_COOL
assert device.preset_mode == PRESET_NONE
device.values.primary.data = HVAC_MODE_OFF
value_changed(device.values.primary)
assert device.hvac_mode == HVAC_MODE_OFF
assert device.preset_mode == PRESET_NONE
device.values.primary = None
assert device.hvac_mode == HVAC_MODE_HEAT_COOL
assert device.preset_mode == PRESET_NONE
def test_operation_value_changed_preset(device_mapping):
"""Test preset changed for climate device."""
device = device_mapping
assert device.hvac_mode == HVAC_MODE_HEAT
assert device.preset_mode == PRESET_NONE
device.values.primary.data = PRESET_ECO
value_changed(device.values.primary)
assert device.hvac_mode == HVAC_MODE_HEAT_COOL
assert device.preset_mode == PRESET_ECO
def test_operation_value_changed_mapping(device_mapping):
"""Test values changed for climate device. Mapping."""
device = device_mapping
assert device.hvac_mode == HVAC_MODE_HEAT
assert device.preset_mode == PRESET_NONE
device.values.primary.data = "Off"
value_changed(device.values.primary)
assert device.hvac_mode == HVAC_MODE_OFF
assert device.preset_mode == PRESET_NONE
device.values.primary.data = "Cool"
value_changed(device.values.primary)
assert device.hvac_mode == HVAC_MODE_COOL
assert device.preset_mode == PRESET_NONE
def test_operation_value_changed_mapping_preset(device_mapping):
"""Test values changed for climate device. Mapping with presets."""
device = device_mapping
assert device.hvac_mode == HVAC_MODE_HEAT
assert device.preset_mode == PRESET_NONE
device.values.primary.data = "Full Power"
value_changed(device.values.primary)
assert device.hvac_mode == HVAC_MODE_HEAT_COOL
assert device.preset_mode == PRESET_BOOST
device.values.primary = None
assert device.hvac_mode == HVAC_MODE_HEAT_COOL
assert device.preset_mode == PRESET_NONE
def test_operation_value_changed_unknown(device_unknown):
"""Test preset changed for climate device. Unknown."""
device = device_unknown
assert device.hvac_mode == HVAC_MODE_HEAT
assert device.preset_mode == PRESET_NONE
device.values.primary.data = "Abcdefg"
value_changed(device.values.primary)
assert device.hvac_mode == HVAC_MODE_HEAT_COOL
assert device.preset_mode == "Abcdefg"
def test_operation_value_changed_heat_cool(device_heat_cool):
"""Test preset changed for climate device. Heat/Cool only."""
device = device_heat_cool
assert device.hvac_mode == HVAC_MODE_HEAT
assert device.preset_mode == PRESET_NONE
device.values.primary.data = "Cool Eco"
value_changed(device.values.primary)
assert device.hvac_mode == HVAC_MODE_COOL
assert device.preset_mode == "Cool Eco"
device.values.primary.data = "Heat Eco"
value_changed(device.values.primary)
assert device.hvac_mode == HVAC_MODE_HEAT
assert device.preset_mode == "Heat Eco"
def test_fan_mode_value_changed(device):
"""Test values changed for climate device."""
assert device.fan_mode == "test2"
device.values.fan_mode.data = "test_updated_fan"
value_changed(device.values.fan_mode)
assert device.fan_mode == "test_updated_fan"
def test_hvac_action_value_changed(device):
"""Test values changed for climate device."""
assert device.hvac_action == CURRENT_HVAC_HEAT
device.values.operating_state.data = CURRENT_HVAC_COOL
value_changed(device.values.operating_state)
assert device.hvac_action == CURRENT_HVAC_COOL
def test_hvac_action_value_changed_mapping(device_mapping):
"""Test values changed for climate device."""
device = device_mapping
assert device.hvac_action == CURRENT_HVAC_HEAT
device.values.operating_state.data = "cooling"
value_changed(device.values.operating_state)
assert device.hvac_action == CURRENT_HVAC_COOL
def test_hvac_action_value_changed_unknown(device_unknown):
"""Test values changed for climate device."""
device = device_unknown
assert device.hvac_action == "test4"
device.values.operating_state.data = "another_hvac_action"
value_changed(device.values.operating_state)
assert device.hvac_action == "another_hvac_action"
def test_fan_action_value_changed(device):
"""Test values changed for climate device."""
assert device.extra_state_attributes[climate.ATTR_FAN_ACTION] == 7
device.values.fan_action.data = 9
value_changed(device.values.fan_action)
assert device.extra_state_attributes[climate.ATTR_FAN_ACTION] == 9
def test_aux_heat_unsupported_set(device):
"""Test aux heat for climate device."""
assert device.values.primary.data == HVAC_MODE_HEAT
device.turn_aux_heat_on()
assert device.values.primary.data == HVAC_MODE_HEAT
device.turn_aux_heat_off()
assert device.values.primary.data == HVAC_MODE_HEAT
def test_aux_heat_unsupported_value_changed(device):
"""Test aux heat for climate device."""
assert device.is_aux_heat is None
device.values.primary.data = HVAC_MODE_HEAT
value_changed(device.values.primary)
assert device.is_aux_heat is None
def test_aux_heat_set(device_aux_heat):
"""Test aux heat for climate device."""
device = device_aux_heat
assert device.values.primary.data == HVAC_MODE_HEAT
device.turn_aux_heat_on()
assert device.values.primary.data == AUX_HEAT_ZWAVE_MODE
device.turn_aux_heat_off()
assert device.values.primary.data == HVAC_MODE_HEAT
def test_aux_heat_value_changed(device_aux_heat):
"""Test aux heat for climate device."""
device = device_aux_heat
assert device.is_aux_heat is False
device.values.primary.data = AUX_HEAT_ZWAVE_MODE
value_changed(device.values.primary)
assert device.is_aux_heat is True
device.values.primary.data = HVAC_MODE_HEAT
value_changed(device.values.primary)
assert device.is_aux_heat is False

View File

@ -1,292 +0,0 @@
"""Test Z-Wave cover devices."""
from unittest.mock import MagicMock
import pytest
from homeassistant.components.cover import SUPPORT_CLOSE, SUPPORT_OPEN
from homeassistant.components.zwave import (
CONF_INVERT_OPENCLOSE_BUTTONS,
CONF_INVERT_PERCENT,
const,
cover,
)
from tests.mock.zwave import MockEntityValues, MockNode, MockValue, value_changed
# Integration is disabled
pytest.skip("Integration has been disabled in the manifest", allow_module_level=True)
def test_get_device_detects_none(hass, mock_openzwave):
"""Test device returns none."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockEntityValues(primary=value, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert device is None
def test_get_device_detects_rollershutter(hass, mock_openzwave):
"""Test device returns rollershutter."""
hass.data[const.DATA_NETWORK] = MagicMock()
node = MockNode()
value = MockValue(
data=0, node=node, command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL
)
values = MockEntityValues(primary=value, open=None, close=None, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert isinstance(device, cover.ZwaveRollershutter)
def test_get_device_detects_garagedoor_switch(hass, mock_openzwave):
"""Test device returns garage door."""
node = MockNode()
value = MockValue(
data=False, node=node, command_class=const.COMMAND_CLASS_SWITCH_BINARY
)
values = MockEntityValues(primary=value, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert isinstance(device, cover.ZwaveGarageDoorSwitch)
assert device.device_class == "garage"
assert device.supported_features == SUPPORT_OPEN | SUPPORT_CLOSE
def test_get_device_detects_garagedoor_barrier(hass, mock_openzwave):
"""Test device returns garage door."""
node = MockNode()
value = MockValue(
data="Closed", node=node, command_class=const.COMMAND_CLASS_BARRIER_OPERATOR
)
values = MockEntityValues(primary=value, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert isinstance(device, cover.ZwaveGarageDoorBarrier)
assert device.device_class == "garage"
assert device.supported_features == SUPPORT_OPEN | SUPPORT_CLOSE
def test_roller_no_position_workaround(hass, mock_openzwave):
"""Test position changed."""
hass.data[const.DATA_NETWORK] = MagicMock()
node = MockNode(manufacturer_id="0047", product_type="5a52")
value = MockValue(
data=45, node=node, command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL
)
values = MockEntityValues(primary=value, open=None, close=None, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert device.current_cover_position is None
def test_roller_value_changed(hass, mock_openzwave):
"""Test position changed."""
hass.data[const.DATA_NETWORK] = MagicMock()
node = MockNode()
value = MockValue(
data=None, node=node, command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL
)
values = MockEntityValues(primary=value, open=None, close=None, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert device.current_cover_position is None
assert device.is_closed is None
value.data = 2
value_changed(value)
assert device.current_cover_position == 0
assert device.is_closed
value.data = 35
value_changed(value)
assert device.current_cover_position == 35
assert not device.is_closed
value.data = 97
value_changed(value)
assert device.current_cover_position == 100
assert not device.is_closed
def test_roller_commands(hass, mock_openzwave):
"""Test position changed."""
mock_network = hass.data[const.DATA_NETWORK] = MagicMock()
node = MockNode()
value = MockValue(
data=50, node=node, command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL
)
open_value = MockValue(data=False, node=node)
close_value = MockValue(data=False, node=node)
values = MockEntityValues(
primary=value, open=open_value, close=close_value, node=node
)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
device.set_cover_position(position=25)
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 25
device.open_cover()
assert mock_network.manager.pressButton.called
(value_id,) = mock_network.manager.pressButton.mock_calls.pop(0)[1]
assert value_id == open_value.value_id
device.close_cover()
assert mock_network.manager.pressButton.called
(value_id,) = mock_network.manager.pressButton.mock_calls.pop(0)[1]
assert value_id == close_value.value_id
device.stop_cover()
assert mock_network.manager.releaseButton.called
(value_id,) = mock_network.manager.releaseButton.mock_calls.pop(0)[1]
assert value_id == open_value.value_id
def test_roller_invert_percent(hass, mock_openzwave):
"""Test position changed."""
mock_network = hass.data[const.DATA_NETWORK] = MagicMock()
node = MockNode()
value = MockValue(
data=50, node=node, command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL
)
open_value = MockValue(data=False, node=node)
close_value = MockValue(data=False, node=node)
values = MockEntityValues(
primary=value, open=open_value, close=close_value, node=node
)
device = cover.get_device(
hass=hass, node=node, values=values, node_config={CONF_INVERT_PERCENT: True}
)
device.set_cover_position(position=25)
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 75
device.open_cover()
assert mock_network.manager.pressButton.called
(value_id,) = mock_network.manager.pressButton.mock_calls.pop(0)[1]
assert value_id == open_value.value_id
def test_roller_reverse_open_close(hass, mock_openzwave):
"""Test position changed."""
mock_network = hass.data[const.DATA_NETWORK] = MagicMock()
node = MockNode()
value = MockValue(
data=50, node=node, command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL
)
open_value = MockValue(data=False, node=node)
close_value = MockValue(data=False, node=node)
values = MockEntityValues(
primary=value, open=open_value, close=close_value, node=node
)
device = cover.get_device(
hass=hass,
node=node,
values=values,
node_config={CONF_INVERT_OPENCLOSE_BUTTONS: True},
)
device.open_cover()
assert mock_network.manager.pressButton.called
(value_id,) = mock_network.manager.pressButton.mock_calls.pop(0)[1]
assert value_id == close_value.value_id
device.close_cover()
assert mock_network.manager.pressButton.called
(value_id,) = mock_network.manager.pressButton.mock_calls.pop(0)[1]
assert value_id == open_value.value_id
device.stop_cover()
assert mock_network.manager.releaseButton.called
(value_id,) = mock_network.manager.releaseButton.mock_calls.pop(0)[1]
assert value_id == close_value.value_id
def test_switch_garage_value_changed(hass, mock_openzwave):
"""Test position changed."""
node = MockNode()
value = MockValue(
data=False, node=node, command_class=const.COMMAND_CLASS_SWITCH_BINARY
)
values = MockEntityValues(primary=value, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert device.is_closed
value.data = True
value_changed(value)
assert not device.is_closed
def test_switch_garage_commands(hass, mock_openzwave):
"""Test position changed."""
node = MockNode()
value = MockValue(
data=False, node=node, command_class=const.COMMAND_CLASS_SWITCH_BINARY
)
values = MockEntityValues(primary=value, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert value.data is False
device.open_cover()
assert value.data is True
device.close_cover()
assert value.data is False
def test_barrier_garage_value_changed(hass, mock_openzwave):
"""Test position changed."""
node = MockNode()
value = MockValue(
data="Closed", node=node, command_class=const.COMMAND_CLASS_BARRIER_OPERATOR
)
values = MockEntityValues(primary=value, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert device.is_closed
assert not device.is_opening
assert not device.is_closing
value.data = "Opening"
value_changed(value)
assert not device.is_closed
assert device.is_opening
assert not device.is_closing
value.data = "Opened"
value_changed(value)
assert not device.is_closed
assert not device.is_opening
assert not device.is_closing
value.data = "Closing"
value_changed(value)
assert not device.is_closed
assert not device.is_opening
assert device.is_closing
def test_barrier_garage_commands(hass, mock_openzwave):
"""Test position changed."""
node = MockNode()
value = MockValue(
data="Closed", node=node, command_class=const.COMMAND_CLASS_BARRIER_OPERATOR
)
values = MockEntityValues(primary=value, node=node)
device = cover.get_device(hass=hass, node=node, values=values, node_config={})
assert value.data == "Closed"
device.open_cover()
assert value.data == "Opened"
device.close_cover()
assert value.data == "Closed"

View File

@ -1,91 +0,0 @@
"""Test Z-Wave fans."""
import pytest
from homeassistant.components.fan import SUPPORT_SET_SPEED
from homeassistant.components.zwave import fan
from tests.mock.zwave import MockEntityValues, MockNode, MockValue
# Integration is disabled
pytest.skip("Integration has been disabled in the manifest", allow_module_level=True)
def test_get_device_detects_fan(mock_openzwave):
"""Test get_device returns a zwave fan."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockEntityValues(primary=value)
device = fan.get_device(node=node, values=values, node_config={})
assert isinstance(device, fan.ZwaveFan)
assert device.supported_features == SUPPORT_SET_SPEED
def test_fan_turn_on(mock_openzwave):
"""Test turning on a zwave fan."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockEntityValues(primary=value)
device = fan.get_device(node=node, values=values, node_config={})
device.turn_on()
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 255
node.reset_mock()
device.turn_on(percentage=0)
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 0
node.reset_mock()
device.turn_on(percentage=1)
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 1
node.reset_mock()
device.turn_on(percentage=50)
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 50
node.reset_mock()
device.turn_on(percentage=100)
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 99
def test_fan_turn_off(mock_openzwave):
"""Test turning off a dimmable zwave fan."""
node = MockNode()
value = MockValue(data=46, node=node)
values = MockEntityValues(primary=value)
device = fan.get_device(node=node, values=values, node_config={})
device.turn_off()
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 0

File diff suppressed because it is too large Load Diff

View File

@ -1,481 +0,0 @@
"""Test Z-Wave lights."""
from unittest.mock import MagicMock, patch
import pytest
from homeassistant.components import zwave
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_RGB_COLOR,
ATTR_RGBW_COLOR,
ATTR_TRANSITION,
COLOR_MODE_BRIGHTNESS,
COLOR_MODE_COLOR_TEMP,
COLOR_MODE_RGB,
COLOR_MODE_RGBW,
SUPPORT_TRANSITION,
)
from homeassistant.components.zwave import const, light
from tests.mock.zwave import MockEntityValues, MockNode, MockValue, value_changed
# Integration is disabled
pytest.skip("Integration has been disabled in the manifest", allow_module_level=True)
class MockLightValues(MockEntityValues):
"""Mock Z-Wave light values."""
def __init__(self, **kwargs):
"""Initialize the mock zwave values."""
self.dimming_duration = None
self.color = None
self.color_channels = None
super().__init__(**kwargs)
def test_get_device_detects_dimmer(mock_openzwave):
"""Test get_device returns a normal dimmer."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockLightValues(primary=value)
device = light.get_device(node=node, values=values, node_config={})
assert isinstance(device, light.ZwaveDimmer)
assert device.color_mode == COLOR_MODE_BRIGHTNESS
assert device.supported_features == 0
assert device.supported_color_modes == {COLOR_MODE_BRIGHTNESS}
def test_get_device_detects_colorlight(mock_openzwave):
"""Test get_device returns a color light."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
values = MockLightValues(primary=value)
device = light.get_device(node=node, values=values, node_config={})
assert isinstance(device, light.ZwaveColorLight)
assert device.color_mode == COLOR_MODE_RGB
assert device.supported_features == 0
assert device.supported_color_modes == {COLOR_MODE_RGB}
def test_get_device_detects_zw098(mock_openzwave):
"""Test get_device returns a zw098 color light."""
node = MockNode(
manufacturer_id="0086",
product_id="0062",
command_classes=[const.COMMAND_CLASS_SWITCH_COLOR],
)
value = MockValue(data=0, node=node)
values = MockLightValues(primary=value)
device = light.get_device(node=node, values=values, node_config={})
assert isinstance(device, light.ZwaveColorLight)
assert device.color_mode == COLOR_MODE_RGB
assert device.supported_features == 0
assert device.supported_color_modes == {COLOR_MODE_COLOR_TEMP, COLOR_MODE_RGB}
def test_get_device_detects_rgbw_light(mock_openzwave):
"""Test get_device returns a color light."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
color_channels = MockValue(data=0x1D, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
device.value_added()
assert isinstance(device, light.ZwaveColorLight)
assert device.color_mode == COLOR_MODE_RGBW
assert device.supported_features == 0
assert device.supported_color_modes == {COLOR_MODE_RGBW}
def test_dimmer_turn_on(mock_openzwave):
"""Test turning on a dimmable Z-Wave light."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockLightValues(primary=value)
device = light.get_device(node=node, values=values, node_config={})
device.turn_on()
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 255
node.reset_mock()
device.turn_on(**{ATTR_BRIGHTNESS: 224})
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 87 # round(224 / 255 * 99)
node.reset_mock()
device.turn_on(**{ATTR_BRIGHTNESS: 120})
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 47 # round(120 / 255 * 99)
with patch.object(light, "_LOGGER", MagicMock()) as mock_logger:
device.turn_on(**{ATTR_TRANSITION: 35})
assert mock_logger.debug.called
assert node.set_dimmer.called
msg, entity_id = mock_logger.debug.mock_calls[0][1]
assert entity_id == device.entity_id
def test_dimmer_min_brightness(mock_openzwave):
"""Test turning on a dimmable Z-Wave light to its minimum brightness."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockLightValues(primary=value)
device = light.get_device(node=node, values=values, node_config={})
assert not device.is_on
device.turn_on(**{ATTR_BRIGHTNESS: 1})
assert device.is_on
assert device.brightness == 1
device.turn_on(**{ATTR_BRIGHTNESS: 0})
assert device.is_on
assert device.brightness == 0
def test_dimmer_transitions(mock_openzwave):
"""Test dimming transition on a dimmable Z-Wave light."""
node = MockNode()
value = MockValue(data=0, node=node)
duration = MockValue(data=0, node=node)
values = MockLightValues(primary=value, dimming_duration=duration)
device = light.get_device(node=node, values=values, node_config={})
assert device.color_mode == COLOR_MODE_BRIGHTNESS
assert device.supported_features == SUPPORT_TRANSITION
assert device.supported_color_modes == {COLOR_MODE_BRIGHTNESS}
# Test turn_on
# Factory Default
device.turn_on()
assert duration.data == 0xFF
# Seconds transition
device.turn_on(**{ATTR_TRANSITION: 45})
assert duration.data == 45
# Minutes transition
device.turn_on(**{ATTR_TRANSITION: 245})
assert duration.data == 0x83
# Clipped transition
device.turn_on(**{ATTR_TRANSITION: 10000})
assert duration.data == 0xFE
# Test turn_off
# Factory Default
device.turn_off()
assert duration.data == 0xFF
# Seconds transition
device.turn_off(**{ATTR_TRANSITION: 45})
assert duration.data == 45
# Minutes transition
device.turn_off(**{ATTR_TRANSITION: 245})
assert duration.data == 0x83
# Clipped transition
device.turn_off(**{ATTR_TRANSITION: 10000})
assert duration.data == 0xFE
def test_dimmer_turn_off(mock_openzwave):
"""Test turning off a dimmable Z-Wave light."""
node = MockNode()
value = MockValue(data=46, node=node)
values = MockLightValues(primary=value)
device = light.get_device(node=node, values=values, node_config={})
device.turn_off()
assert node.set_dimmer.called
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
assert brightness == 0
def test_dimmer_value_changed(mock_openzwave):
"""Test value changed for dimmer lights."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockLightValues(primary=value)
device = light.get_device(node=node, values=values, node_config={})
assert not device.is_on
value.data = 46
value_changed(value)
assert device.is_on
assert device.brightness == 118
def test_dimmer_refresh_value(mock_openzwave):
"""Test value changed for dimmer lights."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockLightValues(primary=value)
device = light.get_device(
node=node,
values=values,
node_config={zwave.CONF_REFRESH_VALUE: True, zwave.CONF_REFRESH_DELAY: 5},
)
assert not device.is_on
with patch.object(light, "Timer") as mock_timer:
value.data = 46
value_changed(value)
assert not device.is_on
assert mock_timer.called
assert len(mock_timer.mock_calls) == 2
timeout, callback = mock_timer.mock_calls[0][1][:2]
assert timeout == 5
assert mock_timer().start.called
assert len(mock_timer().start.mock_calls) == 1
with patch.object(light, "Timer") as mock_timer_2:
value_changed(value)
assert not device.is_on
assert mock_timer().cancel.called
assert len(mock_timer_2.mock_calls) == 2
timeout, callback = mock_timer_2.mock_calls[0][1][:2]
assert timeout == 5
assert mock_timer_2().start.called
assert len(mock_timer_2().start.mock_calls) == 1
callback()
assert device.is_on
assert device.brightness == 118
def test_set_rgb_color(mock_openzwave):
"""Test setting zwave light color."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
# Supports RGB only
color_channels = MockValue(data=0x1C, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
assert color.data == "#0000000000"
device.turn_on(**{ATTR_RGB_COLOR: (0xFF, 0xBF, 0x7F)})
assert color.data == "#ffbf7f0000"
def test_set_white_value(mock_openzwave):
"""Test setting zwave light color."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
# Supports RGBW
color_channels = MockValue(data=0x1D, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
assert color.data == "#0000000000"
device.turn_on(**{ATTR_RGBW_COLOR: (0xFF, 0xFF, 0xFF, 0xC8)})
assert color.data == "#ffffffc800"
def test_disable_white_if_set_color(mock_openzwave):
"""
Test that _white is set to 0 if turn_on with ATTR_RGB_COLOR.
See Issue #13930 - many RGBW ZWave bulbs will only activate the RGB LED to
produce color if _white is set to zero.
"""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
# Supports RGB only
color_channels = MockValue(data=0x1C, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
device._white = 234
assert color.data == "#0000000000"
assert device.rgbw_color == (0, 0, 0, 234)
device.turn_on(**{ATTR_RGB_COLOR: (0xFF, 0xBF, 0x7F)})
assert color.data == "#ffbf7f0000"
assert device.rgbw_color == (0xFF, 0xBF, 0x7F, 0x00)
def test_zw098_set_color_temp(mock_openzwave):
"""Test setting zwave light color."""
node = MockNode(
manufacturer_id="0086",
product_id="0062",
command_classes=[const.COMMAND_CLASS_SWITCH_COLOR],
)
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
# Supports RGB, warm white, cold white
color_channels = MockValue(data=0x1F, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
assert color.data == "#0000000000"
device.turn_on(**{ATTR_COLOR_TEMP: 200})
assert color.data == "#00000000ff"
device.turn_on(**{ATTR_COLOR_TEMP: 400})
assert color.data == "#000000ff00"
def test_rgb_not_supported(mock_openzwave):
"""Test value changed for rgb lights."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
# Supports color temperature only
color_channels = MockValue(data=0x01, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
assert device.rgb_color is None
assert device.rgbw_color is None
def test_no_color_value(mock_openzwave):
"""Test value changed for rgb lights."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
values = MockLightValues(primary=value)
device = light.get_device(node=node, values=values, node_config={})
assert device.rgb_color is None
assert device.rgbw_color is None
def test_no_color_channels_value(mock_openzwave):
"""Test value changed for rgb lights."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
values = MockLightValues(primary=value, color=color)
device = light.get_device(node=node, values=values, node_config={})
assert device.rgb_color is None
assert device.rgbw_color is None
def test_rgb_value_changed(mock_openzwave):
"""Test value changed for rgb lights."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
# Supports RGB only
color_channels = MockValue(data=0x1C, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
assert device.rgb_color == (0, 0, 0)
color.data = "#ffbf800000"
value_changed(color)
assert device.rgb_color == (0xFF, 0xBF, 0x80)
def test_rgbww_value_changed(mock_openzwave):
"""Test value changed for rgb lights."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
# Supports RGB, Warm White
color_channels = MockValue(data=0x1D, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
assert device.rgbw_color == (0, 0, 0, 0)
color.data = "#c86400c800"
value_changed(color)
assert device.rgbw_color == (0xC8, 0x64, 0x00, 0xC8)
def test_rgbcw_value_changed(mock_openzwave):
"""Test value changed for rgb lights."""
node = MockNode(command_classes=[const.COMMAND_CLASS_SWITCH_COLOR])
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
# Supports RGB, Cold White
color_channels = MockValue(data=0x1E, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
assert device.rgbw_color == (0, 0, 0, 0)
color.data = "#c86400c800"
value_changed(color)
assert device.rgbw_color == (0xC8, 0x64, 0x00, 0xC8)
def test_ct_value_changed(mock_openzwave):
"""Test value changed for zw098 lights."""
node = MockNode(
manufacturer_id="0086",
product_id="0062",
command_classes=[const.COMMAND_CLASS_SWITCH_COLOR],
)
value = MockValue(data=0, node=node)
color = MockValue(data="#0000000000", node=node)
# Supports RGB, Cold White
color_channels = MockValue(data=0x1F, node=node)
values = MockLightValues(primary=value, color=color, color_channels=color_channels)
device = light.get_device(node=node, values=values, node_config={})
assert device.color_mode == COLOR_MODE_RGB
assert device.color_temp is None
color.data = "#000000ff00"
value_changed(color)
assert device.color_mode == COLOR_MODE_COLOR_TEMP
assert device.color_temp == light.TEMP_WARM_HASS
color.data = "#00000000ff"
value_changed(color)
assert device.color_mode == COLOR_MODE_COLOR_TEMP
assert device.color_temp == light.TEMP_COLD_HASS
color.data = "#ff00000000"
value_changed(color)
assert device.color_mode == COLOR_MODE_RGB

View File

@ -1,389 +0,0 @@
"""Test Z-Wave locks."""
from unittest.mock import MagicMock, patch
import pytest
from homeassistant import config_entries
from homeassistant.components.zwave import const, lock
from tests.mock.zwave import MockEntityValues, MockNode, MockValue, value_changed
# Integration is disabled
pytest.skip("Integration has been disabled in the manifest", allow_module_level=True)
def test_get_device_detects_lock(mock_openzwave):
"""Test get_device returns a Z-Wave lock."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(data=None, node=node),
access_control=None,
alarm_type=None,
alarm_level=None,
)
device = lock.get_device(node=node, values=values, node_config={})
assert isinstance(device, lock.ZwaveLock)
def test_lock_turn_on_and_off(mock_openzwave):
"""Test turning on a Z-Wave lock."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(data=None, node=node),
access_control=None,
alarm_type=None,
alarm_level=None,
)
device = lock.get_device(node=node, values=values, node_config={})
assert not values.primary.data
device.lock()
assert values.primary.data
device.unlock()
assert not values.primary.data
def test_lock_value_changed(mock_openzwave):
"""Test value changed for Z-Wave lock."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(data=None, node=node),
access_control=None,
alarm_type=None,
alarm_level=None,
)
device = lock.get_device(node=node, values=values, node_config={})
assert not device.is_locked
values.primary.data = True
value_changed(values.primary)
assert device.is_locked
def test_lock_state_workaround(mock_openzwave):
"""Test value changed for Z-Wave lock using notification state."""
node = MockNode(manufacturer_id="0090", product_id="0440")
values = MockEntityValues(
primary=MockValue(data=True, node=node),
access_control=MockValue(data=1, node=node),
alarm_type=None,
alarm_level=None,
)
device = lock.get_device(node=node, values=values)
assert device.is_locked
values.access_control.data = 2
value_changed(values.access_control)
assert not device.is_locked
def test_track_message_workaround(mock_openzwave):
"""Test value changed for Z-Wave lock by alarm-clearing workaround."""
node = MockNode(
manufacturer_id="003B",
product_id="5044",
stats={"lastReceivedMessage": [0] * 6},
)
values = MockEntityValues(
primary=MockValue(data=True, node=node),
access_control=None,
alarm_type=None,
alarm_level=None,
)
# Here we simulate an RF lock. The first lock.get_device will call
# update properties, simulating the first DoorLock report. We then trigger
# a change, simulating the openzwave automatic refreshing behavior (which
# is enabled for at least the lock that needs this workaround)
node.stats["lastReceivedMessage"][5] = const.COMMAND_CLASS_DOOR_LOCK
device = lock.get_device(node=node, values=values)
value_changed(values.primary)
assert device.is_locked
assert device.extra_state_attributes[lock.ATTR_NOTIFICATION] == "RF Lock"
# Simulate a keypad unlock. We trigger a value_changed() which simulates
# the Alarm notification received from the lock. Then, we trigger
# value_changed() to simulate the automatic refreshing behavior.
values.access_control = MockValue(data=6, node=node)
values.alarm_type = MockValue(data=19, node=node)
values.alarm_level = MockValue(data=3, node=node)
node.stats["lastReceivedMessage"][5] = const.COMMAND_CLASS_ALARM
value_changed(values.access_control)
node.stats["lastReceivedMessage"][5] = const.COMMAND_CLASS_DOOR_LOCK
values.primary.data = False
value_changed(values.primary)
assert not device.is_locked
assert (
device.extra_state_attributes[lock.ATTR_LOCK_STATUS]
== "Unlocked with Keypad by user 3"
)
# Again, simulate an RF lock.
device.lock()
node.stats["lastReceivedMessage"][5] = const.COMMAND_CLASS_DOOR_LOCK
value_changed(values.primary)
assert device.is_locked
assert device.extra_state_attributes[lock.ATTR_NOTIFICATION] == "RF Lock"
def test_v2btze_value_changed(mock_openzwave):
"""Test value changed for v2btze Z-Wave lock."""
node = MockNode(manufacturer_id="010e", product_id="0002")
values = MockEntityValues(
primary=MockValue(data=None, node=node),
v2btze_advanced=MockValue(data="Advanced", node=node),
access_control=MockValue(data=19, node=node),
alarm_type=None,
alarm_level=None,
)
device = lock.get_device(node=node, values=values, node_config={})
assert device._v2btze
assert not device.is_locked
values.access_control.data = 24
value_changed(values.primary)
assert device.is_locked
def test_alarm_type_workaround(mock_openzwave):
"""Test value changed for Z-Wave lock using alarm type."""
node = MockNode(manufacturer_id="0109", product_id="0000")
values = MockEntityValues(
primary=MockValue(data=True, node=node),
access_control=None,
alarm_type=MockValue(data=16, node=node),
alarm_level=None,
)
device = lock.get_device(node=node, values=values)
assert not device.is_locked
values.alarm_type.data = 18
value_changed(values.alarm_type)
assert device.is_locked
values.alarm_type.data = 19
value_changed(values.alarm_type)
assert not device.is_locked
values.alarm_type.data = 21
value_changed(values.alarm_type)
assert device.is_locked
values.alarm_type.data = 22
value_changed(values.alarm_type)
assert not device.is_locked
values.alarm_type.data = 24
value_changed(values.alarm_type)
assert device.is_locked
values.alarm_type.data = 25
value_changed(values.alarm_type)
assert not device.is_locked
values.alarm_type.data = 27
value_changed(values.alarm_type)
assert device.is_locked
def test_lock_access_control(mock_openzwave):
"""Test access control for Z-Wave lock."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(data=None, node=node),
access_control=MockValue(data=11, node=node),
alarm_type=None,
alarm_level=None,
)
device = lock.get_device(node=node, values=values, node_config={})
assert device.extra_state_attributes[lock.ATTR_NOTIFICATION] == "Lock Jammed"
def test_lock_alarm_type(mock_openzwave):
"""Test alarm type for Z-Wave lock."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(data=None, node=node),
access_control=None,
alarm_type=MockValue(data=None, node=node),
alarm_level=None,
)
device = lock.get_device(node=node, values=values, node_config={})
assert lock.ATTR_LOCK_STATUS not in device.extra_state_attributes
values.alarm_type.data = 21
value_changed(values.alarm_type)
assert (
device.extra_state_attributes[lock.ATTR_LOCK_STATUS] == "Manually Locked None"
)
values.alarm_type.data = 18
value_changed(values.alarm_type)
assert (
device.extra_state_attributes[lock.ATTR_LOCK_STATUS]
== "Locked with Keypad by user None"
)
values.alarm_type.data = 161
value_changed(values.alarm_type)
assert device.extra_state_attributes[lock.ATTR_LOCK_STATUS] == "Tamper Alarm: None"
values.alarm_type.data = 9
value_changed(values.alarm_type)
assert device.extra_state_attributes[lock.ATTR_LOCK_STATUS] == "Deadbolt Jammed"
def test_lock_alarm_level(mock_openzwave):
"""Test alarm level for Z-Wave lock."""
node = MockNode()
values = MockEntityValues(
primary=MockValue(data=None, node=node),
access_control=None,
alarm_type=MockValue(data=None, node=node),
alarm_level=MockValue(data=None, node=node),
)
device = lock.get_device(node=node, values=values, node_config={})
assert lock.ATTR_LOCK_STATUS not in device.extra_state_attributes
values.alarm_type.data = 21
values.alarm_level.data = 1
value_changed(values.alarm_type)
value_changed(values.alarm_level)
assert (
device.extra_state_attributes[lock.ATTR_LOCK_STATUS]
== "Manually Locked by Key Cylinder or Inside thumb turn"
)
values.alarm_type.data = 18
values.alarm_level.data = "alice"
value_changed(values.alarm_type)
value_changed(values.alarm_level)
assert (
device.extra_state_attributes[lock.ATTR_LOCK_STATUS]
== "Locked with Keypad by user alice"
)
values.alarm_type.data = 161
values.alarm_level.data = 1
value_changed(values.alarm_type)
value_changed(values.alarm_level)
assert (
device.extra_state_attributes[lock.ATTR_LOCK_STATUS]
== "Tamper Alarm: Too many keypresses"
)
async def setup_ozw(hass, mock_openzwave):
"""Set up the mock ZWave config entry."""
hass.config.components.add("zwave")
config_entry = config_entries.ConfigEntry(
1,
"zwave",
"Mock Title",
{"usb_path": "mock-path", "network_key": "mock-key"},
"test",
)
await hass.config_entries.async_forward_entry_setup(config_entry, "lock")
await hass.async_block_till_done()
async def test_lock_set_usercode_service(hass, mock_openzwave):
"""Test the zwave lock set_usercode service."""
mock_network = hass.data[const.DATA_NETWORK] = MagicMock()
node = MockNode(node_id=12)
value0 = MockValue(data=" ", node=node, index=0)
value1 = MockValue(data=" ", node=node, index=1)
node.get_values.return_value = {value0.value_id: value0, value1.value_id: value1}
mock_network.nodes = {node.node_id: node}
await setup_ozw(hass, mock_openzwave)
await hass.async_block_till_done()
await hass.services.async_call(
lock.DOMAIN,
lock.SERVICE_SET_USERCODE,
{
const.ATTR_NODE_ID: node.node_id,
lock.ATTR_USERCODE: "1234",
lock.ATTR_CODE_SLOT: 1,
},
)
await hass.async_block_till_done()
assert value1.data == "1234"
mock_network.nodes = {node.node_id: node}
await hass.services.async_call(
lock.DOMAIN,
lock.SERVICE_SET_USERCODE,
{
const.ATTR_NODE_ID: node.node_id,
lock.ATTR_USERCODE: "123",
lock.ATTR_CODE_SLOT: 1,
},
)
await hass.async_block_till_done()
assert value1.data == "1234"
async def test_lock_get_usercode_service(hass, mock_openzwave):
"""Test the zwave lock get_usercode service."""
mock_network = hass.data[const.DATA_NETWORK] = MagicMock()
node = MockNode(node_id=12)
value0 = MockValue(data=None, node=node, index=0)
value1 = MockValue(data="1234", node=node, index=1)
node.get_values.return_value = {value0.value_id: value0, value1.value_id: value1}
await setup_ozw(hass, mock_openzwave)
await hass.async_block_till_done()
with patch.object(lock, "_LOGGER") as mock_logger:
mock_network.nodes = {node.node_id: node}
await hass.services.async_call(
lock.DOMAIN,
lock.SERVICE_GET_USERCODE,
{const.ATTR_NODE_ID: node.node_id, lock.ATTR_CODE_SLOT: 1},
)
await hass.async_block_till_done()
# This service only seems to write to the log
assert mock_logger.info.called
assert len(mock_logger.info.mock_calls) == 1
assert mock_logger.info.mock_calls[0][1][2] == "1234"
async def test_lock_clear_usercode_service(hass, mock_openzwave):
"""Test the zwave lock clear_usercode service."""
mock_network = hass.data[const.DATA_NETWORK] = MagicMock()
node = MockNode(node_id=12)
value0 = MockValue(data=None, node=node, index=0)
value1 = MockValue(data="123", node=node, index=1)
node.get_values.return_value = {value0.value_id: value0, value1.value_id: value1}
mock_network.nodes = {node.node_id: node}
await setup_ozw(hass, mock_openzwave)
await hass.async_block_till_done()
await hass.services.async_call(
lock.DOMAIN,
lock.SERVICE_CLEAR_USERCODE,
{const.ATTR_NODE_ID: node.node_id, lock.ATTR_CODE_SLOT: 1},
)
await hass.async_block_till_done()
assert value1.data == "\0\0\0"

View File

@ -1,723 +0,0 @@
"""Test Z-Wave node entity."""
from unittest.mock import MagicMock, patch
import pytest
from homeassistant.components.zwave import const, node_entity
from homeassistant.const import ATTR_ENTITY_ID
import tests.mock.zwave as mock_zwave
# Integration is disabled
pytest.skip("Integration has been disabled in the manifest", allow_module_level=True)
async def test_maybe_schedule_update(hass, mock_openzwave):
"""Test maybe schedule update."""
base_entity = node_entity.ZWaveBaseEntity()
base_entity.entity_id = "zwave.bla"
base_entity.hass = hass
with patch.object(hass.loop, "call_later") as mock_call_later:
base_entity._schedule_update()
assert mock_call_later.called
base_entity._schedule_update()
assert len(mock_call_later.mock_calls) == 1
assert base_entity._update_scheduled is True
do_update = mock_call_later.mock_calls[0][1][1]
do_update()
assert base_entity._update_scheduled is False
base_entity._schedule_update()
assert len(mock_call_later.mock_calls) == 2
async def test_node_event_activated(hass, mock_openzwave):
"""Test Node event activated event."""
mock_receivers = []
def mock_connect(receiver, signal, *args, **kwargs):
if signal == mock_zwave.MockNetwork.SIGNAL_NODE_EVENT:
mock_receivers.append(receiver)
node = mock_zwave.MockNode(node_id=11)
with patch("pydispatch.dispatcher.connect", new=mock_connect):
entity = node_entity.ZWaveNodeEntity(node, mock_openzwave)
assert len(mock_receivers) == 1
events = []
def listener(event):
events.append(event)
hass.bus.async_listen(const.EVENT_NODE_EVENT, listener)
# Test event before entity added to hass
value = 234
hass.async_add_job(mock_receivers[0], node, value)
await hass.async_block_till_done()
assert len(events) == 0
# Add entity to hass
entity.hass = hass
entity.entity_id = "zwave.mock_node"
value = 234
hass.async_add_job(mock_receivers[0], node, value)
await hass.async_block_till_done()
assert len(events) == 1
assert events[0].data[ATTR_ENTITY_ID] == "zwave.mock_node"
assert events[0].data[const.ATTR_NODE_ID] == 11
assert events[0].data[const.ATTR_BASIC_LEVEL] == value
async def test_scene_activated(hass, mock_openzwave):
"""Test scene activated event."""
mock_receivers = []
def mock_connect(receiver, signal, *args, **kwargs):
if signal == mock_zwave.MockNetwork.SIGNAL_SCENE_EVENT:
mock_receivers.append(receiver)
node = mock_zwave.MockNode(node_id=11)
with patch("pydispatch.dispatcher.connect", new=mock_connect):
entity = node_entity.ZWaveNodeEntity(node, mock_openzwave)
assert len(mock_receivers) == 1
events = []
def listener(event):
events.append(event)
hass.bus.async_listen(const.EVENT_SCENE_ACTIVATED, listener)
# Test event before entity added to hass
scene_id = 123
hass.async_add_job(mock_receivers[0], node, scene_id)
await hass.async_block_till_done()
assert len(events) == 0
# Add entity to hass
entity.hass = hass
entity.entity_id = "zwave.mock_node"
scene_id = 123
hass.async_add_job(mock_receivers[0], node, scene_id)
await hass.async_block_till_done()
assert len(events) == 1
assert events[0].data[ATTR_ENTITY_ID] == "zwave.mock_node"
assert events[0].data[const.ATTR_NODE_ID] == 11
assert events[0].data[const.ATTR_SCENE_ID] == scene_id
async def test_central_scene_activated(hass, mock_openzwave):
"""Test central scene activated event."""
mock_receivers = []
def mock_connect(receiver, signal, *args, **kwargs):
if signal == mock_zwave.MockNetwork.SIGNAL_VALUE_CHANGED:
mock_receivers.append(receiver)
node = mock_zwave.MockNode(node_id=11)
with patch("pydispatch.dispatcher.connect", new=mock_connect):
entity = node_entity.ZWaveNodeEntity(node, mock_openzwave)
assert len(mock_receivers) == 1
events = []
def listener(event):
events.append(event)
hass.bus.async_listen(const.EVENT_SCENE_ACTIVATED, listener)
# Test event before entity added to hass
scene_id = 1
scene_data = 3
value = mock_zwave.MockValue(
command_class=const.COMMAND_CLASS_CENTRAL_SCENE, index=scene_id, data=scene_data
)
hass.async_add_job(mock_receivers[0], node, value)
await hass.async_block_till_done()
assert len(events) == 0
# Add entity to hass
entity.hass = hass
entity.entity_id = "zwave.mock_node"
scene_id = 1
scene_data = 3
value = mock_zwave.MockValue(
command_class=const.COMMAND_CLASS_CENTRAL_SCENE, index=scene_id, data=scene_data
)
hass.async_add_job(mock_receivers[0], node, value)
await hass.async_block_till_done()
assert len(events) == 1
assert events[0].data[ATTR_ENTITY_ID] == "zwave.mock_node"
assert events[0].data[const.ATTR_NODE_ID] == 11
assert events[0].data[const.ATTR_SCENE_ID] == scene_id
assert events[0].data[const.ATTR_SCENE_DATA] == scene_data
async def test_application_version(hass, mock_openzwave):
"""Test application version."""
mock_receivers = {}
signal_mocks = [
mock_zwave.MockNetwork.SIGNAL_VALUE_CHANGED,
mock_zwave.MockNetwork.SIGNAL_VALUE_ADDED,
]
def mock_connect(receiver, signal, *args, **kwargs):
if signal in signal_mocks:
mock_receivers[signal] = receiver
node = mock_zwave.MockNode(node_id=11)
with patch("pydispatch.dispatcher.connect", new=mock_connect):
entity = node_entity.ZWaveNodeEntity(node, mock_openzwave)
for signal_mock in signal_mocks:
assert signal_mock in mock_receivers.keys()
events = []
def listener(event):
events.append(event)
# Make sure application version isn't set before
assert (
node_entity.ATTR_APPLICATION_VERSION not in entity.extra_state_attributes.keys()
)
# Add entity to hass
entity.hass = hass
entity.entity_id = "zwave.mock_node"
# Fire off an added value
value = mock_zwave.MockValue(
command_class=const.COMMAND_CLASS_VERSION,
label="Application Version",
data="5.10",
)
hass.async_add_job(
mock_receivers[mock_zwave.MockNetwork.SIGNAL_VALUE_ADDED], node, value
)
await hass.async_block_till_done()
assert entity.extra_state_attributes[node_entity.ATTR_APPLICATION_VERSION] == "5.10"
# Fire off a changed
value = mock_zwave.MockValue(
command_class=const.COMMAND_CLASS_VERSION,
label="Application Version",
data="4.14",
)
hass.async_add_job(
mock_receivers[mock_zwave.MockNetwork.SIGNAL_VALUE_CHANGED], node, value
)
await hass.async_block_till_done()
assert entity.extra_state_attributes[node_entity.ATTR_APPLICATION_VERSION] == "4.14"
async def test_network_node_changed_from_value(hass, mock_openzwave):
"""Test for network_node_changed."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
value = mock_zwave.MockValue(node=node)
with patch.object(entity, "maybe_schedule_update") as mock:
mock_zwave.value_changed(value)
mock.assert_called_once_with()
async def test_network_node_changed_from_node(hass, mock_openzwave):
"""Test for network_node_changed."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
with patch.object(entity, "maybe_schedule_update") as mock:
mock_zwave.node_changed(node)
mock.assert_called_once_with()
async def test_network_node_changed_from_another_node(hass, mock_openzwave):
"""Test for network_node_changed."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
with patch.object(entity, "maybe_schedule_update") as mock:
another_node = mock_zwave.MockNode(node_id=1024)
mock_zwave.node_changed(another_node)
assert not mock.called
async def test_network_node_changed_from_notification(hass, mock_openzwave):
"""Test for network_node_changed."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
with patch.object(entity, "maybe_schedule_update") as mock:
mock_zwave.notification(node_id=node.node_id)
mock.assert_called_once_with()
async def test_network_node_changed_from_another_notification(hass, mock_openzwave):
"""Test for network_node_changed."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
with patch.object(entity, "maybe_schedule_update") as mock:
mock_zwave.notification(node_id=1024)
assert not mock.called
async def test_node_changed(hass, mock_openzwave):
"""Test node_changed function."""
zwave_network = MagicMock()
node = mock_zwave.MockNode(
query_stage="Dynamic",
is_awake=True,
is_ready=False,
is_failed=False,
is_info_received=True,
max_baud_rate=40000,
is_zwave_plus=False,
capabilities=[],
neighbors=[],
location=None,
)
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
assert {
"node_id": node.node_id,
"node_name": "Mock Node",
"manufacturer_name": "Test Manufacturer",
"product_name": "Test Product",
} == entity.extra_state_attributes
node.get_values.return_value = {1: mock_zwave.MockValue(data=1800)}
zwave_network.manager.getNodeStatistics.return_value = {
"receivedCnt": 4,
"ccData": [
{"receivedCnt": 0, "commandClassId": 134, "sentCnt": 0},
{"receivedCnt": 1, "commandClassId": 133, "sentCnt": 1},
{"receivedCnt": 1, "commandClassId": 115, "sentCnt": 1},
{"receivedCnt": 0, "commandClassId": 114, "sentCnt": 0},
{"receivedCnt": 0, "commandClassId": 112, "sentCnt": 0},
{"receivedCnt": 1, "commandClassId": 32, "sentCnt": 1},
{"receivedCnt": 0, "commandClassId": 0, "sentCnt": 0},
],
"receivedUnsolicited": 0,
"sentTS": "2017-03-27 15:38:15:620 ",
"averageRequestRTT": 2462,
"lastResponseRTT": 3679,
"retries": 0,
"sentFailed": 1,
"sentCnt": 7,
"quality": 0,
"lastRequestRTT": 1591,
"lastReceivedMessage": [
0,
4,
0,
15,
3,
32,
3,
0,
221,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
],
"receivedDups": 1,
"averageResponseRTT": 2443,
"receivedTS": "2017-03-27 15:38:19:298 ",
}
entity.node_changed()
assert {
"node_id": node.node_id,
"node_name": "Mock Node",
"manufacturer_name": "Test Manufacturer",
"product_name": "Test Product",
"query_stage": "Dynamic",
"is_awake": True,
"is_ready": False,
"is_failed": False,
"is_info_received": True,
"max_baud_rate": 40000,
"is_zwave_plus": False,
"battery_level": 42,
"wake_up_interval": 1800,
"averageRequestRTT": 2462,
"averageResponseRTT": 2443,
"lastRequestRTT": 1591,
"lastResponseRTT": 3679,
"receivedCnt": 4,
"receivedDups": 1,
"receivedTS": "2017-03-27 15:38:19:298 ",
"receivedUnsolicited": 0,
"retries": 0,
"sentCnt": 7,
"sentFailed": 1,
"sentTS": "2017-03-27 15:38:15:620 ",
} == entity.extra_state_attributes
node.can_wake_up_value = False
entity.node_changed()
assert "wake_up_interval" not in entity.extra_state_attributes
async def test_name(hass, mock_openzwave):
"""Test name property."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
assert entity.name == "Mock Node"
async def test_state_before_update(hass, mock_openzwave):
"""Test state before update was called."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
assert entity.state is None
async def test_state_not_ready(hass, mock_openzwave):
"""Test state property."""
zwave_network = MagicMock()
node = mock_zwave.MockNode(
query_stage="Dynamic",
is_awake=True,
is_ready=False,
is_failed=False,
is_info_received=True,
)
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
node.is_ready = False
entity.node_changed()
assert entity.state == "initializing"
node.is_failed = True
node.query_stage = "Complete"
entity.node_changed()
assert entity.state == "dead"
node.is_failed = False
node.is_awake = False
entity.node_changed()
assert entity.state == "sleeping"
async def test_state_ready(hass, mock_openzwave):
"""Test state property."""
zwave_network = MagicMock()
node = mock_zwave.MockNode(
query_stage="Dynamic",
is_awake=True,
is_ready=False,
is_failed=False,
is_info_received=True,
)
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
node.query_stage = "Complete"
node.is_ready = True
entity.node_changed()
await hass.async_block_till_done()
assert entity.state == "ready"
node.is_failed = True
entity.node_changed()
assert entity.state == "dead"
node.is_failed = False
node.is_awake = False
entity.node_changed()
assert entity.state == "sleeping"
async def test_not_polled(hass, mock_openzwave):
"""Test should_poll property."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
assert not entity.should_poll
async def test_unique_id(hass, mock_openzwave):
"""Test unique_id."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
assert entity.unique_id == "node-567"
async def test_unique_id_missing_data(hass, mock_openzwave):
"""Test unique_id."""
zwave_network = MagicMock()
node = mock_zwave.MockNode()
node.manufacturer_name = None
node.name = None
node.is_ready = False
entity = node_entity.ZWaveNodeEntity(node, zwave_network)
assert entity.unique_id is None

View File

@ -1,183 +0,0 @@
"""Test Z-Wave sensor."""
import pytest
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.components.zwave import const, sensor
import homeassistant.const
from tests.mock.zwave import MockEntityValues, MockNode, MockValue, value_changed
# Integration is disabled
pytest.skip("Integration has been disabled in the manifest", allow_module_level=True)
def test_get_device_detects_none(mock_openzwave):
"""Test get_device returns None."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
assert device is None
def test_get_device_detects_alarmsensor(mock_openzwave):
"""Test get_device returns a Z-Wave alarmsensor."""
node = MockNode(
command_classes=[const.COMMAND_CLASS_ALARM, const.COMMAND_CLASS_SENSOR_ALARM]
)
value = MockValue(data=0, node=node)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
assert isinstance(device, sensor.ZWaveAlarmSensor)
def test_get_device_detects_multilevelsensor(mock_openzwave):
"""Test get_device returns a Z-Wave multilevel sensor."""
node = MockNode(
command_classes=[
const.COMMAND_CLASS_SENSOR_MULTILEVEL,
const.COMMAND_CLASS_METER,
]
)
value = MockValue(data=0, node=node)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
assert isinstance(device, sensor.ZWaveMultilevelSensor)
assert device.force_update
def test_get_device_detects_multilevel_meter(mock_openzwave):
"""Test get_device returns a Z-Wave multilevel sensor."""
node = MockNode(command_classes=[const.COMMAND_CLASS_METER])
value = MockValue(data=0, node=node, type=const.TYPE_DECIMAL)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
assert isinstance(device, sensor.ZWaveMultilevelSensor)
def test_get_device_detects_battery_sensor(mock_openzwave):
"""Test get_device returns a Z-Wave battery sensor."""
node = MockNode(command_classes=[const.COMMAND_CLASS_BATTERY])
value = MockValue(
data=0,
node=node,
type=const.TYPE_DECIMAL,
command_class=const.COMMAND_CLASS_BATTERY,
)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
assert isinstance(device, sensor.ZWaveBatterySensor)
assert device.device_class is SensorDeviceClass.BATTERY
def test_multilevelsensor_value_changed_temp_fahrenheit(hass, mock_openzwave):
"""Test value changed for Z-Wave multilevel sensor for temperature."""
hass.config.units.temperature_unit = homeassistant.const.TEMP_FAHRENHEIT
node = MockNode(
command_classes=[
const.COMMAND_CLASS_SENSOR_MULTILEVEL,
const.COMMAND_CLASS_METER,
]
)
value = MockValue(data=190.95555, units="F", node=node)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
device.hass = hass
assert device.state == 191.0
assert device.unit_of_measurement == homeassistant.const.TEMP_FAHRENHEIT
assert device.device_class is SensorDeviceClass.TEMPERATURE
value.data = 197.95555
value_changed(value)
assert device.state == 198.0
def test_multilevelsensor_value_changed_temp_celsius(hass, mock_openzwave):
"""Test value changed for Z-Wave multilevel sensor for temperature."""
hass.config.units.temperature_unit = homeassistant.const.TEMP_CELSIUS
node = MockNode(
command_classes=[
const.COMMAND_CLASS_SENSOR_MULTILEVEL,
const.COMMAND_CLASS_METER,
]
)
value = MockValue(data=38.85555, units="C", node=node)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
device.hass = hass
assert device.state == 38.9
assert device.unit_of_measurement == homeassistant.const.TEMP_CELSIUS
assert device.device_class is SensorDeviceClass.TEMPERATURE
value.data = 37.95555
value_changed(value)
assert device.state == 38.0
def test_multilevelsensor_value_changed_other_units(hass, mock_openzwave):
"""Test value changed for Z-Wave multilevel sensor for other units."""
node = MockNode(
command_classes=[
const.COMMAND_CLASS_SENSOR_MULTILEVEL,
const.COMMAND_CLASS_METER,
]
)
value = MockValue(
data=190.95555, units=homeassistant.const.ENERGY_KILO_WATT_HOUR, node=node
)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
device.hass = hass
assert device.state == 190.96
assert device.unit_of_measurement == homeassistant.const.ENERGY_KILO_WATT_HOUR
assert device.device_class is None
value.data = 197.95555
value_changed(value)
assert device.state == 197.96
def test_multilevelsensor_value_changed_integer(hass, mock_openzwave):
"""Test value changed for Z-Wave multilevel sensor for other units."""
node = MockNode(
command_classes=[
const.COMMAND_CLASS_SENSOR_MULTILEVEL,
const.COMMAND_CLASS_METER,
]
)
value = MockValue(data=5, units="counts", node=node)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
device.hass = hass
assert device.state == 5
assert device.unit_of_measurement == "counts"
assert device.device_class is None
value.data = 6
value_changed(value)
assert device.state == 6
def test_alarm_sensor_value_changed(hass, mock_openzwave):
"""Test value changed for Z-Wave sensor."""
node = MockNode(
command_classes=[const.COMMAND_CLASS_ALARM, const.COMMAND_CLASS_SENSOR_ALARM]
)
value = MockValue(data=12.34, node=node, units=homeassistant.const.PERCENTAGE)
values = MockEntityValues(primary=value)
device = sensor.get_device(node=node, values=values, node_config={})
device.hass = hass
assert device.state == 12.34
assert device.unit_of_measurement == homeassistant.const.PERCENTAGE
assert device.device_class is None
value.data = 45.67
value_changed(value)
assert device.state == 45.67

Some files were not shown because too many files have changed in this diff Show More