diff --git a/src/globals.h b/src/globals.h new file mode 100644 index 0000000..39c6260 --- /dev/null +++ b/src/globals.h @@ -0,0 +1,79 @@ +#include "arduino_secrets.h" +// Timer lib +#include +#include + +// Wifi and MQTT libs +#include +#include +#include +#include + +#include + + +// 0: no log messages, 1: safe log messages, 2: halting log messages +#define DEBUG 2 +// Time in MS the pump is on after receiving MQTT msg +#define PUMP_ON_TIME 5000L +// MAX Time in MS the heater is on after receiving MQTT msg (if not turned off by user before) +#define HEATER_TIMEOUT 30*1000L +// Interval of the main HW Clock in MS +#define HW_TIMER_INTERVAL_MS 50L +#define WATER_LEVEL_SENSOR_READINGS 10 +#define READING_INTERVAL 2 +#define WATER_MAX_LEVEL 680 +#define WATER_MIN_LEVEL 400 + +const int JSON_SIZE = 1000; + +const int HEATER_PIN = 0; +const int WATER_PUMP_PIN = 1; +const int MIC_PIN = A0; +const int BUZZER_PIN = A1; +const int WATER_LEVEL_PIN = A4; +const int MOTOR_PIN = A3; + +int getWaterLevelReading(); +bool isWaterContainerFull(); +bool isWaterContainerEmpty(); + +// Values modifed by Interrupts +volatile int heaterTimerId = -1; // Stores the id of the current heaterTimer interrupt +volatile bool heater_status = false; +volatile bool pump_status = false; +volatile uint32_t preMillisTimer = 0; + +// ------------ MQTT related vars ------------------ +void connectToMQTT(); +void callback(char* topic, byte* payload, unsigned int length); +void sendHeaterStatus(); +void sendPumpStatus(); +WiFiClient wifiClient; +PubSubClient mqtt(MQTT_HOST, MQTT_PORT, callback, wifiClient); +// --------------------------------------------- + +// ----------------- JSON variables ------------ +StaticJsonDocument jsonDoc; +JsonObject payload = jsonDoc.to(); +JsonObject status = payload.createNestedObject("sensor_data"); + +StaticJsonDocument jsonDocHeater; +JsonObject payloadHeater = jsonDocHeater.to(); + +StaticJsonDocument jsonDocPump; +JsonObject payloadPump = jsonDocPump.to(); + +static char msg[JSON_SIZE]; +StaticJsonDocument<128> callbackDoc; +DeserializationError error; +// --------------------------------------------- + +// ------------------ Timer Objects ------------ +// Main timer +SAMDTimerInterrupt ITimer0(TIMER_TCC); +// SAMD ISR timers, use main timer for up to 16 timers +SAMD_ISR_Timer ISR_Timer; +void TimerHandler(); +void pumpTimerHandler(); +// --------------------------------------------- diff --git a/src/src.ino b/src/src.ino index 86c5090..afacd11 100644 --- a/src/src.ino +++ b/src/src.ino @@ -1,4 +1,5 @@ #pragma once +#include "globals.h" #include "arduino_secrets.h" #include "setup.h" #include @@ -8,68 +9,56 @@ #include #include -// Timer lib -#include -#include -// 0: no log messages, 1: safe log messages, 2: halting log messages -#define DEBUG 2 -// Time in MS the pump is on after receiving MQTT msg -#define PUMP_ON_TIME 5000L -// MAX Time in MS the heater is on after receiving MQTT msg (if not turned off by user before) -#define HEATER_TIMEOUT 30*1000L -// Interval of the main HW Clock in MS -#define HW_TIMER_INTERVAL_MS 50L - -const int JSON_SIZE = 1000; - -const int HEATER_PIN = 0; -const int WATER_PUMP_PIN = 1; -const int MIC_PIN = A0; -const int BUZZER_PIN = A1; -const int WATER_LEVEL_PIN = A2; -const int MOTOR_PIN = A3; - -// Values modifed by Interrupts -volatile int heaterTimerId = -1; // Stores the id of the current heaterTimer interrupt -volatile bool heater_status = false; -volatile bool pump_status = false; -volatile uint32_t preMillisTimer = 0; - -// ------------ MQTT objects ------------------ -void connectToMQTT(); -void callback(char* topic, byte* payload, unsigned int length); -void sendHeaterStatus(); -void sendPumpStatus(); -WiFiClient wifiClient; -PubSubClient mqtt(MQTT_HOST, MQTT_PORT, callback, wifiClient); -// --------------------------------------------- - -// ----------------- JSON variables ------------ -StaticJsonDocument jsonDoc; -JsonObject payload = jsonDoc.to(); -JsonObject status = payload.createNestedObject("sensor_data"); - -StaticJsonDocument jsonDocHeater; -JsonObject payloadHeater = jsonDocHeater.to(); - -StaticJsonDocument jsonDocPump; -JsonObject payloadPump = jsonDocPump.to(); +bool isWaterContainerFull() +{ + int water_level = getWaterLevelReading(); + // validate the reading: + if (water_level < 0 || water_level > 1023) + return true; // cannot pour as sensor malfunctioned! + if (water_level < WATER_MAX_LEVEL) + { +#if (DEBUG > 1) + Serial.println("Water level below MAX, can pour!"); +#endif + return false; + } +#if (DEBUG > 1) + Serial.println("Water level above or equal MAX, cannot pour!"); +#endif + return true; +} -static char msg[JSON_SIZE]; -StaticJsonDocument<128> callbackDoc; -DeserializationError error; -// --------------------------------------------- +bool isWaterContainerEmpty() +{ + int water_level = getWaterLevelReading(); + // validate the reading: + if (water_level < 0 || water_level > 1023) + return false; // cannot pour as sensor malfunctioned! + if (getWaterLevelReading() < WATER_MIN_LEVEL) + { +#if (DEBUG > 1) + Serial.println("Water level below MIN, need to pour!"); +#endif + return true; + } +#if (DEBUG > 1) + Serial.println("Water level above or equal MIN, no need to pour!"); +#endif + return false; +} -// ------------------ Timer Objects ------------ -// Main timer -SAMDTimerInterrupt ITimer0(TIMER_TCC); -// SAMD ISR timers, use main timer for up to 16 timers -SAMD_ISR_Timer ISR_Timer; +int getWaterLevelReading() +{ + float avg = 0; + for (int i = 0; i < WATER_LEVEL_SENSOR_READINGS; ++i) + { + avg += analogRead(WATER_LEVEL_PIN); + delay(READING_INTERVAL); + } + return avg/WATER_LEVEL_SENSOR_READINGS; +} -void TimerHandler(); -void pumpTimerHandler(); -// --------------------------------------------- void TimerHandler() { @@ -154,6 +143,7 @@ void callback(char* topic, byte* payload, unsigned int length) { ISR_Timer.deleteTimer(heaterTimerId); heaterTimerId = -1; } + digitalWrite(HEATER_PIN, LOW); } #if (DEBUG > 0) Serial.println(heater_status); @@ -166,8 +156,16 @@ void callback(char* topic, byte* payload, unsigned int length) { { if (strcmp((const char*) callbackDoc["water_pump"], "Pour") == 0) { + if (isWaterContainerFull()) + { + pump_status = false; + sendPumpStatus(); + return; + } pump_status = true; +#if (DEBUG > 1) preMillisTimer = millis(); +#endif digitalWrite(WATER_PUMP_PIN,HIGH); ISR_Timer.setTimeout(PUMP_ON_TIME, pumpTimerHandler); } @@ -231,7 +229,7 @@ void loop() { float humi = ENV.readHumidity(); float illu = ENV.readIlluminance(); int sound = analogRead(MIC_PIN); - float water = analogRead(WATER_LEVEL_PIN); + float water = getWaterLevelReading(); // Check if any reads failed if (isnan(temp) || isnan(humi) || isnan(illu)) { @@ -239,6 +237,10 @@ void loop() { Serial.println("Failed to read data!"); #endif } else { + // check if water container empty + if (isWaterContainerEmpty()) + { + } // Prepare data status["temp"] = temp;