Skip to content

Commit 7886c9f

Browse files
committed
feat(smart-plug,powerstream): Add button to trigger full-sync
Corrects the max/min charge level for the powerstream to 0-100% relates-to: #704, #758, #560, #469
1 parent 8b8e93a commit 7886c9f

7 files changed

Lines changed: 80 additions & 21 deletions

File tree

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,7 @@ For information on how to add, remove, and configure devices, please refer to th
10291029

10301030
</p></details>
10311031

1032-
<details><summary> POWERSTREAM <i>(sensors: 63, switches: 1, sliders: 2, boxes: 1, selects: 1)</i> </summary>
1032+
<details><summary> POWERSTREAM <i>(sensors: 63, switches: 1, sliders: 2, boxes: 1, selects: 1, buttons: 1)</i> </summary>
10331033
<p>
10341034

10351035
*Sensors*
@@ -1110,6 +1110,9 @@ For information on how to add, remove, and configure devices, please refer to th
11101110
*Selects*
11111111
- Power supply mode
11121112

1113+
*Buttons*
1114+
- Trigger Full Sync
1115+
11131116
</p></details>
11141117

11151118
<details><summary> GLACIER <i>(sensors: 29, binary_sensors: 4, switches: 3, sliders: 3)</i> </summary>
@@ -1272,7 +1275,7 @@ For information on how to add, remove, and configure devices, please refer to th
12721275
</p></details>
12731276

12741277

1275-
<details><summary> SMART_PLUG <i>(sensors: 5, switches: 1, sliders: 2)</i> </summary>
1278+
<details><summary> SMART_PLUG <i>(sensors: 5, switches: 1, sliders: 2, buttons: 1)</i> </summary>
12761279
<p>
12771280

12781281
*Sensors*
@@ -1289,6 +1292,9 @@ For information on how to add, remove, and configure devices, please refer to th
12891292
- Brightness
12901293
- Max Power
12911294

1295+
*Buttons*
1296+
- Trigger Full Sync
1297+
12921298
</p></details>
12931299

12941300
<details><summary> STREAM_AC <i>(sensors: 39)</i> </summary>

custom_components/ecoflow_cloud/button.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e
2222
async_add_entities([ReconnectButtonEntity(client, device)])
2323

2424

25-
class EnabledButtonEntity(BaseButtonEntity):
25+
class SetMessageButtonEntity(BaseButtonEntity):
2626
def press(self, **kwargs: Any) -> None:
2727
if self._command:
2828
self.send_set_message(0, self.command_dict(0))
2929

30-
31-
class DisabledButtonEntity(BaseButtonEntity):
32-
async def async_press(self, **kwargs: Any) -> None:
30+
class GetMessageButtonEntity(BaseButtonEntity):
31+
def press(self, **kwargs: Any) -> None:
3332
if self._command:
34-
self.send_set_message(0, self.command_dict(0))
35-
33+
self.send_get_message(self.command_dict(0))
3634

3735
class ReconnectButtonEntity(ButtonEntity, EcoFlowAbstractEntity):
3836
def __init__(self, client: EcoflowApiClient, device):

custom_components/ecoflow_cloud/devices/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@
261261
MODE_AC2_ON = "AC 2 On"
262262
BRIGHTNESS = "Brightness"
263263
BEEPER = "Beeper"
264+
TRIGGER_FULL_SYNC = "Trigger Full Sync"
264265
USB_ENABLED = "USB Enabled"
265266
AC_ENABLED = "AC Enabled"
266267
BYPASS_AC = "Bypass AC auto start"

custom_components/ecoflow_cloud/devices/internal/glacier.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from homeassistant.components.switch import SwitchEntity
88

99
from custom_components.ecoflow_cloud.api import EcoflowApiClient
10-
from custom_components.ecoflow_cloud.button import EnabledButtonEntity
10+
from custom_components.ecoflow_cloud.button import SetMessageButtonEntity
1111
from custom_components.ecoflow_cloud.devices import BaseInternalDevice, const
1212
from custom_components.ecoflow_cloud.number import SetTempEntity
1313
from custom_components.ecoflow_cloud.sensor import (
@@ -168,21 +168,21 @@ def switches(self, client: EcoflowApiClient) -> list[SwitchEntity]:
168168

169169
def buttons(self, client: EcoflowApiClient) -> list[ButtonEntity]:
170170
return [
171-
EnabledButtonEntity(
171+
SetMessageButtonEntity(
172172
client,
173173
self,
174174
"smlice",
175175
"Make Small Ice",
176176
lambda value: {"moduleType": 1, "operateType": "iceMake", "params": {"enable": 1, "iceShape": 0}},
177177
),
178-
EnabledButtonEntity(
178+
SetMessageButtonEntity(
179179
client,
180180
self,
181181
"lrgice",
182182
"Make Large Ice",
183183
lambda value: {"moduleType": 1, "operateType": "iceMake", "params": {"enable": 1, "iceShape": 1}},
184184
),
185-
EnabledButtonEntity(
185+
SetMessageButtonEntity(
186186
client,
187187
self,
188188
"deice",

custom_components/ecoflow_cloud/devices/internal/powerstream.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from google.protobuf.json_format import MessageToDict
77
from google.protobuf.message import Message as ProtoMessageRaw
8+
from homeassistant.components.button import ButtonEntity
89
from homeassistant.components.number import NumberEntity
910
from homeassistant.components.select import SelectEntity
1011
from homeassistant.components.sensor import SensorEntity
@@ -13,6 +14,7 @@
1314

1415
from custom_components.ecoflow_cloud.api import EcoflowApiClient
1516
from custom_components.ecoflow_cloud.api.message import JSONDict, Message, PrivateAPIMessageProtocol
17+
from custom_components.ecoflow_cloud.button import GetMessageButtonEntity
1618
from custom_components.ecoflow_cloud.devices import BaseInternalDevice, const
1719
from custom_components.ecoflow_cloud.devices.data_holder import PreparedData
1820
from custom_components.ecoflow_cloud.devices.internal import to_lower_camel_case
@@ -69,6 +71,7 @@ def id(self) -> int:
6971
SET_BAT_UPPER = CommandFuncAndId(func=20, id=133)
7072
SET_BRIGHTNESS = CommandFuncAndId(func=20, id=135)
7173
SET_FEED_PROTECT = CommandFuncAndId(func=20, id=143)
74+
GET_HEARTBEAT = CommandFuncAndId(func=0, id=0)
7275
RATED_POWER = CommandFuncAndId(func=20, id=146)
7376

7477
PLATFORM_WATTH = CommandFuncAndId(func=254, id=32)
@@ -294,7 +297,7 @@ def numbers(self, client: EcoflowApiClient) -> Sequence[NumberEntity]:
294297
self,
295298
"20_1.upperLimit",
296299
const.MAX_CHARGE_LEVEL,
297-
50,
300+
0,
298301
100,
299302
lambda value: PowerStreamCommandMessage(
300303
device_sn=self.device_info.sn,
@@ -308,7 +311,7 @@ def numbers(self, client: EcoflowApiClient) -> Sequence[NumberEntity]:
308311
"20_1.lowerLimit",
309312
const.MIN_DISCHARGE_LEVEL,
310313
0,
311-
30,
314+
100,
312315
lambda value: PowerStreamCommandMessage(
313316
device_sn=self.device_info.sn,
314317
command=Command.SET_BAT_LOWER,
@@ -330,6 +333,21 @@ def numbers(self, client: EcoflowApiClient) -> Sequence[NumberEntity]:
330333
).with_icon("mdi:transmission-tower-export"),
331334
]
332335

336+
def buttons(self, client: EcoflowApiClient) -> list[ButtonEntity]:
337+
return [
338+
GetMessageButtonEntity(
339+
client,
340+
self,
341+
"fullsync",
342+
const.TRIGGER_FULL_SYNC,
343+
lambda _: PowerStreamCommandMessage(
344+
device_sn=self.device_info.sn,
345+
command=Command.GET_HEARTBEAT,
346+
payload=None,
347+
),
348+
),
349+
]
350+
333351
@override
334352
def _prepare_data(self, raw_data: bytes) -> dict[str, Any]:
335353
res: dict[str, Any] = {"params": {}}

custom_components/ecoflow_cloud/devices/internal/smart_plug.py

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import logging
1111
from typing import Any, override
1212

13+
from homeassistant.components.button import ButtonEntity
1314
from homeassistant.components.number import NumberEntity
1415
from homeassistant.components.select import SelectEntity
1516
from homeassistant.components.sensor import SensorEntity
@@ -20,7 +21,9 @@
2021

2122
from custom_components.ecoflow_cloud.api import EcoflowApiClient
2223
from custom_components.ecoflow_cloud.api.message import Message, PrivateAPIMessageProtocol
24+
from custom_components.ecoflow_cloud.button import GetMessageButtonEntity
2325
from custom_components.ecoflow_cloud.devices import BaseInternalDevice, const
26+
from custom_components.ecoflow_cloud.devices.data_holder import PreparedData
2427
from custom_components.ecoflow_cloud.number import BrightnessLevelEntity, MaxWattsEntity
2528
from custom_components.ecoflow_cloud.devices.internal.proto import AddressId
2629
import custom_components.ecoflow_cloud.devices.internal.proto.smartplug_pb2 as pb2
@@ -82,6 +85,23 @@ def switches(self, client: EcoflowApiClient) -> list[SwitchEntity]:
8285
def selects(self, client: EcoflowApiClient) -> list[SelectEntity]:
8386
return []
8487

88+
def buttons(self, client: EcoflowApiClient) -> list[ButtonEntity]:
89+
return [
90+
GetMessageButtonEntity(
91+
client,
92+
self,
93+
"fullsync",
94+
const.TRIGGER_FULL_SYNC,
95+
lambda _: _create_heartbeat_message(),
96+
),
97+
]
98+
99+
def _prepare_data_get_reply_topic(self, raw_data: bytes) -> PreparedData:
100+
data = self._prepare_data(raw_data)
101+
if "params" in data:
102+
return PreparedData(None, data, data)
103+
return super()._prepare_data_get_reply_topic(raw_data)
104+
85105
def _prepare_data(self, raw_data: bytes) -> dict[str, Any]:
86106
try:
87107
_LOGGER.debug(f"Processing {len(raw_data)} bytes of raw data")
@@ -132,12 +152,12 @@ def _parse_smartplug_packet(self, raw_data: bytes) -> dict[str, Any]:
132152
_LOGGER.debug(f"result: {result}")
133153
return result
134154

135-
class SmartPlug3CommandMessage(PrivateAPIMessageProtocol):
155+
class SmartPlugCommandMessage(PrivateAPIMessageProtocol):
136156
"""Message wrapper for SmartPlug protobuf commands."""
137157

138158
def __init__(
139159
self,
140-
payload: ProtoMessageRaw,
160+
payload: ProtoMessageRaw | None,
141161
packet: pb2.SendSmartPlugHeaderMsg,
142162
):
143163
self._packet = packet
@@ -149,13 +169,26 @@ def to_mqtt_payload(self):
149169

150170
@override
151171
def to_dict(self) -> dict:
172+
if self._payload is None:
173+
return {}
174+
152175
payload_dict = MessageToDict(self._payload, preserving_proto_field_name=True)
176+
packet_dict = MessageToDict(self._packet, preserving_proto_field_name=True)
177+
178+
packet_dict["msg"][0]["pdata"] = {type(self._payload).__name__: payload_dict}
179+
packet_dict["msg"][0].pop("seq", None)
180+
return {type(self._packet).__name__: packet_dict}
153181

154-
result = MessageToDict(self._packet, preserving_proto_field_name=True)
155-
result["msg"][0]["pdata"] = {type(self._payload).__name__: payload_dict}
156-
result["msg"][0].pop("seq", None)
157-
return {type(self._packet).__name__: result}
182+
def _create_heartbeat_message() -> SmartPlugCommandMessage:
183+
packet = pb2.SendSmartPlugHeaderMsg()
184+
msg = packet.msg.add()
185+
186+
msg.src = AddressId.APP
187+
msg.dest = AddressId.APP
188+
msg.seq = Message.gen_seq()
189+
setattr(msg, "from", "Android")
158190

191+
return SmartPlugCommandMessage(None, packet)
159192

160193
def _create_send_header_message(cmd_id: int, device_sn: str, payload: ProtoMessageRaw):
161194
packet = pb2.SendSmartPlugHeaderMsg()
@@ -171,7 +204,7 @@ def _create_send_header_message(cmd_id: int, device_sn: str, payload: ProtoMessa
171204
msg.seq = Message.gen_seq()
172205
msg.deviceSn = device_sn
173206

174-
return SmartPlug3CommandMessage(payload, packet)
207+
return SmartPlugCommandMessage(payload, packet)
175208

176209

177210
def _create_change_switch_status_message(value: int, device_sn: str):

custom_components/ecoflow_cloud/entities/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ def command_dict(self, value: _CommandArg) -> dict[str, Any] | Message:
227227
def send_set_message(self, target_value: Any, command: dict | Message):
228228
self._client.send_set_message(self._device.device_info.sn, {self._mqtt_key_adopted: target_value}, command)
229229

230+
def send_get_message(self, command: dict | Message):
231+
self._client.send_get_message(self._device.device_info.sn, command)
232+
230233

231234
class BaseNumberEntity(NumberEntity, EcoFlowBaseCommandEntity[int]):
232235
_attr_entity_category = EntityCategory.CONFIG

0 commit comments

Comments
 (0)