Arriving visitors alerted to your phone (or watch)

We have a bush track that arrives on the bottom of our property, on the public land. When people suddenly appear there it makes our dogs very excited, and my partner would prefer we had notice that they are arriving ahead of time, so we can control the dogs.

This same solution could also be used for a gateway / driveway to tell you people are arriving on your farm, or in fact any other Dakota Alert monitoring solution.

The aim is to connect our Dakota Alert monitor to a raspberry pi, and then in turn connect that to a push alerting application that puts alerts onto your mobile phone when someone is coming. From there, if you have a smart watch your phone will alert on your smart watch.

The Dakota Alert equipment can be found here: https://dakotaalert.com/. You need a module that has the relay outputs – in our case the 4000 plus kit. This kit can trigger a relay when someone arrives, as well as playing a tone. That trigger is then read by the raspberry pi. This unit has a 1.6km range between the beams and the receiver unit (1 mile I guess), which is plenty for what we needed.

Start off by configuring the Dakota Alert system, and set the dip switches so that relay 1 will trigger. Get someone to walk through the beam and check that you’re getting a signal on the relay output (you can do this with a continuity tester, or using your multimeter to check the resistance – it should go to zero on the normally open connections when someone goes through the beam).

Next, you need a Raspberry Pi. Install it with Raspberry Pi OS (raspbian), and get it connected to your network and operating. There are plenty of guides on the internet to do that. We’re going to connect the Dakota Alert system to the GPIO pins on the Raspberry Pi. You need to know which Pi you have – I have an old Raspberry Pi model A, but you may have a newer one, and the pins can be slightly different. Refer to the pinout here.

What we’ll do is to take a line from the 3V3 (3.3V) power output on the pi, through the switch on the Dakota Alert, and back to the GPIO pin you’ve chosen on the pi (in my case, I’m going to GPIO11, or pin 23). That looks something like this:

Pi connected to Dakota Alert receiver

What you can see here is the red wire coming from pin 1 on the Raspberry Pi (marked as 3V3 in the pinout). It then goes to the NO (normally open) connection for relay 1 on the Dakota Alert Receiver (you press the orange tab in with a screwdriver to put the wire in). Then we come back out of the common on the NO relay 1 switch, and back to pin 23 on the Pi (GPIO pin 11).

The effect of this is that we’re taking 3.3V from the Pi, running it through the relay switch on the Dakota Alert receiver, and back to Pin 11. When the Dakota Alert relay switch is open (remembering it’s “normally open”) then we have no voltage. When the Dakota Alert relay switch closes (when someone comes) then it will put 3.3V on GPIO pin 11.

You can test this directly on the Pi with the following commands:

pi@raspberrypi4:~ $ cd /sys/class/gpio
pi@raspberrypi4:/sys/class/gpio $ ls
export gpiochip0  unexport
pi@raspberrypi4:/sys/class/gpio $ echo 11 > export
pi@raspberrypi4:/sys/class/gpio $ ls
export  gpio11  gpiochip0  unexport

This makes the pin gpio11 available for direct manipulation.

pi@raspberrypi4:/sys/class/gpio $ cd gpio11
pi@raspberrypi4:/sys/class/gpio/gpio11 $ ls
active_low  device  direction  edge  power  subsystem  uevent  value
pi@raspberrypi4:/sys/class/gpio/gpio11 $ echo in > direction
pi@raspberrypi4:/sys/class/gpio/gpio11 $ cat value
0

The value is currently 0, meaning no voltage. If you trigger your Dakota Alert by having someone else walk through the beam, and cat value whilst they do it, you should see the value change to 1. If it doesn’t then you need to do some trouble shooting.

You now have your Dakota Alert system connected to your pi, and telling your pi when someone crosses the beam.

Next, you need to install a push alert app on your phone, so that you can receive alerts. There are a number of different apps available, but I chose pushover, as it seemed the most simple and did exactly what I wanted and nothing more. Follow the instructions on their site to create a userid, download the app, and install it on your phone. Get to a point where you can send alerts to yourself on your phone through their website or by using the e-mail.

Next, create an application on the pushover site, and get the API token from that new application.

Next, we’re going to write a python script that listens for the Dakota Alert relay on the GPIO pins, and then calls pushover to tell it that an alert has been recieved.

I initially wrote this code using information from this alarm howto, and modified it using information from this robotics tutorial, which had more elegant handling of ctrl-c through using interrupts instead of waiting on an alert.

The final code looks like this:

#!/usr/bin/python3.7
import http.client, urllib
import signal, sys, syslog, time
import RPi.GPIO as GPIO

# constant for the GPIO pin wwe've chosen
OUR_PIN = 11 

# signal handler that traps ctrl-c, cleans up the GPIO, and exits
def signal_handler(sig, frame):
    GPIO.cleanup()
    sys.exit(0)

# callback when the pin is triggered, which calls pushover
def pin_triggered_callback(channel):
  syslog.syslog("Detected a rising edge - waiting 100ms to see if we stay on")
  time.sleep(0.1)

  if GPIO.input(OUR_PIN) == 1:
    syslog.syslog("Still high after 100ms, someone is approaching")

    conn = http.client.HTTPSConnection("api.pushover.net:443")

    conn.request("POST", "/1/messages.json",
      urllib.parse.urlencode({
        "token": "<<your pushover API/application token>>",
        "user": "<<comma separated pushover users to notify>>",
        "message": "Someone approaches around the track",
        "sound": "alien",
      }), { "Content-type": "application/x-www-form-urlencoded" })

    response = conn.getresponse()

    # if response isn't 200 then we failed - no actual error handling here, we just print it on the console
    if response.status != 200 :
      syslog.syslog("Failed to send notification for trail monitoring: " + response.status + response.reason + response.read(1000) )

  else:
    syslog.syslog("Wasn't sustained for 100ms, transient spike of some sort")

# main routine - sets everything up, and installs the interrupt handlers
if __name__ == '__main__':
    
  #setup GPIO using Broadcom SOC channel numbering
  GPIO.setmode(GPIO.BCM)

  # set to pull-up (normally closed position)
  GPIO.setup(OUR_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

  GPIO.add_event_detect(OUR_PIN, GPIO.RISING, 
    callback=pin_triggered_callback, bouncetime=2000)
    
  signal.signal(signal.SIGINT, signal_handler)
  signal.pause()

You then need to add this script to the autostart on your pi, so that when it reboots it’s automatically executed. There are a bunch of ways to do that here, I’m lazy so I’m just doing rc.local. One impact of this is that if the script crashes it won’t restart, and more complete methods could monitor it’s execution and auto-restart it.

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

/home/pi/TrailMonitoring/trailMonitoring.py &

exit 0

We add in our script name with an & on the end so that it runs in the background (rather than blocking the startup script). We can see what it’s doing by looking in /var/log/syslog.

Openhab Heating Configuration

This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house.  Refer to the index here.

In this post I cover a detailed configuration of Openhab for heating purposes.  We create the rule sets to allow us to have an arbitrary number of zones, with each zone having 4 setpoints at configurable times during the day.  The zones push those setpoints down to the devices in the zone.  We allow people to change the temperature in a zone using the wall thermostat, but override again at the next timed change.

We also control the running of the boiler based on how many valves are open – this is to avoid the boiler short cycling when there are very few valves or valves only partly open.  We’ll cover this in more detail when we get to the relevant rules.

We create a sitemap that gives us access to most of this information.

Continue reading

Configuration of MAXCUL and CUL Dongle

This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house.  Refer to the index here.

In this post I cover the installation of the firmware for the CUL dongle (culfw), the programming of the dongle to work with your raspberry pi, and configuration of the maxcul binding for Openhab.

At the end of this tutorial you should have one wall thermostat and one radiator valve paired to your raspberry pi via the CUL dongle.

Continue reading

Installing Openhab on Pi

This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house.  Refer to the index here.

In this post we install a new Raspberry Pi from scratch, and get OpenHab running on it.  We choose to use Wifi, and we install it headless (no GUI and no monitor).  We install by connecting the card reader to a linux machine, which gives us access to the file system as we build it.

Continue reading

Using Pi and OpenHab to control radiators and watering

Our house has hydronic radiator heating, we also have a watering system and other equipment.  I wanted to use a Raspberry Pi to control the heating, as our radiators previously had manual valves.  I also wanted to control the garden watering system whilst I was at it.

This tutorial series will cover the process of installing and configuring the software to achieve this, with topics being:

 

Exporting playlists from mythmusic

In my new house I don’t have any free to air TV – reception is too poor.  So my mythtv installation is less useful than it could be – it’s primarily a setup that records TV.  It also plays music, but it’s not inspiring at it.

My frontend died and needed replacing, and after fighting for a while I couldn’t get LIRC/remote controls going with the new hardware.  I looked around and Kodi (an evolution of XBMC) looks to have a really good remote app that goes on my iPhone.  Way better.

I’ve installed Kodi and it’s working well after some fiddling around.  But I had a lot of music playlists in mythtv.  I want them in Kodi.  Kodi can import standard m3u playlists, mythtv doesn’t have a standard export for them.

After googling around a bit, I decided to write a perl script that does it.  Without further ado, here it is for anyone that might need such a thing.

#!/usr/bin/perl
use strict;
use warnings;
use DBI;

# MySQL database configuration
my $dsn = "DBI:mysql:mythconverg";
my $username = "root";
my $password = 'Massey01';

# path prefix - haven't dealt with storage groups, so set this to your storage group path
my $prefix = "/usr/share/mythtv/server/mp3/";

# connect to database
my $dbh  = DBI->connect($dsn,$username,$password);

# create temporary table for holding song list
my $sql = "CREATE temporary table tmp_playlist_songs (
  playlist_id int(11),
  playlist_name varchar(255),
  song_id int(11)
)";
my $create_table = $dbh->prepare($sql);

# create the table
$create_table->execute();
$create_table->finish();

# setup the insert statement ready for use
$sql = "INSERT INTO tmp_playlist_songs( playlist_id, playlist_name, song_id )
        VALUES (?,?,?)";

my $insert_stmt = $dbh->prepare($sql);

# select all playlists from the database
$sql = "SELECT playlist_id,
               playlist_name,
               playlist_songs
           FROM music_playlists";
my $get_playlists = $dbh->prepare($sql);
# execute the query
$get_playlists->execute();

my $playlist_id;
my $playlist_name;
my $playlist_songs;

# iterate over each playlist
while( my @row = $get_playlists->fetchrow_array() ) {
  $playlist_id = $row[0];
  $playlist_name = $row[1];
  $playlist_songs = $row[2];

  my @songs = split( ',', $playlist_songs );

  # insert the songs into the temporary table
  foreach my $song ( @songs ) {
    $insert_stmt->execute($playlist_id, $playlist_name, $song);
  }

  # select out the song filenames
  $sql = "SELECT path, filename FROM
            tmp_playlist_songs,
            music_songs,
            music_directories
          WHERE
            tmp_playlist_songs.song_id = music_songs.song_id AND
            music_songs.directory_id = music_directories.directory_id";
  my $get_playlist_detail = $dbh->prepare($sql);

  $get_playlist_detail->execute();

  open my $file_handle, ">$playlist_name.m3u";

  while( my @song_row = $get_playlist_detail->fetchrow_array() ) {
    print $file_handle $prefix . $song_row[0] . '/' . $song_row[1];
    print $file_handle "\n";
  }
  $get_playlist_detail->finish();

  close $file_handle;

  # clear out the temporary table
  $sql = "DELETE FROM tmp_playlist_songs";
  my $delete_playlist = $dbh->prepare($sql);
  $delete_playlist->execute();
}
$get_playlists->finish();
$insert_stmt->finish();

# disconnect from the MySQL database
$dbh->disconnect();

Hope it’s useful for someone.

Automating radiator based heating system

Our house has a radiator heating system, fired by a large Marshall wood burner.

I’m looking to improve this heating system to achieve:

  • some level of heat storage – so that we don’t have to run the wood fire whenever we want heat
  • a way for that storage to stay reasonably warm for 4-5 days, so we can go away and have the heating automatically run before we return home
  • thermostat control on the individual radiators so we can hold a temperature, rather than adjusting temperature through how vigorously we stoke the fire
  • zoning of the rooms, so that those rooms not in use can not consume heat
  • allow me to run the boiler hard, rather than damping it down, which reduces pollution and increases heat output from a given weight of wood
  • the boiler also runs the domestic hot water (DHW) in winter, currently that’s an open cylinder rather than mains pressure, it’s a bit small, and takes forever to get hot water to the kitchen
  • the thermostat on the boiler that controls the pump is slow to cycle, leading to the boiler overheating and boiling the water, rather than heating it. This is wasteful of heat.

Continue reading

Using protractor to e2e test ui-grid 3.0 (ng-grid)

In my previous post I described upgrading to ui-grid 3.0, which is the not-yet-beta version of ng-grid.  Over time this will offer significant benefits, at the moment it feels like a faster ng-grid.  As part of implementing it on my core application I needed to rewrite the library routines for my end-to-end testing using protractor.  These were reasonably tricky to work out, so I thought I’d post them here for anyone else trying something similar.

Continue reading