@@ -328,8 +328,15 @@ def encode_field(fnum, val):
328328
329329 # moduleWifiRssi
330330 def numbers (self , client : EcoflowApiClient ) -> list [NumberEntity ]:
331+ outer_self = self
332+
333+ class ProtoBackupReserveEntity (BatteryBackupLevel ):
334+ async def async_set_native_value (self_ , value : float ):
335+ raw = outer_self ._build_proto_command (102 , int (value ))
336+ client .mqtt_client .publish (outer_self .device_info .set_topic , raw )
337+
331338 return [
332- BatteryBackupLevel (
339+ ProtoBackupReserveEntity (
333340 client ,
334341 self ,
335342 "backupReverseSoc" ,
@@ -339,18 +346,7 @@ def numbers(self, client: EcoflowApiClient) -> list[NumberEntity]:
339346 "cmsMinDsgSoc" ,
340347 "cmsMaxChgSoc" ,
341348 3 ,
342- lambda value : {
343- "sn" : self .device_info .sn ,
344- "cmdId" : 17 ,
345- "cmdFunc" : 254 ,
346- "dirDest" : 1 ,
347- "dirSrc" : 1 ,
348- "dest" : 2 ,
349- "needAck" : True ,
350- "params" : {
351- "cfgBackupReverseSoc" : int (value ),
352- },
353- },
349+ lambda value : {},
354350 ),
355351 ]
356352
@@ -388,6 +384,49 @@ def turn_off(self_, **kwargs):
388384 def selects (self , client : EcoflowApiClient ) -> list [SelectEntity ]:
389385 return []
390386
387+ _MANUAL_FIELD_MAP : dict = {
388+ 380 : ("relay2Onoff" , bool ),
389+ 461 : ("backupReverseSoc" , int ),
390+ 1628 : ("feedGridMode" , int ),
391+ }
392+
393+ def _decode_manual_fields (self , pdata : bytes , raw : dict ) -> None :
394+ """Extract specific unmapped protobuf varint fields from raw pdata bytes."""
395+
396+ def decode_varint (data , pos ):
397+ result , shift = 0 , 0
398+ while pos < len (data ):
399+ b = data [pos ]
400+ pos += 1
401+ result |= (b & 0x7F ) << shift
402+ if not (b & 0x80 ):
403+ return result , pos
404+ shift += 7
405+ return result , pos
406+
407+ pos = 0
408+ while pos < len (pdata ):
409+ try :
410+ tag , pos = decode_varint (pdata , pos )
411+ field_num = tag >> 3
412+ wire_type = tag & 0x7
413+ if wire_type == 0 :
414+ value , pos = decode_varint (pdata , pos )
415+ if field_num in self ._MANUAL_FIELD_MAP :
416+ name , cast = self ._MANUAL_FIELD_MAP [field_num ]
417+ raw ["params" ][name ] = cast (value )
418+ elif wire_type == 2 :
419+ length , pos = decode_varint (pdata , pos )
420+ pos += length
421+ elif wire_type == 5 :
422+ pos += 4
423+ elif wire_type == 1 :
424+ pos += 8
425+ else :
426+ break
427+ except Exception :
428+ break
429+
391430 @override
392431 def _prepare_data (self , raw_data : bytes ) -> dict [str , Any ]:
393432 raw : dict [str , Any ] = {"params" : {}}
@@ -444,6 +483,8 @@ def _prepare_data(self, raw_data: bytes) -> dict[str, Any]:
444483 if packet .msg .cmd_id > 0 :
445484 self ._parsedata (packet , stream_ac2 .StreamACChamp_cmd50_3 (), raw )
446485
486+ self ._decode_manual_fields (packet .msg .pdata , raw )
487+
447488 _LOGGER .info ("Found %u fields" , len (raw ["params" ]))
448489
449490 raw ["timestamp" ] = utcnow ()
0 commit comments