Last summer during vacation, was quite hot at my place. My green grass in the garden became ... brown and yellow - there was nobody to irrigate and was no rain, of course!
So I made a decision to buy irrigation controller and all that stuff. I wanted to have 7-8 zones, BT or wireless control, temperature and rain based control, RTC, Keypad, etc. The problem was that nobody had it or was to expencive.
So long story short I came up with idea to build one with all those features i need. Without having experience with uC I start to learn (google and youtube) a bit and build some "prototypes". Than IrrigatonController ver 1.0 was ready (December 2015):
Than I found @petewill IrrigationControler at youtube - but it was to hard for me from software (all this MySensors) and hardware side - I thought!
So I built new one - well it is almost done.
It is tested and working, few things are still missing like running without HA controller and rain sensor. Anyway I post some pictures and script what I've done. At my place it is working under Domoticz and manual (keypad). Tomorrow final wiring!
.
Any comments are more than welcome, know that script need some more work - but it is just a beginning.
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*******************************
*
* REVISION HISTORY
* based on Version 1.0 - Henrik Ekblad
* Version 2.0 - Marek Dajnowicz
*
* DESCRIPTION
* Example sketch showing how to control physical relays.
*
* http://www.mysensors.org/build/relay
*/
// Enable debug prints to serial monitor
#define MY_DEBUG
#define MY_RF24_CE_PIN A8 // żółty 51
#define MY_RF24_CS_PIN A9 // pomarańczowy 53
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
#define MY_NODE_ID 66
// Enable repeater functionality for this node
#define MY_REPEATER_FEATURE
#include <Wire.h>
#include <Time.h>
#include <SPI.h>
#include <MySensor.h>
#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include <DS3232RTC.h> // A DS3231/DS3232 library
#include <Keypad_I2C.h> // Klawiatura na I2c
#include <Keypad.h> // klawiatura
#define RELAY_1 2 // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
#define NUMBER_OF_RELAYS 8 // Total number of attached relays
#define RELAY_ON 1 // GPIO value to write to turn on attached relay
#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
#define ONE_WIRE_BUS 22 // Pin where dallase sensor is connected MEGA256
#define MAX_ATTACHED_DS18B20 16
#define TEMPERATURE_PRECISION 12
#define CHILD_ID_SPRINKLER1 1
#define CHILD_ID_SPRINKLER2 2
#define CHILD_ID_SPRINKLER3 3
#define CHILD_ID_SPRINKLER4 4
#define CHILD_ID_SPRINKLER5 5
#define CHILD_ID_SPRINKLER6 6
#define CHILD_ID_SPRINKLER7 7
#define CHILD_ID_PUMP 10
#define CHILD_ID_TEMP 11
#define CHILD_ID_TEMP2 12
OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature.
boolean timeReceived = false;
byte clock[8] = {0x0, 0xe, 0x15, 0x17, 0x11, 0xe, 0x0}; // fetching time indicator
byte raindrop[8] = {0x4, 0x4, 0xA, 0xA, 0x11, 0xE, 0x0,}; // fetching Valve Data indicator
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address to 0x27
DeviceAddress addrT1 = { 0x28, 0xFF, 0x9F, 0x80, 0x93, 0x15, 0x04, 0xF7 }; //DS18 Dallas temp.
float T1;
float lastTemperature[MAX_ATTACHED_DS18B20];
int numSensors = 0;
MyMessage msgValve1(CHILD_ID_SPRINKLER1, V_LIGHT);
MyMessage msgValve2(CHILD_ID_SPRINKLER2, V_LIGHT);
MyMessage msgValve3(CHILD_ID_SPRINKLER3, V_LIGHT);
MyMessage msgValve4(CHILD_ID_SPRINKLER4, V_LIGHT);
MyMessage msgValve5(CHILD_ID_SPRINKLER5, V_LIGHT);
MyMessage msgValve6(CHILD_ID_SPRINKLER6, V_LIGHT);
MyMessage msgValve7(CHILD_ID_SPRINKLER7, V_LIGHT);
MyMessage msgPump(CHILD_ID_PUMP, V_LIGHT);
MyMessage msgT1(CHILD_ID_TEMP, V_TEMP);
MyMessage msgT2(CHILD_ID_TEMP2, V_TEMP);
/**** Kepad settings */
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {47, 45, 43, 41};
byte colPins[COLS] = {39, 37, 35, 33};
int i2caddress = 0x20;
Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, i2caddress );
bool state;
// system messages
const char *string_table[] =
{
" WELCOME! =)", // 0
"DOMOTICZ TIME", // 1
"WATERING", // 2
" SYSTEM CHECK ", // 3
" STARTING UP THE", // 4
" WATERING SYSTEM", // 5
" Popmp is ON ", // 6
" MySensors", // 7
" Watering System", // 8
" Please wait !!" // 9
};
const char *string_table2[] = {
"Strefa 1", "Strefa 2", "Strefa 3", "Strefa 4", "Strefa 5", "Strefa 6", "Strefa 7", "Pompa zasilająca" // ZONE 1...2...
};
const unsigned long tUpdate = 60000; // update interval for temp sensors
unsigned long t0;
void setup()
{
for (int sensor = 1, pin = RELAY_1; sensor <= NUMBER_OF_RELAYS; sensor++, pin++)
{
pinMode(pin, OUTPUT); // Then set relay pins in output mode
digitalWrite(pin, RELAY_OFF); // set all relays OFF
saveState(sensor, state); // save data at startup.
}
requestTime();
kpd.begin(); //keypad
sensors.begin(); //dallas temp
sensors.setResolution(addrT1, TEMPERATURE_PRECISION);
lcd.begin(20, 4); //(20 characters and 4 line display)
lcd.clear();
lcd.backlight();
lcd.createChar(0, clock);
lcd.createChar(1, raindrop);
lcd.home();
lcd.print(string_table[4]);
lcd.setCursor(0, 1);
lcd.print(string_table[5]);
lcd.setCursor(0, 3);
lcd.print(string_table[7]);
delay(3000);
for (int i = 0; i < 20; i++) {
delay(100);
lcd.scrollDisplayLeft();
}
lcd.clear();
lcd.home();
lcd.print(string_table[0]);
lcd.setCursor(0, 1);
lcd.print(string_table[3]);
(lcd.setCursor(0, 3));
for (int M = 1; M >= 0; M--) // countdown
{
lcd.setCursor(10, 3);
lcd.print(M);
delay(1000);
}
lcd.clear();
lcd.home ();
requestTime();
ServerUpdate();
}
void presentation()
{
// Send the sketch version information to the gateway and Controller
sendSketchInfo("Watering", "2.0");
for (int sensor = 1, pin = RELAY_1; sensor <= NUMBER_OF_RELAYS; sensor++, pin++) {
// Register all sensors to gw (they will be created as child devices)
present(sensor, S_LIGHT, string_table2[sensor - 1]); // use CHILD ID names from table
}
present(CHILD_ID_TEMP, S_TEMP,"Dallas");
present(CHILD_ID_TEMP2, S_TEMP,"RTC Temp");
}
void loop()
{
domoticztime(); // to PRINT the time from conroller
keypad(); // READING KEYPAD
if ((millis() - t0) > tUpdate) ServerUpdate();
}
void ServerUpdate()
{
sensors.requestTemperatures();
T1 = sensors.getTempC(addrT1);
send(msgT1.set(T1 , 1));
int t= RTC.temperature()/4;
send(msgT2.set(t,2));
lcd.setCursor(11, 2);
lcd.print("T:");
lcd.print(T1);
lcd.print(char(223));
lcd.print("C");
lcd.setCursor(11, 3);
lcd.print("T:");
lcd.print(t);
lcd.print(char(223));
lcd.print("C");
t0 = millis();
}
void domoticztime()
{
lcd.home();
lcd.setCursor(0, 2);
// lcd.print(string_table[1]);
//lcd.setCursor(2, 2);
lcd.write(byte(0));
lcd.setCursor(1, 2);
lcd.print(hour());
lcd.print(":");
int min = minute();
if (min < 10) lcd.print("0");
lcd.print(minute());
lcd.print(":");
lcd.print(second());
lcd.setCursor(0, 3);
lcd.print(day());
lcd.print("/");
lcd.print(month());
lcd.print("/");
lcd.print(year());
}
void keypad()
{
char key = kpd.getKey(); delay(50);
if (key == '*') ALL_OFF();
if (key == '#') WRONG();
if (key == '1') ZONE_1();
if (key == '2') ZONE_2();
if (key == '3') ZONE_3();
if (key == '4') ZONE_4();
if (key == '5') ZONE_5();
if (key == '6') ZONE_6();
if (key == '7') ZONE_7();
if (key == '8') WRONG();
if (key == '9') WRONG();
if (key == '0') WRONG();
if (key == 'D') DEBUG();
}
void DEBUG()
{for (int sensor = 1, pin = RELAY_1; sensor <= NUMBER_OF_RELAYS; sensor++, pin++)
{
state = loadState(sensor);
Serial.print("sensor: ");
Serial.print(sensor);
Serial.print(" / stan: ");
Serial.println(state);
}}
void ALL_OFF()// TURNING ALL ZONES OFF @ ONE KEY PRESSED
{
for (int sensor = 1, pin = RELAY_1; sensor <= NUMBER_OF_RELAYS; sensor++, pin++)
{
digitalWrite(pin, RELAY_OFF);
saveState(sensor, state);
}
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(" TURN ALL ZONES OFF");
Serial.println(" turn ALL OFF");
/*
send(msgValve1.set(0) );delay(100);
send(msgValve2.set(0) );delay(100);
send(msgValve3.set(0) );delay(100);
send(msgValve4.set(0) );delay(100);
send(msgValve5.set(0) );delay(100);
send(msgValve6.set(0) );delay(100);
send(msgValve7.set(0) );
*/
send(msgValve1.set(0), true); delay(100);
send(msgValve2.set(0), true);delay(100);
send(msgValve3.set(0), true);delay(100);
send(msgValve4.set(0), true);delay(100);
send(msgValve5.set(0), true);delay(100);
send(msgValve6.set(0), true);delay(100);
send(msgValve7.set(0), true);
DEBUG();
delay(1500);
lcd.clear();
}
void ZONE_1()
{ // zone 1, pin 2
byte pin=RELAY_1;
state = loadState(CHILD_ID_SPRINKLER1);
digitalWrite(pin, state ? RELAY_ON : RELAY_OFF);
saveState(CHILD_ID_SPRINKLER1, state);
lcd.setCursor(0, 1);
if (state == 1)
{
lcd.setCursor(0, 1);
lcd.print(" ");
}
send(msgValve1.set(state ? false : true), true);
}
void ZONE_2()
{
byte pin=RELAY_1+1;
state = loadState(CHILD_ID_SPRINKLER2);
digitalWrite(pin, state ? RELAY_ON : RELAY_OFF);
saveState(CHILD_ID_SPRINKLER2, state);
if (state == 1)
{
lcd.setCursor(1, 1);
lcd.print(" ");
}
send(msgValve2.set(state ? false : true), true);
}
void ZONE_3()
{
byte pin=RELAY_1+2;
state = loadState(CHILD_ID_SPRINKLER3);
digitalWrite(pin, state ? RELAY_ON : RELAY_OFF);
saveState(CHILD_ID_SPRINKLER3, state);
if (state == 1)
{
lcd.setCursor(2, 1);
lcd.print(" ");
}
send(msgValve3.set(state ? false : true), true);
}
void ZONE_4()
{
byte pin=RELAY_1+3;
state = loadState(CHILD_ID_SPRINKLER4);
digitalWrite(pin, state ? RELAY_ON : RELAY_OFF);
saveState(CHILD_ID_SPRINKLER4, state);
if (state == 1)
{
lcd.setCursor(3, 1);
lcd.print(" ");
}
send(msgValve4.set(state ? false : true), true);
}
void ZONE_5()
{
byte pin=RELAY_1+4;
state = loadState(CHILD_ID_SPRINKLER5);
digitalWrite(pin, state ? RELAY_ON : RELAY_OFF);
saveState(CHILD_ID_SPRINKLER5, state);
if (state == 1)
{
lcd.setCursor(4, 1);
lcd.print(" ");
}
send(msgValve5.set(state ? false : true), true);
}
void ZONE_6()
{
byte pin=RELAY_1+5;
state = loadState(CHILD_ID_SPRINKLER6);
digitalWrite(pin, state ? RELAY_ON : RELAY_OFF);
saveState(CHILD_ID_SPRINKLER6, state);
if (state == 1)
{
lcd.setCursor(5, 1);
lcd.print(" ");
}
send(msgValve6.set(state ? false : true), true);
}
void ZONE_7()
{
byte pin=RELAY_1+6;
state = loadState(CHILD_ID_SPRINKLER7);
digitalWrite(pin, state ? RELAY_ON : RELAY_OFF);
saveState(CHILD_ID_SPRINKLER7, state);
if (state == 1)
{
lcd.setCursor(6, 1);
lcd.print(" ");
}
send(msgValve7.set(state ? false : true), true);
}
void WRONG() {}
void receive(const MyMessage &message) {
byte zone;
if (message.isAck()) {
Serial.println("This is an ack from gateway");
}
// We only expect one type of message from controller. But we better check anyway.
if (message.type == V_LIGHT) {
// Change relay state
digitalWrite(message.sensor - 1 + RELAY_1, message.getBool() ? RELAY_ON : RELAY_OFF);
zone = message.sensor; // less typing :)
// Store state in eeprom
saveState(message.sensor, message.getBool());
// representing active zones at LCD
if (message.getBool() == RELAY_ON) // checking new state of relay
{
Serial.print("Watering ZONE: "); Serial.println(zone);
lcd.setCursor(0, 0);
lcd.print("Watering ZONE: ");
lcd.setCursor(zone - 1, 1);
lcd.print(zone);
}
if (message.getBool() == RELAY_OFF) // checking new state of relay
{
lcd.setCursor(zone - 1, 1);
lcd.print(" ");
}
// Write some debug info
Serial.print("Incoming change for ZONE:");
Serial.print(message.sensor);
Serial.print(", New status: ");
Serial.println(message.getBool());
}
}
Regards