@@ -188,7 +188,7 @@
|
||||
<polygon fill="none" stroke="#000000" points="410.5,-330 410.5,-362 560.5,-362 560.5,-330 410.5,-330"/>
|
||||
<text text-anchor="start" x="453.5455" y="-343" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="410.5,-298 410.5,-330 560.5,-330 560.5,-298 410.5,-298"/>
|
||||
<text text-anchor="start" x="420.487" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remoteStream:ConnectionG3</text>
|
||||
<text text-anchor="start" x="420.487" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote_stream:ConnectionG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="410.5,-254 410.5,-298 560.5,-298 560.5,-254 410.5,-254"/>
|
||||
<text text-anchor="start" x="466.054" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="470.5025" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
@@ -213,7 +213,7 @@
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-330 125.5,-362 281.5,-362 281.5,-330 125.5,-330"/>
|
||||
<text text-anchor="start" x="168.211" y="-343" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-298 125.5,-330 281.5,-330 281.5,-298 125.5,-298"/>
|
||||
<text text-anchor="start" x="135.1525" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remoteStream:ConnectionG3P</text>
|
||||
<text text-anchor="start" x="135.1525" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote_stream:ConnectionG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-254 125.5,-298 281.5,-298 281.5,-254 125.5,-254"/>
|
||||
<text text-anchor="start" x="184.054" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="188.5025" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
@@ -8,9 +8,9 @@
|
||||
[IterRegistry||__iter__]^[Message|server_side:bool;header_valid:bool;header_len:unsigned;data_len:unsigned;unique_id;node_id;sug_area;_recv_buffer:bytearray;_send_buffer:bytearray;_forward_buffer:bytearray;db:Infos;new_data:list;state|_read():void<abstract>;close():void;inc_counter():void;dec_counter():void]
|
||||
[Message]^[Talent|await_conn_resp_cnt;id_str;contact_name;contact_mail;db:InfosG3;mb:Modbus;switch|msg_contact_info();msg_ota_update();msg_get_time();msg_collector_data();msg_inverter_data();msg_unknown();;close()]
|
||||
[Message]^[SolarmanV5|control;serial;snr;db:InfosG3P;mb:Modbus;switch|msg_unknown();;close()]
|
||||
[Talent]^[ConnectionG3|remoteStream:ConnectionG3|healthy();close()]
|
||||
[Talent]^[ConnectionG3|remote_stream:ConnectionG3|healthy();close()]
|
||||
[Talent]has-1>[Modbus]
|
||||
[SolarmanV5]^[ConnectionG3P|remoteStream:ConnectionG3P|healthy();close()]
|
||||
[SolarmanV5]^[ConnectionG3P|remote_stream:ConnectionG3P|healthy();close()]
|
||||
[SolarmanV5]has-1>[Modbus]
|
||||
[AsyncStream|reader;writer;addr;r_addr;l_addr|<async>server_loop();<async>client_loop();<async>loop;disc();close();;__async_read();async_write();__async_forward()]^[ConnectionG3]
|
||||
[AsyncStream]^[ConnectionG3P]
|
||||
|
||||
@@ -67,18 +67,18 @@ class AsyncStream():
|
||||
|
||||
# if the server connection closes, we also have to disconnect
|
||||
# the connection to te TSUN cloud
|
||||
if self.remoteStream:
|
||||
if self.remote_stream:
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] disc client '
|
||||
f'connection: [{self.remoteStream.node_id}:'
|
||||
f'{self.remoteStream.conn_no}]')
|
||||
await self.remoteStream.disc()
|
||||
f'connection: [{self.remote_stream.node_id}:'
|
||||
f'{self.remote_stream.conn_no}]')
|
||||
await self.remote_stream.disc()
|
||||
|
||||
async def client_loop(self, addr: str) -> None:
|
||||
async def client_loop(self, _: str) -> None:
|
||||
'''Loop for receiving messages from the TSUN cloud (client-side)'''
|
||||
clientStream = await self.remoteStream.loop()
|
||||
logger.info(f'[{clientStream.node_id}:{clientStream.conn_no}] '
|
||||
client_stream = await self.remote_stream.loop()
|
||||
logger.info(f'[{client_stream.node_id}:{client_stream.conn_no}] '
|
||||
'Client loop stopped for'
|
||||
f' l{clientStream.l_addr}')
|
||||
f' l{client_stream.l_addr}')
|
||||
|
||||
# if the client connection closes, we don't touch the server
|
||||
# connection. Instead we erase the client connection stream,
|
||||
@@ -86,13 +86,13 @@ class AsyncStream():
|
||||
# establish a new connection to the TSUN cloud
|
||||
|
||||
# erase backlink to inverter
|
||||
clientStream.remoteStream = None
|
||||
client_stream.remote_stream = None
|
||||
|
||||
if self.remoteStream == clientStream:
|
||||
# logging.debug(f'Client l{clientStream.l_addr} refs:'
|
||||
# f' {gc.get_referrers(clientStream)}')
|
||||
if self.remote_stream == client_stream:
|
||||
# logging.debug(f'Client l{client_stream.l_addr} refs:'
|
||||
# f' {gc.get_referrers(client_stream)}')
|
||||
# than erase client connection
|
||||
self.remoteStream = None
|
||||
self.remote_stream = None
|
||||
|
||||
async def loop(self) -> Self:
|
||||
"""Async loop handler for precessing all received messages"""
|
||||
@@ -203,35 +203,35 @@ class AsyncStream():
|
||||
if not self._forward_buffer:
|
||||
return
|
||||
try:
|
||||
if not self.remoteStream:
|
||||
if not self.remote_stream:
|
||||
await self.async_create_remote()
|
||||
if self.remoteStream:
|
||||
if self.remoteStream._init_new_client_conn():
|
||||
await self.remoteStream.async_write()
|
||||
if self.remote_stream:
|
||||
if self.remote_stream._init_new_client_conn():
|
||||
await self.remote_stream.async_write()
|
||||
|
||||
if self.remoteStream:
|
||||
self.remoteStream._update_header(self._forward_buffer)
|
||||
if self.remote_stream:
|
||||
self.remote_stream._update_header(self._forward_buffer)
|
||||
hex_dump_memory(logging.INFO,
|
||||
f'Forward to {self.remoteStream.addr}:',
|
||||
f'Forward to {self.remote_stream.addr}:',
|
||||
self._forward_buffer,
|
||||
len(self._forward_buffer))
|
||||
self.remoteStream.writer.write(self._forward_buffer)
|
||||
await self.remoteStream.writer.drain()
|
||||
self.remote_stream.writer.write(self._forward_buffer)
|
||||
await self.remote_stream.writer.drain()
|
||||
self._forward_buffer = bytearray(0)
|
||||
|
||||
except OSError as error:
|
||||
if self.remoteStream:
|
||||
rmt = self.remoteStream
|
||||
self.remoteStream = None
|
||||
if self.remote_stream:
|
||||
rmt = self.remote_stream
|
||||
self.remote_stream = None
|
||||
logger.error(f'[{rmt.node_id}:{rmt.conn_no}] Fwd: {error} for '
|
||||
f'l{rmt.l_addr} | r{rmt.r_addr}')
|
||||
await rmt.disc()
|
||||
rmt.close()
|
||||
|
||||
except RuntimeError as error:
|
||||
if self.remoteStream:
|
||||
rmt = self.remoteStream
|
||||
self.remoteStream = None
|
||||
if self.remote_stream:
|
||||
rmt = self.remote_stream
|
||||
self.remote_stream = None
|
||||
logger.info(f'[{rmt.node_id}:{rmt.conn_no}] '
|
||||
f'Fwd: {error} for {rmt.l_addr}')
|
||||
await rmt.disc()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import logging
|
||||
# import gc
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
from async_stream import AsyncStream
|
||||
from gen3.talent import Talent
|
||||
@@ -15,7 +14,7 @@ class ConnectionG3(AsyncStream, Talent):
|
||||
AsyncStream.__init__(self, reader, writer, addr)
|
||||
Talent.__init__(self, server_side, id_str)
|
||||
|
||||
self.remoteStream: 'ConnectionG3' = remote_stream
|
||||
self.remote_stream: 'ConnectionG3' = remote_stream
|
||||
|
||||
'''
|
||||
Our puplic methods
|
||||
@@ -26,10 +25,10 @@ class ConnectionG3(AsyncStream, Talent):
|
||||
# logger.info(f'AsyncStream refs: {gc.get_referrers(self)}')
|
||||
|
||||
async def async_create_remote(self) -> None:
|
||||
pass
|
||||
pass # virtual interface
|
||||
|
||||
async def async_publ_mqtt(self) -> None:
|
||||
pass
|
||||
pass # virtual interface
|
||||
|
||||
def healthy(self) -> bool:
|
||||
logger.debug('ConnectionG3 healthy()')
|
||||
|
||||
@@ -9,9 +9,7 @@ from gen3.connection_g3 import ConnectionG3
|
||||
from aiomqtt import MqttCodeError
|
||||
from infos import Infos
|
||||
|
||||
# import gc
|
||||
|
||||
# logger = logging.getLogger('conn')
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
|
||||
|
||||
@@ -60,10 +58,10 @@ class InverterG3(Inverter, ConnectionG3):
|
||||
logging.info(f'[{self.node_id}] Connect to {addr}')
|
||||
connect = asyncio.open_connection(host, port)
|
||||
reader, writer = await connect
|
||||
self.remoteStream = ConnectionG3(reader, writer, addr, self,
|
||||
False, self.id_str)
|
||||
logging.info(f'[{self.remoteStream.node_id}:'
|
||||
f'{self.remoteStream.conn_no}] '
|
||||
self.remote_stream = ConnectionG3(reader, writer, addr, self,
|
||||
False, self.id_str)
|
||||
logging.info(f'[{self.remote_stream.node_id}:'
|
||||
f'{self.remote_stream.conn_no}] '
|
||||
f'Connected to {addr}')
|
||||
asyncio.create_task(self.client_loop(addr))
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import struct
|
||||
import logging
|
||||
import time
|
||||
import pytz
|
||||
from datetime import datetime
|
||||
from tzlocal import get_localzone
|
||||
@@ -169,7 +168,6 @@ class Talent(Message):
|
||||
fnc = self.switch.get(self.msg_id, self.msg_unknown)
|
||||
logger.info(self.__flow_str(self.server_side, 'forwrd') +
|
||||
f' Ctl: {int(self.ctrl):#02x} Msg: {fnc.__name__!r}')
|
||||
return
|
||||
|
||||
def send_modbus_cb(self, modbus_pdu: bytearray, log_lvl: int, state: str):
|
||||
if self.state != State.up:
|
||||
@@ -242,12 +240,8 @@ class Talent(Message):
|
||||
def _timestamp(self): # pragma: no cover
|
||||
'''returns timestamp fo the inverter as localtime
|
||||
since 1.1.1970 in msec'''
|
||||
if False:
|
||||
# utc as epoche
|
||||
ts = time.time()
|
||||
else:
|
||||
# convert localtime in epoche
|
||||
ts = (datetime.now() - datetime(1970, 1, 1)).total_seconds()
|
||||
# convert localtime in epoche
|
||||
ts = (datetime.now() - datetime(1970, 1, 1)).total_seconds()
|
||||
return round(ts*1000)
|
||||
|
||||
def _utcfromts(self, ts: float):
|
||||
@@ -297,7 +291,7 @@ class Talent(Message):
|
||||
if (buf_len < 5): # enough bytes to read len and id_len?
|
||||
return
|
||||
result = struct.unpack_from('!lB', buf, 0)
|
||||
len = result[0] # len of complete message
|
||||
msg_len = result[0] # len of complete message
|
||||
id_len = result[1] # len of variable id string
|
||||
|
||||
hdr_len = 5+id_len+2
|
||||
@@ -311,10 +305,9 @@ class Talent(Message):
|
||||
self.id_str = result[0]
|
||||
self.ctrl = Control(result[1])
|
||||
self.msg_id = result[2]
|
||||
self.data_len = len-id_len-3
|
||||
self.data_len = msg_len-id_len-3
|
||||
self.header_len = hdr_len
|
||||
self.header_valid = True
|
||||
return
|
||||
|
||||
def __build_header(self, ctrl, msg_id=None) -> None:
|
||||
if not msg_id:
|
||||
@@ -360,7 +353,6 @@ class Talent(Message):
|
||||
self.await_conn_resp_cnt -= 1
|
||||
else:
|
||||
self.forward()
|
||||
return
|
||||
else:
|
||||
logger.warning('Unknown Ctrl')
|
||||
self.inc_counter('Unknown_Ctrl')
|
||||
@@ -477,7 +469,7 @@ class Talent(Message):
|
||||
if self.ctrl.is_req():
|
||||
self.inc_counter('OTA_Start_Msg')
|
||||
elif self.ctrl.is_ind():
|
||||
pass
|
||||
pass # Ok, nothing to do
|
||||
else:
|
||||
logger.warning('Unknown Ctrl')
|
||||
self.inc_counter('Unknown_Ctrl')
|
||||
@@ -490,27 +482,24 @@ class Talent(Message):
|
||||
result = struct.unpack_from('!lBB', self._recv_buffer,
|
||||
self.header_len)
|
||||
modbus_len = result[1]
|
||||
# logger.debug(f'Ref: {result[0]}')
|
||||
# logger.debug(f'Modbus MsgLen: {modbus_len} Func:{result[2]}')
|
||||
return msg_hdr_len, modbus_len
|
||||
|
||||
def get_modbus_log_lvl(self) -> int:
|
||||
if self.ctrl.is_req():
|
||||
return logging.INFO
|
||||
elif self.ctrl.is_ind():
|
||||
if self.server_side:
|
||||
return self.mb.last_log_lvl
|
||||
elif self.ctrl.is_ind() and self.server_side:
|
||||
return self.mb.last_log_lvl
|
||||
return logging.WARNING
|
||||
|
||||
def msg_modbus(self):
|
||||
hdr_len, modbus_len = self.parse_modbus_header()
|
||||
hdr_len, _ = self.parse_modbus_header()
|
||||
data = self._recv_buffer[self.header_len:
|
||||
self.header_len+self.data_len]
|
||||
|
||||
if self.ctrl.is_req():
|
||||
if self.remoteStream.mb.recv_req(data[hdr_len:],
|
||||
self.remoteStream.
|
||||
msg_forward):
|
||||
if self.remote_stream.mb.recv_req(data[hdr_len:],
|
||||
self.remote_stream.
|
||||
msg_forward):
|
||||
self.inc_counter('Modbus_Command')
|
||||
else:
|
||||
self.inc_counter('Invalid_Msg_Format')
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import logging
|
||||
# import gc
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
from async_stream import AsyncStream
|
||||
from gen3plus.solarman_v5 import SolarmanV5
|
||||
@@ -16,7 +15,7 @@ class ConnectionG3P(AsyncStream, SolarmanV5):
|
||||
AsyncStream.__init__(self, reader, writer, addr)
|
||||
SolarmanV5.__init__(self, server_side, client_mode)
|
||||
|
||||
self.remoteStream: 'ConnectionG3P' = remote_stream
|
||||
self.remote_stream: 'ConnectionG3P' = remote_stream
|
||||
|
||||
'''
|
||||
Our puplic methods
|
||||
@@ -27,10 +26,10 @@ class ConnectionG3P(AsyncStream, SolarmanV5):
|
||||
# logger.info(f'AsyncStream refs: {gc.get_referrers(self)}')
|
||||
|
||||
async def async_create_remote(self) -> None:
|
||||
pass
|
||||
pass # virtual interface
|
||||
|
||||
async def async_publ_mqtt(self) -> None:
|
||||
pass
|
||||
pass # virtual interface
|
||||
|
||||
def healthy(self) -> bool:
|
||||
logger.debug('ConnectionG3P healthy()')
|
||||
|
||||
@@ -9,9 +9,7 @@ from gen3plus.connection_g3p import ConnectionG3P
|
||||
from aiomqtt import MqttCodeError
|
||||
from infos import Infos
|
||||
|
||||
# import gc
|
||||
|
||||
# logger = logging.getLogger('conn')
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
|
||||
|
||||
@@ -62,11 +60,11 @@ class InverterG3P(Inverter, ConnectionG3P):
|
||||
logging.info(f'[{self.node_id}] Connect to {addr}')
|
||||
connect = asyncio.open_connection(host, port)
|
||||
reader, writer = await connect
|
||||
self.remoteStream = ConnectionG3P(reader, writer, addr, self,
|
||||
server_side=False,
|
||||
client_mode=False)
|
||||
logging.info(f'[{self.remoteStream.node_id}:'
|
||||
f'{self.remoteStream.conn_no}] '
|
||||
self.remote_stream = ConnectionG3P(reader, writer, addr, self,
|
||||
server_side=False,
|
||||
client_mode=False)
|
||||
logging.info(f'[{self.remote_stream.node_id}:'
|
||||
f'{self.remote_stream.conn_no}] '
|
||||
f'Connected to {addr}')
|
||||
asyncio.create_task(self.client_loop(addr))
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import struct
|
||||
# import json
|
||||
import logging
|
||||
import time
|
||||
import asyncio
|
||||
@@ -19,7 +18,6 @@ else: # pragma: no cover
|
||||
from my_timer import Timer
|
||||
from gen3plus.infos_g3p import InfosG3P
|
||||
from infos import Register
|
||||
# import traceback
|
||||
|
||||
logger = logging.getLogger('msg')
|
||||
|
||||
@@ -258,7 +256,6 @@ class SolarmanV5(Message):
|
||||
logger.info(self.__flow_str(self.server_side, 'forwrd') +
|
||||
f' Ctl: {int(self.control):#04x}'
|
||||
f' Msg: {fnc.__name__!r}')
|
||||
return
|
||||
|
||||
def _init_new_client_conn(self) -> bool:
|
||||
return False
|
||||
@@ -312,7 +309,6 @@ class SolarmanV5(Message):
|
||||
self._recv_buffer = bytearray()
|
||||
return
|
||||
self.header_valid = True
|
||||
return
|
||||
|
||||
def __trailer_is_ok(self, buf: bytes, buf_len: int) -> bool:
|
||||
crc = buf[self.data_len+11]
|
||||
@@ -436,15 +432,15 @@ class SolarmanV5(Message):
|
||||
return not cmd.startswith(tuple(self.at_acl[connection]['allow'])) or \
|
||||
cmd.startswith(tuple(self.at_acl[connection]['block']))
|
||||
|
||||
async def send_at_cmd(self, AT_cmd: str) -> None:
|
||||
async def send_at_cmd(self, at_cmd: str) -> None:
|
||||
if self.state != State.up:
|
||||
logger.warning(f'[{self.node_id}] ignore AT+ cmd,'
|
||||
' as the state is not UP')
|
||||
return
|
||||
AT_cmd = AT_cmd.strip()
|
||||
at_cmd = at_cmd.strip()
|
||||
|
||||
if self.at_cmd_forbidden(cmd=AT_cmd, connection='mqtt'):
|
||||
data_json = f'\'{AT_cmd}\' is forbidden'
|
||||
if self.at_cmd_forbidden(cmd=at_cmd, connection='mqtt'):
|
||||
data_json = f'\'{at_cmd}\' is forbidden'
|
||||
node_id = self.node_id
|
||||
key = 'at_resp'
|
||||
logger.info(f'{key}: {data_json}')
|
||||
@@ -453,8 +449,8 @@ class SolarmanV5(Message):
|
||||
|
||||
self.forward_at_cmd_resp = False
|
||||
self.__build_header(0x4510)
|
||||
self._send_buffer += struct.pack(f'<BHLLL{len(AT_cmd)}sc', self.AT_CMD,
|
||||
2, 0, 0, 0, AT_cmd.encode('utf-8'),
|
||||
self._send_buffer += struct.pack(f'<BHLLL{len(at_cmd)}sc', self.AT_CMD,
|
||||
2, 0, 0, 0, at_cmd.encode('utf-8'),
|
||||
b'\r')
|
||||
self.__finish_send_msg()
|
||||
try:
|
||||
@@ -467,19 +463,19 @@ class SolarmanV5(Message):
|
||||
|
||||
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})'
|
||||
max_pow = db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
|
||||
rated = db.get_db_value(Register.RATED_POWER, 0)
|
||||
model = None
|
||||
if max_pow == 2000:
|
||||
if rated == 800 or rated == 600:
|
||||
model = f'TSOL-MS{max_pow}({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)
|
||||
model = f'TSOL-MS{max_pow}'
|
||||
elif max_pow == 1800 or max_pow == 1600:
|
||||
model = f'TSOL-MS{max_pow}'
|
||||
if model:
|
||||
logger.info(f'Model: {model}')
|
||||
self.db.set_db_def_value(Register.EQUIPMENT_MODEL, model)
|
||||
|
||||
def __process_data(self, ftype, ts):
|
||||
inv_update = False
|
||||
@@ -564,17 +560,17 @@ class SolarmanV5(Message):
|
||||
result = struct.unpack_from('<B', data, 0)
|
||||
ftype = result[0]
|
||||
if ftype == self.AT_CMD:
|
||||
AT_cmd = data[15:].decode()
|
||||
if self.at_cmd_forbidden(cmd=AT_cmd, connection='tsun'):
|
||||
at_cmd = data[15:].decode()
|
||||
if self.at_cmd_forbidden(cmd=at_cmd, connection='tsun'):
|
||||
self.inc_counter('AT_Command_Blocked')
|
||||
return
|
||||
self.inc_counter('AT_Command')
|
||||
self.forward_at_cmd_resp = True
|
||||
|
||||
elif ftype == self.MB_RTU_CMD:
|
||||
if self.remoteStream.mb.recv_req(data[15:],
|
||||
self.remoteStream.
|
||||
__forward_msg):
|
||||
if self.remote_stream.mb.recv_req(data[15:],
|
||||
self.remote_stream.
|
||||
__forward_msg):
|
||||
self.inc_counter('Modbus_Command')
|
||||
else:
|
||||
logger.error('Invalid Modbus Msg')
|
||||
@@ -593,9 +589,9 @@ class SolarmanV5(Message):
|
||||
if self.forward_at_cmd_resp:
|
||||
return logging.INFO
|
||||
return logging.DEBUG
|
||||
elif ftype == self.MB_RTU_CMD:
|
||||
if self.server_side:
|
||||
return self.mb.last_log_lvl
|
||||
elif ftype == self.MB_RTU_CMD \
|
||||
and self.server_side:
|
||||
return self.mb.last_log_lvl
|
||||
|
||||
return logging.WARNING
|
||||
|
||||
|
||||
@@ -130,16 +130,16 @@ class ClrAtMidnight:
|
||||
return
|
||||
|
||||
prfx += f'{keys[0]}'
|
||||
dict = cls.db
|
||||
if prfx not in dict:
|
||||
dict[prfx] = {}
|
||||
dict = dict[prfx]
|
||||
db_dict = cls.db
|
||||
if prfx not in db_dict:
|
||||
db_dict[prfx] = {}
|
||||
db_dict = db_dict[prfx]
|
||||
|
||||
for key in keys[1:-1]:
|
||||
if key not in dict:
|
||||
dict[key] = {}
|
||||
dict = dict[key]
|
||||
dict[keys[-1]] = 0
|
||||
if key not in db_dict:
|
||||
db_dict[key] = {}
|
||||
db_dict = db_dict[key]
|
||||
db_dict[keys[-1]] = 0
|
||||
|
||||
@classmethod
|
||||
def elm(cls) -> Generator[tuple[str, dict], None, None]:
|
||||
@@ -333,7 +333,7 @@ class Infos:
|
||||
def info_defs(self) -> dict:
|
||||
return self.__info_defs
|
||||
|
||||
def dev_value(self, idx: str | int) -> str | int | float | None:
|
||||
def dev_value(self, idx: str | int) -> str | int | float | dict | None:
|
||||
'''returns the stored device value from our database
|
||||
|
||||
idx:int ==> lookup the value in the database and return it as str,
|
||||
@@ -346,29 +346,29 @@ class Infos:
|
||||
elif idx in self.info_defs:
|
||||
row = self.info_defs[idx]
|
||||
if 'singleton' in row and row['singleton']:
|
||||
dict = self.stat
|
||||
db_dict = self.stat
|
||||
else:
|
||||
dict = self.db
|
||||
db_dict = self.db
|
||||
|
||||
keys = row['name']
|
||||
|
||||
for key in keys:
|
||||
if key not in dict:
|
||||
if key not in db_dict:
|
||||
return None # value not found in the database
|
||||
dict = dict[key]
|
||||
return dict # value of the reqeusted entry
|
||||
db_dict = db_dict[key]
|
||||
return db_dict # value of the reqeusted entry
|
||||
|
||||
return None # unknwon idx, not in info_defs
|
||||
|
||||
def inc_counter(self, counter: str) -> None:
|
||||
'''inc proxy statistic counter'''
|
||||
dict = self.stat['proxy']
|
||||
dict[counter] += 1
|
||||
db_dict = self.stat['proxy']
|
||||
db_dict[counter] += 1
|
||||
|
||||
def dec_counter(self, counter: str) -> None:
|
||||
'''dec proxy statistic counter'''
|
||||
dict = self.stat['proxy']
|
||||
dict[counter] -= 1
|
||||
db_dict = self.stat['proxy']
|
||||
db_dict[counter] -= 1
|
||||
|
||||
def ha_proxy_confs(self, ha_prfx: str, node_id: str, snr: str) \
|
||||
-> Generator[tuple[str, str, str, str], None, None]:
|
||||
@@ -525,9 +525,8 @@ class Infos:
|
||||
return None
|
||||
row = self.info_defs[key]
|
||||
|
||||
if 'singleton' in row:
|
||||
if row['singleton']:
|
||||
return None
|
||||
if 'singleton' in row and row['singleton']:
|
||||
return None
|
||||
|
||||
# check if we have details for home assistant
|
||||
if 'ha' in row:
|
||||
@@ -542,7 +541,7 @@ class Infos:
|
||||
return json.dumps(attr), component, node_id, uniq_id
|
||||
return None
|
||||
|
||||
def _key_obj(self, id: Register) -> list:
|
||||
def _key_obj(self, id: Register) -> tuple:
|
||||
d = self.info_defs.get(id, {'name': None, 'level': logging.DEBUG,
|
||||
'unit': ''})
|
||||
if 'ha' in d and 'must_incr' in d['ha']:
|
||||
@@ -554,21 +553,21 @@ class Infos:
|
||||
|
||||
def update_db(self, keys: list, must_incr: bool, result):
|
||||
name = ''
|
||||
dict = self.db
|
||||
db_dict = self.db
|
||||
for key in keys[:-1]:
|
||||
if key not in dict:
|
||||
dict[key] = {}
|
||||
dict = dict[key]
|
||||
if key not in db_dict:
|
||||
db_dict[key] = {}
|
||||
db_dict = db_dict[key]
|
||||
name += key + '.'
|
||||
if keys[-1] not in dict:
|
||||
if keys[-1] not in db_dict:
|
||||
update = (not must_incr or result > 0)
|
||||
else:
|
||||
if must_incr:
|
||||
update = dict[keys[-1]] < result
|
||||
update = db_dict[keys[-1]] < result
|
||||
else:
|
||||
update = dict[keys[-1]] != result
|
||||
update = db_dict[keys[-1]] != result
|
||||
if update:
|
||||
dict[keys[-1]] = result
|
||||
db_dict[keys[-1]] = result
|
||||
name += keys[-1]
|
||||
return name, update
|
||||
|
||||
@@ -622,13 +621,13 @@ class Infos:
|
||||
return True
|
||||
|
||||
if 'gte' in dep:
|
||||
return not value >= dep['gte']
|
||||
return value < dep['gte']
|
||||
elif 'less_eq' in dep:
|
||||
return not value <= dep['less_eq']
|
||||
return value > dep['less_eq']
|
||||
return True
|
||||
|
||||
def set_pv_module_details(self, inv: dict) -> None:
|
||||
map = {'pv1': {'manufacturer': Register.PV1_MANUFACTURER, 'model': Register.PV1_MODEL}, # noqa: E501
|
||||
pvs = {'pv1': {'manufacturer': Register.PV1_MANUFACTURER, 'model': Register.PV1_MODEL}, # noqa: E501
|
||||
'pv2': {'manufacturer': Register.PV2_MANUFACTURER, 'model': Register.PV2_MODEL}, # noqa: E501
|
||||
'pv3': {'manufacturer': Register.PV3_MANUFACTURER, 'model': Register.PV3_MODEL}, # noqa: E501
|
||||
'pv4': {'manufacturer': Register.PV4_MANUFACTURER, 'model': Register.PV4_MODEL}, # noqa: E501
|
||||
@@ -636,7 +635,7 @@ class Infos:
|
||||
'pv6': {'manufacturer': Register.PV6_MANUFACTURER, 'model': Register.PV6_MODEL} # noqa: E501
|
||||
}
|
||||
|
||||
for key, reg in map.items():
|
||||
for key, reg in pvs.items():
|
||||
if key in inv:
|
||||
if 'manufacturer' in inv[key]:
|
||||
self.set_db_def_value(reg['manufacturer'],
|
||||
|
||||
@@ -103,11 +103,10 @@ class Message(metaclass=IterRegistry):
|
||||
|
||||
def _update_header(self, _forward_buffer):
|
||||
'''callback for updating the header of the forward buffer'''
|
||||
return # pragma: no cover
|
||||
pass # pragma: no cover
|
||||
|
||||
def _set_mqtt_timestamp(self, key, ts: float | None):
|
||||
if type(ts) is not None and \
|
||||
key not in self.new_data or \
|
||||
if key not in self.new_data or \
|
||||
not self.new_data[key]:
|
||||
if key == 'grid':
|
||||
info_id = Register.TS_GRID
|
||||
@@ -128,7 +127,7 @@ class Message(metaclass=IterRegistry):
|
||||
if self.mb:
|
||||
self.mb.close()
|
||||
self.mb = None
|
||||
pass # pragma: no cover
|
||||
# pragma: no cover
|
||||
|
||||
def inc_counter(self, counter: str) -> None:
|
||||
self.db.inc_counter(counter)
|
||||
|
||||
@@ -246,7 +246,7 @@ def test_queue2():
|
||||
assert mb.pdu == b'\x01\x06\x20\x08\x00\x04\x02\x0b'
|
||||
|
||||
for key, update, val in mb.recv_resp(mb.db, b'\x01\x06\x20\x08\x00\x04\x02\x0b', 'test'):
|
||||
pass
|
||||
pass # call generator mb.recv_resp()
|
||||
|
||||
assert mb.que.qsize() == 0
|
||||
assert mb.send_calls == 3
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user