Skip to content

Commit 218ad96

Browse files
committed
Add protobuf command support for Stream AC Pro: feedGridMode (field 168) and relay2Onoff (field 380)
1 parent 7a56b8f commit 218ad96

1 file changed

Lines changed: 99 additions & 2 deletions

File tree

  • custom_components/ecoflow_cloud/devices/internal

custom_components/ecoflow_cloud/devices/internal/stream_ac.py

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from custom_components.ecoflow_cloud.api import EcoflowApiClient
1212
from custom_components.ecoflow_cloud.devices import BaseInternalDevice, const
13+
from custom_components.ecoflow_cloud.number import BatteryBackupLevel
1314
from custom_components.ecoflow_cloud.sensor import (
1415
CapacitySensorEntity,
1516
CumulativeCapacitySensorEntity,
@@ -23,6 +24,7 @@
2324
TempSensorEntity,
2425
WattsSensorEntity,
2526
)
27+
from custom_components.ecoflow_cloud.switch import EnabledEntity
2628

2729
_LOGGER = logging.getLogger(__name__)
2830

@@ -281,12 +283,107 @@ def sensors(self, client: EcoflowApiClient) -> list[SensorEntity]:
281283
# "waterInFlag": 0,
282284
]
283285

286+
def _build_proto_command(self, field_num: int, value: int) -> bytes:
287+
"""Build a protobuf command payload for Stream AC internal API."""
288+
import time
289+
from .proto import stream_ac_pb2
290+
291+
def encode_varint(n):
292+
result = bytearray()
293+
while True:
294+
bits = n & 0x7F
295+
n >>= 7
296+
if n:
297+
result.append(0x80 | bits)
298+
else:
299+
result.append(bits)
300+
break
301+
return bytes(result)
302+
303+
def encode_field(fnum, val):
304+
return encode_varint((fnum << 3) | 0) + encode_varint(val)
305+
306+
pdata = encode_field(6, int(time.time())) + encode_field(field_num, value)
307+
308+
import random
309+
header = stream_ac_pb2.StreamACHeader()
310+
header.src = 32
311+
header.dest = 2
312+
header.d_src = 1
313+
header.d_dest = 1
314+
header.cmd_func = 254
315+
header.cmd_id = 17
316+
header.data_len = len(pdata)
317+
header.need_ack = 1
318+
header.seq = random.randint(100000000, 999999999)
319+
header.product_id = 58
320+
header.version = 3
321+
header.payload_ver = 1
322+
setattr(header, "from", "Android")
323+
header.pdata = pdata
324+
325+
msg = stream_ac_pb2.StreamACSendHeaderMsg()
326+
msg.msg.CopyFrom(header)
327+
return msg.SerializeToString()
328+
284329
# moduleWifiRssi
285330
def numbers(self, client: EcoflowApiClient) -> list[NumberEntity]:
286-
return []
331+
return [
332+
BatteryBackupLevel(
333+
client,
334+
self,
335+
"backupReverseSoc",
336+
const.BACKUP_RESERVE_LEVEL,
337+
3,
338+
95,
339+
"cmsMinDsgSoc",
340+
"cmsMaxChgSoc",
341+
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+
},
354+
),
355+
]
287356

288357
def switches(self, client: EcoflowApiClient) -> list[SwitchEntity]:
289-
return []
358+
from custom_components.ecoflow_cloud.switch import EnabledEntity
359+
360+
class ProtoEnabledEntity(EnabledEntity):
361+
def __init__(self_, *args, field_num, enable_val, disable_val, **kwargs):
362+
self_._field_num = field_num
363+
self_._enable_val = enable_val
364+
self_._disable_val = disable_val
365+
super().__init__(*args, **kwargs)
366+
367+
def turn_on(self_, **kwargs):
368+
raw = self._build_proto_command(self_._field_num, self_._enable_val)
369+
client.mqtt_client.publish(self.device_info.set_topic, raw)
370+
371+
def turn_off(self_, **kwargs):
372+
raw = self._build_proto_command(self_._field_num, self_._disable_val)
373+
client.mqtt_client.publish(self.device_info.set_topic, raw)
374+
375+
return [
376+
ProtoEnabledEntity(
377+
client, self, "feedGridMode", const.STREAM_FEED_IN_CONTROL,
378+
lambda value: {}, field_num=168, enable_val=1, disable_val=2,
379+
enableValue=2, disableValue=1,
380+
),
381+
ProtoEnabledEntity(
382+
client, self, "relay2Onoff", const.MODE_AC1_ON,
383+
lambda value: {}, field_num=380, enable_val=1, disable_val=0,
384+
enableValue=True, disableValue=False,
385+
),
386+
]
290387

291388
def selects(self, client: EcoflowApiClient) -> list[SelectEntity]:
292389
return []

0 commit comments

Comments
 (0)