#include <Arduino.h>
#include <stdint.h>
#include <string.h>
// Hardware Pin Mappings
constexpr uint8_t VALVE_PIN_1 = 18;
constexpr uint8_t VALVE_PIN_2 = 19;
constexpr uint8_t SOIL_SENSOR_PIN = 34;
// Operational Timing & Threshold Constants
constexpr uint32_t PULSE_DURATION_MS = 30;
constexpr uint32_t WATERING_DURATION_MS = 1000; // Reduced for simulation speed
constexpr float INFERENCE_THRESHOLD = 0.65f; // ML Model Activation Probability
// Zero-Heap Static Data Structure
struct GreenhouseTelemetry {
uint32_t cycle_count;
uint16_t soil_moisture;
float ambient_temp;
bool valve_is_open;
float ml_prediction_score;
};
class EdgeInferenceEngine {
public:
// Simulated quantized TinyML weights
const float weights[2] = {-0.0015f, 0.085f};
const float bias = -1.2f;
float predict(uint16_t moisture, float temp) {
float raw_logit = (static_cast<float>(moisture) * weights[0]) + (temp * weights[1]) + bias;
float probability = 1.0f / (1.0f + expf(-raw_logit));
return probability;
}
};
class GreenhouseController {
private:
GreenhouseTelemetry telemetry_;
EdgeInferenceEngine ml_engine_;
public:
GreenhouseController() {
memset(&telemetry_, 0, sizeof(GreenhouseTelemetry));
}
void init() {
pinMode(VALVE_PIN_1, OUTPUT);
pinMode(VALVE_PIN_2, OUTPUT);
digitalWrite(VALVE_PIN_1, LOW);
digitalWrite(VALVE_PIN_2, LOW);
pinMode(SOIL_SENSOR_PIN, INPUT);
telemetry_.cycle_count++;
}
void triggerValve(bool open) {
if (open) {
digitalWrite(VALVE_PIN_1, HIGH);
digitalWrite(VALVE_PIN_2, LOW);
} else {
digitalWrite(VALVE_PIN_1, LOW);
digitalWrite(VALVE_PIN_2, HIGH);
}
delay(PULSE_DURATION_MS);
digitalWrite(VALVE_PIN_1, LOW);
digitalWrite(VALVE_PIN_2, LOW);
telemetry_.valve_is_open = open;
}
void evaluateAndExecute() {
telemetry_.soil_moisture = analogRead(SOIL_SENSOR_PIN);
telemetry_.ambient_temp = 35.0f; // Simulated microclimate heat spike
// Run Edge AI Inference
telemetry_.ml_prediction_score = ml_engine_.predict(telemetry_.soil_moisture, telemetry_.ambient_temp);
Serial.printf("Inference Score: %.2f\n", telemetry_.ml_prediction_score);
// Edge Decision Logic driven by the model score
bool needsWater = (telemetry_.ml_prediction_score >= INFERENCE_THRESHOLD);
if (needsWater && !telemetry_.valve_is_open) {
Serial.println("Edge AI Alert: Stress threshold met. Opening valve...");
triggerValve(true);
delay(WATERING_DURATION_MS);
Serial.println("Closing valve.");
triggerValve(false);
} else {
Serial.println("Conditions optimal according to edge model. Staying idle.");
}
}
};
static GreenhouseController controller;
void setup() {
Serial.begin(115200);
delay(500);
controller.init();
Serial.println("ESP32 Edge AI Greenhouse Initialized (Zero-Heap & Low-Power).");
}
void loop() {
controller.evaluateAndExecute();
// Low Power Battery Conservation: Enter deep sleep
Serial.println("Entering deep sleep for battery preservation...\n");
Serial.flush();
esp_deep_sleep(1000000ULL * 10); // 10 seconds for quick Wokwi testing
}Loading
esp32-devkit-c-v4
esp32-devkit-c-v4