Remove deprecated OpenZWave integration (#68054)

This commit is contained in:
Franck Nijhof 2022-03-14 17:33:04 +01:00 committed by GitHub
parent 344537d0a8
commit 57c33a5cf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
96 changed files with 0 additions and 9863 deletions

View File

@ -872,9 +872,6 @@ omit =
homeassistant/components/ovo_energy/__init__.py
homeassistant/components/ovo_energy/const.py
homeassistant/components/ovo_energy/sensor.py
homeassistant/components/ozw/__init__.py
homeassistant/components/ozw/entity.py
homeassistant/components/ozw/services.py
homeassistant/components/panasonic_bluray/media_player.py
homeassistant/components/panasonic_viera/media_player.py
homeassistant/components/pandora/media_player.py

View File

@ -735,8 +735,6 @@ homeassistant/components/overkiz/* @imicknl @vlebourl @tetienne
tests/components/overkiz/* @imicknl @vlebourl @tetienne
homeassistant/components/ovo_energy/* @timmo001
tests/components/ovo_energy/* @timmo001
homeassistant/components/ozw/* @cgarwood @marcelveldt @MartinHjelmare
tests/components/ozw/* @cgarwood @marcelveldt @MartinHjelmare
homeassistant/components/p1_monitor/* @klaasnicolaas
tests/components/p1_monitor/* @klaasnicolaas
homeassistant/components/panel_custom/* @home-assistant/frontend

View File

@ -1,418 +0,0 @@
"""The ozw integration."""
import asyncio
from contextlib import suppress
import json
import logging
from openzwavemqtt import OZWManager, OZWOptions
from openzwavemqtt.const import (
EVENT_INSTANCE_EVENT,
EVENT_NODE_ADDED,
EVENT_NODE_CHANGED,
EVENT_NODE_REMOVED,
EVENT_VALUE_ADDED,
EVENT_VALUE_CHANGED,
EVENT_VALUE_REMOVED,
CommandClass,
ValueType,
)
from openzwavemqtt.models.node import OZWNode
from openzwavemqtt.models.value import OZWValue
from openzwavemqtt.util.mqtt_client import MQTTClient
from homeassistant.components import hassio, mqtt
from homeassistant.components.hassio.handler import HassioAPIError
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.device_registry import async_get_registry as get_dev_reg
from homeassistant.helpers.dispatcher import async_dispatcher_send
from . import const
from .const import (
CONF_INTEGRATION_CREATED_ADDON,
CONF_USE_ADDON,
DATA_UNSUBSCRIBE,
DOMAIN,
MANAGER,
NODES_VALUES,
PLATFORMS,
TOPIC_OPENZWAVE,
)
from .discovery import DISCOVERY_SCHEMAS, check_node_schema, check_value_schema
from .entity import (
ZWaveDeviceEntityValues,
create_device_id,
create_device_name,
create_value_id,
)
from .services import ZWaveServices
from .websocket_api import async_register_api
_LOGGER = logging.getLogger(__name__)
DATA_DEVICES = "zwave-mqtt-devices"
DATA_STOP_MQTT_CLIENT = "ozw_stop_mqtt_client"
async def async_setup_entry( # noqa: C901
hass: HomeAssistant, entry: ConfigEntry
) -> bool:
"""Set up ozw from a config entry."""
hass.data.setdefault(DOMAIN, {})
ozw_data = hass.data[DOMAIN][entry.entry_id] = {}
ozw_data[DATA_UNSUBSCRIBE] = []
data_nodes = {}
hass.data[DOMAIN][NODES_VALUES] = data_values = {}
removed_nodes = []
manager_options = {"topic_prefix": f"{TOPIC_OPENZWAVE}/"}
if entry.unique_id is None:
hass.config_entries.async_update_entry(entry, unique_id=DOMAIN)
if entry.data.get(CONF_USE_ADDON):
# Do not use MQTT integration. Use own MQTT client.
# Retrieve discovery info from the OpenZWave add-on.
discovery_info = await hassio.async_get_addon_discovery_info(hass, "core_zwave")
if not discovery_info:
_LOGGER.error("Failed to get add-on discovery info")
raise ConfigEntryNotReady
discovery_info_config = discovery_info["config"]
host = discovery_info_config["host"]
port = discovery_info_config["port"]
username = discovery_info_config["username"]
password = discovery_info_config["password"]
mqtt_client = MQTTClient(host, port, username=username, password=password)
manager_options["send_message"] = mqtt_client.send_message
else:
mqtt_entries = hass.config_entries.async_entries("mqtt")
if not mqtt_entries or mqtt_entries[0].state is not ConfigEntryState.LOADED:
_LOGGER.error("MQTT integration is not set up")
return False
mqtt_entry = mqtt_entries[0] # MQTT integration only has one entry.
@callback
def send_message(topic, payload):
if mqtt_entry.state is not ConfigEntryState.LOADED:
_LOGGER.error("MQTT integration is not set up")
return
hass.async_create_task(mqtt.async_publish(hass, topic, json.dumps(payload)))
manager_options["send_message"] = send_message
options = OZWOptions(**manager_options)
manager = OZWManager(options)
hass.data[DOMAIN][MANAGER] = manager
@callback
def async_node_added(node):
# Caution: This is also called on (re)start.
_LOGGER.debug("[NODE ADDED] node_id: %s", node.id)
data_nodes[node.id] = node
if node.id not in data_values:
data_values[node.id] = []
@callback
def async_node_changed(node):
_LOGGER.debug("[NODE CHANGED] node_id: %s", node.id)
data_nodes[node.id] = node
# notify devices about the node change
if node.id not in removed_nodes:
hass.async_create_task(async_handle_node_update(hass, node))
@callback
def async_node_removed(node):
_LOGGER.debug("[NODE REMOVED] node_id: %s", node.id)
data_nodes.pop(node.id)
# node added/removed events also happen on (re)starts of hass/mqtt/ozw
# cleanup device/entity registry if we know this node is permanently deleted
# entities itself are removed by the values logic
if node.id in removed_nodes:
hass.async_create_task(async_handle_remove_node(hass, node))
removed_nodes.remove(node.id)
@callback
def async_instance_event(message):
event = message["event"]
event_data = message["data"]
_LOGGER.debug("[INSTANCE EVENT]: %s - data: %s", event, event_data)
# The actual removal action of a Z-Wave node is reported as instance event
# Only when this event is detected we cleanup the device and entities from hass
# Note: Find a more elegant way of doing this, e.g. a notification of this event from OZW
if event in ("removenode", "removefailednode") and "Node" in event_data:
removed_nodes.append(event_data["Node"])
@callback
def async_value_added(value):
node = value.node
# Clean up node.node_id and node.id use. They are the same.
node_id = value.node.node_id
# Filter out CommandClasses we're definitely not interested in.
if value.command_class in (CommandClass.MANUFACTURER_SPECIFIC,):
return
_LOGGER.debug(
"[VALUE ADDED] node_id: %s - label: %s - value: %s - value_id: %s - CC: %s",
value.node.id,
value.label,
value.value,
value.value_id_key,
value.command_class,
)
node_data_values = data_values[node_id]
# Check if this value should be tracked by an existing entity
value_unique_id = create_value_id(value)
for values in node_data_values:
values.async_check_value(value)
if values.values_id == value_unique_id:
return # this value already has an entity
# Run discovery on it and see if any entities need created
for schema in DISCOVERY_SCHEMAS:
if not check_node_schema(node, schema):
continue
if not check_value_schema(
value, schema[const.DISC_VALUES][const.DISC_PRIMARY]
):
continue
values = ZWaveDeviceEntityValues(hass, options, schema, value)
values.async_setup()
# This is legacy and can be cleaned up since we are in the main thread:
# We create a new list and update the reference here so that
# the list can be safely iterated over in the main thread
data_values[node_id] = node_data_values + [values]
@callback
def async_value_changed(value):
# if an entity belonging to this value needs updating,
# it's handled within the entity logic
_LOGGER.debug(
"[VALUE CHANGED] node_id: %s - label: %s - value: %s - value_id: %s - CC: %s",
value.node.id,
value.label,
value.value,
value.value_id_key,
value.command_class,
)
# Handle a scene activation message
if value.command_class in (
CommandClass.SCENE_ACTIVATION,
CommandClass.CENTRAL_SCENE,
):
async_handle_scene_activated(hass, value)
return
@callback
def async_value_removed(value):
_LOGGER.debug(
"[VALUE REMOVED] node_id: %s - label: %s - value: %s - value_id: %s - CC: %s",
value.node.id,
value.label,
value.value,
value.value_id_key,
value.command_class,
)
# signal all entities using this value for removal
value_unique_id = create_value_id(value)
async_dispatcher_send(hass, const.SIGNAL_DELETE_ENTITY, value_unique_id)
# remove value from our local list
node_data_values = data_values[value.node.id]
node_data_values[:] = [
item for item in node_data_values if item.values_id != value_unique_id
]
# Listen to events for node and value changes
for event, event_callback in (
(EVENT_NODE_ADDED, async_node_added),
(EVENT_NODE_CHANGED, async_node_changed),
(EVENT_NODE_REMOVED, async_node_removed),
(EVENT_VALUE_ADDED, async_value_added),
(EVENT_VALUE_CHANGED, async_value_changed),
(EVENT_VALUE_REMOVED, async_value_removed),
(EVENT_INSTANCE_EVENT, async_instance_event),
):
ozw_data[DATA_UNSUBSCRIBE].append(options.listen(event, event_callback))
# Register Services
services = ZWaveServices(hass, manager)
services.async_register()
# Register WebSocket API
async_register_api(hass)
@callback
def async_receive_message(msg):
manager.receive_message(msg.topic, msg.payload)
async def start_platforms():
await asyncio.gather(
*(
hass.config_entries.async_forward_entry_setup(entry, platform)
for platform in PLATFORMS
)
)
if entry.data.get(CONF_USE_ADDON):
mqtt_client_task = asyncio.create_task(mqtt_client.start_client(manager))
async def async_stop_mqtt_client(event=None):
"""Stop the mqtt client.
Do not unsubscribe the manager topic.
"""
mqtt_client_task.cancel()
with suppress(asyncio.CancelledError):
await mqtt_client_task
ozw_data[DATA_UNSUBSCRIBE].append(
hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, async_stop_mqtt_client
)
)
ozw_data[DATA_STOP_MQTT_CLIENT] = async_stop_mqtt_client
else:
ozw_data[DATA_UNSUBSCRIBE].append(
await mqtt.async_subscribe(
hass, f"{manager.options.topic_prefix}#", async_receive_message
)
)
hass.async_create_task(start_platforms())
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
# cleanup platforms
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if not unload_ok:
return False
# unsubscribe all listeners
for unsubscribe_listener in hass.data[DOMAIN][entry.entry_id][DATA_UNSUBSCRIBE]:
unsubscribe_listener()
if entry.data.get(CONF_USE_ADDON):
async_stop_mqtt_client = hass.data[DOMAIN][entry.entry_id][
DATA_STOP_MQTT_CLIENT
]
await async_stop_mqtt_client()
hass.data[DOMAIN].pop(entry.entry_id)
return True
async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Remove a config entry."""
if not entry.data.get(CONF_INTEGRATION_CREATED_ADDON):
return
try:
await hassio.async_stop_addon(hass, "core_zwave")
except HassioAPIError as err:
_LOGGER.error("Failed to stop the OpenZWave add-on: %s", err)
return
try:
await hassio.async_uninstall_addon(hass, "core_zwave")
except HassioAPIError as err:
_LOGGER.error("Failed to uninstall the OpenZWave add-on: %s", err)
async def async_handle_remove_node(hass: HomeAssistant, node: OZWNode):
"""Handle the removal of a Z-Wave node, removing all traces in device/entity registry."""
dev_registry = await get_dev_reg(hass)
# grab device in device registry attached to this node
dev_id = create_device_id(node)
device = dev_registry.async_get_device({(DOMAIN, dev_id)})
if not device:
return
devices_to_remove = [device.id]
# also grab slave devices (node instances)
for item in dev_registry.devices.values():
if item.via_device_id == device.id:
devices_to_remove.append(item.id)
# remove all devices in registry related to this node
# note: removal of entity registry is handled by core
for dev_id in devices_to_remove:
dev_registry.async_remove_device(dev_id)
async def async_handle_node_update(hass: HomeAssistant, node: OZWNode):
"""
Handle a node updated event from OZW.
Meaning some of the basic info like name/model is updated.
We want these changes to be pushed to the device registry.
"""
dev_registry = await get_dev_reg(hass)
# grab device in device registry attached to this node
dev_id = create_device_id(node)
device = dev_registry.async_get_device({(DOMAIN, dev_id)})
if not device:
return
# update device in device registry with (updated) info
for item in dev_registry.devices.values():
if device.id not in (item.id, item.via_device_id):
continue
dev_name = create_device_name(node)
dev_registry.async_update_device(
item.id,
manufacturer=node.node_manufacturer_name,
model=node.node_product_name,
name=dev_name,
)
@callback
def async_handle_scene_activated(hass: HomeAssistant, scene_value: OZWValue):
"""Handle a (central) scene activation message."""
node_id = scene_value.node.id
ozw_instance_id = scene_value.ozw_instance.id
scene_id = scene_value.index
scene_label = scene_value.label
if scene_value.command_class == CommandClass.SCENE_ACTIVATION:
# legacy/network scene
scene_value_id = scene_value.value
scene_value_label = scene_value.label
else:
# central scene command
if scene_value.type != ValueType.LIST:
return
scene_value_label = scene_value.value["Selected"]
scene_value_id = scene_value.value["Selected_id"]
_LOGGER.debug(
"[SCENE_ACTIVATED] ozw_instance: %s - node_id: %s - scene_id: %s - scene_value_id: %s",
ozw_instance_id,
node_id,
scene_id,
scene_value_id,
)
# Simply forward it to the hass event bus
hass.bus.async_fire(
const.EVENT_SCENE_ACTIVATED,
{
const.ATTR_INSTANCE_ID: ozw_instance_id,
const.ATTR_NODE_ID: node_id,
const.ATTR_SCENE_ID: scene_id,
const.ATTR_SCENE_LABEL: scene_label,
const.ATTR_SCENE_VALUE_ID: scene_value_id,
const.ATTR_SCENE_VALUE_LABEL: scene_value_label,
},
)

View File

@ -1,396 +0,0 @@
"""Representation of Z-Wave binary_sensors."""
from openzwavemqtt.const import CommandClass, ValueIndex, ValueType
from homeassistant.components.binary_sensor import (
DOMAIN as BINARY_SENSOR_DOMAIN,
BinarySensorDeviceClass,
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 .const import DATA_UNSUBSCRIBE, DOMAIN
from .entity import ZWaveDeviceEntity
NOTIFICATION_TYPE = "index"
NOTIFICATION_VALUES = "values"
NOTIFICATION_DEVICE_CLASS = "device_class"
NOTIFICATION_SENSOR_ENABLED = "enabled"
NOTIFICATION_OFF_VALUE = "off_value"
NOTIFICATION_VALUE_CLEAR = 0
# Translation from values in Notification CC to binary sensors
# https://github.com/OpenZWave/open-zwave/blob/master/config/NotificationCCTypes.xml
NOTIFICATION_SENSORS = [
{
# Index 1: Smoke Alarm - Value Id's 1 and 2
# Assuming here that Value 1 and 2 are not present at the same time
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_SMOKE_ALARM,
NOTIFICATION_VALUES: [1, 2],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.SMOKE,
},
{
# Index 1: Smoke Alarm - All other Value Id's
# Create as disabled sensors
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_SMOKE_ALARM,
NOTIFICATION_VALUES: [3, 4, 5, 6, 7, 8],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.SMOKE,
NOTIFICATION_SENSOR_ENABLED: False,
},
{
# Index 2: Carbon Monoxide - Value Id's 1 and 2
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CARBON_MONOOXIDE,
NOTIFICATION_VALUES: [1, 2],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.GAS,
},
{
# Index 2: Carbon Monoxide - All other Value Id's
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CARBON_MONOOXIDE,
NOTIFICATION_VALUES: [4, 5, 7],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.GAS,
NOTIFICATION_SENSOR_ENABLED: False,
},
{
# Index 3: Carbon Dioxide - Value Id's 1 and 2
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CARBON_DIOXIDE,
NOTIFICATION_VALUES: [1, 2],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.GAS,
},
{
# Index 3: Carbon Dioxide - All other Value Id's
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CARBON_DIOXIDE,
NOTIFICATION_VALUES: [4, 5, 7],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.GAS,
NOTIFICATION_SENSOR_ENABLED: False,
},
{
# Index 4: Heat - Value Id's 1, 2, 5, 6 (heat/underheat)
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HEAT,
NOTIFICATION_VALUES: [1, 2, 5, 6],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.HEAT,
},
{
# Index 4: Heat - All other Value Id's
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HEAT,
NOTIFICATION_VALUES: [3, 4, 8, 10, 11],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.HEAT,
NOTIFICATION_SENSOR_ENABLED: False,
},
{
# Index 5: Water - Value Id's 1, 2, 3, 4
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_WATER,
NOTIFICATION_VALUES: [1, 2, 3, 4],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.MOISTURE,
},
{
# Index 5: Water - All other Value Id's
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_WATER,
NOTIFICATION_VALUES: [5],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.MOISTURE,
NOTIFICATION_SENSOR_ENABLED: False,
},
{
# Index 6: Access Control - Value Id's 1, 2, 3, 4 (Lock)
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_ACCESS_CONTROL,
NOTIFICATION_VALUES: [1, 2, 3, 4],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.LOCK,
},
{
# Index 6: Access Control - Value Id 22 (door/window open)
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_ACCESS_CONTROL,
NOTIFICATION_VALUES: [22],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.DOOR,
NOTIFICATION_OFF_VALUE: 23,
},
{
# Index 7: Home Security - Value Id's 1, 2 (intrusion)
# Assuming that value 1 and 2 are not present at the same time
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HOME_SECURITY,
NOTIFICATION_VALUES: [1, 2],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.SAFETY,
},
{
# Index 7: Home Security - Value Id's 3, 4, 9 (tampering)
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HOME_SECURITY,
NOTIFICATION_VALUES: [3, 4, 9],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.SAFETY,
},
{
# Index 7: Home Security - Value Id's 5, 6 (glass breakage)
# Assuming that value 5 and 6 are not present at the same time
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HOME_SECURITY,
NOTIFICATION_VALUES: [5, 6],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.SAFETY,
},
{
# Index 7: Home Security - Value Id's 7, 8 (motion)
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HOME_SECURITY,
NOTIFICATION_VALUES: [7, 8],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.MOTION,
},
{
# Index 8: Power management - Values 1...9
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_POWER_MANAGEMENT,
NOTIFICATION_VALUES: [1, 2, 3, 4, 5, 6, 7, 8, 9],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.POWER,
NOTIFICATION_SENSOR_ENABLED: False,
},
{
# Index 8: Power management - Values 10...15
# Battery values (mutually exclusive)
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_POWER_MANAGEMENT,
NOTIFICATION_VALUES: [10, 11, 12, 13, 14, 15],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.POWER,
NOTIFICATION_SENSOR_ENABLED: False,
NOTIFICATION_OFF_VALUE: None,
},
{
# Index 9: System - Value Id's 1, 2, 6, 7
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_SYSTEM,
NOTIFICATION_VALUES: [1, 2, 6, 7],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.PROBLEM,
NOTIFICATION_SENSOR_ENABLED: False,
},
{
# Index 10: Emergency - Value Id's 1, 2, 3
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_EMERGENCY,
NOTIFICATION_VALUES: [1, 2, 3],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.PROBLEM,
},
{
# Index 11: Clock - Value Id's 1, 2
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CLOCK,
NOTIFICATION_VALUES: [1, 2],
NOTIFICATION_DEVICE_CLASS: None,
NOTIFICATION_SENSOR_ENABLED: False,
},
{
# Index 12: Appliance - All Value Id's
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_APPLIANCE,
NOTIFICATION_VALUES: [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
],
NOTIFICATION_DEVICE_CLASS: None,
},
{
# Index 13: Home Health - Value Id's 1,2,3,4,5
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_APPLIANCE,
NOTIFICATION_VALUES: [1, 2, 3, 4, 5],
NOTIFICATION_DEVICE_CLASS: None,
},
{
# Index 14: Siren
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_SIREN,
NOTIFICATION_VALUES: [1],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.SOUND,
},
{
# Index 15: Water valve
# ignore non-boolean values
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_WATER_VALVE,
NOTIFICATION_VALUES: [3, 4],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.PROBLEM,
},
{
# Index 16: Weather
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_WEATHER,
NOTIFICATION_VALUES: [1, 2],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.PROBLEM,
},
{
# Index 17: Irrigation
# ignore non-boolean values
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_IRRIGATION,
NOTIFICATION_VALUES: [1, 2, 3, 4, 5],
NOTIFICATION_DEVICE_CLASS: None,
},
{
# Index 18: Gas
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_GAS,
NOTIFICATION_VALUES: [1, 2, 3, 4],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.GAS,
},
{
# Index 18: Gas
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_GAS,
NOTIFICATION_VALUES: [6],
NOTIFICATION_DEVICE_CLASS: BinarySensorDeviceClass.PROBLEM,
},
]
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave binary_sensor from config entry."""
@callback
def async_add_binary_sensor(values):
"""Add Z-Wave Binary Sensor(s)."""
async_add_entities(VALUE_TYPE_SENSORS[values.primary.type](values))
hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append(
async_dispatcher_connect(
hass, f"{DOMAIN}_new_{BINARY_SENSOR_DOMAIN}", async_add_binary_sensor
)
)
@callback
def async_get_legacy_binary_sensors(values):
"""Add Legacy/classic Z-Wave Binary Sensor."""
return [ZWaveBinarySensor(values)]
@callback
def async_get_notification_sensors(values):
"""Convert Notification values into binary sensors."""
sensors_to_add = []
for list_value in values.primary.value["List"]:
# check if we have a mapping for this value
for item in NOTIFICATION_SENSORS:
if item[NOTIFICATION_TYPE] != values.primary.index:
continue
if list_value["Value"] not in item[NOTIFICATION_VALUES]:
continue
sensors_to_add.append(
ZWaveListValueSensor(
# required values
values,
list_value["Value"],
item[NOTIFICATION_DEVICE_CLASS],
# optional values
item.get(NOTIFICATION_SENSOR_ENABLED, True),
item.get(NOTIFICATION_OFF_VALUE, NOTIFICATION_VALUE_CLEAR),
)
)
return sensors_to_add
VALUE_TYPE_SENSORS = {
ValueType.BOOL: async_get_legacy_binary_sensors,
ValueType.LIST: async_get_notification_sensors,
}
class ZWaveBinarySensor(ZWaveDeviceEntity, BinarySensorEntity):
"""Representation of a Z-Wave binary_sensor."""
@property
def is_on(self):
"""Return if the sensor is on or off."""
return self.values.primary.value
@property
def entity_registry_enabled_default(self) -> bool:
"""Return if the entity should be enabled when first added to the entity registry."""
# Legacy binary sensors are phased out (replaced by notification sensors)
# Disable by default to not confuse users
for item in self.values.primary.node.values():
if item.command_class == CommandClass.NOTIFICATION:
# This device properly implements the Notification CC, legacy sensor can be disabled
return False
return True
class ZWaveListValueSensor(ZWaveDeviceEntity, BinarySensorEntity):
"""Representation of a binary_sensor from values in the Z-Wave Notification CommandClass."""
def __init__(
self,
values,
on_value,
device_class=None,
default_enabled=True,
off_value=NOTIFICATION_VALUE_CLEAR,
):
"""Initialize a ZWaveListValueSensor entity."""
super().__init__(values)
self._on_value = on_value
self._device_class = device_class
self._default_enabled = default_enabled
self._off_value = off_value
# make sure the correct value is selected at startup
self._state = False
self.on_value_update()
@callback
def on_value_update(self):
"""Call when a value is added/updated in the underlying EntityValues Collection."""
if self.values.primary.value["Selected_id"] == self._on_value:
# Only when the active ID exactly matches our watched ON value, set sensor state to ON
self._state = True
elif self.values.primary.value["Selected_id"] == self._off_value:
# Only when the active ID exactly matches our watched OFF value, set sensor state to OFF
self._state = False
elif (
self._off_value is None
and self.values.primary.value["Selected_id"] != self._on_value
):
# Off value not explicitly specified
# Some values are reset by the simple fact they're overruled by another value coming in
# For example the battery charging values in Power Management Index
self._state = False
@property
def name(self):
"""Return the name of the entity."""
# Append value label to base name
base_name = super().name
value_label = ""
for item in self.values.primary.value["List"]:
if item["Value"] == self._on_value:
value_label = item["Label"]
break
# Strip "on location" / "at location" from name
# Note: We're assuming that we don't retrieve 2 values with different location
value_label = value_label.split(" on ")[0]
value_label = value_label.split(" at ")[0]
return f"{base_name}: {value_label}"
@property
def unique_id(self):
"""Return the unique_id of the entity."""
unique_id = super().unique_id
return f"{unique_id}.{self._on_value}"
@property
def is_on(self):
"""Return if the sensor is on or off."""
return self._state
@property
def device_class(self):
"""Return the class of this device, from component DEVICE_CLASSES."""
return self._device_class
@property
def entity_registry_enabled_default(self) -> bool:
"""Return if the entity should be enabled when first added to the entity registry."""
# We hide the more advanced sensors by default to not overwhelm users
return self._default_enabled

View File

@ -1,379 +0,0 @@
"""Support for Z-Wave climate devices."""
from __future__ import annotations
from enum import IntEnum
import logging
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN, ClimateEntity
from homeassistant.components.climate.const import (
ATTR_HVAC_MODE,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
CURRENT_HVAC_COOL,
CURRENT_HVAC_FAN,
CURRENT_HVAC_HEAT,
CURRENT_HVAC_IDLE,
CURRENT_HVAC_OFF,
HVAC_MODE_COOL,
HVAC_MODE_DRY,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_HEAT,
HVAC_MODE_HEAT_COOL,
HVAC_MODE_OFF,
PRESET_NONE,
SUPPORT_FAN_MODE,
SUPPORT_PRESET_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 .const import DATA_UNSUBSCRIBE, DOMAIN
from .entity import ZWaveDeviceEntity
VALUE_LIST = "List"
VALUE_ID = "Value"
VALUE_LABEL = "Label"
VALUE_SELECTED_ID = "Selected_id"
VALUE_SELECTED_LABEL = "Selected"
ATTR_FAN_ACTION = "fan_action"
ATTR_VALVE_POSITION = "valve_position"
_LOGGER = logging.getLogger(__name__)
class ThermostatMode(IntEnum):
"""Enum with all (known/used) Z-Wave ThermostatModes."""
# https://github.com/OpenZWave/open-zwave/blob/master/cpp/src/command_classes/ThermostatMode.cpp
OFF = 0
HEAT = 1
COOL = 2
AUTO = 3
AUXILIARY = 4
RESUME_ON = 5
FAN = 6
FURNANCE = 7
DRY = 8
MOIST = 9
AUTO_CHANGE_OVER = 10
HEATING_ECON = 11
COOLING_ECON = 12
AWAY = 13
FULL_POWER = 15
MANUFACTURER_SPECIFIC = 31
# In Z-Wave the modes and presets are both in ThermostatMode.
# This list contains thermostatmodes we should consider a mode only
MODES_LIST = [
ThermostatMode.OFF,
ThermostatMode.HEAT,
ThermostatMode.COOL,
ThermostatMode.AUTO,
ThermostatMode.AUTO_CHANGE_OVER,
]
MODE_SETPOINT_MAPPINGS = {
ThermostatMode.OFF: (),
ThermostatMode.HEAT: ("setpoint_heating",),
ThermostatMode.COOL: ("setpoint_cooling",),
ThermostatMode.AUTO: ("setpoint_heating", "setpoint_cooling"),
ThermostatMode.AUXILIARY: ("setpoint_heating",),
ThermostatMode.FURNANCE: ("setpoint_furnace",),
ThermostatMode.DRY: ("setpoint_dry_air",),
ThermostatMode.MOIST: ("setpoint_moist_air",),
ThermostatMode.AUTO_CHANGE_OVER: ("setpoint_auto_changeover",),
ThermostatMode.HEATING_ECON: ("setpoint_eco_heating",),
ThermostatMode.COOLING_ECON: ("setpoint_eco_cooling",),
ThermostatMode.AWAY: ("setpoint_away_heating", "setpoint_away_cooling"),
ThermostatMode.FULL_POWER: ("setpoint_full_power",),
}
# strings, OZW and/or qt-ozw does not send numeric values
# https://github.com/OpenZWave/open-zwave/blob/master/cpp/src/command_classes/ThermostatOperatingState.cpp
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,
}
# Map Z-Wave HVAC Mode to Home Assistant value
# Note: We treat "auto" as "heat_cool" as most Z-Wave devices
# report auto_changeover as auto without schedule support.
ZW_HVAC_MODE_MAPPINGS = {
ThermostatMode.OFF: HVAC_MODE_OFF,
ThermostatMode.HEAT: HVAC_MODE_HEAT,
ThermostatMode.COOL: HVAC_MODE_COOL,
# Z-Wave auto mode is actually heat/cool in the hass world
ThermostatMode.AUTO: HVAC_MODE_HEAT_COOL,
ThermostatMode.AUXILIARY: HVAC_MODE_HEAT,
ThermostatMode.FAN: HVAC_MODE_FAN_ONLY,
ThermostatMode.FURNANCE: HVAC_MODE_HEAT,
ThermostatMode.DRY: HVAC_MODE_DRY,
ThermostatMode.AUTO_CHANGE_OVER: HVAC_MODE_HEAT_COOL,
ThermostatMode.HEATING_ECON: HVAC_MODE_HEAT,
ThermostatMode.COOLING_ECON: HVAC_MODE_COOL,
ThermostatMode.AWAY: HVAC_MODE_HEAT_COOL,
ThermostatMode.FULL_POWER: HVAC_MODE_HEAT,
}
# Map Home Assistant HVAC Mode to Z-Wave value
HVAC_MODE_ZW_MAPPINGS = {
HVAC_MODE_OFF: ThermostatMode.OFF,
HVAC_MODE_HEAT: ThermostatMode.HEAT,
HVAC_MODE_COOL: ThermostatMode.COOL,
HVAC_MODE_FAN_ONLY: ThermostatMode.FAN,
HVAC_MODE_DRY: ThermostatMode.DRY,
HVAC_MODE_HEAT_COOL: ThermostatMode.AUTO_CHANGE_OVER,
}
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Z-Wave Climate from Config Entry."""
@callback
def async_add_climate(values):
"""Add Z-Wave Climate."""
async_add_entities([ZWaveClimateEntity(values)])
hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append(
async_dispatcher_connect(
hass, f"{DOMAIN}_new_{CLIMATE_DOMAIN}", async_add_climate
)
)
class ZWaveClimateEntity(ZWaveDeviceEntity, ClimateEntity):
"""Representation of a Z-Wave Climate device."""
def __init__(self, values):
"""Initialize the entity."""
super().__init__(values)
self._hvac_modes = {}
self._hvac_presets = {}
self.on_value_update()
@callback
def on_value_update(self):
"""Call when the underlying values object changes."""
self._current_mode_setpoint_values = self._get_current_mode_setpoint_values()
if not self._hvac_modes:
self._set_modes_and_presets()
@property
def hvac_mode(self):
"""Return hvac operation ie. heat, cool mode."""
if not self.values.mode:
# Thermostat(valve) with no support for setting a mode is considered heating-only
return HVAC_MODE_HEAT
return ZW_HVAC_MODE_MAPPINGS.get(
self.values.mode.value[VALUE_SELECTED_ID], HVAC_MODE_HEAT_COOL
)
@property
def hvac_modes(self):
"""Return the list of available hvac operation modes."""
return list(self._hvac_modes)
@property
def fan_mode(self):
"""Return the fan speed set."""
return self.values.fan_mode.value[VALUE_SELECTED_LABEL]
@property
def fan_modes(self):
"""Return a list of available fan modes."""
return [entry[VALUE_LABEL] for entry in self.values.fan_mode.value[VALUE_LIST]]
@property
def temperature_unit(self):
"""Return the unit of measurement."""
if self.values.temperature is not None and self.values.temperature.units == "F":
return TEMP_FAHRENHEIT
return TEMP_CELSIUS
@property
def current_temperature(self):
"""Return the current temperature."""
if not self.values.temperature:
return None
return self.values.temperature.value
@property
def hvac_action(self):
"""Return the current running hvac operation if supported."""
if not self.values.operating_state:
return None
cur_state = self.values.operating_state.value.lower()
return HVAC_CURRENT_MAPPINGS.get(cur_state)
@property
def preset_mode(self):
"""Return preset operation ie. eco, away."""
# A Zwave mode that can not be translated to a hass mode is considered a preset
if not self.values.mode:
return None
if self.values.mode.value[VALUE_SELECTED_ID] not in MODES_LIST:
return self.values.mode.value[VALUE_SELECTED_LABEL]
return PRESET_NONE
@property
def preset_modes(self):
"""Return the list of available preset operation modes."""
return list(self._hvac_presets)
@property
def target_temperature(self):
"""Return the temperature we try to reach."""
return self._current_mode_setpoint_values[0].value
@property
def target_temperature_low(self) -> float | None:
"""Return the lowbound target temperature we try to reach."""
return self._current_mode_setpoint_values[0].value
@property
def target_temperature_high(self) -> float | None:
"""Return the highbound target temperature we try to reach."""
return self._current_mode_setpoint_values[1].value
async def async_set_temperature(self, **kwargs):
"""Set new target temperature.
Must know if single or double setpoint.
"""
if (hvac_mode := kwargs.get(ATTR_HVAC_MODE)) is not None:
await self.async_set_hvac_mode(hvac_mode)
if len(self._current_mode_setpoint_values) == 1:
setpoint = self._current_mode_setpoint_values[0]
target_temp = kwargs.get(ATTR_TEMPERATURE)
if setpoint is not None and target_temp is not None:
setpoint.send_value(target_temp)
elif len(self._current_mode_setpoint_values) == 2:
(setpoint_low, setpoint_high) = self._current_mode_setpoint_values
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:
setpoint_low.send_value(target_temp_low)
if setpoint_high is not None and target_temp_high is not None:
setpoint_high.send_value(target_temp_high)
async def async_set_fan_mode(self, fan_mode):
"""Set new target fan mode."""
# get id for this fan_mode
fan_mode_value = _get_list_id(self.values.fan_mode.value[VALUE_LIST], fan_mode)
if fan_mode_value is None:
_LOGGER.warning("Received an invalid fan mode: %s", fan_mode)
return
self.values.fan_mode.send_value(fan_mode_value)
async def async_set_hvac_mode(self, hvac_mode):
"""Set new target hvac mode."""
if not self.values.mode:
# Thermostat(valve) with no support for setting a mode
_LOGGER.warning(
"Thermostat %s does not support setting a mode", self.entity_id
)
return
if (hvac_mode_value := self._hvac_modes.get(hvac_mode)) is None:
_LOGGER.warning("Received an invalid hvac mode: %s", hvac_mode)
return
self.values.mode.send_value(hvac_mode_value)
async def async_set_preset_mode(self, preset_mode):
"""Set new target preset mode."""
if preset_mode == PRESET_NONE:
# try to restore to the (translated) main hvac mode
await self.async_set_hvac_mode(self.hvac_mode)
return
preset_mode_value = self._hvac_presets.get(preset_mode)
if preset_mode_value is None:
_LOGGER.warning("Received an invalid preset mode: %s", preset_mode)
return
self.values.mode.send_value(preset_mode_value)
@property
def extra_state_attributes(self):
"""Return the optional state attributes."""
data = super().extra_state_attributes
if self.values.fan_action:
data[ATTR_FAN_ACTION] = self.values.fan_action.value
if self.values.valve_position:
data[
ATTR_VALVE_POSITION
] = f"{self.values.valve_position.value} {self.values.valve_position.units}"
return data
@property
def supported_features(self):
"""Return the list of supported features."""
support = 0
if len(self._current_mode_setpoint_values) == 1:
support |= SUPPORT_TARGET_TEMPERATURE
if len(self._current_mode_setpoint_values) > 1:
support |= SUPPORT_TARGET_TEMPERATURE_RANGE
if self.values.fan_mode:
support |= SUPPORT_FAN_MODE
if self.values.mode:
support |= SUPPORT_PRESET_MODE
return support
def _get_current_mode_setpoint_values(self) -> tuple:
"""Return a tuple of current setpoint Z-Wave value(s)."""
if not self.values.mode:
setpoint_names = ("setpoint_heating",)
else:
current_mode = self.values.mode.value[VALUE_SELECTED_ID]
setpoint_names = MODE_SETPOINT_MAPPINGS.get(current_mode, ())
# we do not want None values in our tuple so check if the value exists
return tuple(
getattr(self.values, value_name)
for value_name in setpoint_names
if getattr(self.values, value_name, None)
)
def _set_modes_and_presets(self):
"""Convert Z-Wave Thermostat modes into Home Assistant modes and presets."""
all_modes = {}
all_presets = {PRESET_NONE: None}
if self.values.mode:
# Z-Wave uses one list for both modes and presets.
# Iterate over all Z-Wave ThermostatModes and extract the hvac modes and presets.
for val in self.values.mode.value[VALUE_LIST]:
if val[VALUE_ID] in MODES_LIST:
# treat value as hvac mode
hass_mode = ZW_HVAC_MODE_MAPPINGS.get(val[VALUE_ID])
all_modes[hass_mode] = val[VALUE_ID]
else:
# treat value as hvac preset
all_presets[val[VALUE_LABEL]] = val[VALUE_ID]
else:
all_modes[HVAC_MODE_HEAT] = None
self._hvac_modes = all_modes
self._hvac_presets = all_presets
def _get_list_id(value_lst, value_lbl):
"""Return the id for the value in the list."""
return next(
(val[VALUE_ID] for val in value_lst if val[VALUE_LABEL] == value_lbl), None
)

View File

@ -1,228 +0,0 @@
"""Config flow for ozw integration."""
import logging
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components import hassio
from homeassistant.components.hassio import HassioServiceInfo
from homeassistant.core import callback
from homeassistant.data_entry_flow import AbortFlow, FlowResult
from .const import CONF_INTEGRATION_CREATED_ADDON, CONF_USE_ADDON, DOMAIN
_LOGGER = logging.getLogger(__name__)
CONF_ADDON_DEVICE = "device"
CONF_ADDON_NETWORK_KEY = "network_key"
CONF_NETWORK_KEY = "network_key"
CONF_USB_PATH = "usb_path"
TITLE = "OpenZWave"
ON_SUPERVISOR_SCHEMA = vol.Schema({vol.Optional(CONF_USE_ADDON, default=False): bool})
class DomainConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for ozw."""
VERSION = 1
def __init__(self):
"""Set up flow instance."""
self.addon_config = None
self.network_key = None
self.usb_path = None
self.use_addon = False
# If we install the add-on we should uninstall it on entry remove.
self.integration_created_addon = False
self.install_task = None
async def async_step_user(self, user_input=None):
"""Handle the initial step."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
# Set a unique_id to make sure discovery flow is aborted on progress.
await self.async_set_unique_id(DOMAIN, raise_on_progress=False)
if not hassio.is_hassio(self.hass):
return self._async_use_mqtt_integration()
return await self.async_step_on_supervisor()
async def async_step_hassio(self, discovery_info: HassioServiceInfo) -> FlowResult:
"""Receive configuration from add-on discovery info.
This flow is triggered by the OpenZWave add-on.
"""
await self.async_set_unique_id(DOMAIN)
self._abort_if_unique_id_configured()
return await self.async_step_hassio_confirm()
async def async_step_hassio_confirm(self, user_input=None):
"""Confirm the add-on discovery."""
if user_input is not None:
return await self.async_step_on_supervisor(
user_input={CONF_USE_ADDON: True}
)
return self.async_show_form(step_id="hassio_confirm")
def _async_create_entry_from_vars(self):
"""Return a config entry for the flow."""
return self.async_create_entry(
title=TITLE,
data={
CONF_USB_PATH: self.usb_path,
CONF_NETWORK_KEY: self.network_key,
CONF_USE_ADDON: self.use_addon,
CONF_INTEGRATION_CREATED_ADDON: self.integration_created_addon,
},
)
@callback
def _async_use_mqtt_integration(self):
"""Handle logic when using the MQTT integration.
This is the entry point for the logic that is needed
when this integration will depend on the MQTT integration.
"""
mqtt_entries = self.hass.config_entries.async_entries("mqtt")
if (
not mqtt_entries
or mqtt_entries[0].state is not config_entries.ConfigEntryState.LOADED
):
return self.async_abort(reason="mqtt_required")
return self._async_create_entry_from_vars()
async def async_step_on_supervisor(self, user_input=None):
"""Handle logic when on Supervisor host."""
if user_input is None:
return self.async_show_form(
step_id="on_supervisor", data_schema=ON_SUPERVISOR_SCHEMA
)
if not user_input[CONF_USE_ADDON]:
return self._async_create_entry_from_vars()
self.use_addon = True
if await self._async_is_addon_running():
addon_config = await self._async_get_addon_config()
self.usb_path = addon_config[CONF_ADDON_DEVICE]
self.network_key = addon_config.get(CONF_ADDON_NETWORK_KEY, "")
return self._async_create_entry_from_vars()
if await self._async_is_addon_installed():
return await self.async_step_start_addon()
return await self.async_step_install_addon()
async def async_step_install_addon(self, user_input=None):
"""Install OpenZWave add-on."""
if not self.install_task:
self.install_task = self.hass.async_create_task(self._async_install_addon())
return self.async_show_progress(
step_id="install_addon", progress_action="install_addon"
)
try:
await self.install_task
except hassio.HassioAPIError as err:
_LOGGER.error("Failed to install OpenZWave add-on: %s", err)
return self.async_show_progress_done(next_step_id="install_failed")
self.integration_created_addon = True
return self.async_show_progress_done(next_step_id="start_addon")
async def async_step_install_failed(self, user_input=None):
"""Add-on installation failed."""
return self.async_abort(reason="addon_install_failed")
async def async_step_start_addon(self, user_input=None):
"""Ask for config and start OpenZWave add-on."""
if self.addon_config is None:
self.addon_config = await self._async_get_addon_config()
errors = {}
if user_input is not None:
self.network_key = user_input[CONF_NETWORK_KEY]
self.usb_path = user_input[CONF_USB_PATH]
new_addon_config = {
CONF_ADDON_DEVICE: self.usb_path,
CONF_ADDON_NETWORK_KEY: self.network_key,
}
if new_addon_config != self.addon_config:
await self._async_set_addon_config(new_addon_config)
try:
await hassio.async_start_addon(self.hass, "core_zwave")
except hassio.HassioAPIError as err:
_LOGGER.error("Failed to start OpenZWave add-on: %s", err)
errors["base"] = "addon_start_failed"
else:
return self._async_create_entry_from_vars()
usb_path = self.addon_config.get(CONF_ADDON_DEVICE, self.usb_path or "")
network_key = self.addon_config.get(
CONF_ADDON_NETWORK_KEY, self.network_key or ""
)
data_schema = vol.Schema(
{
vol.Required(CONF_USB_PATH, default=usb_path): str,
vol.Optional(CONF_NETWORK_KEY, default=network_key): str,
}
)
return self.async_show_form(
step_id="start_addon", data_schema=data_schema, errors=errors
)
async def _async_get_addon_info(self):
"""Return and cache OpenZWave add-on info."""
try:
addon_info = await hassio.async_get_addon_info(self.hass, "core_zwave")
except hassio.HassioAPIError as err:
_LOGGER.error("Failed to get OpenZWave add-on info: %s", err)
raise AbortFlow("addon_info_failed") from err
return addon_info
async def _async_is_addon_running(self):
"""Return True if OpenZWave add-on is running."""
addon_info = await self._async_get_addon_info()
return addon_info["state"] == "started"
async def _async_is_addon_installed(self):
"""Return True if OpenZWave add-on is installed."""
addon_info = await self._async_get_addon_info()
return addon_info["version"] is not None
async def _async_get_addon_config(self):
"""Get OpenZWave add-on config."""
addon_info = await self._async_get_addon_info()
return addon_info["options"]
async def _async_set_addon_config(self, config):
"""Set OpenZWave add-on config."""
options = {"options": config}
try:
await hassio.async_set_addon_options(self.hass, "core_zwave", options)
except hassio.HassioAPIError as err:
_LOGGER.error("Failed to set OpenZWave add-on config: %s", err)
raise AbortFlow("addon_set_config_failed") from err
async def _async_install_addon(self):
"""Install the OpenZWave add-on."""
try:
await hassio.async_install_addon(self.hass, "core_zwave")
finally:
# Continue the flow after show progress when the task is done.
self.hass.async_create_task(
self.hass.config_entries.flow.async_configure(flow_id=self.flow_id)
)

View File

@ -1,71 +0,0 @@
"""Constants for the ozw integration."""
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN
from homeassistant.components.cover import DOMAIN as COVER_DOMAIN
from homeassistant.components.fan import DOMAIN as FAN_DOMAIN
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
DOMAIN = "ozw"
DATA_UNSUBSCRIBE = "unsubscribe"
CONF_INTEGRATION_CREATED_ADDON = "integration_created_addon"
CONF_USE_ADDON = "use_addon"
PLATFORMS = [
BINARY_SENSOR_DOMAIN,
COVER_DOMAIN,
CLIMATE_DOMAIN,
FAN_DOMAIN,
LIGHT_DOMAIN,
LOCK_DOMAIN,
SENSOR_DOMAIN,
SWITCH_DOMAIN,
]
MANAGER = "manager"
NODES_VALUES = "nodes_values"
# MQTT Topics
TOPIC_OPENZWAVE = "OpenZWave"
# Common Attributes
ATTR_CONFIG_PARAMETER = "parameter"
ATTR_CONFIG_VALUE = "value"
ATTR_INSTANCE_ID = "instance_id"
ATTR_SECURE = "secure"
ATTR_NODE_ID = "node_id"
ATTR_SCENE_ID = "scene_id"
ATTR_SCENE_LABEL = "scene_label"
ATTR_SCENE_VALUE_ID = "scene_value_id"
ATTR_SCENE_VALUE_LABEL = "scene_value_label"
# Config entry data and options
MIGRATED = "migrated"
# Service specific
SERVICE_ADD_NODE = "add_node"
SERVICE_REMOVE_NODE = "remove_node"
SERVICE_CANCEL_COMMAND = "cancel_command"
SERVICE_SET_CONFIG_PARAMETER = "set_config_parameter"
# Home Assistant Events
EVENT_SCENE_ACTIVATED = f"{DOMAIN}.scene_activated"
# Signals
SIGNAL_DELETE_ENTITY = f"{DOMAIN}_delete_entity"
# Discovery Information
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_SPECIFIC_DEVICE_CLASS = "specific_device_class"
DISC_TYPE = "type"
DISC_VALUES = "values"

View File

@ -1,127 +0,0 @@
"""Support for Z-Wave cover devices."""
from openzwavemqtt.const import CommandClass
from homeassistant.components.cover import (
ATTR_POSITION,
DOMAIN as COVER_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 .const import DATA_UNSUBSCRIBE, DOMAIN
from .entity import ZWaveDeviceEntity
SUPPORT_GARAGE = SUPPORT_OPEN | SUPPORT_CLOSE
VALUE_SELECTED_ID = "Selected_id"
PRESS_BUTTON = True
RELEASE_BUTTON = False
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(values):
"""Add Z-Wave Cover."""
if values.primary.command_class == CommandClass.BARRIER_OPERATOR:
cover = ZwaveGarageDoorBarrier(values)
else:
cover = ZWaveCoverEntity(values)
async_add_entities([cover])
hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append(
async_dispatcher_connect(hass, f"{DOMAIN}_new_{COVER_DOMAIN}", async_add_cover)
)
def percent_to_zwave_position(value):
"""Convert position in 0-100 scale to 0-99 scale.
`value` -- (int) Position byte value from 0-100.
"""
if value > 0:
return max(1, round((value / 100) * 99))
return 0
class ZWaveCoverEntity(ZWaveDeviceEntity, CoverEntity):
"""Representation of a Z-Wave Cover device."""
@property
def is_closed(self):
"""Return true if cover is closed."""
return self.values.primary.value == 0
@property
def current_cover_position(self):
"""Return the current position of cover where 0 means closed and 100 is fully open."""
return round((self.values.primary.value / 99) * 100)
async def async_set_cover_position(self, **kwargs):
"""Move the cover to a specific position."""
self.values.primary.send_value(percent_to_zwave_position(kwargs[ATTR_POSITION]))
async def async_open_cover(self, **kwargs):
"""Open the cover."""
self.values.open.send_value(PRESS_BUTTON)
async def async_close_cover(self, **kwargs):
"""Close cover."""
self.values.close.send_value(PRESS_BUTTON)
async def async_stop_cover(self, **kwargs):
"""Stop cover."""
# Need to issue both buttons release since qt-openzwave implements idempotency
# keeping internal state of model to trigger actual updates. We could also keep
# another state in Home Assistant to know which button to release,
# but this implementation is simpler.
self.values.open.send_value(RELEASE_BUTTON)
self.values.close.send_value(RELEASE_BUTTON)
class ZwaveGarageDoorBarrier(ZWaveDeviceEntity, CoverEntity):
"""Representation of a barrier operator Zwave garage door device."""
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_GARAGE
@property
def device_class(self):
"""Return the class of this device, from CoverDeviceClass."""
return CoverDeviceClass.GARAGE
@property
def is_opening(self):
"""Return true if cover is in an opening state."""
return self.values.primary.value[VALUE_SELECTED_ID] == 3
@property
def is_closing(self):
"""Return true if cover is in a closing state."""
return self.values.primary.value[VALUE_SELECTED_ID] == 1
@property
def is_closed(self):
"""Return the current position of Zwave garage door."""
return self.values.primary.value[VALUE_SELECTED_ID] == 0
async def async_close_cover(self, **kwargs):
"""Close the garage door."""
self.values.primary.send_value(0)
async def async_open_cover(self, **kwargs):
"""Open the garage door."""
self.values.primary.send_value(4)

View File

@ -1,356 +0,0 @@
"""Map Z-Wave nodes and values to Home Assistant entities."""
import openzwavemqtt.const as const_ozw
from openzwavemqtt.const import CommandClass, ValueGenre, ValueIndex, ValueType
from . import const
DISCOVERY_SCHEMAS = (
{ # Binary sensors
const.DISC_COMPONENT: "binary_sensor",
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: CommandClass.SENSOR_BINARY,
const.DISC_TYPE: ValueType.BOOL,
const.DISC_GENRE: ValueGenre.USER,
},
"off_delay": {
const.DISC_COMMAND_CLASS: CommandClass.CONFIGURATION,
const.DISC_INDEX: 9,
const.DISC_OPTIONAL: True,
},
},
},
{ # Notification CommandClass translates to binary_sensor
const.DISC_COMPONENT: "binary_sensor",
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: CommandClass.NOTIFICATION,
const.DISC_GENRE: ValueGenre.USER,
const.DISC_TYPE: (ValueType.BOOL, ValueType.LIST),
}
},
},
{ # Z-Wave Thermostat device translates to Climate entity
const.DISC_COMPONENT: "climate",
const.DISC_GENERIC_DEVICE_CLASS: (
const_ozw.GENERIC_TYPE_THERMOSTAT,
const_ozw.GENERIC_TYPE_SENSOR_MULTILEVEL,
),
const.DISC_SPECIFIC_DEVICE_CLASS: (
const_ozw.SPECIFIC_TYPE_THERMOSTAT_GENERAL,
const_ozw.SPECIFIC_TYPE_THERMOSTAT_GENERAL_V2,
const_ozw.SPECIFIC_TYPE_SETBACK_THERMOSTAT,
const_ozw.SPECIFIC_TYPE_THERMOSTAT_HEATING,
const_ozw.SPECIFIC_TYPE_SETPOINT_THERMOSTAT,
const_ozw.SPECIFIC_TYPE_NOT_USED,
),
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_MODE,)
},
"mode": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_MODE,),
const.DISC_OPTIONAL: True,
},
"temperature": {
const.DISC_COMMAND_CLASS: (CommandClass.SENSOR_MULTILEVEL,),
const.DISC_INDEX: (1,),
const.DISC_OPTIONAL: True,
},
"fan_mode": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_FAN_MODE,),
const.DISC_OPTIONAL: True,
},
"operating_state": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_OPERATING_STATE,),
const.DISC_OPTIONAL: True,
},
"fan_action": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_FAN_STATE,),
const.DISC_OPTIONAL: True,
},
"valve_position": {
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_MULTILEVEL,),
const.DISC_INDEX: (0,),
const.DISC_OPTIONAL: True,
},
"setpoint_heating": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (1,),
const.DISC_OPTIONAL: True,
},
"setpoint_cooling": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (2,),
const.DISC_OPTIONAL: True,
},
"setpoint_furnace": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (7,),
const.DISC_OPTIONAL: True,
},
"setpoint_dry_air": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (8,),
const.DISC_OPTIONAL: True,
},
"setpoint_moist_air": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (9,),
const.DISC_OPTIONAL: True,
},
"setpoint_auto_changeover": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (10,),
const.DISC_OPTIONAL: True,
},
"setpoint_eco_heating": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (11,),
const.DISC_OPTIONAL: True,
},
"setpoint_eco_cooling": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (12,),
const.DISC_OPTIONAL: True,
},
"setpoint_away_heating": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (13,),
const.DISC_OPTIONAL: True,
},
"setpoint_away_cooling": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (14,),
const.DISC_OPTIONAL: True,
},
"setpoint_full_power": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (15,),
const.DISC_OPTIONAL: True,
},
},
},
{ # Z-Wave Thermostat device without mode support
const.DISC_COMPONENT: "climate",
const.DISC_GENERIC_DEVICE_CLASS: (const_ozw.GENERIC_TYPE_THERMOSTAT,),
const.DISC_SPECIFIC_DEVICE_CLASS: (
const_ozw.SPECIFIC_TYPE_SETPOINT_THERMOSTAT,
const_ozw.SPECIFIC_TYPE_NOT_USED,
),
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,)
},
"temperature": {
const.DISC_COMMAND_CLASS: (CommandClass.SENSOR_MULTILEVEL,),
const.DISC_INDEX: (1,),
const.DISC_OPTIONAL: True,
},
"operating_state": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_OPERATING_STATE,),
const.DISC_OPTIONAL: True,
},
"valve_position": {
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_MULTILEVEL,),
const.DISC_INDEX: (0,),
const.DISC_OPTIONAL: True,
},
"setpoint_heating": {
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
const.DISC_INDEX: (1,),
const.DISC_OPTIONAL: True,
},
},
},
{ # Rollershutter
const.DISC_COMPONENT: "cover",
const.DISC_GENERIC_DEVICE_CLASS: (const_ozw.GENERIC_TYPE_SWITCH_MULTILEVEL,),
const.DISC_SPECIFIC_DEVICE_CLASS: (
const_ozw.SPECIFIC_TYPE_CLASS_A_MOTOR_CONTROL,
const_ozw.SPECIFIC_TYPE_CLASS_B_MOTOR_CONTROL,
const_ozw.SPECIFIC_TYPE_CLASS_C_MOTOR_CONTROL,
const_ozw.SPECIFIC_TYPE_MOTOR_MULTIPOSITION,
const_ozw.SPECIFIC_TYPE_SECURE_BARRIER_ADDON,
const_ozw.SPECIFIC_TYPE_SECURE_DOOR,
),
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: CommandClass.SWITCH_MULTILEVEL,
const.DISC_INDEX: ValueIndex.SWITCH_MULTILEVEL_LEVEL,
const.DISC_GENRE: ValueGenre.USER,
},
"open": {
const.DISC_COMMAND_CLASS: CommandClass.SWITCH_MULTILEVEL,
const.DISC_INDEX: ValueIndex.SWITCH_MULTILEVEL_BRIGHT,
const.DISC_OPTIONAL: True,
},
"close": {
const.DISC_COMMAND_CLASS: CommandClass.SWITCH_MULTILEVEL,
const.DISC_INDEX: ValueIndex.SWITCH_MULTILEVEL_DIM,
const.DISC_OPTIONAL: True,
},
},
},
{ # Garage Door Barrier
const.DISC_COMPONENT: "cover",
const.DISC_GENERIC_DEVICE_CLASS: (const_ozw.GENERIC_TYPE_ENTRY_CONTROL,),
const.DISC_SPECIFIC_DEVICE_CLASS: (
const_ozw.SPECIFIC_TYPE_SECURE_BARRIER_ADDON,
),
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: CommandClass.BARRIER_OPERATOR,
const.DISC_INDEX: ValueIndex.BARRIER_OPERATOR_LABEL,
},
},
},
{ # Fan
const.DISC_COMPONENT: "fan",
const.DISC_GENERIC_DEVICE_CLASS: const_ozw.GENERIC_TYPE_SWITCH_MULTILEVEL,
const.DISC_SPECIFIC_DEVICE_CLASS: const_ozw.SPECIFIC_TYPE_FAN_SWITCH,
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: CommandClass.SWITCH_MULTILEVEL,
const.DISC_INDEX: ValueIndex.SWITCH_MULTILEVEL_LEVEL,
const.DISC_TYPE: ValueType.BYTE,
},
},
},
{ # Light
const.DISC_COMPONENT: "light",
const.DISC_GENERIC_DEVICE_CLASS: (
const_ozw.GENERIC_TYPE_SWITCH_MULTILEVEL,
const_ozw.GENERIC_TYPE_SWITCH_REMOTE,
),
const.DISC_SPECIFIC_DEVICE_CLASS: (
const_ozw.SPECIFIC_TYPE_POWER_SWITCH_MULTILEVEL,
const_ozw.SPECIFIC_TYPE_SCENE_SWITCH_MULTILEVEL,
const_ozw.SPECIFIC_TYPE_COLOR_TUNABLE_BINARY,
const_ozw.SPECIFIC_TYPE_COLOR_TUNABLE_MULTILEVEL,
const_ozw.SPECIFIC_TYPE_NOT_USED,
),
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_MULTILEVEL,),
const.DISC_INDEX: ValueIndex.SWITCH_MULTILEVEL_LEVEL,
const.DISC_TYPE: ValueType.BYTE,
},
"dimming_duration": {
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_MULTILEVEL,),
const.DISC_INDEX: ValueIndex.SWITCH_MULTILEVEL_DURATION,
const.DISC_OPTIONAL: True,
},
"color": {
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_COLOR,),
const.DISC_INDEX: ValueIndex.SWITCH_COLOR_COLOR,
const.DISC_OPTIONAL: True,
},
"color_channels": {
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_COLOR,),
const.DISC_INDEX: ValueIndex.SWITCH_COLOR_CHANNELS,
const.DISC_OPTIONAL: True,
},
"min_kelvin": {
const.DISC_COMMAND_CLASS: (CommandClass.CONFIGURATION,),
const.DISC_INDEX: 81, # PR for upstream to add SWITCH_COLOR_CT_WARM
const.DISC_TYPE: ValueType.INT,
const.DISC_OPTIONAL: True,
},
"max_kelvin": {
const.DISC_COMMAND_CLASS: (CommandClass.CONFIGURATION,),
const.DISC_INDEX: 82, # PR for upstream to add SWITCH_COLOR_CT_COLD
const.DISC_TYPE: ValueType.INT,
const.DISC_OPTIONAL: True,
},
},
},
{ # All other text/numeric sensors
const.DISC_COMPONENT: "sensor",
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: (
CommandClass.SENSOR_MULTILEVEL,
CommandClass.METER,
CommandClass.ALARM,
CommandClass.SENSOR_ALARM,
CommandClass.INDICATOR,
CommandClass.BATTERY,
CommandClass.NOTIFICATION,
CommandClass.BASIC,
),
const.DISC_TYPE: (
ValueType.DECIMAL,
ValueType.INT,
ValueType.STRING,
ValueType.BYTE,
ValueType.LIST,
),
}
},
},
{ # Switch platform
const.DISC_COMPONENT: "switch",
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_BINARY,),
const.DISC_TYPE: ValueType.BOOL,
const.DISC_GENRE: ValueGenre.USER,
}
},
},
{ # Lock platform
const.DISC_COMPONENT: "lock",
const.DISC_VALUES: {
const.DISC_PRIMARY: {
const.DISC_COMMAND_CLASS: (CommandClass.DOOR_LOCK,),
const.DISC_TYPE: ValueType.BOOL,
const.DISC_GENRE: ValueGenre.USER,
}
},
},
)
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]:
return False
if const.DISC_GENERIC_DEVICE_CLASS in schema and not eq_or_in(
node.node_generic, schema[const.DISC_GENERIC_DEVICE_CLASS]
):
return False
if const.DISC_SPECIFIC_DEVICE_CLASS in schema and not eq_or_in(
node.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 not eq_or_in(
value.parent.command_class_id, schema[const.DISC_COMMAND_CLASS]
):
return False
if const.DISC_TYPE in schema and not eq_or_in(value.type, schema[const.DISC_TYPE]):
return False
if const.DISC_GENRE in schema and not eq_or_in(
value.genre, schema[const.DISC_GENRE]
):
return False
if const.DISC_INDEX in schema and not eq_or_in(
value.index, schema[const.DISC_INDEX]
):
return False
if const.DISC_INSTANCE in schema and not eq_or_in(
value.instance, schema[const.DISC_INSTANCE]
):
return False
return True
def eq_or_in(val, options):
"""Return True if options contains value or if value is equal to options."""
return val in options if isinstance(options, tuple) else val == options

View File

@ -1,304 +0,0 @@
"""Generic Z-Wave Entity Classes."""
import copy
import logging
from openzwavemqtt.const import (
EVENT_INSTANCE_STATUS_CHANGED,
EVENT_VALUE_CHANGED,
OZW_READY_STATES,
CommandClass,
ValueIndex,
)
from openzwavemqtt.models.node import OZWNode
from openzwavemqtt.models.value import OZWValue
from homeassistant.const import ATTR_NAME, ATTR_SW_VERSION, ATTR_VIA_DEVICE
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.entity import DeviceInfo, Entity
from . import const
from .const import DOMAIN, PLATFORMS
from .discovery import check_node_schema, check_value_schema
_LOGGER = logging.getLogger(__name__)
OZW_READY_STATES_VALUES = {st.value for st in OZW_READY_STATES}
class ZWaveDeviceEntityValues:
"""Manages entity access to the underlying Z-Wave value objects."""
def __init__(self, hass, options, schema, primary_value):
"""Initialize the values object with the passed entity schema."""
self._hass = hass
self._entity_created = False
self._schema = copy.deepcopy(schema)
self._values = {}
self.options = options
# Go through values listed in the discovery schema, initialize them,
# and add a check to the schema to make sure the Instance matches.
for name, disc_settings in self._schema[const.DISC_VALUES].items():
self._values[name] = None
disc_settings[const.DISC_INSTANCE] = (primary_value.instance,)
self._values[const.DISC_PRIMARY] = primary_value
self._node = primary_value.node
self._schema[const.DISC_NODE_ID] = [self._node.node_id]
def async_setup(self):
"""Set up values instance."""
# Check values that have already been discovered for node
# and see if they match the schema and need added to the entity.
for value in self._node.values():
self.async_check_value(value)
# Check if all the _required_ values in the schema are present and
# create the entity.
self._async_check_entity_ready()
def __getattr__(self, name):
"""Get the specified value for this entity."""
return self._values.get(name, None)
def __iter__(self):
"""Allow iteration over all values."""
return iter(self._values.values())
def __contains__(self, name):
"""Check if the specified name/key exists in the values."""
return name in self._values
@callback
def async_check_value(self, value):
"""Check if the new value matches a missing value for this entity.
If a match is found, it is added to the values mapping.
"""
# Make sure the node matches the schema for this entity.
if not check_node_schema(value.node, self._schema):
return
# Go through the possible values for this entity defined by the schema.
for name, name_value in self._values.items():
# Skip if it's already been added.
if name_value is not None:
continue
# Skip if the value doesn't match the schema.
if not check_value_schema(value, self._schema[const.DISC_VALUES][name]):
continue
# Add value to mapping.
self._values[name] = value
# If the entity has already been created, notify it of the new value.
if self._entity_created:
async_dispatcher_send(
self._hass, f"{DOMAIN}_{self.values_id}_value_added"
)
# Check if entity has all required values and create the entity if needed.
self._async_check_entity_ready()
@callback
def _async_check_entity_ready(self):
"""Check if all required values are discovered and create entity."""
# Abort if the entity has already been created
if self._entity_created:
return
# Go through values defined in the schema and abort if a required value is missing.
for name, disc_settings in self._schema[const.DISC_VALUES].items():
if self._values[name] is None and not disc_settings.get(
const.DISC_OPTIONAL
):
return
# We have all the required values, so create the entity.
component = self._schema[const.DISC_COMPONENT]
_LOGGER.debug(
"Adding Node_id=%s Generic_command_class=%s, "
"Specific_command_class=%s, "
"Command_class=%s, Index=%s, Value type=%s, "
"Genre=%s as %s",
self._node.node_id,
self._node.node_generic,
self._node.node_specific,
self.primary.command_class,
self.primary.index,
self.primary.type,
self.primary.genre,
component,
)
self._entity_created = True
if component in PLATFORMS:
async_dispatcher_send(self._hass, f"{DOMAIN}_new_{component}", self)
@property
def values_id(self):
"""Identification for this values collection."""
return create_value_id(self.primary)
class ZWaveDeviceEntity(Entity):
"""Generic Entity Class for a Z-Wave Device."""
def __init__(self, values):
"""Initialize a generic Z-Wave device entity."""
self.values = values
self.options = values.options
@callback
def on_value_update(self):
"""Call when a value is added/updated in the entity EntityValues Collection.
To be overridden by platforms needing this event.
"""
async def async_added_to_hass(self):
"""Call when entity is added."""
# Add dispatcher and OZW listeners callbacks.
# Add to on_remove so they will be cleaned up on entity removal.
self.async_on_remove(
self.options.listen(EVENT_VALUE_CHANGED, self._value_changed)
)
self.async_on_remove(
self.options.listen(EVENT_INSTANCE_STATUS_CHANGED, self._instance_updated)
)
self.async_on_remove(
async_dispatcher_connect(
self.hass, const.SIGNAL_DELETE_ENTITY, self._delete_callback
)
)
self.async_on_remove(
async_dispatcher_connect(
self.hass,
f"{DOMAIN}_{self.values.values_id}_value_added",
self._value_added,
)
)
@property
def device_info(self) -> DeviceInfo:
"""Return device information for the device registry."""
node = self.values.primary.node
node_instance = self.values.primary.instance
dev_id = create_device_id(node, self.values.primary.instance)
node_firmware = node.get_value(
CommandClass.VERSION, ValueIndex.VERSION_APPLICATION
)
device_info = DeviceInfo(
identifiers={(DOMAIN, dev_id)},
name=create_device_name(node),
manufacturer=node.node_manufacturer_name,
model=node.node_product_name,
)
if node_firmware is not None:
device_info[ATTR_SW_VERSION] = node_firmware.value
# device with multiple instances is split up into virtual devices for each instance
if node_instance > 1:
parent_dev_id = create_device_id(node)
device_info[ATTR_NAME] += f" - Instance {node_instance}"
device_info[ATTR_VIA_DEVICE] = (DOMAIN, parent_dev_id)
return device_info
@property
def extra_state_attributes(self):
"""Return the device specific state attributes."""
return {const.ATTR_NODE_ID: self.values.primary.node.node_id}
@property
def name(self):
"""Return the name of the entity."""
node = self.values.primary.node
return f"{create_device_name(node)}: {self.values.primary.label}"
@property
def unique_id(self):
"""Return the unique_id of the entity."""
return self.values.values_id
@property
def available(self) -> bool:
"""Return entity availability."""
# Use OZW Daemon status for availability.
instance_status = self.values.primary.ozw_instance.get_status()
return instance_status and instance_status.status in OZW_READY_STATES_VALUES
@callback
def _value_changed(self, value):
"""Call when a value from ZWaveDeviceEntityValues is changed.
Should not be overridden by subclasses.
"""
if value.value_id_key in (v.value_id_key for v in self.values if v):
self.on_value_update()
self.async_write_ha_state()
@callback
def _value_added(self):
"""Call when a value from ZWaveDeviceEntityValues is added.
Should not be overridden by subclasses.
"""
self.on_value_update()
@callback
def _instance_updated(self, new_status):
"""Call when the instance status changes.
Should not be overridden by subclasses.
"""
self.on_value_update()
self.async_write_ha_state()
@property
def should_poll(self):
"""No polling needed."""
return False
async def _delete_callback(self, values_id):
"""Remove this entity."""
if not self.values:
return # race condition: delete already requested
if values_id == self.values.values_id:
await self.async_remove(force_remove=True)
def create_device_name(node: OZWNode):
"""Generate sensible (short) default device name from a OZWNode."""
# Prefer custom name set by OZWAdmin if present
if node.node_name:
return node.node_name
# Prefer short devicename from metadata if present
if node.meta_data and node.meta_data.get("Name"):
return node.meta_data["Name"]
# Fallback to productname or devicetype strings
if node.node_product_name:
return node.node_product_name
if node.node_device_type_string:
return node.node_device_type_string
if node.node_specific_string:
return node.node_specific_string
# Last resort: use Node id (should never happen, but just in case)
return f"Node {node.id}"
def create_device_id(node: OZWNode, node_instance: int = 1):
"""Generate unique device_id from a OZWNode."""
ozw_instance = node.parent.id
dev_id = f"{ozw_instance}.{node.node_id}.{node_instance}"
return dev_id
def create_value_id(value: OZWValue):
"""Generate unique value_id from an OZWValue."""
# [OZW_INSTANCE_ID]-[NODE_ID]-[VALUE_ID_KEY]
return f"{value.node.parent.id}-{value.node.id}-{value.value_id_key}"

View File

@ -1,88 +0,0 @@
"""Support for Z-Wave fans."""
import math
from homeassistant.components.fan import (
DOMAIN as FAN_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 .const import DATA_UNSUBSCRIBE, DOMAIN
from .entity 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(values):
"""Add Z-Wave Fan."""
fan = ZwaveFan(values)
async_add_entities([fan])
hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append(
async_dispatcher_connect(hass, f"{DOMAIN}_new_{FAN_DOMAIN}", async_add_fan)
)
class ZwaveFan(ZWaveDeviceEntity, FanEntity):
"""Representation of a Z-Wave fan."""
async def async_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.values.primary.send_value(zwave_speed)
async def async_turn_on(self, percentage=None, preset_mode=None, **kwargs):
"""Turn the device on."""
await self.async_set_percentage(percentage)
async def async_turn_off(self, **kwargs):
"""Turn the device off."""
self.values.primary.send_value(0)
@property
def is_on(self):
"""Return true if device is on (speed above 0)."""
return self.values.primary.value > 0
@property
def percentage(self):
"""Return the current speed.
The Z-Wave speed value is a byte 0-255. 255 means previous value.
The normal range of the speed is 0-99. 0 means off.
"""
return ranged_value_to_percentage(SPEED_RANGE, self.values.primary.value)
@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,343 +0,0 @@
"""Support for Z-Wave lights."""
import logging
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_HS_COLOR,
ATTR_RGBW_COLOR,
ATTR_TRANSITION,
COLOR_MODE_BRIGHTNESS,
COLOR_MODE_COLOR_TEMP,
COLOR_MODE_HS,
COLOR_MODE_RGBW,
DOMAIN as LIGHT_DOMAIN,
SUPPORT_TRANSITION,
LightEntity,
)
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
import homeassistant.util.color as color_util
from .const import DATA_UNSUBSCRIBE, DOMAIN
from .entity import ZWaveDeviceEntity
_LOGGER = logging.getLogger(__name__)
ATTR_VALUE = "Value"
COLOR_CHANNEL_WARM_WHITE = 0x01
COLOR_CHANNEL_COLD_WHITE = 0x02
COLOR_CHANNEL_RED = 0x04
COLOR_CHANNEL_GREEN = 0x08
COLOR_CHANNEL_BLUE = 0x10
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(values):
"""Add Z-Wave Light."""
light = ZwaveLight(values)
async_add_entities([light])
hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append(
async_dispatcher_connect(hass, f"{DOMAIN}_new_{LIGHT_DOMAIN}", async_add_light)
)
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 ZwaveLight(ZWaveDeviceEntity, LightEntity):
"""Representation of a Z-Wave light."""
def __init__(self, values):
"""Initialize the light."""
super().__init__(values)
self._color_channels = None
self._hs = None
self._rgbw_color = None
self._ct = None
self._attr_color_mode = None
self._attr_supported_features = 0
self._attr_supported_color_modes = set()
self._min_mireds = 153 # 6500K as a safe default
self._max_mireds = 370 # 2700K as a safe default
# make sure that supported features is correctly set
self.on_value_update()
@callback
def on_value_update(self):
"""Call when the underlying value(s) is added or updated."""
if self.values.dimming_duration is not None:
self._attr_supported_features |= SUPPORT_TRANSITION
if self.values.color_channels is not None:
# Support Color Temp if both white channels
if (self.values.color_channels.value & COLOR_CHANNEL_WARM_WHITE) and (
self.values.color_channels.value & COLOR_CHANNEL_COLD_WHITE
):
self._attr_supported_color_modes.add(COLOR_MODE_COLOR_TEMP)
self._attr_supported_color_modes.add(COLOR_MODE_HS)
# Support White value if only a single white channel
if ((self.values.color_channels.value & COLOR_CHANNEL_WARM_WHITE) != 0) ^ (
(self.values.color_channels.value & COLOR_CHANNEL_COLD_WHITE) != 0
):
self._attr_supported_color_modes.add(COLOR_MODE_RGBW)
if not self._attr_supported_color_modes and self.values.color is not None:
self._attr_supported_color_modes.add(COLOR_MODE_HS)
if not self._attr_supported_color_modes:
self._attr_supported_color_modes.add(COLOR_MODE_BRIGHTNESS)
# Default: Brightness (no color)
self._attr_color_mode = COLOR_MODE_BRIGHTNESS
if self.values.color is not None:
self._calculate_color_values()
@property
def brightness(self):
"""Return the brightness of this light between 0..255.
Zwave multilevel switches use a range of [0, 99] to control brightness.
"""
if "target" in self.values:
return round((self.values.target.value / 99) * 255)
return round((self.values.primary.value / 99) * 255)
@property
def is_on(self):
"""Return true if device is on (brightness above 0)."""
if "target" in self.values:
return self.values.target.value > 0
return self.values.primary.value > 0
@property
def hs_color(self):
"""Return the hs color."""
return self._hs
@property
def rgbw_color(self):
"""Return the rgbw color."""
return self._rgbw_color
@property
def color_temp(self):
"""Return the color temperature."""
return self._ct
@property
def min_mireds(self):
"""Return the coldest color_temp that this light supports."""
return self._min_mireds
@property
def max_mireds(self):
"""Return the warmest color_temp that this light supports."""
return self._max_mireds
@callback
def async_set_duration(self, **kwargs):
"""Set the transition time for the brightness value.
Zwave Dimming Duration values now use seconds as an
integer (max: 7620 seconds or 127 mins)
Build 1205 https://github.com/OpenZWave/open-zwave/commit/f81bc04
"""
if self.values.dimming_duration is None:
return
ozw_version = tuple(
int(x)
for x in self.values.primary.ozw_instance.get_status().openzwave_version.split(
"."
)
)
if ATTR_TRANSITION not in kwargs:
# no transition specified by user, use defaults
new_value = 7621 # anything over 7620 uses the factory default
if ozw_version < (1, 6, 1205):
new_value = 255 # default for older version
else:
# transition specified by user
new_value = int(max(0, min(7620, kwargs[ATTR_TRANSITION])))
if ozw_version < (1, 6, 1205):
if (transition := kwargs[ATTR_TRANSITION]) <= 127:
new_value = int(transition)
else:
minutes = int(transition / 60)
_LOGGER.debug(
"Transition rounded to %d minutes for %s",
minutes,
self.entity_id,
)
new_value = minutes + 128
# only send value if it differs from current
# this prevents a command for nothing
if self.values.dimming_duration.value != new_value:
self.values.dimming_duration.send_value(new_value)
async def async_turn_on(self, **kwargs):
"""Turn the device on."""
self.async_set_duration(**kwargs)
rgbw = None
hs_color = kwargs.get(ATTR_HS_COLOR)
rgbw_color = kwargs.get(ATTR_RGBW_COLOR)
color_temp = kwargs.get(ATTR_COLOR_TEMP)
if hs_color is not None:
rgbw = "#"
for colorval in color_util.color_hs_to_RGB(*hs_color):
rgbw += f"{colorval:02x}"
if self._color_channels and self._color_channels & COLOR_CHANNEL_COLD_WHITE:
rgbw += "0000"
else:
# trim the CW value or it will not work correctly
rgbw += "00"
# white LED must be off in order for color to work
elif rgbw_color is not None:
red = rgbw_color[0]
green = rgbw_color[1]
blue = rgbw_color[2]
white = rgbw_color[3]
if self._color_channels & COLOR_CHANNEL_WARM_WHITE:
# trim the CW value or it will not work correctly
rgbw = f"#{red:02x}{green:02x}{blue:02x}{white:02x}"
else:
rgbw = f"#{red:02x}{green:02x}{blue:02x}00{white:02x}"
elif color_temp is not None:
# Limit color temp to min/max values
cold = max(
0,
min(
255,
round(
(self._max_mireds - color_temp)
/ (self._max_mireds - self._min_mireds)
* 255
),
),
)
warm = 255 - cold
rgbw = f"#000000{warm:02x}{cold:02x}"
if rgbw and self.values.color:
self.values.color.send_value(rgbw)
# 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:
brightness = kwargs[ATTR_BRIGHTNESS]
brightness = byte_to_zwave_brightness(brightness)
else:
brightness = 255
self.values.primary.send_value(brightness)
async def async_turn_off(self, **kwargs):
"""Turn the device off."""
self.async_set_duration(**kwargs)
self.values.primary.send_value(0)
def _calculate_color_values(self):
"""Parse color rgb and color temperature data."""
# Color Data String
data = self.values.color.data[ATTR_VALUE]
# RGB is always present in the OpenZWave color data string.
rgb = [int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16)]
self._hs = color_util.color_RGB_to_hs(*rgb)
# Light supports color, set color mode to hs
self._attr_color_mode = COLOR_MODE_HS
if self.values.color_channels is None:
return
# Color Channels
self._color_channels = self.values.color_channels.data[ATTR_VALUE]
# Parse remaining color channels. OpenZWave appends white channels
# that are present.
index = 7
temp_warm = 0
temp_cold = 0
# Update color temp limits.
if self.values.min_kelvin:
self._max_mireds = color_util.color_temperature_kelvin_to_mired(
self.values.min_kelvin.data[ATTR_VALUE]
)
if self.values.max_kelvin:
self._min_mireds = color_util.color_temperature_kelvin_to_mired(
self.values.max_kelvin.data[ATTR_VALUE]
)
# Warm white
if self._color_channels & COLOR_CHANNEL_WARM_WHITE:
white = int(data[index : index + 2], 16)
self._rgbw_color = [rgb[0], rgb[1], rgb[2], white]
temp_warm = white
# Light supports rgbw, set color mode to rgbw
self._attr_color_mode = COLOR_MODE_RGBW
index += 2
# Cold white
if self._color_channels & COLOR_CHANNEL_COLD_WHITE:
white = int(data[index : index + 2], 16)
self._rgbw_color = [rgb[0], rgb[1], rgb[2], white]
temp_cold = white
# Light supports rgbw, set color mode to rgbw
self._attr_color_mode = COLOR_MODE_RGBW
# Calculate color temps based on white LED status
if temp_cold or temp_warm:
self._ct = round(
self._max_mireds
- ((temp_cold / 255) * (self._max_mireds - self._min_mireds))
)
if (
self._color_channels & COLOR_CHANNEL_WARM_WHITE
and self._color_channels & COLOR_CHANNEL_COLD_WHITE
):
# Light supports 5 channels, set color_mode to color_temp or hs
if rgb[0] == 0 and rgb[1] == 0 and rgb[2] == 0:
# Color channels turned off, set color mode to color_temp
self._attr_color_mode = COLOR_MODE_COLOR_TEMP
else:
self._attr_color_mode = COLOR_MODE_HS
if not (
self._color_channels & COLOR_CHANNEL_RED
or self._color_channels & COLOR_CHANNEL_GREEN
or self._color_channels & COLOR_CHANNEL_BLUE
):
self._hs = None

View File

@ -1,105 +0,0 @@
"""Representation of Z-Wave locks."""
import logging
from openzwavemqtt.const import ATTR_CODE_SLOT
from openzwavemqtt.exceptions import BaseOZWError
from openzwavemqtt.util.lock import clear_usercode, set_usercode
import voluptuous as vol
from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN, LockEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DATA_UNSUBSCRIBE, DOMAIN
from .entity import ZWaveDeviceEntity
ATTR_USERCODE = "usercode"
SERVICE_SET_USERCODE = "set_usercode"
SERVICE_GET_USERCODE = "get_usercode"
SERVICE_CLEAR_USERCODE = "clear_usercode"
_LOGGER = logging.getLogger(__name__)
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(value):
"""Add Z-Wave Lock."""
lock = ZWaveLock(value)
async_add_entities([lock])
hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append(
async_dispatcher_connect(hass, f"{DOMAIN}_new_{LOCK_DOMAIN}", async_add_lock)
)
platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
SERVICE_SET_USERCODE,
{
vol.Required(ATTR_CODE_SLOT): vol.Coerce(int),
vol.Required(ATTR_USERCODE): cv.string,
},
"async_set_usercode",
)
platform.async_register_entity_service(
SERVICE_CLEAR_USERCODE,
{vol.Required(ATTR_CODE_SLOT): vol.Coerce(int)},
"async_clear_usercode",
)
def _call_util_lock_function(function, *args):
"""Call an openzwavemqtt.util.lock function and return success of call."""
try:
function(*args)
except BaseOZWError as err:
_LOGGER.error("%s: %s", type(err), err.args[0])
return False
return True
class ZWaveLock(ZWaveDeviceEntity, LockEntity):
"""Representation of a Z-Wave lock."""
@property
def is_locked(self):
"""Return a boolean for the state of the lock."""
return bool(self.values.primary.value)
async def async_lock(self, **kwargs):
"""Lock the lock."""
self.values.primary.send_value(True)
async def async_unlock(self, **kwargs):
"""Unlock the lock."""
self.values.primary.send_value(False)
@callback
def async_set_usercode(self, code_slot, usercode):
"""Set the usercode to index X on the lock."""
if _call_util_lock_function(
set_usercode, self.values.primary.node, code_slot, usercode
):
_LOGGER.debug("User code at slot %s set", code_slot)
@callback
def async_clear_usercode(self, code_slot):
"""Clear usercode in slot X on the lock."""
if _call_util_lock_function(
clear_usercode, self.values.primary.node, code_slot
):
_LOGGER.info("Usercode at slot %s is cleared", code_slot)

View File

@ -1,11 +0,0 @@
{
"domain": "ozw",
"name": "OpenZWave (deprecated)",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/ozw",
"requirements": ["python-openzwave-mqtt[mqtt-client]==1.4.0"],
"after_dependencies": ["mqtt"],
"codeowners": ["@cgarwood", "@marcelveldt", "@MartinHjelmare"],
"iot_class": "local_push",
"loggers": ["openzwavemqtt"]
}

View File

@ -1,164 +0,0 @@
"""Representation of Z-Wave sensors."""
import logging
from openzwavemqtt.const import CommandClass, ValueType
from homeassistant.components.sensor import (
DOMAIN as SENSOR_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 .const import DATA_UNSUBSCRIBE, DOMAIN
from .entity import ZWaveDeviceEntity
_LOGGER = logging.getLogger(__name__)
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(value):
"""Add Z-Wave Sensor."""
# Basic Sensor types
if value.primary.type in (
ValueType.BYTE,
ValueType.INT,
ValueType.SHORT,
ValueType.DECIMAL,
):
sensor = ZWaveNumericSensor(value)
elif value.primary.type == ValueType.LIST:
sensor = ZWaveListSensor(value)
elif value.primary.type == ValueType.STRING:
sensor = ZWaveStringSensor(value)
else:
_LOGGER.warning("Sensor not implemented for value %s", value.primary.label)
return
async_add_entities([sensor])
hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append(
async_dispatcher_connect(
hass, f"{DOMAIN}_new_{SENSOR_DOMAIN}", async_add_sensor
)
)
class ZwaveSensorBase(ZWaveDeviceEntity, SensorEntity):
"""Basic Representation of a Z-Wave sensor."""
@property
def device_class(self):
"""Return the device class of the sensor."""
if self.values.primary.command_class == CommandClass.BATTERY:
return SensorDeviceClass.BATTERY
if self.values.primary.command_class == CommandClass.METER:
return SensorDeviceClass.POWER
if "Temperature" in self.values.primary.label:
return SensorDeviceClass.TEMPERATURE
if "Illuminance" in self.values.primary.label:
return SensorDeviceClass.ILLUMINANCE
if "Humidity" in self.values.primary.label:
return SensorDeviceClass.HUMIDITY
if "Power" in self.values.primary.label:
return SensorDeviceClass.POWER
if "Energy" in self.values.primary.label:
return SensorDeviceClass.POWER
if "Electric" in self.values.primary.label:
return SensorDeviceClass.POWER
if "Pressure" in self.values.primary.label:
return SensorDeviceClass.PRESSURE
return None
@property
def entity_registry_enabled_default(self) -> bool:
"""Return if the entity should be enabled when first added to the entity registry."""
# We hide some of the more advanced sensors by default to not overwhelm users
if self.values.primary.command_class in (
CommandClass.BASIC,
CommandClass.INDICATOR,
CommandClass.NOTIFICATION,
):
return False
return True
@property
def force_update(self) -> bool:
"""Force updates."""
return True
class ZWaveStringSensor(ZwaveSensorBase):
"""Representation of a Z-Wave sensor."""
@property
def native_value(self):
"""Return state of the sensor."""
return self.values.primary.value
@property
def native_unit_of_measurement(self):
"""Return unit of measurement the value is expressed in."""
return self.values.primary.units
@property
def entity_registry_enabled_default(self):
"""Return if the entity should be enabled when first added to the entity registry."""
return False
class ZWaveNumericSensor(ZwaveSensorBase):
"""Representation of a Z-Wave sensor."""
@property
def native_value(self):
"""Return state of the sensor."""
return round(self.values.primary.value, 2)
@property
def native_unit_of_measurement(self):
"""Return unit of measurement the value is expressed in."""
if self.values.primary.units == "C":
return TEMP_CELSIUS
if self.values.primary.units == "F":
return TEMP_FAHRENHEIT
return self.values.primary.units
class ZWaveListSensor(ZwaveSensorBase):
"""Representation of a Z-Wave list sensor."""
@property
def native_value(self):
"""Return the state of the sensor."""
# We use the id as value for backwards compatibility
return self.values.primary.value["Selected_id"]
@property
def extra_state_attributes(self):
"""Return the device specific state attributes."""
attributes = super().extra_state_attributes
# add the value's label as property
attributes["label"] = self.values.primary.value["Selected"]
return attributes
@property
def entity_registry_enabled_default(self) -> bool:
"""Return if the entity should be enabled when first added to the entity registry."""
# these sensors are only here for backwards compatibility, disable them by default
return False

View File

@ -1,134 +0,0 @@
"""Methods and classes related to executing Z-Wave commands and publishing these to hass."""
import logging
from openzwavemqtt.const import ATTR_LABEL, ATTR_POSITION, ATTR_VALUE
from openzwavemqtt.util.node import get_node_from_manager, set_config_parameter
import voluptuous as vol
from homeassistant.core import ServiceCall, callback
import homeassistant.helpers.config_validation as cv
from . import const
_LOGGER = logging.getLogger(__name__)
class ZWaveServices:
"""Class that holds our services ( Zwave Commands) that should be published to hass."""
def __init__(self, hass, manager):
"""Initialize with both hass and ozwmanager objects."""
self._hass = hass
self._manager = manager
@callback
def async_register(self):
"""Register all our services."""
self._hass.services.async_register(
const.DOMAIN,
const.SERVICE_ADD_NODE,
self.async_add_node,
schema=vol.Schema(
{
vol.Optional(const.ATTR_INSTANCE_ID, default=1): vol.Coerce(int),
vol.Optional(const.ATTR_SECURE, default=False): vol.Coerce(bool),
}
),
)
self._hass.services.async_register(
const.DOMAIN,
const.SERVICE_REMOVE_NODE,
self.async_remove_node,
schema=vol.Schema(
{vol.Optional(const.ATTR_INSTANCE_ID, default=1): vol.Coerce(int)}
),
)
self._hass.services.async_register(
const.DOMAIN,
const.SERVICE_CANCEL_COMMAND,
self.async_cancel_command,
schema=vol.Schema(
{vol.Optional(const.ATTR_INSTANCE_ID, default=1): vol.Coerce(int)}
),
)
self._hass.services.async_register(
const.DOMAIN,
const.SERVICE_SET_CONFIG_PARAMETER,
self.async_set_config_parameter,
schema=vol.Schema(
{
vol.Optional(const.ATTR_INSTANCE_ID, default=1): vol.Coerce(int),
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
vol.Required(const.ATTR_CONFIG_VALUE): vol.Any(
vol.All(
cv.ensure_list,
[
vol.All(
{
vol.Exclusive(ATTR_LABEL, "bit"): cv.string,
vol.Exclusive(ATTR_POSITION, "bit"): vol.Coerce(
int
),
vol.Required(ATTR_VALUE): bool,
},
cv.has_at_least_one_key(ATTR_LABEL, ATTR_POSITION),
)
],
),
vol.Coerce(int),
bool,
cv.string,
),
}
),
)
@callback
def async_set_config_parameter(self, service: ServiceCall) -> None:
"""Set a config parameter to a node."""
instance_id = service.data[const.ATTR_INSTANCE_ID]
node_id = service.data[const.ATTR_NODE_ID]
param = service.data[const.ATTR_CONFIG_PARAMETER]
selection = service.data[const.ATTR_CONFIG_VALUE]
# These function calls may raise an exception but that's ok because
# the exception will show in the UI to the user
node = get_node_from_manager(self._manager, instance_id, node_id)
payload = set_config_parameter(node, param, selection)
_LOGGER.info(
"Setting configuration parameter %s on Node %s with value %s",
param,
node_id,
payload,
)
@callback
def async_add_node(self, service: ServiceCall) -> None:
"""Enter inclusion mode on the controller."""
instance_id = service.data[const.ATTR_INSTANCE_ID]
secure = service.data[const.ATTR_SECURE]
instance = self._manager.get_instance(instance_id)
if instance is None:
raise ValueError(f"No OpenZWave Instance with ID {instance_id}")
instance.add_node(secure)
@callback
def async_remove_node(self, service: ServiceCall) -> None:
"""Enter exclusion mode on the controller."""
instance_id = service.data[const.ATTR_INSTANCE_ID]
instance = self._manager.get_instance(instance_id)
if instance is None:
raise ValueError(f"No OpenZWave Instance with ID {instance_id}")
instance.remove_node()
@callback
def async_cancel_command(self, service: ServiceCall) -> None:
"""Tell the controller to cancel an add or remove command."""
instance_id = service.data[const.ATTR_INSTANCE_ID]
instance = self._manager.get_instance(instance_id)
if instance is None:
raise ValueError(f"No OpenZWave Instance with ID {instance_id}")
instance.cancel_controller_command()

View File

@ -1,121 +0,0 @@
# Describes the format for available Z-Wave services
add_node:
name: Add node
description: Add a new node to the Z-Wave network.
fields:
secure:
name: Secure
description: Add the new node 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.
default: false
selector:
boolean:
instance_id:
name: Instance ID
description: The OZW Instance/Controller to use.
selector:
number:
min: 1
max: 255
remove_node:
name: Remove node
description: Remove a node from the Z-Wave network. Will set the controller into exclusion mode.
fields:
instance_id:
name: Instance ID
description: The OZW Instance/Controller to use.
default: 1
selector:
number:
min: 1
max: 255
cancel_command:
name: Cancel command
description: Cancel a pending add or remove node command.
fields:
instance_id:
name: Instance ID
description: The OZW Instance/Controller to use.
default: 1
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
example: 50268673
selector:
text:
instance_id:
name: Instance ID
description: The OZW Instance/Controller to use.
default: 1
selector:
number:
min: 1
max: 255
clear_usercode:
name: Clear usercode
description: Clear a usercode from lock.
target:
entity:
integration: ozw
domain: lock
fields:
code_slot:
name: Code slot
description: Code slot to clear code from.
required: true
selector:
number:
min: 1
max: 255
set_usercode:
name: Set usercode
description: Set a usercode to lock.
target:
entity:
integration: ozw
domain: lock
fields:
code_slot:
name: Code slot
description: Code slot to set the code.
required: true
selector:
number:
min: 1
max: 255
usercode:
name: Usercode
description: Code to set.
required: true
example: 1234
selector:
text:

View File

@ -1,39 +0,0 @@
{
"config": {
"step": {
"on_supervisor": {
"title": "Select connection method",
"description": "Do you want to use the OpenZWave Supervisor add-on?",
"data": { "use_addon": "Use the OpenZWave Supervisor add-on" }
},
"install_addon": {
"title": "The OpenZWave add-on installation has started"
},
"start_addon": {
"title": "Enter the OpenZWave add-on configuration",
"data": {
"usb_path": "[%key:common::config_flow::data::usb_path%]",
"network_key": "Network Key"
}
},
"hassio_confirm": {
"title": "Set up OpenZWave integration with the OpenZWave add-on"
}
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
"addon_info_failed": "Failed to get OpenZWave add-on info.",
"addon_install_failed": "Failed to install the OpenZWave add-on.",
"addon_set_config_failed": "Failed to set OpenZWave configuration.",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
"mqtt_required": "The MQTT integration is not set up"
},
"error": {
"addon_start_failed": "Failed to start the OpenZWave add-on. Check the configuration."
},
"progress": {
"install_addon": "Please wait while the OpenZWave add-on installation finishes. This can take several minutes."
}
}
}

View File

@ -1,47 +0,0 @@
"""Representation of Z-Wave switches."""
from homeassistant.components.switch import DOMAIN as SWITCH_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 .const import DATA_UNSUBSCRIBE, DOMAIN
from .entity import ZWaveDeviceEntity
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(value):
"""Add Z-Wave Switch."""
switch = ZWaveSwitch(value)
async_add_entities([switch])
hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append(
async_dispatcher_connect(
hass, f"{DOMAIN}_new_{SWITCH_DOMAIN}", async_add_switch
)
)
class ZWaveSwitch(ZWaveDeviceEntity, SwitchEntity):
"""Representation of a Z-Wave switch."""
@property
def is_on(self):
"""Return a boolean for the state of the switch."""
return bool(self.values.primary.value)
async def async_turn_on(self, **kwargs):
"""Turn the switch on."""
self.values.primary.send_value(True)
async def async_turn_off(self, **kwargs):
"""Turn the switch off."""
self.values.primary.send_value(False)

View File

@ -1,8 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u0442\u043e \u0432\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u043e",
"single_instance_allowed": "\u0412\u0435\u0447\u0435 \u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u043e. \u0412\u044a\u0437\u043c\u043e\u0436\u043d\u0430 \u0435 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f."
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "No s'ha pogut obtenir la informaci\u00f3 del complement OpenZWave.",
"addon_install_failed": "No s'ha pogut instal\u00b7lar el complement OpenZWave.",
"addon_set_config_failed": "No s'ha pogut establir la configuraci\u00f3 d'OpenZWave.",
"already_configured": "El dispositiu ja est\u00e0 configurat",
"already_in_progress": "El flux de configuraci\u00f3 ja est\u00e0 en curs",
"mqtt_required": "La integraci\u00f3 MQTT no est\u00e0 configurada",
"single_instance_allowed": "Ja configurat. Nom\u00e9s \u00e9s possible una sola configuraci\u00f3."
},
"error": {
"addon_start_failed": "No s'ha pogut iniciar el complement OpenZWave. Comprova la configuraci\u00f3."
},
"progress": {
"install_addon": "Espera mentre finalitza la instal\u00b7laci\u00f3 del complement OpenZWave. Pot tardar uns quants minuts."
},
"step": {
"hassio_confirm": {
"title": "Configuraci\u00f3 de la integraci\u00f3 d'OpenZWave amb el complement OpenZWave"
},
"install_addon": {
"title": "Ha comen\u00e7at la instal\u00b7laci\u00f3 del complement OpenZWave"
},
"on_supervisor": {
"data": {
"use_addon": "Utilitza el complement OpenZWave Supervisor"
},
"description": "Vols utilitzar el complement Supervisor d'OpenZWave?",
"title": "Selecciona el m\u00e8tode de connexi\u00f3"
},
"start_addon": {
"data": {
"network_key": "Clau de xarxa",
"usb_path": "Ruta del dispositiu USB"
},
"title": "Introdueix la configuraci\u00f3 del complement OpenZWave"
}
}
}
}

View File

@ -1,38 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Nepoda\u0159ilo se z\u00edskat informace o dopl\u0148ku OpenZWave.",
"addon_install_failed": "Instalace dopl\u0148ku OpenZWave se nezda\u0159ila.",
"addon_set_config_failed": "Nepoda\u0159ilo se nastavit OpenZWave.",
"already_configured": "Za\u0159\u00edzen\u00ed je ji\u017e nastaveno",
"already_in_progress": "Konfigurace ji\u017e prob\u00edh\u00e1",
"mqtt_required": "Integrace MQTT nen\u00ed nastavena",
"single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace."
},
"error": {
"addon_start_failed": "Spu\u0161t\u011bn\u00ed dopl\u0148ku OpenZWave se nezda\u0159ilo. Zkontrolujte konfiguraci."
},
"step": {
"hassio_confirm": {
"title": "Nastaven\u00ed integrace OpenZWave s dopl\u0148kem OpenZWave"
},
"install_addon": {
"title": "Instalace dopl\u0148ku OpenZWave byla zah\u00e1jena."
},
"on_supervisor": {
"data": {
"use_addon": "Pou\u017e\u00edt dopln\u011bk OpenZWave pro Supervisor"
},
"description": "Chcete pou\u017e\u00edt dopln\u011bk OpenZWave pro Supervisor?",
"title": "Vyberte metodu p\u0159ipojen\u00ed"
},
"start_addon": {
"data": {
"network_key": "S\u00ed\u0165ov\u00fd kl\u00ed\u010d",
"usb_path": "Cesta k USB za\u0159\u00edzen\u00ed"
},
"title": "Zadejte konfiguraci dopl\u0148ku OpenZWave"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Fehler beim Abrufen von OpenZWave Add-on Informationen.",
"addon_install_failed": "Installation des OpenZWave Add-ons fehlgeschlagen.",
"addon_set_config_failed": "Setzen der OpenZWave Konfiguration fehlgeschlagen.",
"already_configured": "Ger\u00e4t ist bereits konfiguriert",
"already_in_progress": "Der Konfigurationsablauf wird bereits ausgef\u00fchrt",
"mqtt_required": "Die MQTT-Integration ist nicht eingerichtet",
"single_instance_allowed": "Bereits konfiguriert. Nur eine einzige Konfiguration m\u00f6glich."
},
"error": {
"addon_start_failed": "Fehler beim Starten des OpenZWave Add-ons. \u00dcberpr\u00fcfe die Konfiguration."
},
"progress": {
"install_addon": "Bitte warten, bis die Installation des OpenZWave-Add-Ons abgeschlossen ist. Dies kann einige Minuten dauern."
},
"step": {
"hassio_confirm": {
"title": "Richte die OpenZWave Integration mit dem OpenZWave Add-On ein"
},
"install_addon": {
"title": "Die Installation des OpenZWave-Add-On wurde gestartet"
},
"on_supervisor": {
"data": {
"use_addon": "Verwende das OpenZWave Supervisor Add-on"
},
"description": "M\u00f6chtest du das OpenZWave Supervisor Add-on verwenden?",
"title": "Verbindungstyp ausw\u00e4hlen"
},
"start_addon": {
"data": {
"network_key": "Netzwerk-Schl\u00fcssel",
"usb_path": "USB-Ger\u00e4te-Pfad"
},
"title": "Gib die Konfiguration des OpenZWave Add-ons ein"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03bb\u03ae\u03c8\u03b7\u03c2 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03b9\u03ce\u03bd \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf\u03c5 OpenZWave.",
"addon_install_failed": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7\u03c2 \u03c4\u03bf\u03c5 \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf\u03c5 OpenZWave.",
"addon_set_config_failed": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03c1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7\u03c2 \u03c0\u03b1\u03c1\u03b1\u03bc\u03ad\u03c4\u03c1\u03c9\u03bd OpenZWave.",
"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",
"already_in_progress": "\u0397 \u03c1\u03bf\u03ae \u03b4\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7\u03c2 \u03b2\u03c1\u03af\u03c3\u03ba\u03b5\u03c4\u03b1\u03b9 \u03ae\u03b4\u03b7 \u03c3\u03b5 \u03b5\u03be\u03ad\u03bb\u03b9\u03be\u03b7",
"mqtt_required": "\u0397 \u03b5\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7 MQTT \u03b4\u03b5\u03bd \u03ad\u03c7\u03b5\u03b9 \u03c1\u03c5\u03b8\u03bc\u03b9\u03c3\u03c4\u03b5\u03af",
"single_instance_allowed": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03c4\u03b7\u03ba\u03b5 \u03ae\u03b4\u03b7. \u039c\u03cc\u03bd\u03bf \u03bc\u03af\u03b1 \u03c0\u03b1\u03c1\u03b1\u03bc\u03b5\u03c4\u03c1\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae."
},
"error": {
"addon_start_failed": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7\u03c2 \u03c4\u03bf\u03c5 \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf\u03c5 OpenZWave. \u0395\u03bb\u03ad\u03b3\u03be\u03c4\u03b5 \u03c4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7."
},
"progress": {
"install_addon": "\u03a0\u03b5\u03c1\u03b9\u03bc\u03ad\u03bd\u03b5\u03c4\u03b5 \u03bc\u03ad\u03c7\u03c1\u03b9 \u03bd\u03b1 \u03bf\u03bb\u03bf\u03ba\u03bb\u03b7\u03c1\u03c9\u03b8\u03b5\u03af \u03b7 \u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf\u03c5 OpenZWave. \u0391\u03c5\u03c4\u03cc \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03b4\u03b9\u03b1\u03c1\u03ba\u03ad\u03c3\u03b5\u03b9 \u03b1\u03c1\u03ba\u03b5\u03c4\u03ac \u03bb\u03b5\u03c0\u03c4\u03ac."
},
"step": {
"hassio_confirm": {
"title": "\u03a1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03b5\u03bd\u03c3\u03c9\u03bc\u03ac\u03c4\u03c9\u03c3\u03b7\u03c2 OpenZWave \u03bc\u03b5 \u03c4\u03bf \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf OpenZWave"
},
"install_addon": {
"title": "\u0397 \u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf\u03c5 OpenZWave \u03ad\u03c7\u03b5\u03b9 \u03be\u03b5\u03ba\u03b9\u03bd\u03ae\u03c3\u03b5\u03b9"
},
"on_supervisor": {
"data": {
"use_addon": "\u03a7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03bf \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf OpenZWave Supervisor"
},
"description": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf OpenZWave Supervisor;",
"title": "\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03bc\u03ad\u03b8\u03bf\u03b4\u03bf \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2"
},
"start_addon": {
"data": {
"network_key": "\u039a\u03bb\u03b5\u03b9\u03b4\u03af \u03b4\u03b9\u03ba\u03c4\u03cd\u03bf\u03c5",
"usb_path": "\u0394\u03b9\u03b1\u03b4\u03c1\u03bf\u03bc\u03ae \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae\u03c2 USB"
},
"title": "\u0395\u03b9\u03c3\u03ac\u03b3\u03b5\u03c4\u03b5 \u03c4\u03b7 \u03b4\u03b9\u03b1\u03bc\u03cc\u03c1\u03c6\u03c9\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf\u03c5 OpenZWave"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Failed to get OpenZWave add-on info.",
"addon_install_failed": "Failed to install the OpenZWave add-on.",
"addon_set_config_failed": "Failed to set OpenZWave configuration.",
"already_configured": "Device is already configured",
"already_in_progress": "Configuration flow is already in progress",
"mqtt_required": "The MQTT integration is not set up",
"single_instance_allowed": "Already configured. Only a single configuration possible."
},
"error": {
"addon_start_failed": "Failed to start the OpenZWave add-on. Check the configuration."
},
"progress": {
"install_addon": "Please wait while the OpenZWave add-on installation finishes. This can take several minutes."
},
"step": {
"hassio_confirm": {
"title": "Set up OpenZWave integration with the OpenZWave add-on"
},
"install_addon": {
"title": "The OpenZWave add-on installation has started"
},
"on_supervisor": {
"data": {
"use_addon": "Use the OpenZWave Supervisor add-on"
},
"description": "Do you want to use the OpenZWave Supervisor add-on?",
"title": "Select connection method"
},
"start_addon": {
"data": {
"network_key": "Network Key",
"usb_path": "USB Device Path"
},
"title": "Enter the OpenZWave add-on configuration"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "No se pudo obtener la informaci\u00f3n del complemento de OpenZWave.",
"addon_install_failed": "No se pudo instalar el complemento de OpenZWave.",
"addon_set_config_failed": "No se pudo establecer la configuraci\u00f3n de OpenZWave.",
"already_configured": "El dispositivo ya est\u00e1 configurado",
"already_in_progress": "El flujo de configuraci\u00f3n ya est\u00e1 en proceso",
"mqtt_required": "La integraci\u00f3n de MQTT no est\u00e1 configurada",
"single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n."
},
"error": {
"addon_start_failed": "No se pudo iniciar el complemento OpenZWave. Verifica la configuraci\u00f3n."
},
"progress": {
"install_addon": "Espera mientras finaliza la instalaci\u00f3n del complemento OpenZWave. Esto puede tardar varios minutos."
},
"step": {
"hassio_confirm": {
"title": "Configurar la integraci\u00f3n de OpenZWave con el complemento OpenZWave"
},
"install_addon": {
"title": "La instalaci\u00f3n del complemento OpenZWave se ha iniciado"
},
"on_supervisor": {
"data": {
"use_addon": "Usar el complemento de supervisor de OpenZWave"
},
"description": "\u00bfQuiere utilizar el complemento de Supervisor de OpenZWave?",
"title": "Selecciona el m\u00e9todo de conexi\u00f3n"
},
"start_addon": {
"data": {
"network_key": "Clave de red",
"usb_path": "Ruta del dispositivo USB"
},
"title": "Introduce la configuraci\u00f3n del complemento OpenZWave"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "OpenZWave'i lisandmooduli teabe hankimine nurjus.",
"addon_install_failed": "OpenZWave'i lisandmooduli paigaldamine nurjus.",
"addon_set_config_failed": "OpenZWave'i konfiguratsiooni seadistamine eba\u00f5nnestus.",
"already_configured": "Seade on juba h\u00e4\u00e4lestatud",
"already_in_progress": "Seadistamine on juba k\u00e4imas",
"mqtt_required": "MQTT sidumine pole seadistatud",
"single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine."
},
"error": {
"addon_start_failed": "OpenZWave'i lisandmooduli k\u00e4ivitamine nurjus. Kontrolli s\u00e4tteid."
},
"progress": {
"install_addon": "Palun oota kuni OpenZWave lisandmooduli paigaldus l\u00f5peb. See v\u00f5ib v\u00f5tta mitu minutit."
},
"step": {
"hassio_confirm": {
"title": "Seadista OpenZWave'i sidumine OpenZWave lisandmooduli abil"
},
"install_addon": {
"title": "OpenZWave lisandmooduli paigaldamine on alanud"
},
"on_supervisor": {
"data": {
"use_addon": "Kasuta OpenZWave Supervisori lisandmoodulit"
},
"description": "Kas soovid kasutada OpenZWave'i halduri lisandmoodulit?",
"title": "Vali \u00fchendusviis"
},
"start_addon": {
"data": {
"network_key": "V\u00f5rgu v\u00f5ti",
"usb_path": "USB seadme rada"
},
"title": "Sisesta OpenZWave'i lisandmooduli seaded"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Impossible d'obtenir les informations sur le module compl\u00e9mentaire OpenZWave.",
"addon_install_failed": "\u00c9chec de l'installation du module compl\u00e9mentaire OpenZWave.",
"addon_set_config_failed": "\u00c9chec de la configuration OpenZWave.",
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9",
"already_in_progress": "La configuration est d\u00e9j\u00e0 en cours\u00e0",
"mqtt_required": "L'int\u00e9gration MQTT n'est pas configur\u00e9e",
"single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible."
},
"error": {
"addon_start_failed": "\u00c9chec du d\u00e9marrage du module compl\u00e9mentaire OpenZWave. V\u00e9rifiez la configuration."
},
"progress": {
"install_addon": "Veuillez patienter pendant que l'installation du module OpenZWave se termine. Cela peut prendre plusieurs minutes."
},
"step": {
"hassio_confirm": {
"title": "Configurer l'int\u00e9gration d'OpenZWave avec le module compl\u00e9mentaire OpenZWave"
},
"install_addon": {
"title": "L'installation du module compl\u00e9mentaire OpenZWave a commenc\u00e9"
},
"on_supervisor": {
"data": {
"use_addon": "Utilisez le module compl\u00e9mentaire OpenZWave du Supervisor"
},
"description": "Voulez-vous utiliser le module compl\u00e9mentaire OpenZWave du Supervisor?",
"title": "S\u00e9lectionner la m\u00e9thode de connexion"
},
"start_addon": {
"data": {
"network_key": "Cl\u00e9 r\u00e9seau",
"usb_path": "Chemin du p\u00e9riph\u00e9rique USB"
},
"title": "Entrez dans la configuration du module compl\u00e9mentaire OpenZWave"
}
}
}
}

View File

@ -1,24 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u05ea\u05e6\u05d5\u05e8\u05ea \u05d4\u05d4\u05ea\u05e7\u05df \u05db\u05d1\u05e8 \u05e0\u05e7\u05d1\u05e2\u05d4",
"already_in_progress": "\u05d6\u05e8\u05d9\u05de\u05ea \u05d4\u05ea\u05e6\u05d5\u05e8\u05d4 \u05db\u05d1\u05e8 \u05de\u05ea\u05d1\u05e6\u05e2\u05ea",
"mqtt_required": "\u05e9\u05d9\u05dc\u05d5\u05d1 MQTT \u05d0\u05d9\u05e0\u05d5 \u05de\u05d5\u05d2\u05d3\u05e8",
"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": {
"on_supervisor": {
"data": {
"use_addon": "\u05e9\u05d9\u05de\u05d5\u05e9 \u05d1\u05d4\u05e8\u05d7\u05d1\u05d4 '\u05de\u05e4\u05e7\u05d7 OpenZWave'"
},
"description": "\u05d4\u05d0\u05dd \u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05e9\u05ea\u05de\u05e9 \u05d1\u05d4\u05e8\u05d7\u05d1\u05d4 \u05e9\u05dc \u05de\u05e4\u05e7\u05d7 OpenZWave?",
"title": "\u05d1\u05d7\u05e8 \u05e9\u05d9\u05d8\u05ea \u05d7\u05d9\u05d1\u05d5\u05e8"
},
"start_addon": {
"data": {
"usb_path": "\u05e0\u05ea\u05d9\u05d1 \u05d4\u05ea\u05e7\u05df USB"
}
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Nem siker\u00fclt leh\u00edvni az OpenZWave b\u0151v\u00edtm\u00e9ny inform\u00e1ci\u00f3kat.",
"addon_install_failed": "Nem siker\u00fclt telep\u00edteni az OpenZWave b\u0151v\u00edtm\u00e9nyt.",
"addon_set_config_failed": "Nem siker\u00fclt be\u00e1ll\u00edtani az OpenZWave konfigur\u00e1ci\u00f3t.",
"already_configured": "Az eszk\u00f6z m\u00e1r konfigur\u00e1lva van",
"already_in_progress": "A konfigur\u00e1l\u00e1s m\u00e1r folyamatban van",
"mqtt_required": "Az MQTT integr\u00e1ci\u00f3 nincs be\u00e1ll\u00edtva",
"single_instance_allowed": "M\u00e1r konfigur\u00e1lva van. Csak egy konfigur\u00e1ci\u00f3 lehets\u00e9ges."
},
"error": {
"addon_start_failed": "Nem siker\u00fclt elind\u00edtani az OpenZWave b\u0151v\u00edtm\u00e9nyt. Ellen\u0151rizze a konfigur\u00e1ci\u00f3t."
},
"progress": {
"install_addon": "V\u00e1rjon, am\u00edg az OpenZWave b\u0151v\u00edtm\u00e9ny telep\u00edt\u00e9se befejez\u0151dik. Ez t\u00f6bb percig is eltarthat."
},
"step": {
"hassio_confirm": {
"title": "\u00c1ll\u00edtsa be az OpenZWave integr\u00e1ci\u00f3t az OpenZWave b\u0151v\u00edtm\u00e9nnyel"
},
"install_addon": {
"title": "Elindult az OpenZWave b\u0151v\u00edtm\u00e9ny telep\u00edt\u00e9se"
},
"on_supervisor": {
"data": {
"use_addon": "OpenZWave Supervisor b\u0151v\u00edtm\u00e9ny haszn\u00e1lata"
},
"description": "Szeretn\u00e9 haszn\u00e1lni az OpenZWave Supervisor b\u0151v\u00edtm\u00e9nyt?",
"title": "V\u00e1lassza ki a csatlakoz\u00e1si m\u00f3dot"
},
"start_addon": {
"data": {
"network_key": "H\u00e1l\u00f3zati kulcs",
"usb_path": "USB eszk\u00f6z el\u00e9r\u00e9si \u00fat"
},
"title": "Adja meg az OpenZWave b\u0151v\u00edtm\u00e9ny konfigur\u00e1ci\u00f3j\u00e1t"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Gagal mendapatkan info add-on OpenZWave.",
"addon_install_failed": "Gagal menginstal add-on OpenZWave.",
"addon_set_config_failed": "Gagal menyetel konfigurasi OpenZWave.",
"already_configured": "Perangkat sudah dikonfigurasi",
"already_in_progress": "Alur konfigurasi sedang berlangsung",
"mqtt_required": "Integrasi MQTT belum disiapkan",
"single_instance_allowed": "Sudah dikonfigurasi. Hanya satu konfigurasi yang diizinkan."
},
"error": {
"addon_start_failed": "Gagal memulai add-on OpenZWave. Periksa konfigurasi."
},
"progress": {
"install_addon": "Harap tunggu hingga penginstalan add-on OpenZWave selesai. Ini bisa memakan waktu beberapa saat."
},
"step": {
"hassio_confirm": {
"title": "Siapkan integrasi OpenZWave dengan add-on OpenZWave"
},
"install_addon": {
"title": "Instalasi add-on OpenZWave telah dimulai"
},
"on_supervisor": {
"data": {
"use_addon": "Gunakan add-on Supervisor OpenZWave"
},
"description": "Ingin menggunakan add-on Supervisor OpenZWave?",
"title": "Pilih metode koneksi"
},
"start_addon": {
"data": {
"network_key": "Kunci Jaringan",
"usb_path": "Jalur Perangkat USB"
},
"title": "Masukkan konfigurasi add-on OpenZWave"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Impossibile ottenere le informazioni sul componente aggiuntivo OpenZWave.",
"addon_install_failed": "Impossibile installare il componente aggiuntivo OpenZWave.",
"addon_set_config_failed": "Impossibile impostare la configurazione di OpenZWave.",
"already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato",
"already_in_progress": "Il flusso di configurazione \u00e8 gi\u00e0 in corso",
"mqtt_required": "L'integrazione MQTT non \u00e8 impostata",
"single_instance_allowed": "Gi\u00e0 configurato. \u00c8 possibile una sola configurazione."
},
"error": {
"addon_start_failed": "Impossibile avviare il componente aggiuntivo OpenZWave. Controlla la configurazione."
},
"progress": {
"install_addon": "Attendi il termine dell'installazione del componente aggiuntivo OpenZWave. Questa operazione pu\u00f2 richiedere diversi minuti."
},
"step": {
"hassio_confirm": {
"title": "Configura l'integrazione di OpenZWave con il componente aggiuntivo OpenZWave"
},
"install_addon": {
"title": "L'installazione del componente aggiuntivo OpenZWave \u00e8 iniziata"
},
"on_supervisor": {
"data": {
"use_addon": "Usa il componente aggiuntivo OpenZWave Supervisor"
},
"description": "Vuoi usare il componente aggiuntivo OpenZWave Supervisor?",
"title": "Seleziona il metodo di connessione"
},
"start_addon": {
"data": {
"network_key": "Chiave di rete",
"usb_path": "Percorso del dispositivo USB"
},
"title": "Accedi alla configurazione dell'add-on OpenZWave"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "OpenZWave\u306e\u30a2\u30c9\u30aa\u30f3\u60c5\u5831\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002",
"addon_install_failed": "OpenZWave\u30a2\u30c9\u30aa\u30f3\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002",
"addon_set_config_failed": "OpenZWave\u306e\u8a2d\u5b9a\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002",
"already_configured": "\u30c7\u30d0\u30a4\u30b9\u306f\u3059\u3067\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059",
"already_in_progress": "\u69cb\u6210\u30d5\u30ed\u30fc\u306f\u3059\u3067\u306b\u9032\u884c\u4e2d\u3067\u3059",
"mqtt_required": "MQTT\u30a4\u30f3\u30c6\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093",
"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": {
"addon_start_failed": "OpenZWave\u30a2\u30c9\u30aa\u30f3\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u8a2d\u5b9a\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002"
},
"progress": {
"install_addon": "OpenZWave\u30a2\u30c9\u30aa\u30f3\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u304c\u5b8c\u4e86\u3059\u308b\u307e\u3067\u304a\u5f85\u3061\u304f\u3060\u3055\u3044\u3002\u3053\u308c\u306b\u306f\u6570\u5206\u304b\u304b\u308b\u5834\u5408\u304c\u3042\u308a\u307e\u3059\u3002"
},
"step": {
"hassio_confirm": {
"title": "OpenZWave\u30a2\u30c9\u30aa\u30f3\u3068OpenZWave\u30a4\u30f3\u30c6\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u3092\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7"
},
"install_addon": {
"title": "OpenZWave\u30a2\u30c9\u30aa\u30f3\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u304c\u958b\u59cb\u3055\u308c\u307e\u3057\u305f"
},
"on_supervisor": {
"data": {
"use_addon": "OpenZWave Supervisor\u30a2\u30c9\u30aa\u30f3\u3092\u4f7f\u7528\u3059\u308b"
},
"description": "OpenZWave Supervisor\u30a2\u30c9\u30aa\u30f3\u3092\u4f7f\u7528\u3057\u307e\u3059\u304b\uff1f",
"title": "\u63a5\u7d9a\u65b9\u6cd5\u306e\u9078\u629e"
},
"start_addon": {
"data": {
"network_key": "\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u30ad\u30fc",
"usb_path": "USB\u30c7\u30d0\u30a4\u30b9\u306e\u30d1\u30b9"
},
"title": "OpenZWave\u30a2\u30c9\u30aa\u30f3\u306e\u8a2d\u5b9a\u3092\u5165\u529b\u3059\u308b"
}
}
}
}

View File

@ -1,29 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "\u10d5\u10d4\u10e0 \u10db\u10dd\u10ee\u10d4\u10e0\u10ee\u10d3\u10d0 OpenZWave \u10d3\u10d0\u10dc\u10d0\u10db\u10d0\u10e2\u10d8\u10e1 \u10d8\u10dc\u10e4\u10dd\u10e1 \u10db\u10d8\u10e6\u10d4\u10d1\u10d0.",
"addon_install_failed": "\u10d5\u10d4\u10e0 \u10db\u10dd\u10ee\u10d4\u10e0\u10ee\u10d3\u10d0 OpenZWave \u10d3\u10d0\u10dc\u10d0\u10db\u10d0\u10e2\u10d8\u10e1 \u10d8\u10dc\u10e1\u10e2\u10d0\u10da\u10d8\u10e0\u10d4\u10d1\u10d0.",
"addon_set_config_failed": "\u10d5\u10d4\u10e0 \u10db\u10dd\u10ee\u10d4\u10e0\u10ee\u10d3\u10d0 OpenZWave \u10d9\u10dd\u10dc\u10e4\u10d8\u10d2\u10e3\u10e0\u10d0\u10ea\u10d8\u10d8\u10e1 \u10d3\u10d0\u10e7\u10d4\u10dc\u10d4\u10d1\u10d0.",
"single_instance_allowed": "\u10e3\u10d9\u10d5\u10d4 \u10d3\u10d0\u10d9\u10dd\u10dc\u10e4\u10d8\u10d2\u10e3\u10e0\u10d8\u10e0\u10d4\u10d1\u10e3\u10da\u10d8\u10d0. \u10e8\u10d4\u10e1\u10d0\u10eb\u10da\u10d4\u10d1\u10d4\u10da\u10d8\u10d0 \u10db\u10ee\u10dd\u10da\u10dd\u10d3 \u10d4\u10e0\u10d7\u10d8 \u10d9\u10dd\u10dc\u10e4\u10d8\u10d2\u10e3\u10e0\u10d0\u10ea\u10d8\u10d0."
},
"error": {
"addon_start_failed": "OpenZWave \u10d3\u10d0\u10dc\u10d0\u10db\u10d0\u10e2\u10d8 \u10d0\u10e0 \u10d3\u10d0\u10d8\u10e1\u10e2\u10d0\u10e0\u10e2\u10d0. \u10e8\u10d4\u10d0\u10db\u10dd\u10ec\u10db\u10d4\u10d7 \u10d9\u10dd\u10dc\u10e4\u10d8\u10d2\u10e3\u10e0\u10d0\u10ea\u10d8\u10d0."
},
"step": {
"on_supervisor": {
"data": {
"use_addon": "\u10d2\u10d0\u10db\u10dd\u10d8\u10e7\u10d4\u10dc\u10d4\u10d7 OpenZWave Supervisor \u10d3\u10d0\u10dc\u10d0\u10db\u10d0\u10e2\u10d8"
},
"description": "\u10d2\u10e1\u10e3\u10e0\u10d7 \u10d2\u10d0\u10db\u10dd\u10d8\u10e7\u10d4\u10dc\u10dd\u10d7 OpenZWave Supervisor-\u10d8\u10e1 \u10d3\u10d0\u10dc\u10d0\u10db\u10d0\u10e2\u10d8?",
"title": "\u10d0\u10d8\u10e0\u10e9\u10d8\u10d4\u10d7 \u10d9\u10d0\u10d5\u10e8\u10d8\u10e0\u10d8\u10e1 \u10db\u10d4\u10d7\u10dd\u10d3\u10d8"
},
"start_addon": {
"data": {
"network_key": "\u10e5\u10e1\u10d4\u10da\u10d8\u10e1 \u10d2\u10d0\u10e1\u10d0\u10e6\u10d4\u10d1\u10d8",
"usb_path": "USB \u10db\u10dd\u10ec\u10e7\u10dd\u10d1\u10da\u10dd\u10d1\u10d8\u10e1 \u10d2\u10d6\u10d0"
},
"title": "\u10e8\u10d4\u10d8\u10e7\u10d5\u10d0\u10dc\u10d4\u10d7 OpenZWave \u10d3\u10d0\u10dc\u10d0\u10db\u10d0\u10e2\u10d8\u10e1 \u10d9\u10dd\u10dc\u10e4\u10d8\u10d2\u10e3\u10e0\u10d0\u10ea\u10d8\u10d0"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "OpenZWave \uc560\ub4dc\uc628\uc758 \uc815\ubcf4\ub97c \uac00\uc838\uc624\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.",
"addon_install_failed": "OpenZWave \uc560\ub4dc\uc628\uc744 \uc124\uce58\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.",
"addon_set_config_failed": "OpenZWave \uad6c\uc131\uc744 \uc124\uc815\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.",
"already_configured": "\uae30\uae30\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4",
"already_in_progress": "\uae30\uae30 \uad6c\uc131\uc774 \uc774\ubbf8 \uc9c4\ud589 \uc911\uc785\ub2c8\ub2e4",
"mqtt_required": "MQTT \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\uac00 \uc124\uc815\ub418\uc9c0 \uc54a\uc558\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": {
"addon_start_failed": "OpenZWave \uc560\ub4dc\uc628\uc744 \uc2dc\uc791\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. \uad6c\uc131 \ub0b4\uc6a9\uc744 \ud655\uc778\ud574\uc8fc\uc138\uc694."
},
"progress": {
"install_addon": "Openzwave \uc560\ub4dc\uc628\uc758 \uc124\uce58\uac00 \uc644\ub8cc\ub418\ub294 \ub3d9\uc548 \uc7a0\uc2dc \uae30\ub2e4\ub824\uc8fc\uc138\uc694. \uba87 \ubd84 \uc815\ub3c4 \uac78\ub9b4 \uc218 \uc788\uc2b5\ub2c8\ub2e4."
},
"step": {
"hassio_confirm": {
"title": "OpenZWave \uc560\ub4dc\uc628\uc73c\ub85c OpenZWave \ud1b5\ud569 \uad6c\uc131\uc694\uc18c \uc124\uc815\ud558\uae30"
},
"install_addon": {
"title": "Openzwave \uc560\ub4dc\uc628 \uc124\uce58\uac00 \uc2dc\uc791\ub418\uc5c8\uc2b5\ub2c8\ub2e4"
},
"on_supervisor": {
"data": {
"use_addon": "OpenZWave Supervisor \uc560\ub4dc\uc628\uc744 \uc0ac\uc6a9\ud558\uae30"
},
"description": "OpenZWave Supervisor \uc560\ub4dc\uc628\uc744 \uc0ac\uc6a9\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?",
"title": "\uc5f0\uacb0 \ubc29\ubc95 \uc120\ud0dd\ud558\uae30"
},
"start_addon": {
"data": {
"network_key": "\ub124\ud2b8\uc6cc\ud06c \ud0a4",
"usb_path": "USB \uc7a5\uce58 \uacbd\ub85c"
},
"title": "OpenZWave \uc560\ub4dc\uc628\uc758 \uad6c\uc131\uc744 \uc785\ub825\ud574\uc8fc\uc138\uc694"
}
}
}
}

View File

@ -1,17 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Apparat ass scho konfigur\u00e9iert",
"already_in_progress": "Konfiguratioun's Oflaf ass schon am gaang",
"mqtt_required": "MQTT Integratioun ass net ageriicht",
"single_instance_allowed": "Scho konfigur\u00e9iert. N\u00ebmmen eng eenzeg Konfiguratioun ass m\u00e9iglech."
},
"step": {
"start_addon": {
"data": {
"network_key": "Netzwierk Schl\u00ebssel"
}
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Mislukt om OpenZWave add-on info te krijgen.",
"addon_install_failed": "De installatie van de OpenZWave add-on is mislukt.",
"addon_set_config_failed": "Mislukt om OpenZWave configuratie in te stellen.",
"already_configured": "Apparaat is al geconfigureerd",
"already_in_progress": "De configuratiestroom is al aan de gang",
"mqtt_required": "De MQTT-integratie is niet ingesteld",
"single_instance_allowed": "Al geconfigureerd. Slechts \u00e9\u00e9n configuratie mogelijk."
},
"error": {
"addon_start_failed": "Het starten van de OpenZWave-add-on is mislukt. Controleer de configuratie."
},
"progress": {
"install_addon": "Wacht even terwijl de installatie van de OpenZWave add-on wordt voltooid. Dit kan enkele minuten duren."
},
"step": {
"hassio_confirm": {
"title": "OpenZWave integratie instellen met de OpenZWave add-on"
},
"install_addon": {
"title": "De OpenZWave add-on installatie is gestart"
},
"on_supervisor": {
"data": {
"use_addon": "Gebruik de OpenZWave Supervisor add-on"
},
"description": "Wilt u de OpenZWave Supervisor add-on gebruiken?",
"title": "Selecteer een verbindingsmethode"
},
"start_addon": {
"data": {
"network_key": "Netwerksleutel",
"usb_path": "USB-apparaatpad"
},
"title": "Voer de OpenZWave add-on configuratie in"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Kunne ikke hente informasjon om OpenZWave-tillegg",
"addon_install_failed": "Kunne ikke installere OpenZWave-tillegg",
"addon_set_config_failed": "Kunne ikke angi OpenZWave-konfigurasjon",
"already_configured": "Enheten er allerede konfigurert",
"already_in_progress": "Konfigurasjonsflyten p\u00e5g\u00e5r allerede",
"mqtt_required": "MQTT-integrasjonen er ikke satt opp",
"single_instance_allowed": "Allerede konfigurert. Bare \u00e9n enkelt konfigurasjon er mulig."
},
"error": {
"addon_start_failed": "Kunne ikke starte OpenZWave-tillegg. Sjekk konfigurasjonen."
},
"progress": {
"install_addon": "Vent mens installasjonen av OpenZWave-tillegg er ferdig. Dette kan ta flere minutter."
},
"step": {
"hassio_confirm": {
"title": "Sett opp OpenZWave-integrasjon med OpenZWave-tillegg"
},
"install_addon": {
"title": "Installasjonen av OpenZWave-tillegg har startet"
},
"on_supervisor": {
"data": {
"use_addon": "Bruk OpenZWave Supervisor-tillegg"
},
"description": "\u00d8nsker du \u00e5 bruke OpenZWave Supervisor-tillegg?",
"title": "Velg tilkoblingsmetode"
},
"start_addon": {
"data": {
"network_key": "Nettverksn\u00f8kkel",
"usb_path": "USB enhetsbane"
},
"title": "Angi konfigurasjon for OpenZWave-tillegg"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Nie uda\u0142o si\u0119 pobra\u0107 informacji o dodatku OpenZWave",
"addon_install_failed": "Nie uda\u0142o si\u0119 zainstalowa\u0107 dodatku OpenZWave",
"addon_set_config_failed": "Nie uda\u0142o si\u0119 ustawi\u0107 konfiguracji OpenZWave",
"already_configured": "Urz\u0105dzenie jest ju\u017c skonfigurowane",
"already_in_progress": "Konfiguracja jest ju\u017c w toku",
"mqtt_required": "Integracja MQTT nie jest skonfigurowana",
"single_instance_allowed": "Ju\u017c skonfigurowano. Mo\u017cliwa jest tylko jedna konfiguracja."
},
"error": {
"addon_start_failed": "Nie uda\u0142o si\u0119 uruchomi\u0107 dodatku OpenZWave. Sprawd\u017a konfiguracj\u0119."
},
"progress": {
"install_addon": "Poczekaj, a\u017c zako\u0144czy si\u0119 instalacja dodatku OpenZWave. Mo\u017ce to potrwa\u0107 kilka minut."
},
"step": {
"hassio_confirm": {
"title": "Konfiguracja integracji OpenZWave z dodatkiem OpenZWave"
},
"install_addon": {
"title": "Rozpocz\u0119\u0142a si\u0119 instalacja dodatku OpenZWave"
},
"on_supervisor": {
"data": {
"use_addon": "U\u017cyj dodatku OpenZWave Supervisor"
},
"description": "Czy chcesz u\u017cy\u0107 dodatku OpenZWave Supervisor?",
"title": "Wybierz metod\u0119 po\u0142\u0105czenia"
},
"start_addon": {
"data": {
"network_key": "Klucz sieci",
"usb_path": "\u015acie\u017cka urz\u0105dzenia USB"
},
"title": "Wprowad\u017a konfiguracj\u0119 dodatku OpenZWave"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "Falha ao obter informa\u00e7\u00f5es do add-on OpenZWave.",
"addon_install_failed": "Falha ao instalar o add-on OpenZWave.",
"addon_set_config_failed": "Falha ao definir a configura\u00e7\u00e3o do OpenZWave.",
"already_configured": "Dispositivo j\u00e1 est\u00e1 configurado",
"already_in_progress": "O fluxo de configura\u00e7\u00e3o j\u00e1 est\u00e1 em andamento",
"mqtt_required": "A integra\u00e7\u00e3o do MQTT n\u00e3o est\u00e1 configurada",
"single_instance_allowed": "J\u00e1 configurado. Apenas uma configura\u00e7\u00e3o \u00e9 poss\u00edvel."
},
"error": {
"addon_start_failed": "Falha ao iniciar o add-on OpenZWave. Verifique a configura\u00e7\u00e3o."
},
"progress": {
"install_addon": "Aguarde enquanto a instala\u00e7\u00e3o do add-on OpenZWave termina. Isso pode levar v\u00e1rios minutos."
},
"step": {
"hassio_confirm": {
"title": "Configure a integra\u00e7\u00e3o do OpenZWave com o add-on OpenZWave"
},
"install_addon": {
"title": "A instala\u00e7\u00e3o do add-on OpenZWave foi iniciada"
},
"on_supervisor": {
"data": {
"use_addon": "Use o add-on OpenZWave Supervisor"
},
"description": "Deseja usar o add-on OpenZWave Supervisor?",
"title": "Selecione o m\u00e9todo de conex\u00e3o"
},
"start_addon": {
"data": {
"network_key": "Chave de rede",
"usb_path": "Caminho do Dispositivo USB"
},
"title": "Digite a configura\u00e7\u00e3o do add-on OpenZWave"
}
}
}
}

View File

@ -1,16 +0,0 @@
{
"config": {
"abort": {
"already_configured": "O dispositivo j\u00e1 est\u00e1 configurado",
"already_in_progress": "O processo de configura\u00e7\u00e3o j\u00e1 est\u00e1 a decorrer",
"single_instance_allowed": "J\u00e1 configurado. Apenas uma \u00fanica configura\u00e7\u00e3o \u00e9 poss\u00edvel."
},
"step": {
"start_addon": {
"data": {
"usb_path": "Caminho do Dispositivo USB"
}
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 OpenZWave.",
"addon_install_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c OpenZWave.",
"addon_set_config_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e OpenZWave.",
"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.",
"already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f.",
"mqtt_required": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f MQTT \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430.",
"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": {
"addon_start_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c OpenZWave. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e."
},
"progress": {
"install_addon": "\u041f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435, \u043f\u043e\u043a\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f OpenZWave. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043d\u044f\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043d\u0443\u0442."
},
"step": {
"hassio_confirm": {
"title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f OpenZWave"
},
"install_addon": {
"title": "\u041d\u0430\u0447\u0430\u043b\u0430\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f OpenZWave"
},
"on_supervisor": {
"data": {
"use_addon": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 Supervisor OpenZWave"
},
"description": "\u0412\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 Supervisor OpenZWave?",
"title": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f"
},
"start_addon": {
"data": {
"network_key": "\u041a\u043b\u044e\u0447 \u0441\u0435\u0442\u0438",
"usb_path": "\u041f\u0443\u0442\u044c \u043a USB-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443"
},
"title": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f OpenZWave"
}
}
}
}

View File

@ -1,7 +0,0 @@
{
"config": {
"abort": {
"already_in_progress": "Konfigur\u00e1cia u\u017e prebieha"
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Naprava je \u017ee name\u0161\u010dena",
"already_in_progress": "Name\u0161\u010danje se \u017ee izvaja",
"mqtt_required": "Integracija MQTT ni nastavljena"
},
"progress": {
"install_addon": "Po\u010dakajte, da se namestitev dodatka OpenZWave zaklju\u010di. To lahko traja ve\u010d minut."
},
"step": {
"hassio_confirm": {
"title": "Namestite OpenZWave integracijo z OpenZWave dodatkom."
},
"install_addon": {
"title": "Namestitev dodatka OpenZWave se je za\u010dela"
},
"on_supervisor": {
"title": "Izberite na\u010din povezave"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "OpenZWave eklenti bilgileri al\u0131namad\u0131.",
"addon_install_failed": "OpenZWave eklentisi y\u00fcklenemedi.",
"addon_set_config_failed": "OpenZWave yap\u0131land\u0131rmas\u0131 ayarlanamad\u0131.",
"already_configured": "Cihaz zaten yap\u0131land\u0131r\u0131lm\u0131\u015f",
"already_in_progress": "Yap\u0131land\u0131rma ak\u0131\u015f\u0131 zaten devam ediyor",
"mqtt_required": "MQTT entegrasyonu kurulmam\u0131\u015f",
"single_instance_allowed": "Zaten yap\u0131land\u0131r\u0131lm\u0131\u015f. Yaln\u0131zca tek bir konfig\u00fcrasyon m\u00fcmk\u00fcnd\u00fcr."
},
"error": {
"addon_start_failed": "OpenZWave eklentisi ba\u015flat\u0131lamad\u0131. Yap\u0131land\u0131rmay\u0131 kontrol edin."
},
"progress": {
"install_addon": "OpenZWave eklenti kurulumu bitene kadar l\u00fctfen bekleyin. Bu birka\u00e7 dakika s\u00fcrebilir."
},
"step": {
"hassio_confirm": {
"title": "OpenZWave eklentisi ile OpenZWave entegrasyonunu kurun"
},
"install_addon": {
"title": "OpenZWave eklenti kurulumu ba\u015flad\u0131"
},
"on_supervisor": {
"data": {
"use_addon": "OpenZWave Supervisor eklentisini kullan\u0131n"
},
"description": "OpenZWave Supervisor eklentisini kullanmak istiyor musunuz?",
"title": "Ba\u011flant\u0131 y\u00f6ntemini se\u00e7in"
},
"start_addon": {
"data": {
"network_key": "A\u011f Anahtar\u0131",
"usb_path": "USB Cihaz Yolu"
},
"title": "OpenZWave eklenti yap\u0131land\u0131rmas\u0131n\u0131 girin"
}
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "\u041d\u0435 \u0432\u0434\u0430\u043b\u043e\u0441\u044f \u043e\u0442\u0440\u0438\u043c\u0430\u0442\u0438 \u0456\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u044e \u043f\u0440\u043e \u0434\u043e\u043f\u043e\u0432\u043d\u0435\u043d\u043d\u044f OpenZWave.",
"addon_install_failed": "\u041d\u0435 \u0432\u0434\u0430\u043b\u043e\u0441\u044f \u0432\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0438 OpenZWave.",
"addon_set_config_failed": "\u041d\u0435 \u0432\u0434\u0430\u043b\u043e\u0441\u044f \u0432\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0438 \u043a\u043e\u043d\u0444\u0456\u0433\u0443\u0440\u0430\u0446\u0456\u044e OpenZWave.",
"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.",
"already_in_progress": "\u041f\u0440\u043e\u0446\u0435\u0441 \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f \u0432\u0436\u0435 \u0442\u0440\u0438\u0432\u0430\u0454.",
"mqtt_required": "\u0406\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0456\u044f MQTT \u043d\u0435 \u0437\u043d\u0430\u0439\u0434\u0435\u043d\u0430.",
"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": {
"addon_start_failed": "\u041d\u0435 \u0432\u0434\u0430\u043b\u043e\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0438 OpenZWave. \u041f\u0435\u0440\u0435\u0432\u0456\u0440\u0442\u0435 \u043a\u043e\u043d\u0444\u0456\u0433\u0443\u0440\u0430\u0446\u0456\u044e."
},
"progress": {
"install_addon": "\u0417\u0430\u0447\u0435\u043a\u0430\u0439\u0442\u0435, \u043f\u043e\u043a\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c\u0441\u044f \u0432\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044f \u0434\u043e\u043f\u043e\u0432\u043d\u0435\u043d\u043d\u044f OpenZWave. \u0426\u0435 \u043c\u043e\u0436\u0435 \u0437\u0430\u0439\u043d\u044f\u0442\u0438 \u043a\u0456\u043b\u044c\u043a\u0430 \u0445\u0432\u0438\u043b\u0438\u043d."
},
"step": {
"hassio_confirm": {
"title": "\u041d\u0430\u043b\u0430\u0448\u0442\u0443\u0439\u0442\u0435 \u0437\u0430 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u043e\u044e \u0434\u043e\u043f\u043e\u0432\u043d\u0435\u043d\u043d\u044f OpenZWave"
},
"install_addon": {
"title": "\u0420\u043e\u0437\u043f\u043e\u0447\u0430\u0442\u043e \u0432\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044f \u0434\u043e\u043f\u043e\u0432\u043d\u0435\u043d\u043d\u044f Open'Wave"
},
"on_supervisor": {
"data": {
"use_addon": "\u0412\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0439\u0442\u0435 \u0434\u043e\u0434\u0430\u0442\u043e\u043a Supervisor OpenZWave"
},
"description": "\u0412\u0438 \u0445\u043e\u0447\u0435\u0442\u0435 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438 \u0434\u043e\u0434\u0430\u0442\u043e\u043a Supervisor OpenZWave?",
"title": "\u0412\u0438\u0431\u0435\u0440\u0456\u0442\u044c \u0441\u043f\u043e\u0441\u0456\u0431 \u043f\u0456\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044f"
},
"start_addon": {
"data": {
"network_key": "\u041a\u043b\u044e\u0447 \u043c\u0435\u0440\u0435\u0436\u0456",
"usb_path": "\u0428\u043b\u044f\u0445 \u0434\u043e USB-\u043f\u0440\u0438\u0441\u0442\u0440\u043e\u044e"
},
"title": "\u0412\u0432\u0435\u0434\u0456\u0442\u044c \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f \u0434\u043e\u0434\u0430\u0442\u043a\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 Open'Wave"
}
}
}
}

View File

@ -1,7 +0,0 @@
{
"config": {
"abort": {
"mqtt_required": "\u672a\u8bbe\u7f6e MQTT \u96c6\u6210"
}
}
}

View File

@ -1,41 +0,0 @@
{
"config": {
"abort": {
"addon_info_failed": "\u53d6\u5f97 OpenZWave \u9644\u52a0\u5143\u4ef6\u8cc7\u8a0a\u5931\u6557\u3002",
"addon_install_failed": "OpenZWave \u9644\u52a0\u5143\u4ef6\u5b89\u88dd\u5931\u6557\u3002",
"addon_set_config_failed": "OpenZWave a\u9644\u52a0\u5143\u4ef6\u8a2d\u5b9a\u5931\u6557\u3002",
"already_configured": "\u88dd\u7f6e\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210",
"already_in_progress": "\u8a2d\u5b9a\u5df2\u7d93\u9032\u884c\u4e2d",
"mqtt_required": "MQTT \u6574\u5408\u5c1a\u672a\u8a2d\u5b9a",
"single_instance_allowed": "\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210\u3001\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44\u88dd\u7f6e\u3002"
},
"error": {
"addon_start_failed": "OpenZWave \u9644\u52a0\u5143\u4ef6\u555f\u52d5\u5931\u6557\uff0c\u8acb\u6aa2\u67e5\u8a2d\u5b9a\u3002"
},
"progress": {
"install_addon": "\u8acb\u7a0d\u7b49 OpenZWave \u9644\u52a0\u5143\u4ef6\u5b89\u88dd\u5b8c\u6210\uff0c\u53ef\u80fd\u6703\u9700\u8981\u5e7e\u5206\u9418\u3002"
},
"step": {
"hassio_confirm": {
"title": "\u4ee5 OpenZWave \u9644\u52a0\u5143\u4ef6\u8a2d\u5b9a OpenZwave \u6574\u5408"
},
"install_addon": {
"title": "OpenZWave \u9644\u52a0\u5143\u4ef6\u5b89\u88dd\u5df2\u555f\u52d5"
},
"on_supervisor": {
"data": {
"use_addon": "\u4f7f\u7528 OpenZWave Supervisor \u9644\u52a0\u5143\u4ef6"
},
"description": "\u662f\u5426\u8981\u4f7f\u7528 OpenZWave Supervisor \u9644\u52a0\u5143\u4ef6\uff1f",
"title": "\u9078\u64c7\u9023\u7dda\u985e\u5225"
},
"start_addon": {
"data": {
"network_key": "\u7db2\u8def\u91d1\u9470",
"usb_path": "USB \u88dd\u7f6e\u8def\u5f91"
},
"title": "\u8acb\u8f38\u5165 OpenZWave \u9644\u52a0\u5143\u4ef6\u8a2d\u5b9a\u3002"
}
}
}
}

View File

@ -1,493 +0,0 @@
"""Web socket API for OpenZWave."""
from openzwavemqtt.const import (
ATTR_CODE_SLOT,
ATTR_LABEL,
ATTR_POSITION,
ATTR_VALUE,
EVENT_NODE_ADDED,
EVENT_NODE_CHANGED,
)
from openzwavemqtt.exceptions import NotFoundError, NotSupportedError
from openzwavemqtt.util.lock import clear_usercode, get_code_slots, set_usercode
from openzwavemqtt.util.node import (
get_config_parameters,
get_node_from_manager,
set_config_parameter,
)
import voluptuous as vol
import voluptuous_serialize
from homeassistant.components import websocket_api
from homeassistant.core import callback
from homeassistant.helpers import config_validation as cv
from .const import ATTR_CONFIG_PARAMETER, ATTR_CONFIG_VALUE, DOMAIN, MANAGER
from .lock import ATTR_USERCODE
DRY_RUN = "dry_run"
TYPE = "type"
ID = "id"
OZW_INSTANCE = "ozw_instance"
NODE_ID = "node_id"
PARAMETER = ATTR_CONFIG_PARAMETER
VALUE = ATTR_CONFIG_VALUE
SCHEMA = "schema"
ATTR_NODE_QUERY_STAGE = "node_query_stage"
ATTR_IS_ZWAVE_PLUS = "is_zwave_plus"
ATTR_IS_AWAKE = "is_awake"
ATTR_IS_FAILED = "is_failed"
ATTR_NODE_BAUD_RATE = "node_baud_rate"
ATTR_IS_BEAMING = "is_beaming"
ATTR_IS_FLIRS = "is_flirs"
ATTR_IS_ROUTING = "is_routing"
ATTR_IS_SECURITYV1 = "is_securityv1"
ATTR_NODE_BASIC_STRING = "node_basic_string"
ATTR_NODE_GENERIC_STRING = "node_generic_string"
ATTR_NODE_SPECIFIC_STRING = "node_specific_string"
ATTR_NODE_MANUFACTURER_NAME = "node_manufacturer_name"
ATTR_NODE_PRODUCT_NAME = "node_product_name"
ATTR_NEIGHBORS = "neighbors"
@callback
def async_register_api(hass):
"""Register all of our api endpoints."""
websocket_api.async_register_command(hass, websocket_get_instances)
websocket_api.async_register_command(hass, websocket_get_nodes)
websocket_api.async_register_command(hass, websocket_network_status)
websocket_api.async_register_command(hass, websocket_network_statistics)
websocket_api.async_register_command(hass, websocket_node_metadata)
websocket_api.async_register_command(hass, websocket_node_status)
websocket_api.async_register_command(hass, websocket_node_statistics)
websocket_api.async_register_command(hass, websocket_refresh_node_info)
websocket_api.async_register_command(hass, websocket_get_config_parameters)
websocket_api.async_register_command(hass, websocket_set_config_parameter)
websocket_api.async_register_command(hass, websocket_set_usercode)
websocket_api.async_register_command(hass, websocket_clear_usercode)
websocket_api.async_register_command(hass, websocket_get_code_slots)
def _call_util_function(hass, connection, msg, send_result, function, *args):
"""Call an openzwavemqtt.util function."""
try:
node = get_node_from_manager(
hass.data[DOMAIN][MANAGER], msg[OZW_INSTANCE], msg[NODE_ID]
)
except NotFoundError as err:
connection.send_error(
msg[ID],
websocket_api.const.ERR_NOT_FOUND,
err.args[0],
)
return
try:
payload = function(node, *args)
except NotFoundError as err:
connection.send_error(
msg[ID],
websocket_api.const.ERR_NOT_FOUND,
err.args[0],
)
return
except NotSupportedError as err:
connection.send_error(
msg[ID],
websocket_api.const.ERR_NOT_SUPPORTED,
err.args[0],
)
return
if send_result:
connection.send_result(
msg[ID],
payload,
)
return
connection.send_result(msg[ID])
def _get_config_params(node, *args):
raw_values = get_config_parameters(node)
config_params = []
for param in raw_values:
schema = {}
if param["type"] in ("Byte", "Int", "Short"):
schema = vol.Schema(
{
vol.Required(param["label"], default=param["value"]): vol.All(
vol.Coerce(int), vol.Range(min=param["min"], max=param["max"])
)
}
)
data = {param["label"]: param["value"]}
if param["type"] == "List":
for options in param["options"]:
if options["Label"] == param["value"]:
selected = options
break
schema = vol.Schema(
{
vol.Required(param["label"],): vol.In(
{
option["Value"]: option["Label"]
for option in param["options"]
}
)
}
)
data = {param["label"]: selected["Value"]}
config_params.append(
{
"type": param["type"],
"label": param["label"],
"parameter": param["parameter"],
"help": param["help"],
"value": param["value"],
"schema": voluptuous_serialize.convert(
schema, custom_serializer=cv.custom_serializer
),
"data": data,
}
)
return config_params
@websocket_api.websocket_command({vol.Required(TYPE): "ozw/get_instances"})
def websocket_get_instances(hass, connection, msg):
"""Get a list of OZW instances."""
manager = hass.data[DOMAIN][MANAGER]
instances = []
for instance in manager.collections["instance"]:
instances.append(dict(instance.get_status().data, ozw_instance=instance.id))
connection.send_result(
msg[ID],
instances,
)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/get_nodes",
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
}
)
def websocket_get_nodes(hass, connection, msg):
"""Get a list of nodes for an OZW instance."""
manager = hass.data[DOMAIN][MANAGER]
nodes = []
for node in manager.get_instance(msg[OZW_INSTANCE]).collections["node"]:
nodes.append(
{
ATTR_NODE_QUERY_STAGE: node.node_query_stage,
NODE_ID: node.node_id,
ATTR_IS_ZWAVE_PLUS: node.is_zwave_plus,
ATTR_IS_AWAKE: node.is_awake,
ATTR_IS_FAILED: node.is_failed,
ATTR_NODE_BAUD_RATE: node.node_baud_rate,
ATTR_IS_BEAMING: node.is_beaming,
ATTR_IS_FLIRS: node.is_flirs,
ATTR_IS_ROUTING: node.is_routing,
ATTR_IS_SECURITYV1: node.is_securityv1,
ATTR_NODE_BASIC_STRING: node.node_basic_string,
ATTR_NODE_GENERIC_STRING: node.node_generic_string,
ATTR_NODE_SPECIFIC_STRING: node.node_specific_string,
ATTR_NODE_MANUFACTURER_NAME: node.node_manufacturer_name,
ATTR_NODE_PRODUCT_NAME: node.node_product_name,
ATTR_NEIGHBORS: node.neighbors,
OZW_INSTANCE: msg[OZW_INSTANCE],
}
)
connection.send_result(
msg[ID],
nodes,
)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/set_usercode",
vol.Required(NODE_ID): vol.Coerce(int),
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
vol.Required(ATTR_CODE_SLOT): vol.Coerce(int),
vol.Required(ATTR_USERCODE): cv.string,
}
)
def websocket_set_usercode(hass, connection, msg):
"""Set a usercode to a node code slot."""
_call_util_function(
hass, connection, msg, False, set_usercode, msg[ATTR_CODE_SLOT], ATTR_USERCODE
)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/clear_usercode",
vol.Required(NODE_ID): vol.Coerce(int),
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
vol.Required(ATTR_CODE_SLOT): vol.Coerce(int),
}
)
def websocket_clear_usercode(hass, connection, msg):
"""Clear a node code slot."""
_call_util_function(
hass, connection, msg, False, clear_usercode, msg[ATTR_CODE_SLOT]
)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/get_code_slots",
vol.Required(NODE_ID): vol.Coerce(int),
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
}
)
def websocket_get_code_slots(hass, connection, msg):
"""Get status of node's code slots."""
_call_util_function(hass, connection, msg, True, get_code_slots)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/get_config_parameters",
vol.Required(NODE_ID): vol.Coerce(int),
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
}
)
def websocket_get_config_parameters(hass, connection, msg):
"""Get a list of configuration parameters for an OZW node instance."""
_call_util_function(hass, connection, msg, True, _get_config_params)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/set_config_parameter",
vol.Required(NODE_ID): vol.Coerce(int),
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
vol.Required(PARAMETER): vol.Coerce(int),
vol.Required(VALUE): vol.Any(
vol.All(
cv.ensure_list,
[
vol.All(
{
vol.Exclusive(ATTR_LABEL, "bit"): cv.string,
vol.Exclusive(ATTR_POSITION, "bit"): vol.Coerce(int),
vol.Required(ATTR_VALUE): bool,
},
cv.has_at_least_one_key(ATTR_LABEL, ATTR_POSITION),
)
],
),
vol.Coerce(int),
bool,
cv.string,
),
}
)
def websocket_set_config_parameter(hass, connection, msg):
"""Set a config parameter to a node."""
_call_util_function(
hass, connection, msg, True, set_config_parameter, msg[PARAMETER], msg[VALUE]
)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/network_status",
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
}
)
def websocket_network_status(hass, connection, msg):
"""Get Z-Wave network status."""
manager = hass.data[DOMAIN][MANAGER]
status = manager.get_instance(msg[OZW_INSTANCE]).get_status().data
connection.send_result(
msg[ID],
dict(status, ozw_instance=msg[OZW_INSTANCE]),
)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/network_statistics",
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
}
)
def websocket_network_statistics(hass, connection, msg):
"""Get Z-Wave network statistics."""
manager = hass.data[DOMAIN][MANAGER]
statistics = manager.get_instance(msg[OZW_INSTANCE]).get_statistics().data
node_count = len(
manager.get_instance(msg[OZW_INSTANCE]).collections["node"].collection
)
connection.send_result(
msg[ID],
dict(statistics, ozw_instance=msg[OZW_INSTANCE], node_count=node_count),
)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/node_status",
vol.Required(NODE_ID): vol.Coerce(int),
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
}
)
def websocket_node_status(hass, connection, msg):
"""Get the status for a Z-Wave node."""
try:
node = get_node_from_manager(
hass.data[DOMAIN][MANAGER], msg[OZW_INSTANCE], msg[NODE_ID]
)
except NotFoundError as err:
connection.send_error(
msg[ID],
websocket_api.const.ERR_NOT_FOUND,
err.args[0],
)
return
connection.send_result(
msg[ID],
{
ATTR_NODE_QUERY_STAGE: node.node_query_stage,
NODE_ID: node.node_id,
ATTR_IS_ZWAVE_PLUS: node.is_zwave_plus,
ATTR_IS_AWAKE: node.is_awake,
ATTR_IS_FAILED: node.is_failed,
ATTR_NODE_BAUD_RATE: node.node_baud_rate,
ATTR_IS_BEAMING: node.is_beaming,
ATTR_IS_FLIRS: node.is_flirs,
ATTR_IS_ROUTING: node.is_routing,
ATTR_IS_SECURITYV1: node.is_securityv1,
ATTR_NODE_BASIC_STRING: node.node_basic_string,
ATTR_NODE_GENERIC_STRING: node.node_generic_string,
ATTR_NODE_SPECIFIC_STRING: node.node_specific_string,
ATTR_NODE_MANUFACTURER_NAME: node.node_manufacturer_name,
ATTR_NODE_PRODUCT_NAME: node.node_product_name,
ATTR_NEIGHBORS: node.neighbors,
OZW_INSTANCE: msg[OZW_INSTANCE],
},
)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/node_metadata",
vol.Required(NODE_ID): vol.Coerce(int),
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
}
)
def websocket_node_metadata(hass, connection, msg):
"""Get the metadata for a Z-Wave node."""
try:
node = get_node_from_manager(
hass.data[DOMAIN][MANAGER], msg[OZW_INSTANCE], msg[NODE_ID]
)
except NotFoundError as err:
connection.send_error(
msg[ID],
websocket_api.const.ERR_NOT_FOUND,
err.args[0],
)
return
connection.send_result(
msg[ID],
{
"metadata": node.meta_data,
NODE_ID: node.node_id,
OZW_INSTANCE: msg[OZW_INSTANCE],
},
)
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/node_statistics",
vol.Required(NODE_ID): vol.Coerce(int),
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
}
)
def websocket_node_statistics(hass, connection, msg):
"""Get the statistics for a Z-Wave node."""
manager = hass.data[DOMAIN][MANAGER]
stats = (
manager.get_instance(msg[OZW_INSTANCE]).get_node(msg[NODE_ID]).get_statistics()
)
connection.send_result(
msg[ID],
{
NODE_ID: msg[NODE_ID],
"send_count": stats.send_count,
"sent_failed": stats.sent_failed,
"retries": stats.retries,
"last_request_rtt": stats.last_request_rtt,
"last_response_rtt": stats.last_response_rtt,
"average_request_rtt": stats.average_request_rtt,
"average_response_rtt": stats.average_response_rtt,
"received_packets": stats.received_packets,
"received_dup_packets": stats.received_dup_packets,
"received_unsolicited": stats.received_unsolicited,
OZW_INSTANCE: msg[OZW_INSTANCE],
},
)
@websocket_api.require_admin
@websocket_api.websocket_command(
{
vol.Required(TYPE): "ozw/refresh_node_info",
vol.Optional(OZW_INSTANCE, default=1): vol.Coerce(int),
vol.Required(NODE_ID): vol.Coerce(int),
}
)
def websocket_refresh_node_info(hass, connection, msg):
"""Tell OpenZWave to re-interview a node."""
manager = hass.data[DOMAIN][MANAGER]
options = manager.options
@callback
def forward_node(node):
"""Forward node events to websocket."""
if node.node_id != msg[NODE_ID]:
return
forward_data = {
"type": "node_updated",
ATTR_NODE_QUERY_STAGE: node.node_query_stage,
}
connection.send_message(websocket_api.event_message(msg["id"], forward_data))
@callback
def async_cleanup() -> None:
"""Remove signal listeners."""
for unsub in unsubs:
unsub()
connection.subscriptions[msg["id"]] = async_cleanup
unsubs = [
options.listen(EVENT_NODE_CHANGED, forward_node),
options.listen(EVENT_NODE_ADDED, forward_node),
]
instance = manager.get_instance(msg[OZW_INSTANCE])
instance.refresh_node(msg[NODE_ID])
connection.send_result(msg["id"])

View File

@ -245,7 +245,6 @@ FLOWS = [
"overkiz",
"ovo_energy",
"owntracks",
"ozw",
"p1_monitor",
"panasonic_viera",
"philips_js",

View File

@ -2612,15 +2612,6 @@ ignore_errors = true
[mypy-homeassistant.components.onvif.sensor]
ignore_errors = true
[mypy-homeassistant.components.ozw]
ignore_errors = true
[mypy-homeassistant.components.ozw.climate]
ignore_errors = true
[mypy-homeassistant.components.ozw.entity]
ignore_errors = true
[mypy-homeassistant.components.philips_js]
ignore_errors = true

View File

@ -1905,9 +1905,6 @@ python-mystrom==1.1.2
# homeassistant.components.nest
python-nest==4.2.0
# homeassistant.components.ozw
python-openzwave-mqtt[mqtt-client]==1.4.0
# homeassistant.components.picnic
python-picnic-api==1.1.0

View File

@ -1226,9 +1226,6 @@ python-miio==0.5.11
# homeassistant.components.nest
python-nest==4.2.0
# homeassistant.components.ozw
python-openzwave-mqtt[mqtt-client]==1.4.0
# homeassistant.components.picnic
python-picnic-api==1.1.0

View File

@ -112,9 +112,6 @@ IGNORED_MODULES: Final[list[str]] = [
"homeassistant.components.onvif.models",
"homeassistant.components.onvif.parsers",
"homeassistant.components.onvif.sensor",
"homeassistant.components.ozw",
"homeassistant.components.ozw.climate",
"homeassistant.components.ozw.entity",
"homeassistant.components.philips_js",
"homeassistant.components.philips_js.config_flow",
"homeassistant.components.philips_js.device_trigger",

View File

@ -1 +0,0 @@
"""Tests for the OZW integration."""

View File

@ -1,62 +0,0 @@
"""Helpers for tests."""
import json
from unittest.mock import Mock, patch
from homeassistant import config_entries
from homeassistant.components.ozw.const import DOMAIN
from tests.common import MockConfigEntry
async def setup_ozw(hass, entry=None, fixture=None):
"""Set up OZW and load a dump."""
mqtt_entry = MockConfigEntry(
domain="mqtt", state=config_entries.ConfigEntryState.LOADED
)
mqtt_entry.add_to_hass(hass)
if entry is None:
entry = MockConfigEntry(
domain=DOMAIN,
title="Z-Wave",
)
entry.add_to_hass(hass)
with patch("homeassistant.components.mqtt.async_subscribe") as mock_subscribe:
mock_subscribe.return_value = Mock()
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert "ozw" in hass.config.components
assert len(mock_subscribe.mock_calls) == 1
receive_message = mock_subscribe.mock_calls[0][1][2]
if fixture is not None:
for line in fixture.split("\n"):
line = line.strip()
if not line:
continue
topic, payload = line.split(",", 1)
receive_message(Mock(topic=topic, payload=payload))
await hass.async_block_till_done()
return receive_message
class MQTTMessage:
"""Represent a mock MQTT message."""
def __init__(self, topic, payload):
"""Set up message."""
self.topic = topic
self.payload = payload
def decode(self):
"""Decode message payload from a string to a json dict."""
self.payload = json.loads(self.payload)
def encode(self):
"""Encode message payload into a string."""
self.payload = json.dumps(self.payload)

View File

@ -1,280 +0,0 @@
"""Helpers for tests."""
import json
from unittest.mock import patch
import pytest
from homeassistant.config_entries import ConfigEntryState
from .common import MQTTMessage
from tests.common import MockConfigEntry, load_fixture
from tests.components.light.conftest import mock_light_profiles # noqa: F401
@pytest.fixture(name="generic_data", scope="session")
def generic_data_fixture():
"""Load generic MQTT data and return it."""
return load_fixture("ozw/generic_network_dump.csv")
@pytest.fixture(name="migration_data", scope="session")
def migration_data_fixture():
"""Load migration MQTT data and return it."""
return load_fixture("ozw/migration_fixture.csv")
@pytest.fixture(name="fan_data", scope="session")
def fan_data_fixture():
"""Load fan MQTT data and return it."""
return load_fixture("ozw/fan_network_dump.csv")
@pytest.fixture(name="light_data", scope="session")
def light_data_fixture():
"""Load light dimmer MQTT data and return it."""
return load_fixture("ozw/light_network_dump.csv")
@pytest.fixture(name="light_new_ozw_data", scope="session")
def light_new_ozw_data_fixture():
"""Load light dimmer MQTT data and return it."""
return load_fixture("ozw/light_new_ozw_network_dump.csv")
@pytest.fixture(name="light_no_ww_data", scope="session")
def light_no_ww_data_fixture():
"""Load light dimmer MQTT data and return it."""
return load_fixture("ozw/light_no_ww_network_dump.csv")
@pytest.fixture(name="light_no_cw_data", scope="session")
def light_no_cw_data_fixture():
"""Load light dimmer MQTT data and return it."""
return load_fixture("ozw/light_no_cw_network_dump.csv")
@pytest.fixture(name="light_wc_data", scope="session")
def light_wc_only_data_fixture():
"""Load light dimmer MQTT data and return it."""
return load_fixture("ozw/light_wc_network_dump.csv")
@pytest.fixture(name="cover_data", scope="session")
def cover_data_fixture():
"""Load cover MQTT data and return it."""
return load_fixture("ozw/cover_network_dump.csv")
@pytest.fixture(name="cover_gdo_data", scope="session")
def cover_gdo_data_fixture():
"""Load cover_gdo MQTT data and return it."""
return load_fixture("ozw/cover_gdo_network_dump.csv")
@pytest.fixture(name="climate_data", scope="session")
def climate_data_fixture():
"""Load climate MQTT data and return it."""
return load_fixture("ozw/climate_network_dump.csv")
@pytest.fixture(name="lock_data", scope="session")
def lock_data_fixture():
"""Load lock MQTT data and return it."""
return load_fixture("ozw/lock_network_dump.csv")
@pytest.fixture(name="string_sensor_data", scope="session")
def string_sensor_fixture():
"""Load string sensor MQTT data and return it."""
return load_fixture("ozw/sensor_string_value_network_dump.csv")
@pytest.fixture(name="sent_messages")
def sent_messages_fixture():
"""Fixture to capture sent messages."""
sent_messages = []
with patch(
"homeassistant.components.mqtt.async_publish",
side_effect=lambda hass, topic, payload: sent_messages.append(
{"topic": topic, "payload": json.loads(payload)}
),
):
yield sent_messages
@pytest.fixture(name="fan_msg")
async def fan_msg_fixture(hass):
"""Return a mock MQTT msg with a fan actuator message."""
fan_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/fan.json")
)
message = MQTTMessage(topic=fan_json["topic"], payload=fan_json["payload"])
message.encode()
return message
@pytest.fixture(name="light_msg")
async def light_msg_fixture(hass):
"""Return a mock MQTT msg with a light actuator message."""
light_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/light.json")
)
message = MQTTMessage(topic=light_json["topic"], payload=light_json["payload"])
message.encode()
return message
@pytest.fixture(name="light_no_rgb_msg")
async def light_no_rgb_msg_fixture(hass):
"""Return a mock MQTT msg with a light actuator message."""
light_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/light_no_rgb.json")
)
message = MQTTMessage(topic=light_json["topic"], payload=light_json["payload"])
message.encode()
return message
@pytest.fixture(name="light_rgb_msg")
async def light_rgb_msg_fixture(hass):
"""Return a mock MQTT msg with a light actuator message."""
light_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/light_rgb.json")
)
message = MQTTMessage(topic=light_json["topic"], payload=light_json["payload"])
message.encode()
return message
@pytest.fixture(name="light_pure_rgb_msg")
async def light_pure_rgb_msg_fixture(hass):
"""Return a mock MQTT msg with a pure rgb light actuator message."""
light_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/light_pure_rgb.json")
)
message = MQTTMessage(topic=light_json["topic"], payload=light_json["payload"])
message.encode()
return message
@pytest.fixture(name="switch_msg")
async def switch_msg_fixture(hass):
"""Return a mock MQTT msg with a switch actuator message."""
switch_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/switch.json")
)
message = MQTTMessage(topic=switch_json["topic"], payload=switch_json["payload"])
message.encode()
return message
@pytest.fixture(name="sensor_msg")
async def sensor_msg_fixture(hass):
"""Return a mock MQTT msg with a sensor change message."""
sensor_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/sensor.json")
)
message = MQTTMessage(topic=sensor_json["topic"], payload=sensor_json["payload"])
message.encode()
return message
@pytest.fixture(name="binary_sensor_msg")
async def binary_sensor_msg_fixture(hass):
"""Return a mock MQTT msg with a binary_sensor change message."""
sensor_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/binary_sensor.json")
)
message = MQTTMessage(topic=sensor_json["topic"], payload=sensor_json["payload"])
message.encode()
return message
@pytest.fixture(name="binary_sensor_alt_msg")
async def binary_sensor_alt_msg_fixture(hass):
"""Return a mock MQTT msg with a binary_sensor change message."""
sensor_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/binary_sensor_alt.json")
)
message = MQTTMessage(topic=sensor_json["topic"], payload=sensor_json["payload"])
message.encode()
return message
@pytest.fixture(name="cover_msg")
async def cover_msg_fixture(hass):
"""Return a mock MQTT msg with a cover level change message."""
sensor_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/cover.json")
)
message = MQTTMessage(topic=sensor_json["topic"], payload=sensor_json["payload"])
message.encode()
return message
@pytest.fixture(name="cover_gdo_msg")
async def cover_gdo_msg_fixture(hass):
"""Return a mock MQTT msg with a cover barrier state change message."""
sensor_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/cover_gdo.json")
)
message = MQTTMessage(topic=sensor_json["topic"], payload=sensor_json["payload"])
message.encode()
return message
@pytest.fixture(name="climate_msg")
async def climate_msg_fixture(hass):
"""Return a mock MQTT msg with a climate mode change message."""
sensor_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/climate.json")
)
message = MQTTMessage(topic=sensor_json["topic"], payload=sensor_json["payload"])
message.encode()
return message
@pytest.fixture(name="lock_msg")
async def lock_msg_fixture(hass):
"""Return a mock MQTT msg with a lock actuator message."""
lock_json = json.loads(
await hass.async_add_executor_job(load_fixture, "ozw/lock.json")
)
message = MQTTMessage(topic=lock_json["topic"], payload=lock_json["payload"])
message.encode()
return message
@pytest.fixture(name="stop_addon")
def mock_install_addon():
"""Mock stop add-on."""
with patch("homeassistant.components.hassio.async_stop_addon") as stop_addon:
yield stop_addon
@pytest.fixture(name="uninstall_addon")
def mock_uninstall_addon():
"""Mock uninstall add-on."""
with patch(
"homeassistant.components.hassio.async_uninstall_addon"
) as uninstall_addon:
yield uninstall_addon
@pytest.fixture(name="get_addon_discovery_info")
def mock_get_addon_discovery_info():
"""Mock get add-on discovery info."""
with patch(
"homeassistant.components.hassio.async_get_addon_discovery_info"
) as get_addon_discovery_info:
yield get_addon_discovery_info
@pytest.fixture(name="mqtt")
async def mock_mqtt_fixture(hass):
"""Mock the MQTT integration."""
mqtt_entry = MockConfigEntry(domain="mqtt", state=ConfigEntryState.LOADED)
mqtt_entry.add_to_hass(hass)
return mqtt_entry

View File

@ -1,38 +0,0 @@
{
"topic": "OpenZWave/1/node/37/instance/1/commandclass/113/value/1970325463777300/",
"payload": {
"Label": "Home Security",
"Value": {
"List": [
{
"Value": 0,
"Label": "Clear"
},
{
"Value": 8,
"Label": "Motion Detected at Unknown Location"
}
],
"Selected": "Motion Detected at Unknown Location",
"Selected_id": 8
},
"Units": "",
"Min": 0,
"Max": 0,
"Type": "List",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_NOTIFICATION",
"Index": 7,
"Node": 37,
"Genre": "User",
"Help": "Home Security Alerts",
"ValueIDKey": 1970325463777300,
"ReadOnly": false,
"WriteOnly": false,
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Event": "valueAdded",
"TimeStamp": 1579566891
}
}

View File

@ -1,25 +0,0 @@
{
"topic": "OpenZWave/1/node/37/instance/1/commandclass/48/value/625737744/",
"payload": {
"Label": "Sensor",
"Value": true,
"Units": "",
"Min": 0,
"Max": 0,
"Type": "Bool",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_SENSOR_BINARY",
"Index": 0,
"Node": 37,
"Genre": "User",
"Help": "Binary Sensor State",
"ValueIDKey": 625737744,
"ReadOnly": false,
"WriteOnly": false,
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Event": "valueAdded",
"TimeStamp": 1579566891
}
}

View File

@ -1,54 +0,0 @@
{
"topic": "OpenZWave/1/node/7/instance/1/commandclass/64/value/122683412/",
"payload": {
"Label": "Mode",
"Value": {
"List": [
{
"Value": 0,
"Label": "Off"
},
{
"Value": 1,
"Label": "Heat"
},
{
"Value": 2,
"Label": "Cool"
},
{
"Value": 3,
"Label": "Auto"
},
{
"Value": 11,
"Label": "Heat Econ"
},
{
"Value": 12,
"Label": "Cool Econ"
}
],
"Selected": "Auto",
"Selected_id": 3
},
"Units": "",
"Min": 0,
"Max": 0,
"Type": "List",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_THERMOSTAT_MODE",
"Index": 0,
"Node": 7,
"Genre": "User",
"Help": "Set the Thermostat Mode",
"ValueIDKey": 122683412,
"ReadOnly": false,
"WriteOnly": false,
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Event": "valueAdded",
"TimeStamp": 1588264894
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,25 +0,0 @@
{
"topic": "OpenZWave/1/node/37/instance/1/commandclass/38/value/625573905/",
"payload": {
"Label": "Instance 1: Level",
"Value": 0,
"Units": "",
"ValueSet": true,
"ValuePolled": false,
"ChangeVerified": false,
"Min": 0,
"Max": 255,
"Type": "Byte",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL",
"Index": 0,
"Node": 37,
"Genre": "User",
"Help": "The Current Level of the Device",
"ValueIDKey": 625573905,
"ReadOnly": false,
"WriteOnly": false,
"Event": "valueChanged",
"TimeStamp": 1593370642
}
}

View File

@ -1,54 +0,0 @@
{
"topic": "OpenZWave/1/node/6/instance/1/commandclass/102/value/281475083239444/",
"payload": {
"Label": "Barrier State",
"Value": {
"List": [
{
"Value": 0,
"Label": "Closed"
},
{
"Value": 1,
"Label": "Closing"
},
{
"Value": 2,
"Label": "Stopped"
},
{
"Value": 3,
"Label": "Opening"
},
{
"Value": 4,
"Label": "Opened"
},
{
"Value": 5,
"Label": "Unknown"
}
],
"Selected": "Closed",
"Selected_id": 0
},
"Units": "",
"ValueSet": true,
"ValuePolled": false,
"ChangeVerified": false,
"Min": 0,
"Max": 0,
"Type": "List",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_BARRIER_OPERATOR",
"Index": 1,
"Node": 6,
"Genre": "User",
"Help": "The Current State of the Barrier",
"ValueIDKey": 281475083239444,
"ReadOnly": false,
"WriteOnly": false,
"Event": "valueChanged",
"TimeStamp": 1593634453
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,25 +0,0 @@
{
"topic": "OpenZWave/1/node/10/instance/1/commandclass/38/value/172589073/",
"payload": {
"Label": "Level",
"Value": 41,
"Units": "",
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Min": 0,
"Max": 255,
"Type": "Byte",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL",
"Index": 0,
"Node": 10,
"Genre": "User",
"Help": "The Current Level of the Device",
"ValueIDKey": 172589073,
"ReadOnly": false,
"WriteOnly": false,
"Event": "valueAdded",
"TimeStamp": 1589997977
}
}

View File

@ -1,51 +0,0 @@
OpenZWave/1/status/,{ "OpenZWave_Version": "1.6.1123", "OZWDaemon_Version": "0.1.98", "QTOpenZWave_Version": "1.0.0", "QT_Version": "5.12.5", "Status": "driverAllNodesQueried", "TimeStamp": 1589998153, "ManufacturerSpecificDBReady": true, "homeID": 4188283268, "getControllerNodeId": 1, "getSUCNodeId": 1, "isPrimaryController": true, "isBridgeController": false, "hasExtendedTXStatistics": false, "getControllerLibraryVersion": "Z-Wave 4.54", "getControllerLibraryType": "Static Controller", "getControllerPath": "/dev/ttyACM0"}
OpenZWave/1/node/10/,{ "NodeID": 10, "NodeQueryStage": "Complete", "isListening": true, "isFlirs": false, "isBeaming": true, "isRouting": true, "isSecurityv1": false, "isZWavePlus": true, "isNIFRecieved": true, "isAwake": true, "isFailed": false, "MetaData": { "OZWInfoURL": "http://www.openzwave.com/device-database/0063:3031:4944", "ZWAProductURL": "", "ProductPic": "images/ge/12724-dimmer.png", "Description": "Transform any home into a smart home with the GE Z-Wave Smart Fan Control. The in-wall fan control easily replaces any standard in-wall switch remotely controls a ceiling fan in your home and features a three-speed control system. Your home will be equipped with ultimate flexibility with the GE Z-Wave Smart Fan Control, capable of being used by itself or with up to four GE add-on switches. Screw terminal installation provides improved space efficiency when replacing existing switches and the integrated LED indicator light allows you to easily locate the switch in a dark room. The GE Z-Wave Smart Fan Control is compatible with any Z-Wave certified gateway, providing access to many popular home automation systems. Take control of your home lighting with GE Z-Wave Smart Lighting Controls!", "ProductManualURL": "https://Products.Z-WaveAlliance.org/ProductManual/File?folder=&filename=Manuals/2506/Binder2.pdf", "ProductPageURL": "http://www.ezzwave.com", "InclusionHelp": "1. Follow the instructions for your Z-Wave certified controller to include a device to the Z-Wave network. 2. Once the controller is ready to include your device, press and release the top or bottom of the smart fan control switch (rocker) to include it in the network. 3. Once your controller has confirmed the device has been included, refresh the Z-Wave network to optimize performance.", "ExclusionHelp": "1. Follow the instructions for your Z-Wave certified controller to exclude a device from the Z-Wave network. 2. Once the controller is ready to Exclude your device, press and release the top or bottom of the wireless smart switch (rocker) to exclude it from the network.", "ResetHelp": "1. Quickly press ON (Top) button three (3) times then immediately press the OFF (Bottom) button three (3) times. The LED will flash ON/OFF 5 times when completed successfully. Note: This should only be used in the event your networks primary controller is missing or otherwise inoperable.", "WakeupHelp": "", "ProductSupportURL": "", "Frequency": "", "Name": "In-Wall Smart Fan Control" }, "Event": "nodeQueriesComplete", "TimeStamp": 1589998151, "NodeManufacturerName": "GE (Jasco Products)", "NodeProductName": "14287 Fan Control Switch", "NodeBasicString": "Routing Slave", "NodeBasic": 4, "NodeGenericString": "Multilevel Switch", "NodeGeneric": 17, "NodeSpecificString": "Fan Switch", "NodeSpecific": 8, "NodeManufacturerID": "0x0063", "NodeProductType": "0x4944", "NodeProductID": "0x3131", "NodeBaudRate": 100000, "NodeVersion": 4, "NodeGroups": 3, "NodeName": "", "NodeLocation": "", "NodeDeviceTypeString": "Fan Switch", "NodeDeviceType": 1024, "NodeRole": 5, "NodeRoleString": "Always On Slave", "NodePlusType": 0, "NodePlusTypeString": "Z-Wave+ node", "Neighbors": [ 1, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 29, 30, 32, 33 ]}
OpenZWave/1/node/10/instance/1/,{ "Instance": 1, "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/38/,{ "Instance": 1, "CommandClassId": 38, "CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL", "CommandClassVersion": 1, "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/38/value/172589073/,{ "Label": "Level", "Value": 41, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL", "Index": 0, "Node": 10, "Genre": "User", "Help": "The Current Level of the Device", "ValueIDKey": 172589073, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/38/value/281475149299736/,{ "Label": "Bright", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL", "Index": 1, "Node": 10, "Genre": "User", "Help": "Increase the Brightness of the Device", "ValueIDKey": 281475149299736, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/38/value/562950126010392/,{ "Label": "Dim", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL", "Index": 2, "Node": 10, "Genre": "User", "Help": "Decrease the Brightness of the Device", "ValueIDKey": 562950126010392, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/38/value/844425111109648/,{ "Label": "Ignore Start Level", "Value": true, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Bool", "Instance": 1, "CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL", "Index": 3, "Node": 10, "Genre": "System", "Help": "Ignore the Start Level of the Device when increasing/decreasing brightness", "ValueIDKey": 844425111109648, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/38/value/1125900087820305/,{ "Label": "Start Level", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL", "Index": 4, "Node": 10, "Genre": "System", "Help": "Start Level when Changing the Brightness of a Device", "ValueIDKey": 1125900087820305, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/39/,{ "Instance": 1, "CommandClassId": 39, "CommandClass": "COMMAND_CLASS_SWITCH_ALL", "CommandClassVersion": 1, "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/39/value/180994068/,{ "Label": "Switch All", "Value": { "List": [ { "Value": 0, "Label": "Disabled" }, { "Value": 1, "Label": "Off Enabled" }, { "Value": 2, "Label": "On Enabled" }, { "Value": 255, "Label": "On and Off Enabled" } ], "Selected": "On and Off Enabled", "Selected_id": 255 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_SWITCH_ALL", "Index": 0, "Node": 10, "Genre": "System", "Help": "Switch All Devices On/Off", "ValueIDKey": 180994068, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/43/,{ "Instance": 1, "CommandClassId": 43, "CommandClass": "COMMAND_CLASS_SCENE_ACTIVATION", "CommandClassVersion": 1, "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/43/value/172670995/,{ "Label": "Scene", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -2147483648, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_SCENE_ACTIVATION", "Index": 0, "Node": 10, "Genre": "User", "Help": "", "ValueIDKey": 172670995, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/43/value/281475149381651/,{ "Label": "Duration", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -2147483648, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_SCENE_ACTIVATION", "Index": 1, "Node": 10, "Genre": "User", "Help": "", "ValueIDKey": 281475149381651, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/94/,{ "Instance": 1, "CommandClassId": 94, "CommandClass": "COMMAND_CLASS_ZWAVEPLUS_INFO", "CommandClassVersion": 1, "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/94/value/181895185/,{ "Label": "ZWave+ Version", "Value": 1, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_ZWAVEPLUS_INFO", "Index": 0, "Node": 10, "Genre": "System", "Help": "ZWave+ Version Supported on the Device", "ValueIDKey": 181895185, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/94/value/281475158605846/,{ "Label": "InstallerIcon", "Value": 1024, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_ZWAVEPLUS_INFO", "Index": 1, "Node": 10, "Genre": "System", "Help": "Icon File to use for the Installer Application", "ValueIDKey": 281475158605846, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/94/value/562950135316502/,{ "Label": "UserIcon", "Value": 1024, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_ZWAVEPLUS_INFO", "Index": 2, "Node": 10, "Genre": "System", "Help": "Icon File to use for the User Application", "ValueIDKey": 562950135316502, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/112/,{ "Instance": 1, "CommandClassId": 112, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "CommandClassVersion": 1, "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/112/value/844425108127764/,{ "Label": "LED Light", "Value": { "List": [ { "Value": 0, "Label": "LED on when light off" }, { "Value": 1, "Label": "LED on when light on" }, { "Value": 2, "Label": "LED always off" } ], "Selected": "LED on when light off", "Selected_id": 0 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 2, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 3, "Node": 10, "Genre": "Config", "Help": "Sets when the LED on the switch is lit.", "ValueIDKey": 844425108127764, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/112/value/1125900084838420/,{ "Label": "Invert Switch", "Value": { "List": [ { "Value": 0, "Label": "No" }, { "Value": 1, "Label": "Yes" } ], "Selected": "No", "Selected_id": 0 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 1, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 4, "Node": 10, "Genre": "Config", "Help": "Change the top of the switch to OFF and the bottom of the switch to ON, if the switch was installed upside down.", "ValueIDKey": 1125900084838420, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/112/value/1970325014970385/,{ "Label": "Z-Wave Command Dim Step", "Value": 1, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 1, "Max": 99, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 7, "Node": 10, "Genre": "Config", "Help": "Indicates how many levels the dimmer will change for each dimming step.", "ValueIDKey": 1970325014970385, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/112/value/2251799991681041/,{ "Label": "Z-Wave Command Dim Rate", "Value": 3, "Units": "x 10 milliseconds", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 1, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 8, "Node": 10, "Genre": "Config", "Help": "This value indicates in 10 millisecond resolution, how often the dim level will change. For example, if you set this parameter to 1, then every 10ms the dim level will change. If you set it to 255, then every 2.55 seconds the dim level will change.", "ValueIDKey": 2251799991681041, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/112/value/2533274968391697/,{ "Label": "Local Control Dim Step", "Value": 1, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 1, "Max": 99, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 9, "Node": 10, "Genre": "Config", "Help": "Indicates how many levels the dimmer will change for each dimming step.", "ValueIDKey": 2533274968391697, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/112/value/2814749945102353/,{ "Label": "Local Control Dim Rate", "Value": 3, "Units": "x 10 milliseconds", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 1, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 10, "Node": 10, "Genre": "Config", "Help": "This value indicates in 10 millisecond resolution, how often the dim level will change. For example, if you set this parameter to 1, then every 10ms the dim level will change. If you set it to 255, then every 2.55 seconds the dim level will change.", "ValueIDKey": 2814749945102353, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/112/value/3096224921813009/,{ "Label": "ALL ON/ALL OFF Dim Step", "Value": 1, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 1, "Max": 99, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 11, "Node": 10, "Genre": "Config", "Help": "Indicates how many levels the dimmer will change for each dimming step.", "ValueIDKey": 3096224921813009, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/112/value/3377699898523665/,{ "Label": "ALL ON/ALL OFF Dim Rate", "Value": 3, "Units": "x 10 milliseconds", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 1, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 12, "Node": 10, "Genre": "Config", "Help": "This value indicates in 10 millisecond resolution, how often the dim level will change. For example, if you set this parameter to 1, then every 10ms the dim level will change. If you set it to 255, then every 2.55 seconds the dim level will change.", "ValueIDKey": 3377699898523665, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/114/,{ "Instance": 1, "CommandClassId": 114, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "CommandClassVersion": 2, "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/114/value/182222867/,{ "Label": "Loaded Config Revision", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -2147483648, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 0, "Node": 10, "Genre": "System", "Help": "Revision of the Config file currently loaded", "ValueIDKey": 182222867, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/114/value/281475158933523/,{ "Label": "Config File Revision", "Value": 9, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -2147483648, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 1, "Node": 10, "Genre": "System", "Help": "Revision of the Config file on the File System", "ValueIDKey": 281475158933523, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/114/value/562950135644179/,{ "Label": "Latest Available Config File Revision", "Value": 9, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -2147483648, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 2, "Node": 10, "Genre": "System", "Help": "Latest Revision of the Config file available for download", "ValueIDKey": 562950135644179, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/114/value/844425112354839/,{ "Label": "Device ID", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 3, "Node": 10, "Genre": "System", "Help": "Manufacturer Specific Device ID/Model", "ValueIDKey": 844425112354839, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/114/value/1125900089065495/,{ "Label": "Serial Number", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 4, "Node": 10, "Genre": "System", "Help": "Device Serial Number", "ValueIDKey": 1125900089065495, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/,{ "Instance": 1, "CommandClassId": 115, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "CommandClassVersion": 1, "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/182239252/,{ "Label": "Powerlevel", "Value": { "List": [ { "Value": 0, "Label": "Normal" }, { "Value": 1, "Label": "-1dB" }, { "Value": 2, "Label": "-2dB" }, { "Value": 3, "Label": "-3dB" }, { "Value": 4, "Label": "-4dB" }, { "Value": 5, "Label": "-5dB" }, { "Value": 6, "Label": "-6dB" }, { "Value": 7, "Label": "-7dB" }, { "Value": 8, "Label": "-8dB" }, { "Value": 9, "Label": "-9dB" } ], "Selected": "Normal", "Selected_id": 0 }, "Units": "dB", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 0, "Node": 10, "Genre": "System", "Help": "Output RF PowerLevel", "ValueIDKey": 182239252, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/281475158949905/,{ "Label": "Timeout", "Value": 0, "Units": "seconds", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 1, "Node": 10, "Genre": "System", "Help": "Timeout till the PowerLevel is reset to Normal", "ValueIDKey": 281475158949905, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/562950135660568/,{ "Label": "Set Powerlevel", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 2, "Node": 10, "Genre": "System", "Help": "Apply the Output PowerLevel and Timeout Values", "ValueIDKey": 562950135660568, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/844425112371217/,{ "Label": "Test Node", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 3, "Node": 10, "Genre": "System", "Help": "Node to Perform a test against", "ValueIDKey": 844425112371217, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/1125900089081876/,{ "Label": "Test Powerlevel", "Value": { "List": [ { "Value": 0, "Label": "Normal" }, { "Value": 1, "Label": "-1dB" }, { "Value": 2, "Label": "-2dB" }, { "Value": 3, "Label": "-3dB" }, { "Value": 4, "Label": "-4dB" }, { "Value": 5, "Label": "-5dB" }, { "Value": 6, "Label": "-6dB" }, { "Value": 7, "Label": "-7dB" }, { "Value": 8, "Label": "-8dB" }, { "Value": 9, "Label": "-9dB" } ], "Selected": "Normal", "Selected_id": 0 }, "Units": "dB", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 4, "Node": 10, "Genre": "System", "Help": "PowerLevel to use for the Test", "ValueIDKey": 1125900089081876, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/1407375065792534/,{ "Label": "Frame Count", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 5, "Node": 10, "Genre": "System", "Help": "How Many Messages to send to the Node for the Test", "ValueIDKey": 1407375065792534, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/1688850042503192/,{ "Label": "Test", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 6, "Node": 10, "Genre": "System", "Help": "Perform a PowerLevel Test against the a Node", "ValueIDKey": 1688850042503192, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/1970325019213848/,{ "Label": "Report", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 7, "Node": 10, "Genre": "System", "Help": "Get the results of the latest PowerLevel Test against a Node", "ValueIDKey": 1970325019213848, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/2251799995924500/,{ "Label": "Test Status", "Value": { "List": [ { "Value": 0, "Label": "Failed" }, { "Value": 1, "Label": "Success" }, { "Value": 2, "Label": "In Progress" } ], "Selected": "Failed", "Selected_id": 0 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 8, "Node": 10, "Genre": "System", "Help": "The Current Status of the last PowerNode Test Executed", "ValueIDKey": 2251799995924500, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/115/value/2533274972635158/,{ "Label": "Acked Frames", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 9, "Node": 10, "Genre": "System", "Help": "Number of Messages successfully Acked by the Target Node", "ValueIDKey": 2533274972635158, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/134/,{ "Instance": 1, "CommandClassId": 134, "CommandClass": "COMMAND_CLASS_VERSION", "CommandClassVersion": 1, "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/134/value/182550551/,{ "Label": "Library Version", "Value": "3", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_VERSION", "Index": 0, "Node": 10, "Genre": "System", "Help": "Z-Wave Library Version", "ValueIDKey": 182550551, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/134/value/281475159261207/,{ "Label": "Protocol Version", "Value": "4.54", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_VERSION", "Index": 1, "Node": 10, "Genre": "System", "Help": "Z-Wave Protocol Version", "ValueIDKey": 281475159261207, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/instance/1/commandclass/134/value/562950135971863/,{ "Label": "Application Version", "Value": "5.22", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_VERSION", "Index": 2, "Node": 10, "Genre": "System", "Help": "Application Version", "ValueIDKey": 562950135971863, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1589997977}
OpenZWave/1/node/10/association/1/,{ "Name": "Group 1", "Help": "", "MaxAssociations": 5, "Members": [ "1.0" ], "TimeStamp": 1589997977}
OpenZWave/1/node/10/association/2/,{ "Name": "Group 2", "Help": "", "MaxAssociations": 5, "Members": [], "TimeStamp": 1589998004}
OpenZWave/1/node/10/association/3/,{ "Name": "Group 3", "Help": "", "MaxAssociations": 5, "Members": [], "TimeStamp": 1589998004}
Can't render this file because it contains an unexpected character in line 1 and column 26.

File diff suppressed because one or more lines are too long

View File

@ -1,25 +0,0 @@
{
"topic": "OpenZWave/1/node/39/instance/1/commandclass/38/value/659128337/",
"payload": {
"Label": "Level",
"Value": 0,
"Units": "",
"Min": 0,
"Max": 255,
"Type": "Byte",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL",
"Index": 0,
"Node": 39,
"Genre": "User",
"Help": "The Current Level of the Device",
"ValueIDKey": 659128337,
"ReadOnly": false,
"WriteOnly": false,
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Event": "valueAdded",
"TimeStamp": 1579566891
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,25 +0,0 @@
{
"topic": "OpenZWave/1/node/2/instance/1/commandclass/38/value/38371345/",
"payload": {
"Label": "Level",
"Value": 0,
"Units": "",
"Min": 0,
"Max": 255,
"Type": "Byte",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_SWITCH_MULTILEVEL",
"Index": 0,
"Node": 2,
"Genre": "User",
"Help": "The Current Level of the Device",
"ValueIDKey": 38371345,
"ReadOnly": false,
"WriteOnly": false,
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Event": "valueAdded",
"TimeStamp": 1579566891
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,25 +0,0 @@
{
"topic": "OpenZWave/1/node/7/instance/1/commandclass/51/value/122470423/",
"payload": {
"Label": "Color",
"Value": "#ff00000000",
"Units": "#RRGGBBWW",
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Min": 0,
"Max": 0,
"Type": "String",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_COLOR",
"Index": 0,
"Node": 7,
"Genre": "User",
"Help": "Color (in RGB format)",
"ValueIDKey": 122470423,
"ReadOnly": false,
"WriteOnly": false,
"Event": "valueAdded",
"TimeStamp": 1597142799
}
}

View File

@ -1,25 +0,0 @@
{
"topic": "OpenZWave/1/node/39/instance/1/commandclass/51/value/659341335/",
"payload": {
"Label": "Color",
"Value": "#000000FF00",
"Units": "#RRGGBBWWCW",
"Min": 0,
"Max": 0,
"Type": "String",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_COLOR",
"Index": 0,
"Node": 39,
"Genre": "User",
"Help": "Color (in RGB format)",
"ValueIDKey": 659341335,
"ReadOnly": false,
"WriteOnly": false,
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Event": "valueAdded",
"TimeStamp": 1579566891
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,25 +0,0 @@
{
"topic": "OpenZWave/1/node/10/instance/1/commandclass/98/value/173572112/",
"payload": {
"Label": "Lock",
"Value": false,
"Units": "",
"Min": 0,
"Max": 0,
"Type": "Bool",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_DOOR_LOCK",
"Index": 0,
"Node": 10,
"Genre": "User",
"Help": "Lock / Unlock Device",
"ValueIDKey": 173572112,
"ReadOnly": false,
"WriteOnly": false,
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Event": "valueAdded",
"TimeStamp": 1579566891
}
}

View File

@ -1,79 +0,0 @@
OpenZWave/1/status/,{ "OpenZWave_Version": "1.6.1131", "OZWDaemon_Version": "0.1.101", "QTOpenZWave_Version": "1.0.0", "QT_Version": "5.12.5", "Status": "driverAllNodesQueriedSomeDead", "TimeStamp": 1590178891, "ManufacturerSpecificDBReady": true, "homeID": 4075923038, "getControllerNodeId": 1, "getSUCNodeId": 0, "isPrimaryController": false, "isBridgeController": false, "hasExtendedTXStatistics": true, "getControllerLibraryVersion": "Z-Wave 4.05", "getControllerLibraryType": "Static Controller", "getControllerPath": "/dev/zwave"}
OpenZWave/1/node/10/,{ "NodeID": 10, "NodeQueryStage": "Complete", "isListening": false, "isFlirs": true, "isBeaming": true, "isRouting": true, "isSecurityv1": false, "isZWavePlus": true, "isNIFRecieved": true, "isAwake": true, "isFailed": false, "MetaData": { "OZWInfoURL": "", "ZWAProductURL": "", "ProductPic": "", "Description": "", "ProductManualURL": "", "ProductPageURL": "", "InclusionHelp": "", "ExclusionHelp": "", "ResetHelp": "", "WakeupHelp": "", "ProductSupportURL": "", "Frequency": "", "Name": "", "ProductPicBase64": "" }, "Event": "nodeQueriesComplete", "TimeStamp": 1590178891, "NodeManufacturerName": "Poly-control", "NodeProductName": "Danalock V3 BTZE", "NodeBasicString": "Routing Slave", "NodeBasic": 4, "NodeGenericString": "Entry Control", "NodeGeneric": 64, "NodeSpecificString": "Secure Keypad Door Lock", "NodeSpecific": 3, "NodeManufacturerID": "0x010e", "NodeProductType": "0x0009", "NodeProductID": "0x0001", "NodeBaudRate": 100000, "NodeVersion": 4, "NodeName": "", "NodeLocation": "", "NodeGroups": 1, "NodeDeviceTypeString": "Door Lock Keypad", "NodeDeviceType": 768, "NodeRole": 7, "NodeRoleString": "Listening Sleeping Slave", "NodePlusType": 0, "NodePlusTypeString": "Z-Wave+ node", "Neighbors": [ 1, 5, 9 ]}
OpenZWave/1/node/10/instance/1/,{ "Instance": 1, "TimeStamp": 1590178857}
OpenZWave/1/node/10/instance/1/commandclass/112/,{ "Instance": 1, "CommandClassId": 112, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "CommandClassVersion": 1, "TimeStamp": 1590178855}
OpenZWave/1/node/10/instance/1/commandclass/112/value/281475154706452/,{ "Label": "Twist Assist", "Value": { "List": [ { "Value": 0, "Label": "Disabled" }, { "Value": 1, "Label": "Enabled" } ], "Selected": "Disabled", "Selected_id": 0 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 1, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 1, "Node": 10, "Genre": "Config", "Help": "", "ValueIDKey": 281475154706452, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178855}
OpenZWave/1/node/10/instance/1/commandclass/112/value/562950131417107/,{ "Label": "Hold and Release", "Value": 0, "Units": "seconds", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 2, "Node": 10, "Genre": "Config", "Help": "0 Disable. 1 to 2147483647 Enable, time in seconds.", "ValueIDKey": 562950131417107, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178855}
OpenZWave/1/node/10/instance/1/commandclass/112/value/844425108127764/,{ "Label": "Block to Block", "Value": { "List": [ { "Value": 0, "Label": "Disable" }, { "Value": 1, "Label": "Enable" } ], "Selected": "Disable", "Selected_id": 0 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 1, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 3, "Node": 10, "Genre": "Config", "Help": "", "ValueIDKey": 844425108127764, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178855}
OpenZWave/1/node/10/instance/1/commandclass/112/value/1125900084838419/,{ "Label": "BLE Temporary Allowed", "Value": 0, "Units": "seconds", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 4, "Node": 10, "Genre": "Config", "Help": "0 Disable. 1 to 2147483647 Enable, time in seconds.", "ValueIDKey": 1125900084838419, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178855}
OpenZWave/1/node/10/instance/1/commandclass/112/value/1407375061549076/,{ "Label": "BLE Always Allowed", "Value": { "List": [ { "Value": 0, "Label": "Disable" }, { "Value": 1, "Label": "Enable" } ], "Selected": "Disable", "Selected_id": 0 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 1, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 5, "Node": 10, "Genre": "Config", "Help": "", "ValueIDKey": 1407375061549076, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178855}
OpenZWave/1/node/10/instance/1/commandclass/112/value/1688850038259731/,{ "Label": "Autolock", "Value": 0, "Units": "seconds", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_CONFIGURATION", "Index": 6, "Node": 10, "Genre": "Config", "Help": "0 Disable. 1 to 2147483647 Enable, time in seconds.", "ValueIDKey": 1688850038259731, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/94/,{ "Instance": 1, "CommandClassId": 94, "CommandClass": "COMMAND_CLASS_ZWAVEPLUS_INFO", "CommandClassVersion": 1, "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/94/value/181895185/,{ "Label": "ZWave+ Version", "Value": 1, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_ZWAVEPLUS_INFO", "Index": 0, "Node": 10, "Genre": "System", "Help": "ZWave+ Version Supported on the Device", "ValueIDKey": 181895185, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/94/value/281475158605846/,{ "Label": "InstallerIcon", "Value": 768, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_ZWAVEPLUS_INFO", "Index": 1, "Node": 10, "Genre": "System", "Help": "Icon File to use for the Installer Application", "ValueIDKey": 281475158605846, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/94/value/562950135316502/,{ "Label": "UserIcon", "Value": 768, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_ZWAVEPLUS_INFO", "Index": 2, "Node": 10, "Genre": "System", "Help": "Icon File to use for the User Application", "ValueIDKey": 562950135316502, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/98/,{ "Instance": 1, "CommandClassId": 98, "CommandClass": "COMMAND_CLASS_DOOR_LOCK", "CommandClassVersion": 1, "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/98/value/173572112/,{ "Label": "Locked", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Bool", "Instance": 1, "CommandClass": "COMMAND_CLASS_DOOR_LOCK", "Index": 0, "Node": 10, "Genre": "User", "Help": "State of the Lock", "ValueIDKey": 173572112, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590345913}
OpenZWave/1/node/10/instance/1/commandclass/98/value/281475150282772/,{ "Label": "Locked (Advanced)", "Value": { "List": [ { "Value": 0, "Label": "Unsecure" }, { "Value": 1, "Label": "Unsecured with Timeout" }, { "Value": 2, "Label": "Inside Handle Unsecured" }, { "Value": 3, "Label": "Inside Handle Unsecured with Timeout" }, { "Value": 4, "Label": "Outside Handle Unsecured" }, { "Value": 5, "Label": "Outside Handle Unsecured with Timeout" }, { "Value": 6, "Label": "Secured" }, { "Value": 255, "Label": "Invalid" } ], "Selected": "Unsecure", "Selected_id": 0 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_DOOR_LOCK", "Index": 1, "Node": 10, "Genre": "User", "Help": "State of the Lock (Advanced)", "ValueIDKey": 281475150282772, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590345913}
OpenZWave/1/node/10/instance/1/commandclass/98/value/562950135382036/,{ "Label": "Timeout Mode", "Value": { "List": [ { "Value": 1, "Label": "No Timeout" }, { "Value": 2, "Label": "Secure Lock after Timeout" } ], "Selected": "No Timeout", "Selected_id": 1 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_DOOR_LOCK", "Index": 2, "Node": 10, "Genre": "System", "Help": "Timeout Mode for Reverting Lock State", "ValueIDKey": 562950135382036, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/98/value/1407375065514001/,{ "Label": "Outside Handle Control", "Value": 1, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_DOOR_LOCK", "Index": 5, "Node": 10, "Genre": "System", "Help": "State of the Exterior Handle Control", "ValueIDKey": 1407375065514001, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/98/value/1688850042224657/,{ "Label": "Inside Handle Control", "Value": 1, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_DOOR_LOCK", "Index": 6, "Node": 10, "Genre": "System", "Help": "State of the Interior Handle Control", "ValueIDKey": 1688850042224657, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/,{ "Instance": 1, "CommandClassId": 99, "CommandClass": "COMMAND_CLASS_USER_CODE", "CommandClassVersion": 1, "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/72339069196615702/,{ "Label": "Code Count", "Value": 20, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 257, "Node": 10, "Genre": "System", "Help": "Number of User Codes supported by the Device", "ValueIDKey": 72339069196615702, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/71776119243194392/,{ "Label": "Refresh All UserCodes", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 255, "Node": 10, "Genre": "System", "Help": "Refresh All UserCodes Stored on Device", "ValueIDKey": 71776119243194392, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/72057594219905046/,{ "Label": "Remove User Code", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 256, "Node": 10, "Genre": "System", "Help": "Remove A UserCode at the Specified Index", "ValueIDKey": 72057594219905046, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/173588503/,{ "Label": "Enrollment Code", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 0, "Node": 10, "Genre": "User", "Help": "Enrollment Code", "ValueIDKey": 173588503, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/281475150299159/,{ "Label": "Code 1:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 1, "Node": 10, "Genre": "User", "Help": "UserCode 1", "ValueIDKey": 281475150299159, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/562950127009815/,{ "Label": "Code 2:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 2, "Node": 10, "Genre": "User", "Help": "UserCode 2", "ValueIDKey": 562950127009815, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/844425103720471/,{ "Label": "Code 3:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 3, "Node": 10, "Genre": "User", "Help": "UserCode 3", "ValueIDKey": 844425103720471, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/1125900080431127/,{ "Label": "Code 4:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 4, "Node": 10, "Genre": "User", "Help": "UserCode 4", "ValueIDKey": 1125900080431127, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/1407375057141783/,{ "Label": "Code 5:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 5, "Node": 10, "Genre": "User", "Help": "UserCode 5", "ValueIDKey": 1407375057141783, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/1688850033852439/,{ "Label": "Code 6:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 6, "Node": 10, "Genre": "User", "Help": "UserCode 6", "ValueIDKey": 1688850033852439, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/1970325010563095/,{ "Label": "Code 7:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 7, "Node": 10, "Genre": "User", "Help": "UserCode 7", "ValueIDKey": 1970325010563095, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/2251799987273751/,{ "Label": "Code 8:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 8, "Node": 10, "Genre": "User", "Help": "UserCode 8", "ValueIDKey": 2251799987273751, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/2533274963984407/,{ "Label": "Code 9:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 9, "Node": 10, "Genre": "User", "Help": "UserCode 9", "ValueIDKey": 2533274963984407, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/2814749940695063/,{ "Label": "Code 10:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 10, "Node": 10, "Genre": "User", "Help": "UserCode 10", "ValueIDKey": 2814749940695063, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/3096224917405719/,{ "Label": "Code 11:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 11, "Node": 10, "Genre": "User", "Help": "UserCode 11", "ValueIDKey": 3096224917405719, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/3377699894116375/,{ "Label": "Code 12:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 12, "Node": 10, "Genre": "User", "Help": "UserCode 12", "ValueIDKey": 3377699894116375, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/3659174870827031/,{ "Label": "Code 13:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 13, "Node": 10, "Genre": "User", "Help": "UserCode 13", "ValueIDKey": 3659174870827031, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/3940649847537687/,{ "Label": "Code 14:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 14, "Node": 10, "Genre": "User", "Help": "UserCode 14", "ValueIDKey": 3940649847537687, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/4222124824248343/,{ "Label": "Code 15:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 15, "Node": 10, "Genre": "User", "Help": "UserCode 15", "ValueIDKey": 4222124824248343, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/4503599800958999/,{ "Label": "Code 16:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 16, "Node": 10, "Genre": "User", "Help": "UserCode 16", "ValueIDKey": 4503599800958999, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/4785074777669655/,{ "Label": "Code 17:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 17, "Node": 10, "Genre": "User", "Help": "UserCode 17", "ValueIDKey": 4785074777669655, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/5066549754380311/,{ "Label": "Code 18:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 18, "Node": 10, "Genre": "User", "Help": "UserCode 18", "ValueIDKey": 5066549754380311, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/5348024731090967/,{ "Label": "Code 19:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 19, "Node": 10, "Genre": "User", "Help": "UserCode 19", "ValueIDKey": 5348024731090967, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/99/value/5629499707801623/,{ "Label": "Code 20:", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_USER_CODE", "Index": 20, "Node": 10, "Genre": "User", "Help": "UserCode 20", "ValueIDKey": 5629499707801623, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/114/,{ "Instance": 1, "CommandClassId": 114, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "CommandClassVersion": 2, "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/114/value/182222867/,{ "Label": "Loaded Config Revision", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -2147483648, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 0, "Node": 10, "Genre": "System", "Help": "Revision of the Config file currently loaded", "ValueIDKey": 182222867, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/114/value/281475158933523/,{ "Label": "Config File Revision", "Value": 15, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -2147483648, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 1, "Node": 10, "Genre": "System", "Help": "Revision of the Config file on the File System", "ValueIDKey": 281475158933523, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/114/value/562950135644179/,{ "Label": "Latest Available Config File Revision", "Value": 15, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -2147483648, "Max": 2147483647, "Type": "Int", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 2, "Node": 10, "Genre": "System", "Help": "Latest Revision of the Config file available for download", "ValueIDKey": 562950135644179, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/114/value/844425112354839/,{ "Label": "Device ID", "Value": "", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 3, "Node": 10, "Genre": "System", "Help": "Manufacturer Specific Device ID/Model", "ValueIDKey": 844425112354839, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/114/value/1125900089065495/,{ "Label": "Serial Number", "Value": "3b548b972bf8", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_MANUFACTURER_SPECIFIC", "Index": 4, "Node": 10, "Genre": "System", "Help": "Device Serial Number", "ValueIDKey": 1125900089065495, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178857}
OpenZWave/1/node/10/instance/1/commandclass/115/,{ "Instance": 1, "CommandClassId": 115, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "CommandClassVersion": 1, "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/182239252/,{ "Label": "Powerlevel", "Value": { "List": [ { "Value": 0, "Label": "Normal" }, { "Value": 1, "Label": "-1dB" }, { "Value": 2, "Label": "-2dB" }, { "Value": 3, "Label": "-3dB" }, { "Value": 4, "Label": "-4dB" }, { "Value": 5, "Label": "-5dB" }, { "Value": 6, "Label": "-6dB" }, { "Value": 7, "Label": "-7dB" }, { "Value": 8, "Label": "-8dB" }, { "Value": 9, "Label": "-9dB" } ], "Selected": "Normal", "Selected_id": 0 }, "Units": "dB", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 0, "Node": 10, "Genre": "System", "Help": "Output RF PowerLevel", "ValueIDKey": 182239252, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/281475158949905/,{ "Label": "Timeout", "Value": 0, "Units": "seconds", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 1, "Node": 10, "Genre": "System", "Help": "Timeout till the PowerLevel is reset to Normal", "ValueIDKey": 281475158949905, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/562950135660568/,{ "Label": "Set Powerlevel", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 2, "Node": 10, "Genre": "System", "Help": "Apply the Output PowerLevel and Timeout Values", "ValueIDKey": 562950135660568, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/844425112371217/,{ "Label": "Test Node", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 3, "Node": 10, "Genre": "System", "Help": "Node to Perform a test against", "ValueIDKey": 844425112371217, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/1125900089081876/,{ "Label": "Test Powerlevel", "Value": { "List": [ { "Value": 0, "Label": "Normal" }, { "Value": 1, "Label": "-1dB" }, { "Value": 2, "Label": "-2dB" }, { "Value": 3, "Label": "-3dB" }, { "Value": 4, "Label": "-4dB" }, { "Value": 5, "Label": "-5dB" }, { "Value": 6, "Label": "-6dB" }, { "Value": 7, "Label": "-7dB" }, { "Value": 8, "Label": "-8dB" }, { "Value": 9, "Label": "-9dB" } ], "Selected": "Normal", "Selected_id": 0 }, "Units": "dB", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 4, "Node": 10, "Genre": "System", "Help": "PowerLevel to use for the Test", "ValueIDKey": 1125900089081876, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/1407375065792534/,{ "Label": "Frame Count", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 5, "Node": 10, "Genre": "System", "Help": "How Many Messages to send to the Node for the Test", "ValueIDKey": 1407375065792534, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/1688850042503192/,{ "Label": "Test", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 6, "Node": 10, "Genre": "System", "Help": "Perform a PowerLevel Test against the a Node", "ValueIDKey": 1688850042503192, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/1970325019213848/,{ "Label": "Report", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 7, "Node": 10, "Genre": "System", "Help": "Get the results of the latest PowerLevel Test against a Node", "ValueIDKey": 1970325019213848, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/2251799995924500/,{ "Label": "Test Status", "Value": { "List": [ { "Value": 0, "Label": "Failed" }, { "Value": 1, "Label": "Success" }, { "Value": 2, "Label": "In Progress" } ], "Selected": "Failed", "Selected_id": 0 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 8, "Node": 10, "Genre": "System", "Help": "The Current Status of the last PowerNode Test Executed", "ValueIDKey": 2251799995924500, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/115/value/2533274972635158/,{ "Label": "Acked Frames", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": -32768, "Max": 32767, "Type": "Short", "Instance": 1, "CommandClass": "COMMAND_CLASS_POWERLEVEL", "Index": 9, "Node": 10, "Genre": "System", "Help": "Number of Messages successfully Acked by the Target Node", "ValueIDKey": 2533274972635158, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/128/,{ "Instance": 1, "CommandClassId": 128, "CommandClass": "COMMAND_CLASS_BATTERY", "CommandClassVersion": 1, "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/128/value/174063633/,{ "Label": "Battery Level", "Value": 94, "Units": "%", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_BATTERY", "Index": 0, "Node": 10, "Genre": "User", "Help": "Current Battery Level", "ValueIDKey": 174063633, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178891}
OpenZWave/1/node/10/instance/1/commandclass/134/,{ "Instance": 1, "CommandClassId": 134, "CommandClass": "COMMAND_CLASS_VERSION", "CommandClassVersion": 1, "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/134/value/182550551/,{ "Label": "Library Version", "Value": "3", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_VERSION", "Index": 0, "Node": 10, "Genre": "System", "Help": "Z-Wave Library Version", "ValueIDKey": 182550551, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178857}
OpenZWave/1/node/10/instance/1/commandclass/134/value/281475159261207/,{ "Label": "Protocol Version", "Value": "4.61", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_VERSION", "Index": 1, "Node": 10, "Genre": "System", "Help": "Z-Wave Protocol Version", "ValueIDKey": 281475159261207, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178857}
OpenZWave/1/node/10/instance/1/commandclass/134/value/562950135971863/,{ "Label": "Application Version", "Value": "1.02", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_VERSION", "Index": 2, "Node": 10, "Genre": "System", "Help": "Application Version", "ValueIDKey": 562950135971863, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178857}
OpenZWave/1/node/10/instance/1/commandclass/139/,{ "Instance": 1, "CommandClassId": 139, "CommandClass": "COMMAND_CLASS_TIME_PARAMETERS", "CommandClassVersion": 1, "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/139/value/182632471/,{ "Label": "Date", "Value": "22/05/2020", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_TIME_PARAMETERS", "Index": 0, "Node": 10, "Genre": "System", "Help": "Current Date", "ValueIDKey": 182632471, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178858}
OpenZWave/1/node/10/instance/1/commandclass/139/value/281475159343127/,{ "Label": "Time", "Value": "20:20:57", "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "String", "Instance": 1, "CommandClass": "COMMAND_CLASS_TIME_PARAMETERS", "Index": 1, "Node": 10, "Genre": "System", "Help": "Current Time", "ValueIDKey": 281475159343127, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590178858}
OpenZWave/1/node/10/instance/1/commandclass/139/value/562950136053784/,{ "Label": "Set Date/Time", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_TIME_PARAMETERS", "Index": 2, "Node": 10, "Genre": "System", "Help": "Set the Date/Time", "ValueIDKey": 562950136053784, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/139/value/844425112764440/,{ "Label": "Refresh Date/Time", "Value": false, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Button", "Instance": 1, "CommandClass": "COMMAND_CLASS_TIME_PARAMETERS", "Index": 3, "Node": 10, "Genre": "System", "Help": "Refresh the Date/Time", "ValueIDKey": 844425112764440, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/152/,{ "Instance": 1, "CommandClassId": 152, "CommandClass": "COMMAND_CLASS_SECURITY", "CommandClassVersion": 1, "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/152/value/182845456/,{ "Label": "Secured", "Value": true, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "Bool", "Instance": 1, "CommandClass": "COMMAND_CLASS_SECURITY", "Index": 0, "Node": 10, "Genre": "System", "Help": "Is Communication with Device Encrypted", "ValueIDKey": 182845456, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178856}
OpenZWave/1/node/10/instance/1/commandclass/113/,{ "Instance": 1, "CommandClassId": 113, "CommandClass": "COMMAND_CLASS_NOTIFICATION", "CommandClassVersion": 8, "TimeStamp": 1590178857}
OpenZWave/1/node/10/instance/1/commandclass/113/value/72057594211745809/,{ "Label": "Previous Event Cleared", "Value": 0, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_NOTIFICATION", "Index": 256, "Node": 10, "Genre": "User", "Help": "Previous Event that was sent", "ValueIDKey": 72057594211745809, "ReadOnly": false, "WriteOnly": false, "Event": "valueAdded", "TimeStamp": 1590178857}
OpenZWave/1/node/10/instance/1/commandclass/113/value/1688850034081812/,{ "Label": "Access Control", "Value": { "List": [ { "Value": 0, "Label": "Clear" }, { "Value": 1, "Label": "Manual Lock Operation" }, { "Value": 2, "Label": "Manual Unlock Operation" }, { "Value": 3, "Label": "Wireless Lock Operation" }, { "Value": 4, "Label": "Wireless Unlock Operation" }, { "Value": 9, "Label": "Auto Lock" }, { "Value": 11, "Label": "Lock Jammed" } ], "Selected": "Wireless Unlock Operation", "Selected_id": 4 }, "Units": "", "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Min": 0, "Max": 0, "Type": "List", "Instance": 1, "CommandClass": "COMMAND_CLASS_NOTIFICATION", "Index": 6, "Node": 10, "Genre": "User", "Help": "Access Control Alerts", "ValueIDKey": 1688850034081812, "ReadOnly": false, "WriteOnly": false, "Event": "valueChanged", "TimeStamp": 1590345911}
OpenZWave/1/node/10/association/1/,{ "Name": "Lifeline", "Help": "", "MaxAssociations": 1, "Members": [ "1.0" ], "TimeStamp": 1590178858}
Can't render this file because it contains an unexpected character in line 1 and column 26.

View File

@ -1,9 +0,0 @@
OpenZWave/1/status/,{ "OpenZWave_Version": "1.6.1008", "OZWDeamon_Version": "0.1", "QTOpenZWave_Version": "1.0.0", "QT_Version": "5.12.5", "Status": "driverAllNodesQueried", "TimeStamp": 1579566933, "ManufacturerSpecificDBReady": true, "homeID": 3245146787, "getControllerNodeId": 1, "getSUCNodeId": 1, "isPrimaryController": true, "isBridgeController": false, "hasExtendedTXStatistics": true, "getControllerLibraryVersion": "Z-Wave 3.95", "getControllerLibraryType": "Static Controller", "getControllerPath": "/dev/zwave"}
OpenZWave/1/node/32/,{ "NodeID": 32, "NodeQueryStage": "Complete", "isListening": true, "isFlirs": false, "isBeaming": true, "isRouting": true, "isSecurityv1": false, "isZWavePlus": true, "isNIFRecieved": true, "isAwake": true, "isFailed": false, "MetaData": { "OZWInfoURL": "http://www.openzwave.com/device-database/0208:0005:0101", "ZWAProductURL": "", "ProductPic": "images/hank/hkzw-so01-smartplug.png", "Description": "fixture description", "WakeupHelp": "", "ProductSupportURL": "", "Frequency": "", "Name": "Smart Plug", "ProductPicBase64": "iVBORggg==" }, "Event": "nodeQueriesComplete", "TimeStamp": 1579566933, "NodeManufacturerName": "HANK Electronics Ltd", "NodeProductName": "HKZW-SO01 Smart Plug", "NodeBasicString": "Routing Slave", "NodeBasic": 4, "NodeGenericString": "Binary Switch", "NodeGeneric": 16, "NodeSpecificString": "Binary Power Switch", "NodeSpecific": 1, "NodeManufacturerID": "0x0208", "NodeProductType": "0x0101", "NodeProductID": "0x0005", "NodeBaudRate": 100000, "NodeVersion": 4, "NodeGroups": 1, "NodeName": "", "NodeLocation": "", "NodeDeviceTypeString": "On/Off Power Switch", "NodeDeviceType": 1792, "NodeRole": 5, "NodeRoleString": "Always On Slave", "NodePlusType": 0, "NodePlusTypeString": "Z-Wave+ node", "Neighbors": [ 1, 33, 36, 37, 39 ]}
OpenZWave/1/node/32/instance/1/,{ "Instance": 1, "TimeStamp": 1579566891}
OpenZWave/1/node/32/instance/1/commandclass/50/,{ "Instance": 1, "CommandClassId": 50, "CommandClass": "COMMAND_CLASS_METER", "TimeStamp": 1579566891}
OpenZWave/1/node/32/instance/1/commandclass/50/value/562950495305746/,{ "Label": "Electric - W", "Value": 0.0, "Units": "W", "Min": 0, "Max": 0, "Type": "Decimal", "Instance": 1, "CommandClass": "COMMAND_CLASS_METER", "Index": 2, "Node": 32, "Genre": "User", "Help": "", "ValueIDKey": 562950495305746, "ReadOnly": false, "WriteOnly": false, "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Event": "valueAdded", "TimeStamp": 1579566891}
OpenZWave/1/node/36/,{ "NodeID": 36, "NodeQueryStage": "CacheLoad", "isListening": false, "isFlirs": false, "isBeaming": true, "isRouting": true, "isSecurityv1": false, "isZWavePlus": false, "isNIFRecieved": true, "isAwake": true, "isFailed": false, "MetaData": { "OZWInfoURL": "http://www.openzwave.com/device-database/0086:007A:0102", "ZWAProductURL": "", "ProductPic": "images/aeotec/zw122.png", "Description": "fixture description", "WakeupHelp": "Pressing the Action Button once will trigger sending the Wake up notification command. If press and hold the Z-Wave button for 3 seconds, the Water Sensor will wake up for 10 minutes.", "ProductSupportURL": "", "Frequency": "", "Name": "Water Sensor 6", "ProductPicBase64": "kSuQmCC" }, "Event": "nodeNaming", "TimeStamp": 1579566891, "NodeManufacturerName": "AEON Labs", "NodeProductName": "ZW122 Water Sensor 6", "NodeBasicString": "Routing Slave", "NodeBasic": 4, "NodeGenericString": "Notification Sensor", "NodeGeneric": 7, "NodeSpecificString": "Notification Sensor", "NodeSpecific": 1, "NodeManufacturerID": "0x0086", "NodeProductType": "0x0102", "NodeProductID": "0x007a", "NodeBaudRate": 100000, "NodeVersion": 4, "NodeGroups": 4}
OpenZWave/1/node/36/instance/1/,{ "Instance": 1, "TimeStamp": 1579566891}
OpenZWave/1/node/36/instance/1/commandclass/128/,{ "Instance": 1, "CommandClassId": 128, "CommandClass": "COMMAND_CLASS_BATTERY", "TimeStamp": 1579566891}
OpenZWave/1/node/36/instance/1/commandclass/128/value/610271249/,{ "Label": "Battery Level", "Value": 100, "Units": "%", "Min": 0, "Max": 255, "Type": "Byte", "Instance": 1, "CommandClass": "COMMAND_CLASS_BATTERY", "Index": 0, "Node": 36, "Genre": "User", "Help": "Current Battery Level", "ValueIDKey": 610271249, "ReadOnly": false, "WriteOnly": false, "ValueSet": false, "ValuePolled": false, "ChangeVerified": false, "Event": "valueAdded", "TimeStamp": 1579566891}
Can't render this file because it contains an unexpected character in line 1 and column 26.

View File

@ -1,38 +0,0 @@
{
"topic": "OpenZWave/1/node/36/instance/1/commandclass/113/value/1407375493578772/",
"payload": {
"Label": "Instance 1: Water",
"Value": {
"List": [
{
"Value": 0,
"Label": "Clear"
},
{
"Value": 2,
"Label": "Water Leak at Unknown Location"
}
],
"Selected": "Clear",
"Selected_id": 0
},
"Units": "",
"Min": 0,
"Max": 0,
"Type": "List",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_NOTIFICATION",
"Index": 5,
"Node": 36,
"Genre": "User",
"Help": "Water Alerts",
"ValueIDKey": 1407375493578772,
"ReadOnly": false,
"WriteOnly": false,
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Event": "valueAdded",
"TimeStamp": 1579566891
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,25 +0,0 @@
{
"topic": "OpenZWave/1/node/32/instance/1/commandclass/37/value/541671440/",
"payload": {
"Label": "Switch",
"Value": false,
"Units": "",
"Min": 0,
"Max": 0,
"Type": "Bool",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_SWITCH_BINARY",
"Index": 0,
"Node": 32,
"Genre": "User",
"Help": "Turn On/Off Device",
"ValueIDKey": 541671440,
"ReadOnly": false,
"WriteOnly": false,
"ValueSet": false,
"ValuePolled": false,
"ChangeVerified": false,
"Event": "valueAdded",
"TimeStamp": 1579566891
}
}

View File

@ -1,67 +0,0 @@
"""Test Z-Wave Sensors."""
from homeassistant.components.binary_sensor import (
DOMAIN as BINARY_SENSOR_DOMAIN,
BinarySensorDeviceClass,
)
from homeassistant.components.ozw.const import DOMAIN
from homeassistant.const import ATTR_DEVICE_CLASS
from homeassistant.helpers import entity_registry as er
from .common import setup_ozw
async def test_binary_sensor(hass, generic_data, binary_sensor_msg):
"""Test setting up config entry."""
receive_msg = await setup_ozw(hass, fixture=generic_data)
# Test Legacy sensor (disabled by default)
registry = er.async_get(hass)
entity_id = "binary_sensor.trisensor_sensor"
state = hass.states.get(entity_id)
assert state is None
entry = registry.async_get(entity_id)
assert entry
assert entry.disabled
assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION
# Test enabling legacy entity
updated_entry = registry.async_update_entity(
entry.entity_id, **{"disabled_by": None}
)
assert updated_entry != entry
assert updated_entry.disabled is False
# Test Sensor for Notification CC
state = hass.states.get("binary_sensor.trisensor_home_security_motion_detected")
assert state
assert state.state == "off"
assert state.attributes[ATTR_DEVICE_CLASS] == BinarySensorDeviceClass.MOTION
# Test incoming state change
receive_msg(binary_sensor_msg)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.trisensor_home_security_motion_detected")
assert state.state == "on"
async def test_sensor_enabled(hass, generic_data, binary_sensor_alt_msg):
"""Test enabling a legacy binary_sensor."""
registry = er.async_get(hass)
entry = registry.async_get_or_create(
BINARY_SENSOR_DOMAIN,
DOMAIN,
"1-37-625737744",
suggested_object_id="trisensor_sensor_instance_1_sensor",
disabled_by=None,
)
assert entry.disabled is False
receive_msg = await setup_ozw(hass, fixture=generic_data)
receive_msg(binary_sensor_alt_msg)
await hass.async_block_till_done()
state = hass.states.get(entry.entity_id)
assert state is not None
assert state.state == "on"

View File

@ -1,327 +0,0 @@
"""Test Z-Wave Multi-setpoint Climate entities."""
from homeassistant.components.climate import ATTR_TEMPERATURE
from homeassistant.components.climate.const import (
ATTR_CURRENT_TEMPERATURE,
ATTR_FAN_MODE,
ATTR_FAN_MODES,
ATTR_HVAC_ACTION,
ATTR_HVAC_MODES,
ATTR_PRESET_MODE,
ATTR_PRESET_MODES,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
CURRENT_HVAC_IDLE,
HVAC_MODE_COOL,
HVAC_MODE_HEAT,
HVAC_MODE_HEAT_COOL,
HVAC_MODE_OFF,
)
from .common import setup_ozw
async def test_climate(hass, climate_data, sent_messages, climate_msg, caplog):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=climate_data)
# Test multi-setpoint thermostat (node 7 in dump)
# mode is heat, this should be single setpoint
state = hass.states.get("climate.ct32_thermostat_mode")
assert state is not None
assert state.state == HVAC_MODE_HEAT
assert state.attributes[ATTR_HVAC_MODES] == [
HVAC_MODE_OFF,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
HVAC_MODE_HEAT_COOL,
]
assert state.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_IDLE
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 23.1
assert state.attributes[ATTR_TEMPERATURE] == 21.1
assert state.attributes.get(ATTR_TARGET_TEMP_LOW) is None
assert state.attributes.get(ATTR_TARGET_TEMP_HIGH) is None
assert state.attributes[ATTR_FAN_MODE] == "Auto Low"
assert state.attributes[ATTR_FAN_MODES] == ["Auto Low", "On Low"]
# Test set target temperature
await hass.services.async_call(
"climate",
"set_temperature",
{"entity_id": "climate.ct32_thermostat_mode", "temperature": 26.1},
blocking=True,
)
assert len(sent_messages) == 1
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
# Celsius is converted to Fahrenheit here!
assert round(msg["payload"]["Value"], 2) == 78.98
assert msg["payload"]["ValueIDKey"] == 281475099443218
# Test hvac_mode with set_temperature
await hass.services.async_call(
"climate",
"set_temperature",
{
"entity_id": "climate.ct32_thermostat_mode",
"temperature": 24.1,
"hvac_mode": "cool",
},
blocking=True,
)
assert len(sent_messages) == 3 # 2 messages
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
# Celsius is converted to Fahrenheit here!
assert round(msg["payload"]["Value"], 2) == 75.38
assert msg["payload"]["ValueIDKey"] == 281475099443218
# Test set mode
await hass.services.async_call(
"climate",
"set_hvac_mode",
{"entity_id": "climate.ct32_thermostat_mode", "hvac_mode": HVAC_MODE_HEAT_COOL},
blocking=True,
)
assert len(sent_messages) == 4
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 3, "ValueIDKey": 122683412}
# Test set missing mode
await hass.services.async_call(
"climate",
"set_hvac_mode",
{"entity_id": "climate.ct32_thermostat_mode", "hvac_mode": "fan_only"},
blocking=True,
)
assert len(sent_messages) == 4
assert "Received an invalid hvac mode: fan_only" in caplog.text
# Test set fan mode
await hass.services.async_call(
"climate",
"set_fan_mode",
{"entity_id": "climate.ct32_thermostat_mode", "fan_mode": "On Low"},
blocking=True,
)
assert len(sent_messages) == 5
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 1, "ValueIDKey": 122748948}
# Test set invalid fan mode
await hass.services.async_call(
"climate",
"set_fan_mode",
{"entity_id": "climate.ct32_thermostat_mode", "fan_mode": "invalid fan mode"},
blocking=True,
)
assert len(sent_messages) == 5
assert "Received an invalid fan mode: invalid fan mode" in caplog.text
# Test incoming mode change to auto,
# resulting in multiple setpoints
receive_message(climate_msg)
await hass.async_block_till_done()
state = hass.states.get("climate.ct32_thermostat_mode")
assert state is not None
assert state.state == HVAC_MODE_HEAT_COOL
assert state.attributes.get(ATTR_TEMPERATURE) is None
assert state.attributes[ATTR_TARGET_TEMP_LOW] == 21.1
assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 25.6
# Test setting high/low temp on multiple setpoints
await hass.services.async_call(
"climate",
"set_temperature",
{
"entity_id": "climate.ct32_thermostat_mode",
"target_temp_low": 20,
"target_temp_high": 25,
},
blocking=True,
)
assert len(sent_messages) == 7 # 2 messages !
msg = sent_messages[-2] # low setpoint
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert round(msg["payload"]["Value"], 2) == 68.0
assert msg["payload"]["ValueIDKey"] == 281475099443218
msg = sent_messages[-1] # high setpoint
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert round(msg["payload"]["Value"], 2) == 77.0
assert msg["payload"]["ValueIDKey"] == 562950076153874
# Test basic/single-setpoint thermostat (node 16 in dump)
state = hass.states.get("climate.komforthaus_spirit_z_wave_plus_mode")
assert state is not None
assert state.state == HVAC_MODE_HEAT
assert state.attributes[ATTR_HVAC_MODES] == [
HVAC_MODE_OFF,
HVAC_MODE_HEAT,
]
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 17.3
assert round(state.attributes[ATTR_TEMPERATURE], 0) == 19
assert state.attributes.get(ATTR_TARGET_TEMP_LOW) is None
assert state.attributes.get(ATTR_TARGET_TEMP_HIGH) is None
assert state.attributes[ATTR_PRESET_MODES] == [
"none",
"Heat Eco",
"Full Power",
"Manufacturer Specific",
]
# Test set target temperature
await hass.services.async_call(
"climate",
"set_temperature",
{
"entity_id": "climate.komforthaus_spirit_z_wave_plus_mode",
"temperature": 28.0,
},
blocking=True,
)
assert len(sent_messages) == 8
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": 28.0,
"ValueIDKey": 281475250438162,
}
# Test set preset mode
await hass.services.async_call(
"climate",
"set_preset_mode",
{
"entity_id": "climate.komforthaus_spirit_z_wave_plus_mode",
"preset_mode": "Heat Eco",
},
blocking=True,
)
assert len(sent_messages) == 9
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": 11,
"ValueIDKey": 273678356,
}
# Test set preset mode None
# This preset should set and return to current hvac mode
await hass.services.async_call(
"climate",
"set_preset_mode",
{
"entity_id": "climate.komforthaus_spirit_z_wave_plus_mode",
"preset_mode": "none",
},
blocking=True,
)
assert len(sent_messages) == 10
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": 1,
"ValueIDKey": 273678356,
}
# Test set invalid preset mode
await hass.services.async_call(
"climate",
"set_preset_mode",
{
"entity_id": "climate.komforthaus_spirit_z_wave_plus_mode",
"preset_mode": "invalid preset mode",
},
blocking=True,
)
assert len(sent_messages) == 10
assert "Received an invalid preset mode: invalid preset mode" in caplog.text
# test thermostat device without a mode commandclass
state = hass.states.get("climate.danfoss_living_connect_z_v1_06_014g0013_heating_1")
assert state is not None
assert state.state == HVAC_MODE_HEAT
assert state.attributes[ATTR_HVAC_MODES] == [
HVAC_MODE_HEAT,
]
assert state.attributes.get(ATTR_CURRENT_TEMPERATURE) is None
assert round(state.attributes[ATTR_TEMPERATURE], 0) == 21
assert state.attributes.get(ATTR_TARGET_TEMP_LOW) is None
assert state.attributes.get(ATTR_TARGET_TEMP_HIGH) is None
assert state.attributes.get(ATTR_PRESET_MODE) is None
assert state.attributes.get(ATTR_PRESET_MODES) is None
# Test set target temperature
await hass.services.async_call(
"climate",
"set_temperature",
{
"entity_id": "climate.danfoss_living_connect_z_v1_06_014g0013_heating_1",
"temperature": 28.0,
},
blocking=True,
)
assert len(sent_messages) == 11
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": 28.0,
"ValueIDKey": 281475116220434,
}
await hass.services.async_call(
"climate",
"set_hvac_mode",
{
"entity_id": "climate.danfoss_living_connect_z_v1_06_014g0013_heating_1",
"hvac_mode": HVAC_MODE_HEAT,
},
blocking=True,
)
assert len(sent_messages) == 11
assert "does not support setting a mode" in caplog.text
# test thermostat device without a mode commandclass
state = hass.states.get("climate.secure_srt321_zwave_stat_tx_heating_1")
assert state is not None
assert state.state == HVAC_MODE_HEAT
assert state.attributes[ATTR_HVAC_MODES] == [
HVAC_MODE_HEAT,
]
assert state.attributes.get(ATTR_CURRENT_TEMPERATURE) == 29.0
assert round(state.attributes[ATTR_TEMPERATURE], 0) == 16
assert state.attributes.get(ATTR_TARGET_TEMP_LOW) is None
assert state.attributes.get(ATTR_TARGET_TEMP_HIGH) is None
assert state.attributes.get(ATTR_PRESET_MODE) is None
assert state.attributes.get(ATTR_PRESET_MODES) is None
# Test set target temperature
await hass.services.async_call(
"climate",
"set_temperature",
{
"entity_id": "climate.secure_srt321_zwave_stat_tx_heating_1",
"temperature": 28.0,
},
blocking=True,
)
assert len(sent_messages) == 12
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": 28.0,
"ValueIDKey": 281475267215378,
}
await hass.services.async_call(
"climate",
"set_hvac_mode",
{
"entity_id": "climate.secure_srt321_zwave_stat_tx_heating_1",
"hvac_mode": HVAC_MODE_HEAT,
},
blocking=True,
)
assert len(sent_messages) == 12
assert "does not support setting a mode" in caplog.text

View File

@ -1,502 +0,0 @@
"""Test the Z-Wave over MQTT config flow."""
from unittest.mock import patch
import pytest
from homeassistant import config_entries
from homeassistant.components.hassio import HassioServiceInfo
from homeassistant.components.hassio.handler import HassioAPIError
from homeassistant.components.ozw.config_flow import TITLE
from homeassistant.components.ozw.const import DOMAIN
from tests.common import MockConfigEntry
ADDON_DISCOVERY_INFO = HassioServiceInfo(
config={
"addon": "OpenZWave",
"host": "host1",
"port": 1234,
"username": "name1",
"password": "pass1",
}
)
@pytest.fixture(name="supervisor")
def mock_supervisor_fixture():
"""Mock Supervisor."""
with patch("homeassistant.components.hassio.is_hassio", return_value=True):
yield
@pytest.fixture(name="addon_info")
def mock_addon_info():
"""Mock Supervisor add-on info."""
with patch("homeassistant.components.hassio.async_get_addon_info") as addon_info:
addon_info.return_value = {}
yield addon_info
@pytest.fixture(name="addon_running")
def mock_addon_running(addon_info):
"""Mock add-on already running."""
addon_info.return_value["state"] = "started"
return addon_info
@pytest.fixture(name="addon_installed")
def mock_addon_installed(addon_info):
"""Mock add-on already installed but not running."""
addon_info.return_value["state"] = "stopped"
addon_info.return_value["version"] = "1.0"
return addon_info
@pytest.fixture(name="addon_options")
def mock_addon_options(addon_info):
"""Mock add-on options."""
addon_info.return_value["options"] = {}
return addon_info.return_value["options"]
@pytest.fixture(name="set_addon_options")
def mock_set_addon_options():
"""Mock set add-on options."""
with patch(
"homeassistant.components.hassio.async_set_addon_options"
) as set_options:
yield set_options
@pytest.fixture(name="install_addon")
def mock_install_addon():
"""Mock install add-on."""
with patch("homeassistant.components.hassio.async_install_addon") as install_addon:
yield install_addon
@pytest.fixture(name="start_addon")
def mock_start_addon():
"""Mock start add-on."""
with patch("homeassistant.components.hassio.async_start_addon") as start_addon:
yield start_addon
async def test_user_not_supervisor_create_entry(hass, mqtt):
"""Test the user step creates an entry not on Supervisor."""
with patch(
"homeassistant.components.ozw.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
await hass.async_block_till_done()
assert result["type"] == "create_entry"
assert result["title"] == TITLE
assert result["data"] == {
"usb_path": None,
"network_key": None,
"use_addon": False,
"integration_created_addon": False,
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_mqtt_not_setup(hass):
"""Test that mqtt is required."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "abort"
assert result["reason"] == "mqtt_required"
async def test_one_instance_allowed(hass):
"""Test that only one instance is allowed."""
entry = MockConfigEntry(domain=DOMAIN, data={}, title=TITLE)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "abort"
assert result["reason"] == "single_instance_allowed"
async def test_not_addon(hass, supervisor, mqtt):
"""Test opting out of add-on on Supervisor."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.ozw.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"use_addon": False}
)
await hass.async_block_till_done()
assert result["type"] == "create_entry"
assert result["title"] == TITLE
assert result["data"] == {
"usb_path": None,
"network_key": None,
"use_addon": False,
"integration_created_addon": False,
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_addon_running(hass, supervisor, addon_running, addon_options):
"""Test add-on already running on Supervisor."""
addon_options["device"] = "/test"
addon_options["network_key"] = "abc123"
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.ozw.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"use_addon": True}
)
await hass.async_block_till_done()
assert result["type"] == "create_entry"
assert result["title"] == TITLE
assert result["data"] == {
"usb_path": "/test",
"network_key": "abc123",
"use_addon": True,
"integration_created_addon": False,
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_addon_info_failure(hass, supervisor, addon_info):
"""Test add-on info failure."""
addon_info.side_effect = HassioAPIError()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"use_addon": True}
)
assert result["type"] == "abort"
assert result["reason"] == "addon_info_failed"
async def test_addon_installed(
hass, supervisor, addon_installed, addon_options, set_addon_options, start_addon
):
"""Test add-on already installed but not running on Supervisor."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"use_addon": True}
)
with patch(
"homeassistant.components.ozw.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"usb_path": "/test", "network_key": "abc123"}
)
await hass.async_block_till_done()
assert result["type"] == "create_entry"
assert result["title"] == TITLE
assert result["data"] == {
"usb_path": "/test",
"network_key": "abc123",
"use_addon": True,
"integration_created_addon": False,
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_set_addon_config_failure(
hass, supervisor, addon_installed, addon_options, set_addon_options
):
"""Test add-on set config failure."""
set_addon_options.side_effect = HassioAPIError()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"use_addon": True}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"usb_path": "/test", "network_key": "abc123"}
)
assert result["type"] == "abort"
assert result["reason"] == "addon_set_config_failed"
async def test_start_addon_failure(
hass, supervisor, addon_installed, addon_options, set_addon_options, start_addon
):
"""Test add-on start failure."""
start_addon.side_effect = HassioAPIError()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"use_addon": True}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"usb_path": "/test", "network_key": "abc123"}
)
assert result["type"] == "form"
assert result["errors"] == {"base": "addon_start_failed"}
async def test_addon_not_installed(
hass,
supervisor,
addon_installed,
install_addon,
addon_options,
set_addon_options,
start_addon,
):
"""Test add-on not installed."""
addon_installed.return_value["version"] = None
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"use_addon": True}
)
assert result["type"] == "progress"
# Make sure the flow continues when the progress task is done.
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["type"] == "form"
assert result["step_id"] == "start_addon"
with patch(
"homeassistant.components.ozw.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"usb_path": "/test", "network_key": "abc123"}
)
await hass.async_block_till_done()
assert result["type"] == "create_entry"
assert result["title"] == TITLE
assert result["data"] == {
"usb_path": "/test",
"network_key": "abc123",
"use_addon": True,
"integration_created_addon": True,
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_install_addon_failure(hass, supervisor, addon_installed, install_addon):
"""Test add-on install failure."""
addon_installed.return_value["version"] = None
install_addon.side_effect = HassioAPIError()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"use_addon": True}
)
assert result["type"] == "progress"
# Make sure the flow continues when the progress task is done.
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["type"] == "abort"
assert result["reason"] == "addon_install_failed"
async def test_supervisor_discovery(hass, supervisor, addon_running, addon_options):
"""Test flow started from Supervisor discovery."""
addon_options["device"] = "/test"
addon_options["network_key"] = "abc123"
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_HASSIO},
data=ADDON_DISCOVERY_INFO,
)
with patch(
"homeassistant.components.ozw.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
await hass.async_block_till_done()
assert result["type"] == "create_entry"
assert result["title"] == TITLE
assert result["data"] == {
"usb_path": "/test",
"network_key": "abc123",
"use_addon": True,
"integration_created_addon": False,
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_clean_discovery_on_user_create(
hass, supervisor, addon_running, addon_options
):
"""Test discovery flow is cleaned up when a user flow is finished."""
addon_options["device"] = "/test"
addon_options["network_key"] = "abc123"
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_HASSIO},
data=ADDON_DISCOVERY_INFO,
)
assert result["type"] == "form"
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.ozw.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"use_addon": False}
)
await hass.async_block_till_done()
assert len(hass.config_entries.flow.async_progress()) == 0
assert result["type"] == "create_entry"
assert result["title"] == TITLE
assert result["data"] == {
"usb_path": None,
"network_key": None,
"use_addon": False,
"integration_created_addon": False,
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_abort_discovery_with_user_flow(
hass, supervisor, addon_running, addon_options
):
"""Test discovery flow is aborted if a user flow is in progress."""
await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_HASSIO},
data=ADDON_DISCOVERY_INFO,
)
assert result["type"] == "abort"
assert result["reason"] == "already_in_progress"
assert len(hass.config_entries.flow.async_progress()) == 1
async def test_abort_discovery_with_existing_entry(
hass, supervisor, addon_running, addon_options
):
"""Test discovery flow is aborted if an entry already exists."""
entry = MockConfigEntry(domain=DOMAIN, data={}, title=TITLE, unique_id=DOMAIN)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_HASSIO},
data=ADDON_DISCOVERY_INFO,
)
assert result["type"] == "abort"
assert result["reason"] == "already_configured"
async def test_discovery_addon_not_running(
hass, supervisor, addon_installed, addon_options, set_addon_options, start_addon
):
"""Test discovery with add-on already installed but not running."""
addon_options["device"] = None
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_HASSIO},
data=ADDON_DISCOVERY_INFO,
)
assert result["step_id"] == "hassio_confirm"
assert result["type"] == "form"
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result["step_id"] == "start_addon"
assert result["type"] == "form"
async def test_discovery_addon_not_installed(
hass, supervisor, addon_installed, install_addon, addon_options
):
"""Test discovery with add-on not installed."""
addon_installed.return_value["version"] = None
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_HASSIO},
data=ADDON_DISCOVERY_INFO,
)
assert result["step_id"] == "hassio_confirm"
assert result["type"] == "form"
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result["step_id"] == "install_addon"
assert result["type"] == "progress"
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["type"] == "form"
assert result["step_id"] == "start_addon"

View File

@ -1,177 +0,0 @@
"""Test Z-Wave Covers."""
from homeassistant.components.cover import ATTR_CURRENT_POSITION
from homeassistant.components.ozw.cover import VALUE_SELECTED_ID
from .common import setup_ozw
VALUE_ID = "Value"
async def test_cover(hass, cover_data, sent_messages, cover_msg):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=cover_data)
# Test loaded
state = hass.states.get("cover.roller_shutter_3_instance_1_level")
assert state is not None
assert state.state == "closed"
assert state.attributes[ATTR_CURRENT_POSITION] == 0
# Test setting position
await hass.services.async_call(
"cover",
"set_cover_position",
{"entity_id": "cover.roller_shutter_3_instance_1_level", "position": 50},
blocking=True,
)
assert len(sent_messages) == 1
msg = sent_messages[0]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 50, "ValueIDKey": 625573905}
# Feedback on state
cover_msg.decode()
cover_msg.payload["Value"] = 50
cover_msg.encode()
receive_message(cover_msg)
await hass.async_block_till_done()
# Test opening
await hass.services.async_call(
"cover",
"open_cover",
{"entity_id": "cover.roller_shutter_3_instance_1_level"},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": True, "ValueIDKey": 281475602284568}
# Test stopping after opening
await hass.services.async_call(
"cover",
"stop_cover",
{"entity_id": "cover.roller_shutter_3_instance_1_level"},
blocking=True,
)
assert len(sent_messages) == 4
msg = sent_messages[2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": False, "ValueIDKey": 281475602284568}
msg = sent_messages[3]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": False, "ValueIDKey": 562950578995224}
# Test closing
await hass.services.async_call(
"cover",
"close_cover",
{"entity_id": "cover.roller_shutter_3_instance_1_level"},
blocking=True,
)
assert len(sent_messages) == 5
msg = sent_messages[4]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": True, "ValueIDKey": 562950578995224}
# Test stopping after closing
await hass.services.async_call(
"cover",
"stop_cover",
{"entity_id": "cover.roller_shutter_3_instance_1_level"},
blocking=True,
)
assert len(sent_messages) == 7
msg = sent_messages[5]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": False, "ValueIDKey": 281475602284568}
msg = sent_messages[6]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": False, "ValueIDKey": 562950578995224}
# Test stopping after no open/close
await hass.services.async_call(
"cover",
"stop_cover",
{"entity_id": "cover.roller_shutter_3_instance_1_level"},
blocking=True,
)
# both stop open/close messages sent
assert len(sent_messages) == 9
msg = sent_messages[7]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": False, "ValueIDKey": 281475602284568}
msg = sent_messages[8]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": False, "ValueIDKey": 562950578995224}
# Test converting position to zwave range for position > 0
await hass.services.async_call(
"cover",
"set_cover_position",
{"entity_id": "cover.roller_shutter_3_instance_1_level", "position": 100},
blocking=True,
)
assert len(sent_messages) == 10
msg = sent_messages[9]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 99, "ValueIDKey": 625573905}
# Test converting position to zwave range for position = 0
await hass.services.async_call(
"cover",
"set_cover_position",
{"entity_id": "cover.roller_shutter_3_instance_1_level", "position": 0},
blocking=True,
)
assert len(sent_messages) == 11
msg = sent_messages[10]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 0, "ValueIDKey": 625573905}
async def test_barrier(hass, cover_gdo_data, sent_messages, cover_gdo_msg):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=cover_gdo_data)
# Test loaded
state = hass.states.get("cover.gd00z_4_barrier_state")
assert state is not None
assert state.state == "closed"
# Test opening
await hass.services.async_call(
"cover",
"open_cover",
{"entity_id": "cover.gd00z_4_barrier_state"},
blocking=True,
)
assert len(sent_messages) == 1
msg = sent_messages[0]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 4, "ValueIDKey": 281475083239444}
# Feedback on state
cover_gdo_msg.decode()
cover_gdo_msg.payload[VALUE_ID][VALUE_SELECTED_ID] = 4
cover_gdo_msg.encode()
receive_message(cover_gdo_msg)
await hass.async_block_till_done()
state = hass.states.get("cover.gd00z_4_barrier_state")
assert state is not None
assert state.state == "open"
# Test closing
await hass.services.async_call(
"cover",
"close_cover",
{"entity_id": "cover.gd00z_4_barrier_state"},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 0, "ValueIDKey": 281475083239444}

View File

@ -1,120 +0,0 @@
"""Test Z-Wave Fans."""
from .common import setup_ozw
async def test_fan(hass, fan_data, fan_msg, sent_messages, caplog):
"""Test fan."""
receive_message = await setup_ozw(hass, fixture=fan_data)
# Test loaded
state = hass.states.get("fan.in_wall_smart_fan_control_level")
assert state is not None
assert state.state == "on"
# Test turning off
await hass.services.async_call(
"fan",
"turn_off",
{"entity_id": "fan.in_wall_smart_fan_control_level"},
blocking=True,
)
assert len(sent_messages) == 1
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 0, "ValueIDKey": 172589073}
# Feedback on state
fan_msg.decode()
fan_msg.payload["Value"] = 0
fan_msg.encode()
receive_message(fan_msg)
await hass.async_block_till_done()
state = hass.states.get("fan.in_wall_smart_fan_control_level")
assert state is not None
assert state.state == "off"
# Test turning on
await hass.services.async_call(
"fan",
"turn_on",
{"entity_id": "fan.in_wall_smart_fan_control_level", "percentage": 66},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": 66,
"ValueIDKey": 172589073,
}
# Feedback on state
fan_msg.decode()
fan_msg.payload["Value"] = 66
fan_msg.encode()
receive_message(fan_msg)
await hass.async_block_till_done()
state = hass.states.get("fan.in_wall_smart_fan_control_level")
assert state is not None
assert state.state == "on"
assert state.attributes["percentage"] == 66
# Test turn on without speed
await hass.services.async_call(
"fan",
"turn_on",
{"entity_id": "fan.in_wall_smart_fan_control_level"},
blocking=True,
)
assert len(sent_messages) == 3
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": 255,
"ValueIDKey": 172589073,
}
# Feedback on state
fan_msg.decode()
fan_msg.payload["Value"] = 99
fan_msg.encode()
receive_message(fan_msg)
await hass.async_block_till_done()
state = hass.states.get("fan.in_wall_smart_fan_control_level")
assert state is not None
assert state.state == "on"
assert state.attributes["percentage"] == 100
# Test set percentage to 0
await hass.services.async_call(
"fan",
"set_percentage",
{"entity_id": "fan.in_wall_smart_fan_control_level", "percentage": 0},
blocking=True,
)
assert len(sent_messages) == 4
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": 0,
"ValueIDKey": 172589073,
}
# Feedback on state
fan_msg.decode()
fan_msg.payload["Value"] = 0
fan_msg.encode()
receive_message(fan_msg)
await hass.async_block_till_done()
state = hass.states.get("fan.in_wall_smart_fan_control_level")
assert state is not None
assert state.state == "off"

View File

@ -1,238 +0,0 @@
"""Test integration initialization."""
from unittest.mock import patch
from homeassistant import config_entries
from homeassistant.components.hassio.handler import HassioAPIError
from homeassistant.components.ozw import DOMAIN, PLATFORMS, const
from homeassistant.const import ATTR_RESTORED, STATE_UNAVAILABLE
from .common import setup_ozw
from tests.common import MockConfigEntry
async def test_init_entry(hass, generic_data):
"""Test setting up config entry."""
await setup_ozw(hass, fixture=generic_data)
# Verify integration + platform loaded.
assert "ozw" in hass.config.components
for platform in PLATFORMS:
assert platform in hass.config.components, platform
assert f"{platform}.{DOMAIN}" in hass.config.components, f"{platform}.{DOMAIN}"
# Verify services registered
assert hass.services.has_service(DOMAIN, const.SERVICE_ADD_NODE)
assert hass.services.has_service(DOMAIN, const.SERVICE_REMOVE_NODE)
async def test_setup_entry_without_mqtt(hass):
"""Test setting up config entry without mqtt integration setup."""
entry = MockConfigEntry(
domain=DOMAIN,
title="OpenZWave",
)
entry.add_to_hass(hass)
assert not await hass.config_entries.async_setup(entry.entry_id)
async def test_publish_without_mqtt(hass, caplog):
"""Test publish without mqtt integration setup."""
with patch("homeassistant.components.ozw.OZWOptions") as ozw_options:
await setup_ozw(hass)
send_message = ozw_options.call_args[1]["send_message"]
mqtt_entries = hass.config_entries.async_entries("mqtt")
mqtt_entry = mqtt_entries[0]
await hass.config_entries.async_remove(mqtt_entry.entry_id)
await hass.async_block_till_done()
assert not hass.config_entries.async_entries("mqtt")
# Sending a message should not error with the MQTT integration not set up.
send_message("test_topic", "test_payload")
await hass.async_block_till_done()
assert "MQTT integration is not set up" in caplog.text
async def test_unload_entry(hass, generic_data, switch_msg, caplog):
"""Test unload the config entry."""
entry = MockConfigEntry(
domain=DOMAIN,
title="Z-Wave",
)
entry.add_to_hass(hass)
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
receive_message = await setup_ozw(hass, entry=entry, fixture=generic_data)
assert entry.state is config_entries.ConfigEntryState.LOADED
assert len(hass.states.async_entity_ids("switch")) == 1
await hass.config_entries.async_unload(entry.entry_id)
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
entities = hass.states.async_entity_ids("switch")
assert len(entities) == 1
for entity in entities:
assert hass.states.get(entity).state == STATE_UNAVAILABLE
assert hass.states.get(entity).attributes.get(ATTR_RESTORED)
# Send a message for a switch from the broker to check that
# all entity topic subscribers are unsubscribed.
receive_message(switch_msg)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids("switch")) == 1
for entity in entities:
assert hass.states.get(entity).state == STATE_UNAVAILABLE
assert hass.states.get(entity).attributes.get(ATTR_RESTORED)
# Load the integration again and check that there are no errors when
# adding the entities.
# This asserts that we have unsubscribed the entity addition signals
# when unloading the integration previously.
await setup_ozw(hass, entry=entry, fixture=generic_data)
await hass.async_block_till_done()
assert entry.state is config_entries.ConfigEntryState.LOADED
assert len(hass.states.async_entity_ids("switch")) == 1
for record in caplog.records:
assert record.levelname != "ERROR"
async def test_remove_entry(hass, stop_addon, uninstall_addon, caplog):
"""Test remove the config entry."""
# test successful remove without created add-on
entry = MockConfigEntry(
domain=DOMAIN,
title="Z-Wave",
data={"integration_created_addon": False},
)
entry.add_to_hass(hass)
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
await hass.config_entries.async_remove(entry.entry_id)
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
# test successful remove with created add-on
entry = MockConfigEntry(
domain=DOMAIN,
title="Z-Wave",
data={"integration_created_addon": True},
)
entry.add_to_hass(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
await hass.config_entries.async_remove(entry.entry_id)
assert stop_addon.call_count == 1
assert uninstall_addon.call_count == 1
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
stop_addon.reset_mock()
uninstall_addon.reset_mock()
# test add-on stop failure
entry.add_to_hass(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
stop_addon.side_effect = HassioAPIError()
await hass.config_entries.async_remove(entry.entry_id)
assert stop_addon.call_count == 1
assert uninstall_addon.call_count == 0
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
assert "Failed to stop the OpenZWave add-on" in caplog.text
stop_addon.side_effect = None
stop_addon.reset_mock()
uninstall_addon.reset_mock()
# test add-on uninstall failure
entry.add_to_hass(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
uninstall_addon.side_effect = HassioAPIError()
await hass.config_entries.async_remove(entry.entry_id)
assert stop_addon.call_count == 1
assert uninstall_addon.call_count == 1
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
assert "Failed to uninstall the OpenZWave add-on" in caplog.text
async def test_setup_entry_with_addon(hass, get_addon_discovery_info):
"""Test set up entry using OpenZWave add-on."""
entry = MockConfigEntry(
domain=DOMAIN,
title="OpenZWave",
data={"use_addon": True},
)
entry.add_to_hass(hass)
with patch("homeassistant.components.ozw.MQTTClient", autospec=True) as mock_client:
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert mock_client.return_value.start_client.call_count == 1
# Verify integration + platform loaded.
assert "ozw" in hass.config.components
for platform in PLATFORMS:
assert platform in hass.config.components, platform
assert f"{platform}.{DOMAIN}" in hass.config.components, f"{platform}.{DOMAIN}"
# Verify services registered
assert hass.services.has_service(DOMAIN, const.SERVICE_ADD_NODE)
assert hass.services.has_service(DOMAIN, const.SERVICE_REMOVE_NODE)
async def test_setup_entry_without_addon_info(hass, get_addon_discovery_info):
"""Test set up entry using OpenZWave add-on but missing discovery info."""
entry = MockConfigEntry(
domain=DOMAIN,
title="OpenZWave",
data={"use_addon": True},
)
entry.add_to_hass(hass)
get_addon_discovery_info.return_value = None
with patch("homeassistant.components.ozw.MQTTClient", autospec=True) as mock_client:
assert not await hass.config_entries.async_setup(entry.entry_id)
assert mock_client.return_value.start_client.call_count == 0
assert entry.state is config_entries.ConfigEntryState.SETUP_RETRY
async def test_unload_entry_with_addon(
hass, get_addon_discovery_info, generic_data, switch_msg, caplog
):
"""Test unload the config entry using the OpenZWave add-on."""
entry = MockConfigEntry(
domain=DOMAIN,
title="OpenZWave",
data={"use_addon": True},
)
entry.add_to_hass(hass)
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED
with patch("homeassistant.components.ozw.MQTTClient", autospec=True) as mock_client:
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert mock_client.return_value.start_client.call_count == 1
assert entry.state is config_entries.ConfigEntryState.LOADED
await hass.config_entries.async_unload(entry.entry_id)
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED

View File

@ -1,683 +0,0 @@
"""Test Z-Wave Lights."""
from homeassistant.components.light import SUPPORT_TRANSITION
from homeassistant.components.ozw.light import byte_to_zwave_brightness
from .common import setup_ozw
async def test_light(hass, light_data, light_msg, light_rgb_msg, sent_messages):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=light_data)
# Test loaded
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "off"
assert state.attributes["supported_features"] == SUPPORT_TRANSITION
assert state.attributes["supported_color_modes"] == ["color_temp", "hs"]
# Test turning on
# Beware that due to rounding, a roundtrip conversion does not always work
new_brightness = 44
new_transition = 0
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.led_bulb_6_multi_colour_level",
"brightness": new_brightness,
"transition": new_transition,
},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[0]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 0, "ValueIDKey": 1407375551070225}
msg = sent_messages[1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": byte_to_zwave_brightness(new_brightness),
"ValueIDKey": 659128337,
}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(new_brightness)
light_msg.encode()
receive_message(light_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["brightness"] == new_brightness
assert state.attributes["color_mode"] == "color_temp"
# Test turning off
new_transition = 6553
await hass.services.async_call(
"light",
"turn_off",
{
"entity_id": "light.led_bulb_6_multi_colour_level",
"transition": new_transition,
},
blocking=True,
)
assert len(sent_messages) == 4
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 237, "ValueIDKey": 1407375551070225}
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 0, "ValueIDKey": 659128337}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = 0
light_msg.encode()
receive_message(light_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "off"
# Test turn on without brightness
new_transition = 127.0
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.led_bulb_6_multi_colour_level",
"transition": new_transition,
},
blocking=True,
)
assert len(sent_messages) == 6
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 127, "ValueIDKey": 1407375551070225}
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": 255,
"ValueIDKey": 659128337,
}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(new_brightness)
light_msg.encode()
receive_message(light_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["brightness"] == new_brightness
assert state.attributes["color_mode"] == "color_temp"
# Test set brightness to 0
new_brightness = 0
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.led_bulb_6_multi_colour_level",
"brightness": new_brightness,
},
blocking=True,
)
assert len(sent_messages) == 7
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": byte_to_zwave_brightness(new_brightness),
"ValueIDKey": 659128337,
}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(new_brightness)
light_msg.encode()
receive_message(light_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "off"
# Test setting color_name
new_color = "blue"
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.led_bulb_6_multi_colour_level", "color_name": new_color},
blocking=True,
)
assert len(sent_messages) == 9
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#0000ff0000", "ValueIDKey": 659341335}
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 255, "ValueIDKey": 659128337}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
light_msg.encode()
light_rgb_msg.decode()
light_rgb_msg.payload["Value"] = "#0000ff0000"
light_rgb_msg.encode()
receive_message(light_msg)
receive_message(light_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["rgb_color"] == (0, 0, 255)
assert state.attributes["color_mode"] == "hs"
# Test setting hs_color
new_color = [300, 70]
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.led_bulb_6_multi_colour_level", "hs_color": new_color},
blocking=True,
)
assert len(sent_messages) == 11
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 255, "ValueIDKey": 659128337}
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#ff4cff0000", "ValueIDKey": 659341335}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
light_msg.encode()
light_rgb_msg.decode()
light_rgb_msg.payload["Value"] = "#ff4cff0000"
light_rgb_msg.encode()
receive_message(light_msg)
receive_message(light_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["hs_color"] == (300.0, 70.196)
assert state.attributes["color_mode"] == "hs"
# Test setting rgb_color
new_color = [255, 154, 0]
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.led_bulb_6_multi_colour_level", "rgb_color": new_color},
blocking=True,
)
assert len(sent_messages) == 13
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 255, "ValueIDKey": 659128337}
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#ff99000000", "ValueIDKey": 659341335}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
light_msg.encode()
light_rgb_msg.decode()
light_rgb_msg.payload["Value"] = "#ff99000000"
light_rgb_msg.encode()
receive_message(light_msg)
receive_message(light_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["rgb_color"] == (255, 153, 0)
assert state.attributes["color_mode"] == "hs"
# Test setting xy_color
new_color = [0.52, 0.43]
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.led_bulb_6_multi_colour_level", "xy_color": new_color},
blocking=True,
)
assert len(sent_messages) == 15
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 255, "ValueIDKey": 659128337}
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#ffbb370000", "ValueIDKey": 659341335}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
light_msg.encode()
light_rgb_msg.decode()
light_rgb_msg.payload["Value"] = "#ffbb370000"
light_rgb_msg.encode()
receive_message(light_msg)
receive_message(light_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["xy_color"] == (0.519, 0.429)
assert state.attributes["color_mode"] == "hs"
# Test setting color temp
new_color = 200
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.led_bulb_6_multi_colour_level", "color_temp": new_color},
blocking=True,
)
assert len(sent_messages) == 17
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 255, "ValueIDKey": 659128337}
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#00000037c8", "ValueIDKey": 659341335}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
light_msg.encode()
light_rgb_msg.decode()
light_rgb_msg.payload["Value"] = "#00000037c8"
light_rgb_msg.encode()
receive_message(light_msg)
receive_message(light_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["color_temp"] == 200
assert state.attributes["color_mode"] == "color_temp"
# Test setting invalid color temp
new_color = 120
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.led_bulb_6_multi_colour_level", "color_temp": new_color},
blocking=True,
)
assert len(sent_messages) == 19
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 255, "ValueIDKey": 659128337}
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#00000000ff", "ValueIDKey": 659341335}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
light_msg.encode()
light_rgb_msg.decode()
light_rgb_msg.payload["Value"] = "#00000000ff"
light_rgb_msg.encode()
receive_message(light_msg)
receive_message(light_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["color_temp"] == 153
assert state.attributes["color_mode"] == "color_temp"
async def test_pure_rgb_dimmer_light(
hass, light_data, light_pure_rgb_msg, sent_messages
):
"""Test light with no color channels command class."""
receive_message = await setup_ozw(hass, fixture=light_data)
# Test loaded
state = hass.states.get("light.kitchen_rgb_strip_level")
assert state is not None
assert state.state == "on"
assert state.attributes["supported_features"] == 0
assert state.attributes["supported_color_modes"] == ["hs"]
assert state.attributes["color_mode"] == "hs"
# Test setting hs_color
new_color = [300, 70]
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.kitchen_rgb_strip_level", "hs_color": new_color},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 255, "ValueIDKey": 122257425}
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#ff4cff00", "ValueIDKey": 122470423}
# Feedback on state
light_pure_rgb_msg.decode()
light_pure_rgb_msg.payload["Value"] = "#ff4cff00"
light_pure_rgb_msg.encode()
receive_message(light_pure_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.kitchen_rgb_strip_level")
assert state is not None
assert state.state == "on"
assert state.attributes["hs_color"] == (300.0, 70.196)
assert state.attributes["color_mode"] == "hs"
async def test_no_rgb_light(hass, light_data, light_no_rgb_msg, sent_messages):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=light_data)
# Test loaded no RGBW support (dimmer only)
state = hass.states.get("light.master_bedroom_l_level")
assert state is not None
assert state.state == "off"
assert state.attributes["supported_features"] == 0
assert state.attributes["supported_color_modes"] == ["brightness"]
# Turn on the light
new_brightness = 44
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.master_bedroom_l_level", "brightness": new_brightness},
blocking=True,
)
assert len(sent_messages) == 1
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {
"Value": byte_to_zwave_brightness(new_brightness),
"ValueIDKey": 38371345,
}
# Feedback on state
light_no_rgb_msg.decode()
light_no_rgb_msg.payload["Value"] = byte_to_zwave_brightness(new_brightness)
light_no_rgb_msg.encode()
receive_message(light_no_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.master_bedroom_l_level")
assert state is not None
assert state.state == "on"
assert state.attributes["brightness"] == new_brightness
assert state.attributes["color_mode"] == "brightness"
async def test_no_ww_light(
hass, light_no_ww_data, light_msg, light_rgb_msg, sent_messages
):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=light_no_ww_data)
# Test loaded no ww support
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "off"
assert state.attributes["supported_features"] == 0
assert state.attributes["supported_color_modes"] == ["rgbw"]
# Turn on the light
white_color = 190
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.led_bulb_6_multi_colour_level",
"rgbw_color": [0, 0, 0, white_color],
},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#00000000be", "ValueIDKey": 659341335}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
light_msg.encode()
light_rgb_msg.decode()
light_rgb_msg.payload["Value"] = "#00000000be"
light_rgb_msg.encode()
receive_message(light_msg)
receive_message(light_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["color_mode"] == "rgbw"
assert state.attributes["rgbw_color"] == (0, 0, 0, 190)
async def test_no_cw_light(
hass, light_no_cw_data, light_msg, light_rgb_msg, sent_messages
):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=light_no_cw_data)
# Test loaded no cw support
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "off"
assert state.attributes["supported_features"] == 0
assert state.attributes["supported_color_modes"] == ["rgbw"]
# Turn on the light
white_color = 190
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.led_bulb_6_multi_colour_level",
"rgbw_color": [0, 0, 0, white_color],
},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#000000be", "ValueIDKey": 659341335}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
light_msg.encode()
light_rgb_msg.decode()
light_rgb_msg.payload["Value"] = "#000000be"
light_rgb_msg.encode()
receive_message(light_msg)
receive_message(light_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["color_mode"] == "rgbw"
assert state.attributes["rgbw_color"] == (0, 0, 0, 190)
async def test_wc_light(hass, light_wc_data, light_msg, light_rgb_msg, sent_messages):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=light_wc_data)
# Test loaded only white LED support
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "off"
assert state.attributes["supported_features"] == 0
assert state.attributes["supported_color_modes"] == ["color_temp", "hs"]
assert state.attributes["min_mireds"] == 153
assert state.attributes["max_mireds"] == 370
# Turn on the light
new_color = 190
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.led_bulb_6_multi_colour_level", "color_temp": new_color},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "#0000002bd4", "ValueIDKey": 659341335}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
light_msg.encode()
light_rgb_msg.decode()
light_rgb_msg.payload["Value"] = "#0000002bd4"
light_rgb_msg.encode()
receive_message(light_msg)
receive_message(light_rgb_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "on"
assert state.attributes["color_temp"] == 190
assert state.attributes["color_mode"] == "color_temp"
async def test_new_ozw_light(hass, light_new_ozw_data, light_msg, sent_messages):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=light_new_ozw_data)
# Test loaded only white LED support
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state is not None
assert state.state == "off"
assert state.attributes["supported_features"] == SUPPORT_TRANSITION
assert state.attributes["supported_color_modes"] == ["color_temp", "hs"]
# Test turning on with new duration (newer openzwave)
new_transition = 4180
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.led_bulb_6_multi_colour_level",
"transition": new_transition,
},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 4180, "ValueIDKey": 1407375551070225}
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 255, "ValueIDKey": 659128337}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = 255
light_msg.encode()
receive_message(light_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state.attributes["color_mode"] == "color_temp"
# Test turning off with new duration (newer openzwave)(new max)
await hass.services.async_call(
"light",
"turn_off",
{"entity_id": "light.led_bulb_6_multi_colour_level"},
blocking=True,
)
assert len(sent_messages) == 4
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 7621, "ValueIDKey": 1407375551070225}
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 0, "ValueIDKey": 659128337}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = 0
light_msg.encode()
receive_message(light_msg)
await hass.async_block_till_done()
# Test turning on with new duration (newer openzwave)(factory default)
new_transition = 8000
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.led_bulb_6_multi_colour_level",
"transition": new_transition,
},
blocking=True,
)
assert len(sent_messages) == 6
msg = sent_messages[-2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 6553, "ValueIDKey": 1407375551070225}
msg = sent_messages[-1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 255, "ValueIDKey": 659128337}
# Feedback on state
light_msg.decode()
light_msg.payload["Value"] = 255
light_msg.encode()
receive_message(light_msg)
await hass.async_block_till_done()
state = hass.states.get("light.led_bulb_6_multi_colour_level")
assert state.attributes["color_mode"] == "color_temp"

View File

@ -1,83 +0,0 @@
"""Test Z-Wave Locks."""
from .common import setup_ozw
async def test_lock(hass, lock_data, sent_messages, lock_msg, caplog):
"""Test lock."""
receive_message = await setup_ozw(hass, fixture=lock_data)
# Test loaded
state = hass.states.get("lock.danalock_v3_btze_locked")
assert state is not None
assert state.state == "unlocked"
# Test locking
await hass.services.async_call(
"lock", "lock", {"entity_id": "lock.danalock_v3_btze_locked"}, blocking=True
)
assert len(sent_messages) == 1
msg = sent_messages[0]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": True, "ValueIDKey": 173572112}
# Feedback on state
lock_msg.decode()
lock_msg.payload["Value"] = True
lock_msg.encode()
receive_message(lock_msg)
await hass.async_block_till_done()
state = hass.states.get("lock.danalock_v3_btze_locked")
assert state is not None
assert state.state == "locked"
# Test unlocking
await hass.services.async_call(
"lock", "unlock", {"entity_id": "lock.danalock_v3_btze_locked"}, blocking=True
)
assert len(sent_messages) == 2
msg = sent_messages[1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": False, "ValueIDKey": 173572112}
# Test set_usercode
await hass.services.async_call(
"ozw",
"set_usercode",
{
"entity_id": "lock.danalock_v3_btze_locked",
"usercode": 123456,
"code_slot": 1,
},
blocking=True,
)
assert len(sent_messages) == 3
msg = sent_messages[2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": "123456", "ValueIDKey": 281475150299159}
# Test clear_usercode
await hass.services.async_call(
"ozw",
"clear_usercode",
{"entity_id": "lock.danalock_v3_btze_locked", "code_slot": 1},
blocking=True,
)
assert len(sent_messages) == 5
msg = sent_messages[4]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 1, "ValueIDKey": 72057594219905046}
# Test set_usercode invalid length
await hass.services.async_call(
"ozw",
"set_usercode",
{
"entity_id": "lock.danalock_v3_btze_locked",
"usercode": "123",
"code_slot": 1,
},
blocking=True,
)
assert len(sent_messages) == 5
assert "User code must be at least 4 digits" in caplog.text

View File

@ -1,89 +0,0 @@
"""Test Z-Wave (central) Scenes."""
from .common import MQTTMessage, setup_ozw
from tests.common import async_capture_events
async def test_scenes(hass, generic_data, sent_messages):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=generic_data)
events = async_capture_events(hass, "ozw.scene_activated")
# Publish fake scene event on mqtt
message = MQTTMessage(
topic="OpenZWave/1/node/39/instance/1/commandclass/43/value/562950622511127/",
payload={
"Label": "Scene",
"Value": 16,
"Units": "",
"Min": -2147483648,
"Max": 2147483647,
"Type": "Int",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_SCENE_ACTIVATION",
"Index": 0,
"Node": 7,
"Genre": "User",
"Help": "",
"ValueIDKey": 122339347,
"ReadOnly": False,
"WriteOnly": False,
"ValueSet": False,
"ValuePolled": False,
"ChangeVerified": False,
"Event": "valueChanged",
"TimeStamp": 1579630367,
},
)
message.encode()
receive_message(message)
# wait for the event
await hass.async_block_till_done()
assert len(events) == 1
assert events[0].data["scene_value_id"] == 16
# Publish fake central scene event on mqtt
message = MQTTMessage(
topic="OpenZWave/1/node/39/instance/1/commandclass/91/value/281476005806100/",
payload={
"Label": "Scene 1",
"Value": {
"List": [
{"Value": 0, "Label": "Inactive"},
{"Value": 1, "Label": "Pressed 1 Time"},
{"Value": 2, "Label": "Key Released"},
{"Value": 3, "Label": "Key Held down"},
],
"Selected": "Pressed 1 Time",
"Selected_id": 1,
},
"Units": "",
"Min": 0,
"Max": 0,
"Type": "List",
"Instance": 1,
"CommandClass": "COMMAND_CLASS_CENTRAL_SCENE",
"Index": 1,
"Node": 61,
"Genre": "User",
"Help": "",
"ValueIDKey": 281476005806100,
"ReadOnly": False,
"WriteOnly": False,
"ValueSet": False,
"ValuePolled": False,
"ChangeVerified": False,
"Event": "valueChanged",
"TimeStamp": 1579640710,
},
)
message.encode()
receive_message(message)
# wait for the event
await hass.async_block_till_done()
assert len(events) == 2
assert events[1].data["scene_id"] == 1
assert events[1].data["scene_label"] == "Scene 1"
assert events[1].data["scene_value_label"] == "Pressed 1 Time"
assert events[1].data["instance_id"] == 1

View File

@ -1,93 +0,0 @@
"""Test Z-Wave Sensors."""
from homeassistant.components.ozw.const import DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN, SensorDeviceClass
from homeassistant.const import ATTR_DEVICE_CLASS
from homeassistant.helpers import entity_registry as er
from .common import setup_ozw
async def test_sensor(hass, generic_data):
"""Test setting up config entry."""
await setup_ozw(hass, fixture=generic_data)
# Test standard sensor
state = hass.states.get("sensor.smart_plug_electric_v")
assert state is not None
assert state.state == "123.9"
assert state.attributes["unit_of_measurement"] == "V"
# Test device classes
state = hass.states.get("sensor.trisensor_relative_humidity")
assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.HUMIDITY
state = hass.states.get("sensor.trisensor_pressure")
assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.PRESSURE
state = hass.states.get("sensor.trisensor_fake_power")
assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.POWER
state = hass.states.get("sensor.trisensor_fake_energy")
assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.POWER
state = hass.states.get("sensor.trisensor_fake_electric")
assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.POWER
# Test ZWaveListSensor disabled by default
registry = er.async_get(hass)
entity_id = "sensor.water_sensor_6_instance_1_water"
state = hass.states.get(entity_id)
assert state is None
entry = registry.async_get(entity_id)
assert entry
assert entry.disabled
assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION
# Test enabling entity
updated_entry = registry.async_update_entity(
entry.entity_id, **{"disabled_by": None}
)
assert updated_entry != entry
assert updated_entry.disabled is False
async def test_sensor_enabled(hass, generic_data, sensor_msg):
"""Test enabling an advanced sensor."""
registry = er.async_get(hass)
entry = registry.async_get_or_create(
SENSOR_DOMAIN,
DOMAIN,
"1-36-1407375493578772",
suggested_object_id="water_sensor_6_instance_1_water",
disabled_by=None,
)
assert entry.disabled is False
receive_msg = await setup_ozw(hass, fixture=generic_data)
receive_msg(sensor_msg)
await hass.async_block_till_done()
state = hass.states.get(entry.entity_id)
assert state is not None
assert state.state == "0"
assert state.attributes["label"] == "Clear"
async def test_string_sensor(hass, string_sensor_data):
"""Test so the returned type is a string sensor."""
registry = er.async_get(hass)
entry = registry.async_get_or_create(
SENSOR_DOMAIN,
DOMAIN,
"1-49-73464969749610519",
suggested_object_id="id_150_z_wave_module_user_code",
disabled_by=None,
)
await setup_ozw(hass, fixture=string_sensor_data)
await hass.async_block_till_done()
state = hass.states.get(entry.entity_id)
assert state is not None
assert state.state == "asdfgh"

View File

@ -1,115 +0,0 @@
"""Test Z-Wave Services."""
from openzwavemqtt.const import ATTR_POSITION, ATTR_VALUE
from openzwavemqtt.exceptions import InvalidValueError, NotFoundError, WrongTypeError
import pytest
from .common import setup_ozw
async def test_services(hass, light_data, sent_messages):
"""Test services on lock."""
await setup_ozw(hass, fixture=light_data)
# Test set_config_parameter list by label
await hass.services.async_call(
"ozw",
"set_config_parameter",
{"node_id": 39, "parameter": 1, "value": "Disable"},
blocking=True,
)
assert len(sent_messages) == 1
msg = sent_messages[0]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 0, "ValueIDKey": 281475641245716}
# Test set_config_parameter list by index int
await hass.services.async_call(
"ozw",
"set_config_parameter",
{"node_id": 39, "parameter": 1, "value": 1},
blocking=True,
)
assert len(sent_messages) == 2
msg = sent_messages[1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 1, "ValueIDKey": 281475641245716}
# Test set_config_parameter int
await hass.services.async_call(
"ozw",
"set_config_parameter",
{"node_id": 39, "parameter": 3, "value": 55},
blocking=True,
)
assert len(sent_messages) == 3
msg = sent_messages[2]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 55, "ValueIDKey": 844425594667027}
# Test set_config_parameter invalid list int
with pytest.raises(NotFoundError):
assert await hass.services.async_call(
"ozw",
"set_config_parameter",
{"node_id": 39, "parameter": 1, "value": 12},
blocking=True,
)
assert len(sent_messages) == 3
# Test set_config_parameter invalid list value
with pytest.raises(NotFoundError):
assert await hass.services.async_call(
"ozw",
"set_config_parameter",
{"node_id": 39, "parameter": 1, "value": "Blah"},
blocking=True,
)
assert len(sent_messages) == 3
# Test set_config_parameter invalid list value type
with pytest.raises(WrongTypeError):
assert await hass.services.async_call(
"ozw",
"set_config_parameter",
{
"node_id": 39,
"parameter": 1,
"value": {ATTR_VALUE: True, ATTR_POSITION: 1},
},
blocking=True,
)
assert len(sent_messages) == 3
# Test set_config_parameter int out of range
with pytest.raises(InvalidValueError):
assert await hass.services.async_call(
"ozw",
"set_config_parameter",
{"node_id": 39, "parameter": 3, "value": 2147483657},
blocking=True,
)
assert len(sent_messages) == 3
# Test set_config_parameter short
await hass.services.async_call(
"ozw",
"set_config_parameter",
{"node_id": 39, "parameter": 81, "value": 3000},
blocking=True,
)
assert len(sent_messages) == 4
msg = sent_messages[3]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 3000, "ValueIDKey": 22799473778098198}
# Test set_config_parameter byte
await hass.services.async_call(
"ozw",
"set_config_parameter",
{"node_id": 39, "parameter": 16, "value": 20},
blocking=True,
)
assert len(sent_messages) == 5
msg = sent_messages[4]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": 20, "ValueIDKey": 4503600291905553}

View File

@ -1,41 +0,0 @@
"""Test Z-Wave Switches."""
from .common import setup_ozw
async def test_switch(hass, generic_data, sent_messages, switch_msg):
"""Test setting up config entry."""
receive_message = await setup_ozw(hass, fixture=generic_data)
# Test loaded
state = hass.states.get("switch.smart_plug_switch")
assert state is not None
assert state.state == "off"
# Test turning on
await hass.services.async_call(
"switch", "turn_on", {"entity_id": "switch.smart_plug_switch"}, blocking=True
)
assert len(sent_messages) == 1
msg = sent_messages[0]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": True, "ValueIDKey": 541671440}
# Feedback on state
switch_msg.decode()
switch_msg.payload["Value"] = True
switch_msg.encode()
receive_message(switch_msg)
await hass.async_block_till_done()
state = hass.states.get("switch.smart_plug_switch")
assert state is not None
assert state.state == "on"
# Test turning off
await hass.services.async_call(
"switch", "turn_off", {"entity_id": "switch.smart_plug_switch"}, blocking=True
)
assert len(sent_messages) == 2
msg = sent_messages[1]
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
assert msg["payload"] == {"Value": False, "ValueIDKey": 541671440}

View File

@ -1,387 +0,0 @@
"""Test OpenZWave Websocket API."""
from unittest.mock import patch
from openzwavemqtt.const import (
ATTR_CODE_SLOT,
ATTR_LABEL,
ATTR_OPTIONS,
ATTR_POSITION,
ATTR_VALUE,
ValueType,
)
from homeassistant.components.ozw.const import ATTR_CONFIG_PARAMETER
from homeassistant.components.ozw.lock import ATTR_USERCODE
from homeassistant.components.ozw.websocket_api import (
ATTR_IS_AWAKE,
ATTR_IS_BEAMING,
ATTR_IS_FAILED,
ATTR_IS_FLIRS,
ATTR_IS_ROUTING,
ATTR_IS_SECURITYV1,
ATTR_IS_ZWAVE_PLUS,
ATTR_NEIGHBORS,
ATTR_NODE_BASIC_STRING,
ATTR_NODE_BAUD_RATE,
ATTR_NODE_GENERIC_STRING,
ATTR_NODE_QUERY_STAGE,
ATTR_NODE_SPECIFIC_STRING,
ID,
NODE_ID,
OZW_INSTANCE,
PARAMETER,
SCHEMA,
TYPE,
VALUE,
)
from homeassistant.components.websocket_api.const import (
ERR_INVALID_FORMAT,
ERR_NOT_FOUND,
ERR_NOT_SUPPORTED,
)
from .common import MQTTMessage, setup_ozw
async def test_websocket_api(hass, generic_data, hass_ws_client, mqtt_mock):
"""Test the ozw websocket api."""
await setup_ozw(hass, fixture=generic_data)
client = await hass_ws_client(hass)
# Test instance list
await client.send_json({ID: 4, TYPE: "ozw/get_instances"})
msg = await client.receive_json()
assert len(msg["result"]) == 1
result = msg["result"][0]
assert result[OZW_INSTANCE] == 1
assert result["Status"] == "driverAllNodesQueried"
assert result["OpenZWave_Version"] == "1.6.1008"
# Test network status
await client.send_json({ID: 5, TYPE: "ozw/network_status"})
msg = await client.receive_json()
result = msg["result"]
assert result["Status"] == "driverAllNodesQueried"
assert result[OZW_INSTANCE] == 1
# Test node status
await client.send_json({ID: 6, TYPE: "ozw/node_status", NODE_ID: 32})
msg = await client.receive_json()
result = msg["result"]
assert result[OZW_INSTANCE] == 1
assert result[NODE_ID] == 32
assert result[ATTR_NODE_QUERY_STAGE] == "Complete"
assert result[ATTR_IS_ZWAVE_PLUS]
assert result[ATTR_IS_AWAKE]
assert not result[ATTR_IS_FAILED]
assert result[ATTR_NODE_BAUD_RATE] == 100000
assert result[ATTR_IS_BEAMING]
assert not result[ATTR_IS_FLIRS]
assert result[ATTR_IS_ROUTING]
assert not result[ATTR_IS_SECURITYV1]
assert result[ATTR_NODE_BASIC_STRING] == "Routing Slave"
assert result[ATTR_NODE_GENERIC_STRING] == "Binary Switch"
assert result[ATTR_NODE_SPECIFIC_STRING] == "Binary Power Switch"
assert result[ATTR_NEIGHBORS] == [1, 33, 36, 37, 39]
await client.send_json({ID: 7, TYPE: "ozw/node_status", NODE_ID: 999})
msg = await client.receive_json()
result = msg["error"]
assert result["code"] == ERR_NOT_FOUND
# Test node statistics
await client.send_json({ID: 8, TYPE: "ozw/node_statistics", NODE_ID: 39})
msg = await client.receive_json()
result = msg["result"]
assert result[OZW_INSTANCE] == 1
assert result[NODE_ID] == 39
assert result["send_count"] == 57
assert result["sent_failed"] == 0
assert result["retries"] == 1
assert result["last_request_rtt"] == 26
assert result["last_response_rtt"] == 38
assert result["average_request_rtt"] == 29
assert result["average_response_rtt"] == 37
assert result["received_packets"] == 3594
assert result["received_dup_packets"] == 12
assert result["received_unsolicited"] == 3546
# Test node metadata
await client.send_json({ID: 9, TYPE: "ozw/node_metadata", NODE_ID: 39})
msg = await client.receive_json()
result = msg["result"]
assert result["metadata"]["ProductPic"] == "images/aeotec/zwa002.png"
await client.send_json({ID: 10, TYPE: "ozw/node_metadata", NODE_ID: 999})
msg = await client.receive_json()
result = msg["error"]
assert result["code"] == ERR_NOT_FOUND
# Test network statistics
await client.send_json({ID: 11, TYPE: "ozw/network_statistics"})
msg = await client.receive_json()
result = msg["result"]
assert result["readCnt"] == 92220
assert result[OZW_INSTANCE] == 1
assert result["node_count"] == 5
# Test get nodes
await client.send_json({ID: 12, TYPE: "ozw/get_nodes"})
msg = await client.receive_json()
result = msg["result"]
assert len(result) == 5
assert result[2][ATTR_IS_AWAKE]
assert not result[1][ATTR_IS_FAILED]
# Test get config parameters
await client.send_json({ID: 13, TYPE: "ozw/get_config_parameters", NODE_ID: 39})
msg = await client.receive_json()
result = msg["result"]
assert len(result) == 8
for config_param in result:
assert config_param["type"] in (
ValueType.LIST.value,
ValueType.BOOL.value,
ValueType.INT.value,
ValueType.BYTE.value,
ValueType.SHORT.value,
ValueType.BITSET.value,
)
# Test set config parameter
config_param = result[0]
current_val = config_param[ATTR_VALUE]
new_val = next(
option[0]
for option in config_param[SCHEMA][0][ATTR_OPTIONS]
if option[0] != current_val
)
new_label = next(
option[1]
for option in config_param[SCHEMA][0][ATTR_OPTIONS]
if option[1] != current_val and option[0] != new_val
)
await client.send_json(
{
ID: 14,
TYPE: "ozw/set_config_parameter",
NODE_ID: 39,
PARAMETER: config_param[ATTR_CONFIG_PARAMETER],
VALUE: new_val,
}
)
msg = await client.receive_json()
assert msg["success"]
await client.send_json(
{
ID: 15,
TYPE: "ozw/set_config_parameter",
NODE_ID: 39,
PARAMETER: config_param[ATTR_CONFIG_PARAMETER],
VALUE: new_label,
}
)
msg = await client.receive_json()
assert msg["success"]
# Test OZW Instance not found error
await client.send_json(
{ID: 16, TYPE: "ozw/get_config_parameters", OZW_INSTANCE: 999, NODE_ID: 1}
)
msg = await client.receive_json()
result = msg["error"]
assert result["code"] == ERR_NOT_FOUND
# Test OZW Node not found error
await client.send_json(
{
ID: 18,
TYPE: "ozw/set_config_parameter",
NODE_ID: 999,
PARAMETER: 0,
VALUE: "test",
}
)
msg = await client.receive_json()
result = msg["error"]
assert result["code"] == ERR_NOT_FOUND
# Test parameter not found
await client.send_json(
{
ID: 19,
TYPE: "ozw/set_config_parameter",
NODE_ID: 39,
PARAMETER: 45,
VALUE: "test",
}
)
msg = await client.receive_json()
result = msg["error"]
assert result["code"] == ERR_NOT_FOUND
# Test list value not found
await client.send_json(
{
ID: 20,
TYPE: "ozw/set_config_parameter",
NODE_ID: 39,
PARAMETER: config_param[ATTR_CONFIG_PARAMETER],
VALUE: "test",
}
)
msg = await client.receive_json()
result = msg["error"]
assert result["code"] == ERR_NOT_FOUND
# Test value type invalid
await client.send_json(
{
ID: 21,
TYPE: "ozw/set_config_parameter",
NODE_ID: 39,
PARAMETER: 3,
VALUE: 0,
}
)
msg = await client.receive_json()
result = msg["error"]
assert result["code"] == ERR_NOT_SUPPORTED
# Test invalid bitset format
await client.send_json(
{
ID: 22,
TYPE: "ozw/set_config_parameter",
NODE_ID: 39,
PARAMETER: 3,
VALUE: {ATTR_POSITION: 1, ATTR_VALUE: True, ATTR_LABEL: "test"},
}
)
msg = await client.receive_json()
result = msg["error"]
assert result["code"] == ERR_INVALID_FORMAT
# Test valid bitset format passes validation
await client.send_json(
{
ID: 23,
TYPE: "ozw/set_config_parameter",
NODE_ID: 39,
PARAMETER: 10000,
VALUE: {ATTR_POSITION: 1, ATTR_VALUE: True},
}
)
msg = await client.receive_json()
result = msg["error"]
assert result["code"] == ERR_NOT_FOUND
async def test_ws_locks(hass, lock_data, hass_ws_client, mqtt_mock):
"""Test lock websocket apis."""
await setup_ozw(hass, fixture=lock_data)
client = await hass_ws_client(hass)
await client.send_json(
{
ID: 1,
TYPE: "ozw/get_code_slots",
NODE_ID: 10,
}
)
msg = await client.receive_json()
assert msg["success"]
await client.send_json(
{
ID: 2,
TYPE: "ozw/set_usercode",
NODE_ID: 10,
ATTR_CODE_SLOT: 1,
ATTR_USERCODE: "1234",
}
)
msg = await client.receive_json()
assert msg["success"]
await client.send_json(
{
ID: 3,
TYPE: "ozw/clear_usercode",
NODE_ID: 10,
ATTR_CODE_SLOT: 1,
}
)
msg = await client.receive_json()
assert msg["success"]
async def test_refresh_node(
hass, generic_data, sent_messages, hass_ws_client, mqtt_mock
):
"""Test the ozw refresh node api."""
receive_message = await setup_ozw(hass, fixture=generic_data)
client = await hass_ws_client(hass)
# Send the refresh_node_info command
await client.send_json({ID: 9, TYPE: "ozw/refresh_node_info", NODE_ID: 39})
msg = await client.receive_json()
assert len(sent_messages) == 1
assert msg["success"]
# Receive a mock status update from OZW
message = MQTTMessage(
topic="OpenZWave/1/node/39/",
payload={"NodeID": 39, "NodeQueryStage": "initializing"},
)
message.encode()
receive_message(message)
# Verify we got expected data on the websocket
msg = await client.receive_json()
result = msg["event"]
assert result["type"] == "node_updated"
assert result["node_query_stage"] == "initializing"
# Send another mock status update from OZW
message = MQTTMessage(
topic="OpenZWave/1/node/39/",
payload={"NodeID": 39, "NodeQueryStage": "versions"},
)
message.encode()
receive_message(message)
# Send a mock status update for a different node
message = MQTTMessage(
topic="OpenZWave/1/node/35/",
payload={"NodeID": 35, "NodeQueryStage": "fake_shouldnt_be_received"},
)
message.encode()
receive_message(message)
# Verify we received the message for node 39 but not for node 35
msg = await client.receive_json()
result = msg["event"]
assert result["type"] == "node_updated"
assert result["node_query_stage"] == "versions"
async def test_refresh_node_unsubscribe(hass, generic_data, hass_ws_client, mqtt_mock):
"""Test unsubscribing the ozw refresh node api."""
await setup_ozw(hass, fixture=generic_data)
client = await hass_ws_client(hass)
with patch("openzwavemqtt.OZWOptions.listen") as mock_listen:
# Send the refresh_node_info command
await client.send_json({ID: 9, TYPE: "ozw/refresh_node_info", NODE_ID: 39})
await client.receive_json()
# Send the unsubscribe command
await client.send_json({ID: 10, TYPE: "unsubscribe_events", "subscription": 9})
await client.receive_json()
assert mock_listen.return_value.called