Hi. First post here thanks for having me! I just got back into arduino and programming since I felt the need to make a CO2 and Air timer for my aquarium. The idea seemed simple at first yet most things do until you truly get into it. The issue that ive been trying to narrow down is on the programming side i believe hence posting here. I have an arduino nano 33 iot, 2 relays 1 for air pump one for co2 solenoid, an external ds3231rtc since the nanos rtc is not very accurate, and a ds18b20 temp probe that sends relay status and temp readings through a local MQTT server on raspberrypi. Which is nested in an old ace hardware power strip... The issue is only with the cycling of relay states for its programmed schedule. Which is: 7 am CO2 on and airump off (plants like CO2 during the day and turn it to O2). 4pm both CO2 and airpump off (to allow plants in aqaurium to absorb excess co2). 5pm till 7 am next day air pump is on and off at 5 min intervals, and co2 is off.
~ The issue is that even though the program switches between the listed times properly through the day, when 7 am the next day comes around it seems the airpump state is stuck in an always on state(no ON, OFF) and does not switch back to running the CO2 solenoid. Though when i unplug the arduino to reset, it corrects the issue and runs the program till getting stuck at the 7am switch once again. So Ive been manually starting the cycle every morning:/
Any help would be appreciated at this point as i am at loss of what to try... Ive been learning more about C++ basics to help me understand this issue. I originally tried this with if statements and it was much too messy and buggy. I have a feeling im either overlooking something very simple, or im just un-aware of how the coding proceeds to run. sorry if this was too long, or in the wrong section as this is my first time, and i havn't been on a forum in ages.
#include <DS3231_Simple.h>
#include <ArduinoMqttClient.h>
#include <WiFiNINA.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
#define TEMPERATURE_PRECISION 9
char ssid[] = ""; // your network SSID (name)
char pass[] = "";
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DS3231_Simple Clock;
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
//wifi and mqtt stuff
const char broker[] = "192.168.0.23";
int port = 1883;
const char topic[] = "airpump";
const char topic2[] = "co2";
const char topic3[] = "temp";
//timer stuff
unsigned long previousMillis = 0;
unsigned int minTime = 0;
unsigned int hourTime = 0;
unsigned int prevminTime = 0;
const int fivemin = 5;
//just the pins for the relays
const int airPin = 12;
const int coPin = 11;
//program state, would have shortened to pro-state but then id have to look at that every freaking time...
unsigned int state;
//air&co2 state bools... find a way to make and on/off string instead of binary 0/1 readout of states
bool airpump = false;
bool carbonDi = false;
// Curent time reset:
const long interval = 8000;
//state of airpump relay
int airrelayState = LOW;
int numberOfDevices; // Number of temperature devices found
DeviceAddress tempDeviceAddress;
float tempC = 0.0;
// We'll use this variable to store a found device address
void setup() {
pinMode(airPin, OUTPUT);
pinMode(coPin, OUTPUT);
Serial.begin(9600);
Serial.println();
sensors.begin();
// Grab a count of devices on the wire
numberOfDevices = sensors.getDeviceCount();
// attempt to connect to Wifi network:
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
Serial.println("You're connected to the network");
Serial.println();
Serial.print("Attempting to connect to the MQTT broker: ");
Serial.println(broker);
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
while (1)
;
}
Serial.println("You're connected to the MQTT broker!");
Serial.println();
Clock.begin();
// Get an initialized timestamp
//DateTime MyTimestamp = Clock.read();
for (int i = 0; i < numberOfDevices; i++) {
// Search the wire for address
if (sensors.getAddress(tempDeviceAddress, i)) { // set the resolution to TEMPERATURE_PRECISION bit (Each Dallas/Maxim device is capable of several different resolutions)
sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);
} else {
Serial.print("Found ghost device at ");
Serial.print(i, DEC);
Serial.print(" but could not detect address. Check power and cabling");
}
}
}
void loop() {
mqttClient.poll();
DateTime MyTimestamp = Clock.read();
sensors.requestTemperatures();
minTime = MyTimestamp.Minute;
hourTime = MyTimestamp.Hour;
//Check if RTC is currently in hour range for the co2 or air pump
if (hourTime >= 17 || hourTime <= 6) // air pump relay flip flops at 5 min intervals for the night
{
state = 1;
} else if (hourTime == 16) //hour pause to use up excess co2
{
state = 2;
} else {
state = 3; // co2 for the day time
}
switch (state) {
case 1:
//Based on blink without delay using DS3231 time to setup 5 min alternating air pump
if (minTime - prevminTime >= fivemin) {
// save the last time prevminTime was updated resetting 5 min time counter
prevminTime = minTime;
if (airrelayState == LOW) {
airrelayState = HIGH;
} else {
airrelayState = LOW;
}
digitalWrite(airPin, airrelayState);
airpump = true;
}
break;
case 2:
digitalWrite(coPin, LOW);
digitalWrite(airPin, LOW);
airpump = false;
carbonDi = false;
break;
case 3:
digitalWrite(coPin, HIGH);
digitalWrite(airPin, LOW);
airpump = false;
carbonDi = true;
break;
}
//Prints relay state and temp values to mqtt and serial
unsigned long currentMillis = millis();
//millis timer also based on blink without delay example but instead shows time stamps in 1 sec intervals
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
Clock.printTimeTo_HMS(Serial);
Serial.println();
int Rvalue1 = airpump;
int Rvalue2 = carbonDi;
float Rvalue3 = sensors.getTempF(tempDeviceAddress);
Serial.print("Sending message to topic: ");
Serial.println(topic);
Serial.println(Rvalue1);
Serial.print("Sending message to topic: ");
Serial.println(topic2);
Serial.println(Rvalue2);
Serial.print("Sending message to topic: ");
Serial.println(topic3);
Serial.println(Rvalue3);
// send message, the Print interface can be used to set the message contents
mqttClient.beginMessage(topic);
mqttClient.print(Rvalue1);
mqttClient.endMessage();
mqttClient.beginMessage(topic2);
mqttClient.print(Rvalue2);
mqttClient.endMessage();
mqttClient.beginMessage(topic3);
mqttClient.print(Rvalue3);
mqttClient.endMessage();
Serial.println();
}
}
the chunks in question are in the loop function, being the if with time constraints setting the state, and the switch case below it reacting to the state changes. I put the airpump and CO2 bools within the case statements just so i could tell if it switched to that case through MQTT explorer. I did this because i couldnt tell if it was hardware or not before, but when looking at it through mqtt the values show it hasnt switched from case 1 to case 3 (airpump stays true, co2 shows false instead). Which makes me think it must be the coding getting stuck... does that seem correct?