MySensor Dioder (Ikea)

MySensor Dioder (Ikea) © CC BY-SA

How to hack an ikea dioder to make it an IoT device. The project uses the mysensors opensource libraries.

  • 2,130 views
  • 0 comments
  • 2 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)

About this project

Some time ago I bought a led strip dioder from Ikea, it was funny and not so expensive for a led bars sold by a big store, in Europe is about 20 euros. Though after a while, when I started to make home automation projects I left it in my canteen replaced by a controllable led strip made by a famous maker.

Today, the way to the domotic world has brought myself to several mysensors projects and when I got the dioder back in my hands, suddenly I thought that I could make it controllable from my home automation system.

How does the dioder work

Thanks to this page I was able to figure out how the dioder is working: basically we have 4 bars each with 8 common anode RGB led. The bars are connected to a connector box where we have also a plug for the power unit (12V) and a plug for the controller unit. This project is focused on the controller unit. This unit has the power button, a wheel to change colors from white (not real white but all RGB on) to red and other two buttons to make colors changing automatically.

This unit is described here but my version is a newer one so I investigated about the new electrical schema: there's a voltage regulator to get 5V but the core is the MC SC91F729BM that get as analog input a level going from 0V (white) to 5V (red) according to the wheel position and 3 digital input coming from the buttons (push button = 0V). The three PWM outputs goes to the 3 MOSFET used to command the led bars, connecting and disconnecting (PWM) the 3 RGB leds cathodes to the ground. Now that we know how the dioder is working we can decide what we want to do. I replaced the SC91F729BM with an Arduino Mysensor node, having also the opportunity to change the first and third button behavior (that I never had used) to make a dimmable LED bar with a UP and DOWN buttons. Since there's already a 5V logic I'm using an Arduino pro mini 5V node sensor, the Radio nRF24LU1+ and than a DC-DC step down voltage regulator to provides 3.3V to the radio module.

The Arduino program is based on dimmer sensor node and this post where Jason Judge explains how to make a RGB colours wheel via Arduino, basically how to convert an analog value to RGB and then to HSV. The standard RGB wheel goes from red to yellow to green to blue to purple and red again, but the IKEA dioder goes from white to yellow to green to blue to purple and to red, so to keep the same behavior I made a change in the algorithm.

My gateway is connected to Openhab, so I'm able to integrate the led strip in my smart system as showed in the video.

By mortommy

© 2016 Sensnology AB. All Rights Reserved.

Code

MySensor DioderC/C++
MySensors libraries v1.5 needed.
/**
 * 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
Github
https://github.com/cdinu/ikea-led-bar-hacking

Schematics

Original controller unit schema
Capacitors and diode are reported as general and the value are not correct.
Dioder 2v controller schem
Mod schema
Capacitors and diode are reported as general and the value are not correct.
Dioder 2v controller custom schem

Comments

Similar projects you might like

Third Eye for The Blind

Project tutorial by Muhammed Azhar

  • 36,670 views
  • 30 comments
  • 87 respects

IoT arduino ESP Garage Door opener (UD)

Project in progress by David Smerkous

  • 10,854 views
  • 6 comments
  • 16 respects

Breville Imperial Tea Maker

Project showcase by Brian Chamberlain

  • 1,458 views
  • 1 comment
  • 6 respects

Weather Station for Drones

Project tutorial by Giuseppe Caccavale

  • 11,512 views
  • 4 comments
  • 35 respects

Button: Arduino Basics

by Alex Glow

  • 10,348 views
  • 0 comments
  • 10 respects

2WD Voice Controlled Robot with Arduino and BitVoicer Server

Project tutorial by Marcio Tamagushi

  • 10,203 views
  • 11 comments
  • 32 respects
Add projectSign up / Login