demeter

Autonomous Hydroponic Intelligence

agent/Sentinel/Encoders/TimeSeries.py (1985B)


 1import numpy as np
 2
 3class SensorEncoder:
 4    # 🔧 CONFIG: Define the maximum possible value for each sensor.
 5    # We divide raw values by this to get a 0-1 range.
 6    SCALERS = {
 7        "pH": 14.0,       # pH Scale is 0-14
 8        "EC": 5.0,        # EC rarely exceeds 3.0-4.0 in hydroponics
 9        "temp": 50.0,     # 50°C (122°F) is a safe max for plants
10        "humidity": 100.0 # 0-100%
11    }
12
13    def encode(self, sensor_data: dict) -> np.ndarray:
14        """
15        Encodes sensor data into a NORMALIZED vector for balanced search.
16        
17        Example: 
18          Input:  {'humidity': 72.0}
19          Vector: [0.72] (Balanced for math)
20          Payload: {'humidity': 72.0} (Readable for humans)
21        """
22        features = []
23        
24        # Sort keys to ensure vector consistency (EC, humidity, pH, temp)
25        for key in sorted(sensor_data.keys()):
26            raw_val = sensor_data[key]
27            
28            # Determine the divisor (Default to 100.0 if unknown sensor)
29            max_val = self.SCALERS.get(key, 100.0)
30
31            if isinstance(raw_val, list) and raw_val:
32                # Handle Window (Mean, Std, Last)
33                arr = np.array(raw_val, dtype=float)
34                
35                # Normalize each statistic
36                mean_norm = np.mean(arr) / max_val
37                std_norm = np.std(arr) / max_val
38                last_norm = arr[-1] / max_val
39                
40                features.extend([mean_norm, std_norm, last_norm])
41
42            elif isinstance(raw_val, (int, float)):
43                # Handle Single Value
44                norm_val = float(raw_val) / max_val
45                
46                # Clamp to ensure we never break the 0-1 scale (e.g. if temp is 55)
47                norm_val = max(0.0, min(1.0, norm_val))
48                
49                features.append(norm_val)
50            else:
51                features.append(0.0)
52                
53        return np.array(features, dtype=np.float32)