Konfiguration auf yaml umgestellt

This commit is contained in:
Eric Neuber 2026-01-01 20:37:03 +01:00
parent e74689c70f
commit 09c41821c8
7 changed files with 283 additions and 123 deletions

21
Cargo.lock generated
View File

@ -1587,6 +1587,19 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "sha1"
version = "0.10.6"
@ -1716,10 +1729,10 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"serde_yaml",
"tera",
"tokio",
"toml",
"toml_edit",
]
[[package]]
@ -1944,6 +1957,12 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "url"
version = "2.5.7"

View File

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
toml_edit = "0.22"
serde_yaml = "0.9"
actix-web = "4.4.0"
actix-files = "0.6.2"
serde = { version = "1.0", features = ["derive"] }

View File

@ -24,15 +24,15 @@ max_input_addr = 45
port = 502
[[modbus_coils]]
MgtSystem = {addr = 0, comment = "Leitsystem aktiv"}
HK1pres = {addr = 1, comment = "HK1 vorhanden"}
HK2pres = {addr = 2, comment = "HK2 vorhanden"}
HK3pres = {addr = 3, comment = "HK3 vorhanden"}
TWrelease = {addr = 4, comment = "Trinkwassererwärmung freigegeben"}
TWlock = {addr = 5, comment = "Trinkwassererwärmung gesprerrt"}
Zrelease = {addr = 6, comment = "Zirkulation freigegeben"}
Zlock = {addr = 7, comment = "Zirkulation gesperrt"}
SHKpres = {addr = 8, comment = "Schwimmbadheizkrei vorhanden"}
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}

139
paramod.yaml Normal file
View File

@ -0,0 +1,139 @@
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 gesperrt"}
- 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}

View File

@ -5,7 +5,7 @@ use std::sync::Mutex;
use tera::{Context, Tera};
// use config::{Config, File};
use std::fs;
use toml_edit::{Document, value, Item};
use serde_yaml;
use std::collections::HashMap;
@ -72,7 +72,7 @@ struct AppState {
impl AppState {
fn load_from_conf(conf_path: &str) -> Self {
let conf_str = std::fs::read_to_string(conf_path).expect("Config-Datei konnte nicht gelesen werden");
let config: AppConfig = toml::from_str(&conf_str).expect("Config-Deserialisierung fehlgeschlagen");
let config: AppConfig = serde_yaml::from_str(&conf_str).expect("Config-Deserialisierung fehlgeschlagen");
let tera = match Tera::new("templates/**/*") {
Ok(t) => t,
@ -170,34 +170,24 @@ async fn save_table(
req: web::Json<SaveTableRequest>,
) -> Result<HttpResponse> {
let mut config = data.config.lock().unwrap();
// Lade bestehende Datei mit toml_edit
let conf_path = "old/paramod.conf";
let conf_str = match fs::read_to_string(conf_path) {
Ok(s) => s,
Err(e) => return Ok(HttpResponse::InternalServerError().body(format!("Fehler beim Lesen: {}", e))),
};
let mut doc = match conf_str.parse::<Document>() {
Ok(d) => d,
Err(e) => return Ok(HttpResponse::InternalServerError().body(format!("TOML-Parse-Fehler: {}", e))),
};
let conf_path = "paramod.yaml";
let key = match req.table_id.as_str() {
"modbus_input_register" => "modbus_input_register",
"modbus_holding_register" => "modbus_holding_register",
"modbus_coils" => "modbus_coils",
_ => return Ok(HttpResponse::BadRequest().body("Invalid table_id")),
};
// Serialisiere nur das relevante Feld als TOML
let value_toml = match toml::to_string(&req.rows) {
match key {
"modbus_input_register" => config.modbus_input_register = Some(req.rows.clone()),
"modbus_holding_register" => config.modbus_holding_register = Some(req.rows.clone()),
"modbus_coils" => config.modbus_coils = Some(req.rows.clone()),
_ => {}
}
let yaml_str = match serde_yaml::to_string(&*config) {
Ok(s) => s,
Err(e) => return Ok(HttpResponse::InternalServerError().body(format!("Serialisierungsfehler: {}", e))),
};
// value_toml ist z.B. "[[...]]", wir brauchen nur den Wert
let value_item = value_toml.parse::<Item>().unwrap_or(Item::None);
doc[key] = value_item;
// Schreibe zurück
if let Err(e) = fs::write(conf_path, doc.to_string()) {
if let Err(e) = fs::write(conf_path, yaml_str) {
return Ok(HttpResponse::InternalServerError().body(format!("Fehler beim Schreiben: {}", e)));
}
Ok(HttpResponse::Ok().body("success"))
@ -209,61 +199,12 @@ async fn save_settings(
) -> Result<HttpResponse> {
let mut config = data.config.lock().unwrap();
*config = settings.into_inner();
let conf_path = "old/paramod.conf";
let conf_str = match fs::read_to_string(conf_path) {
let conf_path = "paramod.yaml";
let yaml_str = match serde_yaml::to_string(&*config) {
Ok(s) => s,
Err(e) => return Ok(HttpResponse::InternalServerError().body(format!("Fehler beim Lesen: {}", e))),
Err(e) => return Ok(HttpResponse::InternalServerError().body(format!("Serialisierungsfehler: {}", e))),
};
let mut doc = match conf_str.parse::<Document>() {
Ok(d) => d,
Err(e) => return Ok(HttpResponse::InternalServerError().body(format!("TOML-Parse-Fehler: {}", e))),
};
// mqtt
let mqtt_value = toml::Value::try_from(&config.mqtt).map_err(|e| actix_web::error::ErrorInternalServerError(format!("Serialisierungsfehler: {}", e)))?;
if let toml::Value::Table(table) = mqtt_value {
let mut item = Item::Table(Default::default());
if let Item::Table(ref mut t) = item {
for (k, v) in table {
t[&k] = v.to_string().parse::<Item>().unwrap_or(Item::None);
}
}
doc["mqtt"] = item;
}
// influxdb
let influxdb_value = toml::Value::try_from(&config.influxdb).map_err(|e| actix_web::error::ErrorInternalServerError(format!("Serialisierungsfehler: {}", e)))?;
if let toml::Value::Table(table) = influxdb_value {
let mut item = Item::Table(Default::default());
if let Item::Table(ref mut t) = item {
for (k, v) in table {
t[&k] = v.to_string().parse::<Item>().unwrap_or(Item::None);
}
}
doc["influxdb"] = item;
}
// modbus
let modbus_value = toml::Value::try_from(&config.modbus).map_err(|e| actix_web::error::ErrorInternalServerError(format!("Serialisierungsfehler: {}", e)))?;
if let toml::Value::Table(table) = modbus_value {
let mut item = Item::Table(Default::default());
if let Item::Table(ref mut t) = item {
for (k, v) in table {
t[&k] = v.to_string().parse::<Item>().unwrap_or(Item::None);
}
}
doc["modbus"] = item;
}
// [default] Abschnitt
let default_value = toml::Value::try_from(&config.default).map_err(|e| actix_web::error::ErrorInternalServerError(format!("Serialisierungsfehler: {}", e)))?;
if let toml::Value::Table(table) = default_value {
let mut item = Item::Table(Default::default());
if let Item::Table(ref mut t) = item {
for (k, v) in table {
t[&k] = v.to_string().parse::<Item>().unwrap_or(Item::None);
}
}
doc["default"] = item;
}
// Schreibe zurück
if let Err(e) = fs::write(conf_path, doc.to_string()) {
if let Err(e) = fs::write(conf_path, yaml_str) {
return Ok(HttpResponse::InternalServerError().body(format!("Fehler beim Schreiben: {}", e)));
}
Ok(HttpResponse::Ok().body("success"))
@ -272,7 +213,7 @@ async fn save_settings(
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let config_path = "old/paramod.conf";
let config_path = "paramod.yaml";
let app_state = web::Data::new(AppState::load_from_conf(config_path));
println!("Server läuft auf http://0.0.0.0:8080");

View File

@ -19,6 +19,34 @@ function addRow() {
const newRow = document.createElement('tr');
newRow.setAttribute('data-row', rowCount);
if (typeof tableId !== 'undefined' && tableId === 'modbus_coils') {
newRow.innerHTML = `
<td><input type='text' class='text-input' data-field='bezeichnung' value='' /></td>
<td><input type='number' class='text-input' data-field='adresse' value='' /></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><input type='text' class='text-input' data-field='comment' value='' /></td>
<td>
<button class="delete-btn" onclick="deleteRow(this)">🗑</button>
</td>
`;
} else {
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>
@ -40,6 +68,7 @@ function addRow() {
<button class="delete-btn" onclick="deleteRow(this)">🗑</button>
</td>
`;
}
tableBody.appendChild(newRow);
}
@ -63,15 +92,27 @@ async function saveTable() {
const rows = [];
const tableRows = document.querySelectorAll('#tableBody tr');
tableRows.forEach((row) => {
const key = row.querySelector("input[data-field='bezeichnung']").value.trim();
const key = row.querySelector("input[data-field='bezeichnung']")?.value.trim() || row.querySelector("input[data-field='key']")?.value.trim();
if (!key) return; // leere Zeilen überspringen
const addr = parseInt(row.querySelector("input[data-field='addr']")?.value || row.querySelector("input[data-field='adresse']")?.value || '0', 10);
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 mqtt = row.querySelector("input[data-field='mqtt']")?.checked || false;
const influxdb = row.querySelector("input[data-field='influxdb']")?.checked || false;
let value = {};
if (typeof tableId !== 'undefined' && tableId === 'modbus_coils') {
const write = row.querySelector("input[data-field='write']")?.checked || false;
const comment = row.querySelector("input[data-field='comment']")?.value || null;
const value = {
value = {
addr: addr,
write: write,
mqtt: mqtt,
influxdb: influxdb,
comment: comment
};
} else {
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,
@ -79,6 +120,7 @@ async function saveTable() {
influxdb: influxdb,
comment: comment
};
}
const obj = {};
obj[key] = value;
rows.push(obj);

View File

@ -34,10 +34,17 @@
<tr>
<th>Bezeichnung</th>
<th>Adresse</th>
{% if table_id == "modbus_coils" %}
<th>Write</th>
{% else %}
<th>Type</th>
<th>Faktor</th>
{% endif %}
<th>MQTT</th>
<th>InfluxDB</th>
{% if table_id == "modbus_coils" %}
<th>Kommentar</th>
{% endif %}
<th>Aktionen</th>
</tr>
</thead>
@ -47,8 +54,17 @@
<tr data-row="{{ loop.index0 }}">
<td><input type='text' class='text-input' data-field='key' value='{{ key }}' /></td>
<td><input type='number' class='text-input' data-field='addr' value='{{ row.addr }}' /></td>
{% if table_id == "modbus_coils" %}
<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 %}
<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>
{% endif %}
<td>
<label class='switch'>
<input type='checkbox' class='bool-input' data-field='mqtt' {% if row.mqtt %}checked{% endif %} />
@ -61,6 +77,9 @@
<span class='slider'></span>
</label>
</td>
{% if table_id == "modbus_coils" %}
<td><input type='text' class='text-input' data-field='comment' value='{{ row.comment | default(value="") }}' /></td>
{% endif %}
<td>
<button class="delete-btn" onclick="deleteRow(this)">🗑️</button>
</td>