SolarManager unter Versionsverwaltung
Erster Stand der Hintergrundprozesse, die auf der Synology unter /volume1/homes/wagner/SolarManager laufen: der Manager selbst, die Sammler je Geraet, die MQTT-Bruecke, der Wecker und - neu hinzugezogen - der AutoAction-Runner, der als Hintergrundprozess hierher gehoert und nicht ins Web-Verzeichnis. Zugangsdaten stehen nicht mehr im Quelltext, sondern in config.ini, die nicht mit eingecheckt wird. Vorlage ist config.ini.example, gelesen wird sie von konfig.py. Betroffen waren solarManager.py (Datenbank und Wattpilot), zeit.py, gatherWaterData.py, wecker.py und skoda_testdaten.py, das sich das Passwort bisher aus dem Quelltext eines anderen Moduls herausgesucht hat. Die Kia-Anbindung ist mit dem Fahrzeug entfallen: kiaTest.py, gatherCarData.py und hyundai_kia_connect_api sind nicht mehr dabei, ebenso gatherInverterData.py, auf das nur noch eine auskommentierte Zeile zeigte. Die mitgelieferten Bibliotheken bleiben im Repository - die NAS hat kein pip, sie muessen neben den Skripten liegen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
import sunspec2.modbus.modbus as modbus_client
|
||||
import pytest
|
||||
import socket
|
||||
import serial
|
||||
import sunspec2.tests.mock_socket as MockSocket
|
||||
import sunspec2.tests.mock_port as MockPort
|
||||
|
||||
|
||||
def test_modbus_rtu_client(monkeypatch):
|
||||
monkeypatch.setattr(serial, 'Serial', MockPort.mock_port)
|
||||
c = modbus_client.modbus_rtu_client('COMM2')
|
||||
assert c.baudrate == 9600
|
||||
assert c.parity == "N"
|
||||
assert modbus_client.modbus_rtu_clients['COMM2']
|
||||
|
||||
with pytest.raises(modbus_client.ModbusClientError) as exc1:
|
||||
c2 = modbus_client.modbus_rtu_client('COMM2', baudrate=99)
|
||||
assert 'Modbus client baudrate mismatch' in str(exc1.value)
|
||||
|
||||
with pytest.raises(modbus_client.ModbusClientError) as exc2:
|
||||
c2 = modbus_client.modbus_rtu_client('COMM2', parity='E')
|
||||
assert 'Modbus client parity mismatch' in str(exc2.value)
|
||||
|
||||
|
||||
def test_modbus_rtu_client_remove(monkeypatch):
|
||||
monkeypatch.setattr(serial, 'Serial', MockPort.mock_port)
|
||||
c = modbus_client.modbus_rtu_client('COMM2')
|
||||
assert modbus_client.modbus_rtu_clients['COMM2']
|
||||
modbus_client.modbus_rtu_client_remove('COMM2')
|
||||
assert modbus_client.modbus_rtu_clients.get('COMM2') is None
|
||||
|
||||
|
||||
def test___generate_crc16_table():
|
||||
pass
|
||||
|
||||
|
||||
def test_computeCRC():
|
||||
pass
|
||||
|
||||
|
||||
def test_checkCRC():
|
||||
pass
|
||||
|
||||
|
||||
class TestModbusClientRTU:
|
||||
def test___init__(self, monkeypatch):
|
||||
monkeypatch.setattr(serial, 'Serial', MockPort.mock_port)
|
||||
c = modbus_client.ModbusClientRTU(name="COM2")
|
||||
assert c.name == "COM2"
|
||||
assert c.baudrate == 9600
|
||||
assert c.parity is None
|
||||
assert c.serial is not None
|
||||
assert c.timeout == .5
|
||||
assert c.write_timeout == .5
|
||||
assert not c.devices
|
||||
|
||||
def test_open(self, monkeypatch):
|
||||
monkeypatch.setattr(serial, 'Serial', MockPort.mock_port)
|
||||
c = modbus_client.ModbusClientRTU(name="COM2")
|
||||
c.open()
|
||||
assert c.serial.connected
|
||||
|
||||
def test_close(self, monkeypatch):
|
||||
monkeypatch.setattr(serial, 'Serial', MockPort.mock_port)
|
||||
c = modbus_client.ModbusClientRTU(name="COM2")
|
||||
c.open()
|
||||
c.close()
|
||||
assert not c.serial.connected
|
||||
|
||||
def test_add_device(self, monkeypatch):
|
||||
monkeypatch.setattr(serial, 'Serial', MockPort.mock_port)
|
||||
c = modbus_client.ModbusClientRTU(name="COM2")
|
||||
c.add_device(1, "1")
|
||||
assert c.devices.get(1) is not None
|
||||
assert c.devices[1] == "1"
|
||||
|
||||
def test_remove_device(self, monkeypatch):
|
||||
monkeypatch.setattr(serial, 'Serial', MockPort.mock_port)
|
||||
c = modbus_client.ModbusClientRTU(name="COM2")
|
||||
c.add_device(1, "1")
|
||||
assert c.devices.get(1) is not None
|
||||
assert c.devices[1] == "1"
|
||||
c.remove_device(1)
|
||||
assert c.devices.get(1) is None
|
||||
|
||||
def test__read(self):
|
||||
pass
|
||||
|
||||
def test_read(self, monkeypatch):
|
||||
monkeypatch.setattr(serial, 'Serial', MockPort.mock_port)
|
||||
c = modbus_client.ModbusClientRTU(name="COM2")
|
||||
in_buff = [b'\x01\x03\x8cSu', b'nS\x00\x01\x00BSunSpecTest\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00TestDevice-1\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00opt_a_b_c\x00'
|
||||
b'\x00\x00\x00\x00\x00\x001.2.3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'sn-123456789\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x01\x00\x00\xb7d']
|
||||
check_req = b'\x01\x03\x9c@\x00F\xeb\xbc'
|
||||
c.open()
|
||||
c.serial._set_buffer(in_buff)
|
||||
|
||||
check_read = in_buff[0] + in_buff[1]
|
||||
assert c.read(1, 40000, 70) == check_read[3:-2]
|
||||
assert c.serial.request[0] == check_req
|
||||
|
||||
def test__write(self):
|
||||
pass
|
||||
|
||||
def test_write(self, monkeypatch):
|
||||
monkeypatch.setattr(serial, 'Serial', MockPort.mock_port)
|
||||
c = modbus_client.ModbusClientRTU(name="COM2")
|
||||
c.open()
|
||||
data_to_write = b'v0.0.0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00sn-000\x00\x00\x00\x00\x00\x00\x00' \
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
|
||||
buffer = [b'\x01\x10\x9cl\x00', b'\x18.N']
|
||||
c.serial._set_buffer(buffer)
|
||||
c.write(1, 40044, data_to_write)
|
||||
|
||||
check_req = b'\x01\x10\x9cl\x00\x180v0.0.0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00sn-000\x00' \
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
|
||||
b'\x00\x00\x00\x00\x00\xad\xff'
|
||||
assert c.serial.request[0] == check_req
|
||||
|
||||
|
||||
class TestModbusClientTCP:
|
||||
def test___init__(self):
|
||||
c = modbus_client.ModbusClientTCP()
|
||||
assert c.slave_id == 1
|
||||
assert c.ipaddr == '127.0.0.1'
|
||||
assert c.ipport == 502
|
||||
assert c.timeout == 2
|
||||
assert c.ctx is None
|
||||
assert c.trace_func is None
|
||||
assert c.max_count == 125
|
||||
|
||||
def test_close(self, monkeypatch):
|
||||
monkeypatch.setattr(socket, 'socket', MockSocket.mock_socket)
|
||||
|
||||
c = modbus_client.ModbusClientTCP()
|
||||
c.connect()
|
||||
assert c.socket
|
||||
c.disconnect()
|
||||
assert c.socket is None
|
||||
|
||||
def test_connect(self, monkeypatch):
|
||||
c = modbus_client.ModbusClientTCP()
|
||||
|
||||
with pytest.raises(Exception) as exc:
|
||||
c.connect()
|
||||
assert 'Connection error' in str(exc.value)
|
||||
|
||||
monkeypatch.setattr(socket, 'socket', MockSocket.mock_socket)
|
||||
c.connect()
|
||||
assert c.socket is not None
|
||||
assert c.socket.connected is True
|
||||
assert c.socket.ipaddr == '127.0.0.1'
|
||||
assert c.socket.ipport == 502
|
||||
assert c.socket.timeout == 2
|
||||
|
||||
def test_disconnect(self, monkeypatch):
|
||||
monkeypatch.setattr(socket, 'socket', MockSocket.mock_socket)
|
||||
|
||||
c = modbus_client.ModbusClientTCP()
|
||||
c.connect()
|
||||
assert c.socket
|
||||
c.disconnect()
|
||||
assert c.socket is None
|
||||
|
||||
def test__read(self, monkeypatch):
|
||||
pass
|
||||
|
||||
def test_read(self, monkeypatch):
|
||||
c = modbus_client.ModbusClientTCP()
|
||||
monkeypatch.setattr(socket, 'socket', MockSocket.mock_socket)
|
||||
in_buff = [b'\x00\x00\x00\x00\x00\x8f\x01\x03\x8c', b'SunS\x00\x01\x00BSunSpecTest\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00TestDevice-1\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00opt_a_b_c'
|
||||
b'\x00\x00\x00\x00\x00\x00\x001.2.3\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00sn-123456789\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x01\x00\x00']
|
||||
check_req = b'\x00\x00\x00\x00\x00\x06\x01\x03\x9c@\x00F'
|
||||
c.connect()
|
||||
c.socket._set_buffer(in_buff)
|
||||
assert c.read(40000, 70) == in_buff[1]
|
||||
assert c.socket.request[0] == check_req
|
||||
|
||||
def test__write(self, monkeypatch):
|
||||
pass
|
||||
|
||||
def test_write(self, monkeypatch):
|
||||
c = modbus_client.ModbusClientTCP()
|
||||
monkeypatch.setattr(socket, 'socket', MockSocket.mock_socket)
|
||||
c.connect()
|
||||
data_to_write = b'sn-000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
|
||||
buffer = [b'\x00\x00\x00\x00\x00\x06\x01\x10\x9c', b't\x00\x10']
|
||||
c.socket._set_buffer(buffer)
|
||||
c.write(40052, data_to_write)
|
||||
|
||||
check_req = b"\x00\x00\x00\x00\x00'\x01\x10\x9ct\x00\x10 sn-000\x00\x00\x00\x00\x00\x00\x00" \
|
||||
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
assert c.socket.request[0] == check_req
|
||||
|
||||
def test_write_over_max_size(self, monkeypatch):
|
||||
c = modbus_client.ModbusClientTCP()
|
||||
monkeypatch.setattr(socket, 'socket', MockSocket.mock_socket)
|
||||
c.connect()
|
||||
data_to_write = bytearray((c.max_write_count+1)*2)
|
||||
data_to_write[:6] = b'sn-000'
|
||||
|
||||
buffer = [b'\x00\x00\x00\x00\x00\x06\x01\x10\x9ct\x00\x7b',
|
||||
b'\x00\x00\x00\x00\x00\x06\x01\x10\x9c\xef\x00\x01']
|
||||
c.socket._set_buffer(buffer)
|
||||
c.write(40052, data_to_write)
|
||||
|
||||
check_req0 = b"\x00\x00\x00\x00\x00\xfd\x01" + b"\x10\x9ct\x00{\xf6" + data_to_write[:(c.max_write_count*2)]
|
||||
check_req1 = b"\x00\x00\x00\x00\x00\x09\x01" + b"\x10\x9c\xef\x00\x01\x02\x00\x00"
|
||||
assert c.socket.request[0] == check_req0
|
||||
assert c.socket.request[1] == check_req1
|
||||
Reference in New Issue
Block a user