add Modbus and AT command handler
This commit is contained in:
@@ -48,6 +48,8 @@ class Sequence():
|
|||||||
|
|
||||||
|
|
||||||
class SolarmanV5(Message):
|
class SolarmanV5(Message):
|
||||||
|
AT_CMD = 1
|
||||||
|
MB_RTU_CMD = 2
|
||||||
|
|
||||||
def __init__(self, server_side: bool):
|
def __init__(self, server_side: bool):
|
||||||
super().__init__(server_side)
|
super().__init__(server_side)
|
||||||
@@ -59,7 +61,7 @@ class SolarmanV5(Message):
|
|||||||
self.db = InfosG3P()
|
self.db = InfosG3P()
|
||||||
self.time_ofs = 0
|
self.time_ofs = 0
|
||||||
self.mb = Modbus()
|
self.mb = Modbus()
|
||||||
self.forward_modbus_rep = False
|
self.forward_modbus_resp = False
|
||||||
self.switch = {
|
self.switch = {
|
||||||
|
|
||||||
0x4210: self.msg_data_ind, # real time data
|
0x4210: self.msg_data_ind, # real time data
|
||||||
@@ -88,7 +90,7 @@ class SolarmanV5(Message):
|
|||||||
#
|
#
|
||||||
# MODbus or AT cmd
|
# MODbus or AT cmd
|
||||||
0x4510: self.msg_command_req, # from server
|
0x4510: self.msg_command_req, # from server
|
||||||
0x1510: self.msg_response, # from inverter
|
0x1510: self.msg_command_rsp, # from inverter
|
||||||
}
|
}
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@@ -298,23 +300,48 @@ class SolarmanV5(Message):
|
|||||||
self.__finish_send_msg()
|
self.__finish_send_msg()
|
||||||
|
|
||||||
async def send_modbus_cmd(self, func, addr, val) -> None:
|
async def send_modbus_cmd(self, func, addr, val) -> None:
|
||||||
self.forward_modbus_rep = False
|
self.forward_modbus_resp = False
|
||||||
self.__build_header(0x4510)
|
self.__build_header(0x4510)
|
||||||
self._send_buffer += struct.pack('<BHLLL', 2, 0x2b0, 0, 0, 0)
|
self._send_buffer += struct.pack('<BHLLL', self.MB_RTU_CMD,
|
||||||
self._send_buffer += self.mb.build_msg(1, func, addr, val)
|
0x2b0, 0, 0, 0)
|
||||||
|
self._send_buffer += self.mb.build_msg(Modbus.INV_ADDR,
|
||||||
|
func, addr, val)
|
||||||
self.__finish_send_msg()
|
self.__finish_send_msg()
|
||||||
await self.async_write('Send Modbus Command:')
|
try:
|
||||||
|
await self.async_write('Send Modbus Command:')
|
||||||
|
except Exception:
|
||||||
|
self._send_buffer = bytearray(0)
|
||||||
|
|
||||||
def send_at_cmd(self, AT_cmd: str) -> None:
|
async def send_at_cmd(self, AT_cmd: str) -> None:
|
||||||
self.__build_header(0x4510)
|
self.__build_header(0x4510)
|
||||||
self._send_buffer += struct.pack(f'<BHLLL{len(AT_cmd)}sc', 1, 2,
|
self._send_buffer += struct.pack(f'<BHLLL{len(AT_cmd)}sc', self.AT_CMD,
|
||||||
0, 0, 0, AT_cmd.encode('utf-8'),
|
2, 0, 0, 0, AT_cmd.encode('utf-8'),
|
||||||
b'\r')
|
b'\r')
|
||||||
self.__finish_send_msg()
|
self.__finish_send_msg()
|
||||||
|
try:
|
||||||
|
await self.async_write('Send AT Command:')
|
||||||
|
except Exception:
|
||||||
|
self._send_buffer = bytearray(0)
|
||||||
|
|
||||||
def __forward_msg(self):
|
def __forward_msg(self):
|
||||||
self.forward(self._recv_buffer, self.header_len+self.data_len+2)
|
self.forward(self._recv_buffer, self.header_len+self.data_len+2)
|
||||||
|
|
||||||
|
def __build_model_name(self):
|
||||||
|
db = self.db
|
||||||
|
MaxPow = db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
|
||||||
|
Rated = db.get_db_value(Register.RATED_POWER, 0)
|
||||||
|
Model = None
|
||||||
|
if MaxPow == 2000:
|
||||||
|
if Rated == 800 or Rated == 600:
|
||||||
|
Model = f'TSOL-MS{MaxPow}({Rated})'
|
||||||
|
else:
|
||||||
|
Model = f'TSOL-MS{MaxPow}'
|
||||||
|
elif MaxPow == 1800 or MaxPow == 1600:
|
||||||
|
Model = f'TSOL-MS{MaxPow}'
|
||||||
|
if Model:
|
||||||
|
logger.info(f'Model: {Model}')
|
||||||
|
self.db.set_db_def_value(Register.EQUIPMENT_MODEL, Model)
|
||||||
|
|
||||||
def __process_data(self, ftype):
|
def __process_data(self, ftype):
|
||||||
inv_update = False
|
inv_update = False
|
||||||
msg_type = self.control >> 8
|
msg_type = self.control >> 8
|
||||||
@@ -325,21 +352,7 @@ class SolarmanV5(Message):
|
|||||||
self.new_data[key] = True
|
self.new_data[key] = True
|
||||||
|
|
||||||
if inv_update:
|
if inv_update:
|
||||||
db = self.db
|
self.__build_model_name()
|
||||||
MaxPow = db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
|
|
||||||
Rated = db.get_db_value(Register.RATED_POWER, 0)
|
|
||||||
Model = None
|
|
||||||
if MaxPow == 2000:
|
|
||||||
if Rated == 800 or Rated == 600:
|
|
||||||
Model = f'TSOL-MS{MaxPow}({Rated})'
|
|
||||||
else:
|
|
||||||
Model = f'TSOL-MS{MaxPow}'
|
|
||||||
elif MaxPow == 1800 or MaxPow == 1600:
|
|
||||||
Model = f'TSOL-MS{MaxPow}'
|
|
||||||
if Model:
|
|
||||||
logger.info(f'Model: {Model}')
|
|
||||||
self.db.set_db_def_value(Register.EQUIPMENT_MODEL, Model)
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Message handler methods
|
Message handler methods
|
||||||
'''
|
'''
|
||||||
@@ -402,11 +415,42 @@ class SolarmanV5(Message):
|
|||||||
data = self._recv_buffer[self.header_len:]
|
data = self._recv_buffer[self.header_len:]
|
||||||
result = struct.unpack_from('<B', data, 0)
|
result = struct.unpack_from('<B', data, 0)
|
||||||
ftype = result[0]
|
ftype = result[0]
|
||||||
|
if ftype == self.AT_CMD:
|
||||||
|
self.inc_counter('AT_Command')
|
||||||
|
elif ftype == self.MB_RTU_CMD:
|
||||||
|
if not self.mb.recv_req(data[15:-2]):
|
||||||
|
return
|
||||||
|
self.forward_modbus_resp = True
|
||||||
|
self.inc_counter('Modbus_Command')
|
||||||
|
|
||||||
self.inc_counter('AT_Command')
|
|
||||||
self.__forward_msg()
|
self.__forward_msg()
|
||||||
self.__send_ack_rsp(0x1510, ftype)
|
self.__send_ack_rsp(0x1510, ftype)
|
||||||
|
|
||||||
|
def msg_command_rsp(self):
|
||||||
|
data = self._recv_buffer[self.header_len:]
|
||||||
|
ftype = data[0]
|
||||||
|
if ftype == self.AT_CMD:
|
||||||
|
pass
|
||||||
|
elif ftype == self.MB_RTU_CMD:
|
||||||
|
valid = data[1]
|
||||||
|
modbus_msg_len = self.data_len - 14
|
||||||
|
logger.info(f'modbus_len:{modbus_msg_len} accepted:{valid}')
|
||||||
|
if valid == 1 and modbus_msg_len > 4:
|
||||||
|
logger.info(f'first byte modbus:{data[14]}')
|
||||||
|
inv_update = False
|
||||||
|
for key, update in self.mb.recv_resp(self.db, data[14:-2]):
|
||||||
|
if update:
|
||||||
|
if key == 'inverter':
|
||||||
|
inv_update = True
|
||||||
|
self.new_data[key] = True
|
||||||
|
|
||||||
|
if inv_update:
|
||||||
|
self.__build_model_name()
|
||||||
|
|
||||||
|
if not self.forward_modbus_resp:
|
||||||
|
return
|
||||||
|
self.__forward_msg()
|
||||||
|
|
||||||
def msg_hbeat_ind(self):
|
def msg_hbeat_ind(self):
|
||||||
data = self._recv_buffer[self.header_len:]
|
data = self._recv_buffer[self.header_len:]
|
||||||
result = struct.unpack_from('<B', data, 0)
|
result = struct.unpack_from('<B', data, 0)
|
||||||
@@ -435,8 +479,9 @@ class SolarmanV5(Message):
|
|||||||
valid = result[1] == 1 # status
|
valid = result[1] == 1 # status
|
||||||
ts = result[2]
|
ts = result[2]
|
||||||
set_hb = result[3] # always 60 or 120
|
set_hb = result[3] # always 60 or 120
|
||||||
logger.info(f'ftype:{ftype} accepted:{valid}'
|
logger.debug(f'ftype:{ftype} accepted:{valid}'
|
||||||
f' ts:{ts:08x} nextHeartbeat: {set_hb}s')
|
f' ts:{ts:08x} nextHeartbeat: {set_hb}s')
|
||||||
|
|
||||||
dt = datetime.fromtimestamp(ts)
|
dt = datetime.fromtimestamp(ts)
|
||||||
logger.info(f'ts: {dt.strftime("%Y-%m-%d %H:%M:%S")}')
|
logger.debug(f'ts: {dt.strftime("%Y-%m-%d %H:%M:%S")}')
|
||||||
|
self.__forward_msg()
|
||||||
|
|||||||
Reference in New Issue
Block a user