Browse Source

Merge pull request #272 from chehrlic/vz_rpi_updates

pull/277/head
stefan123t 3 years ago
committed by GitHub
parent
commit
f3e1bf2fae
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      tools/rpi/hoymiles/__init__.py
  2. 46
      tools/rpi/hoymiles/__main__.py
  3. 40
      tools/rpi/hoymiles/decoders/__init__.py

15
tools/rpi/hoymiles/__init__.py

@ -482,21 +482,20 @@ def compose_esb_packet(packet, mtu=17, **params):
fragment = compose_esb_fragment(packet[i:i+mtu], **params) fragment = compose_esb_fragment(packet[i:i+mtu], **params)
yield fragment yield fragment
def compose_set_time_payload(timestamp=None): def compose_send_time_payload(cmdId):
""" """
Build set time request packet Build set time request packet
:param timestamp: time to set (default: int(time.time()) ) :param cmd to request
:type timestamp: int :type cmd: uint8
:return: payload :return: payload
:rtype: bytes :rtype: bytes
""" """
if not timestamp: timestamp = int(time.time())
timestamp = int(time.time())
payload = b'\x0b\x00' payload = struct.pack('>B', cmdId) + b'\x00'
payload = payload + struct.pack('>L', timestamp) # big-endian: msb at low address payload = payload + struct.pack('>L', timestamp) # big-endian: msb at low address
payload = payload + b'\x00\x00\x00\x05\x00\x00\x00\x00' payload = payload + b'\x00\x00\x00\x00\x00\x00\x00\x00'
return frame_payload(payload) return frame_payload(payload)
@ -649,7 +648,7 @@ class InverterTransaction:
except StopIteration: except StopIteration:
seq_last = max(frames, key=lambda frame:frame.seq).seq if len(frames) else 0 seq_last = max(frames, key=lambda frame:frame.seq).seq if len(frames) else 0
self.__retransmit_frame(seq_last + 1) self.__retransmit_frame(seq_last + 1)
raise BufferError(f'Missing packet: Last packet {len(self.scratch)}') raise BufferError(f'Missing packet: Last packet {seq_last + 1}')
# Rebuild payload from unordered frames # Rebuild payload from unordered frames
payload = b'' payload = b''

46
tools/rpi/hoymiles/__main__.py

@ -7,6 +7,7 @@ Hoymiles micro-inverters main application
import sys import sys
import struct import struct
from enum import IntEnum
import re import re
import time import time
from datetime import datetime from datetime import datetime
@ -16,7 +17,7 @@ from yaml.loader import SafeLoader
import paho.mqtt.client import paho.mqtt.client
import hoymiles import hoymiles
def main_loop(): def main_loop(do_init):
"""Main loop""" """Main loop"""
inverters = [ inverters = [
inverter for inverter in ahoy_config.get('inverters', []) inverter for inverter in ahoy_config.get('inverters', [])
@ -25,9 +26,29 @@ def main_loop():
for inverter in inverters: for inverter in inverters:
if hoymiles.HOYMILES_DEBUG_LOGGING: if hoymiles.HOYMILES_DEBUG_LOGGING:
print(f'Poll inverter {inverter["serial"]}') print(f'Poll inverter {inverter["serial"]}')
poll_inverter(inverter) poll_inverter(inverter, do_init)
def poll_inverter(inverter, retries=4): class InfoCommands(IntEnum):
InverterDevInform_Simple = 0 # 0x00
InverterDevInform_All = 1 # 0x01
GridOnProFilePara = 2 # 0x02
HardWareConfig = 3 # 0x03
SimpleCalibrationPara = 4 # 0x04
SystemConfigPara = 5 # 0x05
RealTimeRunData_Debug = 11 # 0x0b
RealTimeRunData_Reality = 12 # 0x0c
RealTimeRunData_A_Phase = 13 # 0x0d
RealTimeRunData_B_Phase = 14 # 0x0e
RealTimeRunData_C_Phase = 15 # 0x0f
AlarmData = 17 # 0x11, Alarm data - all unsent alarms
AlarmUpdate = 18 # 0x12, Alarm data - all pending alarms
RecordData = 19 # 0x13
InternalData = 20 # 0x14
GetLossRate = 21 # 0x15
GetSelfCheckState = 30 # 0x1e
InitDataState = 0xff
def poll_inverter(inverter, do_init, retries=4):
""" """
Send/Receive command_queue, initiate status poll on inverter Send/Receive command_queue, initiate status poll on inverter
@ -39,11 +60,15 @@ def poll_inverter(inverter, retries=4):
dtu_ser = ahoy_config.get('dtu', {}).get('serial') dtu_ser = ahoy_config.get('dtu', {}).get('serial')
# Queue at least status data request # Queue at least status data request
command_queue[str(inverter_ser)].append(hoymiles.compose_set_time_payload()) inv_str = str(inverter_ser)
if do_init:
command_queue[inv_str].append(hoymiles.compose_send_time_payload(InfoCommands.InverterDevInform_All))
# command_queue[inv_str].append(hoymiles.compose_send_time_payload(InfoCommands.SystemConfigPara))
command_queue[inv_str].append(hoymiles.compose_send_time_payload(InfoCommands.RealTimeRunData_Debug))
# Putt all queued commands for current inverter on air # Put all queued commands for current inverter on air
while len(command_queue[str(inverter_ser)]) > 0: while len(command_queue[inv_str]) > 0:
payload = command_queue[str(inverter_ser)].pop(0) payload = command_queue[inv_str].pop(0)
# Send payload {ttl}-times until we get at least one reponse # Send payload {ttl}-times until we get at least one reponse
payload_ttl = retries payload_ttl = retries
@ -276,10 +301,13 @@ if __name__ == '__main__':
loop_interval = ahoy_config.get('interval', 1) loop_interval = ahoy_config.get('interval', 1)
try: try:
do_init = True
while True: while True:
t_loop_start = time.time() t_loop_start = time.time()
main_loop() main_loop(do_init)
do_init = False
print('', end='', flush=True) print('', end='', flush=True)

40
tools/rpi/hoymiles/decoders/__init__.py

@ -314,6 +314,28 @@ class EventsResponse(UnknownResponse):
print(f' {fmt:7}: ' + str(struct.unpack('>' + fmt, chunk))) print(f' {fmt:7}: ' + str(struct.unpack('>' + fmt, chunk)))
print(end='', flush=True) print(end='', flush=True)
class HardwareInfoResponse(UnknownResponse):
def __init__(self, *args, **params):
super().__init__(*args, **params)
"""
const byteAssign_t InfoAssignment[] = {
{ FLD_FW_VERSION, UNIT_NONE, CH0, 0, 2, 1 },
{ FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 },
{ FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 },
{ FLD_HW_ID, UNIT_NONE, CH0, 8, 2, 1 }
};
self.response = bytes('\x27\x1a\x07\xe5\x04\x4d\x03\x4a\x00\x68\x00\x00\x00\x00\xe6\xfb', 'latin1')
"""
fw_version, fw_build_yyyy, fw_build_mmdd, unknown, hw_id = struct.unpack('>HHHHH', self.response[0:10])
fw_version_maj = int((fw_version / 10000))
fw_version_min = int((fw_version % 10000) / 100)
fw_version_pat = int((fw_version % 100))
fw_build_mm = int(fw_build_mmdd / 100)
fw_build_dd = int(fw_build_mmdd % 100)
print()
print(f'Firmware: {fw_version_maj}.{fw_version_min}.{fw_version_pat} build at {fw_build_dd}/{fw_build_mm}/{fw_build_yyyy}, HW revision {hw_id}')
class DebugDecodeAny(UnknownResponse): class DebugDecodeAny(UnknownResponse):
"""Default decoder""" """Default decoder"""
@ -359,6 +381,9 @@ class DebugDecodeAny(UnknownResponse):
# 1121-Series Intervers, 1 MPPT, 1 Phase # 1121-Series Intervers, 1 MPPT, 1 Phase
class Hm300Decode01(HardwareInfoResponse):
""" Firmware version / date """
class Hm300Decode02(EventsResponse): class Hm300Decode02(EventsResponse):
""" Inverter generic events log """ """ Inverter generic events log """
@ -407,6 +432,9 @@ class Hm300Decode0B(StatusResponse):
""" Inverter temperature in °C """ """ Inverter temperature in °C """
return self.unpack('>H', 26)[0]/10 return self.unpack('>H', 26)[0]/10
class Hm300Decode0C(Hm300Decode0B):
""" 1121-series mirco-inverters status data """
class Hm300Decode11(EventsResponse): class Hm300Decode11(EventsResponse):
""" Inverter generic events log """ """ Inverter generic events log """
@ -415,6 +443,9 @@ class Hm300Decode12(EventsResponse):
# 1141-Series Inverters, 2 MPPT, 1 Phase # 1141-Series Inverters, 2 MPPT, 1 Phase
class Hm600Decode01(HardwareInfoResponse):
""" Firmware version / date """
class Hm600Decode02(EventsResponse): class Hm600Decode02(EventsResponse):
""" Inverter generic events log """ """ Inverter generic events log """
@ -492,6 +523,9 @@ class Hm600Decode0B(StatusResponse):
""" Event counter """ """ Event counter """
return self.unpack('>H', 40)[0] return self.unpack('>H', 40)[0]
class Hm600Decode0C(Hm600Decode0B):
""" 1141-series mirco-inverters status data """
class Hm600Decode11(EventsResponse): class Hm600Decode11(EventsResponse):
""" Inverter generic events log """ """ Inverter generic events log """
@ -500,6 +534,9 @@ class Hm600Decode12(EventsResponse):
# 1161-Series Inverters, 2 MPPT, 1 Phase # 1161-Series Inverters, 2 MPPT, 1 Phase
class Hm1200Decode01(HardwareInfoResponse):
""" Firmware version / date """
class Hm1200Decode02(EventsResponse): class Hm1200Decode02(EventsResponse):
""" Inverter generic events log """ """ Inverter generic events log """
@ -619,6 +656,9 @@ class Hm1200Decode0B(StatusResponse):
""" Event counter """ """ Event counter """
return self.unpack('>H', 60)[0] return self.unpack('>H', 60)[0]
class Hm1200Decode0C(Hm1200Decode0B):
""" 1161-series mirco-inverters status data """
class Hm1200Decode11(EventsResponse): class Hm1200Decode11(EventsResponse):
""" Inverter generic events log """ """ Inverter generic events log """

Loading…
Cancel
Save