You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
7.0 KiB

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import struct
class StatusResponse:
e_keys = ['voltage','current','power','energy_total','energy_daily']
def unpack(self, fmt, base):
size = struct.calcsize(fmt)
return struct.unpack(fmt, self.response[base:base+size])
@property
def phases(self):
phases = []
p_exists = True
while p_exists:
p_exists = False
phase_id = len(phases)
phase = {}
for key in self.e_keys:
prop = f'ac_{key}_{phase_id}'
if hasattr(self, prop):
p_exists = True
phase[key] = getattr(self, prop)
if p_exists:
phases.append(phase)
return phases
@property
def strings(self):
strings = []
s_exists = True
while s_exists:
s_exists = False
string_id = len(strings)
string = {}
for key in self.e_keys:
prop = f'dc_{key}_{string_id}'
if hasattr(self, prop):
s_exists = True
string[key] = getattr(self, prop)
if s_exists:
strings.append(string)
return strings
def __dict__(self):
data = {}
data['phases'] = self.phases
data['strings'] = self.strings
data['temperature'] = self.temperature
data['frequency'] = self.frequency
return data
class UnknownResponse:
@property
def hex_ascii(self):
return ' '.join([f'{b:02x}' for b in self.response])
@property
def dump_longs(self):
res = self.response
n = len(res)/4
vals = None
if n % 4 == 0:
vals = struct.unpack(f'>{int(n)}L', res)
return vals
@property
def dump_longs_pad1(self):
res = self.response[1:]
n = len(res)/4
vals = None
if n % 4 == 0:
vals = struct.unpack(f'>{int(n)}L', res)
return vals
@property
def dump_shorts(self):
n = len(self.response)/2
vals = None
if n % 2 == 0:
vals = struct.unpack(f'>{int(n)}H', self.response)
return vals
@property
def dump_shorts_pad1(self):
res = self.response[1:]
n = len(res)/2
vals = None
if n % 2 == 0:
vals = struct.unpack(f'>{int(n)}H', res)
return vals
class DEBUG_DecodeAny(UnknownResponse):
def __init__(self, response):
self.response = response
longs = self.dump_longs
if not longs:
print(' type long : unable to decode (len or not mod 4)')
else:
print(' type long : ' + str(longs))
longs = self.dump_longs_pad1
if not longs:
print(' type long pad1 : unable to decode (len or not mod 4)')
else:
print(' type long pad1 : ' + str(longs))
shorts = self.dump_shorts
if not shorts:
print(' type short : unable to decode (len or not mod 2)')
else:
print(' type short : ' + str(shorts))
shorts = self.dump_shorts_pad1
if not shorts:
print(' type short pad1: unable to decode (len or not mod 2)')
else:
print(' type short pad1: ' + str(shorts))
# 1141-Series Inverters, 2 MPPT, 1 Phase
class HM600_Decode0B(StatusResponse):
def __init__(self, response):
self.response = response
@property
def dc_voltage_0(self):
return self.unpack('>H', 2)[0]/10
@property
def dc_current_0(self):
return self.unpack('>H', 4)[0]/100
@property
def dc_power_0(self):
return self.unpack('>H', 6)[0]/10
@property
def dc_energy_total_0(self):
return self.unpack('>L', 14)[0]
@property
def dc_energy_daily_0(self):
return self.unpack('>H', 22)[0]
@property
def dc_voltage_1(self):
return self.unpack('>H', 8)[0]/10
@property
def dc_current_1(self):
return self.unpack('>H', 10)[0]/100
@property
def dc_power_1(self):
return self.unpack('>H', 12)[0]/10
@property
def dc_energy_total_1(self):
return self.unpack('>L', 18)[0]
@property
def dc_energy_daily_1(self):
return self.unpack('>H', 24)[0]
@property
def ac_voltage_0(self):
return self.unpack('>H', 26)[0]/10
@property
def ac_current_0(self):
return self.unpack('>H', 34)[0]/10
@property
def ac_power_0(self):
return self.unpack('>H', 30)[0]/10
@property
def frequency(self):
return self.unpack('>H', 28)[0]/100
@property
def temperature(self):
return self.unpack('>H', 38)[0]/10
class HM600_Decode0C(HM600_Decode0B):
def __init__(self, response):
self.response = response
# 1161-Series Inverters, 4 MPPT, 1 Phase
class HM1500_Decode0B(StatusResponse):
def __init__(self, response):
self.response = response
@property
def dc_voltage_0(self):
return self.unpack('>H', 2)[0]/10
@property
def dc_current_0(self):
return self.unpack('>H', 4)[0]/100
@property
def dc_power_0(self):
return self.unpack('>H', 8)[0]/10
@property
def dc_energy_total_0(self):
return self.unpack('>L', 12)[0]
@property
def dc_energy_daily_0(self):
return self.unpack('>H', 20)[0]
@property
def dc_voltage_1(self):
return self.unpack('>H', 2)[0]/10
@property
def dc_current_1(self):
return self.unpack('>H', 4)[0]/100
@property
def dc_power_1(self):
return self.unpack('>H', 10)[0]/10
@property
def dc_energy_total_1(self):
return self.unpack('>L', 16)[0]
@property
def dc_energy_daily_1(self):
return self.unpack('>H', 22)[0]
@property
def dc_voltage_2(self):
return self.unpack('>H', 24)[0]/10
@property
def dc_current_2(self):
return self.unpack('>H', 26)[0]/100
@property
def dc_power_2(self):
return self.unpack('>H', 30)[0]/10
@property
def dc_energy_total_2(self):
return self.unpack('>L', 34)[0]
@property
def dc_energy_daily_2(self):
return self.unpack('>H', 42)[0]
@property
def dc_voltage_3(self):
return self.unpack('>H', 24)[0]/10
@property
def dc_current_3(self):
return self.unpack('>H', 28)[0]/100
@property
def dc_power_3(self):
return self.unpack('>H', 32)[0]/10
@property
def dc_energy_total_3(self):
return self.unpack('>L', 38)[0]
@property
def dc_energy_daily_3(self):
return self.unpack('>H', 44)[0]
@property
def ac_voltage_0(self):
return self.unpack('>H', 46)[0]/10
@property
def ac_current_0(self):
return self.unpack('>H', 54)[0]/100
@property
def ac_power_0(self):
return self.unpack('>H', 50)[0]/10
@property
def frequency(self):
return self.unpack('>H', 48)[0]/100
@property
def temperature(self):
return self.unpack('>H', 58)[0]/10