mecha10-behavior-runtime 0.6.2

Behavior tree runtime for Mecha10 - unified AI and logic composition system
Documentation
//! Action nodes that inspect sensor state.

use crate::{BehaviorNode, Context, NodeStatus};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use serde_json::Value;

/// SensorCheckNode - Checks sensor state
///
/// Subscribes to a sensor topic and checks if a condition is met.
///
/// # Configuration
///
/// ```json
/// {
///   "type": "sensor_check",
///   "config": {
///     "topic": "/sensors/obstacle",
///     "field": "distance",
///     "operator": "less_than",
///     "threshold": 0.5
///   }
/// }
/// ```
#[derive(Debug)]
pub struct SensorCheckNode {
    #[allow(dead_code)] // TODO: Implement sensor subscription
    topic: String,
    field: String,
    operator: ComparisonOperator,
    threshold: f64,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
enum ComparisonOperator {
    LessThan,
    GreaterThan,
    Equal,
}

#[derive(Debug, Serialize, Deserialize)]
struct SensorCheckConfig {
    topic: String,
    field: String,
    operator: ComparisonOperator,
    threshold: f64,
}

impl SensorCheckNode {
    /// Create a new SensorCheckNode from JSON configuration
    pub fn from_json(config: Value) -> anyhow::Result<Self> {
        let cfg: SensorCheckConfig = serde_json::from_value(config)?;
        Ok(Self {
            topic: cfg.topic,
            field: cfg.field,
            operator: cfg.operator,
            threshold: cfg.threshold,
        })
    }
}

#[async_trait]
impl BehaviorNode for SensorCheckNode {
    async fn tick(&mut self, _ctx: &Context) -> anyhow::Result<NodeStatus> {
        // TODO: Implement sensor checking once we have a get_latest_from_path method
        // For now, return Success to allow testing of behavior tree composition
        tracing::debug!(
            "SensorCheckNode: checking {} {} {}",
            self.field,
            match self.operator {
                ComparisonOperator::LessThan => "<",
                ComparisonOperator::GreaterThan => ">",
                ComparisonOperator::Equal => "==",
            },
            self.threshold
        );
        Ok(NodeStatus::Success)
    }

    fn name(&self) -> &str {
        "SensorCheckNode"
    }
}