/**
* 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.0 - Morello Tommaso - Ikea Dioder futures replication with no mysensor support. Button S1 and S2 changed as up/down dimmer buttons.
* Version 1.0.1 - Morello Tommaso - code lines review.
* Version 1.0.2 - Morello Tommaso - store the last brightness value when dimmer up/down and use it when switch on.
* Version 1.1.0 - Morello Tommaso - Integration with Mysensors, only send the current status to the gateway.
* Version 1.1.1 - Morello Tommaso - manage when the dimmer down button switch off the light.
* Version 1.2.0 - Morello Tommaso - Add messages from gateway processing
* Version 1.3.0 - Morello Tommaso - fade transition
* Version 1.3.1 - Morello Tommaso - add message status request
* Version 1.3.2 - Morello Tommaso - bug fixing
* Version 1.3.3 - Morello Tommaso - auto sensor ID
*
*
* DESCRIPTION
* Example sketch showing how to control ikea DIODER.
*/
#include <MyTransportNRF24.h>
#include <MyHwATMega328.h>
#include <MySensor.h>
#include <SPI.h>
#define WHEEL_PIN A0
#define RED_PIN 3
#define GREEN_PIN 6
#define BLUE_PIN 5
#define POWER_BUTTON_PIN 4 //S3
#define DIMMER_UP_BUTTON_PIN 7 //S1
#define DIMMER_DOWN_BUTTON_PIN 2 //S2
#define FADE_DELAY 5
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
const int brightMin = 0; //min bright value
const int brightMax = 255; //max brigtness value
const int brigthOffset = 15; //dimmer step
const int saturation = 255; //we'll keep stauration always max
int hue, brightness, oldBrightness;
int wheelValueHue = 0; //Wheel position converted in hue value
int oldWheelValueHue = 255;
int statusOn;
unsigned int r, g, b; //final RGB value
unsigned int c_r, c_g, c_b; //current RGB value
String rgb = "";
// NRFRF24L01 radio driver (set low transmit power by default)
MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW);
// Select AtMega328 hardware profile
MyHwATMega328 hw;
// Construct MySensors library
MySensor gw(radio, hw);
MyMessage dimmerMsg(0, V_DIMMER);
MyMessage lightMsg(0, V_LIGHT);
MyMessage rgbMsg(1, V_RGB);
void setup()
{
//Mysensors setup
//Initialize library and add callback for incoming messages
gw.begin(incomingMessage, true, true);
//Register the LED Color Light and the dimmer light as two sensors with the gateway
gw.present(0, S_DIMMER);
gw.present(1, S_RGB_LIGHT);
//Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("MySensorDioder", "1.3.2");
//Set pins to output. We'll use PWM output.
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
//Wheel connected to an analogue pin as input.
pinMode(WHEEL_PIN, INPUT);
//Buttons connected to digital input
pinMode(POWER_BUTTON_PIN, INPUT);
pinMode(DIMMER_UP_BUTTON_PIN, INPUT);
pinMode(DIMMER_DOWN_BUTTON_PIN, INPUT);
// Activate internal pull-ups
digitalWrite(POWER_BUTTON_PIN, HIGH);
digitalWrite(DIMMER_UP_BUTTON_PIN, HIGH);
digitalWrite(DIMMER_DOWN_BUTTON_PIN, HIGH);
//in this version we start with min brightness
brightness = oldBrightness = brightMin;
statusOn = 0;
c_r = c_g = c_b = 0;
//initialize the analog reading array
//to avoid noise in analog input we make several reading and then we get the average value
for (int thisReading = 0; thisReading < numReadings; thisReading++)
{
//The Hue potentiometer value is mapped to degrees - 0 to 360 - as the range of hue values.
readings[thisReading] = map(analogRead(WHEEL_PIN), 0, 1023, 0, 360);
//Serial.println(readings[thisReading]);
total = total + readings[thisReading];
}//for
Serial.println("Setup... end.");
}//setup
void loop()
{
//to avoid noise in analog input we make several reading and then we get the average value
//subtract the last reading
total = total - readings[readIndex];
//read from the sensor
//The Hue potentiometer value is mapped to degrees - 0 to 360 - as the range of hue values.
readings[readIndex] = map(analogRead(WHEEL_PIN), 0, 1023, 0, 360);
//add the reading to the total
total = total + readings[readIndex];
//advance to the next position in the array:
readIndex = readIndex + 1;
//if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
}//if
//calculate the average and truncate it
wheelValueHue = int(total / numReadings);
//we consider only significative changes of wheel
if((wheelValueHue > oldWheelValueHue+1) || (wheelValueHue < oldWheelValueHue-1))
{
Serial.println("Wheel position changed.");
Serial.print("Wheel position: ");
Serial.println(wheelValueHue);
hue = map(wheelValueHue, 0, 360, 0, 255);
Serial.print("Hue value of the Wheel position: ");
Serial.println(hue);
//Conversion to RGB.
HSBToRGB(hue, saturation, brightness, &r, &g, &b);
//send value to lights
commandLights(r, g, b, false);
//send the value to the mysensor gateway
gw.send(dimmerMsg.set(map(brightness, 0, 255, 0, 100)));
gw.send(rgbMsg.set(rgb.c_str()));
oldWheelValueHue = wheelValueHue;
}//if
//check of power button
if(!digitalRead(POWER_BUTTON_PIN))
{
//Delay to avoid noise values. Can also be managed by debouncer.
delay(100);
if(!digitalRead(POWER_BUTTON_PIN))
{
//after 100ms the value is 0, so it is a real push button
Serial.println("Power button push.");
if(!statusOn && (brightness == oldBrightness))
//this is a first switch on, we use the max brightness value
brightness = brightMax;
else
brightness = statusOn ? brightMin : oldBrightness;
Serial.print("Brightness: ");
Serial.println(brightness);
statusOn = !statusOn;
HSBToRGB(hue, saturation, brightness, &r, &g, &b);
commandLights(r, g, b, true);
//send the value to the mysensor gateway
gw.send(lightMsg.set(statusOn));
gw.send(dimmerMsg.set(map(brightness, 0, 255, 0, 100)));
gw.send(rgbMsg.set(rgb.c_str()));
}//if
}//if
//check of up button
if(!digitalRead(DIMMER_UP_BUTTON_PIN))
{
//Delay to avoid noise values. Can also be managed by debouncer.
delay(100);
if(!digitalRead(DIMMER_UP_BUTTON_PIN))
{
//after 100ms the value is 0, so it is a real push button
Serial.println("Dimmer up button push.");
brightness = brightness + brigthOffset;
//max value allowed
if(brightness > brightMax)
brightness = brightMax;
oldBrightness = brightness;
statusOn=1; //this button makes always the status as on
Serial.print("Brightness: ");
Serial.println(brightness);
HSBToRGB(hue, saturation, brightness, &r, &g, &b);
commandLights(r, g, b, true);
//send the value to the mysensor gateway
gw.send(lightMsg.set(statusOn));
gw.send(dimmerMsg.set(map(brightness, 0, 255, 0, 100)));
gw.send(rgbMsg.set(rgb.c_str()));
}//if
}//if
//check of down button
if(digitalRead(DIMMER_DOWN_BUTTON_PIN) == 0)
{
//Delay to avoid noise values. Can also be managed by debouncer.
delay(100);
if(digitalRead(DIMMER_DOWN_BUTTON_PIN) == 0)
{
//after 100ms the value is 0, so it is a real push button
Serial.println("Dimmer down button push.");
brightness = brightness - brigthOffset;
//min value allowed
if(brightness <= brightMin)
{
brightness = brightMin;
statusOn=0;
}
else
{
statusOn=1;
oldBrightness = brightness;
}
Serial.print("Brightness: ");
Serial.println(brightness);
HSBToRGB(hue, saturation, brightness, &r, &g, &b);
commandLights(r, g, b, true);
//send the value to the mysensor gateway
gw.send(lightMsg.set(statusOn));
gw.send(dimmerMsg.set(map(brightness, 0, 255, 0, 100)));
gw.send(rgbMsg.set(rgb.c_str()));
}//if
}//if
gw.process();
}//loop
void HSBToRGB(unsigned int inHue, unsigned int inSaturation, unsigned int inBrightness,unsigned int *oR, unsigned int *oG, unsigned int *oB)
{
//based on http://academe.co.uk/2012/04/arduino-cycling-through-colours-of-the-rainbow/
if (inSaturation == 0)
{
// achromatic (grey)
*oR = *oG = *oB = inBrightness;
}
else
{
unsigned int scaledHue = (inHue * 6);
unsigned int sector = scaledHue >> 8; //sector 0 to 5 around the color wheel
unsigned int offsetInSector = scaledHue - (sector << 8); //position within the sector
unsigned int p = (inBrightness * ( 255 - inSaturation )) >> 8;
unsigned int q = (inBrightness * ( 255 - ((inSaturation * offsetInSector) >> 8) )) >> 8;
unsigned int t = (inBrightness * ( 255 - ((inSaturation * ( 255 - offsetInSector )) >> 8) )) >> 8;
switch( sector ) {
case 0:
//The Hue standard wheel has a range of color as: Red -> yellow -> green -> blue -> Red (again)
//The ikea dioder goes: white -> yellow -> green -> blue -> red
//so we use the tradionals 6 levels but with a customization of the first sector
//*oR = inBrightness;
//*oG = t;
//*oB = p;
*oR = inBrightness;
*oG = inBrightness;
*oB = q;
break;
case 1:
*oR = q;
*oG = inBrightness;
*oB = p;
break;
case 2:
*oR = p;
*oG = inBrightness;
*oB = t;
break;
case 3:
*oR = p;
*oG = q;
*oB = inBrightness;
break;
case 4:
*oR = t;
*oG = p;
*oB = inBrightness;
break;
default: // case 5:
*oR = inBrightness;
*oG = p;
*oB = q;
break;
}//switch
//int RGB = ((int)r << 16L) | ((int)g << 8L) | (int)b;
//rgb = String(RGB, HEX);
String hex_r = String(r, HEX);
if(hex_r.length() < 2) hex_r = "0" + hex_r;
String hex_g = String(g, HEX);
if(hex_g.length() < 2) hex_g = "0" + hex_g;
String hex_b = String(b, HEX);
if(hex_b.length() < 2) hex_b = "0" + hex_b;
rgb = hex_r + hex_g + hex_b;
}//else
}//HSBToRGB
void commandLights(unsigned int r, unsigned int g, unsigned int b, bool fade)
{
Serial.println("Send command to lights.");
if(fade)
{
int delta_r = ( r < c_r ) ? -1 : 1;
int delta_g = ( g < c_g ) ? -1 : 1;
int delta_b = ( b < c_b ) ? -1 : 1;
while((r != c_r) || (g != c_g) || (b != c_b))
{
c_r += (r != c_r) ? delta_r : 0;
c_g += (g != c_g) ? delta_g : 0;
c_b += (b != c_b) ? delta_b : 0;
analogWrite(RED_PIN, c_r);
analogWrite(GREEN_PIN, c_g);
analogWrite(BLUE_PIN, c_b);
delay(FADE_DELAY);
}//while
}
else
{
analogWrite(RED_PIN, r);
analogWrite(GREEN_PIN, g);
analogWrite(BLUE_PIN, b);
}
Serial.print("Bright: ");
Serial.println(brightness);
Serial.print("Red: ");
Serial.println(r);
Serial.print("Green: ");
Serial.println(g);
Serial.print("Blue: ");
Serial.println(b);
Serial.print("RGB in HEX: ");
Serial.println(rgb);
Serial.println("");
}//commandLights
void incomingMessage(const MyMessage &message)
{
long int message_status;
int messageCommand = mGetCommand(message);
Serial.print("Incoming message: ");
Serial.println(message.type);
if (message.type == V_LIGHT)
{
if(messageCommand == 2)
{
//requested light status from gateway
gw.send(lightMsg.set(statusOn));
}//if
}//if
else if (message.type == V_DIMMER)
{
if(messageCommand == 1)
{
Serial.print("Incoming light level from gateway. Level: ");
message_status = message.getInt();
Serial.println(message_status);
if((message_status > 100) || (message_status < 0))
Serial.println("Wrong level received.");
else
{
int newBrightness = map(message_status,0,100,0,255);
if(newBrightness == 0)
{
statusOn = 0;
oldBrightness = brightness;
}//if
else
statusOn = 1;
brightness = newBrightness;
}//else
}//if
else
//requested dimmer status from gateway
gw.send(dimmerMsg.set(map(brightness, 0, 255, 0, 100)));
}//else if
else if (message.type == V_RGB)
{
if(messageCommand == 1)
{
Serial.print("Incoming light rgb change from gateway. rgb requested: ");
char convBuffer[8];
message_status = strtol(message.getString(convBuffer),0,16);
Serial.println(message_status);
r=(int)(message_status>>16);
g=(int)(message_status>>8)& 0xFF;
b=(int)(message_status)& 0xFF;
commandLights(r, g, b, true);
}//if
else
//requested rgb values from gateway
gw.send(rgbMsg.set(rgb.c_str()));
}//else if
}//incomingMessage
Comments
Please log in or sign up to comment.