@Ashley-Savage Had a big rewrite this evening and all seems good now. If you set it to a level then switch it off the level is remembered so if you issue an on command it goes to the previous level. It seems a little bit more stable as well but i'll not know fully until i put it outside for use in the wild as it where. I'm thinking i might change the DHT11 for a Dallas sensor though as i received a few waterproof ones this week as they should be more accurate and can support negative temps which living in the UK i'll need come the autumn.
/**
* 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.
*
*******************************
*
* DESCRIPTION
* This sketch provides a Dimmable LED Light along with Temp/Humidity/voltage sensing as well as Motion sensing.
*/
#include <SPI.h>
#include <MySensor.h>
#include <DHT.h>
#include <SimpleTimer.h>
#define SN "SecurityLED"
#define SV "1.3"
#define CHILD_ID_LIGHT 1
#define CHILD_ID_HUM 0
#define CHILD_ID_TEMP 1
#define CHILD_ID_VOLTAGE 2
#define CHILD_ID_PIR 3
#define EPROM_LIGHT_STATE 1
#define EPROM_DIMMER_LEVEL 2
#define LIGHT_OFF 0
#define LIGHT_ON 1
#define LED_PIN 5 // Arduino pin attached to MOSFET Gate pin
#define HUMIDITY_SENSOR_DIGITAL_PIN 6
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor.
#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define MY_DEFAULT_TX_LED_PIN A2
#define MY_DEFAULT_RX_LED_PIN A3
#define MY_DEFAULT_ERR_LED_PIN A4
int FADE_DELAY=50; // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
// the timer object
SimpleTimer timer;
int LastLightState=LIGHT_OFF;
int LastDimValue=100;
DHT dht;
float lastTemp;
boolean metric = true;
float lastHum;
float lastVolt;
int oldBatteryPcnt = 0;
int analogInput = A0;
float vout = 0.0;
float vin = 0.0;
int value = 0;
float R1 = 1000000.0;
float R2 = 454500.0;
boolean sensordelay;
MySensor gw;
MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT);
MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
MyMessage msgVolt(CHILD_ID_VOLTAGE, V_VOLTAGE);
MyMessage msg(CHILD_ID_PIR, V_TRIPPED);
void setup()
{
gw.begin(incomingMessage, AUTO, false);
// Send the Sketch Version Information to the Gateway
gw.sendSketchInfo(SN, SV);
dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input
pinMode(analogInput, INPUT); // sets the battery voltage reading input
gw.present(CHILD_ID_LIGHT, S_DIMMER );
gw.present(CHILD_ID_HUM, S_HUM);
gw.present(CHILD_ID_TEMP, S_TEMP);
gw.present(CHILD_ID_VOLTAGE, V_VOLTAGE);
gw.present(CHILD_ID_PIR, S_MOTION);
sensordelay=0;
timer.setInterval(120000,readTempHum); // Send Temp every 2 mins
timer.setInterval(300000,measureBattery); // Send voltage every 5 mins
//Retreive our last light state from the eprom
int LightState=gw.loadState(EPROM_LIGHT_STATE);
if (LightState<=1) {
LastLightState=LightState;
int DimValue=gw.loadState(EPROM_DIMMER_LEVEL);
if ((DimValue>0)&&(DimValue<=100)) {
//There should be no Dim value of 0, this would mean LIGHT_OFF
LastDimValue=DimValue;
}
}
//Here you actualy switch on/off the light with the last known dim level
SetCurrentState2Hardware();
Serial.println( "Node ready to receive messages..." );
}
void loop()
{
// Process incoming messages (like config and light state from controller)
gw.process();
// Read digital motion value
boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;
if (tripped ==1 && sensordelay==0) {
FADE_DELAY=0;
Serial.print("Security Sensor state : ");
Serial.println(tripped);
gw.send(msg.set(tripped?"1":"0")); // Send tripped value to gw
tripped=0;
gw.send(msg.set(tripped?"1":"0")); // Send tripped value to gw
sensordelay=1;
timer.setTimeout(10000,ResetTripped);
}
timer.run();
}
void incomingMessage(const MyMessage &message)
{
if (message.type == V_LIGHT) {
Serial.println( "V_LIGHT command received..." );
int lstate= atoi( message.data );
if ((lstate<0)||(lstate>1)) {
Serial.println( "V_LIGHT data invalid (should be 0/1)" );
return;
}
LastLightState=lstate;
gw.saveState(EPROM_LIGHT_STATE, LastLightState);
if ((LastLightState==LIGHT_ON)&&(LastDimValue==0)) {
//In the case that the Light State = On, but the dimmer value is zero,
//then something (probably the controller) did something wrong,
//for the Dim value to 100%
LastDimValue=100;
gw.saveState(EPROM_DIMMER_LEVEL, LastDimValue);
}
//When receiving a V_LIGHT command we switch the light between OFF and the last received dimmer value
//This means if you previously set the lights dimmer value to 50%, and turn the light ON
//it will do so at 50%
}
else if (message.type == V_DIMMER) {
Serial.println( "V_DIMMER command received..." );
int dimvalue= atoi( message.data );
if ((dimvalue<0)||(dimvalue>100)) {
Serial.println( "V_DIMMER data invalid (should be 0..100)" );
return;
}
if (dimvalue==0) {
LastLightState=LIGHT_OFF;
LastDimValue=0;
}
else {
LastLightState=LIGHT_ON;
LastDimValue=dimvalue;
gw.saveState(EPROM_DIMMER_LEVEL, LastDimValue);
}
}
else {
Serial.println( "Invalid command received..." );
return;
}
Serial.println( LastDimValue );
//Here you set the actual light state/level
SetCurrentState2Hardware();
}
static int currentLevel = 0; // Current dim level...
void fadeToLevel( int toLevel ) {
int delta = ( toLevel - currentLevel ) < 0 ? -1 : 1;
while ( currentLevel != toLevel ) {
currentLevel += delta;
analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) );
delay( FADE_DELAY );
}
}
void SetCurrentState2Hardware()
{
if (LastLightState==LIGHT_OFF) {
Serial.println( "Light state: OFF" );
fadeToLevel(0);
}
else {
Serial.print( "Light state: ON, Level: " );
Serial.println( LastDimValue );
fadeToLevel( LastDimValue );
}
//Send current state to the controller
SendCurrentState2Controller();
}
void SendCurrentState2Controller()
{
if ((LastLightState==LIGHT_OFF)||(LastDimValue==0)) {
gw.send(dimmerMsg.set(0));
}
else {
gw.send(dimmerMsg.set(LastDimValue));
}
}
void ResetTripped(){
sensordelay=0;
FADE_DELAY=50;
}
void readTempHum() {
delay(dht.getMinimumSamplingPeriod());
float temperature = dht.getTemperature();
if (isnan(temperature)) {
Serial.println("Failed reading temperature from DHT");
} else if (temperature != lastTemp) {
lastTemp = temperature;
if (!metric) {
temperature = dht.toFahrenheit(temperature);
}
gw.send(msgTemp.set(temperature, 1));
Serial.print("T: ");
Serial.println(temperature);
}
float humidity = dht.getHumidity();
if (isnan(humidity)) {
Serial.println("Failed reading humidity from DHT");
} else if (humidity != lastHum) {
lastHum = humidity;
gw.send(msgHum.set(humidity, 1));
Serial.print("H: ");
Serial.println(humidity);
}
}
void measureBattery() {
// read the value at analog input
value = analogRead(analogInput);
vout = (value * 5.0) / 1024.0; // see text
vin = vout / (R2/(R1+R2));
int batteryPcnt = value / 10;
#ifdef DEBUG
Serial.print("Battery Voltage: ");
Serial.print(vin);
Serial.println(" V");
Serial.print("Battery percent: ");
Serial.print(batteryPcnt);
Serial.println(" %");
#endif
if (oldBatteryPcnt != batteryPcnt) {
// Power up radio after sleep
gw.sendBatteryLevel(batteryPcnt);
gw.send(msgVolt.set(vin, 1));
oldBatteryPcnt = batteryPcnt;
}
}