Skip to content

Commit 964f335

Browse files
committed
fix: fixed power socket protocol adaptation
feat: added power socket protocol description to readme
1 parent e2913fd commit 964f335

2 files changed

Lines changed: 176 additions & 80 deletions

File tree

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,30 @@ hekr:
113113
- main_power
114114
```
115115

116+
## Power socket protocol: `power_socket`
117+
118+
![Loaded switches for power socket protocol](https://raw.githubusercontent.com/alryaz/hass-hekr-component/master/images/power_socket/switches.png)
119+
120+
<!--_(more screenshots available at: [images/power_socket](images/power_socket))_-->
121+
122+
### Supported devices
123+
- CZ-05 (??? Information pending)
124+
125+
### Example configuration
126+
```yaml
127+
hekr:
128+
devices:
129+
- host: tv-power-socket.lan
130+
device_id: ESP_2M_AABBCCDDEEFF
131+
control_key: 202cb962ac59075b964b07152d234b70
132+
protocol: power_socket
133+
```
134+
135+
In this state, the component will generate a single switch (`main_power`) obtained via a
136+
single `Quary` command.
137+
138+
<!-- Unfortunately, they named it Quary, not Query, and I'm equally irked by this -->
139+
116140
## Fetching `device_id` and `control_key` for local setup
117141
The following steps (evidently) assume you already paired target device using Wisen.
118142

custom_components/hekr/supported_protocols.py

Lines changed: 152 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
"""Supported protocols for Hekr devices."""
22

33
__all__ = [
4-
'SUPPORTED_PROTOCOLS',
5-
'POWER_METER',
4+
"SUPPORTED_PROTOCOLS",
5+
"POWER_METER",
66
]
77

88
from homeassistant.components.switch import ATTR_CURRENT_POWER_W, DEVICE_CLASS_SWITCH
99
from homeassistant.const import (
10-
ATTR_NAME, ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT,
11-
POWER_WATT, ENERGY_KILO_WATT_HOUR,
12-
STATE_OK, STATE_PROBLEM, STATE_ON, STATE_OFF, ATTR_STATE,
13-
ATTR_DEVICE_CLASS, DEVICE_CLASS_POWER)
10+
ATTR_NAME,
11+
ATTR_ICON,
12+
ATTR_UNIT_OF_MEASUREMENT,
13+
POWER_WATT,
14+
ENERGY_KILO_WATT_HOUR,
15+
STATE_OK,
16+
STATE_PROBLEM,
17+
STATE_ON,
18+
STATE_OFF,
19+
ATTR_STATE,
20+
ATTR_DEVICE_CLASS,
21+
DEVICE_CLASS_POWER,
22+
)
1423

1524
from hekrapi.protocols.power_meter import (
1625
PROTOCOL as PROTOCOL_POWER_METER,
@@ -19,65 +28,87 @@
1928
CurrentWarning,
2029
)
2130
from hekrapi.protocols.power_socket import PROTOCOL as PROTOCOL_POWER_SOCKET
22-
from .const import ATTR_MONITORED, PROTOCOL_DETECTION, PROTOCOL_DEFINITION, PROTOCOL_FILTER, \
23-
PROTOCOL_SENSORS, PROTOCOL_CMD_UPDATE, PROTOCOL_DEFAULT, PROTOCOL_SWITCHES, PROTOCOL_PORT, PROTOCOL_NAME, \
24-
PROTOCOL_CMD_RECEIVE, PROTOCOL_CMD_TURN_ON, PROTOCOL_CMD_TURN_OFF, PROTOCOL_MODEL, PROTOCOL_MANUFACTURER
31+
from .const import (
32+
ATTR_MONITORED,
33+
PROTOCOL_DETECTION,
34+
PROTOCOL_DEFINITION,
35+
PROTOCOL_FILTER,
36+
PROTOCOL_SENSORS,
37+
PROTOCOL_CMD_UPDATE,
38+
PROTOCOL_DEFAULT,
39+
PROTOCOL_SWITCHES,
40+
PROTOCOL_PORT,
41+
PROTOCOL_NAME,
42+
PROTOCOL_CMD_RECEIVE,
43+
PROTOCOL_CMD_TURN_ON,
44+
PROTOCOL_CMD_TURN_OFF,
45+
PROTOCOL_MODEL,
46+
PROTOCOL_MANUFACTURER,
47+
)
2548

2649

2750
def power_meter_attribute_filter(attributes: dict) -> dict:
2851
if "current_energy_consumption" in attributes:
29-
attributes["current_energy_consumption"] = round(attributes["current_energy_consumption"] * 1000, 1)
52+
attributes["current_energy_consumption"] = round(
53+
attributes["current_energy_consumption"] * 1000, 1
54+
)
3055

3156
if "total_active_power" in attributes:
32-
attributes["total_active_power"] = round(attributes["total_active_power"] * 1000, 1)
57+
attributes["total_active_power"] = round(
58+
attributes["total_active_power"] * 1000, 1
59+
)
3360

3461
# filter attributes by phase count
3562
if "phase_count" in attributes:
3663
attributes = {
3764
attribute: value
3865
for attribute, value in attributes.items()
39-
if not (attribute[-2:] == '_' and attribute[-1:].isnumeric())
40-
or int(attribute[-1:]) <= attributes['phase_count']
66+
if not (attribute[-2:] == "_" and attribute[-1:].isnumeric())
67+
or int(attribute[-1:]) <= attributes["phase_count"]
4168
}
4269

4370
# get mean current
4471
if "current_1" in attributes:
4572
currents = [
46-
value for attribute, value in attributes.items()
73+
value
74+
for attribute, value in attributes.items()
4775
if attribute[:-1] == "current_"
4876
]
4977
total_current = sum(currents)
50-
attributes['mean_current'] = round(float(total_current) / len(currents), 3)
51-
attributes['total_current'] = total_current
78+
attributes["mean_current"] = round(float(total_current) / len(currents), 3)
79+
attributes["total_current"] = total_current
5280

5381
# get mean voltages
5482
if "voltage_1" in attributes:
5583
voltages = [
56-
value for attribute, value in attributes.items()
84+
value
85+
for attribute, value in attributes.items()
5786
if attribute[:-1] == "voltage_" and value
5887
]
59-
attributes['mean_voltage'] = round(float(sum(voltages)) / len(voltages), 1)
88+
attributes["mean_voltage"] = round(float(sum(voltages)) / len(voltages), 1)
6089

6190
# detect state of the device
6291
attributes["state"] = STATE_OK
6392
if "warning_voltage" in attributes:
64-
if attributes['warning_voltage'] != VoltageWarning.OK:
93+
if attributes["warning_voltage"] != VoltageWarning.OK:
6594
attributes["state"] = STATE_PROBLEM
66-
attributes['warning_voltage'] = attributes['warning_voltage'].name.lower()
95+
attributes["warning_voltage"] = attributes["warning_voltage"].name.lower()
6796

6897
if "warning_battery" in attributes:
69-
if attributes['warning_battery'] != PowerSupplyWarning.OK:
98+
if attributes["warning_battery"] != PowerSupplyWarning.OK:
7099
attributes["state"] = STATE_PROBLEM
71100
attributes["warning_battery"] = attributes["warning_battery"].name.lower()
72101

73102
if "warning_current" in attributes:
74-
if attributes['warning_current'] != CurrentWarning.OK:
103+
if attributes["warning_current"] != CurrentWarning.OK:
75104
attributes["state"] = STATE_PROBLEM
76-
attributes['warning_current'] = attributes['warning_current'].name.lower()
105+
attributes["warning_current"] = attributes["warning_current"].name.lower()
77106

78107
# process switch state
79108
if "switch_state" in attributes:
80-
attributes["switch_state"] = STATE_ON if attributes["switch_state"] else STATE_OFF
109+
attributes["switch_state"] = (
110+
STATE_ON if attributes["switch_state"] else STATE_OFF
111+
)
81112

82113
return attributes
83114

@@ -92,89 +123,127 @@ def power_meter_attribute_filter(attributes: dict) -> dict:
92123
PROTOCOL_FILTER: power_meter_attribute_filter,
93124
PROTOCOL_SENSORS: {
94125
"general": {
95-
ATTR_NAME: "General Information", ATTR_ICON: 'mdi:eye',
96-
ATTR_STATE: "state", ATTR_MONITORED: True,
97-
PROTOCOL_CMD_UPDATE: 'queryDev',
98-
PROTOCOL_CMD_RECEIVE: 'reportDev',
126+
ATTR_NAME: "General Information",
127+
ATTR_ICON: "mdi:eye",
128+
ATTR_STATE: "state",
129+
ATTR_MONITORED: True,
130+
PROTOCOL_CMD_UPDATE: "queryDev",
131+
PROTOCOL_CMD_RECEIVE: "reportDev",
99132
PROTOCOL_DEFAULT: False,
100133
},
101134
"detailed": {
102-
ATTR_NAME: 'Detailed Information', ATTR_ICON: 'mdi:eye-settings',
103-
ATTR_STATE: "state", ATTR_MONITORED: True,
104-
PROTOCOL_CMD_UPDATE: 'queryData',
105-
PROTOCOL_CMD_RECEIVE: 'reportData',
135+
ATTR_NAME: "Detailed Information",
136+
ATTR_ICON: "mdi:eye-settings",
137+
ATTR_STATE: "state",
138+
ATTR_MONITORED: True,
139+
PROTOCOL_CMD_UPDATE: "queryData",
140+
PROTOCOL_CMD_RECEIVE: "reportData",
106141
PROTOCOL_DEFAULT: False,
107142
},
108143
# queryDev-related sensors
109144
"status": {
110-
ATTR_NAME: "Status", ATTR_ICON: {
111-
STATE_PROBLEM: 'mdi:alert',
112-
STATE_OK: 'mdi:check-circle',
113-
PROTOCOL_DEFAULT: 'mdi:help-circle'
145+
ATTR_NAME: "Status",
146+
ATTR_ICON: {
147+
STATE_PROBLEM: "mdi:alert",
148+
STATE_OK: "mdi:check-circle",
149+
PROTOCOL_DEFAULT: "mdi:help-circle",
114150
},
115151
ATTR_STATE: "state",
116-
ATTR_MONITORED: ["phase_count", "warning_voltage", "warning_current", "warning_battery"],
117-
PROTOCOL_CMD_UPDATE: 'queryDev',
118-
PROTOCOL_CMD_RECEIVE: 'reportDev',
152+
ATTR_MONITORED: [
153+
"phase_count",
154+
"warning_voltage",
155+
"warning_current",
156+
"warning_battery",
157+
],
158+
PROTOCOL_CMD_UPDATE: "queryDev",
159+
PROTOCOL_CMD_RECEIVE: "reportDev",
119160
PROTOCOL_DEFAULT: True,
120161
},
121162
"current_consumption": {
122-
ATTR_NAME: "Current Consumption", ATTR_ICON: 'mdi:gauge',
123-
ATTR_STATE: "current_energy_consumption", ATTR_UNIT_OF_MEASUREMENT: POWER_WATT,
163+
ATTR_NAME: "Current Consumption",
164+
ATTR_ICON: "mdi:gauge",
165+
ATTR_STATE: "current_energy_consumption",
166+
ATTR_UNIT_OF_MEASUREMENT: POWER_WATT,
124167
ATTR_DEVICE_CLASS: DEVICE_CLASS_POWER,
125-
PROTOCOL_CMD_UPDATE: 'queryDev',
126-
PROTOCOL_CMD_RECEIVE: 'reportDev',
168+
PROTOCOL_CMD_UPDATE: "queryDev",
169+
PROTOCOL_CMD_RECEIVE: "reportDev",
127170
PROTOCOL_DEFAULT: True,
128171
},
129172
"total_consumption": {
130-
ATTR_NAME: "Total Consumption", ATTR_ICON: "mdi:sigma",
131-
ATTR_STATE: "total_energy_consumed", ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
132-
PROTOCOL_CMD_UPDATE: 'queryDev',
133-
PROTOCOL_CMD_RECEIVE: 'reportDev',
173+
ATTR_NAME: "Total Consumption",
174+
ATTR_ICON: "mdi:sigma",
175+
ATTR_STATE: "total_energy_consumed",
176+
ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
177+
PROTOCOL_CMD_UPDATE: "queryDev",
178+
PROTOCOL_CMD_RECEIVE: "reportDev",
134179
PROTOCOL_DEFAULT: True,
135180
},
136-
137181
# queryData-related sensors
138182
"voltage": {
139-
ATTR_NAME: "Mean Voltage", ATTR_ICON: "mdi:alpha-v-circle",
140-
ATTR_STATE: "mean_voltage", ATTR_UNIT_OF_MEASUREMENT: "V",
141-
ATTR_MONITORED: ["voltage_1", "voltage_2", "voltage_3", "current_frequency"],
142-
PROTOCOL_CMD_UPDATE: 'queryData',
143-
PROTOCOL_CMD_RECEIVE: 'reportData',
183+
ATTR_NAME: "Mean Voltage",
184+
ATTR_ICON: "mdi:alpha-v-circle",
185+
ATTR_STATE: "mean_voltage",
186+
ATTR_UNIT_OF_MEASUREMENT: "V",
187+
ATTR_MONITORED: [
188+
"voltage_1",
189+
"voltage_2",
190+
"voltage_3",
191+
"current_frequency",
192+
],
193+
PROTOCOL_CMD_UPDATE: "queryData",
194+
PROTOCOL_CMD_RECEIVE: "reportData",
144195
PROTOCOL_DEFAULT: False,
145196
},
146197
"current": {
147-
ATTR_NAME: "Total Current", ATTR_ICON: "mdi:alpha-i-circle",
148-
ATTR_STATE: "total_current", ATTR_UNIT_OF_MEASUREMENT: "A",
149-
ATTR_MONITORED: ["mean_current", "current_1", "current_2", "current_3", "current_frequency"],
150-
PROTOCOL_CMD_UPDATE: 'queryData',
151-
PROTOCOL_CMD_RECEIVE: 'reportData',
198+
ATTR_NAME: "Total Current",
199+
ATTR_ICON: "mdi:alpha-i-circle",
200+
ATTR_STATE: "total_current",
201+
ATTR_UNIT_OF_MEASUREMENT: "A",
202+
ATTR_MONITORED: [
203+
"mean_current",
204+
"current_1",
205+
"current_2",
206+
"current_3",
207+
"current_frequency",
208+
],
209+
PROTOCOL_CMD_UPDATE: "queryData",
210+
PROTOCOL_CMD_RECEIVE: "reportData",
152211
PROTOCOL_DEFAULT: False,
153212
},
154213
"power_factor": {
155-
ATTR_NAME: "Power Factor", ATTR_ICON: "mdi:speedometer",
156-
ATTR_STATE: "total_power_factor", ATTR_UNIT_OF_MEASUREMENT: None,
214+
ATTR_NAME: "Power Factor",
215+
ATTR_ICON: "mdi:speedometer",
216+
ATTR_STATE: "total_power_factor",
217+
ATTR_UNIT_OF_MEASUREMENT: None,
157218
ATTR_MONITORED: ["power_factor_1", "power_factor_2", "power_factor_3"],
158-
PROTOCOL_CMD_UPDATE: 'queryData',
159-
PROTOCOL_CMD_RECEIVE: 'reportData',
219+
PROTOCOL_CMD_UPDATE: "queryData",
220+
PROTOCOL_CMD_RECEIVE: "reportData",
160221
PROTOCOL_DEFAULT: False,
161222
},
162223
"active_power": {
163-
ATTR_NAME: "Active Power", ATTR_ICON: "mdi:flash",
164-
ATTR_STATE: "total_active_power", ATTR_UNIT_OF_MEASUREMENT: POWER_WATT,
224+
ATTR_NAME: "Active Power",
225+
ATTR_ICON: "mdi:flash",
226+
ATTR_STATE: "total_active_power",
227+
ATTR_UNIT_OF_MEASUREMENT: POWER_WATT,
165228
ATTR_MONITORED: ["active_power_1", "active_power_2", "active_power_3"],
166-
PROTOCOL_CMD_UPDATE: 'queryData',
167-
PROTOCOL_CMD_RECEIVE: 'reportData',
229+
PROTOCOL_CMD_UPDATE: "queryData",
230+
PROTOCOL_CMD_RECEIVE: "reportData",
168231
PROTOCOL_DEFAULT: False,
169232
},
170233
"reactive_power": {
171-
ATTR_NAME: "Reactive Power", ATTR_ICON: "mdi:flash-outline",
172-
ATTR_STATE: "total_reactive_power", ATTR_UNIT_OF_MEASUREMENT: "kVar",
173-
ATTR_MONITORED: ["reactive_power_1", "reactive_power_2", "reactive_power_3"],
174-
PROTOCOL_CMD_UPDATE: 'queryData',
175-
PROTOCOL_CMD_RECEIVE: 'reportData',
234+
ATTR_NAME: "Reactive Power",
235+
ATTR_ICON: "mdi:flash-outline",
236+
ATTR_STATE: "total_reactive_power",
237+
ATTR_UNIT_OF_MEASUREMENT: "kVar",
238+
ATTR_MONITORED: [
239+
"reactive_power_1",
240+
"reactive_power_2",
241+
"reactive_power_3",
242+
],
243+
PROTOCOL_CMD_UPDATE: "queryData",
244+
PROTOCOL_CMD_RECEIVE: "reportData",
176245
PROTOCOL_DEFAULT: False,
177-
}
246+
},
178247
},
179248
PROTOCOL_SWITCHES: {
180249
"main_power": {
@@ -183,23 +252,26 @@ def power_meter_attribute_filter(attributes: dict) -> dict:
183252
STATE_ON: "mdi:electric-switch-closed",
184253
PROTOCOL_DEFAULT: "mdi:electric-switch",
185254
},
186-
ATTR_STATE: "switch_state", ATTR_DEVICE_CLASS: DEVICE_CLASS_SWITCH,
255+
ATTR_STATE: "switch_state",
256+
ATTR_DEVICE_CLASS: DEVICE_CLASS_SWITCH,
187257
ATTR_CURRENT_POWER_W: "current_energy_consumption",
188-
PROTOCOL_CMD_UPDATE: 'queryDev',
189-
PROTOCOL_CMD_RECEIVE: 'reportDev',
190-
PROTOCOL_CMD_TURN_ON: ('setSw', {"switch_state": True}),
191-
PROTOCOL_CMD_TURN_OFF: ('setSw', {"switch_state": False}),
258+
PROTOCOL_CMD_UPDATE: "queryDev",
259+
PROTOCOL_CMD_RECEIVE: "reportDev",
260+
PROTOCOL_CMD_TURN_ON: ("setSw", {"switch_state": True}),
261+
PROTOCOL_CMD_TURN_OFF: ("setSw", {"switch_state": False}),
192262
PROTOCOL_DEFAULT: True,
193263
}
194-
}
264+
},
195265
}
196266

267+
197268
def power_socket_attribute_filter(attributes: dict) -> dict:
198269
if "power" in attributes:
199270
attributes["power"] = STATE_ON if attributes["power"] else STATE_OFF
200271

201272
return attributes
202273

274+
203275
POWER_SOCKET = {
204276
PROTOCOL_NAME: "Power Socket",
205277
PROTOCOL_PORT: 10000,
@@ -217,10 +289,10 @@ def power_socket_attribute_filter(attributes: dict) -> dict:
217289
PROTOCOL_CMD_UPDATE: "Quary",
218290
PROTOCOL_CMD_RECEIVE: "Report",
219291
PROTOCOL_CMD_TURN_ON: ("SetPower", {"power": True}),
220-
PROTOCOL_CMD_TURN_ON: ("SetPower", {"power": False}),
292+
PROTOCOL_CMD_TURN_OFF: ("SetPower", {"power": False}),
221293
PROTOCOL_DEFAULT: True,
222294
}
223-
}
295+
},
224296
}
225297

226298
SUPPORTED_PROTOCOLS = {

0 commit comments

Comments
 (0)