Modbus-Table-Konfigurationen ausgelagert
This commit is contained in:
1 parent
84eb4b2365
commit
b9bc0e52d3
7 files changed
+157
-89
No files matched your search
@@ -0,0 +1,32 @@
|
||||
use std::sync::{Mutex, Arc};
|
||||
use tera::Tera;
|
||||
use crate::config::{AppConfig, ModbusValueMaps};
|
||||
|
||||
pub struct AppState {
|
||||
pub config: Mutex<AppConfig>,
|
||||
pub value_maps: Arc<Mutex<ModbusValueMaps>>,
|
||||
pub templates: Tera,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub 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 = serde_yaml::from_str(&conf_str).expect("Config-Deserialisierung fehlgeschlagen");
|
||||
|
||||
let value_maps = Arc::new(Mutex::new(ModbusValueMaps::from_config(&config)));
|
||||
|
||||
let tera = match Tera::new("templates/**/*") {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
println!("Template parsing error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
AppState {
|
||||
config: Mutex::new(config),
|
||||
value_maps,
|
||||
templates: tera,
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-10
@@ -1,5 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use crate::modbus_types::{ModbusRegisterConfig, ModbusCoilsConfig};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct DefaultConfig {
|
||||
@@ -35,15 +36,7 @@ pub struct InfluxConfig {
|
||||
pub measurement: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ModbusRegisterConfig {
|
||||
pub addr: u16,
|
||||
pub r#type: Option<String>,
|
||||
pub factor: Option<f64>,
|
||||
pub mqtt: Option<bool>,
|
||||
pub influxdb: Option<bool>,
|
||||
pub comment: Option<String>,
|
||||
}
|
||||
// ModbusRegisterConfig und ModbusCoilsConfig werden jetzt aus modbus_types.rs importiert
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct AppConfig {
|
||||
@@ -51,7 +44,7 @@ pub struct AppConfig {
|
||||
pub mqtt: MqttConfig,
|
||||
pub influxdb: InfluxConfig,
|
||||
pub modbus: ModbusConfig,
|
||||
pub modbus_coils: Option<Vec<HashMap<String, ModbusRegisterConfig>>>,
|
||||
pub modbus_coils: Option<Vec<HashMap<String, ModbusCoilsConfig>>>,
|
||||
pub modbus_input_register: Option<Vec<HashMap<String, ModbusRegisterConfig>>>,
|
||||
pub modbus_holding_register: Option<Vec<HashMap<String, ModbusRegisterConfig>>>,
|
||||
}
|
||||
|
||||
+94
-75
@@ -1,44 +1,18 @@
|
||||
use actix_web::{web, App, HttpResponse, HttpServer, Result};
|
||||
use actix_files as actix_fs;
|
||||
use std::sync::{Mutex, Arc};
|
||||
use tera::{Context, Tera};
|
||||
use std::sync::{Arc};
|
||||
use tera::Context;
|
||||
use std::fs;
|
||||
use serde_yaml;
|
||||
use std::collections::HashMap;
|
||||
use serde::{Serialize, Deserialize};
|
||||
mod config;
|
||||
mod modbus;
|
||||
use crate::config::{AppConfig, ModbusRegisterConfig, ModbusValueMaps};
|
||||
|
||||
|
||||
struct AppState {
|
||||
config: Mutex<AppConfig>,
|
||||
value_maps: Arc<Mutex<ModbusValueMaps>>,
|
||||
templates: Tera,
|
||||
}
|
||||
|
||||
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 = serde_yaml::from_str(&conf_str).expect("Config-Deserialisierung fehlgeschlagen");
|
||||
|
||||
let value_maps = Arc::new(Mutex::new(ModbusValueMaps::from_config(&config)));
|
||||
|
||||
let tera = match Tera::new("templates/**/*") {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
println!("Template parsing error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
AppState {
|
||||
config: Mutex::new(config),
|
||||
value_maps,
|
||||
templates: tera,
|
||||
}
|
||||
}
|
||||
}
|
||||
mod app_state;
|
||||
pub mod modbus_types;
|
||||
use crate::config::{AppConfig, ModbusValueMaps};
|
||||
use crate::modbus_types::{ModbusRegisterConfig, ModbusCoilsConfig};
|
||||
use crate::app_state::AppState;
|
||||
|
||||
async fn index(data: web::Data<AppState>) -> Result<HttpResponse> {
|
||||
let config = data.config.lock().unwrap();
|
||||
@@ -67,37 +41,63 @@ async fn table_page(data: web::Data<AppState>, path: web::Path<String>) -> Resul
|
||||
let config = data.config.lock().unwrap();
|
||||
let value_maps = data.value_maps.lock().unwrap();
|
||||
let mut context = Context::new();
|
||||
let (rows, value_map) = match table_id.as_str() {
|
||||
"modbus_input_register" => (
|
||||
config.modbus_input_register.clone().unwrap_or_default(),
|
||||
&value_maps.modbus_input_register_values
|
||||
),
|
||||
"modbus_holding_register" => (
|
||||
config.modbus_holding_register.clone().unwrap_or_default(),
|
||||
&value_maps.modbus_holding_register_values
|
||||
),
|
||||
"modbus_coils" => (
|
||||
config.modbus_coils.clone().unwrap_or_default(),
|
||||
&value_maps.modbus_coils_values
|
||||
),
|
||||
_ => return Ok(HttpResponse::NotFound().body("Table not found")),
|
||||
};
|
||||
let mut sorted_rows = rows;
|
||||
sorted_rows.sort_by(|a, b| {
|
||||
let addr_a = a.values().next().map(|v| v.addr).unwrap_or(0);
|
||||
let addr_b = b.values().next().map(|v| v.addr).unwrap_or(0);
|
||||
addr_a.cmp(&addr_b)
|
||||
});
|
||||
context.insert("rows", &sorted_rows);
|
||||
context.insert("table_id", &table_id);
|
||||
context.insert("active_page", &table_id);
|
||||
context.insert("value_map", value_map);
|
||||
let html = data.templates.render("index.html", &context)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template error")
|
||||
})?;
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(html))
|
||||
match table_id.as_str() {
|
||||
"modbus_input_register" => {
|
||||
let mut rows = config.modbus_input_register.clone().unwrap_or_default();
|
||||
rows.sort_by(|a, b| {
|
||||
let addr_a = a.values().next().map(|v| v.addr).unwrap_or(0);
|
||||
let addr_b = b.values().next().map(|v| v.addr).unwrap_or(0);
|
||||
addr_a.cmp(&addr_b)
|
||||
});
|
||||
context.insert("rows", &rows);
|
||||
context.insert("table_id", &table_id);
|
||||
context.insert("active_page", &table_id);
|
||||
context.insert("value_map", &value_maps.modbus_input_register_values);
|
||||
let html = data.templates.render("index.html", &context)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template error")
|
||||
})?;
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(html))
|
||||
}
|
||||
"modbus_holding_register" => {
|
||||
let mut rows = config.modbus_holding_register.clone().unwrap_or_default();
|
||||
rows.sort_by(|a, b| {
|
||||
let addr_a = a.values().next().map(|v| v.addr).unwrap_or(0);
|
||||
let addr_b = b.values().next().map(|v| v.addr).unwrap_or(0);
|
||||
addr_a.cmp(&addr_b)
|
||||
});
|
||||
context.insert("rows", &rows);
|
||||
context.insert("table_id", &table_id);
|
||||
context.insert("active_page", &table_id);
|
||||
context.insert("value_map", &value_maps.modbus_holding_register_values);
|
||||
let html = data.templates.render("index.html", &context)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template error")
|
||||
})?;
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(html))
|
||||
}
|
||||
"modbus_coils" => {
|
||||
let mut rows = config.modbus_coils.clone().unwrap_or_default();
|
||||
rows.sort_by(|a, b| {
|
||||
let addr_a = a.values().next().map(|v| v.addr).unwrap_or(0);
|
||||
let addr_b = b.values().next().map(|v| v.addr).unwrap_or(0);
|
||||
addr_a.cmp(&addr_b)
|
||||
});
|
||||
context.insert("rows", &rows);
|
||||
context.insert("table_id", &table_id);
|
||||
context.insert("active_page", &table_id);
|
||||
context.insert("value_map", &value_maps.modbus_coils_values);
|
||||
let html = data.templates.render("index.html", &context)
|
||||
.map_err(|e| {
|
||||
eprintln!("Template error: {}", e);
|
||||
actix_web::error::ErrorInternalServerError("Template error")
|
||||
})?;
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(html))
|
||||
}
|
||||
_ => Ok(HttpResponse::NotFound().body("Table not found")),
|
||||
}
|
||||
}
|
||||
|
||||
async fn settings_page(data: web::Data<AppState>) -> Result<HttpResponse> {
|
||||
@@ -122,10 +122,17 @@ async fn settings_page(data: web::Data<AppState>) -> Result<HttpResponse> {
|
||||
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
enum SaveTableRows {
|
||||
Register(Vec<HashMap<String, ModbusRegisterConfig>>),
|
||||
Coils(Vec<HashMap<String, ModbusCoilsConfig>>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SaveTableRequest {
|
||||
table_id: String,
|
||||
rows: Vec<HashMap<String, ModbusRegisterConfig>>,
|
||||
rows: SaveTableRows,
|
||||
}
|
||||
|
||||
async fn save_table(
|
||||
@@ -134,17 +141,29 @@ async fn save_table(
|
||||
) -> Result<HttpResponse> {
|
||||
let mut config = data.config.lock().unwrap();
|
||||
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",
|
||||
match req.table_id.as_str() {
|
||||
"modbus_input_register" => {
|
||||
if let SaveTableRows::Register(rows) = req.rows.clone() {
|
||||
config.modbus_input_register = Some(rows);
|
||||
} else {
|
||||
return Ok(HttpResponse::BadRequest().body("Falscher Typ für input_register"));
|
||||
}
|
||||
}
|
||||
"modbus_holding_register" => {
|
||||
if let SaveTableRows::Register(rows) = req.rows.clone() {
|
||||
config.modbus_holding_register = Some(rows);
|
||||
} else {
|
||||
return Ok(HttpResponse::BadRequest().body("Falscher Typ für holding_register"));
|
||||
}
|
||||
}
|
||||
"modbus_coils" => {
|
||||
if let SaveTableRows::Coils(rows) = req.rows.clone() {
|
||||
config.modbus_coils = Some(rows);
|
||||
} else {
|
||||
return Ok(HttpResponse::BadRequest().body("Falscher Typ für coils"));
|
||||
}
|
||||
}
|
||||
_ => return Ok(HttpResponse::BadRequest().body("Invalid table_id")),
|
||||
};
|
||||
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,
|
||||
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
use crate::config::{ModbusValueMaps, ModbusRegisterConfig, ModbusConfig};
|
||||
use crate::config::{ModbusValueMaps, ModbusConfig};
|
||||
use crate::modbus_types::{ModbusRegisterConfig, ModbusCoilsConfig};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
@@ -9,7 +10,7 @@ pub fn start_modbus_polling_thread(
|
||||
_modbus_config: &ModbusConfig,
|
||||
input_registers: &Option<Vec<HashMap<String, ModbusRegisterConfig>>>,
|
||||
holding_registers: &Option<Vec<HashMap<String, ModbusRegisterConfig>>>,
|
||||
coils: &Option<Vec<HashMap<String, ModbusRegisterConfig>>>,
|
||||
coils: &Option<Vec<HashMap<String, ModbusCoilsConfig>>>,
|
||||
value_maps: Arc<Mutex<ModbusValueMaps>>,
|
||||
poll_interval: Duration,
|
||||
) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ModbusCoilsConfig {
|
||||
pub addr: u16,
|
||||
pub write: Option<bool>,
|
||||
pub mqtt: Option<bool>,
|
||||
pub influxdb: Option<bool>,
|
||||
pub comment: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ModbusRegisterConfig {
|
||||
pub addr: u16,
|
||||
pub r#type: Option<String>,
|
||||
pub factor: Option<f64>,
|
||||
pub mqtt: Option<bool>,
|
||||
pub influxdb: Option<bool>,
|
||||
pub comment: Option<String>,
|
||||
}
|
||||
Reference in new issue
Block a user