Last active
December 18, 2024 10:02
-
-
Save thinkier/eca6d7c2ac82de35cd03c40d304902cc to your computer and use it in GitHub Desktop.
Self-watering planter with MQTT analytics
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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