Previous posts for this project:
- [CaTS] ForgetMeNot - Index
- [CaTS] ForgetMeNot - Week 0: Project Description
- [CaTS] ForgetMeNot - Week 1: EnOceanPi and Sensors
- [CaTS] ForgetMeNot - Week 2: Elro CoCo and Pi Cam with OpenHAB
- [CaTS] ForgetMeNot - Week 3: Data persistence and charts with OpenHAB
- [CaTS] ForgetMeNot - 3D Printing: EnOcean sensor bracket
- [CaTS] ForgetMeNot - 3D Printing: EnOcean rocker switch and magnet holder
- [CaTS] ForgetMeNot - 3D Printing: Food dispenser prototype
Introduction
This week's post is about getting sensor data from an Arduino in OpenHAB and sending commands from OpenHAB to Arduino. The post covers the different iterations my code went through in order to achieve the desired result, giving some insight on how I tackle a specific problem until the goal is reached.
This post is also submitted half a day earlier than usual, so it can still have a shot at winning Dave (Forget Me Not Challenge: Minion of the Week #1), as I won't have time to make elaborate posts in the next to weeks. I'm getting married next week, and let's say my Minion bride would not appreciate it if I dared to take my laptop along on our honeymoon (That's probably the kind of thing one could pull off after ten years of marriage, but perhaps not after one day ... Let's not try to find out.)
As doctorcdf pointed out, competition was indeed fierce this week, and this Minion is going all out one last time with this post
Let's go!
Arduino to OpenHAB
Static values
In this first step, I'm trying to have string of data passed from the Arduino to OpenHAB. Once received in OpenHAB, it can be parsed and the values assigned to the corresponding items.
For this test, having the Arduino send a static string to OpenHAB is sufficient, as the focus is more on the reception and the parsing. In a second step, I'll be sending dynamic values, based on sensor data.
Serial data from Arduino to Raspberry Pi
First, the data from the Arduino needs to be sent to the Raspberry Pi. To do this, I plugged the Arduino in one of the USB ports of the Pi, after having configured it with the sketch below:
int weight = 125; int temperature = 39; void setup() { Serial.begin(9600); } void loop() { Serial.print("weight:"); Serial.print(weight); Serial.print("g_temperature:"); Serial.print(temperature); Serial.println("C;"); delay(10000); }
On the Pi, it is possible to verify the serial data is properly received, by listening with minicom:
pi@webserver ~ $ sudo minicom -b 9600 -o -D /dev/ttyACM0
The screenshot shows the data from the Arduino is being received.
Serial data in OpenHAB
Just like with the EnOcean Pi, the OpenHAB "start.sh" script needs to be modified to be able to use this new serial interface.
pi@webserver ~ $ sudo nano /opt/openhab/start.sh
... -Dgnu.io.rxtx.SerialPorts=/dev/ttyAMA0:/dev/ttyACM0 ...
It is possible to define multiple serial ports, as long as they are delimited by ":".
The next step is to enable the serial binding by ensuring it is present in the addons folder:
pi@webserver ~ $ ls -l /opt/openhab/addons/*serial* -rw-r--r-- 1 root root 10748 Jun 16 02:26 /opt/openhab/addons/org.openhab.binding.serial-1.5.0.jar
Finally, we need an item to bind the data to:
String Arduino "Arduino [%s]" (arduino) {serial="/dev/ttyACM0"}
To visualise the data, the item can also be added to the sitemap.
With all the necessary modifications done, I restarted OpenHAB and verified the events log:
pi@webserver ~ $ less /opt/openhab/logs/events.log
2014-08-17 17:34:17 - Arduino state updated to weight:125g_temperature:39C; 2014-08-17 17:34:27 - Arduino state updated to weight:125g_temperature:39C; 2014-08-17 17:34:37 - Arduino state updated to weight:125g_temperature:39C; 2014-08-17 17:34:47 - Arduino state updated to weight:125g_temperature:39C; 2014-08-17 17:34:57 - Arduino state updated to weight:125g_temperature:39C;
Data is coming in! Great!
Parsing serial data
Two additional items were created to assign the parsed data to:
String Arduino_weight "Weight [%s]" String Arduino_temperature "Temperature [%s]"
The Arduino string is parsed with a rule which then updates the weight and temperature items:
rule "Arduino" when Item Arduino received update then var String ArduinoUpdate = Arduino.state.toString.trim var int weightStartsOn = ArduinoUpdate.indexOf("weight:") + "weight:".length var String weight = ArduinoUpdate.mid(weightStartsOn, ArduinoUpdate.indexOf('_')-weightStartsOn) Arduino_weight.postUpdate(weight) var int temperatureStartsOn = ArduinoUpdate.indexOf("temperature:") + "temperature:".length var String temperature = ArduinoUpdate.mid(temperatureStartsOn, ArduinoUpdate.indexOf(';')-temperatureStartsOn) Arduino_temperature.postUpdate(temperature) end
Checking the events log again, we can now see the weight and temperature being updated as well:
2014-08-17 18:47:58 - Arduino state updated to weight:125g_temperature:39C; 2014-08-17 18:47:58 - Arduino_weight state updated to 125g 2014-08-17 18:47:59 - Arduino_temperature state updated to 39C
A quick look in OpenHAB shows the full string and the parsed items:
Dynamic values
With the parsing of static data working, it was time to move to dynamic data.
For this test, I connected potentiometers to two different analog inputs of the Arduino, in order to simulate sensor data.
To make it more visual, I also connected two LEDs.
The setup used is as follows:
In the Arduino sketch, two sensors are simulated:
- a weight sensor ranging from 0-250gr
- a temperature sensor ranging from 0-50°C
These are just test values to demonstrate the functionality until the real sensors arrive and are hooked up.
The sensor data will only be transmitted if one of the two values changes. Later on, this could be fine tuned even more by only sending the changed data.
const int weightSensorPin = A0; const int temperatureSensorPin = A1; int previousWeightSensorValue = 0; int previousTemperatureSensorValue = 0; int currentWeightSensorValue = 0; int currentTemperatureSensorValue = 0; void setup() { Serial.begin(9600); } void loop() { currentWeightSensorValue = analogRead(weightSensorPin); currentTemperatureSensorValue = analogRead(temperatureSensorPin); currentWeightSensorValue = map(currentWeightSensorValue, 0, 1023, 0, 250); // simulate 0-250g currentTemperatureSensorValue = map(currentTemperatureSensorValue, 0, 1023, 0, 50); // simulate 0-50°C if(currentWeightSensorValue != previousWeightSensorValue || currentTemperatureSensorValue != previousTemperatureSensorValue) { Serial.print("weight:"); Serial.print(currentWeightSensorValue); Serial.print("g_temperature:"); Serial.print(currentTemperatureSensorValue); Serial.println("C;"); previousWeightSensorValue = currentWeightSensorValue; previousTemperatureSensorValue = currentTemperatureSensorValue; } delay(1000); }
I've made my very first video montage, specially for this blog post! I learned how to record my screen, create a picture-in-picture and how to add a title!
I manually tried to sync the two videos, and managed to get very close. Perhaps someone has additional tips on how to do this more accurately? (I'm using iMovie on Mac)
Anyway, here's the fancy demonstration:
Converting
In the above steps, the data was parsed as a string of text. In order to be able to do calculations, these need to be converted to numbers. To do this, I slightly modified the rule and the items.
The rule has been updated to:
- drop the unit which was passed in the string, to only keep the numeric data
- create a new variable which converts the String data to Double
rule "Arduino" when Item Arduino received update then var String ArduinoUpdate = Arduino.state.toString.trim var int weightStartsOn = ArduinoUpdate.indexOf("weight:") + "weight:".length var String weight = ArduinoUpdate.mid(weightStartsOn, ArduinoUpdate.indexOf('g_')-weightStartsOn) var Double weightDouble = new Double(weight) Arduino_weight.postUpdate(weightDouble) var int temperatureStartsOn = ArduinoUpdate.indexOf("temperature:") + "temperature:".length var String temperature = ArduinoUpdate.mid(temperatureStartsOn, ArduinoUpdate.indexOf('C;')-temperatureStartsOn) var Double temperatureDouble = new Double(temperature) Arduino_temperature.postUpdate(temperatureDouble) end
Then, I updated the items to have numeric data instead of a string, like so:
Number Arduino_weight "Food quantity [%.1f gr]" <bowl> (Dispenser_Chart) NumberArduino_temperature"Water temperature [%.1f °C]" <temperature> (Dispenser_Chart)
Et voila. The data can now be used for calculations, charts, etc ...
2014-08-24 09:00:42 - Arduino_weight state updated to 57.0 2014-08-24 09:00:43 - Arduino_weight state updated to 180.0 2014-08-24 09:00:50 - Arduino_weight state updated to 73.0 2014-08-24 09:01:02 - Arduino_temperature state updated to 49.0 2014-08-24 09:01:02 - Arduino_temperature state updated to 8.0 2014-08-24 09:01:03 - Arduino_temperature state updated to 22.0
OpenHAB to Arduino
Time to do it the other way around.
In the first part of this blog post, the Arduino was sending data to OpenHAB, now OpenHAB will send data to the Arduino!
Arduino sketch
First, I modified my previous Arduino sketch to listen for incoming serial messages, in addition to what it was already doing.
I discovered function called "SerialEvent" which is automatically executed at the end of every loop. Because of that, it is important to reduce the delays in the loop to a minimum, as this will delay the processing of the incoming serial messages. You can find more on SerialEvent here: Arduino - SerialEvent
My SerialEvent call looks like this:
String inputString = ""; boolean stringComplete = false; void serialEvent() { while (Serial.available()) { char inChar = (char)Serial.read(); inputString += inChar; if (inChar == '\n') { stringComplete = true; } } if(inputString == "light=OFF"){ digitalWrite(13, LOW); } else if (inputString == "light=ON"){ digitalWrite(13, HIGH); } inputString = ""; stringComplete = false; }
In short, it will expect incoming messages equal to "light=ON" or "light=OFF" and update the status of the onboard LED accordingly.
OpenHAB rule
In OpenHAB, I defined an item called "Arduino" earlier, making use of the serial binding. This same item can be used to send data back to the Arduino, via the same serial binding.
I added an additional switch, which is meant to turn a light on or off in order to increase visibility in the Pi camera.
All that is needed after that is a rule that will send the expected command to the Arduino, based on the switch's state.
rule "Video Light" when Item camera_light changed then var state = camera_light.state as OnOffType sendCommand (Arduino , "light=" + state) end
With Arduino and camera_light defined as follows in the items:
String Arduino "Arduino [%s]" (arduino) {serial="/dev/ttyACM0"} Switch camera_light "Video lighting" <video>
Test
With everything set up, it's time for testing!
Reorganising the sitemap, this is the current structure I came up with for the food/water dispenser:
It's populated with dummy data generated by the Arduino, until the real sensors are hooked up. The button for the light has been put just above the video, as this seemed most practical.
In the video below, I demonstrate the action of turning the light on and off while the camera is filming the onboard LED of the Arduino. Later on, this can trigger an LED strip, white LEDs or even IR LEDs (in combination with Pi NoIR).
Conclusion
In the past weeks, I spent a lot of time exploring OpenHAB. I've played with domains such as data collection, persistence, video, etc ...
I can now start the actual build of the project, as the software side mechanisms have been figured out and found to be working!
Some blog posts have been prepared to be published during my absence in the coming two weeks. The focus will gradually be shifting to the hardware side of the project.
Until next time!
Top Comments