OK, HomeAssistant runs on RaspberryPi, but the RPi only has digital in/out, but what if I want to read analog values from sensors? One solution appears to be to use an Arduino, since this is the sort of thing they do well. However, finding details of how to do this seems a bit sketchy. I could use I2C, but that seems a bit tricky. I did read that I can use USB, which is convenient because that will also give me power for the Arduino. To use an Arduino as an add-on board for the RPi, I had read about something called Firmata, which loads as a sketch running on the Arduino. This is easy at the Arduino end, as it is just one of the examples pre-installed, upload and it’s ready to go.
I set up the configuration in HomeAssistant and immediately got a whole heap of errors, mostly referring to needing PyMata 2.14. Now PyMata is a client library that allows Python to control the Arduino. Obviously not part of the standard RPi/Hassbian image. After a bit of messing around here’s what I managed to do:
Plug the Arduino into your computer, load up the IDE and upload the StandardFirmata sketch (found in the Examples submenu)
Plug the Arduino into a USB port on the RPi. Log into the RPi using SSH
At the command line, run:
sudo pip3 install pymata
If you download the examples from the GitHub repository, you should be able to call the blink sketch to verify that all is working. It should flash the LED 10 times, and you should see the process running in your terminal session counting down. (Note that my UNO clone is connected at ‘/dev/ttyACM0’, so the script works as is.
Add the following entries to your configuration.yaml script and save it:
The LED should show up as another switch in your dashboard, and turning it on should light the pin 13 LED on the Arduino
Note that it appears you can only read analog input pins, and switch digital output pins through this interface. No PWM, and I suppose if you need to read digital inputs then you can do that directly on the RPi.
My son entered Science Talent Search with this Arduino-powered buggy. We used IR with a TV remote to issue codes for motor control and combinations of colours for the RGB LEDs.
Programming was fairly simple, but we found issues with power. It seems that motors are very noisy and when they run it can reset the Arduino. We solved this by running the motor off 4 x AA batteries, whilst the Arduino is powered by a phone battery booster. The Arduino in question is actually a Freetronics Leostick, which is a nice small board, and has a USB plug which we just plugged straight into the phone battery.
So this project had been sitting on my desk for ages now with the sensors and RF module spread across two breadboards with a mess of wire connecting it all up. Today I finally found some time to add the RF module to a prototyping shield. The other sensors are still on a breadboard and that’s the extra wires hanging off it, but it’s one step closer to a finished project. Some of the soldering was a bit fiddly but worked straight off.
After merging the XC0348 code I had which was receiving the data transmitted by the outdoor sensors with the Xively code there was a bit of tweaking to do to get the sketch to play nicely. The last step was to add the code back for the pressure sensor. This was problematic as the sensor uses I2C and soon as I added the Wire library the whole thing stopped running properly. After some reading I wondered if I was just running out of memory so I commented out a whole lot of serial print statements and it this got things working again. Of course, without the print statements there was a whole lot less debugging going on.
A couple of things that still need attention:
the pressure sensor has been timing out often, so I get false values where a negative error code is returned. I’ve increased the timing loop and am seeing if this works better
we had a heap of rain overnight and my rainfall figure suddenly dropped because I was only using the LSB, and the count had overflowed. A bit of trial and error and now it is showing the true total. A problem with rainfall is that the sensor reports total rainfall, so this will just keep going up and up. I need some way to keep daily totals. Perhaps I need to add a real time clock?
my light values are related to the resistance in the photoresistors, so the curves are inverted i.e. when it is light the value is lowest FIXED Apr 10 – I chose an arbitrary dark value of 1000 and am using that as a reference point to subtract from, so now a bigger value does mean more light rather than more dark!
wind direction is returned as an integer between 0 and 31, which seem to correspond to 16 compass points. I think there might be some sort of moving average calculation used by the base station to reduce errors due to rapidly fluctuating wind shifts.
I’m thinking I might have to back this one, which has already reached its target after less than 24 hours. It’s Aussie-designed although being made in the USA. Read more on Kickstarter. Now what could I use it for …
These articles together form the source that I drew inspiration from. I didn’t have to do my own signal timing analysis which sounds fascinating but complicated. The above code examples however are written either for Raspberry Pi, or for Arduino using different models of Fine Offset sensors and transmitters.
The next step was to figure out how to receive the sensor data being transmitted to the display base station. There’s plenty of articles on the web describing parts of the puzzle, but I didn’t find any one article that explained it all. For testing I used a Freetronics LeoStick and a 433MHz RF receiver module set up on a breadboard, so I could leave the original sketch still running on my desktop feeding data to the web. The LeoStick was particularly easy to use as I could just plug it into a USB port and test code from anywhere in the house without being tethered to power.
I ran some testing code on the MPL3115A2 breakout board and that worked fine first time, giving me altitude and temperature readings immediately. I then tried to incorporate that code into my existing sensor reading sketch, using the barometer mode. At this point things suddenly stopped working nicely. The serial monitor debugging showed it just stopped when trying to initialise ethernet. I began cutting out bits of code, so that it wasn’t reading other sensors. It then seemed to start sending data and then restart, but the loop would not run.
Next night I sat down and started over with the existing sketch, but with it only sending the barometer reading, and it worked. I was able to add the other sensors back in, one at a time, and it still worked. I did cut out some unnecessary debug statements here and there to try to cut the code size down. Finally, I have everything working, but can’t explain why it didn’t work before and why it does now. I was thinking that perhaps the EtherTen wasn’t up to the task, and I might need to go up to a Mega board.
Obviously there is a bit of redundant data here, so it is just a useful way of testing the different device interfaces. What is somewhat hard to explain is why I have 3 different temperature readings given these devices are supposed to be calibrated to a high degree of accuracy. For example at the moment readings are 24.37 °C (DS18B20), 23.80 °C (DHT22) and 22.75 °C (MPL3115A2).
I put in an order to Little Bird Electronics at Christmas to take advantage of a 10% discount coupon, so I added a few bits and pieces that might come in handy. First off was a DHT22 temperature and humidity sensor, which is readily available with lots of examples around. First I tested it with some sample code, and then modified my existing ‘weather’ station code. So now I have two different measures of light levels, two temperature readings and humidity. There is a slight difference of about half a degree between the two temperature sensors, so I wonder which one is more accurate? The Xively feed immediately picked up the two new data streams, and as a bonus my iPhone app also recognised them.
I also bought an MPL3115A2 barometer/altitude sensor which looks interesting, but it is my first experience of the I2C bus and it appears that to run long distances to an outside sensor it needs a bus driver of some sort, so this one is going to take more effort. The code looks rather daunting too.