Schreibe MQTT.Set Werte, wenn das Leitsystem aktiv ist
Build Docker Image (Podman) / build (push) Failing after 15m52s
Build Docker Image (Podman) / build (push) Failing after 15m52s
This commit is contained in:
1 parent
497a0e48e3
commit
3ed80f4b68
6 files changed
+278
-39
No files matched your search
+107
@@ -1,5 +1,6 @@
|
||||
use crate::config::{ModbusValueMaps, ModbusConfig};
|
||||
use crate::modbus_types::{ModbusInputRegisterConfig, ModbusHoldingRegisterConfig, ModbusCoilsConfig};
|
||||
use crate::config::AppConfig;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
@@ -9,6 +10,112 @@ use tokio_modbus::prelude::*;
|
||||
use tokio_modbus::client::tcp;
|
||||
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
|
||||
pub fn start_modbus_polling_thread(
|
||||
modbus_config: &ModbusConfig,
|
||||
|
||||
Reference in new issue
Block a user