Location Display – Arduino Based Clock

Once I finally got everything working with the weather station clock, predictably, it started to lose its appeal. So I’ve taken the bones of it and refactored to display my current location. The source of the location data is another little iOS app, this time using background fetch.

I may split the various moving parts of this into a couple of posts. There are 6 in all, most of which I’ve cannibalised from the weather app. I’ll only talk about the new [or what I think are more interesting pieces]. And as I’ve mentioned before, messing with this kind of data has personal privacy implications. While people may not be interested, it’s best to make it difficult. The components are:

  • The iOS app generating the data.
  • This posts to my hosting service via a rest interface called Arrest-MySQL.
  • There is a database behind the REST interface, which is on my hosting service.
  • In order to limit the number of annotations / pins on the iOS app, I trim them with a SQL script embedded in PHP [the latter is a restriction imposed by my hosting service]. I call this as a nightly cron job from the Pi.
  • I then display this via pretty much the same Arduino sketch that for the clock for the weather data.
  • This receives data via Serial USB from the Pi based on a ‘nohup’ Perl script. I start and check this is running every 10 minutes using cron.

There is a 7th: we are going to South East Asia in a while, so I’ve written another little iPad app which my mother in law can use to track us with. My idea; I thought she’d be interested :).

I’ll start with the iOS app. One of the most immediate points to note about the iOS 7 background fetch capability is that, in comparison to using the Significant Change mechanism I’ve implemented before, it’s a lot gentler on the battery. While we are comparing the two, the fetch has two frequency settings: ‘none’ and ‘a lot’. I guess this might be something that Apple might increase the granularity on at some point in the future.

I guess there is a shopping list of features that I’ve picked up along the line which raise this above ‘bare bones’. The first is that if there is no network, I allow a manual ‘pin drop’ which writes the current coordinates to Core Data. Each time the background fetch fires [only when the network is available], I try to post these via the REST interface.

I also attempt to use Google’s GeoCoding API, which converts the latitude and longitude into a string for the given address, which then subsequently appears on the map annotation, or on the clock’s LCD display. I have to admit that in both instances, this is a bit of a dog, due to character limits, and custom annotations with mapping – well, while I’ve done it before, it’s substantially more effort than what this app warrants . I’m also not too sure what Google is going to return if we happen to be dropping location data in a jungle location with fantastic WiFi [!].

One more confession on the Core Data approach: originally I thought I would store failed writers to the database based on Reachability telling me I was offline when the background event fired. Actually, iOS does this for you: no network, no attempt to do a background fetch. While this is obvious, it never occurred to me based on prior experience with the Significant Change functionality which percolates away based on cell tower activity.

One or two more points of interest for the mobile app. There are limits on what you can do with the network in terms of libraries used / delegates available, so no AFNetworking. Actually for what I want to do in the foreground, AFNetworking is much too rich: for instance, I had to Google to find a workaround to its rather sticky caching. Also, something that really stumped me until I thought about it: if you are dynamically returning results [such as from the REST interface] don’t bother trying to plumb in a network progress indicator, unless your server is also setting a Content Length header. That’s a couple of hours of my life I’m not getting back :).

Shed Weather: a Journey Into Questionable Purpose

I’ve been continuing to fiddle around with my Arduino over the last few weeks, trying out various sensors and screens. One breakout board on the online store I’ve been using caught my eye, the delightfully named BMP180 Barometric Pressure / Temperature / Altitude sensor. I’d very nearly taken the plunge a few months ago with one of these, so I thought it would be an interesting project to try and build something along the same lines: install an Arduino in the shed [which has a power supply] and somehow or other get the temperature back to the Raspberry Pi. Some quick googling led me to here. The author of that Instructable article has done a very nice job, which I’ve borrowed the principle of: using two Arduinos, and a 433MHz RF link between them to transmit the data. What I wanted to add into the mix was an iPhone app, which necessitates a server component. That factor is why I’m not going to list all the code here: having a hosting service comes with a monthly bill [and a lot of other capability], which I think will very much limit the broader applicability. But there are a few points that I encountered, which I think are worth going into some detail.

First, the shopping list:

  • 2 x Arduino Uno boards. [£22 each].
  • As well as the barometric pressure board [£8], also using an HTU21D humidity sensor.
  • Aforementioned RF Link kit: [£2].
  • 2 x wire coat hangers, more of which later. Not sure how much these cost, but they tend to come with free clothes.
  • 1 plastic takeaway food container for the shed based components to sit in.

There were some other incidentals in the mix such as breadboards and jumper wires; I also repurposed an old iPhone charger for the outdoor sensor.

The pattern I decided to take was pretty simple: I’d connect the sensors to the first Arduino which is outside [well, inside the shed] and send the results in a continuous loop [every second] over the RF link, to be picked up by the receiver. I’d then run some code on the Pi, picking the data off the serial port, which I’d then send to a database server.

Getting the RF Link to work, using the VirtualWire library, was pretty straightforward. The hard bit is getting it to work if the transmitters were more than a few centimetres apart – note the picture in the Instructables article’s final page, and how far apart the two components are [i.e., not very!].

I spent a lot of time on this. I really didn’t want to have to run a second power adaptor to crank up the DC input to 12V, which is the maximum that the RF transmitter can handle [obviously this would be a direct connection, not the toast-making approach of trying to run 12V through the Arduino]. I ended up making a Yagi antenna, which I have to admit was a term I’d never come across before yesterday. If you google for some combination of terms for home made antennas for 433Mhz transmitters, you will invariably come across the same image, which is half way down this bulletin board. I followed the instructions, using the wire coat hangers, and it works. I have one end of the ‘live’ parts of the antenna connecting to the transmitter, and the other connecting to ground. I also used a dirty little hack which I saw somewhere else: I connect both the 3.3V and the 5V outputs of the Arduino to the input of the transmitter – note that this on its own wasn’t enough to cover the distance I need with the V1 antenna [17cm of wire], something like around 25 feet.

Yagi Antenna [post feline damage]So I was chuffed with the result, as without it, the project would have been a right off. One unintended consequence: within an hour of putting the thing in the garden, the cat promptly sat on it and broke off one of the elements. It still works. I have the cable running under the door of the shed, and used a glue gun to try to make sure that all of the connections were waterproof.

One slight problem I encountered was that the signal wouldn’t penetrate through to the place I originally intended having the receiver and Raspberry Pi: the corner of the house is in the way, so I had to relocate the Pi to a spare bedroom. This meant that my lovely little TFT screen is now redundant.

I messed around with the code quite a bit, and it wasn’t without its complexity. I’ve written before about coding in Perl to read off the serial port, and the approach that I had been taking was to embed a call to the serialPy Python library. I’ve discarded this and now use the Device::SerialPort library which is actually pretty elegant. My original approach to this was to run the Perl as a process, and then check that the process was still running with a cron job. This was based on some prototyping when I was taking readings from the sensors on a directly connected Arduino. This is much more reliable, so I was just sending the data from the sensor at the intervals that I wanted – hourly. As I mentioned earlier, I am now sending from the external board every second. I’ve refactored the code to be called from cron, which runs once and then fires the data up to the database. Note that I currently assume that the script will complete within the hourly cycle. I might as well include the Perl actually, as it introduces the database component:

#!/usr/bin/perl

# post to Arrest-MySQL via curl looks something like:
# curl --data "tempC=77.4&time=2014-01-22 19:02:01" http://yoursite.com/Arrest-MySQL_installdir/tablename

use Device::SerialPort;
use DateTime;

my $port = Device::SerialPort->new("/dev/ttyACM0");
$port->databits(8);
$port->baudrate(9600);
$port->parity("none");
$port->stopbits(1);

$gotAllThree = 0;

$gotTemp = 0;
$gotHumidity = 0;
$gotPress = 0;

while($gotAllThree == 0) 
{
   $lastEpoch = time();
   my $char = $port -> lookfor();
   $char =~ s/[^!-~\s]//g;
   # print $char;
   if ($char =~ /T:/)
   {
      $dt2 = DateTime->now(time_zone=>'local');
      $ymd = $dt2->ymd;
      $timeString = $dt2->hms(':');
      $timestamp = $ymd . " " . $timeString ;
      $char =~ s/Received: T: //;
      print "In temp:\n";
      if ($gotTemp == 0)
      {
         print "T: curling\n";
         my $server_endpoint = "http://yoursite.com/Arrest-MySQL_installdir/tablename";
         system("curl --data \"tempC=$char&time=$timestamp\" $server_endpoint");
         $gotTemp  = 1;
      }
   }
   if ($char =~ /H:/)
   {
      # print "got humidity: $char\n";
      $dt2 = DateTime->now(time_zone=>'local');
      $ymd = $dt2->ymd;
      $timeString = $dt2->hms(':');
      $timestamp = $ymd . " " . $timeString ;
      $char =~ s/Received: H: //;
      print "In Humidity\n";  
      if ($gotHumidity == 0)
      {
         print "H: curling\n";
         my $server_endpoint = "http://yoursite.com/Arrest-MySQL_installdir/tablename";
         system("curl --data \"humidity=$char&time=$timestamp\" $server_endpoint");
         $gotHumidity = 1;
      }
   }
   if ($char =~ /P:/)
   {
      # print "got pressure: $char\n";
      $dt2 = DateTime->now(time_zone=>'local');
      $ymd = $dt2->ymd;
      $timeString = $dt2->hms(':');
      $timestamp = $ymd . " " . $timeString ;
      # print "pressure time stamp is $timestamp\n";
      $char =~ s/Received: P: //;
      # last char is a dot?
      $char =~ s/\..*//;
      # print "pressure is now $char\n";
      print "In Pressure\n";  
      if ($gotPress == 0)
      {
         print "P: curling\n";
         my $server_endpoint = "http://yoursite.com/Arrest-MySQL_installdir/tablename";
         system("curl --data \"millBars=$char&time=$timestamp\" $server_endpoint"); 
         $gotPress = 1;
      }
   }
   if (($gotPress == 1) && ($gotHumidity == 1) && ($gotTemp == 1))
   {
      print "we got at least one hit\n";
      $gotAllThree = 1;
   }

My original intention was to use an Amazon RDS instance, as this is free for a year which, if I’m honest, will be long after I’ll probably be bored with this set up and have pulled it apart. Using the whole AWS interface is kind of what I imagine having a quick go at piloting an aircraft carrier would be like: you tend to wonder what all of the buttons do. To put it another way, it’s very much geared up for an enterprise approach. All that said, I got it working [once I’d figured out how to disable the default and admirably paranoid firewall settings that prevent any external connections whatsoever]. Three days later I got my first bill, which was for a couple of bucks, for storage usage I think. From what I can see, the first year is free provided that you don’t actually use it.

I had a fallback option, which was the hosting service I use for this blog, and which allows me up to 3 mySQL installs, including the one that is used for WordPress. The only downside, and the reason it was second choice, is that there is no shell access: all of the database setup is via a web interface [phpMyAdmin].

I’d already realised from some early research that I needed to transform the data into JSON somehow or other. Googling ‘iOS SQL client’ quickly pointed me away from a native interface. What I finally settled on was a thing called Arrest MySQL. Note to self: the link I use for this is buried, but I need to add a .htaccess file to at least have a fig leaf of security. By default, simply posting to the interface will insert data into the table, if you know where to look.

So it’s working, and I am reliably informed that the outside [well, ‘shed’] temperature was 7.43 degrees Celcius, pressure was 988 Mb and humidity 68% the last time the cron job fired off. The iOS client is well under way too. It’s back to the coalface that is Core Plot for the primary functionality.

I’ve learned a lot from this, but end to end it’s something of a plate spinning exercise, however. The RF link obviously isn’t that reliable. I’ve also not really used a database before, and am having to figure out how to trim the data as I go, using events. It also makes sense to do other transformations [say turning the 24 hourly values into a daily average] server side as well.

But I think the reliability issue is what may make me strip it down and move onto the next Arduino-driven bauble that catches my interest :).

New Versions of Pin Your Pics and WeighMe

I’ve just submitted new versions of both of my apps on the App Store. Pin Your Pics had a bug in the ‘group by 50’ table, which meant that the cells comprising the sets of images was empty. I actually need to do a pretty major overhaul of the code base, as I learned a lot about threading in the process of updating WeighMe with the motion activity functionality. I finally got the async functionality [which I posted an update on a few weeks ago] working. I didn’t change the algorithm that I discussed in the post that substantially, however testing indicated that putting counters in the KVO wasn’t reliable. The KVO still checks to see if the queue is at zero. What I simply did was to shift the ‘gatekeeper’ functionality into the method call which executes the plot.

The queue might be empty at the point in time the KVO executes, but that doesn’t mean that there isn’t more activity is in the pipe for the operation queue. As a consequence, in earlier versions of this code I was seeing my plotting method getting called repeatedly. On entry to the plotting method – which is going to be called every time the queue hits zero – I check for two values: the length of an array, which gets appended to by assignment to the operation queue, and also a boolean, which effectively ensures that the method is only ever executed once, when the array has the right number of values.