Skip to content

Commit

Permalink
Add water level checkers, when pouring.
Browse files Browse the repository at this point in the history
* Move global defined vars and objects to globals.h

Signed-off-by: Szymon Duchniewicz <[email protected]>
  • Loading branch information
Willmish committed Mar 28, 2022
1 parent 3a6d1b8 commit afd87ba
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 59 deletions.
79 changes: 79 additions & 0 deletions src/globals.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "arduino_secrets.h"
// Timer lib
#include <SAMDTimerInterrupt.h>
#include <SAMD_ISR_Timer.h>

// Wifi and MQTT libs
#include <WiFiNINA.h>
#include <ArduinoMqttClient.h>
#include <ArduinoJson.h>
#include <PubSubClient.h>

#include <Arduino_MKRENV.h>


// 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<JSON_SIZE> jsonDoc;
JsonObject payload = jsonDoc.to<JsonObject>();
JsonObject status = payload.createNestedObject("sensor_data");

StaticJsonDocument<JSON_SIZE> jsonDocHeater;
JsonObject payloadHeater = jsonDocHeater.to<JsonObject>();

StaticJsonDocument<JSON_SIZE> jsonDocPump;
JsonObject payloadPump = jsonDocPump.to<JsonObject>();

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();
// ---------------------------------------------
120 changes: 61 additions & 59 deletions src/src.ino
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "globals.h"
#include "arduino_secrets.h"
#include "setup.h"
#include <string.h>
Expand All @@ -8,68 +9,56 @@
#include <PubSubClient.h>
#include <Arduino_MKRENV.h>

// Timer lib
#include <SAMDTimerInterrupt.h>
#include <SAMD_ISR_Timer.h>

// 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<JSON_SIZE> jsonDoc;
JsonObject payload = jsonDoc.to<JsonObject>();
JsonObject status = payload.createNestedObject("sensor_data");

StaticJsonDocument<JSON_SIZE> jsonDocHeater;
JsonObject payloadHeater = jsonDocHeater.to<JsonObject>();

StaticJsonDocument<JSON_SIZE> jsonDocPump;
JsonObject payloadPump = jsonDocPump.to<JsonObject>();
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()
{
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
Expand Down Expand Up @@ -231,14 +229,18 @@ 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)) {
#if (DEBUG > 0)
Serial.println("Failed to read data!");
#endif
} else {
// check if water container empty
if (isWaterContainerEmpty())
{
}

// Prepare data
status["temp"] = temp;
Expand Down

0 comments on commit afd87ba

Please sign in to comment.