Merge branch 'develop' of https://git.it.hs-heilbronn.de/auribest/smart_garden into mseyfrie_dev
This commit is contained in:
commit
9ca90ccc46
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
|||||||
.vscode/c_cpp_properties.json
|
.vscode/c_cpp_properties.json
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/ipch
|
.vscode/ipch
|
||||||
|
.vs
|
||||||
|
|||||||
@ -13,6 +13,7 @@ platform = espressif32
|
|||||||
board = az-delivery-devkit-v4
|
board = az-delivery-devkit-v4
|
||||||
framework = arduino
|
framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
; build_flags = -DCORE_DEBUG_LEVEL=5
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
439 #ID of Lightsensor library BH1750
|
439 #ID of Lightsensor library BH1750
|
||||||
@ -24,4 +25,4 @@ lib_deps =
|
|||||||
; MQTT@^2.4.7
|
; MQTT@^2.4.7
|
||||||
PubSubClient@^2.8
|
PubSubClient@^2.8
|
||||||
ArduinoNvs@^2.5
|
ArduinoNvs@^2.5
|
||||||
; ESPRandom@^1.3.3
|
ESPRandom@^1.3.3
|
||||||
@ -1,8 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Code for the Capacitive Soil Moisture Sensor
|
Code for the Capacitive Soil Moisture Sensor
|
||||||
*/
|
*/
|
||||||
|
#include <common.h>
|
||||||
#include <header.h>
|
|
||||||
|
|
||||||
const int numReadings = 20;
|
const int numReadings = 20;
|
||||||
|
|
||||||
@ -10,24 +9,24 @@ void setupCapacitiveSoilMoistureSensor() {
|
|||||||
// pinMode(PIN_MS, INPUT);
|
// pinMode(PIN_MS, INPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int readCapacitiveSoilMoistureSensor()
|
int readCapacitiveSoilMoistureSensor() {
|
||||||
{
|
|
||||||
int total = 0; // the running total
|
int total = 0; // the running total
|
||||||
// read from the sensor:
|
// read from the sensor:
|
||||||
for (int readIndex = 0; readIndex < numReadings; readIndex++)
|
for (int readIndex = 0; readIndex < numReadings; readIndex++) {
|
||||||
{
|
|
||||||
total = total + analogRead(PIN_MS);
|
total = total + analogRead(PIN_MS);
|
||||||
delay(2);
|
delay(2);
|
||||||
}
|
}
|
||||||
int measurement = total / numReadings;
|
int measurement = total / numReadings;
|
||||||
Serial.print("soil moisture raw: ");
|
|
||||||
Serial.println(measurement);
|
|
||||||
// add the reading to the total:
|
|
||||||
//int measurement = analogRead(PIN_MS);
|
|
||||||
|
|
||||||
if (map(measurement, VALUE_AIR, VALUE_WATER, 0, 100) < 0) {
|
int finalRes = map(measurement, VALUE_AIR, VALUE_WATER, 0, 100);
|
||||||
|
Serial.print("current soil moisture: ");
|
||||||
|
Serial.println(finalRes);
|
||||||
|
|
||||||
|
if (finalRes < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (map(measurement, VALUE_AIR, VALUE_WATER, 0, 100) > 100) {
|
} else if (finalRes > 100) {
|
||||||
return 100;
|
return 100;
|
||||||
} else {return map(measurement, VALUE_AIR, VALUE_WATER, 0, 100);}
|
} else {
|
||||||
|
return finalRes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
2
src/capacitiveSoilMoistureSensor.h
Normal file
2
src/capacitiveSoilMoistureSensor.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
void setupCapacitiveSoilMoistureSensor();
|
||||||
|
int readCapacitiveSoilMoistureSensor();
|
||||||
46
src/common.h
Normal file
46
src/common.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// PUBLISH FREQUENCY (MS)
|
||||||
|
#define FREQUENCY 60000
|
||||||
|
|
||||||
|
// fix for core panic during wifi initialization
|
||||||
|
// #define configMINIMAL_STACK_SIZE 4096
|
||||||
|
// #define CONFIG_TIMER_TASK_STACK_SIZE 8192
|
||||||
|
|
||||||
|
// BH1750 lightsensor
|
||||||
|
#define MIN_LIGHT 0
|
||||||
|
#define MAX_LIGHT 54612
|
||||||
|
|
||||||
|
// DHT11
|
||||||
|
#define PIN_DHT11 14
|
||||||
|
|
||||||
|
// MQ-135
|
||||||
|
#define PIN_MQ135_A 12
|
||||||
|
#define PIN_MQ135_D 13
|
||||||
|
|
||||||
|
// MOISTURE SENSOR // A7
|
||||||
|
#define PIN_MS 35
|
||||||
|
#define VALUE_WATER 1650
|
||||||
|
#define VALUE_AIR 3500
|
||||||
|
|
||||||
|
// Ventil
|
||||||
|
#define PIN_VALVE 32
|
||||||
|
#define MAX_VALVE_TIMEOUT 5000
|
||||||
|
|
||||||
|
// STATUS LED
|
||||||
|
#define PIN_LED_R 2
|
||||||
|
#define PIN_LED_G 0
|
||||||
|
#define PIN_LED_B 4
|
||||||
|
|
||||||
|
// LIGHT LED
|
||||||
|
#define LIGHT_LED_PIN_R 27
|
||||||
|
#define LIGHT_LED_PIN_G 26
|
||||||
|
#define LIGHT_LED_PIN_B 25
|
||||||
|
#define MAX_LIGHT_TIMEOUT (FREQUENCY - 5)
|
||||||
|
|
||||||
|
// MQTT
|
||||||
|
#define MQTT_HOST "mqtt.timovolkmann.de"
|
||||||
|
#define MQTT_PORT 1883
|
||||||
|
#define MQTT_TOPIC_BASE_SUB "smartgarden/commands"
|
||||||
|
#define MQTT_TOPIC_BASE_PUB "smartgarden/updates"
|
||||||
|
#define MQTT_PATH_SUB MQTT_TOPIC_BASE_SUB "/#"
|
||||||
@ -1,20 +1,26 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
// #include <MQTT.h>
|
#include <AutoConnect.h>
|
||||||
#include <PubSubClient.h>
|
#include <PubSubClient.h>
|
||||||
#include <header.h>
|
#include <WebServer.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <store.h>
|
||||||
|
#include <valve.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/timers.h"
|
#include "freertos/timers.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MQTT_VALVE_COMMAND MQTT_TOPIC_BASE_SUB "/" MQTT_DEVICE_ID "/valve"
|
#include <connections.h>
|
||||||
#define MQTT_SOIL_PROPERTIES MQTT_TOPIC_BASE_SUB "/" MQTT_DEVICE_ID "/soil"
|
|
||||||
|
char MQTT_VALVE_COMMAND[72];
|
||||||
|
char MQTT_SOIL_PROPERTIES[72];
|
||||||
|
char MQTT_LIGHT_PROPERTIES[72];
|
||||||
|
char MQTT_AUTO_PROPERTIES[72];
|
||||||
|
|
||||||
TimerHandle_t mqttReconnectTimer;
|
TimerHandle_t mqttReconnectTimer;
|
||||||
TimerHandle_t wifiReconnectTimer;
|
TimerHandle_t wifiReconnectTimer;
|
||||||
|
|
||||||
// TimerHandle_t mqttProcessingTimer;
|
|
||||||
TaskHandle_t mqttTask;
|
TaskHandle_t mqttTask;
|
||||||
|
|
||||||
WebServer Server;
|
WebServer Server;
|
||||||
@ -22,12 +28,10 @@ AutoConnect Portal(Server);
|
|||||||
WiFiClient client;
|
WiFiClient client;
|
||||||
|
|
||||||
AutoConnectConfig Config;
|
AutoConnectConfig Config;
|
||||||
// Config.autoReconnect = true;
|
|
||||||
// WiFi.config(Config);
|
|
||||||
// MQTTClient mqttClient;
|
|
||||||
PubSubClient mqttClient(client);
|
PubSubClient mqttClient(client);
|
||||||
|
|
||||||
void connectWiFi() {
|
void connectWiFi() {
|
||||||
|
yield();
|
||||||
Serial.println("Start WiFi...");
|
Serial.println("Start WiFi...");
|
||||||
if (Portal.begin()) {
|
if (Portal.begin()) {
|
||||||
digitalWrite(PIN_LED_G, HIGH);
|
digitalWrite(PIN_LED_G, HIGH);
|
||||||
@ -36,14 +40,15 @@ void connectWiFi() {
|
|||||||
|
|
||||||
void mqttLoop(void *parameter) {
|
void mqttLoop(void *parameter) {
|
||||||
do {
|
do {
|
||||||
|
yield();
|
||||||
mqttClient.loop();
|
mqttClient.loop();
|
||||||
delay(50);
|
delay(100);
|
||||||
} while (mqttClient.connected());
|
} while (mqttClient.connected());
|
||||||
Serial.println("Disconnected from MQTT.");
|
Serial.println("Disconnected from MQTT.");
|
||||||
if (!mqttClient.connected()) {
|
if (!mqttClient.connected()) {
|
||||||
Serial.println("Checking WiFi Connection.");
|
Serial.println("Checking WiFi Connection.");
|
||||||
if (WiFi.isConnected()) {
|
if (WiFi.isConnected()) {
|
||||||
Serial.println("Starting reconnect timer for MQTT.");
|
Serial.println("WiFi OK. Starting reconnect timer for MQTT.");
|
||||||
xTimerStart(mqttReconnectTimer, 0);
|
xTimerStart(mqttReconnectTimer, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,10 +56,13 @@ void mqttLoop(void *parameter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void connectMQTT() {
|
void connectMQTT() {
|
||||||
|
yield();
|
||||||
|
if (mqttClient.connected()) return;
|
||||||
Serial.println("Connecting to MQTT...");
|
Serial.println("Connecting to MQTT...");
|
||||||
// mqttClient.begin(MQTT_HOST, MQTT_PORT, client);
|
// mqttClient.begin(MQTT_HOST, MQTT_PORT, client);
|
||||||
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
|
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
|
||||||
mqttClient.connect(MQTT_DEVICE_ID);
|
mqttClient.disconnect();
|
||||||
|
mqttClient.connect(getDeviceIDcharArr());
|
||||||
if (mqttClient.connected()) {
|
if (mqttClient.connected()) {
|
||||||
Serial.println("Connected!");
|
Serial.println("Connected!");
|
||||||
} else {
|
} else {
|
||||||
@ -63,17 +71,17 @@ void connectMQTT() {
|
|||||||
mqttClient.subscribe(MQTT_PATH_SUB);
|
mqttClient.subscribe(MQTT_PATH_SUB);
|
||||||
Serial.print("subscribed to: ");
|
Serial.print("subscribed to: ");
|
||||||
Serial.println(MQTT_PATH_SUB);
|
Serial.println(MQTT_PATH_SUB);
|
||||||
xTaskCreate(
|
xTaskCreatePinnedToCore(
|
||||||
mqttLoop, /* Task function. */
|
mqttLoop,
|
||||||
"mqttLoop", /* String with name of task. */
|
"mqttLoop",
|
||||||
8192, /* Stack size in bytes. */
|
8192,
|
||||||
NULL, /* Parameter passed as input of the task */
|
NULL,
|
||||||
1, /* Priority of the task. */
|
2,
|
||||||
&mqttTask); /* Task handle. */
|
&mqttTask,
|
||||||
//xTimerStart(mqttProcessingTimer, 0);
|
1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiFiEvent(WiFiEvent_t event) {
|
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||||
Serial.printf("[WiFi-event] event: %d\n", event);
|
Serial.printf("[WiFi-event] event: %d\n", event);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case SYSTEM_EVENT_STA_GOT_IP:
|
case SYSTEM_EVENT_STA_GOT_IP:
|
||||||
@ -84,14 +92,18 @@ void WiFiEvent(WiFiEvent_t event) {
|
|||||||
break;
|
break;
|
||||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||||
digitalWrite(PIN_LED_G, LOW);
|
digitalWrite(PIN_LED_G, LOW);
|
||||||
|
// workaround for 202 auth failed bug: https://github.com/espressif/arduino-esp32/issues/2501
|
||||||
|
if (info.disconnected.reason == 202) {
|
||||||
|
Serial.println("weirdbehaviour");
|
||||||
|
Serial.println(info.disconnected.reason);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
|
xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
|
||||||
// xTimerStop(mqttProcessingTimer, 0);
|
|
||||||
xTimerStart(wifiReconnectTimer, 0);
|
xTimerStart(wifiReconnectTimer, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// void onMqttMessage(MQTTClient *client, char topic[], char payload[], int payload_length) {
|
|
||||||
void onMqttMessage(char *topic, byte *payload, unsigned int payload_length) {
|
void onMqttMessage(char *topic, byte *payload, unsigned int payload_length) {
|
||||||
Serial.print("Message arrived [");
|
Serial.print("Message arrived [");
|
||||||
Serial.print(topic);
|
Serial.print(topic);
|
||||||
@ -101,17 +113,27 @@ void onMqttMessage(char *topic, byte *payload, unsigned int payload_length) {
|
|||||||
}
|
}
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
|
if (strcmp(topic, MQTT_LIGHT_PROPERTIES) == 0) {
|
||||||
|
Serial.println("receiving light treshold...");
|
||||||
|
Serial.println(topic);
|
||||||
|
StaticJsonDocument<1024> doc;
|
||||||
|
DeserializationError err = deserializeJson(doc, payload);
|
||||||
|
if (err == DeserializationError::Ok) {
|
||||||
|
int nm = doc["nm"];
|
||||||
|
int minLX = doc["minLX"];
|
||||||
|
setLightProperties(nm, minLX);
|
||||||
|
} else {
|
||||||
|
Serial.println(err.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
if (strcmp(topic, MQTT_VALVE_COMMAND) == 0) {
|
if (strcmp(topic, MQTT_VALVE_COMMAND) == 0) {
|
||||||
Serial.println("toggling valve...");
|
Serial.println("toggling valve...");
|
||||||
Serial.println(topic);
|
Serial.println(topic);
|
||||||
toggleValve();
|
toggleValve(false);
|
||||||
}
|
}
|
||||||
if (strcmp(topic, MQTT_SOIL_PROPERTIES) == 0) {
|
if (strcmp(topic, MQTT_SOIL_PROPERTIES) == 0) {
|
||||||
Serial.println("receiving soil thresholds...");
|
Serial.println("receiving soil thresholds...");
|
||||||
Serial.println(topic);
|
Serial.println(topic);
|
||||||
//Serial.println(reinterpret_cast<const char *>(payload));
|
|
||||||
// Serial.println(payload);
|
|
||||||
// const int capacity = JSON_OBJECT_SIZE(3) + 2 * JSON_OBJECT_SIZE(1);
|
|
||||||
StaticJsonDocument<1024> doc;
|
StaticJsonDocument<1024> doc;
|
||||||
DeserializationError err = deserializeJson(doc, payload);
|
DeserializationError err = deserializeJson(doc, payload);
|
||||||
if (err == DeserializationError::Ok) {
|
if (err == DeserializationError::Ok) {
|
||||||
@ -123,28 +145,75 @@ void onMqttMessage(char *topic, byte *payload, unsigned int payload_length) {
|
|||||||
Serial.println(err.c_str());
|
Serial.println(err.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (strcmp(topic, MQTT_AUTO_PROPERTIES) == 0) {
|
||||||
|
Serial.println("receiving auto settings...");
|
||||||
|
Serial.println(topic);
|
||||||
|
StaticJsonDocument<1024> doc;
|
||||||
|
DeserializationError err = deserializeJson(doc, payload);
|
||||||
|
if (err == DeserializationError::Ok) {
|
||||||
|
bool ir = doc["irrigation"];
|
||||||
|
bool li = doc["light"];
|
||||||
|
setAutoProperties(li, ir);
|
||||||
|
} else {
|
||||||
|
Serial.println(err.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void constructMQTTpaths() {
|
||||||
|
strcpy(MQTT_VALVE_COMMAND, MQTT_TOPIC_BASE_SUB "/");
|
||||||
|
strcat(MQTT_VALVE_COMMAND, getDeviceIDcharArr());
|
||||||
|
strcat(MQTT_VALVE_COMMAND, "/valve");
|
||||||
|
|
||||||
|
strcpy(MQTT_SOIL_PROPERTIES, MQTT_TOPIC_BASE_SUB "/");
|
||||||
|
strcat(MQTT_SOIL_PROPERTIES, getDeviceIDcharArr());
|
||||||
|
strcat(MQTT_SOIL_PROPERTIES, "/soil");
|
||||||
|
|
||||||
|
strcpy(MQTT_LIGHT_PROPERTIES, MQTT_TOPIC_BASE_SUB "/");
|
||||||
|
strcat(MQTT_LIGHT_PROPERTIES, getDeviceIDcharArr());
|
||||||
|
strcat(MQTT_LIGHT_PROPERTIES, "/light");
|
||||||
|
|
||||||
|
strcpy(MQTT_AUTO_PROPERTIES, MQTT_TOPIC_BASE_SUB "/");
|
||||||
|
strcat(MQTT_AUTO_PROPERTIES, getDeviceIDcharArr());
|
||||||
|
strcat(MQTT_AUTO_PROPERTIES, "/automatic");
|
||||||
|
|
||||||
|
Serial.println("MQTT_COMMANDS:");
|
||||||
|
Serial.println(MQTT_VALVE_COMMAND);
|
||||||
|
Serial.println(MQTT_SOIL_PROPERTIES);
|
||||||
|
Serial.println(MQTT_LIGHT_PROPERTIES);
|
||||||
|
Serial.println(MQTT_AUTO_PROPERTIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupConnections() {
|
void setupConnections() {
|
||||||
|
constructMQTTpaths();
|
||||||
Serial.println();
|
Serial.println();
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
disableCore0WDT();
|
||||||
|
// disableCore1WDT();
|
||||||
|
Config.autoReconnect = true;
|
||||||
|
// Config.autoReset = true;
|
||||||
|
Portal.config(Config);
|
||||||
|
|
||||||
mqttReconnectTimer = xTimerCreate(
|
mqttReconnectTimer = xTimerCreate(
|
||||||
"mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0, reinterpret_cast<TimerCallbackFunction_t>(connectMQTT));
|
"mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0, reinterpret_cast<TimerCallbackFunction_t>(connectMQTT));
|
||||||
wifiReconnectTimer = xTimerCreate(
|
wifiReconnectTimer = xTimerCreate(
|
||||||
"wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0, reinterpret_cast<TimerCallbackFunction_t>(connectWiFi));
|
"wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0, reinterpret_cast<TimerCallbackFunction_t>(connectWiFi));
|
||||||
// mqttProcessingTimer = xTimerCreate(
|
|
||||||
// "messageTimer", pdMS_TO_TICKS(50), pdTRUE, (void *)0, reinterpret_cast<TimerCallbackFunction_t>(mqttLoop));
|
|
||||||
|
|
||||||
WiFi.onEvent(WiFiEvent);
|
WiFi.onEvent(WiFiEvent);
|
||||||
|
|
||||||
// mqttClient.onMessageAdvanced(onMqttMessage);
|
connectWiFi();
|
||||||
|
connectMQTT();
|
||||||
|
|
||||||
mqttClient.setCallback(onMqttMessage);
|
mqttClient.setCallback(onMqttMessage);
|
||||||
|
|
||||||
connectWiFi();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void publishMessage(const char *topic, const char *msg) {
|
void publishMessage(const char *topic, const char *msg) {
|
||||||
|
if(mqttClient.connected()) {
|
||||||
mqttClient.publish(topic, msg);
|
mqttClient.publish(topic, msg);
|
||||||
// mqttClient.publish(topic, msg, true, 1);
|
Serial.print(topic);
|
||||||
|
Serial.println(" successfully sent.");
|
||||||
|
} else {
|
||||||
|
Serial.println("couldn't send message. waiting for reconnect.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
src/connections.h
Normal file
5
src/connections.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
void connectWiFi();
|
||||||
|
void mqttLoop(void *parameter);
|
||||||
|
void connectMQTT();
|
||||||
|
void setupConnections();
|
||||||
|
void publishMessage(const char *topic, const char *msg);
|
||||||
78
src/header.h
78
src/header.h
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
Header file for the SmartGarden project
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define HEADER_H
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
#include <SPI.h>
|
|
||||||
#include <BH1750.h>
|
|
||||||
#include <Adafruit_Sensor.h>
|
|
||||||
#include <DHT.h>
|
|
||||||
#include <DHT_U.h>
|
|
||||||
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <WebServer.h>
|
|
||||||
#include <AutoConnect.h>
|
|
||||||
|
|
||||||
// fix for core panic during wifi initialization
|
|
||||||
// #define configMINIMAL_STACK_SIZE 2048
|
|
||||||
// #define CONFIG_TIMER_TASK_STACK_SIZE 8192
|
|
||||||
|
|
||||||
// DHT11
|
|
||||||
#define PIN_DHT11 14
|
|
||||||
|
|
||||||
// MQ-135
|
|
||||||
#define PIN_MQ135_A 12
|
|
||||||
#define PIN_MQ135_D 13
|
|
||||||
|
|
||||||
// MOISTURE SENSOR // A7
|
|
||||||
#define PIN_MS 35
|
|
||||||
#define VALUE_WATER 1650
|
|
||||||
#define VALUE_AIR 3500
|
|
||||||
|
|
||||||
// Ventil
|
|
||||||
#define PIN_VALVE 32
|
|
||||||
#define MAX_VALVE_TIMEOUT 10000
|
|
||||||
|
|
||||||
// LED
|
|
||||||
#define PIN_LED_R 2
|
|
||||||
#define PIN_LED_G 0
|
|
||||||
#define PIN_LED_B 4
|
|
||||||
|
|
||||||
// MQTT
|
|
||||||
#define MQTT_HOST "mqtt.timovolkmann.de"
|
|
||||||
#define MQTT_PORT 1883
|
|
||||||
#define MQTT_DEVICE_ID "esp-max"
|
|
||||||
#define MQTT_TOPIC_BASE_SUB "smartgarden/commands"
|
|
||||||
#define MQTT_TOPIC_BASE_PUB "smartgarden/updates"
|
|
||||||
#define MQTT_PATH_PUB MQTT_TOPIC_BASE_PUB "/" MQTT_DEVICE_ID "/"
|
|
||||||
#define MQTT_PATH_SUB MQTT_TOPIC_BASE_SUB "/#"
|
|
||||||
// MQTT_DEVICE_ID "/#"
|
|
||||||
|
|
||||||
// PUBLISH FREQUENCY (MS)
|
|
||||||
#define FREQUENCY 3000
|
|
||||||
|
|
||||||
// moisture
|
|
||||||
extern void setupCapacitiveSoilMoistureSensor();
|
|
||||||
extern int readCapacitiveSoilMoistureSensor();
|
|
||||||
|
|
||||||
// light
|
|
||||||
extern void setupLightSensor();
|
|
||||||
extern float readLightSensorValue();
|
|
||||||
|
|
||||||
// temperature & humidity
|
|
||||||
extern void setupTemperatureSensor();
|
|
||||||
extern float readHumidity();
|
|
||||||
extern float readTemperature();
|
|
||||||
|
|
||||||
// mqtt & wifi
|
|
||||||
extern void setupConnections();
|
|
||||||
extern void publishMessage(const char *topic, const char *msg);
|
|
||||||
|
|
||||||
// sensors
|
|
||||||
void readSensors();
|
|
||||||
void toggleValve();
|
|
||||||
void setSoilProperties(int FC, int PWP, int SAT);
|
|
||||||
void setupStore();
|
|
||||||
103
src/lightChecker.cpp
Normal file
103
src/lightChecker.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include <common.h>
|
||||||
|
#include <lightChecker.h>
|
||||||
|
|
||||||
|
// Bool to check if light is already active
|
||||||
|
bool lightActive = false;
|
||||||
|
// Colors in Array: purple, blue, green, yellow, orange, red, white
|
||||||
|
int colorValueArray[][3] = {{125,0,125}, {0,0,255}, {0,255,0}, {255,255,0}, {255,140,0}, {255,0,0}, {255,255,255}};
|
||||||
|
// Pointer for color array
|
||||||
|
int colorCounter = 6;
|
||||||
|
|
||||||
|
// Setting PWM properties
|
||||||
|
const int freq = 5000;
|
||||||
|
const int ledChannelRed = 0;
|
||||||
|
const int ledChannelGreen = 1;
|
||||||
|
const int ledChannelBlue= 2;
|
||||||
|
const int resolution = 8;
|
||||||
|
|
||||||
|
// Setup method for PWM configurations
|
||||||
|
void setupPWM() {
|
||||||
|
// Set pins as output
|
||||||
|
pinMode(LIGHT_LED_PIN_R, OUTPUT);
|
||||||
|
pinMode(LIGHT_LED_PIN_G, OUTPUT);
|
||||||
|
pinMode(LIGHT_LED_PIN_B, OUTPUT);
|
||||||
|
|
||||||
|
// Configure LED PWM functionalitites
|
||||||
|
ledcSetup(ledChannelRed, freq, resolution);
|
||||||
|
ledcSetup(ledChannelGreen, freq, resolution);
|
||||||
|
ledcSetup(ledChannelBlue, freq, resolution);
|
||||||
|
|
||||||
|
// Attach the channel to the GPIO2 to be controlled
|
||||||
|
ledcAttachPin(LIGHT_LED_PIN_R, ledChannelRed);
|
||||||
|
ledcAttachPin(LIGHT_LED_PIN_G, ledChannelGreen);
|
||||||
|
ledcAttachPin(LIGHT_LED_PIN_B, ledChannelBlue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes a int value representing nanometers and sets color array pointer to appropriate color
|
||||||
|
void setValueNM(int NM) {
|
||||||
|
getColorBasedOnValueNM(NM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logic to set color array pointer
|
||||||
|
void getColorBasedOnValueNM(int valueNM) {
|
||||||
|
if (valueNM <= 420) { // Purple
|
||||||
|
colorCounter = 0;
|
||||||
|
}
|
||||||
|
else if (valueNM <= 490) { // Blue
|
||||||
|
colorCounter = 1;
|
||||||
|
}
|
||||||
|
else if (valueNM <= 575) { // Green
|
||||||
|
colorCounter = 2;
|
||||||
|
}
|
||||||
|
else if (valueNM <= 585) { // Yellow
|
||||||
|
colorCounter = 3;
|
||||||
|
}
|
||||||
|
else if (valueNM <= 650) { // Orange
|
||||||
|
colorCounter = 4;
|
||||||
|
}
|
||||||
|
else if (valueNM > 650) { // 650 to 750 is Red
|
||||||
|
colorCounter = 5;
|
||||||
|
}
|
||||||
|
Serial.println("New color set based on: ");
|
||||||
|
Serial.print(valueNM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuts down the light
|
||||||
|
bool shutdownLight() {
|
||||||
|
ledcWrite(ledChannelRed, 0);
|
||||||
|
ledcWrite(ledChannelGreen, 0);
|
||||||
|
ledcWrite(ledChannelBlue, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activates the light based on colorValueArray
|
||||||
|
bool activateLight() {
|
||||||
|
ledcWrite(ledChannelRed, colorValueArray[colorCounter][0]);
|
||||||
|
ledcWrite(ledChannelGreen, colorValueArray[colorCounter][1]);
|
||||||
|
ledcWrite(ledChannelBlue, colorValueArray[colorCounter][2]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate light for given amount of time if not already activated
|
||||||
|
void lightTask(void *parameter) {
|
||||||
|
unsigned long lightTimeoutTimer = millis();
|
||||||
|
if (lightActive == false) {
|
||||||
|
lightActive = activateLight();
|
||||||
|
// If current time is below or equal to light timeout do nothing
|
||||||
|
while (millis() - lightTimeoutTimer <= MAX_LIGHT_TIMEOUT) {
|
||||||
|
}
|
||||||
|
lightActive = shutdownLight();
|
||||||
|
}
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger for lightTask
|
||||||
|
void triggerLight() {
|
||||||
|
xTaskCreate(
|
||||||
|
lightTask, /* Task function. */
|
||||||
|
"lightTask", /* String with name of task. */
|
||||||
|
2048, /* Stack size in bytes. */
|
||||||
|
NULL, /* Parameter passed as input of the task */
|
||||||
|
1, /* Priority of the task. */
|
||||||
|
NULL); /* Task handle. */
|
||||||
|
}
|
||||||
4
src/lightChecker.h
Normal file
4
src/lightChecker.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
void setupPWM();
|
||||||
|
void setValueNM(int NM);
|
||||||
|
void triggerLight();
|
||||||
|
void getColorBasedOnValueNM(int valueNM);
|
||||||
@ -1,14 +1,20 @@
|
|||||||
#include <header.h>
|
#include <Adafruit_Sensor.h>
|
||||||
|
#include <BH1750.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <lightSensor.h>
|
||||||
|
|
||||||
|
// New BH1750 class
|
||||||
BH1750 lightMeter;
|
BH1750 lightMeter;
|
||||||
|
|
||||||
|
// Setup for reading light sensor (prepares i2c communication)
|
||||||
void setupLightSensor() {
|
void setupLightSensor() {
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
lightMeter.begin();
|
lightMeter.begin();
|
||||||
Serial.println("Sensor started...");
|
Serial.println("Sensor started...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to read and return the light value measured by BH1750 sensor
|
||||||
float readLightSensorValue() {
|
float readLightSensorValue() {
|
||||||
float intensity = lightMeter.readLightLevel();
|
int intensity = lightMeter.readLightLevel();
|
||||||
return intensity;
|
return intensity;
|
||||||
}
|
}
|
||||||
2
src/lightSensor.h
Normal file
2
src/lightSensor.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
void setupLightSensor();
|
||||||
|
float readLightSensorValue();
|
||||||
21
src/main.cpp
21
src/main.cpp
@ -2,9 +2,13 @@
|
|||||||
Main file for the SmartGarden project
|
Main file for the SmartGarden project
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <header.h>
|
#include <common.h>
|
||||||
|
#include <sensors.h>
|
||||||
|
#include <store.h>
|
||||||
|
#include <connections.h>
|
||||||
|
|
||||||
#include <string>
|
#define TIME_TO_SLEEP 30
|
||||||
|
volatile int noSleepTasks = 0;
|
||||||
|
|
||||||
unsigned long sensorReadTimer = 0;
|
unsigned long sensorReadTimer = 0;
|
||||||
bool valveOpen = false;
|
bool valveOpen = false;
|
||||||
@ -20,23 +24,22 @@ void setup() {
|
|||||||
|
|
||||||
digitalWrite(PIN_VALVE, LOW);
|
digitalWrite(PIN_VALVE, LOW);
|
||||||
|
|
||||||
|
|
||||||
setupStore();
|
setupStore();
|
||||||
|
setupSensors();
|
||||||
setupConnections();
|
setupConnections();
|
||||||
setupLightSensor();
|
// esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000);
|
||||||
setupTemperatureSensor();
|
|
||||||
setupCapacitiveSoilMoistureSensor();
|
|
||||||
Serial.println("Setup complete...");
|
Serial.println("Setup complete...");
|
||||||
Serial.println();
|
Serial.println();
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
// First read without delay
|
||||||
|
readSensors();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
// read sensors
|
// Main loop: read sensors
|
||||||
if (millis() - sensorReadTimer >= FREQUENCY) {
|
if (millis() - sensorReadTimer >= FREQUENCY) {
|
||||||
readSensors();
|
readSensors();
|
||||||
sensorReadTimer = millis();
|
sensorReadTimer = millis();
|
||||||
}
|
}
|
||||||
// toggle valve
|
|
||||||
if (valveOpen) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
51
src/ntpManager.cpp
Normal file
51
src/ntpManager.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include <common.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <ntpManager.h>
|
||||||
|
|
||||||
|
// Url to ntp server
|
||||||
|
const char* ntpServer = "pool.ntp.org";
|
||||||
|
// Time offset based on gmt in seconds
|
||||||
|
const long gmtOffset_sec = 3600;
|
||||||
|
// Offset in seconds for daylight saving time
|
||||||
|
const int daylightOffset_sec = 3600;
|
||||||
|
|
||||||
|
// Start and end hour of the date
|
||||||
|
const int dayStart = 8;
|
||||||
|
const int dayEnd = 20;
|
||||||
|
// Time info structure comes from time.h
|
||||||
|
struct tm timeinfo;
|
||||||
|
|
||||||
|
// If wifi is connected configure time of esp32
|
||||||
|
void setupNTP() {
|
||||||
|
if (WiFi.isConnected()) {
|
||||||
|
Serial.println("WiFi OK. Getting Timestamp");
|
||||||
|
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
|
||||||
|
printTimestamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to check if it is currently day or night
|
||||||
|
bool checkForDay() {
|
||||||
|
printTimestamp();
|
||||||
|
if((getCurrentHour() > dayStart) && (getCurrentHour() < dayEnd)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to get current hour in 24 hour format
|
||||||
|
int getCurrentHour() {
|
||||||
|
int currentHour = timeinfo.tm_hour;
|
||||||
|
return currentHour;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to print a timestamp
|
||||||
|
void printTimestamp() {
|
||||||
|
if(!getLocalTime(&timeinfo)){
|
||||||
|
Serial.println("Failed to obtain time");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
|
||||||
|
}
|
||||||
4
src/ntpManager.h
Normal file
4
src/ntpManager.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
void setupNTP();
|
||||||
|
bool checkForDay();
|
||||||
|
int getCurrentHour();
|
||||||
|
void printTimestamp();
|
||||||
@ -1,150 +0,0 @@
|
|||||||
#include <ArduinoJson.h>
|
|
||||||
#include <ArduinoNvs.h>
|
|
||||||
#include <header.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
//using namespace std;
|
|
||||||
extern "C" {
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MQTT_SENSOR_DATA MQTT_PATH_PUB "data"
|
|
||||||
|
|
||||||
char buffer[128];
|
|
||||||
|
|
||||||
// Feldkapazität des Bodens in Prozent: Standard ist Humus
|
|
||||||
int fieldCapacity = 44;
|
|
||||||
// PWP des Bodens in Prozent: Standard ist Humus
|
|
||||||
int permanentWiltingPoint = 25;
|
|
||||||
// Boden vollständig gesättigt bei (Prozent): Standard ist Humus
|
|
||||||
int soilSaturation = 69;
|
|
||||||
|
|
||||||
void readSensors() {
|
|
||||||
StaticJsonDocument<128> doc;
|
|
||||||
float lxValue = readLightSensorValue();
|
|
||||||
Serial.print("Light intensity: ");
|
|
||||||
Serial.print(lxValue);
|
|
||||||
Serial.println(" lx");
|
|
||||||
doc["brightness"] = lxValue;
|
|
||||||
//sprintf(buffer, "%f", lxValue);
|
|
||||||
//publishMessage(MQTT_BRIGHTNESS, buffer);
|
|
||||||
|
|
||||||
int mstValue = readCapacitiveSoilMoistureSensor();
|
|
||||||
Serial.print("Soil moisture: ");
|
|
||||||
Serial.println(mstValue);
|
|
||||||
// sprintf(buffer, "%i", mstValue);
|
|
||||||
// publishMessage(MQTT_MOISTURE, buffer);
|
|
||||||
doc["moisture"] = mstValue;
|
|
||||||
|
|
||||||
float humidityValue = readHumidity();
|
|
||||||
Serial.print("Humidity: ");
|
|
||||||
Serial.println(humidityValue);
|
|
||||||
// sprintf(buffer, "%f", humidityValue);
|
|
||||||
// publishMessage(MQTT_HUMIDITY, buffer);
|
|
||||||
doc["humidity"] = humidityValue;
|
|
||||||
|
|
||||||
float temperatureValue = readTemperature();
|
|
||||||
Serial.print("Temperature: ");
|
|
||||||
Serial.println(temperatureValue);
|
|
||||||
// sprintf(buffer, "%f", temperatureValue);
|
|
||||||
// publishMessage(MQTT_TEMPERATURE, buffer);
|
|
||||||
doc["temperature"] = temperatureValue;
|
|
||||||
Serial.print("\n");
|
|
||||||
serializeJson(doc, buffer);
|
|
||||||
publishMessage(MQTT_SENSOR_DATA, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool openValve() {
|
|
||||||
digitalWrite(PIN_VALVE, HIGH);
|
|
||||||
digitalWrite(PIN_LED_G, LOW);
|
|
||||||
digitalWrite(PIN_LED_B, HIGH);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool closeValve() {
|
|
||||||
digitalWrite(PIN_VALVE, LOW);
|
|
||||||
digitalWrite(PIN_LED_G, HIGH);
|
|
||||||
digitalWrite(PIN_LED_B, LOW);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void valveTask(void *parameter) {
|
|
||||||
unsigned long valveTimeoutTimer = millis();
|
|
||||||
bool valveOpen = openValve();
|
|
||||||
|
|
||||||
while (valveOpen) {
|
|
||||||
delay(500);
|
|
||||||
int mstValue = readCapacitiveSoilMoistureSensor();
|
|
||||||
|
|
||||||
if (millis() - valveTimeoutTimer >= MAX_VALVE_TIMEOUT) {
|
|
||||||
valveOpen = closeValve();
|
|
||||||
}
|
|
||||||
// if (mstValue > 80) {
|
|
||||||
// valveOpen = closeValve();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void toggleValve() {
|
|
||||||
xTaskCreate(
|
|
||||||
valveTask, /* Task function. */
|
|
||||||
"valveTask", /* String with name of task. */
|
|
||||||
2048, /* Stack size in bytes. */
|
|
||||||
NULL, /* Parameter passed as input of the task */
|
|
||||||
1, /* Priority of the task. */
|
|
||||||
NULL); /* Task handle. */
|
|
||||||
}
|
|
||||||
|
|
||||||
void persistSoilProps(int FC, int PWP, int SAT) {
|
|
||||||
Serial.println("persistSoilProps");
|
|
||||||
bool f = NVS.setInt("fieldCapacity", FC);
|
|
||||||
bool p = NVS.setInt("permanentWilt", PWP);
|
|
||||||
bool s = NVS.setInt("soilSaturation", SAT);
|
|
||||||
if (f && p && s) {
|
|
||||||
Serial.println("Soil properties sucessfully stored.");
|
|
||||||
NVS.commit();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Serial.println("error occured while trying to persist soil properties");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void restoreSoilProps() {
|
|
||||||
Serial.println("restoreSoilProps");
|
|
||||||
int fc = NVS.getInt("fieldCapacity");
|
|
||||||
int pwp = NVS.getInt("permanentWilt");
|
|
||||||
int sat = NVS.getInt("soilSaturation");
|
|
||||||
if (fc != 0) {
|
|
||||||
fieldCapacity = fc;
|
|
||||||
}
|
|
||||||
if (pwp != 0) {
|
|
||||||
permanentWiltingPoint = pwp;
|
|
||||||
}
|
|
||||||
if (sat != 0) {
|
|
||||||
soilSaturation = sat;
|
|
||||||
}
|
|
||||||
Serial.print(fieldCapacity);
|
|
||||||
Serial.print(permanentWiltingPoint);
|
|
||||||
Serial.print(soilSaturation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupStore() {
|
|
||||||
NVS.begin("store");
|
|
||||||
restoreSoilProps();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSoilProperties(int FC, int PWP, int SAT) {
|
|
||||||
fieldCapacity = FC;
|
|
||||||
permanentWiltingPoint = PWP;
|
|
||||||
soilSaturation = SAT;
|
|
||||||
persistSoilProps(FC, PWP, SAT);
|
|
||||||
Serial.print("new fieldCapacity: ");
|
|
||||||
Serial.println(fieldCapacity);
|
|
||||||
Serial.print("new permanentWiltingPoint: ");
|
|
||||||
Serial.println(permanentWiltingPoint);
|
|
||||||
Serial.print("new soilSaturation: ");
|
|
||||||
Serial.println(soilSaturation);
|
|
||||||
}
|
|
||||||
|
|
||||||
65
src/sensors.cpp
Normal file
65
src/sensors.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <capacitiveSoilMoistureSensor.h>
|
||||||
|
#include <connections.h>
|
||||||
|
#include <lightChecker.h>
|
||||||
|
#include <lightSensor.h>
|
||||||
|
#include <ntpManager.h>
|
||||||
|
#include <sensors.h>
|
||||||
|
#include <valve.h>
|
||||||
|
#include <store.h>
|
||||||
|
#include <temperatureSensor.h>
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
char buffer[128];
|
||||||
|
char MQTT_SENSOR_DATA_TOPIC[64];
|
||||||
|
|
||||||
|
void setupSensors() {
|
||||||
|
setupLightSensor();
|
||||||
|
setupPWM();
|
||||||
|
setupTemperatureSensor();
|
||||||
|
setupCapacitiveSoilMoistureSensor();
|
||||||
|
setupNTP();
|
||||||
|
|
||||||
|
strcpy(MQTT_SENSOR_DATA_TOPIC, MQTT_TOPIC_BASE_PUB "/");
|
||||||
|
strcat(MQTT_SENSOR_DATA_TOPIC, getDeviceIDcharArr());
|
||||||
|
strcat(MQTT_SENSOR_DATA_TOPIC, "/data");
|
||||||
|
Serial.println("MQTT_SENSOR_DATA_TOPIC:");
|
||||||
|
Serial.println(MQTT_SENSOR_DATA_TOPIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readSensors() {
|
||||||
|
Serial.println();
|
||||||
|
StaticJsonDocument<128> doc;
|
||||||
|
float lxValue = readLightSensorValue();
|
||||||
|
Serial.print("Light intensity: ");
|
||||||
|
Serial.print(lxValue);
|
||||||
|
Serial.println(" lx");
|
||||||
|
doc["brightness"] = lxValue;
|
||||||
|
if ((lxValue < minimumLightValueLX) && checkForDay()) {
|
||||||
|
triggerLight();
|
||||||
|
}
|
||||||
|
|
||||||
|
int mstValue = readCapacitiveSoilMoistureSensor();
|
||||||
|
Serial.print("Soil moisture: ");
|
||||||
|
Serial.println(mstValue);
|
||||||
|
|
||||||
|
if (automaticIrrigation) {
|
||||||
|
toggleValve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
doc["moisture"] = mstValue;
|
||||||
|
|
||||||
|
float humidityValue = readHumidity();
|
||||||
|
Serial.print("Humidity: ");
|
||||||
|
Serial.println(humidityValue);
|
||||||
|
|
||||||
|
doc["humidity"] = humidityValue;
|
||||||
|
|
||||||
|
float temperatureValue = readTemperature();
|
||||||
|
Serial.print("Temperature: ");
|
||||||
|
Serial.println(temperatureValue);
|
||||||
|
|
||||||
|
doc["temperature"] = temperatureValue;
|
||||||
|
serializeJson(doc, buffer);
|
||||||
|
publishMessage(MQTT_SENSOR_DATA_TOPIC, buffer);
|
||||||
|
}
|
||||||
2
src/sensors.h
Normal file
2
src/sensors.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
void setupSensors();
|
||||||
|
void readSensors();
|
||||||
171
src/store.cpp
Normal file
171
src/store.cpp
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#include <ArduinoNvs.h>
|
||||||
|
#include <ESPRandom.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <lightChecker.h>
|
||||||
|
#include <store.h>
|
||||||
|
|
||||||
|
// Fieldcapacity of the Ground in Percentage: Standard is Humus
|
||||||
|
int fieldCapacity = 44;
|
||||||
|
// PWP of the Ground in Percentage: Standard is Humus
|
||||||
|
int permanentWiltingPoint = 25;
|
||||||
|
// Ground completely saturated by (Percentage): Standard is Humus
|
||||||
|
int soilSaturation = 69;
|
||||||
|
// Minimum light value before light turns on
|
||||||
|
int minimumLightValueLX = 50;
|
||||||
|
// Switches for automatic light and irrigation control
|
||||||
|
bool automaticLight = true;
|
||||||
|
bool automaticIrrigation = true;
|
||||||
|
// Make sure device irrigates until fieldcapacity is reached
|
||||||
|
bool irrigateUntilFC = false;
|
||||||
|
|
||||||
|
void persistSoilProps(int FC, int PWP, int SAT) {
|
||||||
|
Serial.println("persistSoilProps");
|
||||||
|
bool f = NVS.setInt("fieldCapacity", FC);
|
||||||
|
bool p = NVS.setInt("permanentWilt", PWP);
|
||||||
|
bool s = NVS.setInt("soilSaturation", SAT);
|
||||||
|
if (f && p && s) {
|
||||||
|
Serial.println("Soil properties sucessfully stored.");
|
||||||
|
NVS.commit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("error occured while trying to persist soil properties");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreSoilProps() {
|
||||||
|
Serial.println("restoreSoilProps");
|
||||||
|
int fc = NVS.getInt("fieldCapacity");
|
||||||
|
int pwp = NVS.getInt("permanentWilt");
|
||||||
|
int sat = NVS.getInt("soilSaturation");
|
||||||
|
if (fc != 0) {
|
||||||
|
fieldCapacity = fc;
|
||||||
|
}
|
||||||
|
if (pwp != 0) {
|
||||||
|
permanentWiltingPoint = pwp;
|
||||||
|
}
|
||||||
|
if (sat != 0) {
|
||||||
|
soilSaturation = sat;
|
||||||
|
}
|
||||||
|
Serial.print("fieldCapacity: ");
|
||||||
|
Serial.println(fieldCapacity);
|
||||||
|
Serial.print("permanentWiltingPoint: ");
|
||||||
|
Serial.println(permanentWiltingPoint);
|
||||||
|
Serial.print("soilSaturation: ");
|
||||||
|
Serial.println(soilSaturation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupStore() {
|
||||||
|
NVS.begin("store");
|
||||||
|
initDeviceID();
|
||||||
|
restoreSoilProps();
|
||||||
|
restoreLightProps();
|
||||||
|
restoreAutoProps();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSoilProperties(int FC, int PWP, int SAT) {
|
||||||
|
fieldCapacity = FC;
|
||||||
|
permanentWiltingPoint = PWP;
|
||||||
|
soilSaturation = SAT;
|
||||||
|
persistSoilProps(FC, PWP, SAT);
|
||||||
|
Serial.print("new fieldCapacity: ");
|
||||||
|
Serial.println(fieldCapacity);
|
||||||
|
Serial.print("new permanentWiltingPoint: ");
|
||||||
|
Serial.println(permanentWiltingPoint);
|
||||||
|
Serial.print("new soilSaturation: ");
|
||||||
|
Serial.println(soilSaturation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to persist save the given lightning properties to NVS
|
||||||
|
void persistLightProps(int NM, int minLX) {
|
||||||
|
Serial.println("persistLightProps");
|
||||||
|
bool n = NVS.setInt("nanoMeter", NM);
|
||||||
|
bool m = NVS.setInt("minimumLux", minLX);
|
||||||
|
if (n && m) {
|
||||||
|
Serial.println("Light properties sucessfully stored.");
|
||||||
|
NVS.commit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("error occured while trying to persist light properties");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to restore light properties from Non-Volatile Storage (NVS)
|
||||||
|
void restoreLightProps() {
|
||||||
|
Serial.println("restoreLightProps");
|
||||||
|
int nm = NVS.getInt("nanoMeter");
|
||||||
|
int minLX = NVS.getInt("minimumLux");
|
||||||
|
if (nm != 0) {
|
||||||
|
setValueNM(nm);
|
||||||
|
}
|
||||||
|
if (minLX != 0) {
|
||||||
|
minimumLightValueLX = minLX;
|
||||||
|
}
|
||||||
|
Serial.println(minimumLightValueLX);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to set given light properties
|
||||||
|
void setLightProperties(int NM, int minLX) {
|
||||||
|
setValueNM(NM);
|
||||||
|
minimumLightValueLX = minLX;
|
||||||
|
persistLightProps(NM, minLX);
|
||||||
|
Serial.print("new minimum Light Value LX: ");
|
||||||
|
Serial.println(minimumLightValueLX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void persistAutoProps(bool light, bool irrigation) {
|
||||||
|
Serial.println("persistAutoProps");
|
||||||
|
// Saved in NVS as Integer: 1 = true, 2 = false, 0 = not persisted, use standard settings
|
||||||
|
bool n = NVS.setInt("automaticLight", (light ? 1 : 2));
|
||||||
|
bool m = NVS.setInt("automaticIrrigation", (irrigation ? 1 : 2));
|
||||||
|
if (n && m) {
|
||||||
|
NVS.commit();
|
||||||
|
Serial.println("Auto properties sucessfully stored.");
|
||||||
|
} else {
|
||||||
|
Serial.println("error occured while trying to persist auto properties");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreAutoProps() {
|
||||||
|
Serial.println("restoreLightProps");
|
||||||
|
int li = NVS.getInt("automaticLight");
|
||||||
|
int ir = NVS.getInt("automaticIrrigation");
|
||||||
|
automaticLight = (bool) (li != 2);
|
||||||
|
automaticIrrigation = (bool) (ir != 2);
|
||||||
|
Serial.println(minimumLightValueLX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAutoProperties(bool light, bool irrigation) {
|
||||||
|
automaticLight = light;
|
||||||
|
automaticIrrigation = irrigation;
|
||||||
|
persistAutoProps(light, irrigation);
|
||||||
|
Serial.print("new auto settings: ");
|
||||||
|
Serial.println(automaticLight);
|
||||||
|
Serial.println(automaticIrrigation);
|
||||||
|
}
|
||||||
|
|
||||||
|
String DEVICE_ID = "";
|
||||||
|
|
||||||
|
void initDeviceID() {
|
||||||
|
DEVICE_ID = NVS.getString("UUID");
|
||||||
|
if (!DEVICE_ID.isEmpty()) {
|
||||||
|
Serial.print("Fetched Device ID from NVS: ");
|
||||||
|
Serial.println(DEVICE_ID);
|
||||||
|
} else {
|
||||||
|
uint8_t uuid[16];
|
||||||
|
ESPRandom::uuid(uuid);
|
||||||
|
DEVICE_ID = ESPRandom::uuidToString(uuid);
|
||||||
|
NVS.setString("UUID", DEVICE_ID);
|
||||||
|
NVS.commit();
|
||||||
|
Serial.print("New Device ID: ");
|
||||||
|
Serial.println(DEVICE_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the device ID
|
||||||
|
String getDeviceID() {
|
||||||
|
return DEVICE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* getDeviceIDcharArr() {
|
||||||
|
return DEVICE_ID.c_str();
|
||||||
|
}
|
||||||
29
src/store.h
Normal file
29
src/store.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Feldkapazität des Bodens in Prozent: Standard ist Humus
|
||||||
|
extern int fieldCapacity;
|
||||||
|
// PWP des Bodens in Prozent: Standard ist Humus
|
||||||
|
extern int permanentWiltingPoint;
|
||||||
|
// Boden vollständig gesättigt bei (Prozent): Standard ist Humus
|
||||||
|
extern int soilSaturation;
|
||||||
|
// Helligkeitswert der mindestens vorhanden sein muss
|
||||||
|
extern int minimumLightValueLX;
|
||||||
|
// switches for automatic light and irrigation control
|
||||||
|
extern bool automaticLight;
|
||||||
|
extern bool automaticIrrigation;
|
||||||
|
// make sure device irrigates until fieldcapacity is reached
|
||||||
|
extern bool irrigateUntilFC;
|
||||||
|
// Device UUID will be set on first boot.
|
||||||
|
extern String DEVICE_ID;
|
||||||
|
|
||||||
|
void persistSoilProps(int FC, int PWP, int SAT);
|
||||||
|
void restoreSoilProps();
|
||||||
|
void setupStore();
|
||||||
|
void setSoilProperties(int FC, int PWP, int SAT);
|
||||||
|
void persistLightProps(int NM, int minLX);
|
||||||
|
void restoreLightProps();
|
||||||
|
void setLightProperties(int NM, int minLX);
|
||||||
|
void persistAutoProps(bool light, bool irrigation);
|
||||||
|
void restoreAutoProps();
|
||||||
|
void setAutoProperties(bool light, bool irrigation);
|
||||||
|
void initDeviceID();
|
||||||
|
String getDeviceID();
|
||||||
|
const char* getDeviceIDcharArr();
|
||||||
@ -1,7 +1,9 @@
|
|||||||
#include <header.h>
|
#include <DHT.h>
|
||||||
|
#include <DHT_U.h>
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
|
||||||
#define DHTPIN PIN_DHT11
|
#define DHTPIN PIN_DHT11
|
||||||
|
|
||||||
#define DHTTYPE DHT11
|
#define DHTTYPE DHT11
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
3
src/temperatureSensor.h
Normal file
3
src/temperatureSensor.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
void setupTemperatureSensor();
|
||||||
|
float readHumidity();
|
||||||
|
float readTemperature();
|
||||||
66
src/valve.cpp
Normal file
66
src/valve.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include <capacitiveSoilMoistureSensor.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <store.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <valve.h>
|
||||||
|
|
||||||
|
bool openValve() {
|
||||||
|
digitalWrite(PIN_VALVE, HIGH);
|
||||||
|
digitalWrite(PIN_LED_G, LOW);
|
||||||
|
digitalWrite(PIN_LED_B, HIGH);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool closeValve() {
|
||||||
|
digitalWrite(PIN_VALVE, LOW);
|
||||||
|
digitalWrite(PIN_LED_G, HIGH);
|
||||||
|
digitalWrite(PIN_LED_B, LOW);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void valveTask(void *parameter) {
|
||||||
|
bool isAutomatic = (bool)parameter;
|
||||||
|
Serial.print(isAutomatic);
|
||||||
|
Serial.println(" Valve task triggered.");
|
||||||
|
unsigned long valveTimeoutTimer = millis();
|
||||||
|
bool valveOpen = false;
|
||||||
|
int initialSoilMoisture = readCapacitiveSoilMoistureSensor();
|
||||||
|
|
||||||
|
if (initialSoilMoisture <= permanentWiltingPoint || irrigateUntilFC) {
|
||||||
|
valveOpen = openValve();
|
||||||
|
irrigateUntilFC = true;
|
||||||
|
} else {
|
||||||
|
Serial.println("Soil contains enough water. No irrigation needed. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (valveOpen) {
|
||||||
|
delay(500);
|
||||||
|
int mstValue = readCapacitiveSoilMoistureSensor();
|
||||||
|
|
||||||
|
if (mstValue > fieldCapacity) { // && isAutomatic
|
||||||
|
Serial.println("Field capacity reached. No irrigation needed. ");
|
||||||
|
valveOpen = closeValve();
|
||||||
|
irrigateUntilFC = false;
|
||||||
|
}
|
||||||
|
if (millis() - valveTimeoutTimer >= MAX_VALVE_TIMEOUT) {
|
||||||
|
Serial.println("Irrigation timeout reached. close valve. ");
|
||||||
|
valveOpen = closeValve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleValve(bool automatic) {
|
||||||
|
xTaskCreate(
|
||||||
|
valveTask, /* Task function. */
|
||||||
|
"valveTask", /* String with name of task. */
|
||||||
|
2048, /* Stack size in bytes. */
|
||||||
|
&automatic, /* Parameter passed as input of the task */
|
||||||
|
3, /* Priority of the task. */
|
||||||
|
NULL); /* Task handle. */
|
||||||
|
}
|
||||||
1
src/valve.h
Normal file
1
src/valve.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
void toggleValve(bool automatic);
|
||||||
Loading…
Reference in New Issue
Block a user