1010import logging
1111from typing import Any , override
1212
13+ from homeassistant .components .button import ButtonEntity
1314from homeassistant .components .number import NumberEntity
1415from homeassistant .components .select import SelectEntity
1516from homeassistant .components .sensor import SensorEntity
2021
2122from custom_components .ecoflow_cloud .api import EcoflowApiClient
2223from custom_components .ecoflow_cloud .api .message import Message , PrivateAPIMessageProtocol
24+ from custom_components .ecoflow_cloud .button import GetMessageButtonEntity
2325from custom_components .ecoflow_cloud .devices import BaseInternalDevice , const
26+ from custom_components .ecoflow_cloud .devices .data_holder import PreparedData
2427from custom_components .ecoflow_cloud .number import BrightnessLevelEntity , MaxWattsEntity
2528from custom_components .ecoflow_cloud .devices .internal .proto import AddressId
2629import 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
160193def _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
177210def _create_change_switch_status_message (value : int , device_sn : str ):
0 commit comments