A more robust and scalable way of merging/handling the currentValue/targetValue duality in zwave.mqtt

This commit is contained in:
Fabio Manganiello 2023-01-01 12:45:41 +01:00
parent 0513339be7
commit f9b6799a18
Signed by: blacklight
GPG key ID: D90FBA7F76362774

View file

@ -520,26 +520,57 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
assert values, f'No such value: {value_id or value_label}' assert values, f'No such value: {value_id or value_label}'
value = values[0] value = values[0]
if value.get('property_id') == 'targetValue':
cur_value_id = '-'.join(
value['value_id'].split('-')[:-1] + ['currentValue']
)
cur_value = (
self._nodes_cache['by_id'][value['node_id']]
.get('values', {})
.get(cur_value_id)
)
if cur_value:
value['data'] = cur_value['data']
self._values_cache['by_id'][value['id']] = value self._values_cache['by_id'][value['id']] = value
if value['label']: if value['label']:
self._values_cache['by_label'][value['label']] = value self._values_cache['by_label'][value['label']] = value
self.publish_entities([value]) # type: ignore self.publish_entities([self._to_current_value(value)]) # type: ignore
return value return value
@staticmethod
def _is_target_value(value: Mapping):
return value.get('property_id') in {'targetValue', 'targetColor'}
@staticmethod
def _is_current_value(value: Mapping):
return value.get('property_id') in {'currentValue', 'currentColor'}
def _to_current_value(self, value: dict) -> dict:
return self._get_associated_value(value, 'current')
def _to_target_value(self, value: dict) -> dict:
return self._get_associated_value(value, 'target')
def _get_associated_value(self, value: dict, target: str) -> dict:
check_func = (
self._is_target_value if target == 'current' else self._is_current_value
)
if not check_func(value):
return value
replace_args = (
('target', 'current') if target == 'current' else ('current', 'target')
)
associated_value_id = '-'.join(
value['value_id'].split('-')[:-1]
+ [value['value_id'].split('-')[-1].replace(*replace_args)]
)
associated_value = self._values_cache['by_id'].get(
associated_value_id,
self._nodes_cache['by_id']
.get(value['node_id'], {})
.get('values', {})
.get(associated_value_id),
)
if associated_value:
value = associated_value
return value.copy()
@staticmethod @staticmethod
def _matches_classes(value: Mapping, *names: str): def _matches_classes(value: Mapping, *names: str):
classes = {command_class_by_name[name] for name in names} classes = {command_class_by_name[name] for name in names}
@ -619,17 +650,8 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
and value.get('type') == 'Decimal' and value.get('type') == 'Decimal'
) )
def _to_entity_args(self, value: Mapping) -> dict: def _to_entity_args(self, value: dict) -> dict:
if value['id'].endswith('-targetValue'): value = self._to_current_value(value)
current_value_id = '-'.join(value['id'].split('-')[:-1] + ['currentValue'])
value = {
**value,
'id': current_value_id,
'label': 'Value',
'is_read_only': False,
'is_write_only': False,
}
args = { args = {
'id': value['id'], 'id': value['id'],
'name': value.get('label'), 'name': value.get('label'),
@ -642,13 +664,27 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
args['updated_at'] = value['last_update'] args['updated_at'] = value['last_update']
return args return args
def transform_entities(self, values: Iterable[Mapping]): def transform_entities(self, values: Iterable[dict]):
entities = [] entities = []
for value in values: for value in values:
if not value or self._matches_classes(value, *self._ignored_entity_classes): if not value or self._matches_classes(value, *self._ignored_entity_classes):
continue continue
value = value.copy()
current_value = target_value = None
if self._is_current_value(value):
current_value = value
target_value = self._to_target_value(value)
elif self._is_target_value(value):
current_value = self._to_current_value(value)
target_value = value
if current_value and target_value:
value = self._merge_current_and_target_values(
[current_value, target_value]
)[0]
entity_type = None entity_type = None
entity_args = self._to_entity_args(value) entity_args = self._to_entity_args(value)
sensor_type, sensor_args = self._get_sensor_args(value) sensor_type, sensor_args = self._get_sensor_args(value)
@ -720,39 +756,51 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
entity.parent = parent entity.parent = parent
entity.reachable = parent.reachable entity.reachable = parent.reachable
@staticmethod @classmethod
def _merge_current_and_target_values(values: Iterable[dict]) -> List[dict]: def _merge_current_and_target_values(cls, values: Iterable[dict]) -> List[dict]:
values_by_id = OrderedDict({v.get('id'): v for v in values}) values_by_id = OrderedDict({v.get('id'): v for v in values})
new_values = OrderedDict() new_values = OrderedDict()
for value in values: for value in values:
value = value.copy()
value_id = value.get('id') value_id = value.get('id')
if not value_id: if not value_id:
continue continue
associated_value_id = None associated_value_id = None
associated_value = None associated_value = None
associated_property_id = None
current_property_id = None
current_value = None
value_id_prefix = '-'.join(value_id.split('-')[:-1]) value_id_prefix = '-'.join(value_id.split('-')[:-1])
if value_id.endswith('-currentValue'): if cls._is_current_value(value):
associated_value_id = value_id_prefix + '-targetValue' associated_property_id = value['property_id'].replace(
elif value_id.endswith('-targetValue'): 'current', 'target'
associated_value_id = value_id_prefix + '-currentValue' )
if associated_value_id: current_property_id = value['property_id']
current_value = value
elif cls._is_target_value(value):
associated_property_id = value['property_id'].replace(
'target', 'current'
)
current_property_id = associated_property_id
if associated_property_id:
associated_value_id = f'{value_id_prefix}-{associated_property_id}'
associated_value = values_by_id.pop(associated_value_id, None) associated_value = values_by_id.pop(associated_value_id, None)
if associated_value: if cls._is_target_value(value):
current_value = associated_value
if current_value and associated_value and current_property_id:
value = value.copy() value = value.copy()
value_id = value_id_prefix + '-currentValue' value_id = f'{value_id_prefix}-{current_property_id}'
value['data'] = ( value['data'] = current_value.get('data')
value.get('data')
if value.get('id', '').endswith('-currentValue')
else associated_value.get('data')
)
value['id'] = value['value_id'] = value['id_on_network'] = value_id value['id'] = value['value_id'] = value['id_on_network'] = value_id
value['is_read_only'] = value['is_write_only'] = False value['is_read_only'] = value['is_write_only'] = False
value['label'] = 'Value' value['label'] = 'Value'
value['property_id'] = 'currentValue' value['property_id'] = current_property_id
value['last_update'] = ( value['last_update'] = (
max( max(
value.get('last_update') or 0, value.get('last_update') or 0,
@ -800,17 +848,7 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
) or (filter_callback and not filter_callback(value)): ) or (filter_callback and not filter_callback(value)):
continue continue
value_id = value['id_on_network'] value = self._to_current_value(value)
if value_id.split('-').pop() == 'targetValue':
value_id = '-'.join(value_id.split('-')[:-1]) + '-currentValue'
cur_value = (
self._nodes_cache['by_id'][value['node_id']]
.get('values', {})
.get(value_id)
)
if cur_value:
value['data'] = cur_value['data']
values[value['id_on_network']] = value values[value['id_on_network']] = value
entity_values = self._merge_current_and_target_values(values.values()) entity_values = self._merge_current_and_target_values(values.values())
@ -1419,11 +1457,6 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
if args: if args:
value_id = args[0] value_id = args[0]
id_ = str(value_id or id_on_network or '')
if id_.endswith('-currentValue'):
id_ = '-'.join(id_.split('-')[:-1] + ['targetValue'])
value_id = id_on_network = id_ # type: ignore
value = self._get_value( value = self._get_value(
value_id=value_id, value_id=value_id,
value_label=value_label, value_label=value_label,
@ -1433,6 +1466,9 @@ class ZwaveMqttPlugin(MqttPlugin, ZwaveBasePlugin):
**kwargs, **kwargs,
) )
# Convert to target value if the value is in current value format,
# as that would usually be the writeable attribute
value = self._to_target_value(value)
self._api_request( self._api_request(
'writeValue', 'writeValue',
{ {