Steering LED RGBW light bulb in .NET

Marcin Kawalerowicz / Wednesday, January 27, 2016

Introduction

Milight LED RGBW light bulbs are a lighting system similar to the Phillips Hue light bulbs. Both work using the same pattern: they can be controlled via wireless network via software you can write. But Milight are a lot cheaper than Hue. Milight light bulbs come in two types: white and RGBW (red-Green-Blue-White). We decided to work with the RGBW version, because it has much more potential than the white-only version and allow us to build more advanced and “case-sensitive” programs like continuous integration signaling tools (more on this later). All of that will be based on this simple steering application that we will create. Our goal in this project was to create a .NET application that can control this lighting system via Wi-Fi bridge (Wi-Fi controller) and ultimately the Continuous Integration (CI) signaling tool.

How it works?

MiLight LED RGBW are radio controlled light bulbs that use a Wi-Fi bridge as a “medium” that converts UDP packets sent via Wi-Fi network into radio signal that is readable for the light bulb itself.

Figure 1. RGBW LED light bulb architecture.

 

To execute commands on the lighting system, we need to use UDP and send a packet containing 2 byte information to the Wi-Fi controller. Wi-Fi controller will translate it into radio signal and send directly to light bulb. Every byte is represented by value in 8-bit hexadecimal code (for example 0x00). The light bulb can communicate only in one direction, so it can only react to command but it is not possible to query its actual state.

We can:

- pair our application with a light bulb,

- change the value of the color or brightness,

- turn it on and off.

Setup

Figure 1 shows our gear. One Miligth RGBW light bulb, one Milight WiFi bridge and a power cord for the bridge.

Figure 2. Complete Milight wireless light bulb set with Wi-Fi controller.

You can connect the setup and use one of the mobile device applications (available on the Google Play Store and the Apple Store) to steer the light bulb. But if you want to steer the light using your own software (like we do!), you will need to set the static IP to it. A great article on how to do this can be found here.

In this setup, the bridge provides its own WiFi network called milight or milight_”something”. You can connect to this network and you can send the commands to the default gateway.

You can also connect the bridge to your existing WiFi network (STA mode). In order to do this, open the browser, go to the default gateway IP, and log on using “admin” as the user name and password. Set up your STA mode. In that case you should know what the command’s IP is.

Implementation

To create our application, we used Microsoft Windows Presentation Foundation (WPF), and for the color picker we used Infragistics Color Picker[1].

1) Sending packets via UDP

To transmit UDP packets to the Wi-Fi controller, we created UDPTransmission class:

    class UDPTransmission
    {
        private const int port = 8899; 
 
        public static void Transmission(byte[] data, string ip)
        {
            var serverAdd = IPAddress.Parse(ip);
            UdpClient udpClient = new UdpClient(port);
            udpClient.Connect(serverAdd, port);
            udpClient.Send(data, data.Length);
            System.Threading.Thread.Sleep(100);
            udpClient.Close();
 
        }
    }

The UDPTransmission class contains Transmission method with two parameters that accepts only an array of bytes and an IP string. According to the documentation, UDP packets need to be sent on port 8899 so it is set as constant. What’s more, every command needs to be send with a 100 ms delay, so that’s why the Thread is put to sleep for a duration of 100 ms. Please note that error handling is not provided in order to keep the code examples short.

2) Commands, code flex and readability

For the sake of code readability, every action the light bulb can perform is represented with Enum. There are 3 types of Enums in this project:

·        Activities (Connect)

·        States (On, Off)

·        DiscoMode (advanced multicolor illumination)

In every command (which contain 2 bytes) one byte is always constant, so in this scenario we can easily attach command byte to the Enum that represents the equivalent of the proper action. For example:

        public static byte[] States(State state)
        {
            byte stateByte;
 
            switch (state)
            {
                case State.On:
                    stateByte = 0x42;
                    break;
                case State.Off:
                    stateByte = 0x41;
                    break;
                default:
                    throw new IndexOutOfRangeException();
 
            }
            return new byte[] { stateByte, 0x1B };
        }
 
 

This structure adds to the code flexibility and makes it more readable for the programmer.

3) Pairing application with light bulb

Note: Our application must be connected to a wireless network created by the Milight Wi-Fi controller to perform pairing and other commands.

Before sending any command, our application needs to be paired with the light bulb. We can achieve this by sending an array of 2 bytes, where the first byte is represented by code 0x45 followed by the second byte which is the constant 0x00. A code snippet is showed below. From now on, the light bulb will react to every command.

 
        public static byte[] Activities(Activity activity)
        {
            byte activityByte;
 
            switch (activity)
            {
                case Activity.Connect:
                    activityByte = 0x45;
                    break;
                default:
                    throw new IndexOutOfRangeException();
            }
 
            return new byte[] { activityByte, 0x00 };
        }

Keep in mind that the initial pairing must be done within two seconds from the time the light bulb gets the current. See the Limitless LED dev documentation at the end of the article for details.

4) Most useful command codes sorted by action

States:
Implementation:               byte[] { stateByte, 0x00 };

-        On - > stateByte  = 0x42

-        Off ->  stateByte = 0x41

Disco mode control:
Implementation:               byte[] { discoByte, 0x00 };

-        On/Switch to next mode - > discoByte  = 0x4D

-        Increase speed ->  discoByte = 0x44

-        Decrease speed -> discoByte = 0x43

To switch off the disco mode, simply just change the color manually.
Change color:
Implementation:               byte[] { 0x40, colorByte };
Milight light bulbs operate with 8-bit color palette so color range starts form 0 and ends at FF.
White light:
Implementation:               byte[] { 0xC7, 0x00 };
 

5) Brightness

Changing the brightness value is followed by changing the slider that is attached to the layout of the application. The brightness value oscillates between decimal 2 and 27, where 2 is the minimum and 27 is the maximum. To form a command, it’s necessary to convert the value of the slider to byte and pass it as described below.

new byte[] { 0x4E, convertedBrightnessByte }

Interface

 

Figure 3. Administration panel sample application.

1. Control panel with On/Off switches.

2. IP address Textbox.

3. Connect button -> after click, application checks if IP address is typed correctly. If is it correct then rest of the buttons will be enabled, if not, “Incorrect IP number!” message will be displayed.

4. Color Picker -> Infragistics Color Picker allows the user to pick one of the color from the available palette.

5. Switch mode button -> on first click, the application will turn on disco mode; every next click will switch to the next programmed illumination.

6. Change color to white light.

7. Speed up or speed down actual disco mode program.

8. Brightness slider.

Continuous integration (CI) signaling tool

With all that knowledge about the inner workings of this kind of lighting system, it is possible to create a Continuous Integration (CI)[2] physical tool that will use RGBW Wi-Fi light bulb as an indicator of status of the build. It should simply:

-        Turn the light bulb green if all the builds are passing and everything is all right,

-        Turn the light bulb yellow/orange if one or more builds are on the way,

-        Turn the light bulb red if one or more of the build failed.

This application could work as seen on the simple schema in Figure 4.

Figure 4. Sample application flow.

There are several ways to implement this kind of application. Because it is an application that only shows the state of the CI server, it can be developed as a system tray application with a changing icon color. It could be easier to use than a normal Windows Forms/WPF style application as a Windows service that queries the state of the build server. But it seems the best way to implement it would be to write a plugin of an existing CI server that will turn the light bulb on and off and with the correct color.

To not interrupt the workflow of the users, the controller needs to be connected directly to the existing network. Nonstop network switching could be very annoying, so here are a few simple steps to connect the Wi-Fi controller to the existing network and assign a fixed IP address to it:

1) Connect to Milight Wi-Fi network.

2) Go to the administration panel via a web browser.

3) In Work Mode change the Work Type to STA.

4) In STA Setting change SSID to the name of your existing Wi-Fi network.

5) Select the encryption type that your network is using right now.

6) Enter your Wi-Fi password in password box.

7) Set “Obtain an IP address automatically” to disable.

8) Type the fixed IP address, subnet mask, gateway address and DNS server address (it may vary on your network configuration) to the proper boxes.

9) Click “Save” and restart the controller using the restart button located in the left menu bar

Wait a while for the controller to join your existing Wi-Fi network and check it by typing the assigned IP address into your browser. If something went wrong and the controller is unable to connect your existing network, please reset the controller manually by sticking the end of a paperclip or needle into the reset hole located on the left of the micro USB port.

Implementation of the code that queries the server can be different for every Continuous Integration (CI) solution.

 

 

Figure 5. CI build successful.

Figure 6. CI build failed.

Figure 7. CI build in progress.

Conclusion

The main goal of this article was to show you how to steer the Milight RGBW light bulb using .NET. It’s a simple application that can be a foundation of the bigger system using RGBW light like continuous integration server state signalization and more. We showed the most useful command patterns and how this kind of lighting system works, and we hope you enjoyed. Happy hacking!

Documentation:

http://www.limitlessled.com/dev/

Technical information:

http://www.philippinestuffs.com/milight-wifi-controlled-light-bulbs/

 

[1] https://www.infragistics.com/products/wpf/data-entry-and-display/color-picker

 

[2] https://en.wikipedia.org/wiki/Continuous_integration

 

 Bring high volumes of complex information to life with Infragistics WPF powerful data visualization capabilities! Download free trial now!