Skip to main content

mecha10_behavior_runtime/actions/
sensing.rs

1//! Action nodes that inspect sensor state.
2
3use crate::{BehaviorNode, Context, NodeStatus};
4use async_trait::async_trait;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8/// SensorCheckNode - Checks sensor state
9///
10/// Subscribes to a sensor topic and checks if a condition is met.
11///
12/// # Configuration
13///
14/// ```json
15/// {
16///   "type": "sensor_check",
17///   "config": {
18///     "topic": "/sensors/obstacle",
19///     "field": "distance",
20///     "operator": "less_than",
21///     "threshold": 0.5
22///   }
23/// }
24/// ```
25#[derive(Debug)]
26pub struct SensorCheckNode {
27    #[allow(dead_code)] // TODO: Implement sensor subscription
28    topic: String,
29    field: String,
30    operator: ComparisonOperator,
31    threshold: f64,
32}
33
34#[derive(Debug, Serialize, Deserialize)]
35#[serde(rename_all = "snake_case")]
36enum ComparisonOperator {
37    LessThan,
38    GreaterThan,
39    Equal,
40}
41
42#[derive(Debug, Serialize, Deserialize)]
43struct SensorCheckConfig {
44    topic: String,
45    field: String,
46    operator: ComparisonOperator,
47    threshold: f64,
48}
49
50impl SensorCheckNode {
51    /// Create a new SensorCheckNode from JSON configuration
52    pub fn from_json(config: Value) -> anyhow::Result<Self> {
53        let cfg: SensorCheckConfig = serde_json::from_value(config)?;
54        Ok(Self {
55            topic: cfg.topic,
56            field: cfg.field,
57            operator: cfg.operator,
58            threshold: cfg.threshold,
59        })
60    }
61}
62
63#[async_trait]
64impl BehaviorNode for SensorCheckNode {
65    async fn tick(&mut self, _ctx: &Context) -> anyhow::Result<NodeStatus> {
66        // TODO: Implement sensor checking once we have a get_latest_from_path method
67        // For now, return Success to allow testing of behavior tree composition
68        tracing::debug!(
69            "SensorCheckNode: checking {} {} {}",
70            self.field,
71            match self.operator {
72                ComparisonOperator::LessThan => "<",
73                ComparisonOperator::GreaterThan => ">",
74                ComparisonOperator::Equal => "==",
75            },
76            self.threshold
77        );
78        Ok(NodeStatus::Success)
79    }
80
81    fn name(&self) -> &str {
82        "SensorCheckNode"
83    }
84}