Value Maps angelegt

This commit is contained in:
Eric Neuber 2026-01-05 21:53:18 +01:00
parent 09c41821c8
commit 7a8758d8cc
2 changed files with 72 additions and 9 deletions

View File

@ -63,9 +63,17 @@ pub struct AppConfig {
pub modbus_holding_register: Option<Vec<HashMap<String, ModbusRegisterConfig>>>, pub modbus_holding_register: Option<Vec<HashMap<String, ModbusRegisterConfig>>>,
} }
/// Werthaltung für berechnete Modbus-Werte
#[derive(Debug, Default, Clone)]
pub struct ModbusValueMaps {
pub modbus_coils_values: std::collections::HashMap<String, f64>,
pub modbus_input_register_values: std::collections::HashMap<String, f64>,
pub modbus_holding_register_values: std::collections::HashMap<String, f64>,
}
struct AppState { struct AppState {
config: Mutex<AppConfig>, config: Mutex<AppConfig>,
value_maps: Mutex<ModbusValueMaps>,
templates: Tera, templates: Tera,
} }
@ -74,6 +82,8 @@ impl AppState {
let conf_str = std::fs::read_to_string(conf_path).expect("Config-Datei konnte nicht gelesen werden"); 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 config: AppConfig = serde_yaml::from_str(&conf_str).expect("Config-Deserialisierung fehlgeschlagen");
let value_maps = Mutex::new(ModbusValueMaps::from_config(&config));
let tera = match Tera::new("templates/**/*") { let tera = match Tera::new("templates/**/*") {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
@ -84,15 +94,50 @@ impl AppState {
AppState { AppState {
config: Mutex::new(config), config: Mutex::new(config),
value_maps,
templates: tera, templates: tera,
} }
} }
} }
impl ModbusValueMaps {
pub fn from_config(config: &AppConfig) -> Self {
let mut coils = HashMap::new();
if let Some(ref vec) = config.modbus_coils {
for map in vec {
for key in map.keys() {
coils.entry(key.clone()).or_insert(0.0);
}
}
}
let mut input = HashMap::new();
if let Some(ref vec) = config.modbus_input_register {
for map in vec {
for key in map.keys() {
input.entry(key.clone()).or_insert(0.0);
}
}
}
let mut holding = HashMap::new();
if let Some(ref vec) = config.modbus_holding_register {
for map in vec {
for key in map.keys() {
holding.entry(key.clone()).or_insert(0.0);
}
}
}
ModbusValueMaps {
modbus_coils_values: coils,
modbus_input_register_values: input,
modbus_holding_register_values: holding,
}
}
}
async fn index(data: web::Data<AppState>) -> Result<HttpResponse> { async fn index(data: web::Data<AppState>) -> Result<HttpResponse> {
let config = data.config.lock().unwrap(); let config = data.config.lock().unwrap();
let value_maps = data.value_maps.lock().unwrap();
let mut context = Context::new(); let mut context = Context::new();
// modbus_input_register als rows, sortiert nach addr
let mut rows = config.modbus_input_register.clone().unwrap_or_default(); let mut rows = config.modbus_input_register.clone().unwrap_or_default();
rows.sort_by(|a, b| { rows.sort_by(|a, b| {
let addr_a = a.values().next().map(|v| v.addr).unwrap_or(0); let addr_a = a.values().next().map(|v| v.addr).unwrap_or(0);
@ -102,6 +147,7 @@ async fn index(data: web::Data<AppState>) -> Result<HttpResponse> {
context.insert("rows", &rows); context.insert("rows", &rows);
context.insert("table_id", "modbus_input_register"); context.insert("table_id", "modbus_input_register");
context.insert("active_page", "modbus_input_register"); context.insert("active_page", "modbus_input_register");
context.insert("value_map", &value_maps.modbus_input_register_values);
let html = data.templates.render("index.html", &context) let html = data.templates.render("index.html", &context)
.map_err(|e| { .map_err(|e| {
eprintln!("Template error: {}", e); eprintln!("Template error: {}", e);
@ -113,22 +159,33 @@ async fn index(data: web::Data<AppState>) -> Result<HttpResponse> {
async fn table_page(data: web::Data<AppState>, path: web::Path<String>) -> Result<HttpResponse> { async fn table_page(data: web::Data<AppState>, path: web::Path<String>) -> Result<HttpResponse> {
let table_id = path.into_inner(); let table_id = path.into_inner();
let config = data.config.lock().unwrap(); let config = data.config.lock().unwrap();
let value_maps = data.value_maps.lock().unwrap();
let mut context = Context::new(); let mut context = Context::new();
let mut rows = match table_id.as_str() { let (rows, value_map) = match table_id.as_str() {
"modbus_input_register" => config.modbus_input_register.clone().unwrap_or_default(), "modbus_input_register" => (
"modbus_holding_register" => config.modbus_holding_register.clone().unwrap_or_default(), config.modbus_input_register.clone().unwrap_or_default(),
"modbus_coils" => config.modbus_coils.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")), _ => return Ok(HttpResponse::NotFound().body("Table not found")),
}; };
rows.sort_by(|a, b| { 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_a = a.values().next().map(|v| v.addr).unwrap_or(0);
let addr_b = b.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) addr_a.cmp(&addr_b)
}); });
context.insert("rows", &rows); context.insert("rows", &sorted_rows);
context.insert("table_id", &table_id); context.insert("table_id", &table_id);
context.insert("active_page", &table_id); context.insert("active_page", &table_id);
context.insert("value_map", value_map);
let html = data.templates.render("index.html", &context) let html = data.templates.render("index.html", &context)
.map_err(|e| { .map_err(|e| {
eprintln!("Template error: {}", e); eprintln!("Template error: {}", e);
@ -198,7 +255,11 @@ async fn save_settings(
settings: web::Json<AppConfig>, settings: web::Json<AppConfig>,
) -> Result<HttpResponse> { ) -> Result<HttpResponse> {
let mut config = data.config.lock().unwrap(); let mut config = data.config.lock().unwrap();
*config = settings.into_inner(); let new_config = settings.into_inner();
// Value-Maps neu initialisieren
let mut value_maps = data.value_maps.lock().unwrap();
*value_maps = ModbusValueMaps::from_config(&new_config);
*config = new_config;
let conf_path = "paramod.yaml"; let conf_path = "paramod.yaml";
let yaml_str = match serde_yaml::to_string(&*config) { let yaml_str = match serde_yaml::to_string(&*config) {
Ok(s) => s, Ok(s) => s,

View File

@ -33,6 +33,7 @@
<thead> <thead>
<tr> <tr>
<th>Bezeichnung</th> <th>Bezeichnung</th>
<th>Wert</th>
<th>Adresse</th> <th>Adresse</th>
{% if table_id == "modbus_coils" %} {% if table_id == "modbus_coils" %}
<th>Write</th> <th>Write</th>
@ -53,6 +54,7 @@
{% for key, row in entry %} {% for key, row in entry %}
<tr data-row="{{ loop.index0 }}"> <tr data-row="{{ loop.index0 }}">
<td><input type='text' class='text-input' data-field='key' value='{{ key }}' /></td> <td><input type='text' class='text-input' data-field='key' value='{{ key }}' /></td>
<td>{{ value_map[key] | default(value="-") }}</td>
<td><input type='number' class='text-input' data-field='addr' value='{{ row.addr }}' /></td> <td><input type='number' class='text-input' data-field='addr' value='{{ row.addr }}' /></td>
{% if table_id == "modbus_coils" %} {% if table_id == "modbus_coils" %}
<td> <td>