higrow/src/main.cpp

270 lines
7.6 KiB
C++

#include <Adafruit_Sensor.h>
#include <ArduinoJson.h>
#include <BH1750.h>
#include <DHT.h>
#include <DHT_U.h>
#include <ESPAsyncWebServer.h>
#include <ESPDash.h>
#include <IotWebConf.h>
#include <AsyncMqttClient.h>
#define I2C_SDA 25
#define I2C_SCL 26
#define DHT12_PIN 16
#define BAT_ADC 33
#define SALT_PIN 34
#define SOIL_PIN 32
#define BOOT_PIN 0
#define POWER_CTRL 4
#define USER_BUTTON 35
BH1750 lightMeter;
DHT_Unified dht(DHT12_PIN, DHT11);
#define STRING_LEN 128
// Configuration specific key. The value should be modified if config structure was changed.
#define CONFIG_VERSION "hgr1"
// Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "hiGrow";
// Initial password to connect to the Thing, when it creates an own Access Point.
const char wifiInitialApPassword[] = "test1234";
char mqttServerValue[STRING_LEN];
char mqttUserNameValue[STRING_LEN];
char mqttUserPasswordValue[STRING_LEN];
char mqttTopicValue[STRING_LEN];
IotWebConfSeparator separator1 = IotWebConfSeparator();
IotWebConfParameter mqttServerParam = IotWebConfParameter("MQTT server", "mqttServer", mqttServerValue, STRING_LEN);
IotWebConfParameter mqttUserNameParam = IotWebConfParameter("MQTT user", "mqttUser", mqttUserNameValue, STRING_LEN);
IotWebConfParameter mqttUserPasswordParam = IotWebConfParameter("MQTT password", "mqttPass", mqttUserPasswordValue, STRING_LEN, "password");
IotWebConfParameter mqttTopicParam = IotWebConfParameter("MQTT topic", "mqttTopic", mqttTopicValue, STRING_LEN);
DNSServer dnsServer;
AsyncWebServer server(80);
AsyncCallbackWebHandler* rootHandler;
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
AsyncMqttClient mqttClient;
uint16_t soil = 0;
uint32_t salt = 0;
float bat = 0;
float temperature = 0;
float humidity = 0;
float lux = 0;
bool needMqttReconnect = true;
/**
* Handle web requests to "/" path.
*/
void handleRoot(AsyncWebServerRequest* request)
{
// -- Let IotWebConf test and handle captive portal requests.
if (iotWebConf.handleCaptivePortal(request)) {
// -- Captive portal request were already served.
return;
}
String s = F("<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>");
s += F("<title>IotWebConf 01 Minimal</title></head><body>Hello world!");
s += F("Go to <a href='config'>configure page</a> to change settings.");
s += F("</body></html>\n");
request->send(200, "text/html", s);
}
void handleValues(AsyncWebServerRequest* request)
{
StaticJsonDocument<200> doc;
doc[F("temperature")] = temperature;
doc[F("humidity")] = humidity;
doc[F("soil")] = soil;
doc[F("salt")] = salt;
doc[F("battery")] = bat;
doc[F("lux")] = lux;
String output;
serializeJson(doc, output);
request->send(200, "application/json", output);
}
void wifiConnected()
{
Serial.println("WiFi was connected.");
if (server.removeHandler(rootHandler)) {
Serial.println("Root handler disabled.");
}
ESPDash.init(server);
}
uint32_t readSalt()
{
uint8_t samples = 120;
uint32_t humi = 0;
uint16_t array[120];
for (int i = 0; i < samples; i++) {
array[i] = analogRead(SALT_PIN);
delay(2);
}
std::sort(array, array + samples);
for (int i = 0; i < samples; i++) {
if (i == 0 || i == samples - 1)
continue;
humi += array[i];
}
humi /= samples - 2;
return humi;
}
uint16_t readSoil()
{
uint16_t soil = analogRead(SOIL_PIN);
return map(soil, 0, 4095, 100, 0);
}
float readBattery()
{
int vref = 1100;
uint16_t volt = analogRead(BAT_ADC);
float battery_voltage = ((float)volt / 4095.0) * 2.0 * 3.3 * (vref);
return battery_voltage;
}
void configSaved()
{
Serial.println("Configuration was updated.");
needMqttReconnect = true;
}
boolean formValidator(AsyncWebServerRequest* request)
{
Serial.println("Validating form.");
boolean valid = true;
if (request->arg(mqttServerParam.getId()).length() > 0
&& request->arg(mqttTopicParam.getId()).length() == 0) {
mqttTopicParam.errorMessage = "Please provide at least 1 character!";
valid = false;
}
return valid;
}
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting up...");
// Init IotWebConf
iotWebConf.setWifiConnectionCallback(&wifiConnected);
iotWebConf.addParameter(&separator1);
iotWebConf.addParameter(&mqttServerParam);
iotWebConf.addParameter(&mqttUserNameParam);
iotWebConf.addParameter(&mqttUserPasswordParam);
iotWebConf.addParameter(&mqttTopicParam);
iotWebConf.setConfigSavedCallback(&configSaved);
iotWebConf.setFormValidator(&formValidator);
if (!iotWebConf.init()) {
mqttServerValue[0] = '\0';
mqttUserNameValue[0] = '\0';
mqttUserPasswordValue[0] = '\0';
}
// Init WebServer
rootHandler = new AsyncCallbackWebHandler();
rootHandler->setUri("/");
rootHandler->setMethod(HTTP_GET);
rootHandler->onRequest(handleRoot);
server.addHandler(rootHandler);
server.on("/config", HTTP_ANY, [](AsyncWebServerRequest* request) { iotWebConf.handleConfig(request); });
server.on("/values", HTTP_GET, handleValues);
server.onNotFound([](AsyncWebServerRequest* request) { iotWebConf.handleNotFound(request); });
server.begin();
// Init Dashboard
ESPDash.addTemperatureCard("temp", "Temperature/C", 0, 0);
ESPDash.addHumidityCard("hum", "Humidity/%", 0);
ESPDash.addNumberCard("lux", "BH1750/lx", 0);
ESPDash.addHumidityCard("soil", "Soil", 0);
ESPDash.addNumberCard("salt", "Salt", 0);
ESPDash.addNumberCard("batt", "Battery/mV", 0);
Wire.begin(I2C_SDA, I2C_SCL);
dht.begin();
//! Sensor power control pin , use deteced must set high
pinMode(POWER_CTRL, OUTPUT);
digitalWrite(POWER_CTRL, 1);
delay(1000);
Wire.begin();
if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
Serial.println(F("BH1750 Advanced begin"));
} else {
Serial.println(F("Error initialising BH1750"));
}
Serial.println("Ready.");
}
void loop()
{
static uint64_t timestamp;
iotWebConf.doLoop();
if (needMqttReconnect) {
Serial.println("Reconfigure & reconnect MqTT");
if (String(mqttServerValue) != "") {
mqttClient.setServer(mqttServerValue, 1883);
mqttClient.connect();
}
needMqttReconnect = false;
}
if (millis() - timestamp > 1000) {
timestamp = millis();
// Read brightness
lux = lightMeter.readLightLevel();
sensors_event_t event;
// Read temperature
dht.temperature().getEvent(&event);
temperature = event.temperature;
// Read humidity
dht.humidity().getEvent(&event);
humidity = event.relative_humidity;
// Read soil
soil = readSoil();
// Read salt
salt = readSalt();
// Read battery
bat = readBattery();
// Update Dashboard
if (!isnan(temperature)) {
ESPDash.updateTemperatureCard("temp", (int)temperature);
}
if (!isnan(humidity)) {
ESPDash.updateHumidityCard("hum", (int)humidity);
}
ESPDash.updateNumberCard("lux", (int)lux);
ESPDash.updateHumidityCard("soil", (int)soil);
ESPDash.updateNumberCard("salt", (int)salt);
ESPDash.updateNumberCard("batt", (int)bat);
Serial.printf("DHTT:%.2f H:%.2f Lux:%.2f Soil:%u Salt:%u Bat:%.2f\r\n",
temperature, humidity, lux, soil, salt, bat);
}
}