This is a project I created for my brother’s Ebb & Flow hydroponic system. Its a 4x switched outlets & has the ability for 2x digital inputs (they are supplied 5v) and 3x analog inputs (the are supplied 3.3v). Currently there is a DS18B20 for water temp, a DHT22 for ambient temp & humidity, a water level sensor, and a plant moisture sensor. All sensors can disconnect/reconnected easily as I used a 3 wire headphone stereo plug. Thanks @micho111 for that good idea! The system also has two different timers that can be adjusted by sliders on the dashboard. It has a push button on the side of the housing to do manual on/off/timer functions and a green LED in the center that indicates its connection to Cayenne servers. Always gotta have at least one led in a project! lol
This project uses the MKR1000 and a proto shield as the controller. It utilizes the SAMD chip to run multiple loops and the RTC for accurate timing. I had several alarms setup at different times (encase internet is offline) to run the system but ran into problems calling the alarms so need to work on that a little more. I designed it so that it can be expanded with more sensors down the road if needed and easily reprogrammed with a pull out USB cable under the plate.
#include <Arduino.h>
//#define CAYENNE_DEBUG
//#define CAYENNE_PRINT Serial
// #include <CayenneWiFi101.h>
#include <CayenneMKR1000.h>
#include <SPI.h>
#include <Scheduler.h>
#include <RTCZero.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <DHT.h>
#define relayPin1 6
#define relayPin2 7
#define relayPin3 8
#define relayPin4 9
#define buttonPin 5
#define analog1Pin A0
#define analog2Pin A1
#define analog3Pin A2
#define onlineLED 10
#define myTimezone -5
#define ONE_WIRE_BUS 3 //top port
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
RTCZero rtc;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
char token[] = "token";
char ssid[] = "wifi";
char password[] = "pass";
unsigned long time1;
unsigned long onlineTime;
unsigned long prevTime;
unsigned long expireTime;
unsigned long expireTime2;
unsigned long slider1time;
unsigned long slider2time;
unsigned long wifiTime;
unsigned long cycle2Dur;
unsigned long cycle2Time;
bool online = false;
bool firstRun = true;
bool buttonPressed = false;
byte disco = 0;
byte relay1;
byte relay2;
byte relay3;
byte relay4;
byte button;
byte timer1;
byte timer2;
byte alarmButton;
byte cycle2;
float tempF;
// const byte seconds = 0;
// const byte minutes = 43;
// const byte hours = 21;
// const byte day = 6;
// const byte month = 6;
// const byte year = 17;
void setup()
{
pinMode(relayPin1, OUTPUT);
pinMode(relayPin2, OUTPUT);
pinMode(relayPin3, OUTPUT);
pinMode(relayPin4, OUTPUT);
pinMode(onlineLED, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(analog1Pin, INPUT);
pinMode(analog2Pin, INPUT);
pinMode(analog3Pin, INPUT);
analogReadResolution(12);
digitalWrite(onlineLED, LOW);
// Serial.begin(9600);
rtc.begin();
dht.begin();
sensors.begin();
sensors.setResolution(11);
Cayenne.begin(token, ssid, password);
Scheduler.startLoop(loop2);
Scheduler.startLoop(loop3);
}
void loop()
{
Cayenne.run();
time1 = millis();
}
void loop2()
{
if (relay1 == LOW)
{
digitalWrite(relayPin1, LOW);
}
else
{
digitalWrite(relayPin1, HIGH);
}
if (relay2 == LOW)
{
digitalWrite(relayPin2, LOW);
}
else
{
digitalWrite(relayPin2, HIGH);
}
if (relay3 == LOW)
{
digitalWrite(relayPin3, LOW);
}
else
{
digitalWrite(relayPin3, HIGH);
}
if (relay4 == LOW)
{
digitalWrite(relayPin4, LOW);
}
else
{
digitalWrite(relayPin4, HIGH);
}
// Serial.println(rtc.getDay());
// Serial.println(rtc.getHours());
// Serial.println(" ");
yield();
}
void loop3()
{
button = digitalRead(buttonPin);
if (button == 0)
{
delay(500);
button = digitalRead(buttonPin);
if (button == 0)
{
buttonPressed = true;
relay1 = LOW;
relay2 = HIGH;
Cayenne.virtualWrite(V10, HIGH);
Cayenne.virtualWrite(V11, HIGH);
Cayenne.virtualWrite(V15, HIGH);
expireTime = millis() + slider1time;
timer1 = 1;
}
else
{
buttonPressed = false;
}
}
if (timer1 == 1 || buttonPressed == true)
{
if (expireTime < millis())
{
timer1Done();
}
}
if (timer2 == 1)
{
if (expireTime2 < millis())
{
timer2Done();
}
}
yield();
}
void timer1Done()
{
relay1 = HIGH;
relay2 = LOW;
Cayenne.virtualWrite(V10, LOW);
Cayenne.virtualWrite(V11, LOW);
Cayenne.virtualWrite(V15, LOW);
timer1 = 0;
expireTime = 0;
}
void timer2Done()
{
relay3 = LOW;
relay4 = LOW;
Cayenne.virtualWrite(V12, LOW);
Cayenne.virtualWrite(V13, LOW);
Cayenne.virtualWrite(V17, LOW);
timer2 = 0;
expireTime2 = 0;
}
CAYENNE_CONNECTED()
{
prevTime = millis();
digitalWrite(onlineLED, HIGH);
}
CAYENNE_DISCONNECTED()
{
digitalWrite(onlineLED, LOW);
prevTime = millis();
disco++;
}
CAYENNE_OUT(V0) // & V1
{
if (firstRun == true)
{
wifiTime = WiFi.getTime();
delay(500);
rtc.setEpoch(wifiTime);
int timeAdjust = (rtc.getHours() + myTimezone);
switch (timeAdjust)
{
case -5:
timeAdjust = 7;
break;
case -4:
timeAdjust = 8;
break;
case -3:
timeAdjust = 9;
break;
case -2:
timeAdjust = 10;
break;
case -1:
timeAdjust = 11;
break;
default:
break;
}
rtc.setHours(timeAdjust);
firstRun = false;
}
Cayenne.virtualWrite(V1, rtc.getMinutes());
Cayenne.virtualWrite(V0, rtc.getHours());
}
CAYENNE_OUT(V5)
{
sensors.requestTemperatures();
delay(350);
tempF = (sensors.getTempCByIndex(0) * 1.8) + 32;
Cayenne.virtualWrite(V5, tempF);
Cayenne.virtualWrite(V14, tempF);
}
CAYENNE_OUT(V6)
{
int temp1 = dht.readTemperature(true);
Cayenne.virtualWrite(V6, temp1);
Cayenne.virtualWrite(V19, tempF);
}
CAYENNE_OUT(V7)
{
int hum1 = dht.readHumidity();
Cayenne.virtualWrite(V7, hum1);
}
CAYENNE_OUT(V8)
{
int analog1 = 0;
for (int i = 0; i <= 4; i++)
{
analog1 = analog1 + analogRead(analog1Pin);
}
analog1 = analog1 / 5;
int y = map(analog1,10,3000,0,100);
Cayenne.virtualWrite(V8, y);
}
CAYENNE_OUT(V9)
{
float analog2 = 0;
for (int i = 0; i <= 4; i++)
{
analog2 = analog2 + analogRead(analog2Pin);
}
float percent = ((4096 - (analog2 / 5)) / 4096) * 100;
// int y = map(analog1,10,3000,0,100);
Cayenne.virtualWrite(V9, percent);
}
CAYENNE_OUT(V20)
{
if (timer1 == 1 || buttonPressed == true)
{
Cayenne.virtualWrite(V20, ((expireTime - time1) / 1000) / 60);
}
else
{
Cayenne.virtualWrite(V20, 0);
}
}
CAYENNE_OUT(V21)
{
if (timer2 == 1)
{
Cayenne.virtualWrite(V21, ((expireTime2 - time1) / 1000) / 60);
}
else
{
Cayenne.virtualWrite(V21, 0);
}
}
CAYENNE_OUT(V23)
{
Cayenne.virtualWrite(V23, disco);
}
CAYENNE_OUT(V24)
{
float time2 = (time1 / 1000) / 60;
Cayenne.virtualWrite(V24, time2);
}
CAYENNE_OUT(V25)
{
onlineTime = ((time1 - prevTime) / 1000) / 60;
Cayenne.virtualWrite(V25, onlineTime);
}
/////////////////////////////////////////////////////////////
CAYENNE_IN(V1)
{
cycle2 = getValue.asInt();
if (cycle2 == 1)
{
cycle2Time = cycle2Dur + millis();
}
else
{
cycle2Time = 0;
}
}
CAYENNE_IN(V2)
{
cycle2Dur = getValue.asInt();
cycle2Dur = (cycle2Dur / 1023) * 60 * 60 * 1000;
}
CAYENNE_IN(V10)
{
relay1 = getValue.asInt();
}
CAYENNE_IN(V11)
{
relay2 = getValue.asInt();
}
CAYENNE_IN(V12)
{
relay3 = getValue.asInt();
}
CAYENNE_IN(V13)
{
relay4 = getValue.asInt();
}
CAYENNE_IN(V15)
{
timer1 = getValue.asInt();
if (timer1 == 1)
{
expireTime = millis() + slider1time;
}
else
{
expireTime = 0;
}
}
CAYENNE_IN(V16)
{
unsigned long slider1 = getValue.asInt();
slider1 = slider1 / 1023;
slider1time = slider1 * 60 * 1000;
}
CAYENNE_IN(V17)
{
timer2 = getValue.asInt();
if (timer2 == 1)
{
expireTime2 = millis() + slider2time;
}
else
{
expireTime2 = 0;
}
}
CAYENNE_IN(V18)
{
unsigned long slider2 = getValue.asInt();
slider2 = slider2 / 1023;
slider2time = slider2 * 60 * 1000;
}
// CAYENNE_IN(V19)
// {
// alarmButton = getValue.asInt();
// if (alarmButton == 1)
// {
// // rtc.setAlarmTime(13, 00, 10);
// rtc.setAlarmTime(00, 05, 10);
// rtc.attachInterrupt(alarmMatch);
// rtc.enableAlarm(rtc.MATCH_HHMMSS);
//
//
// }
// else
// {
// rtc.disableAlarm();
// // rtc.detachInterrupt();
// }
// }
// CAYENNE_IN(V22)
// {
// int sleepButton = getValue.asInt();
// if (sleepButton == 1)
// {
// WiFi.lowPowerMode();
// }
//
// else
// {
// WiFi.noLowPowerMode();
// }
// }