Files
ClearGrow Agent ec5904846b
Some checks failed
ClearGrow Controller CI / Run Unit Tests (push) Has been cancelled
ClearGrow Controller CI / Build Development Firmware (push) Has been cancelled
ClearGrow Controller CI / Build Production Firmware (push) Has been cancelled
ClearGrow Controller CI / CI Status Summary (push) Has been cancelled
Initial commit: migrate from GitHub
2025-12-10 09:31:10 -07:00
..
2025-12-10 09:31:10 -07:00
2025-12-10 09:31:10 -07:00
2025-12-10 09:31:10 -07:00

ClearGrow Anomaly Detection Models

This directory contains TensorFlow Lite models for the TinyML anomaly detection feature.

Current Status

ML Feature Status: DISABLED (CONFIG_CLEARGROW_ENABLE_ML=n)

Model File: anomaly_detector.tflite is present (placeholder model, 30.6 KB INT8 quantized)

The ML feature is disabled by default in sdkconfig.defaults. A placeholder model file is provided in the repository for build testing and initial integration. This model is untrained and will produce random results - it is suitable only for testing the TFLite inference pipeline, not for production anomaly detection.

Model Requirements

If you want to enable the ML anomaly detection feature, you must provide a trained model:

Model Specifications

Property Value Notes
Input Shape (1, 60, 6) Batch=1, 60 time steps, 6 features
Output Shape (1, 60, 6) Autoencoder reconstruction
Input Features 6 temp, humidity, VPD, CO2, leaf_temp, PPFD
Operations FullyConnected, ReLU, Reshape, Mul, Add, Mean Registered in tflite_runner.cc
Quantization INT8 (recommended) or FP32 INT8 faster on ESP32-S3
Tensor Arena <256KB Allocated in PSRAM
Format TFLite v3 FlatBuffers schema version

Input Features (in order)

  1. Temperature (°C) - Air temperature
  2. Humidity (%) - Relative humidity
  3. VPD (kPa) - Vapor Pressure Deficit
  4. CO2 (ppm) - Carbon dioxide concentration
  5. Leaf Temperature (°C) - Infrared leaf surface temp
  6. PPFD (µmol/m²/s) - Photosynthetic Photon Flux Density

Normalization

The model expects normalized inputs (z-score):

normalized_value = (raw_value - mean) / std

Current normalization parameters (hardcoded in anomaly_detector.c):

Feature Mean Std Dev
Temperature 24.0°C 5.0°C
Humidity 60.0% 15.0%
VPD 1.0 kPa 0.3 kPa
CO2 800 ppm 300 ppm
Leaf Temp 22.0°C 3.0°C
PPFD 400 µmol/m²/s 200 µmol/m²/s

Important: If you retrain the model with different normalization, update these values in components/tflite_runner/src/anomaly_detector.c lines 30-46.

Placeholder Model (Included)

A placeholder model (anomaly_detector.tflite, 30.6 KB) is included in the repository. This was generated using generate_placeholder_model.py and is suitable for:

  • Build testing with CONFIG_CLEARGROW_ENABLE_ML=y
  • Integration testing of the TFLite inference pipeline
  • Development without real sensor data

WARNING: The placeholder model is untrained and will produce random/meaningless results. Do not use in production.

Regenerating the Placeholder Model

If you need to regenerate the placeholder model:

Prerequisites

  • Python 3.7+
  • TensorFlow 2.x
# Create virtual environment (recommended)
python3 -m venv venv
source venv/bin/activate
pip install tensorflow

Generate Model

cd /root/cleargrow/controller/models
python3 generate_placeholder_model.py

This creates anomaly_detector.tflite with the following characteristics:

  • Architecture: Simple autoencoder (Flatten → Dense(32) → Dense(360) → Reshape)
  • Size: ~30 KB (INT8 quantized)
  • Input/Output: (1, 60, 6) float32
  • Operations: FullyConnected, ReLU, Reshape (all registered in tflite_runner.cc)
  • Training: None (random weights)

Using Docker (if TensorFlow not available locally)

cd /root/cleargrow/controller/models
docker run --rm -v $(pwd):/models python:3.10 bash -c "
    pip install tensorflow && \
    cd /models && \
    python3 generate_placeholder_model.py
"

Note: The placeholder model is already included in the repository, so regeneration is only needed if you've modified generate_placeholder_model.py.

Training a Real Model

For production deployment, train on actual sensor data:

1. Collect Training Data

Collect at least 7-30 days of sensor data from normally operating grow rooms:

  • All 6 sensor types
  • 1Hz sampling rate
  • Only use periods with no known anomalies/issues
  • Include variation in day/night cycles, growth stages

Export from data logger or use /api/v1/export/history REST endpoint.

2. Train Autoencoder

import tensorflow as tf
import numpy as np
import pandas as pd

# Load your sensor data
data = pd.read_csv('sensor_history.csv')

# Extract features (temp, humidity, vpd, co2, leaf_temp, ppfd)
features = data[['temperature', 'humidity', 'vpd', 'co2', 'leaf_temp', 'ppfd']].values

# Normalize (save mean/std for deployment)
mean = features.mean(axis=0)
std = features.std(axis=0)
normalized = (features - mean) / std

# Create sequences of 60 time steps
def create_sequences(data, window=60):
    sequences = []
    for i in range(len(data) - window + 1):
        sequences.append(data[i:i+window])
    return np.array(sequences)

X_train = create_sequences(normalized)

# Build autoencoder
model = tf.keras.Sequential([
    tf.keras.layers.InputLayer(input_shape=(60, 6)),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(32, activation='relu'),
    tf.keras.layers.Dense(360),
    tf.keras.layers.Reshape((60, 6))
])

model.compile(optimizer='adam', loss='mse')
model.fit(X_train, X_train, epochs=50, batch_size=32, validation_split=0.2)

3. Convert to TFLite

# INT8 quantization
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]

def representative_dataset():
    for i in range(100):
        yield [X_train[i:i+1].astype(np.float32)]

converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.float32
converter.inference_output_type = tf.float32

tflite_model = converter.convert()

with open('anomaly_detector.tflite', 'wb') as f:
    f.write(tflite_model)

4. Update Normalization Parameters

Edit /root/cleargrow/controller/components/tflite_runner/src/anomaly_detector.c:

static const float feature_means[INPUT_FEATURES] = {
    mean[0],  /* temperature */
    mean[1],  /* humidity */
    mean[2],  /* VPD */
    mean[3],  /* CO2 */
    mean[4],  /* leaf_temp */
    mean[5]   /* PPFD */
};

static const float feature_stds[INPUT_FEATURES] = {
    std[0], std[1], std[2], std[3], std[4], std[5]
};

5. Tune Threshold

The anomaly threshold (default 0.7) may need tuning:

// anomaly_detector.c line 21
#define ANOMALY_THRESHOLD 0.7f  // Adjust based on validation data

Use ROC curve analysis on validation data with known anomalies to find optimal threshold.

Enabling the Feature

Once you have a trained model:

  1. Place anomaly_detector.tflite in this directory
  2. Enable in sdkconfig.defaults:
    CONFIG_CLEARGROW_ENABLE_ML=y
    
    Or via menuconfig:
    idf.py menuconfig
    # → ClearGrow Configuration → Enable TinyML anomaly detection
    
  3. Rebuild and flash:
    idf.py build flash monitor
    
  4. Monitor initialization:
    I (1234) tflite: Initializing TensorFlow Lite Micro...
    I (1240) tflite: Model schema version: 3
    I (1245) tflite: Tensor arena: 256 KB in PSRAM
    I (1250) tflite: Arena used: 45678 bytes (17.8%)
    I (1255) anomaly: TFLite anomaly detection task started
    

Monitoring

When ML is enabled, watch for anomaly detection logs:

W (12345) anomaly: Anomaly detected! Score: 1.234
W (12346) anomaly: Anomaly detected with score: 1.234

Anomaly events are posted to the event system but are not currently handled by automation (see Gap CTRL-ML-003 in assessment).

Memory Usage

Check tensor arena usage in logs:

I (1250) tflite: Arena used: 45678 bytes (17.8%)

If approaching 100%, increase TENSOR_ARENA_SIZE in tflite_runner.cc line 20.

Troubleshooting

Build fails: "No such file: anomaly_detector.tflite"

  • ML is enabled but model file missing
  • Solution: Disable ML in sdkconfig or generate placeholder model

Inference fails: "AllocateTensors() failed"

  • Model too large for 256KB arena
  • Solution: Simplify model or increase TENSOR_ARENA_SIZE

Low accuracy / too many false positives

  • Normalization parameters don't match training data
  • Threshold too low
  • Model undertrained
  • Solution: Retrain with more data, tune threshold

Inference timeout errors

  • Model too complex for 5s timeout
  • Solution: Simplify model or increase INFERENCE_TIMEOUT_MS in tflite_runner.cc

References

  • CTRL-ML-001 (Critical): Model file missing - ADDRESSED by disabling feature
  • CTRL-ML-002 (Low): CONFIG not documented - RESOLVED by this README + Kconfig
  • CTRL-ML-003 (High): No automation handler for anomaly events - TODO
  • CTRL-ML-004 (Medium): No UI for ML feature - TODO
  • CTRL-ML-005 (Low): Hardcoded normalization params - DOCUMENTED