Compare commits
No commits in common. "3ed80f4b687f95d20a88b86efee5b7a71a6105f7" and "451008b895a7d359f37f85b14c32415613b14e87" have entirely different histories.
3ed80f4b68
...
451008b895
5
.vscode/cargo-build-version.sh
vendored
5
.vscode/cargo-build-version.sh
vendored
@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Patch Cargo.toml version from VERSION file before build
|
|
||||||
VERSION=$(cat VERSION)
|
|
||||||
sed -i "s/^version = ".*"/version = \"$VERSION\"/" Cargo.toml
|
|
||||||
exec cargo build
|
|
||||||
2
.vscode/tasks.json
vendored
2
.vscode/tasks.json
vendored
@ -4,7 +4,7 @@
|
|||||||
{
|
{
|
||||||
"label": "cargo build",
|
"label": "cargo build",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": ".vscode/cargo-build-version.sh",
|
"command": "cargo build",
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
|
|||||||
140
old/paramod.conf
Normal file
140
old/paramod.conf
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
[default]
|
||||||
|
loglevel = "DEBUG"
|
||||||
|
|
||||||
|
[mqtt]
|
||||||
|
broker = "192.168.178.2"
|
||||||
|
button_circulation = "zigbee2mqtt/WirelessButton"
|
||||||
|
password = "97sm3pHNSMZ4M5qUj0x8"
|
||||||
|
port = 1883
|
||||||
|
user = "admin"
|
||||||
|
|
||||||
|
[influxdb]
|
||||||
|
bucket = "Paradigma"
|
||||||
|
location = "Radebeul"
|
||||||
|
measurement = "ParadigmaModbus"
|
||||||
|
org = "skaville"
|
||||||
|
token = "i-sXFQbEkSC1XVzqFEaFwXwzasbsEIciVlK4SaAUOEvk0VjQPkD3fr8d7_3SPeyseTZkqj7ZMZU78b3n2F6_SQ=="
|
||||||
|
url = "192.168.178.2:8086"
|
||||||
|
|
||||||
|
[modbus]
|
||||||
|
host = "192.168.178.10"
|
||||||
|
max_coils_addr = 8
|
||||||
|
max_holding_addr = 61
|
||||||
|
max_input_addr = 45
|
||||||
|
port = 502
|
||||||
|
|
||||||
|
[[modbus_coils]]
|
||||||
|
MgtSystem = {addr = 0, write = false, mqtt = false, influxdb = false, comment = "Leitsystem aktiv"}
|
||||||
|
HK1pres = {addr = 1, write = false, mqtt = false, influxdb = false, comment = "HK1 vorhanden"}
|
||||||
|
HK2pres = {addr = 2, write = false, mqtt = false, influxdb = false, comment = "HK2 vorhanden"}
|
||||||
|
HK3pres = {addr = 3, write = false, mqtt = false, influxdb = false, comment = "HK3 vorhanden"}
|
||||||
|
TWrelease = {addr = 4, write = true, mqtt = false, influxdb = false, comment = "Trinkwassererwärmung freigegeben"}
|
||||||
|
TWlock = {addr = 5, write = true, mqtt = false, influxdb = false, comment = "Trinkwassererwärmung gesprerrt"}
|
||||||
|
Zrelease = {addr = 6, write = true, mqtt = false, influxdb = false, comment = "Zirkulation freigegeben"}
|
||||||
|
Zlock = {addr = 7, write = true, mqtt = false, influxdb = false, comment = "Zirkulation gesperrt"}
|
||||||
|
SHKpres = {addr = 8, write = false, mqtt = false, influxdb = false, comment = "Schwimmbadheizkrei vorhanden"}
|
||||||
|
|
||||||
|
[[modbus_input_register]]
|
||||||
|
TA = {addr = 0, type = "INT16", factor = 0.1, mqtt = true, influxdb = true}
|
||||||
|
TV = {addr = 1, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TR = {addr = 2, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TWO = {addr = 3, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TPO = {addr = 4, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TPU = {addr = 5, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TZR = {addr = 6, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TV2 = {addr = 7, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TR2 = {addr = 8, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
RI1 = {addr = 9, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
RI2 = {addr = 10, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TSA = {addr = 11, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
FATV = {addr = 12, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
FATR = {addr = 13, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TVKH = {addr = 14, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TRKH = {addr = 15, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TPOKH = {addr = 16, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TV3 = {addr = 17, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TR3 = {addr = 18, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TSB = {addr = 19, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TVSB = {addr = 20, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TRSB = {addr = 21, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TWE = {addr = 22, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TWA = {addr = 23, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TWS = {addr = 24, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TVSI = {addr = 25, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TK = {addr = 26, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
FATV1 = {addr = 27, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
FATV2 = {addr = 28, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
FATV3 = {addr = 29, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
FATV4 = {addr = 30, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TSE = {addr = 31, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TW = {addr = 32, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TSV = {addr = 33, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TW2 = {addr = 34, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
S = {addr = 35, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TAM = {addr = 36, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TAM2 = {addr = 37, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TSA1 = {addr = 38, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TSA2 = {addr = 39, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TSP = {addr = 40, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TWW = {addr = 41, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TKW = {addr = 42, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
VKW = {addr = 43, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
VSPm = {addr = 44, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
|
||||||
|
[[modbus_holding_register]]
|
||||||
|
nothing = {addr = 0, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
ErrLS = {addr = 1, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
TVsoll = {addr = 2, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TV2soll = {addr = 3, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TV3soll = {addr = 4, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
HK1soll = {addr = 5, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
HK2soll = {addr = 6, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
HK3soll = {addr = 7, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
TWWsoll = {addr = 8, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TV1max = {addr = 9, type = "INT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TV2max = {addr = 10, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TV3max = {addr = 11, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
ErrHR = {addr = 12, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
ErrSR = {addr = 13, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
ErrWE1_1 = {addr = 14, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
ErrWE1_2 = {addr = 15, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
ErrWE1_3 = {addr = 16, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
ErrWE1_4 = {addr = 17, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
ErrWE1_5 = {addr = 18, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
KollLei = {addr = 19, type = "UINT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TagesS = {addr = 20, type = "UINT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
GesS = {addr = 21, type = "UINT32", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
GesWW = {addr = 23, type = "UINT32", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
GesZ = {addr = 25, type = "UINT32", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
HGesK1 = {addr = 27, type = "UINT32", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
StartK1 = {addr = 29, type = "UINT32", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
HGesPel = {addr = 31, type = "UINT32", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
VGesPel = {addr = 33, type = "UINT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
StatWW = {addr = 34, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
StatZ = {addr = 35, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
StatHK1 = {addr = 36, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
StatHK2 = {addr = 37, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
StatHK3 = {addr = 38, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
StatS = {addr = 39, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
StatSB = {addr = 40, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
StatK1 = {addr = 41, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
StatPel = {addr = 42, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
StatKH = {addr = 43, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
TPOsoll = {addr = 44, type = "UINT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
FATVsoll = {addr = 45, type = "UINT16", factor = 0.1, mqtt = false, influxdb = true}
|
||||||
|
TSBsollHK = {addr = 46, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
TSBsollS = {addr = 47, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
BetrHK1 = {addr = 48, type = "UINT16", factor = 1, mqtt = false, influxdb = true}
|
||||||
|
BetrHK2 = {addr = 49, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
BetrHK3 = {addr = 50, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
BetrSB = {addr = 51, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
GesKKsoll = {addr = 52, type = "INT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
KKsollWE1 = {addr = 53, type = "UINT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
KKsollWE2 = {addr = 54, type = "UINT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
KKsollWE3 = {addr = 55, type = "UINT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
KKsollWE4 = {addr = 56, type = "UINT16", factor = 0.1, mqtt = false, influxdb = false}
|
||||||
|
ErrWE1 = {addr = 57, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
ErrWE2 = {addr = 58, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
ErrWE3 = {addr = 59, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
ErrWE4 = {addr = 60, type = "UINT16", factor = 1, mqtt = false, influxdb = false}
|
||||||
|
|
||||||
120
paramod.yaml
120
paramod.yaml
@ -7,22 +7,22 @@ mqtt:
|
|||||||
user: admin
|
user: admin
|
||||||
password: 97sm3pHNSMZ4M5qUj0x8
|
password: 97sm3pHNSMZ4M5qUj0x8
|
||||||
path: heizung/paradigma
|
path: heizung/paradigma
|
||||||
leitsystem_path: heizung/leitsystem2
|
button_circulation: zigbee2mqtt/WirelessButton
|
||||||
influxdb:
|
influxdb:
|
||||||
bucket: Paradigma
|
bucket: Paradigma
|
||||||
|
location: Radebeul
|
||||||
|
measurement: ParadigmaModbus
|
||||||
org: skaville
|
org: skaville
|
||||||
token: i-sXFQbEkSC1XVzqFEaFwXwzasbsEIciVlK4SaAUOEvk0VjQPkD3fr8d7_3SPeyseTZkqj7ZMZU78b3n2F6_SQ==
|
token: i-sXFQbEkSC1XVzqFEaFwXwzasbsEIciVlK4SaAUOEvk0VjQPkD3fr8d7_3SPeyseTZkqj7ZMZU78b3n2F6_SQ==
|
||||||
url: http://192.168.178.2:8086
|
url: http://192.168.178.2:8086
|
||||||
location: Radebeul
|
|
||||||
measurement: ParadigmaModbus
|
|
||||||
modbus:
|
modbus:
|
||||||
host: 192.168.178.10
|
host: 192.168.178.10
|
||||||
port: 502
|
port: 502
|
||||||
max_coils_addr: 8
|
max_coils_addr: 8
|
||||||
max_input_addr: 45
|
|
||||||
max_holding_addr: 61
|
max_holding_addr: 61
|
||||||
|
max_input_addr: 45
|
||||||
modbus_coils:
|
modbus_coils:
|
||||||
- MgtSystem: {addr: 0, write: false, mqtt: true, influxdb: false, comment: Leitsystem aktiv}
|
- MgtSystem: {addr: 0, write: false, mqtt: false, influxdb: false, comment: Leitsystem aktiv}
|
||||||
- HK1pres: {addr: 1, write: false, mqtt: false, influxdb: false, comment: HK1 vorhanden}
|
- HK1pres: {addr: 1, write: false, mqtt: false, influxdb: false, comment: HK1 vorhanden}
|
||||||
- HK2pres: {addr: 2, write: false, mqtt: false, influxdb: false, comment: HK2 vorhanden}
|
- HK2pres: {addr: 2, write: false, mqtt: false, influxdb: false, comment: HK2 vorhanden}
|
||||||
- HK3pres: {addr: 3, write: false, mqtt: false, influxdb: false, comment: HK3 vorhanden}
|
- HK3pres: {addr: 3, write: false, mqtt: false, influxdb: false, comment: HK3 vorhanden}
|
||||||
@ -78,58 +78,58 @@ modbus_input_register:
|
|||||||
- VKW: {addr: 43, type: INT16, factor: 0.1, mqtt: false, influxdb: true}
|
- VKW: {addr: 43, type: INT16, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- VSPm: {addr: 44, type: INT16, factor: 0.1, mqtt: false, influxdb: true}
|
- VSPm: {addr: 44, type: INT16, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
modbus_holding_register:
|
modbus_holding_register:
|
||||||
- nothing: {addr: 0, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- nothing: {addr: 0, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- ErrLS: {addr: 1, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- ErrLS: {addr: 1, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- TVsoll: {addr: 2, type: INT16, factor: 0.1, write: true, mqtt: true, influxdb: true}
|
- TVsoll: {addr: 2, type: INT16, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- TV2soll: {addr: 3, type: INT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- TV2soll: {addr: 3, type: INT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- TV3soll: {addr: 4, type: INT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- TV3soll: {addr: 4, type: INT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- HK1soll: {addr: 5, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- HK1soll: {addr: 5, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- HK2soll: {addr: 6, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- HK2soll: {addr: 6, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- HK3soll: {addr: 7, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- HK3soll: {addr: 7, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- TWWsoll: {addr: 8, type: INT16, factor: 0.1, write: false, mqtt: false, influxdb: true}
|
- TWWsoll: {addr: 8, type: INT16, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- TV1max: {addr: 9, type: INT16, factor: 0.1, write: false, mqtt: false, influxdb: true}
|
- TV1max: {addr: 9, type: INT16, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- TV2max: {addr: 10, type: INT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- TV2max: {addr: 10, type: INT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- TV3max: {addr: 11, type: INT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- TV3max: {addr: 11, type: INT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- ErrHR: {addr: 12, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- ErrHR: {addr: 12, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- ErrSR: {addr: 13, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- ErrSR: {addr: 13, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- ErrWE1_1: {addr: 14, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- ErrWE1_1: {addr: 14, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- ErrWE1_2: {addr: 15, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- ErrWE1_2: {addr: 15, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- ErrWE1_3: {addr: 16, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- ErrWE1_3: {addr: 16, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- ErrWE1_4: {addr: 17, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- ErrWE1_4: {addr: 17, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- ErrWE1_5: {addr: 18, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- ErrWE1_5: {addr: 18, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- KollLei: {addr: 19, type: UINT16, factor: 0.1, write: false, mqtt: false, influxdb: true}
|
- KollLei: {addr: 19, type: UINT16, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- TagesS: {addr: 20, type: UINT16, factor: 0.1, write: false, mqtt: true, influxdb: true}
|
- TagesS: {addr: 20, type: UINT16, factor: 0.1, mqtt: true, influxdb: true}
|
||||||
- GesS: {addr: 21, type: UINT32, factor: 0.1, write: false, mqtt: false, influxdb: true}
|
- GesS: {addr: 21, type: UINT32, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- GesWW: {addr: 23, type: UINT32, factor: 0.1, write: false, mqtt: false, influxdb: true}
|
- GesWW: {addr: 23, type: UINT32, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- GesZ: {addr: 25, type: UINT32, factor: 0.1, write: false, mqtt: false, influxdb: true}
|
- GesZ: {addr: 25, type: UINT32, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- HGesK1: {addr: 27, type: UINT32, factor: 1, write: false, mqtt: false, influxdb: true}
|
- HGesK1: {addr: 27, type: UINT32, factor: 1, mqtt: false, influxdb: true}
|
||||||
- StartK1: {addr: 29, type: UINT32, factor: 1, write: false, mqtt: false, influxdb: true}
|
- StartK1: {addr: 29, type: UINT32, factor: 1, mqtt: false, influxdb: true}
|
||||||
- HGesPel: {addr: 31, type: UINT32, factor: 1, write: false, mqtt: false, influxdb: true}
|
- HGesPel: {addr: 31, type: UINT32, factor: 1, mqtt: false, influxdb: true}
|
||||||
- VGesPel: {addr: 33, type: UINT16, factor: 0.1, write: false, mqtt: false, influxdb: true}
|
- VGesPel: {addr: 33, type: UINT16, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- StatWW: {addr: 34, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- StatWW: {addr: 34, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- StatZ: {addr: 35, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- StatZ: {addr: 35, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- StatHK1: {addr: 36, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- StatHK1: {addr: 36, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- StatHK2: {addr: 37, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- StatHK2: {addr: 37, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- StatHK3: {addr: 38, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- StatHK3: {addr: 38, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- StatS: {addr: 39, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- StatS: {addr: 39, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- StatSB: {addr: 40, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- StatSB: {addr: 40, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- StatK1: {addr: 41, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- StatK1: {addr: 41, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- StatPel: {addr: 42, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- StatPel: {addr: 42, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- StatKH: {addr: 43, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- StatKH: {addr: 43, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- TPOsoll: {addr: 44, type: UINT16, factor: 0.1, write: false, mqtt: false, influxdb: true}
|
- TPOsoll: {addr: 44, type: UINT16, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- FATVsoll: {addr: 45, type: UINT16, factor: 0.1, write: false, mqtt: false, influxdb: true}
|
- FATVsoll: {addr: 45, type: UINT16, factor: 0.1, mqtt: false, influxdb: true}
|
||||||
- TSBsollHK: {addr: 46, type: INT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- TSBsollHK: {addr: 46, type: INT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- TSBsollS: {addr: 47, type: INT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- TSBsollS: {addr: 47, type: INT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- BetrHK1: {addr: 48, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: true}
|
- BetrHK1: {addr: 48, type: UINT16, factor: 1, mqtt: false, influxdb: true}
|
||||||
- BetrHK2: {addr: 49, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- BetrHK2: {addr: 49, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- BetrHK3: {addr: 50, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- BetrHK3: {addr: 50, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- BetrSB: {addr: 51, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- BetrSB: {addr: 51, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- GesKKsoll: {addr: 52, type: INT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- GesKKsoll: {addr: 52, type: INT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- KKsollWE1: {addr: 53, type: UINT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- KKsollWE1: {addr: 53, type: UINT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- KKsollWE2: {addr: 54, type: UINT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- KKsollWE2: {addr: 54, type: UINT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- KKsollWE3: {addr: 55, type: UINT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- KKsollWE3: {addr: 55, type: UINT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- KKsollWE4: {addr: 56, type: UINT16, factor: 0.1, write: false, mqtt: false, influxdb: false}
|
- KKsollWE4: {addr: 56, type: UINT16, factor: 0.1, mqtt: false, influxdb: false}
|
||||||
- ErrWE1: {addr: 57, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- ErrWE1: {addr: 57, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- ErrWE2: {addr: 58, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- ErrWE2: {addr: 58, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- ErrWE3: {addr: 59, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- ErrWE3: {addr: 59, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
- ErrWE4: {addr: 60, type: UINT16, factor: 1, write: false, mqtt: false, influxdb: false}
|
- ErrWE4: {addr: 60, type: UINT16, factor: 1, mqtt: false, influxdb: false}
|
||||||
@ -24,8 +24,7 @@ pub struct MqttConfig {
|
|||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
pub password: Option<String>,
|
pub password: Option<String>,
|
||||||
pub path: Option<String>,
|
pub path: Option<String>,
|
||||||
pub leitsystem_path: Option<String>,
|
pub button_circulation: Option<String>,
|
||||||
pub set_write_interval_ms: Option<u64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
|||||||
107
src/modbus.rs
107
src/modbus.rs
@ -1,6 +1,5 @@
|
|||||||
use crate::config::{ModbusValueMaps, ModbusConfig};
|
use crate::config::{ModbusValueMaps, ModbusConfig};
|
||||||
use crate::modbus_types::{ModbusInputRegisterConfig, ModbusHoldingRegisterConfig, ModbusCoilsConfig};
|
use crate::modbus_types::{ModbusInputRegisterConfig, ModbusHoldingRegisterConfig, ModbusCoilsConfig};
|
||||||
use crate::config::AppConfig;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
@ -10,112 +9,6 @@ use tokio_modbus::prelude::*;
|
|||||||
use tokio_modbus::client::tcp;
|
use tokio_modbus::client::tcp;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
pub fn write_value_by_name(config: &AppConfig, name: &str, payload: &str) -> Result<(), String> {
|
|
||||||
let addr: SocketAddr = format!("{}:{}", config.modbus.host, config.modbus.port)
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| format!("Ungültige Modbus-Adresse: {}", e))?;
|
|
||||||
|
|
||||||
if let Some(ref coils) = config.modbus_coils {
|
|
||||||
for map in coils {
|
|
||||||
if let Some(coil) = map.get(name) {
|
|
||||||
if !coil.write.unwrap_or(false) {
|
|
||||||
return Err(format!("Schreiben für '{}' nicht erlaubt", name));
|
|
||||||
}
|
|
||||||
let bool_value = parse_bool_payload(payload)?;
|
|
||||||
let rt = tokio::runtime::Runtime::new()
|
|
||||||
.map_err(|e| format!("Tokio Runtime Fehler: {}", e))?;
|
|
||||||
rt.block_on(async {
|
|
||||||
let mut client = tcp::connect_slave(addr, 1u8.into())
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Modbus Verbindung fehlgeschlagen: {}", e))?;
|
|
||||||
client
|
|
||||||
.write_single_coil(coil.addr, bool_value)
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Coil schreiben fehlgeschlagen: {}", e))
|
|
||||||
})?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ref holding_registers) = config.modbus_holding_register {
|
|
||||||
for map in holding_registers {
|
|
||||||
if let Some(reg) = map.get(name) {
|
|
||||||
if !reg.write.unwrap_or(false) {
|
|
||||||
return Err(format!("Schreiben für '{}' nicht erlaubt", name));
|
|
||||||
}
|
|
||||||
let numeric_value = payload
|
|
||||||
.trim()
|
|
||||||
.parse::<f64>()
|
|
||||||
.map_err(|e| format!("Ungültiger Zahlenwert '{}': {}", payload, e))?;
|
|
||||||
let factor = reg.factor.unwrap_or(1.0);
|
|
||||||
let raw = if factor == 0.0 {
|
|
||||||
numeric_value
|
|
||||||
} else {
|
|
||||||
numeric_value / factor
|
|
||||||
};
|
|
||||||
|
|
||||||
let rt = tokio::runtime::Runtime::new()
|
|
||||||
.map_err(|e| format!("Tokio Runtime Fehler: {}", e))?;
|
|
||||||
|
|
||||||
return rt.block_on(async {
|
|
||||||
let mut client = tcp::connect_slave(addr, 1u8.into())
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Modbus Verbindung fehlgeschlagen: {}", e))?;
|
|
||||||
|
|
||||||
match reg.r#type.as_deref().unwrap_or("UINT16") {
|
|
||||||
"INT16" => {
|
|
||||||
let int_value = raw.round();
|
|
||||||
if int_value < i16::MIN as f64 || int_value > i16::MAX as f64 {
|
|
||||||
return Err(format!("Wert außerhalb INT16-Bereich für '{}': {}", name, numeric_value));
|
|
||||||
}
|
|
||||||
let register = int_value as i16 as u16;
|
|
||||||
client
|
|
||||||
.write_multiple_registers(reg.addr, &[register])
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Holding Register schreiben fehlgeschlagen: {}", e))?;
|
|
||||||
}
|
|
||||||
"UINT32" => {
|
|
||||||
let int_value = raw.round();
|
|
||||||
if int_value < 0.0 || int_value > u32::MAX as f64 {
|
|
||||||
return Err(format!("Wert außerhalb UINT32-Bereich für '{}': {}", name, numeric_value));
|
|
||||||
}
|
|
||||||
let val = int_value as u32;
|
|
||||||
let high = ((val >> 16) & 0xFFFF) as u16;
|
|
||||||
let low = (val & 0xFFFF) as u16;
|
|
||||||
client
|
|
||||||
.write_multiple_registers(reg.addr, &[high, low])
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Holding Register (UINT32) schreiben fehlgeschlagen: {}", e))?;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let int_value = raw.round();
|
|
||||||
if int_value < 0.0 || int_value > u16::MAX as f64 {
|
|
||||||
return Err(format!("Wert außerhalb UINT16-Bereich für '{}': {}", name, numeric_value));
|
|
||||||
}
|
|
||||||
client
|
|
||||||
.write_multiple_registers(reg.addr, &[int_value as u16])
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Holding Register schreiben fehlgeschlagen: {}", e))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(format!("Kein schreibbares Modbus-Mapping für '{}' gefunden", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_bool_payload(payload: &str) -> Result<bool, String> {
|
|
||||||
match payload.trim().to_ascii_lowercase().as_str() {
|
|
||||||
"1" | "true" | "on" => Ok(true),
|
|
||||||
"0" | "false" | "off" => Ok(false),
|
|
||||||
_ => Err(format!("Ungültiger bool-Wert '{}', erwartet 0/1 oder true/false", payload)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Startet einen Thread, der zyklisch Modbus-Register abfragt und ModbusValueMaps aktualisiert
|
/// Startet einen Thread, der zyklisch Modbus-Register abfragt und ModbusValueMaps aktualisiert
|
||||||
pub fn start_modbus_polling_thread(
|
pub fn start_modbus_polling_thread(
|
||||||
modbus_config: &ModbusConfig,
|
modbus_config: &ModbusConfig,
|
||||||
|
|||||||
@ -24,7 +24,6 @@ pub struct ModbusHoldingRegisterConfig {
|
|||||||
pub addr: u16,
|
pub addr: u16,
|
||||||
pub r#type: Option<String>,
|
pub r#type: Option<String>,
|
||||||
pub factor: Option<f64>,
|
pub factor: Option<f64>,
|
||||||
pub write: Option<bool>,
|
|
||||||
pub mqtt: Option<bool>,
|
pub mqtt: Option<bool>,
|
||||||
pub influxdb: Option<bool>,
|
pub influxdb: Option<bool>,
|
||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
|
|||||||
146
src/mqtt.rs
146
src/mqtt.rs
@ -1,11 +1,8 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::process;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::Duration;
|
||||||
use crate::config::{AppConfig, ModbusValueMaps};
|
use crate::config::{AppConfig, ModbusValueMaps};
|
||||||
use crate::modbus;
|
use rumqttc::{MqttOptions, Client, QoS};
|
||||||
use rumqttc::{Event, MqttOptions, Packet, Client, QoS, RecvTimeoutError};
|
|
||||||
|
|
||||||
pub fn start_mqtt_thread(config: Arc<Mutex<AppConfig>>, values: Arc<Mutex<ModbusValueMaps>>) {
|
pub fn start_mqtt_thread(config: Arc<Mutex<AppConfig>>, values: Arc<Mutex<ModbusValueMaps>>) {
|
||||||
let mqtt_config = {
|
let mqtt_config = {
|
||||||
@ -15,48 +12,24 @@ pub fn start_mqtt_thread(config: Arc<Mutex<AppConfig>>, values: Arc<Mutex<Modbus
|
|||||||
let broker = if mqtt_config.broker.is_empty() { "localhost".to_string() } else { mqtt_config.broker.clone() };
|
let broker = if mqtt_config.broker.is_empty() { "localhost".to_string() } else { mqtt_config.broker.clone() };
|
||||||
let port = if mqtt_config.port == 0 { 1883 } else { mqtt_config.port };
|
let port = if mqtt_config.port == 0 { 1883 } else { mqtt_config.port };
|
||||||
let path = if let Some(ref p) = mqtt_config.path { p.clone() } else { "paramod/values".to_string() };
|
let path = if let Some(ref p) = mqtt_config.path { p.clone() } else { "paramod/values".to_string() };
|
||||||
let leitsystem_path = mqtt_config
|
|
||||||
.leitsystem_path
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| format!("{}/leitsystem", path));
|
|
||||||
let set_write_interval = Duration::from_millis(mqtt_config.set_write_interval_ms.unwrap_or(2000).max(100));
|
|
||||||
let user = mqtt_config.user.clone().unwrap_or_default();
|
let user = mqtt_config.user.clone().unwrap_or_default();
|
||||||
let password = mqtt_config.password.clone().unwrap_or_default();
|
let password = mqtt_config.password.clone().unwrap_or_default();
|
||||||
let user_is_empty = user.is_empty();
|
let user_is_empty = user.is_empty();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let client_id = format!("paramod-client-{}", process::id());
|
let mut mqttoptions = MqttOptions::new("paramod-client", broker, port);
|
||||||
let mut mqttoptions = MqttOptions::new(client_id, broker, port);
|
|
||||||
mqttoptions.set_keep_alive(Duration::from_secs(5));
|
|
||||||
if !user_is_empty {
|
if !user_is_empty {
|
||||||
mqttoptions.set_credentials(user, password);
|
mqttoptions.set_credentials(user, password);
|
||||||
}
|
}
|
||||||
let (mut client, mut connection) = Client::new(mqttoptions, 10);
|
let (mut client, mut connection) = Client::new(mqttoptions, 10);
|
||||||
|
|
||||||
let set_topic = format!("{}/+/set", path);
|
|
||||||
if let Err(e) = client.subscribe(set_topic, QoS::AtLeastOnce) {
|
|
||||||
eprintln!("MQTT Subscribe fehlgeschlagen: {}", e);
|
|
||||||
}
|
|
||||||
let leitsystem_state_topic = format!("{}/state", leitsystem_path.trim_end_matches('/'));
|
|
||||||
if let Err(e) = client.subscribe(leitsystem_state_topic.clone(), QoS::AtLeastOnce) {
|
|
||||||
eprintln!("MQTT Subscribe Leitsystem fehlgeschlagen: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
let publish_interval = Duration::from_secs(5);
|
|
||||||
let mut last_publish = Instant::now() - publish_interval;
|
|
||||||
let mut last_set_write = Instant::now() - set_write_interval;
|
|
||||||
let mut pending_set_values: HashMap<String, String> = HashMap::new();
|
|
||||||
let mut leitsystem_enabled = false;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if last_publish.elapsed() >= publish_interval {
|
|
||||||
{
|
{
|
||||||
let values = values.lock().unwrap();
|
let values = values.lock().unwrap();
|
||||||
// Input Register
|
// Input Register
|
||||||
for (name, val) in &values.modbus_input_register_values {
|
for (name, val) in &values.modbus_input_register_values {
|
||||||
if let Some(v) = val {
|
if let Some(v) = val {
|
||||||
if should_publish(&config, name, "input_register") {
|
if should_publish(&config, name, "input_register") {
|
||||||
let topic = format!("{}/{}/state", path, name);
|
let topic = format!("{}/{}", path, name);
|
||||||
let payload = format!("{}", v);
|
let payload = format!("{}", v);
|
||||||
let _ = client.publish(topic, QoS::AtLeastOnce, false, payload);
|
let _ = client.publish(topic, QoS::AtLeastOnce, false, payload);
|
||||||
}
|
}
|
||||||
@ -66,7 +39,7 @@ pub fn start_mqtt_thread(config: Arc<Mutex<AppConfig>>, values: Arc<Mutex<Modbus
|
|||||||
for (name, val) in &values.modbus_holding_register_values {
|
for (name, val) in &values.modbus_holding_register_values {
|
||||||
if let Some(v) = val {
|
if let Some(v) = val {
|
||||||
if should_publish(&config, name, "holding_register") {
|
if should_publish(&config, name, "holding_register") {
|
||||||
let topic = format!("{}/{}/state", path, name);
|
let topic = format!("{}/{}", path, name);
|
||||||
let payload = format!("{}", v);
|
let payload = format!("{}", v);
|
||||||
let _ = client.publish(topic, QoS::AtLeastOnce, false, payload);
|
let _ = client.publish(topic, QoS::AtLeastOnce, false, payload);
|
||||||
}
|
}
|
||||||
@ -76,121 +49,22 @@ pub fn start_mqtt_thread(config: Arc<Mutex<AppConfig>>, values: Arc<Mutex<Modbus
|
|||||||
for (name, val) in &values.modbus_coils_values {
|
for (name, val) in &values.modbus_coils_values {
|
||||||
if let Some(v) = val {
|
if let Some(v) = val {
|
||||||
if should_publish(&config, name, "coils") {
|
if should_publish(&config, name, "coils") {
|
||||||
let topic = format!("{}/{}/state", path, name);
|
let topic = format!("{}/{}", path, name);
|
||||||
let payload = format!("{}", v);
|
let payload = format!("{}", v);
|
||||||
let _ = client.publish(topic, QoS::AtLeastOnce, false, payload);
|
let _ = client.publish(topic, QoS::AtLeastOnce, false, payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Handle MQTT connection events
|
||||||
let state_payload = if leitsystem_enabled { "ON" } else { "OFF" };
|
for _event in connection.iter().take(1) {
|
||||||
let _ = client.publish(
|
// Optionally log or handle events
|
||||||
leitsystem_state_topic.clone(),
|
|
||||||
QoS::AtLeastOnce,
|
|
||||||
true,
|
|
||||||
state_payload,
|
|
||||||
);
|
|
||||||
last_publish = Instant::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
if last_set_write.elapsed() >= set_write_interval {
|
|
||||||
let cfg = {
|
|
||||||
let lock = config.lock().unwrap();
|
|
||||||
lock.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if leitsystem_enabled {
|
|
||||||
for (name, payload) in &pending_set_values {
|
|
||||||
if let Err(e) = modbus::write_value_by_name(&cfg, name, payload) {
|
|
||||||
eprintln!("MQTT set -> Modbus Fehler ({}): {}", name, e);
|
|
||||||
} else {
|
|
||||||
mirror_set_value(&values, &cfg, name, payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
last_set_write = Instant::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
match connection.recv_timeout(Duration::from_millis(200)) {
|
|
||||||
Ok(Ok(Event::Incoming(Packet::Publish(publish)))) => {
|
|
||||||
if publish.topic == leitsystem_state_topic {
|
|
||||||
let payload = String::from_utf8_lossy(&publish.payload).trim().to_string();
|
|
||||||
match parse_boolish(&payload) {
|
|
||||||
Some(v) => leitsystem_enabled = v,
|
|
||||||
None => eprintln!("Ungültiger Leitsystem state '{}', erwartet ON/OFF", payload),
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(name) = extract_name_from_set_topic(&path, &publish.topic) {
|
|
||||||
let payload = String::from_utf8_lossy(&publish.payload).trim().to_string();
|
|
||||||
pending_set_values.insert(name.clone(), payload.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Ok(_)) => {}
|
|
||||||
Ok(Err(e)) => {
|
|
||||||
eprintln!("MQTT Connection Fehler: {}", e);
|
|
||||||
eprintln!("Hinweis: Häufige Ursache ist eine zweite MQTT-Session mit derselben Client-ID.");
|
|
||||||
}
|
|
||||||
Err(RecvTimeoutError::Timeout) => {}
|
|
||||||
Err(RecvTimeoutError::Disconnected) => {
|
|
||||||
eprintln!("MQTT Verbindung getrennt (request channel geschlossen)");
|
|
||||||
thread::sleep(Duration::from_millis(500));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
thread::sleep(Duration::from_secs(5));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_boolish(payload: &str) -> Option<bool> {
|
|
||||||
match payload.trim().to_ascii_lowercase().as_str() {
|
|
||||||
"1" | "true" | "on" => Some(true),
|
|
||||||
"0" | "false" | "off" => Some(false),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mirror_set_value(values: &Arc<Mutex<ModbusValueMaps>>, cfg: &AppConfig, name: &str, payload: &str) {
|
|
||||||
if let Ok(mut maps) = values.lock() {
|
|
||||||
if let Some(ref coils) = cfg.modbus_coils {
|
|
||||||
for map in coils {
|
|
||||||
if map.contains_key(name) {
|
|
||||||
if let Some(v) = parse_boolish(payload) {
|
|
||||||
maps.modbus_coils_values.insert(name.to_string(), Some(if v { 1.0 } else { 0.0 }));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ref holding) = cfg.modbus_holding_register {
|
|
||||||
for map in holding {
|
|
||||||
if map.contains_key(name) {
|
|
||||||
if let Ok(v) = payload.parse::<f64>() {
|
|
||||||
maps.modbus_holding_register_values.insert(name.to_string(), Some(v));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_name_from_set_topic(base_path: &str, topic: &str) -> Result<String, String> {
|
|
||||||
let prefix = format!("{}/", base_path.trim_end_matches('/'));
|
|
||||||
if !topic.starts_with(&prefix) || !topic.ends_with("/set") {
|
|
||||||
return Err("Topic passt nicht zum /set-Schema".to_string());
|
|
||||||
}
|
|
||||||
let without_prefix = &topic[prefix.len()..];
|
|
||||||
let name = without_prefix.strip_suffix("/set").unwrap_or_default();
|
|
||||||
if name.is_empty() || name.contains('/') {
|
|
||||||
return Err("Ungültiger Variablenname im Topic".to_string());
|
|
||||||
}
|
|
||||||
Ok(name.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn should_publish(config: &Arc<Mutex<AppConfig>>, name: &str, reg_type: &str) -> bool {
|
fn should_publish(config: &Arc<Mutex<AppConfig>>, name: &str, reg_type: &str) -> bool {
|
||||||
let cfg = config.lock().unwrap();
|
let cfg = config.lock().unwrap();
|
||||||
match reg_type {
|
match reg_type {
|
||||||
|
|||||||
@ -56,34 +56,6 @@ function addRow() {
|
|||||||
<button class="delete-btn" onclick="deleteRow(this)">🗑️</button>
|
<button class="delete-btn" onclick="deleteRow(this)">🗑️</button>
|
||||||
</td>
|
</td>
|
||||||
`;
|
`;
|
||||||
} else if (typeof tableId !== 'undefined' && tableId === 'modbus_holding_registers') {
|
|
||||||
newRow.innerHTML = `
|
|
||||||
<td><input type='text' class='text-input' data-field='bezeichnung' value='' /></td>
|
|
||||||
<td><input type='text' class='text-input' data-field='adresse' value='' /></td>
|
|
||||||
<td><input type='text' class='text-input' data-field='type' value='' /></td>
|
|
||||||
<td><input type='text' class='text-input' data-field='faktor' value='1.0' /></td>
|
|
||||||
<td>
|
|
||||||
<label class='switch'>
|
|
||||||
<input type='checkbox' class='bool-input' data-field='write' />
|
|
||||||
<span class='slider'></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<label class='switch'>
|
|
||||||
<input type='checkbox' class='bool-input' data-field='mqtt' />
|
|
||||||
<span class='slider'></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<label class='switch'>
|
|
||||||
<input type='checkbox' class='bool-input' data-field='influxdb' />
|
|
||||||
<span class='slider'></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button class="delete-btn" onclick="deleteRow(this)">🗑️</button>
|
|
||||||
</td>
|
|
||||||
`;
|
|
||||||
} else {
|
} else {
|
||||||
newRow.innerHTML = `
|
newRow.innerHTML = `
|
||||||
<td><input type='text' class='text-input' data-field='bezeichnung' value='' /></td>
|
<td><input type='text' class='text-input' data-field='bezeichnung' value='' /></td>
|
||||||
@ -147,20 +119,6 @@ async function saveTable() {
|
|||||||
influxdb: influxdb,
|
influxdb: influxdb,
|
||||||
comment: comment
|
comment: comment
|
||||||
};
|
};
|
||||||
} else if (typeof tableId !== 'undefined' && tableId === 'modbus_holding_registers') {
|
|
||||||
const write = row.querySelector("input[data-field='write']")?.checked || false;
|
|
||||||
const rtype = row.querySelector("input[data-field='type']")?.value || null;
|
|
||||||
const factor = parseFloat(row.querySelector("input[data-field='factor']")?.value || row.querySelector("input[data-field='faktor']")?.value || '1.0');
|
|
||||||
const comment = row.querySelector("input[data-field='comment']")?.value || null;
|
|
||||||
value = {
|
|
||||||
addr: addr,
|
|
||||||
rtype: rtype,
|
|
||||||
factor: factor,
|
|
||||||
write: write,
|
|
||||||
mqtt: mqtt,
|
|
||||||
influxdb: influxdb,
|
|
||||||
comment: comment
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
const rtype = row.querySelector("input[data-field='type']")?.value || null;
|
const rtype = row.querySelector("input[data-field='type']")?.value || null;
|
||||||
const factor = parseFloat(row.querySelector("input[data-field='factor']")?.value || row.querySelector("input[data-field='faktor']")?.value || '1.0');
|
const factor = parseFloat(row.querySelector("input[data-field='factor']")?.value || row.querySelector("input[data-field='faktor']")?.value || '1.0');
|
||||||
|
|||||||
@ -55,8 +55,7 @@ async function saveSettings() {
|
|||||||
user: document.getElementById('mqtt_user').value || null,
|
user: document.getElementById('mqtt_user').value || null,
|
||||||
password: document.getElementById('mqtt_password').value || null,
|
password: document.getElementById('mqtt_password').value || null,
|
||||||
path: document.getElementById('mqtt_path')?.value || null,
|
path: document.getElementById('mqtt_path')?.value || null,
|
||||||
leitsystem_path: document.getElementById('mqtt_leitsystem_path')?.value || null,
|
button_circulation: document.getElementById('mqtt_button_circulation').value || null
|
||||||
set_write_interval_ms: parseInt(document.getElementById('mqtt_set_write_interval_ms')?.value, 10) || 2000
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// InfluxDB
|
// InfluxDB
|
||||||
|
|||||||
@ -96,8 +96,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.logo-text {
|
.logo-text {
|
||||||
font-size: 40px;
|
font-size: 20px;
|
||||||
font-weight: 800;
|
font-weight: 700;
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Konfiguration</title>
|
<title>Sensor Konfiguration</title>
|
||||||
<link rel="stylesheet" href="/static/style.css">
|
<link rel="stylesheet" href="/static/style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<rect width="40" height="40" rx="8" fill="#667eea"/>
|
<rect width="40" height="40" rx="8" fill="#667eea"/>
|
||||||
<path d="M12 20L18 26L28 14" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M12 20L18 26L28 14" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="logo-text">Paramod</span>
|
<span class="logo-text">Sensor Manager</span>
|
||||||
</div>
|
</div>
|
||||||
<nav class="nav">
|
<nav class="nav">
|
||||||
<a href="/table/modbus_input_register" class="nav-link {% if active_page == 'modbus_input_register' %}active{% endif %}">Input Register</a>
|
<a href="/table/modbus_input_register" class="nav-link {% if active_page == 'modbus_input_register' %}active{% endif %}">Input Register</a>
|
||||||
@ -26,7 +26,7 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>🔧 Konfiguration - {{ table_id | upper }}</h1>
|
<h1>🔧 Sensor Konfiguration - {{ table_id | upper }}</h1>
|
||||||
<div id="message" class="message"></div>
|
<div id="message" class="message"></div>
|
||||||
<div class="table-wrapper">
|
<div class="table-wrapper">
|
||||||
<table id="sensorTable">
|
<table id="sensorTable">
|
||||||
@ -37,10 +37,6 @@
|
|||||||
<th>Adresse</th>
|
<th>Adresse</th>
|
||||||
{% if table_id == "modbus_coils" %}
|
{% if table_id == "modbus_coils" %}
|
||||||
<th>Write</th>
|
<th>Write</th>
|
||||||
{% elif table_id == "modbus_holding_registers" or table_id == "modbus_holding_register" %}
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Faktor</th>
|
|
||||||
<th>Write</th>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Faktor</th>
|
<th>Faktor</th>
|
||||||
@ -67,15 +63,6 @@
|
|||||||
<span class='slider'></span>
|
<span class='slider'></span>
|
||||||
</label>
|
</label>
|
||||||
</td>
|
</td>
|
||||||
{% elif table_id == "modbus_holding_registers" or table_id == "modbus_holding_register" %}
|
|
||||||
<td><input type='text' class='text-input' data-field='type' value='{{ row.type | default(value="") }}' /></td>
|
|
||||||
<td><input type='text' class='text-input' data-field='factor' value='{{ row.factor | default(value="") }}' /></td>
|
|
||||||
<td>
|
|
||||||
<label class='switch'>
|
|
||||||
<input type='checkbox' class='bool-input' data-field='write' {% if row.write %}checked{% endif %} />
|
|
||||||
<span class='slider'></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<td><input type='text' class='text-input' data-field='type' value='{{ row.type | default(value="") }}' /></td>
|
<td><input type='text' class='text-input' data-field='type' value='{{ row.type | default(value="") }}' /></td>
|
||||||
<td><input type='text' class='text-input' data-field='factor' value='{{ row.factor | default(value="") }}' /></td>
|
<td><input type='text' class='text-input' data-field='factor' value='{{ row.factor | default(value="") }}' /></td>
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
<rect width="40" height="40" rx="8" fill="#667eea"/>
|
<rect width="40" height="40" rx="8" fill="#667eea"/>
|
||||||
<path d="M12 20L18 26L28 14" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M12 20L18 26L28 14" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="logo-text">Paramod</span>
|
<span class="logo-text">Sensor Manager</span>
|
||||||
</div>
|
</div>
|
||||||
<nav class="nav">
|
<nav class="nav">
|
||||||
<a href="/table/modbus_input_register" class="nav-link {% if active_page == 'modbus_input_register' %}active{% endif %}">Input Register</a>
|
<a href="/table/modbus_input_register" class="nav-link {% if active_page == 'modbus_input_register' %}active{% endif %}">Input Register</a>
|
||||||
@ -98,12 +98,8 @@
|
|||||||
<input type="text" id="mqtt_path" class="text-input" value="{{ mqtt.path | default(value="") }}" />
|
<input type="text" id="mqtt_path" class="text-input" value="{{ mqtt.path | default(value="") }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="mqtt_leitsystem_path">Leitsystem Pfad:</label>
|
<label for="mqtt_button_circulation">Button Circulation:</label>
|
||||||
<input type="text" id="mqtt_leitsystem_path" class="text-input" value="{{ mqtt.leitsystem_path | default(value="") }}" />
|
<input type="text" id="mqtt_button_circulation" class="text-input" value="{{ mqtt.button_circulation | default(value="") }}" />
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="mqtt_set_write_interval_ms">Set-Sendeintervall (ms):</label>
|
|
||||||
<input type="number" min="100" id="mqtt_set_write_interval_ms" class="text-input" value="{{ mqtt.set_write_interval_ms | default(value="2000") }}" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user