Hi!
I recently modified the relay example sketch so that it fits my needs; maybe some of you can make use of my little work too.
Here's what you can do / what the features are:
- Easily add as much Relays / FETs as you want (or as much as the arduino allows) by entering the according pin numbers in the RELAYS[ ]-Array
- You can trigger each relay from your controller
- You can add a motion sensor and specify which (MOTION_ACTIVATED_RELAYS[ ]) of your relays should be triggered through motion and for how long (ON_TIMES[ ])
- The state of the motion sensor will be reported to your controller
- When a relay is changed through motion, the change will also be reported to your controller
- You can send a manual override from your controller, so that the motion will still be reported, but none of the relays will be triggered through motion
/**
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
Version 1.0 - Henrik Ekblad
Version 1.1 - HenryWhite
DESCRIPTION
Example sketch showing how to control physical relays.
This example will remember relay state after power failure.
Optional attachment of motion sensor to control the relays is possible.
Notes:
-- The Child-IDs of the attached relays range from 1 up to (1-(NUMBER_OF_RELAYS))
-- Make sure to adjust the potentiometer for triggertime on your motion sensor as leftmost as possible,
because the countdown will not start until the motion sensor reports back a "0" (no movement)
*/
//----------------------- Library Configuration ---------------------
//#define MY_DEBUG // uncomment to enable debug prints to serial monitor
//#define MY_REPEATER_FEATURE // uncomment to enable repeater functionality for this node
//#define MY_NODE_ID 20 // uncomment to define static node ID
// Enable and uncomment attached radio type
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
//#define MY_TRANSPORT_WAIT_READY_MS 1 // uncomment this to enter the loop() and setup()-function even when the node cannot be registered to gw
//----------------------- Relay and Motion Sensor Configuration -----------------------
#define MOTION // un-comment to enable motion sensing
#define NUMBER_OF_RELAYS 2 // Total number of attached relays. Must be equal to total number of elements in array below!
const int RELAYS[] = {3, 5}; // digital pins of attached relays
const int MOTION_ACTIVATED_RELAYS[] = {1, 0}; // 1 to trigger the relay through motion, 0 to not trigger. Array length must correspond to RELAYS[] array.
const long ON_TIMES[] = {300, 0}; // Specify for each element in MOTION_ACTIVATED_RELAYS, how long the specified relay should be active in seconds.
#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 MOTION_PIN 2 // The digital input pin of the motion sensor
#define MOTION_CHILD_ID 0 // Set the child id of the motion sensor
bool ack = 1; // set this to 1 if you want destination node to send ack back to this node
//----------------------- DO NOT CHANGE -----------------------------
#include <MySensors.h>
MyMessage motion_msg(MOTION_CHILD_ID, V_TRIPPED); // Initialize motion message
unsigned long trigger_millis[NUMBER_OF_RELAYS]; // Used for the timer
bool lastTripped = 0; // Used to store last motion sensor value
bool manual_override = 0; // if this gets set to 1 (e.g. by a switch or a command from the gateway), motion triggering of relays is deactivated
MyMessage relay_msg; // Initialize relay message
void before()
{
int i;
for (int sensor = 1, i = 0; sensor <= NUMBER_OF_RELAYS; sensor++, i++) {
// set relay pins to output mode
pinMode(RELAYS[i], OUTPUT);
// Restore relay to last known state (using eeprom storage)
digitalWrite(RELAYS[i], loadState(sensor) ? RELAY_ON : RELAY_OFF);
}
// set motion pin to output mode, if MOTION is defined
#ifdef MOTION
pinMode(MOTION_PIN, INPUT);
#endif
}
void setup()
{
#ifdef MOTION
// give the motion sensor some time to settle
Serial.println("Starting up. Please wait 8 seconds...");
delay(8000);
#endif
}
void presentation()
{
// Send the sketch version information to the gateway and Controller
sendSketchInfo("Relay/Motion", "1.0");
// Register all sensors to gw (they will be created as child devices)
for (int sensor = 1; sensor <= NUMBER_OF_RELAYS; sensor++) {
present(sensor, S_BINARY, "Relay", ack);
}
#ifdef MOTION
present(MOTION_CHILD_ID, S_MOTION, "Motion Sensor", ack);
#endif
}
void loop()
{
#ifdef MOTION
if (!manual_override) {
// Read digital motion value
bool tripped = digitalRead(MOTION_PIN) == HIGH;
if (lastTripped != tripped) {
Serial.print("New Motion State: ");
Serial.println(tripped);
// Send tripped value to gw
send(motion_msg.set(tripped ? "1" : "0"));
lastTripped = tripped;
// Change relay states, send new state to gw and store state in eeprom
if (tripped == 1) {
for (int i = 0; i < NUMBER_OF_RELAYS; i++) {
if (MOTION_ACTIVATED_RELAYS[i] == 1) {
digitalWrite(RELAYS[i], RELAY_ON);
relay_msg_constructor(i + 1, V_STATUS);
send(relay_msg.set(RELAY_ON));
trigger_millis[i] = millis();
Serial.print("Relay ");
Serial.print(RELAYS[i]);
Serial.println(" turned on");
saveState(i, 1);
}
}
}
}
for (int i = 0; i < NUMBER_OF_RELAYS; i++) {
if (tripped == 1 and MOTION_ACTIVATED_RELAYS[i] == 1 and trigger_millis[i] != 0) {
trigger_millis[i] = millis();
}
if ((trigger_millis[i] + ON_TIMES[i] * 1000 < millis()) and MOTION_ACTIVATED_RELAYS[i] == 1 and trigger_millis[i] != 0) {
digitalWrite(RELAYS[i], RELAY_OFF);
relay_msg_constructor(i + 1, V_STATUS);
send(relay_msg.set(RELAY_OFF));
Serial.print("Relay ");
Serial.print(RELAYS[i]);
Serial.println(" turned off");
saveState(i, 0);
trigger_millis[i] = 0;
}
}
}
else {
bool tripped = digitalRead(MOTION_PIN) == HIGH;
if (lastTripped != tripped) {
Serial.print("New Motion State: ");
Serial.println(tripped);
// Send tripped value to gw
send(motion_msg.set(tripped ? "1" : "0"));
lastTripped = tripped;
}
for (int i = 0; i < NUMBER_OF_RELAYS; i++) {
if (MOTION_ACTIVATED_RELAYS[i] == 1 and trigger_millis[i] != 0) {
trigger_millis[i] = 0; // reset running timers
}
}
}
#endif
}
void receive(const MyMessage &message)
{
// Handle incoming relay commands
if (message.type == V_STATUS) {
// Change relay state
if (RELAYS[message.sensor - 1]) {
digitalWrite(RELAYS[message.sensor - 1], message.getBool() ? RELAY_ON : RELAY_OFF);
// Store state in eeprom
saveState(message.sensor - 1, message.getBool());
// Write some debug info
Serial.print("Incoming change for sensor:");
Serial.print(message.sensor);
Serial.print(", New status: ");
Serial.println(message.getBool());
}
}
// Handle incoming manual override/bypass of motion sensor
if (message.type == V_ARMED and message.sensor == 0) {
manual_override = message.getBool();
Serial.print("Manual Override: ");
Serial.println(manual_override);
}
}
void relay_msg_constructor(int sensor, uint8_t type)
{
relay_msg.setSensor(sensor);
relay_msg.setType(type);
}
Additional Notes:
- The Child-IDs of the attached relays range from 1 up to (1-(NUMBER_OF_RELAYS))
- The default Child-ID for the motion sensor is 0
- Make sure to adjust the potentiometer for triggertime on your motion sensor as leftmost as possible, because the countdown-timer will not start until the motion sensor reports back a "0" (no movement)