Skip to content

Instantly share code, notes, and snippets.

@thinkier
Last active December 18, 2024 10:02
Show Gist options
  • Save thinkier/eca6d7c2ac82de35cd03c40d304902cc to your computer and use it in GitHub Desktop.
Save thinkier/eca6d7c2ac82de35cd03c40d304902cc to your computer and use it in GitHub Desktop.
Self-watering planter with MQTT analytics
#include <WiFi.h>
#include <MQTT.h>
#include <ArduinoJson.h>
#include "arduino_secrets.h"
#include <algorithm>
WiFiClient net;
MQTTClient client;
#define PIN_PUMP 12
#define PIN_HYGRO 28
uint16_t hygrometer_exposed_len = 3;
uint16_t hygrometer_max_depth = 12;
uint16_t hygrometer_calibration_air = 880;
uint16_t hygrometer_calibration_wet = hygrometer_calibration_air * hygrometer_exposed_len / hygrometer_max_depth;
void connect() {
while (WiFi.status() != WL_CONNECTED) {
Serial.print("^");
delay(1000);
}
while (!client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS)) {
Serial.print("=");
delay(1000);
}
Serial.println("\nconnected!");
}
void setup() {
pinMode(PIN_HYGRO, INPUT);
pinMode(PIN_PUMP, OUTPUT);
digitalWrite(PIN_PUMP, LOW);
Serial.begin(115200);
WiFi.hostname(STANAME);
WiFi.begin(STASSID, STAPSK);
client.begin(MQTT_HOST, MQTT_PORT, net);
connect();
}
void loop() {
client.loop();
delay(50);
if (!client.connected()) {
connect();
}
unsigned long thisMillis = millis();
static unsigned long lastMillis = 0;
// publish a message roughly every second.
if (thisMillis - lastMillis > 2000 || thisMillis < lastMillis) {
lastMillis = thisMillis;
String json;
JsonDocument doc;
updateSensors(doc);
serializeJson(doc, json);
client.publish(MQTT_PUB_TOPIC, json);
}
}
void updateSensors(JsonDocument &doc) {
uint8_t vwc = volumetricWaterContentFromAnalog(PIN_HYGRO);
bool pumping = digitalRead(PIN_PUMP);
static uint64_t pumpStart = 0;
if (vwc < 50) {
digitalWrite(PIN_PUMP, HIGH);
if (!pumping) {
pumpStart = millis();
pumping = true;
}
} else if (vwc > 75) {
digitalWrite(PIN_PUMP, LOW);
if (pumping) {
doc["total_pump_time"] = millis() - pumpStart;
pumping = false;
}
}
doc["volumetric_water_content"] = vwc;
doc["pump"] = (bool) pumping;
if (pumping) {
doc["pump_time"] = millis() - pumpStart;
}
}
uint8_t volumetricWaterContentFromAnalog(uint8_t pin) {
float reading = std::clamp((uint16_t)analogRead(pin), hygrometer_calibration_wet, hygrometer_calibration_air) - hygrometer_calibration_wet;
return 100 - (float) (reading * 100 / (hygrometer_calibration_air - hygrometer_calibration_wet));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment