Add zwave_js integration (#45020)
* Run zwave_js scaffold (#44891) * Add zwave_js basic connection to zwave server (#44904) * add the basic connection to zwave server * fix name * Fix requirements * Fix things * Version bump dep to 0.1.2 * fix pylint Co-authored-by: Paulus Schoutsen <balloob@gmail.com> * Bump zwave-js-server-python to 0.2.0 * Use zwave js server version check instead of fetching full state (#44943) * Use version check instead of fetching full state * Fix tests * Use 0.3.0 * Also catch aiohttp client errors * Update docstring * Lint * Unignore zwave_js * Add zwave_js entity discovery basics and sensor platform (#44927) Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Paulus Schoutsen <balloob@gmail.com> * Complete zwave_js typing (#44960) * Type discovery * Type init * Type entity * Type config flow * Type sensor * Require typing of zwave_js * Complete zwave_js config flow test coverage (#44955) * Correct zwave_js sensor device class (#44968) * Fix zwave_js KeyError on entry setup timeout (#44966) * Bump zwave-js-server-python to 0.5.0 (#44975) * Remove stale callback signal from zwave_js (#44994) * Add light platform to zwave_js integration (#44974) * add light platform * styling fix * fix type hint * Fix typing * Update homeassistant/components/zwave_js/const.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/zwave_js/entity.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/zwave_js/entity.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/zwave_js/entity.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/zwave_js/entity.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/zwave_js/entity.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * color temp should be integer * guard Nonetype error * Update homeassistant/components/zwave_js/light.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/zwave_js/light.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * some fixes after merging * add additional guards for None values * adjustments for rgb lights * Fix typing * Fix black * Bump zwave-js-server-python to 0.6.0 * guard value updated log * remove value_id lookup as its no longer needed * fiz sending white value * Update homeassistant/components/zwave_js/light.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Add zwave_js test foundation (#44983) * Exclude text files from codespell * Add basic dump fixture * Add test foundation * Fix test after rebase * Exclude jsonl files from codespell * Rename fixture file type to jsonl * Update fixture path * Fix stale docstring * Add controller state json fixture * Add multisensor 6 state json fixture * Update fixtures * Remove basic dump fixture * Fix fixtures after library bump * Update codeowner * Minor cleanup Z-Wave JS (#45021) * Update zwave_js device_info (#45023) Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com> Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
1402e7ae56
commit
d68fdbc283
23 changed files with 3212 additions and 2 deletions
151
homeassistant/components/zwave_js/entity.py
Normal file
151
homeassistant/components/zwave_js/entity.py
Normal file
|
@ -0,0 +1,151 @@
|
|||
"""Generic Z-Wave Entity Class."""
|
||||
|
||||
import logging
|
||||
from typing import Optional, Union
|
||||
|
||||
from zwave_js_server.client import Client as ZwaveClient
|
||||
from zwave_js_server.model.value import Value as ZwaveValue, get_value_id
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import DOMAIN
|
||||
from .discovery import ZwaveDiscoveryInfo
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
EVENT_VALUE_UPDATED = "value updated"
|
||||
|
||||
|
||||
class ZWaveBaseEntity(Entity):
|
||||
"""Generic Entity Class for a Z-Wave Device."""
|
||||
|
||||
def __init__(self, client: ZwaveClient, info: ZwaveDiscoveryInfo) -> None:
|
||||
"""Initialize a generic Z-Wave device entity."""
|
||||
self.client = client
|
||||
self.info = info
|
||||
# entities requiring additional values, can add extra ids to this list
|
||||
self.watched_value_ids = {self.info.primary_value.value_id}
|
||||
|
||||
@callback
|
||||
def on_value_update(self) -> None:
|
||||
"""Call when one of the watched values change.
|
||||
|
||||
To be overridden by platforms needing this event.
|
||||
"""
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Call when entity is added."""
|
||||
assert self.hass # typing
|
||||
# Add value_changed callbacks.
|
||||
self.async_on_remove(
|
||||
self.info.node.on(EVENT_VALUE_UPDATED, self._value_changed)
|
||||
)
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, f"{DOMAIN}_connection_state", self.async_write_ha_state
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
def device_info(self) -> dict:
|
||||
"""Return device information for the device registry."""
|
||||
# device is precreated in main handler
|
||||
return {
|
||||
"identifiers": {
|
||||
(
|
||||
DOMAIN,
|
||||
f"{self.client.driver.controller.home_id}-{self.info.node.node_id}",
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return default name from device name and value name combination."""
|
||||
node_name = self.info.node.name or self.info.node.device_config.description
|
||||
value_name = (
|
||||
self.info.primary_value.metadata.label
|
||||
or self.info.primary_value.property_key_name
|
||||
or self.info.primary_value.property_name
|
||||
)
|
||||
return f"{node_name}: {value_name}"
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique_id of the entity."""
|
||||
return f"{self.client.driver.controller.home_id}.{self.info.value_id}"
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return entity availability."""
|
||||
return self.client.connected and bool(self.info.node.ready)
|
||||
|
||||
@callback
|
||||
def _value_changed(self, event_data: Union[dict, ZwaveValue]) -> None:
|
||||
"""Call when (one of) our watched values changes.
|
||||
|
||||
Should not be overridden by subclasses.
|
||||
"""
|
||||
if isinstance(event_data, ZwaveValue):
|
||||
value_id = event_data.value_id
|
||||
else:
|
||||
value_id = event_data["value"].value_id
|
||||
|
||||
if value_id not in self.watched_value_ids:
|
||||
return
|
||||
|
||||
value = self.info.node.values[value_id]
|
||||
|
||||
LOGGER.debug(
|
||||
"[%s] Value %s/%s changed to: %s",
|
||||
self.entity_id,
|
||||
value.property_,
|
||||
value.property_key_name,
|
||||
value.value,
|
||||
)
|
||||
|
||||
self.on_value_update()
|
||||
self.async_write_ha_state()
|
||||
|
||||
@callback
|
||||
def get_zwave_value(
|
||||
self,
|
||||
value_property: Union[str, int],
|
||||
command_class: Optional[int] = None,
|
||||
endpoint: Optional[int] = None,
|
||||
value_property_key_name: Optional[str] = None,
|
||||
add_to_watched_value_ids: bool = True,
|
||||
) -> Optional[ZwaveValue]:
|
||||
"""Return specific ZwaveValue on this ZwaveNode."""
|
||||
# use commandclass and endpoint from primary value if omitted
|
||||
return_value = None
|
||||
if command_class is None:
|
||||
command_class = self.info.primary_value.command_class
|
||||
if endpoint is None:
|
||||
endpoint = self.info.primary_value.endpoint
|
||||
# lookup value by value_id
|
||||
value_id = get_value_id(
|
||||
self.info.node,
|
||||
{
|
||||
"commandClass": command_class,
|
||||
"endpoint": endpoint,
|
||||
"property": value_property,
|
||||
"propertyKeyName": value_property_key_name,
|
||||
},
|
||||
)
|
||||
return_value = self.info.node.values.get(value_id)
|
||||
# add to watched_ids list so we will be triggered when the value updates
|
||||
if (
|
||||
return_value
|
||||
and return_value.value_id not in self.watched_value_ids
|
||||
and add_to_watched_value_ids
|
||||
):
|
||||
self.watched_value_ids.add(return_value.value_id)
|
||||
return return_value
|
||||
|
||||
@property
|
||||
def should_poll(self) -> bool:
|
||||
"""No polling needed."""
|
||||
return False
|
Loading…
Add table
Add a link
Reference in a new issue