Compare commits

..

19 Commits

Author SHA1 Message Date
Stefan Allius
e629488963 Merge branch 'main' of https://github.com/s-allius/tsun-gen3-proxy into s-allius/issue415 2025-06-12 23:01:31 +02:00
Stefan Allius
ac828921c6 update pytest to version v8.4.0 2025-06-12 22:33:06 +02:00
Stefan Allius
6744e03a90 DCU: Possibility for setting the out power
Fixes #415
2025-06-12 22:27:47 +02:00
Stefan Allius
e78395c269 fix full_topic definition in dispatch test 2025-05-19 00:16:27 +02:00
Stefan Allius
55665c95f8 test dispatcher exceptions 2025-05-18 23:53:12 +02:00
Stefan Allius
51aec15148 undo last change 2025-05-18 23:22:20 +02:00
Stefan Allius
dc9e90d049 increase test coverage 2025-05-18 23:12:08 +02:00
Stefan Allius
b98b133d79 test MQTT error and exception handling 2025-05-18 23:03:09 +02:00
Stefan Allius
2eab7fec3e update changelog 2025-05-18 20:27:40 +02:00
Stefan Allius
fb4fe6b34d cleanup MQTT topic handling 2025-05-18 19:48:16 +02:00
Stefan Allius
bfd7dbe032 test dcu commands from the TSUN cloud 2025-05-18 17:22:33 +02:00
Stefan Allius
25e4714fa5 handle and test DCU Command responses 2025-05-18 16:55:42 +02:00
Stefan Allius
46d1b77e56 test invalid dcu_power values 2025-05-18 16:55:01 +02:00
Stefan Allius
dc360f31d6 remove unneeded exception handling 2025-05-18 16:54:34 +02:00
Stefan Allius
2e9d16b611 add DCU_COMMAND counter 2025-05-18 16:54:11 +02:00
Stefan Allius
1491e42913 add dcu_power MQTT topic 2025-05-18 15:55:46 +02:00
Stefan Allius
07b90da09e add dcu_power MQTT topic and unit tests
Signed-off-by: Stefan Allius <stefan.allius@t-online.de>
2025-05-18 15:35:06 +02:00
Stefan Allius
b2d9da2c09 add dcu_power topic and unit tests 2025-05-18 15:33:17 +02:00
Stefan Allius
cf1a87ed6f DCU: Possibility for setting the out power
Fixes #415
2025-05-18 15:11:35 +02:00
18 changed files with 91 additions and 157 deletions

View File

@@ -1 +1 @@
3.13.5
3.13.4

View File

@@ -7,10 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [unreleased]
- fix some SonarQube warnings
- remove unused 32-bit architectures
- Babel don't build new po file if only the pot creation-date was changed
- Improve Makefile
- Update dependency pytest-asyncio to v1
## [0.14.1] - 2025-05-31
@@ -23,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- set no of pv modules for MS800 GEN3PLUS inverters
- fix the paths to copy the config.example.toml file during proxy start
- add MQTT topic `dcu_power` for setting output power on DCUs
- add MQTT topic `dcu_power` for setting output power on DCUs
- Update ghcr.io/hassio-addons/base Docker tag to v17.2.5
- fix a lot of pytest-asyncio problems in the unit tests
- Cleanup startup code for Quart and the Proxy

View File

@@ -1,37 +1,27 @@
.PHONY: help build babel clean addon-dev addon-debug addon-rc addon-rel debug dev preview rc rel check-docker-compose install
.PHONY: build babel clean addon-dev addon-debug addon-rc addon-rel debug dev preview rc rel check-docker-compose install
help: ## show help message
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[$$()% a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
babel: ## build language files
babel:
$(MAKE) -C app $@
build:
$(MAKE) -C ha_addons $@
clean: ## delete all built files
clean:
$(MAKE) -C app $@
$(MAKE) -C ha_addons $@
debug dev preview rc rel: ## build docker container in <dev|debg|rc|rel> version
debug dev preview rc rel:
$(MAKE) -C app babel
$(MAKE) -C app $@
addon-dev addon-debug addon-rc addon-rel: ## build HA add-on in <dev|debg|rc|rel> version
addon-dev addon-debug addon-rc addon-rel:
$(MAKE) -C app babel
$(MAKE) -C ha_addons $(patsubst addon-%,%,$@)
check-docker-compose: ## check the docker-compose file
check-docker-compose:
docker-compose config -q
PY_VER := $(shell cat .python-version)
install: ## install requirements into the pyenv and switch to proper venv
@pyenv local $(PY_VER) || { pyenv install $(PY_VER) && pyenv local $(PY_VER) || exit 1; }
@pyenv exec pip install --upgrade pip
@pyenv exec pip install -r requirements.txt
@pyenv exec pip install -r requirements-test.txt
pyenv exec python --version
run: ## run proxy locally out of the actual venv
pyenv exec python app/src/server.py -c /app/src/cnf
install:
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
python3 -m pip install -r requirements-test.txt

View File

@@ -55,7 +55,7 @@ $(BABEL_TRANSLATIONS)/%.pot : $(SRC)/.babel.cfg $(BABEL_INPUT)
$(BABEL_TRANSLATIONS)/%/LC_MESSAGES/messages.po : $(BABEL_TRANSLATIONS)/messages.pot
@mkdir -p $(@D)
@pybabel update --init-missing --ignore-pot-creation-date -i $< -d $(BABEL_TRANSLATIONS) -l $*
@pybabel update --init-missing -i $< -d $(BABEL_TRANSLATIONS) -l $*
$(BABEL_TRANSLATIONS)/%/LC_MESSAGES/messages.mo : $(BABEL_TRANSLATIONS)/%/LC_MESSAGES/messages.po
@pybabel compile -d $(BABEL_TRANSLATIONS) -l $*

View File

@@ -53,7 +53,7 @@ target "_common" {
]
no-cache = false
platforms = ["linux/amd64", "linux/arm64"]
platforms = ["linux/amd64", "linux/arm64", "linux/arm/v7"]
}
target "_debug" {

View File

@@ -1,8 +1,8 @@
flake8==7.3.0
pytest==8.4.1
flake8==7.2.0
pytest==8.4.0
pytest-asyncio==1.0.0
pytest-cov==6.2.1
python-dotenv==1.1.0
mock==5.2.0
coverage==7.9.1
coverage==7.9.0
jinja2-cli==0.8.2

View File

@@ -341,9 +341,9 @@ class SolarmanV5(SolarmanBase):
self.log_lvl.clear()
super().close()
def send_start_cmd(self, snr: int, host: str,
forward: bool,
start_timeout=MB_CLIENT_DATA_UP):
async def send_start_cmd(self, snr: int, host: str,
forward: bool,
start_timeout=MB_CLIENT_DATA_UP):
self.no_forwarding = True
self.establish_inv_emu = forward
self.snr = snr

View File

@@ -193,7 +193,7 @@ class Message(ProtocolIfc):
return
self.mb.build_msg(dev_id, func, addr, val, log_lvl)
def send_modbus_cmd(self, func, addr, val, log_lvl) -> None:
async def send_modbus_cmd(self, func, addr, val, log_lvl) -> None:
self._send_modbus_cmd(Modbus.INV_ADDR, func, addr, val, log_lvl)
def _send_modbus_scan(self):

View File

@@ -66,7 +66,7 @@ class ModbusTcp():
try:
async with ModbusConn(host, port) as inverter:
stream = inverter.local.stream
stream.send_start_cmd(snr, host, forward)
await stream.send_start_cmd(snr, host, forward)
await stream.ifc.loop()
logger.info(f'[{stream.node_id}:{stream.conn_no}] '
f'Connection closed - Shutdown: '

View File

@@ -112,7 +112,7 @@ class Mqtt(metaclass=Singleton):
except asyncio.CancelledError:
logger_mqtt.debug("MQTT task cancelled")
self.__client = None
raise
return
except Exception:
# self.inc_counter('SW_Exception') # fixme
self.ctime = None
@@ -151,7 +151,7 @@ class Mqtt(metaclass=Singleton):
if self.__cb_mqtt_is_up:
await self.__cb_mqtt_is_up()
def _out_coeff(self, message):
async def _out_coeff(self, message):
payload = message.payload.decode("UTF-8")
try:
val = round(float(payload) * 1024/100)
@@ -160,9 +160,9 @@ class Mqtt(metaclass=Singleton):
'the range 0..100,'
f' got: {payload}')
else:
self._modbus_cmd(message,
Modbus.WRITE_SINGLE_REG,
0, 0x202c, val)
await self._modbus_cmd(message,
Modbus.WRITE_SINGLE_REG,
0, 0x202c, val)
except Exception:
pass
@@ -182,7 +182,7 @@ class Mqtt(metaclass=Singleton):
else:
logger_mqtt.warning(f'Node_id: {node_id} not found')
def _modbus_cmd(self, message, func, params=0, addr=0, val=0):
async def _modbus_cmd(self, message, func, params=0, addr=0, val=0):
payload = message.payload.decode("UTF-8")
for fnc in self.each_inverter(message, "send_modbus_cmd"):
res = payload.split(',')
@@ -195,7 +195,7 @@ class Mqtt(metaclass=Singleton):
elif params == 2:
addr = int(res[0], base=16)
val = int(res[1]) # lenght
fnc(func, addr, val, logging.INFO)
await fnc(func, addr, val, logging.INFO)
async def _at_cmd(self, message):
payload = message.payload.decode("UTF-8")

View File

@@ -60,7 +60,7 @@ class Server():
@app.context_processor
def utility_processor():
return {'version': self.version}
return dict(version=self.version)
def parse_args(self, arg_list: list[str] | None):
parser = argparse.ArgumentParser()

View File

@@ -29,9 +29,9 @@ def get_tz():
@web.context_processor
def utility_processor():
return {'lang': babel_get_locale(),
'lang_str': LANGUAGES.get(str(babel_get_locale()), "English"),
'languages': LANGUAGES}
return dict(lang=babel_get_locale(),
lang_str=LANGUAGES.get(str(babel_get_locale()), "English"),
languages=LANGUAGES)
@web.route('/language/<language>')

View File

@@ -3,8 +3,7 @@ import pytest
import asyncio
import aiomqtt
import logging
from aiomqtt import MqttError, MessagesIterator
from aiomqtt import Message as AiomqttMessage
from aiomqtt import MqttError
from mock import patch, Mock
from async_stream import AsyncIfcImpl
@@ -35,26 +34,6 @@ def test_hostname():
# else:
return 'test.mosquitto.org'
@pytest.fixture(scope="function")
def aiomqtt_mock(monkeypatch):
recv_que = asyncio.Queue()
async def my_aenter(self):
return self
async def my_subscribe(self, *arg):
return
async def my_anext(self):
return await recv_que.get()
async def my_receive(self, topic: str, payload: bytes):
msg = AiomqttMessage(topic, payload,qos=0, retain=False, mid=0, properties=None)
await recv_que.put(msg)
await asyncio.sleep(0) # dispath the msg
monkeypatch.setattr(aiomqtt.Client, "__aenter__", my_aenter)
monkeypatch.setattr(aiomqtt.Client, "subscribe", my_subscribe)
monkeypatch.setattr(MessagesIterator, "__anext__", my_anext)
monkeypatch.setattr(Mqtt, "receive", my_receive, False)
@pytest.fixture
def config_mqtt_conn(test_hostname, test_port):
Config.act_config = {'mqtt':{'host': test_hostname, 'port': test_port, 'user': '', 'passwd': ''},
@@ -182,17 +161,13 @@ async def test_ha_reconnect(config_mqtt_conn):
await m.close()
@pytest.mark.asyncio
async def test_mqtt_no_config(config_no_conn, monkeypatch):
async def test_mqtt_no_config(config_no_conn):
_ = config_no_conn
assert asyncio.get_running_loop()
on_connect = asyncio.Event()
async def cb():
on_connect.set()
async def my_publish(*args):
return
monkeypatch.setattr(aiomqtt.Client, "publish", my_publish)
try:
m = Mqtt(cb)
@@ -201,9 +176,9 @@ async def test_mqtt_no_config(config_no_conn, monkeypatch):
assert not on_connect.is_set()
try:
await m.publish('homeassistant/status', 'online')
assert m.published == 1
assert False
except Exception:
assert False
pass
except TimeoutError:
assert False
finally:
@@ -275,119 +250,92 @@ async def test_mqtt_except_def_config(config_def_conn, monkeypatch, caplog):
assert 'MQTT is unconfigured; Check your config.toml!' in caplog.text
@pytest.mark.asyncio
async def test_mqtt_dispatch(config_mqtt_conn, aiomqtt_mock, spy_modbus_cmd):
async def test_msg_dispatch(config_mqtt_conn, spy_modbus_cmd):
_ = config_mqtt_conn
_ = aiomqtt_mock
spy = spy_modbus_cmd
try:
m = Mqtt(None)
assert m.ha_restarts == 0
await m.receive('homeassistant/status', b'online') # send the message
msg = aiomqtt.Message(topic= 'homeassistant/status', payload= b'online', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
assert m.ha_restarts == 1
await m.receive(topic= 'tsun/inv_1/rated_load', payload= b'2')
spy.assert_called_once_with(Modbus.WRITE_SINGLE_REG, 0x2008, 2, logging.INFO)
spy.reset_mock()
await m.receive(topic= 'tsun/inv_1/out_coeff', payload= b'100')
spy.assert_called_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 1024, logging.INFO)
msg = aiomqtt.Message(topic= 'tsun/inv_1/rated_load', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_awaited_once_with(Modbus.WRITE_SINGLE_REG, 0x2008, 2, logging.INFO)
spy.reset_mock()
await m.receive(topic= 'tsun/inv_1/out_coeff', payload= b'50')
spy.assert_called_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 512, logging.INFO)
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'100', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_awaited_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 1024, logging.INFO)
spy.reset_mock()
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'50', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_awaited_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 512, logging.INFO)
spy.reset_mock()
await m.receive(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10')
spy.assert_called_once_with(Modbus.READ_REGS, 0x3000, 10, logging.INFO)
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_awaited_once_with(Modbus.READ_REGS, 0x3000, 10, logging.INFO)
spy.reset_mock()
await m.receive(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10')
spy.assert_called_once_with(Modbus.READ_INPUTS, 0x3000, 10, logging.INFO)
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_awaited_once_with(Modbus.READ_INPUTS, 0x3000, 10, logging.INFO)
# test dispatching with empty mapping table
m.topic_defs.clear()
spy.reset_mock()
await m.receive(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10')
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_not_called()
# test dispatching with incomplete mapping table - invalid fnc defined
m.topic_defs.append(
{'prefix': 'entity_prefix', 'topic': '/+/modbus_read_inputs',
'full_topic': 'tsun/+/modbus_read_inputs', 'fnc': 'addr'}
'full_topic': 'tsun/+/modbus_read_inputs', 'fnc': 'invalid'}
)
spy.reset_mock()
await m.receive(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10')
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_not_called()
except MqttError:
assert False
except Exception:
assert False
finally:
await m.close()
@pytest.mark.asyncio
async def test_mqtt_dispatch_cb(config_mqtt_conn, aiomqtt_mock):
async def test_msg_dispatch_err(config_mqtt_conn, spy_modbus_cmd):
_ = config_mqtt_conn
_ = aiomqtt_mock
on_connect = asyncio.Event()
async def cb():
on_connect.set()
try:
m = Mqtt(cb)
assert m.ha_restarts == 0
await m.receive('homeassistant/status', b'online') # send the message
assert on_connect.is_set()
assert m.ha_restarts == 1
except MqttError:
assert False
except Exception:
assert False
finally:
await m.close()
@pytest.mark.asyncio
async def test_mqtt_dispatch_err(config_mqtt_conn, aiomqtt_mock, spy_modbus_cmd, caplog):
_ = config_mqtt_conn
_ = aiomqtt_mock
spy = spy_modbus_cmd
LOGGER = logging.getLogger("mqtt")
LOGGER.propagate = True
LOGGER.setLevel(logging.INFO)
try:
m = Mqtt(None)
# test out of range param
await m.receive(topic= 'tsun/inv_1/out_coeff', payload= b'-1')
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'-1', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_not_called()
# test unknown node_id
await m.receive(topic= 'tsun/inv_2/out_coeff', payload= b'2')
spy.reset_mock()
msg = aiomqtt.Message(topic= 'tsun/inv_2/out_coeff', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_not_called()
# test invalid fload param
await m.receive(topic= 'tsun/inv_1/out_coeff', payload= b'2, 3')
spy.assert_not_called()
await m.receive(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10, 7')
spy.reset_mock()
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'2, 3', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_not_called()
await m.receive(topic= 'tsun/inv_1/dcu_power', payload= b'100W')
spy.reset_mock()
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10, 7', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_not_called()
spy.reset_mock()
msg = aiomqtt.Message(topic= 'tsun/inv_1/dcu_power', payload= b'100W', qos= 0, retain = False, mid= 0, properties= None)
await m.dispatch_msg(msg)
spy.assert_not_called()
with caplog.at_level(logging.INFO):
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
for _ in m.each_inverter(msg, "addr"):
pass # do nothing here
assert 'Cmd not supported by: inv_1/' in caplog.text
except MqttError:
assert False
except Exception:
assert False
finally:
await m.close()

View File

@@ -1624,7 +1624,7 @@ async def test_msg_build_modbus_req(my_loop, config_tsun_inv1, device_ind_msg, d
assert m.ifc.tx_fifo.get()==device_rsp_msg
assert m.ifc.fwd_fifo.get()==device_ind_msg
m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
assert 0 == m.send_msg_ofs
assert m.ifc.fwd_fifo.get() == b''
assert m.sent_pdu == b'' # modbus command must be ignore, cause connection is still not up
@@ -1642,7 +1642,7 @@ async def test_msg_build_modbus_req(my_loop, config_tsun_inv1, device_ind_msg, d
assert m.ifc.tx_fifo.get()==inverter_rsp_msg
assert m.ifc.fwd_fifo.get()==inverter_ind_msg
m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
assert 0 == m.send_msg_ofs
assert m.ifc.fwd_fifo.get() == b''
assert m.sent_pdu == msg_modbus_cmd
@@ -2318,7 +2318,7 @@ async def test_start_client_mode(my_loop, config_tsun_inv1, str_test_ip):
assert m.no_forwarding == False
assert m.mb_timer.tim == None
assert asyncio.get_running_loop() == m.mb_timer.loop
m.send_start_cmd(get_sn_int(), str_test_ip, False, m.mb_first_timeout)
await m.send_start_cmd(get_sn_int(), str_test_ip, False, m.mb_first_timeout)
assert m.sent_pdu==bytearray(b'\xa5\x17\x00\x10E\x01\x00!Ce{\x02\xb0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x030\x00\x000J\xde\xf1\x15')
assert m.db.get_db_value(Register.IP_ADDRESS) == str_test_ip
assert isclose(m.db.get_db_value(Register.POLLING_INTERVAL), 0.5)
@@ -2351,7 +2351,7 @@ async def test_start_client_mode_scan(config_tsun_scan_dcu, str_test_ip, dcu_mod
assert m.no_forwarding == False
assert m.mb_timer.tim == None
assert asyncio.get_running_loop() == m.mb_timer.loop
m.send_start_cmd(get_dcu_sn_int(), str_test_ip, False, m.mb_first_timeout)
await m.send_start_cmd(get_dcu_sn_int(), str_test_ip, False, m.mb_first_timeout)
assert m.mb_start_reg == 0x0000
assert m.mb_step == 0x100
assert m.mb_bytes == 0x2d
@@ -2662,7 +2662,6 @@ async def test_proxy_dcu_cmd(my_loop, config_tsun_dcu1, patch_open_connection, d
assert l.db.stat['proxy']['AT_Command'] == 0
assert l.db.stat['proxy']['AT_Command_Blocked'] == 0
assert l.db.stat['proxy']['Modbus_Command'] == 0
assert 2 == l.db.get_db_value(Register.NO_INPUTS, 0)
l.append_msg(dcu_command_rsp_msg)
l.read() # read at resp

View File

@@ -144,7 +144,7 @@ async def test_emu_start(my_loop, config_tsun_inv1, msg_modbus_rsp, str_test_ip,
inv = InvStream(msg_modbus_rsp)
assert asyncio.get_running_loop() == inv.mb_timer.loop
inv.send_start_cmd(get_sn_int(), str_test_ip, True, inv.mb_first_timeout)
await inv.send_start_cmd(get_sn_int(), str_test_ip, True, inv.mb_first_timeout)
inv.read() # read complete msg, and dispatch msg
assert not inv.header_valid # must be invalid, since msg was handled and buffer flushed
assert inv.msg_count == 1
@@ -161,7 +161,7 @@ async def test_snd_hb(my_loop, config_tsun_inv1, heartbeat_ind):
inv = InvStream()
cld = CldStream(inv)
# inv.send_start_cmd(get_sn_int(), str_test_ip, False, inv.mb_first_timeout)
# await inv.send_start_cmd(get_sn_int(), str_test_ip, False, inv.mb_first_timeout)
cld.send_heartbeat_cb(0)
assert cld.ifc.tx_fifo.peek() == heartbeat_ind
cld.close()
@@ -178,7 +178,7 @@ async def test_snd_inv_data(my_loop, config_tsun_inv1, inverter_ind_msg, inverte
inv.db.set_db_def_value(Register.GRID_FREQUENCY, 50.05)
inv.db.set_db_def_value(Register.PROD_COMPL_TYPE, 6)
assert asyncio.get_running_loop() == inv.mb_timer.loop
inv.send_start_cmd(get_sn_int(), str_test_ip, False, inv.mb_first_timeout)
await inv.send_start_cmd(get_sn_int(), str_test_ip, False, inv.mb_first_timeout)
inv.db.set_db_def_value(Register.DATA_UP_INTERVAL, 17) # set test value
cld = CldStream(inv)
@@ -213,7 +213,7 @@ async def test_rcv_invalid(my_loop, config_tsun_inv1, inverter_ind_msg, inverter
_ = config_tsun_inv1
inv = InvStream()
assert asyncio.get_running_loop() == inv.mb_timer.loop
inv.send_start_cmd(get_sn_int(), str_test_ip, False, inv.mb_first_timeout)
await inv.send_start_cmd(get_sn_int(), str_test_ip, False, inv.mb_first_timeout)
inv.db.set_db_def_value(Register.DATA_UP_INTERVAL, 17) # set test value
cld = CldStream(inv)

View File

@@ -2411,14 +2411,14 @@ async def test_msg_build_modbus_req(config_tsun_inv1, msg_modbus_cmd):
_ = config_tsun_inv1
m = MemoryStream(b'', (0,), True)
m.id_str = b"R170000000000001"
m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
assert 0 == m.send_msg_ofs
assert m.ifc.fwd_fifo.get() == b''
assert m.ifc.tx_fifo.get() == b''
assert m.sent_pdu == b''
m.state = State.up
m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
assert 0 == m.send_msg_ofs
assert m.ifc.fwd_fifo.get() == b''
assert m.ifc.tx_fifo.get() == b''

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: tsun-gen3-proxy 0.14.0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2025-05-13 22:34+0200\n"
"POT-Creation-Date: 2025-05-18 15:30+0200\n"
"PO-Revision-Date: 2025-04-18 16:24+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: de\n"

View File

@@ -59,7 +59,7 @@ target "_common" {
]
no-cache = false
platforms = ["linux/amd64", "linux/arm64"]
platforms = ["linux/amd64", "linux/arm64", "linux/arm/v7"]
}
target "_debug" {