diff --git a/RS485-protocol-pylon-low-voltage-V3.3-20180821.pdf b/Specifications/RS485-protocol-pylon-low-voltage-V3.3-20180821.pdf similarity index 100% rename from RS485-protocol-pylon-low-voltage-V3.3-20180821.pdf rename to Specifications/RS485-protocol-pylon-low-voltage-V3.3-20180821.pdf diff --git a/Specifications/RS485-protocol-pylon-low-voltage-V3.5-20190807.pdf b/Specifications/RS485-protocol-pylon-low-voltage-V3.5-20190807.pdf new file mode 100644 index 0000000..2a674ca Binary files /dev/null and b/Specifications/RS485-protocol-pylon-low-voltage-V3.5-20190807.pdf differ diff --git a/Specifications/Sunsynk_BatteryCompatibility_v12_English-1.pdf b/Specifications/Sunsynk_BatteryCompatibility_v12_English-1.pdf new file mode 100644 index 0000000..aa7f261 Binary files /dev/null and b/Specifications/Sunsynk_BatteryCompatibility_v12_English-1.pdf differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..6f7824f --- /dev/null +++ b/main.py @@ -0,0 +1,4 @@ +import pylontech + +p = pylontech.Pylontech(serial_port='COM3', baudrate=9600) +print(p.get_values()) \ No newline at end of file diff --git a/pylontech/pylontech.py b/pylontech/pylontech.py index 356c6cc..6e3536f 100644 --- a/pylontech/pylontech.py +++ b/pylontech/pylontech.py @@ -2,6 +2,13 @@ import logging import serial import construct +import logging +import time + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s:%(funcName)s:%(lineno)d - %(levelname)s - %(message)s' +) logger = logging.getLogger(__name__) @@ -171,17 +178,21 @@ def get_info_length(info: bytes) -> int: def send_cmd(self, address: int, cmd, info: bytes = b''): raw_frame = self._encode_cmd(address, cmd, info) + logger.debug(f"{raw_frame=}") self.s.write(raw_frame) def _encode_cmd(self, address: int, cid2: int, info: bytes = b''): + ver = 0x20 cid1 = 0x46 info_length = Pylontech.get_info_length(info) - frame = "{:02X}{:02X}{:02X}{:02X}{:04X}".format(0x20, address, cid1, cid2, info_length).encode() + frame = "{:02X}{:02X}{:02X}{:02X}{:04X}".format(ver, address, cid1, cid2, info_length).encode() frame += info + logger.info(f"VER=%s; ADDR=%s; CID1={cid1:02X}H; CID2={cid2:02X}H; frame.INFO=%s", ver, address, info.decode()) + frame_chksum = Pylontech.get_frame_checksum(frame) whole_frame = (b"~" + frame + "{:04X}".format(frame_chksum).encode() + b"\r") return whole_frame @@ -212,9 +223,15 @@ def _decode_frame(self, frame): def read_frame(self): raw_frame = self.s.readline() - f = self._decode_hw_frame(raw_frame=raw_frame) - parsed = self._decode_frame(f) - return parsed + logger.debug(f"{raw_frame=}") + chk_frame = self._decode_hw_frame(raw_frame=raw_frame) + logger.debug(f"{chk_frame=}") + dec_frame = self._decode_frame(chk_frame) + data = b'\x05\xff\x0a'; + logger.info(f"VER=%s; ADDR=%s; CID1={dec_frame.cid1[0]:02X}H; CID2={dec_frame.cid2[0]:02X}H; frame.INFO=%s", ord(dec_frame.ver), ord(dec_frame.adr), dec_frame.info.hex(" ").upper()) + + logger.debug(f"{dec_frame=}") + return dec_frame def scan_for_batteries(self, start=0, end=255) -> Dict[int, str]: @@ -284,9 +301,13 @@ def get_values(self): self.send_cmd(2, 0x42, b'FF') f = self.read_frame() - # infoflag = f.info[0] - d = self.get_values_fmt.parse(f.info[1:]) - return d + if f.cid2 == b'\x00': +# infoflag = f.info[0] + d = self.get_values_fmt.parse(f.info[1:]) + return d + else: + return -1 + return -2 def get_values_single(self, dev_id): bdevid = "{:02X}".format(dev_id).encode()