|  | @ -2,18 +2,34 @@ | 
			
		
	
		
		
			
				
					|  |  | # -*- coding: utf-8 -*- |  |  | # -*- coding: utf-8 -*- | 
			
		
	
		
		
			
				
					|  |  | import struct |  |  | import struct | 
			
		
	
		
		
			
				
					|  |  | import crcmod |  |  | import crcmod | 
			
		
	
		
		
			
				
					|  |  |  |  |  | from datetime import timedelta | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | f_crc_m = crcmod.predefined.mkPredefinedCrcFun('modbus') |  |  | f_crc_m = crcmod.predefined.mkPredefinedCrcFun('modbus') | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | class StatusResponse: |  |  | class StatusResponse: | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     """Inverter StatusResponse object""" | 
			
		
	
		
		
			
				
					|  |  |     e_keys  = ['voltage','current','power','energy_total','energy_daily'] |  |  |     e_keys  = ['voltage','current','power','energy_total','energy_daily'] | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     def unpack(self, fmt, base): |  |  |     def unpack(self, fmt, base): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         Data unpack helper | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :param str fmt: struct format string | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :param int base: unpack base position from self.response bytes | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :return: unpacked values | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :rtype: tuple | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |         size = struct.calcsize(fmt) |  |  |         size = struct.calcsize(fmt) | 
			
		
	
		
		
			
				
					|  |  |         return struct.unpack(fmt, self.response[base:base+size]) |  |  |         return struct.unpack(fmt, self.response[base:base+size]) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def phases(self): |  |  |     def phases(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         AC power data | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :retrun: list of dict's | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :rtype: list | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |         phases = [] |  |  |         phases = [] | 
			
		
	
		
		
			
				
					|  |  |         p_exists = True |  |  |         p_exists = True | 
			
		
	
		
		
			
				
					|  |  |         while p_exists: |  |  |         while p_exists: | 
			
		
	
	
		
		
			
				
					|  | @ -32,6 +48,12 @@ class StatusResponse: | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def strings(self): |  |  |     def strings(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         DC PV-string data | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :retrun: list of dict's | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :rtype: list | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |         strings = [] |  |  |         strings = [] | 
			
		
	
		
		
			
				
					|  |  |         s_exists = True |  |  |         s_exists = True | 
			
		
	
		
		
			
				
					|  |  |         while s_exists: |  |  |         while s_exists: | 
			
		
	
	
		
		
			
				
					|  | @ -49,6 +71,12 @@ class StatusResponse: | 
			
		
	
		
		
			
				
					|  |  |         return strings |  |  |         return strings | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     def __dict__(self): |  |  |     def __dict__(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         Get all known data | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :return: dict of properties | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :rtype: dict | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |         data = {} |  |  |         data = {} | 
			
		
	
		
		
			
				
					|  |  |         data['phases'] = self.phases |  |  |         data['phases'] = self.phases | 
			
		
	
		
		
			
				
					|  |  |         data['strings'] = self.strings |  |  |         data['strings'] = self.strings | 
			
		
	
	
		
		
			
				
					|  | @ -57,18 +85,34 @@ class StatusResponse: | 
			
		
	
		
		
			
				
					|  |  |         return data |  |  |         return data | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | class UnknownResponse: |  |  | class UnknownResponse: | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     """ | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     Debugging helper for unknown payload format | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     """ | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def hex_ascii(self): |  |  |     def hex_ascii(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         Generate white-space separated byte representation | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :return: hexlifierd byte string | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :rtype: str | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |         return ' '.join([f'{b:02x}' for b in self.response]) |  |  |         return ' '.join([f'{b:02x}' for b in self.response]) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def valid_crc(self): |  |  |     def valid_crc(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         Checks if self.response has valid Modbus CRC | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :return: if crc is available and correct | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :rtype: bool | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |         # check crc |  |  |         # check crc | 
			
		
	
		
		
			
				
					|  |  |         pcrc = struct.unpack('>H', self.response[-2:])[0] |  |  |         pcrc = struct.unpack('>H', self.response[-2:])[0] | 
			
		
	
		
		
			
				
					|  |  |         return f_crc_m(self.response[:-2]) == pcrc |  |  |         return f_crc_m(self.response[:-2]) == pcrc | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def dump_longs(self): |  |  |     def dump_longs(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """Get all data, interpreted as long""" | 
			
		
	
		
		
			
				
					|  |  |         if len(self.response) < 5: |  |  |         if len(self.response) < 5: | 
			
		
	
		
		
			
				
					|  |  |             return None |  |  |             return None | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -86,6 +130,7 @@ class UnknownResponse: | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def dump_longs_pad1(self): |  |  |     def dump_longs_pad1(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """Get all data, interpreted as long""" | 
			
		
	
		
		
			
				
					|  |  |         if len(self.response) < 7: |  |  |         if len(self.response) < 7: | 
			
		
	
		
		
			
				
					|  |  |             return None |  |  |             return None | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -103,6 +148,7 @@ class UnknownResponse: | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def dump_longs_pad2(self): |  |  |     def dump_longs_pad2(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """Get all data, interpreted as long""" | 
			
		
	
		
		
			
				
					|  |  |         if len(self.response) < 9: |  |  |         if len(self.response) < 9: | 
			
		
	
		
		
			
				
					|  |  |             return None |  |  |             return None | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -120,6 +166,7 @@ class UnknownResponse: | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def dump_longs_pad3(self): |  |  |     def dump_longs_pad3(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """Get all data, interpreted as long""" | 
			
		
	
		
		
			
				
					|  |  |         if len(self.response) < 11: |  |  |         if len(self.response) < 11: | 
			
		
	
		
		
			
				
					|  |  |             return None |  |  |             return None | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -137,6 +184,7 @@ class UnknownResponse: | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def dump_shorts(self): |  |  |     def dump_shorts(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """Get all data, interpreted as short""" | 
			
		
	
		
		
			
				
					|  |  |         if len(self.response) < 5: |  |  |         if len(self.response) < 5: | 
			
		
	
		
		
			
				
					|  |  |             return None |  |  |             return None | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -154,6 +202,7 @@ class UnknownResponse: | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def dump_shorts_pad1(self): |  |  |     def dump_shorts_pad1(self): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """Get all data, interpreted as short""" | 
			
		
	
		
		
			
				
					|  |  |         if len(self.response) < 6: |  |  |         if len(self.response) < 6: | 
			
		
	
		
		
			
				
					|  |  |             return None |  |  |             return None | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -169,7 +218,79 @@ class UnknownResponse: | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |         return vals |  |  |         return vals | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  | class HM600_Decode11(UnknownResponse): |  |  | class EventsResponse(UnknownResponse): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     alarm_codes = { | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             1: 'Inverter start', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             2: 'Producing power', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             121: 'Over temperature protection', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             125: 'Grid configuration parameter error', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             126: 'Software error code 126', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             127: 'Firmware error', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             128: 'Software error code 128', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             129: 'Software error code 129', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             130: 'Offline', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             141: 'Grid overvoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             142: 'Average grid overvoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             143: 'Grid undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             144: 'Grid overfrequency', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             145: 'Grid underfrequency', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             146: 'Rapid grid frequency change', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             147: 'Power grid outage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             148: 'Grid disconnection', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             149: 'Island detected', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             205: 'Input port 1 & 2 overvoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             206: 'Input port 3 & 4 overvoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             207: 'Input port 1 & 2 undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             208: 'Input port 3 & 4 undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             209: 'Port 1 no input', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             210: 'Port 2 no input', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             211: 'Port 3 no input', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             212: 'Port 4 no input', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             213: 'PV-1 & PV-2 abnormal wiring', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             214: 'PV-3 & PV-4 abnormal wiring', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             215: 'PV-1 Input overvoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             216: 'PV-1 Input undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             217: 'PV-2 Input overvoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             218: 'PV-2 Input undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             219: 'PV-3 Input overvoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             220: 'PV-3 Input undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             221: 'PV-4 Input overvoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             222: 'PV-4 Input undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             301: 'Hardware error code 301', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             302: 'Hardware error code 302', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             303: 'Hardware error code 303', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             304: 'Hardware error code 304', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             305: 'Hardware error code 305', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             306: 'Hardware error code 306', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             307: 'Hardware error code 307', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             308: 'Hardware error code 308', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             309: 'Hardware error code 309', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             310: 'Hardware error code 310', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             311: 'Hardware error code 311', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             312: 'Hardware error code 312', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             313: 'Hardware error code 313', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             314: 'Hardware error code 314', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5041: 'Error code-04 Port 1', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5042: 'Error code-04 Port 2', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5043: 'Error code-04 Port 3', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5044: 'Error code-04 Port 4', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5051: 'PV Input 1 Overvoltage/Undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5052: 'PV Input 2 Overvoltage/Undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5053: 'PV Input 3 Overvoltage/Undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5054: 'PV Input 4 Overvoltage/Undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5060: 'Abnormal bias', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5070: 'Over temperature protection', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5080: 'Grid Overvoltage/Undervoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5090: 'Grid Overfrequency/Underfrequency', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5100: 'Island detected', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5120: 'EEPROM reading and writing error', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5150: '10 min value grid overvoltage', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             5200: 'Firmware error', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             8310: 'Shut down', | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             9000: 'Microinverter is suspected of being stolen' | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     def __init__(self, response): |  |  |     def __init__(self, response): | 
			
		
	
		
		
			
				
					|  |  |         self.response = response |  |  |         self.response = response | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -183,16 +304,26 @@ class HM600_Decode11(UnknownResponse): | 
			
		
	
		
		
			
				
					|  |  |         chunk_size = 12 |  |  |         chunk_size = 12 | 
			
		
	
		
		
			
				
					|  |  |         for c in range(2, len(self.response), chunk_size): |  |  |         for c in range(2, len(self.response), chunk_size): | 
			
		
	
		
		
			
				
					|  |  |             chunk = self.response[c:c+chunk_size] |  |  |             chunk = self.response[c:c+chunk_size] | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |             print(' '.join([f'{b:02x}' for b in chunk]) + ': ') |  |  |             print(' '.join([f'{b:02x}' for b in chunk]) + ': ') | 
			
		
	
		
		
			
				
					|  |  |             print(' BBLHl  : ' + str(struct.unpack('>BBLHl', chunk))) |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             print() |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  | class HM600_Decode12(HM600_Decode11): |  |  |             opcode, a_code, a_count, uptime_sec = struct.unpack('>BBHH', chunk[0:6]) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     def __init__(self, response): |  |  |             a_text = self.alarm_codes.get(a_code, 'N/A') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |         super().__init__(response) |  |  | 
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |             print(f' uptime={timedelta(seconds=uptime_sec)} a_count={a_count} opcode={opcode} a_code={a_code} a_text={a_text}') | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             for fmt in ['BBHHHHH']: | 
			
		
	
		
		
			
				
					|  |  |  |  |  |                 print(f' {fmt:7}: ' + str(struct.unpack('>' + fmt, chunk))) | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             print(end='', flush=True) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | class DEBUG_DecodeAny(UnknownResponse): |  |  | class DEBUG_DecodeAny(UnknownResponse): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     """Default decoder""" | 
			
		
	
		
		
			
				
					|  |  |     def __init__(self, response): |  |  |     def __init__(self, response): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         Try interpret and print unknown response data | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         :param bytes response: response payload bytes | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         """ | 
			
		
	
		
		
			
				
					|  |  |         self.response = response |  |  |         self.response = response | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |         crc_valid = self.valid_crc |  |  |         crc_valid = self.valid_crc | 
			
		
	
	
		
		
			
				
					|  | @ -239,6 +370,18 @@ class DEBUG_DecodeAny(UnknownResponse): | 
			
		
	
		
		
			
				
					|  |  |         else: |  |  |         else: | 
			
		
	
		
		
			
				
					|  |  |             print(' type short pad1: ' + str(shorts)) |  |  |             print(' type short pad1: ' + str(shorts)) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         try: | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             if len(self.response) > 2: | 
			
		
	
		
		
			
				
					|  |  |  |  |  |                 print(' type utf-8  : ' + self.response.decode('utf-8')) | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         except UnicodeDecodeError: | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             print(' type utf-8  : utf-8 decode error') | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         try: | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             if len(self.response) > 2: | 
			
		
	
		
		
			
				
					|  |  |  |  |  |                 print(' type ascii  : ' + self.response.decode('ascii')) | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         except UnicodeDecodeError: | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             print(' type ascii  : ascii decode error') | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | # 1121-Series Intervers, 1 MPPT, 1 Phase |  |  | # 1121-Series Intervers, 1 MPPT, 1 Phase | 
			
		
	
		
		
			
				
					|  |  | class HM300_Decode0B(StatusResponse): |  |  | class HM300_Decode0B(StatusResponse): | 
			
		
	
	
		
		
			
				
					|  | @ -278,6 +421,15 @@ class HM300_Decode0B(StatusResponse): | 
			
		
	
		
		
			
				
					|  |  |     def temperature(self): |  |  |     def temperature(self): | 
			
		
	
		
		
			
				
					|  |  |         return self.unpack('>H', 26)[0]/10 |  |  |         return self.unpack('>H', 26)[0]/10 | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | class HM300_Decode11(EventsResponse): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     def __init__(self, response): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         super().__init__(response) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | class HM300_Decode12(EventsResponse): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     def __init__(self, response): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         super().__init__(response) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | # 1141-Series Inverters, 2 MPPT, 1 Phase |  |  | # 1141-Series Inverters, 2 MPPT, 1 Phase | 
			
		
	
		
		
			
				
					|  |  | class HM600_Decode0B(StatusResponse): |  |  | class HM600_Decode0B(StatusResponse): | 
			
		
	
	
		
		
			
				
					|  | @ -332,9 +484,13 @@ class HM600_Decode0B(StatusResponse): | 
			
		
	
		
		
			
				
					|  |  |     def temperature(self): |  |  |     def temperature(self): | 
			
		
	
		
		
			
				
					|  |  |         return self.unpack('>H', 38)[0]/10 |  |  |         return self.unpack('>H', 38)[0]/10 | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  | class HM600_Decode0C(HM600_Decode0B): |  |  | class HM600_Decode11(EventsResponse): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |     def __init__(self, response): |  |  |     def __init__(self, response): | 
			
		
	
		
		
			
				
					
					|  |  |         self.response = response |  |  |         super().__init__(response) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | class HM600_Decode12(EventsResponse): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     def __init__(self, response): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         super().__init__(response) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | # 1161-Series Inverters, 4 MPPT, 1 Phase |  |  | # 1161-Series Inverters, 4 MPPT, 1 Phase | 
			
		
	
	
		
		
			
				
					|  | @ -421,3 +577,11 @@ class HM1200_Decode0B(StatusResponse): | 
			
		
	
		
		
			
				
					|  |  |     @property |  |  |     @property | 
			
		
	
		
		
			
				
					|  |  |     def temperature(self): |  |  |     def temperature(self): | 
			
		
	
		
		
			
				
					|  |  |         return self.unpack('>H', 58)[0]/10 |  |  |         return self.unpack('>H', 58)[0]/10 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | class HM1200_Decode11(EventsResponse): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     def __init__(self, response): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         super().__init__(response) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | class HM1200_Decode12(EventsResponse): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |     def __init__(self, response): | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         super().__init__(response) | 
			
		
	
	
		
		
			
				
					|  | 
 |