Created
November 4, 2015 01:52
-
-
Save sytone/de62d298ffda246ee20d to your computer and use it in GitHub Desktop.
Arduino Code for Garage Node
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This proram is for a node that is always powered, do not | |
use this if you want a low powered node on your network. | |
This node will be subscribing and listening for MQTT | |
messages all the time and also sending out messages | |
when state changes occur. | |
*/ | |
#include <RF24Mesh_config.h> | |
#include <RF24.h> | |
#include <SPI.h> | |
#include <RF24Mesh.h> | |
#include <RF24Network.h> | |
#include <stdlib.h> | |
//#include <printf.h> | |
#include <RF24Ethernet.h> | |
#include <PubSubClient.h> | |
#if !defined __arm__ && !defined __ARDUINO_X86__ | |
#include <EEPROM.h> | |
#endif | |
/* | |
* Comment this line out when you are deploying the | |
* code for the last time. | |
*/ | |
#define DEBUG | |
/* Configure the node properties here | |
* NOTE: This assumes all nodes, Gateway and MQTT brokers are in same subnet. | |
*/ | |
#define HA_NODE_NETWORK_ID 5 // 5-253 | |
#define HA_NODE_NETWORK_GW_ID 2 // 5-253 | |
#define HA_NODE_NETWORK_MQTT_ID 2 // 5-253 | |
/* General networking configuration */ | |
#define HA_NODE_NETWORK_OCT_ONE 10 | |
#define HA_NODE_NETWORK_OCT_TWO 10 | |
#define HA_NODE_NETWORK_OCT_THREE 2 | |
#define HS_NODE_MESH_CONNECTIVITY 30000 // Time in ms between mesh connectivity checks. | |
// macros from DateTime.h | |
/* Useful Constants */ | |
#define SECS_PER_MIN (60UL) | |
#define SECS_PER_HOUR (3600UL) | |
#define SECS_PER_DAY (SECS_PER_HOUR * 24L) | |
/* Useful Macros for getting elapsed time */ | |
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN) | |
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN) | |
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR) | |
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) | |
#define RELAY_ON 0 | |
#define RELAY_OFF 1 | |
#define RELAY_1 4 | |
#define RELAY_2 5 | |
#define SWITCH_1 2 | |
#define SWITCH_2 3 | |
#define DOOR_1_STATE "HOME/Garage/Door1/STATE" | |
#define DOOR_2_STATE "HOME/Garage/Door2/STATE" | |
#define DOOR_1_CMD "HOME/Garage/Door1/CMD" | |
#define DOOR_2_CMD "HOME/Garage/Door2/CMD" | |
#define DOOR_STATE_POLL_FREQUENCY 10000 | |
#define HEARTBEAT_PIN 10 | |
#define TEMP_SENSOR 5 | |
#define GARAGE_TEMP "HOME/Garage/Temperature" | |
/* | |
* Configure the radio CE & CS pins | |
* If you used the guides at http://www.sytone.com these should match your | |
* configuration on the Arduino. | |
*/ | |
RF24 radio(7, 8); | |
RF24Network network(radio); | |
RF24Mesh mesh(radio, network); | |
RF24EthernetClass RF24Ethernet(radio, network, mesh); | |
IPAddress mqttServer(HA_NODE_NETWORK_OCT_ONE, HA_NODE_NETWORK_OCT_TWO, HA_NODE_NETWORK_OCT_THREE, HA_NODE_NETWORK_MQTT_ID); | |
// RF24 Version | |
EthernetClient ethClient; | |
PubSubClient mqttClient(ethClient); | |
// Internal vars | |
uint32_t counter = 0; | |
uint32_t reqTimer = 0; | |
long mesh_timer = 0; | |
long doorOpenTimer = 0; | |
char mqttClientId[10]; | |
long relaytest = 0; | |
boolean relayFlip = 0; | |
void setup() | |
{ | |
digitalWrite(RELAY_1, RELAY_OFF); | |
digitalWrite(RELAY_2, RELAY_OFF); | |
pinMode(RELAY_1, OUTPUT); | |
pinMode(RELAY_2, OUTPUT); | |
digitalWrite(RELAY_1, RELAY_OFF); | |
digitalWrite(RELAY_2, RELAY_OFF); | |
pinMode(SWITCH_1, INPUT); // switchPin is an input | |
digitalWrite(SWITCH_1, HIGH); // Activate internal pullup resistor | |
pinMode(SWITCH_2, INPUT); // switchPin is an input | |
digitalWrite(SWITCH_2, HIGH); // Activate internal pullup resistor | |
pinMode(HEARTBEAT_PIN, OUTPUT); // switchPin is an input | |
pinMode(TEMP_SENSOR, INPUT); | |
Serial.begin(115200); | |
// Setup the Node Client ID | |
String mqttClientID = "HANODE"; | |
mqttClientID += HA_NODE_NETWORK_ID; | |
mqttClientID.toCharArray(mqttClientId, 10); | |
publishNodeLog("Start"); | |
IPAddress myIP(HA_NODE_NETWORK_OCT_ONE, HA_NODE_NETWORK_OCT_TWO, HA_NODE_NETWORK_OCT_THREE, HA_NODE_NETWORK_ID); | |
Ethernet.begin(myIP); | |
mesh.begin(); | |
IPAddress gwIP(HA_NODE_NETWORK_OCT_ONE, HA_NODE_NETWORK_OCT_TWO, HA_NODE_NETWORK_OCT_THREE, HA_NODE_NETWORK_GW_ID); | |
Ethernet.set_gateway(gwIP); | |
mqttClient.setServer(mqttServer, 1883); | |
mqttClient.setCallback(callback); | |
#ifdef DEBUG | |
Serial.println(F("** Network Address")); | |
Serial.print(F(" NodeID: ")); | |
Serial.print(mesh._nodeID); | |
Serial.print("\t"); | |
Serial.print(F(" RF24Network Address: ")); | |
Serial.println(mesh.mesh_address, OCT); | |
Serial.print(F(" MQTT Client: ")); | |
Serial.print(mqttClientId); | |
Serial.print("\t"); | |
Serial.print(F(" MQTT Address: ")); | |
Serial.print(mqttClient.getIp(), OCT); | |
Serial.print(":"); | |
Serial.println(mqttClient.getPort()); | |
Serial.println(); | |
Serial.println(F("**********************************")); | |
#endif | |
// Allow the hardware to sort itself out | |
delay(4000); | |
mesh_timer = millis(); | |
doorOpenTimer = millis(); | |
relaytest = millis(); | |
} | |
void loop() | |
{ | |
if (!mqttClient.connected()) { | |
reconnect(); | |
} | |
mqttClient.loop(); | |
// Optional: If the node needs to move around physically, or using failover nodes etc., | |
// enable address renewal | |
if (millis() - mesh_timer > HS_NODE_MESH_CONNECTIVITY) { //Every 30 seconds, test mesh connectivity | |
mesh_timer = millis(); | |
if (!mesh.checkConnection()) { | |
//refresh the network address | |
mesh.renewAddress(); | |
publishNodeLog("Renewed Mesh Address."); | |
} | |
else { | |
publishNodeLog("Heartbeat"); | |
digitalWrite(HEARTBEAT_PIN, HIGH); // turn the LED on (HIGH is the voltage level) | |
delay(250); // wait for a second | |
digitalWrite(HEARTBEAT_PIN, LOW); // turn the LED off by making the voltage LOW | |
float farh = ((((analogRead(TEMP_SENSOR) / 1024.0) * 5000) / 10) * 9) / 5 + 32; | |
char temp[6]; | |
dtostrf(farh, 6, 4, temp); | |
publishMessage(GARAGE_TEMP, temp); | |
} | |
} | |
if (millis() - doorOpenTimer > DOOR_STATE_POLL_FREQUENCY) { | |
doorOpenTimer = millis(); | |
if (digitalRead(SWITCH_1) == 0) { | |
publishMessage(DOOR_1_STATE, "OPEN"); | |
} | |
else { | |
publishMessage(DOOR_1_STATE, "CLOSED"); | |
} | |
if (digitalRead(SWITCH_2) == 0) { | |
publishMessage(DOOR_2_STATE, "OPEN"); | |
} | |
else { | |
publishMessage(DOOR_2_STATE, "CLOSED"); | |
} | |
} | |
} | |
void publishNodeLog(char* message) { | |
String nodeMessage = mqttClientId; | |
nodeMessage += ":"; | |
nodeMessage += getTimeString(); | |
nodeMessage += ":"; | |
nodeMessage += message; | |
Serial.println(nodeMessage.c_str()); | |
String mqttTopic = "HOME/Test/Mesh/"; | |
mqttTopic += mqttClientId; | |
if (mqttClient.connected()) { | |
mqttClient.publish(mqttTopic.c_str(), nodeMessage.c_str()); | |
} | |
} | |
void publishMessage(char *topic, char *message) { | |
if (mqttClient.connected()) { | |
mqttClient.publish(topic, message); | |
} | |
} | |
long lastCmdTimeForDoorOne = 0; | |
long lastCmdTimeForDoorTwo = 0; | |
void callback(char* topic, byte* payload, unsigned int length) { | |
String topicName = String(topic); | |
if (millis() - lastCmdTimeForDoorOne < 5000 && topicName == DOOR_1_CMD) { // Ignore messages for 5 seconds. | |
return; | |
} | |
if (millis() - lastCmdTimeForDoorTwo < 5000 && topicName == DOOR_2_CMD) { // Ignore messages for 5 seconds. | |
return; | |
} | |
if (topicName == DOOR_1_CMD) { | |
lastCmdTimeForDoorOne = millis(); | |
digitalWrite(RELAY_1, RELAY_ON);// set the Relay ON | |
delay(2000); // wait for a second | |
digitalWrite(RELAY_1, RELAY_OFF);// set the Relay OFF | |
} | |
if (topicName == DOOR_2_CMD) { | |
lastCmdTimeForDoorTwo = millis(); | |
digitalWrite(RELAY_2, RELAY_ON);// set the Relay ON | |
delay(2000); // wait for a second | |
digitalWrite(RELAY_2, RELAY_OFF);// set the Relay OFF | |
} | |
} | |
void reconnect() { | |
// Loop until we're reconnected | |
while (!mqttClient.connected()) { | |
publishNodeLog("Attempting MQTT connection..."); | |
// If we are not connected to mesh MQTT connections will fail. | |
while (!mesh.checkConnection()) { | |
//refresh the network address | |
publishNodeLog("Mesh Client disconnected, attempting connection..."); | |
mesh.renewAddress(); | |
delay(2000); | |
} | |
if (!ethClient.connected()) { | |
publishNodeLog("Ethernet Client disconnected..."); | |
} | |
// Attempt to connect | |
if (mqttClient.connect(mqttClientId)) { | |
// Once connected, publish an announcement... | |
publishNodeLog("Connected to network and MQTT"); | |
// ... and resubscribe | |
mqttClient.subscribe(DOOR_1_CMD); | |
mqttClient.subscribe(DOOR_2_CMD); | |
} | |
else { | |
Serial.print("failed, rc="); | |
Serial.print(mqttClient.state()); | |
Serial.println(" try again in 5 seconds"); | |
// Wait 5 seconds before retrying | |
delay(5000); | |
} | |
} | |
} | |
String getTimeString() { | |
long milliseconds = millis() / 1000; | |
int days = elapsedDays(milliseconds); | |
int hours = numberOfHours(milliseconds); | |
int minutes = numberOfMinutes(milliseconds); | |
int seconds = numberOfSeconds(milliseconds); | |
String returnedTime; | |
returnedTime.concat(days); | |
returnedTime.concat(":"); | |
returnedTime.concat(hours); | |
returnedTime.concat(":"); | |
returnedTime.concat(minutes); | |
returnedTime.concat(":"); | |
returnedTime.concat(seconds); | |
return returnedTime; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment