2017-03-03 12:47:59 +00:00
|
|
|
"""Zwave util methods."""
|
2018-05-08 19:30:28 +00:00
|
|
|
import asyncio
|
2017-03-03 12:47:59 +00:00
|
|
|
import logging
|
|
|
|
|
2018-05-08 19:30:28 +00:00
|
|
|
import homeassistant.util.dt as dt_util
|
|
|
|
|
2017-03-14 23:55:33 +00:00
|
|
|
from . import const
|
|
|
|
|
2017-03-03 12:47:59 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2017-03-14 23:55:33 +00:00
|
|
|
def check_node_schema(node, schema):
|
|
|
|
"""Check if node matches the passed node schema."""
|
2019-07-31 19:25:30 +00:00
|
|
|
if const.DISC_NODE_ID in schema and node.node_id not in schema[const.DISC_NODE_ID]:
|
|
|
|
_LOGGER.debug(
|
|
|
|
"node.node_id %s not in node_id %s",
|
|
|
|
node.node_id,
|
|
|
|
schema[const.DISC_NODE_ID],
|
|
|
|
)
|
2017-03-14 23:55:33 +00:00
|
|
|
return False
|
2019-07-31 19:25:30 +00:00
|
|
|
if (
|
|
|
|
const.DISC_GENERIC_DEVICE_CLASS in schema
|
|
|
|
and node.generic not in schema[const.DISC_GENERIC_DEVICE_CLASS]
|
|
|
|
):
|
|
|
|
_LOGGER.debug(
|
|
|
|
"node.generic %s not in generic_device_class %s",
|
|
|
|
node.generic,
|
|
|
|
schema[const.DISC_GENERIC_DEVICE_CLASS],
|
|
|
|
)
|
2017-03-14 23:55:33 +00:00
|
|
|
return False
|
2019-07-31 19:25:30 +00:00
|
|
|
if (
|
|
|
|
const.DISC_SPECIFIC_DEVICE_CLASS in schema
|
|
|
|
and node.specific not in schema[const.DISC_SPECIFIC_DEVICE_CLASS]
|
|
|
|
):
|
|
|
|
_LOGGER.debug(
|
|
|
|
"node.specific %s not in specific_device_class %s",
|
|
|
|
node.specific,
|
|
|
|
schema[const.DISC_SPECIFIC_DEVICE_CLASS],
|
|
|
|
)
|
2017-03-14 23:55:33 +00:00
|
|
|
return False
|
|
|
|
return True
|
2017-03-03 12:47:59 +00:00
|
|
|
|
|
|
|
|
2017-03-14 23:55:33 +00:00
|
|
|
def check_value_schema(value, schema):
|
|
|
|
"""Check if the value matches the passed value schema."""
|
2019-07-31 19:25:30 +00:00
|
|
|
if (
|
|
|
|
const.DISC_COMMAND_CLASS in schema
|
|
|
|
and value.command_class not in schema[const.DISC_COMMAND_CLASS]
|
|
|
|
):
|
|
|
|
_LOGGER.debug(
|
|
|
|
"value.command_class %s not in command_class %s",
|
|
|
|
value.command_class,
|
|
|
|
schema[const.DISC_COMMAND_CLASS],
|
|
|
|
)
|
2017-03-14 23:55:33 +00:00
|
|
|
return False
|
2019-07-31 19:25:30 +00:00
|
|
|
if const.DISC_TYPE in schema and value.type not in schema[const.DISC_TYPE]:
|
|
|
|
_LOGGER.debug(
|
|
|
|
"value.type %s not in type %s", value.type, schema[const.DISC_TYPE]
|
|
|
|
)
|
2017-03-14 23:55:33 +00:00
|
|
|
return False
|
2019-07-31 19:25:30 +00:00
|
|
|
if const.DISC_GENRE in schema and value.genre not in schema[const.DISC_GENRE]:
|
|
|
|
_LOGGER.debug(
|
|
|
|
"value.genre %s not in genre %s", value.genre, schema[const.DISC_GENRE]
|
|
|
|
)
|
2017-03-14 23:55:33 +00:00
|
|
|
return False
|
2019-07-31 19:25:30 +00:00
|
|
|
if const.DISC_INDEX in schema and value.index not in schema[const.DISC_INDEX]:
|
|
|
|
_LOGGER.debug(
|
|
|
|
"value.index %s not in index %s", value.index, schema[const.DISC_INDEX]
|
|
|
|
)
|
2017-03-14 23:55:33 +00:00
|
|
|
return False
|
2019-07-31 19:25:30 +00:00
|
|
|
if (
|
|
|
|
const.DISC_INSTANCE in schema
|
|
|
|
and value.instance not in schema[const.DISC_INSTANCE]
|
|
|
|
):
|
|
|
|
_LOGGER.debug(
|
|
|
|
"value.instance %s not in instance %s",
|
|
|
|
value.instance,
|
|
|
|
schema[const.DISC_INSTANCE],
|
|
|
|
)
|
2017-03-14 23:55:33 +00:00
|
|
|
return False
|
2017-06-14 12:41:20 +00:00
|
|
|
if const.DISC_SCHEMAS in schema:
|
2017-08-14 01:15:59 +00:00
|
|
|
found = False
|
2017-06-14 12:41:20 +00:00
|
|
|
for schema_item in schema[const.DISC_SCHEMAS]:
|
2017-08-14 01:15:59 +00:00
|
|
|
found = found or check_value_schema(value, schema_item)
|
|
|
|
if not found:
|
|
|
|
return False
|
|
|
|
|
2017-03-14 23:55:33 +00:00
|
|
|
return True
|
2017-03-23 15:37:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
def node_name(node):
|
|
|
|
"""Return the name of the node."""
|
2018-05-29 01:49:38 +00:00
|
|
|
if is_node_parsed(node):
|
2019-09-03 19:15:31 +00:00
|
|
|
return node.name or f"{node.manufacturer_name} {node.product_name}"
|
|
|
|
return f"Unknown Node {node.node_id}"
|
2018-05-08 19:30:28 +00:00
|
|
|
|
|
|
|
|
2019-07-07 05:36:57 +00:00
|
|
|
def node_device_id_and_name(node, instance=1):
|
|
|
|
"""Return the name and device ID for the value with the given index."""
|
|
|
|
name = node_name(node)
|
|
|
|
if instance == 1:
|
|
|
|
return ((const.DOMAIN, node.node_id), name)
|
2019-09-03 19:15:31 +00:00
|
|
|
name = f"{name} ({instance})"
|
2019-07-07 05:36:57 +00:00
|
|
|
return ((const.DOMAIN, node.node_id, instance), name)
|
|
|
|
|
|
|
|
|
2019-07-01 22:54:19 +00:00
|
|
|
async def check_has_unique_id(entity, ready_callback, timeout_callback):
|
2018-05-08 19:30:28 +00:00
|
|
|
"""Wait for entity to have unique_id."""
|
|
|
|
start_time = dt_util.utcnow()
|
|
|
|
while True:
|
2019-07-31 19:25:30 +00:00
|
|
|
waited = int((dt_util.utcnow() - start_time).total_seconds())
|
2018-05-08 19:30:28 +00:00
|
|
|
if entity.unique_id:
|
|
|
|
ready_callback(waited)
|
|
|
|
return
|
2018-07-23 08:16:05 +00:00
|
|
|
if waited >= const.NODE_READY_WAIT_SECS:
|
2018-05-08 19:30:28 +00:00
|
|
|
# Wait up to NODE_READY_WAIT_SECS seconds for unique_id to appear.
|
|
|
|
timeout_callback(waited)
|
|
|
|
return
|
2019-07-01 22:54:19 +00:00
|
|
|
await asyncio.sleep(1)
|
2018-05-08 19:30:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
def is_node_parsed(node):
|
|
|
|
"""Check whether the node has been parsed or still waiting to be parsed."""
|
2018-05-29 01:49:38 +00:00
|
|
|
return bool((node.manufacturer_name and node.product_name) or node.name)
|