Prototype of the first automation stull ugly

This commit is contained in:
Valère Plantevin
2026-05-12 14:00:12 -04:00
parent 20d59ed0ba
commit 7f54aea439
9 changed files with 152 additions and 4 deletions

View File

@@ -91,7 +91,9 @@ pub(super) fn threshold_for(t: SensorType) -> f64 {
SensorType::Temperature => 22.0, // °C — simulator oscillates 15..25
SensorType::Humidity => 55.0, // % — 30..70
SensorType::Pressure => 1014.0, // hPa — 1008..1018
SensorType::Voltage => 230.2, // V — 229.5..230.5
SensorType::Voltage => 230.5, // V — 229..231
SensorType::Current => 10.5, // A — 8..12
SensorType::Presence => 1.0, // s — Trigger threshold
SensorType::Relay => f64::INFINITY, // Actuator state, no threshold
}
}

View File

@@ -41,7 +41,10 @@ impl Plugin for WorldPlugin {
PreUpdate,
systems::ingest_system.run_if(in_state(ServerState::Started)),
)
.add_systems(Update, systems::simulation_system)
.add_systems(
Update,
(systems::simulation_system, systems::automation_system).chain(),
)
.add_systems(
PostUpdate,
(systems::export_system, systems::diagnostics_system).chain(),

View File

@@ -144,6 +144,38 @@ fn upsert_reading(
registry.map.insert(key, entity);
}
/// Closed-loop automation triggered by T1/T2 sensor data, affecting a T3 actuator.
pub(super) fn automation_system(
mut registry: ResMut<SensorRegistry>,
mut commands: Commands,
mut p: ParamSet<(
Query<(&DeviceId, &SensorTypeTag, &RawSensorData), Changed<RawSensorData>>,
Query<&mut RawSensorData>,
)>,
) {
let mut triggers = Vec::new();
for (dev_id, tag, data) in p.p0().iter() {
if tag.0 == SensorType::Presence {
// Trigger threshold: 1.0 seconds
let relay_state = if data.raw_value < 1.0 { 1.0 } else { 0.0 };
triggers.push((dev_id.0, relay_state));
}
}
let mut q = p.p1();
for (device_id, relay_state) in triggers {
let msg = QuicMessage {
device_id,
sensor_id: 6, // Relay is always 6 in our industrial profile
raw_value: relay_state,
timestamp_us: now_us(),
sequence_number: 0,
sensor_type: SensorType::Relay.as_u8(),
};
upsert_reading(&mut registry, &mut commands, &mut q, msg);
}
}
/// Per-sensor digital-twin transform. Pulls each entity's latest
/// `RawSensorData` into a sliding-window mean (`SmoothedValue`), and emits