Compare commits
2 Commits
master
...
lüftungsan
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f19cc518b | ||
|
|
7b00d622aa |
BIN
modbus_registers/_modbus_register_template.xlsx
Normal file
BIN
modbus_registers/_modbus_register_template.xlsx
Normal file
Binary file not shown.
BIN
modbus_registers/ventilation_modbus_registers.xlsx
Normal file
BIN
modbus_registers/ventilation_modbus_registers.xlsx
Normal file
Binary file not shown.
69
test.py
Normal file
69
test.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import time
|
||||
import struct
|
||||
from pymodbus.client import ModbusTcpClient
|
||||
|
||||
MODBUS_IP = "10.0.0.40"
|
||||
SLAVE_ID = 1
|
||||
POLL = 2.0 # Sekunden
|
||||
|
||||
def u16_to_i16(u16):
|
||||
return struct.unpack(">h", struct.pack(">H", u16 & 0xFFFF))[0]
|
||||
|
||||
def read_i16(client, addr, scale):
|
||||
rr = client.read_input_registers(address=addr, count=1, slave=SLAVE_ID)
|
||||
if rr.isError():
|
||||
return None
|
||||
raw = rr.registers[0]
|
||||
if raw == 65535:
|
||||
return None
|
||||
return round(u16_to_i16(raw) / scale, 1)
|
||||
|
||||
def fmt(v):
|
||||
return f"{v:5.1f}" if v is not None else " ---"
|
||||
|
||||
client = ModbusTcpClient(MODBUS_IP, port=502)
|
||||
|
||||
try:
|
||||
if not client.connect():
|
||||
raise RuntimeError("Modbus connect failed")
|
||||
|
||||
print("Logging temperatures (Ctrl+C to stop)\n")
|
||||
|
||||
while True:
|
||||
# Eintrittsluft = Mittelwert aus 3x0324 & 3x0323 (scale 100)
|
||||
t_e1 = read_i16(client, 324, 100)
|
||||
t_e2 = read_i16(client, 323, 100)
|
||||
t_ein = None
|
||||
if t_e1 is not None and t_e2 is not None:
|
||||
t_ein = round((t_e1 + t_e2) / 2, 1)
|
||||
|
||||
# Zuluft -> 3x0614 (/10)
|
||||
t_zuluft = read_i16(client, 614, 10)
|
||||
|
||||
# Abluft -> Mittelwert aus 3x0581 & 3x0582 (/10)
|
||||
t_a1 = read_i16(client, 581, 10)
|
||||
t_a2 = read_i16(client, 582, 10)
|
||||
t_abluft = None
|
||||
if t_a1 is not None and t_a2 is not None:
|
||||
t_abluft = round((t_a1 + t_a2) / 2, 1)
|
||||
|
||||
# Fortluft -> 3x0301 (/100)
|
||||
t_fortluft = read_i16(client, 301, 100)
|
||||
|
||||
ts = time.strftime("%H:%M:%S")
|
||||
|
||||
print(
|
||||
f"{ts} | "
|
||||
f"Eintritt: {fmt(t_ein)} °C | "
|
||||
f"Zuluft: {fmt(t_zuluft)} °C | "
|
||||
f"Abluft: {fmt(t_abluft)} °C | "
|
||||
f"Fortluft: {fmt(t_fortluft)} °C"
|
||||
)
|
||||
|
||||
time.sleep(POLL)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nStopped by user.")
|
||||
|
||||
finally:
|
||||
client.close()
|
||||
57
test_knx.py
Normal file
57
test_knx.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
from xknx import XKNX
|
||||
from xknx.io import ConnectionConfig, ConnectionType
|
||||
from xknx.devices import Sensor
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
GA_TEMP = "0/0/8" # Außentemperatur
|
||||
POLL_SECONDS = 60 # Abfrageintervall
|
||||
TIMEOUT_SECONDS = 10 # Antwort-Timeout pro Read
|
||||
|
||||
async def main():
|
||||
connection_config = ConnectionConfig(
|
||||
connection_type=ConnectionType.TUNNELING,
|
||||
gateway_ip="10.0.0.111",
|
||||
gateway_port=3671,
|
||||
local_ip="192.168.1.88",
|
||||
route_back=True,
|
||||
# Optional: festen UDP-Quellport setzen, falls NAT instabil wird
|
||||
# local_port=50055,
|
||||
)
|
||||
|
||||
async with XKNX(connection_config=connection_config, daemon_mode=True) as xknx:
|
||||
temp = Sensor(
|
||||
xknx=xknx,
|
||||
name="Aussentemperatur",
|
||||
group_address_state=GA_TEMP,
|
||||
value_type="temperature",
|
||||
sync_state=True,
|
||||
)
|
||||
xknx.devices.async_add(temp)
|
||||
|
||||
while True:
|
||||
logging.info("Sende GroupValueRead an %s ...", GA_TEMP)
|
||||
try:
|
||||
try:
|
||||
await temp.sync(wait_for_result=True, timeout=TIMEOUT_SECONDS)
|
||||
except TypeError:
|
||||
await asyncio.wait_for(temp.sync(wait_for_result=True), timeout=TIMEOUT_SECONDS)
|
||||
|
||||
value = temp.resolve_state()
|
||||
ts = datetime.now().isoformat(timespec="seconds")
|
||||
if value is None:
|
||||
logging.warning("%s Aussentemperatur: None (keine verwertbare Antwort)", ts)
|
||||
else:
|
||||
logging.info("%s Aussentemperatur: %.2f °C", ts, value)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
logging.warning("Timeout nach %ss: keine Antwort", TIMEOUT_SECONDS)
|
||||
|
||||
await asyncio.sleep(POLL_SECONDS)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user