Ikea Dioder LEDs Wifi controlled by FHEM

Motivation

A few years ago – while strolling through IKEA – i bought two sets of IKEA Dioder RGB  LEDs. Then the ESP8266 32Bit Microcontroller became very popular. Now, i am running a FHEM Server for quiet a while. Eventually the idea grew to controlling the LED Strips/Bars via an ESP12-E from FHEM. At the very beginning i figured i would also have to write a perl module for FHEM to integrated with my ESP but it turned out an antsy guy from Hamburg already created one called Wifilight. It works for a dozen devices and so i just had to pick one and interpret what Wifilight is sending. A bit of browsing the code, googling and digging through the FHEM Forum turned out the LW12 LED Controller (german) implementation might be the one to try.

The Finished Project In Motion

smartdioder

Steps

The basic outline of the steps involved is fairly straight forward:

  1. Gathering hardware components
  2. Wiring stuff up on a breadboard
  3. Programming the ESP using the Arduino IDE
  4. Connecting to FHEM

1. Gathering Hardware Components

1 x ESP8266 Type ESP12-E
3 x N-Channel MOSFET with a maximum Gate Threshold Voltage of 3.3V (e.g IRLZ44NPBF)
1 x 12V to 3.3V Step-Down Module (e.g. LD1117V33)

Sidenote: If you do not have IDEA Dioder LEDs and intend to do a project like this…DO NOT BUY THEM! There are cheaper and better LED strips out there. The circuit and the code might have to be different in that case but there is plenty of information on the web on how to control other LED strips.

2. Wiring Stuff Up

I will not explain a lot about wiring the ESP. This can be easily looked up all over the web and most sources will say you need to pull up/down various more pins than i did. But the setup below works very well for me. I consider components like FTDI-Converters, breadboards, resistors, capacitors and all sorts of tools as given.

Upfront Thoughts

ESPs can’t stand input voltages over 3,3v. Also, all output voltages max at 3.3 volts logic level.
Always keep in mind that we are using 2 power rails because the LEDs work with 12 volts.
The layout of the ESP12-e does not fit strip-/breadboards so you could either solder your own IO adapter board or simply buy one.

Breadboard Layout

esp12-ikea-dioder-fhem_breadboard
This layout shows my final setup. The button is used for resetting the ESP (because i had to do that a lot :) ) and the J1 male header pulls GPIO0 to GND which is necessary for programming. The connections for the FTDI module are missing here. MOSFETs Gate shouldn’t be floating so i used 10k resistors to pull them to GND. The voltage regulator (upper right corner in  this picture) mentioned at point one got worrying hot for me so i simply attached a heatsink dismounted of an old mainboard. Please pay attention to GPIO15, it is connected to GND directly on the IO-Adapter of the ESP.

img_20161025_211622
In reality the setup doesn’t look nearly that clean. I used a different step-down module to get 3,3V for the ESP while testing and programming the circuit.

Poor Man’s PCB

esp12-ikea-dioder-fhem_final_breadboard_connections
Placement and wiring of all components for the final drilled board. Yellow wires are all run on top used to bridge unavoidable crossings and blue wires are going on the bottom of the board. The 3 single pin headers in the lower-right corner are used to represent the connection points of the 12V power supply. The 4 wires right above this headers are connected to the LED Stripts in bottom to top order: Red, Green, Blue, +12V

esp12-ikea-dioder-fhem_esp_finesp12-ikea-dioder-fhem_ftdi_fin
In the final layout the ESP was mounted upside down. So the pins align as shown in the left image. The picture on the right shows the FTDI connections of the header.

3. Programming the ESP

I was excited about the fact that the ESP8266 can be programmed using LUA. But there are multiple statements saying LUA renders the microcontroller rather unstable. So, without further ado and no verification whatsoever i gave Arduino’s C/C++ slang a shot and stuck to it.

The Arduino IDE

Setting up the Arduino IDE to work with the ESP and my FTDI module was almost straight forward

  1. Goto File -> Preferences -> Settings Tab
  2. Enter http://arduino.esp8266.com/package_esp8266com_index.json to the field labeled Additional Boards Manager URLs
  3. Goto >Tools -> Board -> Boards Manager…
  4. Filter for esp8266
  5. Select and install the latest version of the entry labeled esp8266 by ESP8266 Community
  6. The board settings working best for me are highlighted in yellow in the image below. Flash Size (marked red) worked in different variants. It became very important at a later stage when i added OTA-Update to the code. The setting shown was the only one that made OTA work reliable for me.

arduino_boardsettings

The Code

#include 
#include 
#include 
#include 

// GPIO definitions for LEDs
#define red 14
#define green 13
#define blue 12

// Max values for PWM
#define colorOnRed 1024
#define colorOnGreen 1024
#define colorOnBlue 1024

// Hardcode WiFi parameters
const char* ssid = ".....";
const char* password = ".....";

// Define TCP Server on port 5577
WiFiServer server(5577);
WiFiClient client = server.available();

// HTTP Push Update
// curl -F "image=@firmware.bin" :/update
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

Line number 7 – 9 defines the GPIO pins to use for the MOSFETs Gate. ESPs have 10Bit PWM hence the maximum value for ~3,3V output is 1024 on lines 12 to 14. Line 17 – 18 takes the Wifi’s SSID and password. 21 to 22 defines a new object for our TCP Server we actually send our desired values to. Line numbers 26 and 27 define an HTTP-Server on port 80 for OTA-Updates.(I figured i’ll easily be annoyed by getting that little thing down the cupboard every time i decide to flash new software. So, being able to program it via HTTP with just a short curl-command is a feature i wouldn’t wanna miss anymore.)

void setup() {
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);
  
  Serial.begin(115200);
  WiFi.begin(ssid,password);
  Serial.println("");
  
  //Wait for connection
  digitalWrite(red, HIGH);
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  httpUpdater.setup(&httpServer);
  httpServer.begin();
  delay(10);

  digitalWrite(red, LOW);
  digitalWrite(green, HIGH);
  delay(3000);

  Serial.print("Connected to "); Serial.println(ssid);
  Serial.print("IP Address: "); Serial.println(WiFi.localIP());
  
  digitalWrite(green, LOW);

  // Start the TCP server
  server.begin();
  Serial.println("Server started");
}

Setting pin ‘red’ to HIGH is used for indication of the connection status. My RGB LEDs will stay red until the ESP got successfully connected to my WLAN (line 37 – 41). Once we got connected we start our HTTP-Update Server (43-44), turn red off (line 47) and green on for 3 seconds (48-49, 54). Last but not least we start the TCP Server (line 57).

void loop() {
  // For push flashing only
  httpServer.handleClient();

  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  // Wait until the client sends some data
  // Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  int buflen = 8;
  byte inputbuf[buflen];
  client.readBytes(inputbuf, buflen);
  client.flush();
  
  /*
  // DEBUG
  Serial.print("Byte 0: "); Serial.println(inputbuf[0]);
  Serial.print("byte array length: "); Serial.println(sizeof(inputbuf));
  Serial.print("last byte: ");  Serial.println(inputbuf[sizeof(inputbuf) - 1]);
  */
  
  // Find startbyte (LW12 connection of FHEM's Wifilight module)  
  int startbyte;
  for (int i = 0; i < buflen; i++) {
    if (inputbuf[i] == 86 and inputbuf[i + 4] == 170) {
      startbyte = i;
    }
    /*
    // DEBUG
    Serial.print(i); Serial.print(": "); Serial.println(inputbuf[i]);
    */
  }

  int redval = map(inputbuf[startbyte + 1], 0, 255, 0, colorOnRed);
  int greenval = map(inputbuf[startbyte + 2], 0, 255, 0, colorOnGreen);
  int blueval = map(inputbuf[startbyte + 3], 0, 255, 0, colorOnBlue);

  /*
  // DEBUG
  Serial.print("redval: ");  Serial.println(redval);
  Serial.print("greenval: ");  Serial.println(greenval);
  Serial.print("blueval: ");  Serial.println(blueval);
  */

  analogWrite(red, redval);
  analogWrite(green, greenval);
  analogWrite(blue, blueval);

  
  client.flush();
  delay(1);
  //Serial.println("Client disonnected");

  // The client will actually be disconnected 
  // when the function returns and 'client' object is detroyed
}

Line 89 - 98: Looking at the LW12 connection of FHEMs Wifilight.pm we can see that it is sending 0x56, 0, 0, 0, 0xAA. The first byte is always 86 then it provides us with 3 bytes of RGB values from 0-255 and ends with 170. But, if the on command is issued by FHEM we get first 0xCC, 0x23, 0x33 followed by the first sequence. So, this iteration is only used to determine where the data resides we are interested in.
Line 100 - 102: As described above, is our PWM 10 bits wide. FHEM sends 8Bit wide values, so map() is used to transform 0-255 to the representative 0-1024 values.
Line 111-114: Well, set our pins. :)

Actual Files on Github

4. Connecting to FHEM

Teaching FHEM about the new "esp-ikea-led" is by far the easiest part.

telnet localhost 7072
define  WifiLight RGB LW12:
set  on
set  HSV 0,100,100   #red
set  HSV 120,100,100 #green
set  HSV 240,100,100 #blue

It might be necessary to play a bit with the attributes set by default:

 
Attributes:
   colorCast  0, -20, -20, -25, 0, -10
   whitePoint 1, 0.75, 0.25

The Result

Bottom View

img_20161106_182424
As you can tell, soldering is not exactly a point to put on my "Strengths List" but it worked straight from try one. I have to admit that i was surprised because i expected at least a few shortenings.

Top View

img_20161106_182405
As mentioned earlier in that post, i used an old heatsink borrowed from a mainboard to cool down the voltage regulator. It is oversized and makes the whole circuit-board chunky.

3 things i immediately regretted on that board
  • The capacitor should move a bit further from the LD33V.
  • The J1 jumper (for programming) should move somewhere else as it is hard to reach when the FTDI converter is attached.
  • I am not sure if it is a good idea to have the MOSFETs packed so close.
Product Picture

img_20161106_182412
Well, i can't say it's ready for production line but i sort of like how it turned out.

Moving In

img_20161107_225149
Moved to it's new home...on top of the cupboard.

img_20161109_215558
In the end...there is light.

Leave a Reply

Your email address will not be published / Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.