Mercurial > code > home > repos > mqtt_metrics
annotate convert.py @ 10:2a507e679d0d default tip
add zigbee covnerters
author | drewp@bigasterisk.com |
---|---|
date | Mon, 12 Aug 2024 13:15:07 -0700 |
parents | bc2a93b306e9 |
children |
rev | line source |
---|---|
4 | 1 ''' |
2 Note that these functions need to parse the message['payload'] into a float | |
3 ''' | |
6 | 4 import json |
10 | 5 import logging |
6 | 6 |
10 | 7 log = logging.getLogger('conv') |
2
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
8 converters = [] |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
9 |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
10 |
5
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
11 def f_from_c(c): |
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
12 return (c * 9 / 5) + 32 |
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
13 |
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
14 |
2
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
15 def topic(topic_pattern: str): |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
16 |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
17 def decorator(func): |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
18 func.topic_pattern = topic_pattern |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
19 converters.append(func) |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
20 return func |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
21 |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
22 return decorator |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
23 |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
24 |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
25 @topic(r'([^-]+)-air-quality/sensor/particulate_matter__10_0__m_concentration/state') |
5
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
26 def pm(message, topicGroups: tuple[str]) -> list[dict]: |
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
27 return [{ |
2
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
28 'name': 'air_quality_pm', |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
29 'labels': [{ |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
30 'labelName': 'location', |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
31 'labelValue': topicGroups[0], |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
32 }, { |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
33 'labelName': 'size', |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
34 'labelValue': '10', |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
35 }], |
4 | 36 'value': float(message['payload']), |
5
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
37 }] |
2
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
38 |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
39 |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
40 @topic(r'([^-]+)-air-quality/sensor/air_temperature_c/state') |
5
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
41 def air_temp(message, topicGroups: tuple[str]) -> list[dict]: |
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
42 return [{ |
2
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
43 'name': 'air_temperature_f', |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
44 'labels': [{ |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
45 'labelName': 'location', |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
46 'labelValue': topicGroups[0], |
579df3a4e62d
rewrite converters as register'able functions
drewp@bigasterisk.com
parents:
diff
changeset
|
47 }], |
5
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
48 'value': f_from_c(float(message['payload'])), |
8390d5d0d512
one mqtt message can convert to multiple measurements
drewp@bigasterisk.com
parents:
4
diff
changeset
|
49 }] |
6 | 50 |
51 | |
52 @topic(r'(tele/st-wall-power/SENSOR|tele/ki-fridge/SENSOR|tt-console-power/SENSOR)') | |
53 def poorly_named_sonoff_powermeter(message, topicGroups: tuple[str]) -> list[dict]: | |
54 energy = json.loads(message['payload'])['ENERGY'] | |
55 sensor = { | |
56 'tele/st-wall-power/SENSOR': 'st_wall', | |
57 'tele/ki-fridge/SENSOR': 'ki_fridge', | |
58 'tt-console-power/SENSOR': 'tt_console', | |
59 }[topicGroups[0]] | |
60 return [{ 'name': 'powermeter_w', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': energy['Power'] }, | |
61 { 'name': 'powermeter_apparent_power_va', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': energy['ApparentPower'] }, | |
62 { 'name': 'powermeter_reactive_power_var', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': energy['ReactivePower'] }, | |
63 { 'name': 'powermeter_factor', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': energy['Factor'] }, | |
64 { 'name': 'powermeter_voltage_v', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': energy['Voltage'] }, | |
65 { 'name': 'powermeter_current_a', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': energy['Current'] } ] # yapf: disable | |
66 | |
67 @topic(r'(.*)-power/status/switch:0') | |
68 def shelly_powermeter(message, topicGroups: tuple[str]) -> list[dict]: | |
69 sensor = topicGroups[0].replace('-', '_') | |
70 msg = json.loads(message['payload']) | |
71 return [ | |
72 { 'name': 'powermeter_w', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': msg['apower'] }, | |
73 { 'name': 'powermeter_voltage_v', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': msg['voltage'] }, | |
74 { 'name': 'powermeter_current_a', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': msg['current'] }, | |
75 { 'name': 'powermeter_apparent_power_va', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': msg['apower'] }, | |
76 { 'name': 'powermeter_temp_f', 'labels': [{'labelName': 'sensor', 'labelValue': sensor}], 'value': f_from_c(msg['temperature']['tC']) }, | |
77 ] # yapf: disable | |
10 | 78 |
79 @topic(r'^zigbee/([^/]+)$') | |
80 def zigbee(message, topicGroups: tuple[str]) -> list[dict]: | |
81 dev = topicGroups[0] | |
82 body = json.loads(message['payload']) | |
83 ret = [] | |
84 for v in ['update_available', 'link_quality', 'battery', 'occupancy', 'brightness', 'contact']: | |
85 body_key = 'linkquality' if v == 'link_quality' else v | |
86 if body_key not in body: | |
87 continue | |
88 value = body[body_key] | |
89 if v in ['update_available', 'contact', 'occupancy']: | |
90 value = int(bool(value)) | |
91 if v == 'brightness' and body.get('state', None) != 'ON': | |
92 value = 0 | |
93 if v == 'link_quality' and value is None: | |
94 value = -1 | |
95 if value is None: | |
96 logging.warning(f'zigbee {v=} {value=}') | |
97 continue | |
98 ret.append({'name': 'zigbee_' + v, 'labels': [{'labelName': 'dev', 'labelValue': dev}], 'value': value}) | |
99 return ret | |
100 | |
101 | |
102 @topic(r'^zigbee/([^/]+)/availability$') | |
103 def zigbee_availability(message, topicGroups: tuple[str]) -> list[dict]: | |
104 dev = topicGroups[0] | |
105 online = message['payload'] == "online" | |
106 ret = [{'name': 'zigbee_online', 'labels': [{'labelName': 'dev', 'labelValue': dev}], 'value': int(online)}] | |
107 if online and dev.startswith('0x'): | |
108 ret.append({'name': 'zigbee_unnamed_dev', 'labels': [{'labelName': 'dev', 'labelValue': dev}], 'value': 1}) | |
109 return ret |