Previous posts in this project:
- [Christmas Tree] Internet of Holiday Lights - Project Description
- [Christmas Tree] Internet of Holiday Lights - Getting Started
Introduction
After setting everything up in last post, I started working on the actual configuration of openHAB and control of the Arduino Yun via MQTT.
This is the result so far ...
openHAB
To be able to control the colors and animations of my digital Christmas tree, I opted for openHAB. I discovered openHAB during the Forget Me Not Design Challenge and like it very much. I find it easy to work with and very versatile (home automation, pet feeding, controlling Christmas lights).
In my previous post, I covered the installation and basic configuration. Now, i will document how I've created following interface to control my lights:
Items
The openHAB documentation on MQTT was sufficient to get me started. It describes how to define items to subscribe to or publish MQTT messages.
At this stage, I'm using openHAB to publish values selected in the web interface such as color or animation.
Here are some example items (the others are just duplicates of this with other names and topics):
Group All Color TreeLight "Tree Color" (All) String TreeLightColor (All) {mqtt=">[eclipse:/fvanTestOpenHAB/tree/color:command:*:default]"} Number TreeAnimation "Tree Animation" (All) {mqtt=">[eclipse:/fvanTestOpenHAB/tree/animation:command:*:default]"}
You'll notice that I've separated the MQTT binding from the color picker. This is because I want to process the color picker's value before sending it over MQTT.
The processing of the color picker's value is done with a rule and then assigned to another item which then triggers the binding.
Rules
The color picker's default value format was not really usable in my case, so I needed to convert it to something I could use.
Taking the state of the color picker, I extracted the R, G, B and brightness values and put everything in one big string.
import org.openhab.core.library.types.* rule "Set RGB value TreeLight" when Item TreeLight changed then val hsbValue = TreeLight.state as HSBType val brightness = hsbValue.brightness.intValue val redValue = ((((hsbValue.red.intValue * 255) / 100) * brightness) / 100).toString val greenValue = ((((hsbValue.green.intValue * 255) / 100) * brightness) / 100).toString val blueValue = ((((hsbValue.blue.intValue *255) / 100) * brightness) / 100).toString val color = redValue + "," + greenValue + "," + blueValue sendCommand( TreeLightColor, color ) end
The processed data is then sent to the correct variable, triggering the MQTT binding.
Sitemap
Finally, there is the sitemap, in charge of the layout of the web interface. This configuration defines how items are ordered in the GUI.
The configuration is very basic and categorises everything per LED strip. You've seen the result in one of the screenshots above.
sitemap xmas label="Holiday Lights" { Frame label="Topper" { Colorpicker item=TopperLight icon="slider" Colorpicker item=TopperLight2 icon="slider" Selection item=TopperAnimation mappings=[0=OFF, 1=Random_position, 2=Side_fill, 3=Middle_fill, 4=Alternating_colors] } Frame label="Tree" { Colorpicker item=TreeLight icon="slider" Selection item=TreeAnimation mappings=[0=OFF, 1=Pulse_slow, 2=Pulse_fast] } }
Retain
One more thing ... Because some of my functions (animations) take longer to execute, I might miss certain MQTT messages. Also, if power is lost, no state is kept in the Arduino to restore colors and animations.
To remedy this, I enabled the option to "retain" messages. This will ensure the MQTT broker will keep the messages even after being sent, so that new or late subscribers are sent the messages again instead of having to wait for an update.
This is change in the "openhab.cfg" file:
# Optional. True or false. Defines if the broker should retain the messages sent to # it. Defaults to false. mqtt:eclipse.retain=true
Arduino
Benjamin Cabé did a great job to help us forward with his post on MQTT with the Paho client.
Still, I decided to give another library a try, not because I'm stubborn (perhaps a little bit ) but because I believe in multiple solutions to a certain problem.
This is why I used the following library: Arduino Client for MQTT « knolleary
The library is easy to use. The following bit of code reflects the general use:
#include <PubSubClient.h> #include <Bridge.h> #include <YunClient.h> YunClient yunClient; PubSubClient client("iot.eclipse.org", 1883, callback, yunClient); void callback(char* topic, byte* payload, unsigned int length) { // handle message arrived } void setup() { if (client.connect("arduinoClient")) { client.publish("outTopic","hello world"); client.subscribe("inTopic"); } } void loop() { client.loop(); }
The hardest part (for me) was converting the received messages in a format I could use to compare/parse/etc ...
As you can see in the code above, the payload and topic are not strings.
For example, the MQTT messages sent for color codes, are formatted in RGB format with values ranging from 0, 0, 0 to 255, 255, 255.
To parse these, I did the following:
void callback(char* topic, byte* payload, unsigned int length) { // check for messages on subscribed topics Console.print("Topic: "); Console.println(String(topic)); // check topic to identify type of content if(String(topic) == "\/fvanTestOpenHAB\/topper/color") { // convert payload to String String value = String((char*)payload); // split string at every "," and store in proper variable // convert final result to integer TopperR = value.substring(0,value.indexOf(',')).toInt(); TopperG = value.substring(value.indexOf(',')+1,value.lastIndexOf(',')).toInt(); TopperB = value.substring(value.lastIndexOf(',')+1).toInt(); // print obtained values for debugging Console.print("RED: "); Console.println(TopperR); Console.print("GREEN: "); Console.println(TopperG); Console.print("BLUE: "); Console.println(TopperB); } }
I repeated the "if" statement for every topic and am now able to receive all the messages required to apply color and animation of both strips.
Troubleshooting
During testing of this project, there are two "tools" I'm using quite often: MQTT Lens and Arduino Console.
MQTT Lens
MQTT Lens is an MQTT client capable of subscribing to and publishing MQTT messages.
Using this tool, I was able to verify the following:
- MQTT messages are being sent properly
- the content of the messages is correct
- the content is published for the correct topic
Arduino Console
The Arduino Yun makes it possible to upload sketches wirelessly, so it must be able to debug wirelessly as well.
I initially tried to use "Serial.println()" statements for debugging, but that only works when connected to the Yun via USB.
After some digging around, I found the command to be used is very similar: "Console.println()".
In short, you can use the console as follows:
#include <Bridge.h> #include <Console.h> void setup() { Bridge.begin(); Console.begin(); } void loop() { Console.println("Output"); }
When placed at relevant places in your code, the output becomes very useful:
As you can see in the screenshot above, I'm using the console to verify the incoming MQTT messages on both topic and content.
This is very useful to know if the received content is parsed properly before being passed to the next function.
Demo
Finally, here's a short video demonstrating the control of both analog and digital LED strips connected to the Arduino Yun via openHAB and MQTT.
Happy Holidays
If you've come this far reading this blog post (or if you skipped ahead ), I'd like to wish you and your family happy holidays! May they be fun and festive.
I'll be back with more blogs for you to read in 2015! But in the mean time, enjoy this painting my 4yo daughter made: