#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
// --- Hardware setup ---
#define DHTPIN 15
#define DHTTYPE DHT22
#define LDRPIN 34
#define BUTTON_PIN 0
DHT dht(DHTPIN, DHTTYPE);
// --- WiFi + MQTT ---
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "broker.hivemq.com";
WiFiClient espClient;
PubSubClient client(espClient);
// --- FreeRTOS handles ---
QueueHandle_t sensorQueue;
SemaphoreHandle_t otaSem;
// --- Data structures ---
struct SensorData {
float temp;
float hum;
int light;
};
// --- Tasks ---
void SensorTask(void *pvParameters) {
while (1) {
SensorData data;
data.temp = dht.readTemperature();
data.hum = dht.readHumidity();
data.light = analogRead(LDRPIN);
xQueueSend(sensorQueue, &data, portMAX_DELAY);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
void MqttTask(void *pvParameters) {
while (1) {
if (!client.connected()) {
while (!client.connected()) {
if (client.connect("esp32-wokwi-demo")) {
client.subscribe("greenhouse/cmd/ota");
} else {
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
}
client.loop();
SensorData data;
if (xQueueReceive(sensorQueue, &data, 0) == pdTRUE) {
char msg[100];
sprintf(msg, "{\"temp\":%.2f,\"hum\":%.2f,\"light\":%d}", data.temp, data.hum, data.light);
client.publish("greenhouse/telemetry", msg);
Serial.println(msg);
}
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
}
void OtaTask(void *pvParameters) {
while (1) {
if (xSemaphoreTake(otaSem, portMAX_DELAY)) {
Serial.println("OTA Update triggered (simulated in Wokwi)!");
// Real OTA would use HTTP GET here
}
}
}
// --- MQTT callback ---
void callback(char* topic, byte* payload, unsigned int length) {
String msg;
for (int i = 0; i < length; i++) msg += (char)payload[i];
if (String(topic) == "greenhouse/cmd/ota") {
xSemaphoreGive(otaSem);
}
}
// --- Setup ---
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(BUTTON_PIN, INPUT_PULLUP);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); }
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
sensorQueue = xQueueCreate(5, sizeof(SensorData));
otaSem = xSemaphoreCreateBinary();
xTaskCreate(SensorTask, "SensorTask", 4096, NULL, 1, NULL);
xTaskCreate(MqttTask, "MqttTask", 4096, NULL, 1, NULL);
xTaskCreate(OtaTask, "OtaTask", 4096, NULL, 1, NULL);
// Button ISR to trigger OTA
attachInterrupt(BUTTON_PIN, []() { xSemaphoreGiveFromISR(otaSem, NULL); }, FALLING);
}
void loop() {
// Nothing here (tasks handle everything)
}