Skip to content

Commit

Permalink
Add __repr__ to aa55 protocol messages
Browse files Browse the repository at this point in the history
  • Loading branch information
mletenay committed May 26, 2024
1 parent f7b04f4 commit 893a81e
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 4 deletions.
1 change: 1 addition & 0 deletions goodwe/es.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ async def read_setting(self, setting_id: str) -> Any:
response = await self._read_from_socket(self._read_command(int(setting_id[7:]), 1))
return int.from_bytes(response.read(2), byteorder="big", signed=True)
elif setting_id in self._settings:
logger.debug("Reading setting %s", setting_id)
all_settings = await self.read_settings_data()
return all_settings.get(setting_id)
else:
Expand Down
30 changes: 26 additions & 4 deletions goodwe/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ class Aa55ProtocolCommand(ProtocolCommand):
The last 2 bytes are again plain checksum of header+payload.
"""

def __init__(self, payload: str, response_type: str):
def __init__(self, payload: str, response_type: str, offset: int = 0, value: int = 0):
super().__init__(
bytes.fromhex(
"AA55C07F"
Expand All @@ -491,6 +491,8 @@ def __init__(self, payload: str, response_type: str):
),
lambda x: self._validate_aa55_response(x, response_type),
)
self.first_address: int = offset
self.value = value

@staticmethod
def _checksum(data: bytes) -> bytes:
Expand Down Expand Up @@ -534,14 +536,31 @@ def trim_response(self, raw_response: bytes):
"""Trim raw response from header and checksum data"""
return raw_response[7:-2]

def __repr__(self):
if self.request[4] == 1:
if self.request[5] == 2:
return f'READ device info ({self.request.hex()})'
elif self.request[5] == 6:
return f'READ runtime data ({self.request.hex()})'
elif self.request[5] == 9:
return f'READ settings ({self.request.hex()})'
else:
return self.request.hex()


class Aa55ReadCommand(Aa55ProtocolCommand):
"""
Inverter modbus READ command for retrieving <count> modbus registers starting at register # <offset>
"""

def __init__(self, offset: int, count: int):
super().__init__("011A03" + "{:04x}".format(offset) + "{:02x}".format(count), "019A")
super().__init__("011A03" + "{:04x}".format(offset) + "{:02x}".format(count), "019A", offset, count)

def __repr__(self):
if self.value > 1:
return f'READ {self.value} registers from {self.first_address} ({self.request.hex()})'
else:
return f'READ register {self.first_address} ({self.request.hex()})'


class Aa55WriteCommand(Aa55ProtocolCommand):
Expand All @@ -550,7 +569,10 @@ class Aa55WriteCommand(Aa55ProtocolCommand):
"""

def __init__(self, register: int, value: int):
super().__init__("023905" + "{:04x}".format(register) + "01" + "{:04x}".format(value), "02B9")
super().__init__("023905" + "{:04x}".format(register) + "01" + "{:04x}".format(value), "02B9", register, value)

def __repr__(self):
return f'WRITE {self.value} to register {self.first_address} ({self.request.hex()})'


class Aa55WriteMultiCommand(Aa55ProtocolCommand):
Expand All @@ -560,7 +582,7 @@ class Aa55WriteMultiCommand(Aa55ProtocolCommand):

def __init__(self, offset: int, values: bytes):
super().__init__("02390B" + "{:04x}".format(offset) + "{:02x}".format(len(values)) + values.hex(),
"02B9")
"02B9", offset, len(values) // 2)


class ModbusRtuProtocolCommand(ProtocolCommand):
Expand Down
75 changes: 75 additions & 0 deletions tests/mock_aa55_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import asyncio


class EchoServerProtocol(asyncio.Protocol):
def connection_made(self, transport):
peername = transport.get_extra_info('peername')
print('Connection from {}'.format(peername))
self.transport = transport

def datagram_received(self, data, addr):
payload = data.hex()
print(payload)

if payload == "aa55c07f0102000241":
# Device info
self.transport.sendto(bytes.fromhex(
"aa557fc001824d323532354b4757353034382d4553412331300000000000000000000000000039353034384553413030305730303030333630303431302d30343032352d3235203431302d30323033342d323001102f"),
addr)
elif payload == "aa55c07f0106000245":
# Running data
self.transport.sendto(bytes.fromhex(
"aa557fc001868c09270047020fe60042010214000200500118000400000032000064006464020000010a11009e0ce11389010a11000303e11389010202010000000000023780000053c3012600770001ad1510c30100200100000001000003e500000840000018051a0e0e120000000000000000000000000000000000000000000000000000ca260000baab0200000000000012e1"),
addr)
elif payload == "aa55c07f0109000248":
# Settings data
self.transport.sendto(bytes.fromhex(
"aa557fc00189560000000000000000000000000001000100010000000a00d2024000f0008001e0000a000f0000000000000064024003e8001e00f20000000000000000023f000000070000000000000001038403e801e0000a000000220c12"),
addr)
elif payload == "aa55c07f011a030701040268":
# Read eco_mode_1
self.transport.sendto(bytes.fromhex(
"aa557fc0019a08000000000000007f0360"),
addr)
elif payload == "aa55c07f032c0500000000000272":
self.transport.sendto(bytes.fromhex(
"aa557fc003ac010602f4"),
addr)
elif payload == "aa55c07f032d0500000000000273":
self.transport.sendto(bytes.fromhex(
"aa557fc003ad010602f5"),
addr)
elif payload == "aa55c07f02390507000100010287":
self.transport.sendto(bytes.fromhex(
"aa557fc002b901060300"),
addr)
elif payload == "aa55c07f033601000278":
self.transport.sendto(bytes.fromhex(
"aa557fc003b6010602fe"),
addr)
elif payload == "aa55c07f03590100029b":
self.transport.sendto(bytes.fromhex(
"aa557fc003d901060321"),
addr)
else:
self.transport.sendto(bytes.fromhex("00000000"), addr)
# print('Close the client socket')
# self.transport.close()


async def main():
# Get a reference to the event loop as we plan to use
# low-level APIs.
loop = asyncio.get_running_loop()

transport, protocol = await loop.create_datagram_endpoint(
lambda: EchoServerProtocol(),
local_addr=('127.0.0.1', 8899))

try:
await asyncio.sleep(3600) # Serve for 1 hour.
finally:
transport.close()


asyncio.run(main())

0 comments on commit 893a81e

Please sign in to comment.