sl-perception dc6eea4016 feat: Add weather awareness system (Issue #442)
Implements sensor fusion for environmental monitoring and adaptive outdoor behavior:
- BME280 environmental sensor (temperature, humidity, pressure)
- Phone weather API fallback (wind speed, conditions)
- Camera-based rain detection (image gradient analysis)
- WeatherState.msg with condition bitmask and recommendations
- Behavior triggers: rain→seek shelter, wind→reduce speed, extreme temp→warning
- Facial expressions: squint (rain), shiver (cold), relax (comfortable)
- Real-time publishing: /saltybot/weather (WeatherState), /saltybot/weather_alert (String)
- Adaptive thresholds: temp_min_safe, temp_max_safe, wind_threshold

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-05 09:04:20 -05:00

79 lines
2.5 KiB
Python

"""
Basic tests for weather awareness system.
"""
import pytest
import numpy as np
from saltybot_weather.weather_node import RainDetector
class TestRainDetector:
"""Tests for rain detection algorithm."""
def test_rain_detector_init(self):
"""Test rain detector initialization."""
detector = RainDetector()
assert len(detector.history) == 0
def test_rain_detector_clear_frame(self):
"""Test rain detection on clear (low-noise) frame."""
detector = RainDetector()
# Create a smooth, clear frame (low gradient)
frame = np.ones((480, 640, 3), dtype=np.uint8) * 128
prob = detector.detect(frame)
# Clear frame should have low rain probability
assert 0.0 <= prob <= 1.0
assert prob < 0.3
def test_rain_detector_noisy_frame(self):
"""Test rain detection on noisy (rain-like) frame."""
detector = RainDetector()
# Create a noisy frame (high gradient, rain-like)
np.random.seed(42)
frame = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8)
prob = detector.detect(frame)
assert 0.0 <= prob <= 1.0
def test_rain_detector_empty_frame(self):
"""Test rain detection with empty/None frame."""
detector = RainDetector()
prob = detector.detect(None)
assert prob == 0.0
def test_rain_detector_smoothing(self):
"""Test rain detection history smoothing."""
detector = RainDetector()
# Simulate alternating clear and noisy frames
clear = np.ones((480, 640, 3), dtype=np.uint8) * 128
noisy = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8)
probs = []
for i in range(10):
frame = noisy if i % 2 == 0 else clear
probs.append(detector.detect(frame))
# History should have 10 elements
assert len(detector.history) == 10
# Probabilities should be bounded
assert all(0.0 <= p <= 1.0 for p in probs)
class TestWeatherState:
"""Basic WeatherState message tests."""
def test_weather_state_creation(self):
"""Test creating a WeatherState message."""
try:
from saltybot_weather_msgs.msg import WeatherState
ws = WeatherState()
ws.temperature = 25.0
ws.humidity = 60.0
assert ws.temperature == 25.0
assert ws.humidity == 60.0
except ImportError:
pytest.skip("saltybot_weather_msgs not built")
if __name__ == '__main__':
pytest.main([__file__])