Vorke HDMI Switch

Rather than all that rather sensible structured cabling business, our home is awash with HDMI cables to distribute video, peppered with splitters and active cables to reach over the 10 metres you can usually get HDMI on a good day with a tail wind. Like any perfectly reasonable home, much of what we watch originates from the lounge room from satellite, Internet and quaint archaic optical sources, all of which are switched locally. Of course, life is not confined to the lounge room, so a feed goes back to our “racks room” or in BBC terminology, “Central Apparatus Room”, the heart of our home’s slightly haphazard audio, video, telephony and data systems.

From there we had a generic HDMI switch selecting between the lounge and various local sources: CCTV and the console output of various servers. Switching the house feed between CCTV and the lounge output necessitated finding the switch or its equally elusive remote control, pushing the right button and hoping the gods of HDMI would forgive you for interrupting the fragile continuum that normal people seem to accept as being a robust digital A/V interconnect system

So When said switch died, it was an opportunity to replace it with something that could be switched remotely, not by crappy IR control, but the power of the interwebs, specifically in our case the wonder that is MQTT.

So I scoured Amazon for some sort of HDMI switching device that could be controlled by some modern digital medium: Wi-fi? Nope. Ethernet? Nope. USB? Nope. Errr, RS-232? Yes!

How ironic, a commonplace serial protocol capable of carrying up to 18Gbps can only be switched by a serial protocol from the 1960s designed to carry at most 9600bps and grudgingly bumped up to 115200bps in the 90’s because no one could think anything better.

So I ordered a Vorke HDMI Switch (why is this page now in Spanish? It wasn’t like that when I ordered it.) See also http://www.vorke.com/project/vorke-hd41-pro/

 

61Km2BD0GtuL._SL1060_

Linked off the Vorke website support page the serial protocol PDF can be found at the less than encouraging address:  http://www.mediafire.com/file/5ks7wwbg2e5333s/VORKE_HD41_PRO__RS232_HEX.pdf

#!/usr/bin/python3

import paho.mqtt.client as mqtt
import serial

devicePath='/dev/ttyUSB0'
outSelectTopic='home/controller/hdmiswitch/vorkehd41pro/racks/output/switch'
outStateTopic="home/controller/hdmiswitch/vorkehd41pro/racks/output/state"
respOk=b'\xa5[\x02\x03\x00\x00\x01\x00\x00\x00\x00\x00\xfa'

cmd_Output_1 = {
'Input_1':b'\xA5\x5B\x02\x03\x01\x00\x01\x00\x00\x00\x00\x00\xF9',
'Input_2':b'\xA5\x5B\x02\x03\x02\x00\x01\x00\x00\x00\x00\x00\xF8',
'Input_3':b'\xA5\x5B\x02\x03\x03\x00\x01\x00\x00\x00\x00\x00\xF7',
'Input_4':b'\xA5\x5B\x02\x03\x04\x00\x01\x00\x00\x00\x00\x00\xF6',
}
cmd_Audio_Switch = {
'Audio_Auto':b'\xA5\x5B\x03\x02\x01\x00\x01\x00\x00\x00\x00\x00\xF9',
'Stereo_Audio2.0':b'\xA5\x5B\x03\x02\x02\x00\x01\x00\x00\x00\x00\x00\xF8',
'Dolby/DTS_5.1':b'\xA5\x5B\x03\x02\x03\x00\x01\x00\x00\x00\x00\x00\xF7',
'HD_Audio_7.1':b'\xA5\x5B\x03\x02\x04\x00\x01\x00\x00\x00\x00\x00\xF6',
'Query_Audio':b'\xA5\x5B\x01\x0C\x01\x00\x00\x00\x00\x00\x00\x00\xF2',
'Audio_Auto':b'\xA5\x5B\x01\x0C\x01\x00\x01\x00\x00\x00\x00\x00\xF1',
'Audio_2.0':b'\xA5\x5B\x01\x0C\x01\x00\x02\x00\x00\x00\x00\x00\xF0',
'Audio_5.1':b'\xA5\x5B\x01\x0C\x01\x00\x03\x00\x00\x00\x00\x00\xEF',
'Audio_7.1':b'\xA5\x5B\x01\x0C\x01\x00\x04\x00\x00\x00\x00\x00\xEE',
}
cmd_Auto_Switch = {
'ON':b'\xA5\x5B\x02\x05\x0F\x00\x00\x00\x00\x00\x00\x00\xEA',
'OFF':b'\xA5\x5B\x02\x05\xF0\x00\x00\x00\x00\x00\x00\x00\x09',
'Query_Auto':b'\xA5\x5B\x01\x0D\x00\x00\x00\x00\x00\x00\x00\x00\xF2',
'Auto_ON':b'\xA5\x5B\x01\x0D\x0F\x00\x00\x00\x00\x00\x00\x00\xE3',
'Auto_OFF':b'\xA5\x5B\x01\x0D\xF0\x00\x00\x00\x00\x00\x00\x00\x02',
}
cmd_ARC = {
'ON':b'\xA5\x5B\x10\x01\x0F\x00\x01\x00\x00\x00\x00\x00\xDF',
'OFF':b'\xA5\x5B\x10\x01\xF0\x00\x01\x00\x00\x00\x00\x00\xFE',
'Query_ARC':b'\xA5\x5B\x10\x02\x00\x00\x01\x00\x00\x00\x00\x00\xED',
'ARC_ON':b'\xA5\x5B\x10\x02\x0F\x00\x01\x00\x00\x00\x00\x00\xDE',
'ARC_OFF':b'\xA5\x5B\x10\x02\xF0\x00\x01\x00\x00\x00\x00\x00\xFD',
}
cmd_Device_Information_Query = {
'HDMI_IN1':b'\xA5\x5B\x01\x04\x01\x00\x00\x00\x00\x00\x00\x00\xFA',
'HDMI_IN2':b'\xA5\x5B\x01\x04\x02\x00\x00\x00\x00\x00\x00\x00\xF9',
'HDMI_IN3':b'\xA5\x5B\x01\x04\x03\x00\x00\x00\x00\x00\x00\x00\xF8',
'HDMI_IN4':b'\xA5\x5B\x01\x04\x04\x00\x00\x00\x00\x00\x00\x00\xF7',
'HDMI_OUT':b'\xA5\x5B\x01\x05\x01\x00\x00\x00\x00\x00\x00\x00\xF9',
}

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))

    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.

    # Select input -> output 1
    client.subscribe(outSelectTopic)

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print("Rxd: "+msg.topic+" "+str(msg.payload))
    key = 'Input_' + msg.payload.decode()
    if key in cmd_Output_1 :
        print("writing " + key + " to switcher Output_1")
        switcher.write(cmd_Output_1[key])
        resp = switcher.read(13)
        print ("Result: "+str(resp))
        if resp == respOk :
            print("Success!")
            client.publish(outStateTopic, msg.payload, 1, True)
            ignoreNext = 1
        else:
            print("Failure!")
    else :
        print (key + " does not exist in Output_1 command set")

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect("iothub", 1883, 60)
switcher = serial.Serial(devicePath, 19200, timeout=1)


# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.
client.loop_forever()

I don’t normally do Python, but when I do, I mostly copy it from Stack Overflow. Because I didn’t want to type all those numbers in, I copied the pdf into a text file, did some judicious sed’ing and hand fettling to get libraries of  Python strings, most of which this application doesn’t use, but future expansion and all that.

So all this does is listen on outSelectTopic for an input number, send the appropriate string to the switcher and on receipt of a response okay message, publishes the selection back to outStateTopic. I was hoping to actually query the state the switcher was in in case someone operated it via the remote or front panel, but it seems the protocol doesn’t allow for that so ho hum.

Anyway, apart from taking a ponderously long time to switch it works quite nicely.

 

Advertisements

More Random Garden Furniture

After the quite successful, but relatively pedestrian garden bench, I wanted to try another idea I had been harbouring: axial symmetry and angled legs, braced at a central hub. Brilliant, eh?

My first effort was a four legged, round table for our courtyard, big enough to comfortably accommodate 4 people, heavy enough to hold a giant parasol (not selected at the time of designing, but ended up being a 2m x 3m rectangular monster.)

Rather than conventional vertical legs, I put the legs at a 50° or so angle, all connected to a central hub meaning they were all mutually braced. Obviously they can’t all cross through the centre line, so they are offset by about 70mm, using standard timber sizes to connect them and create the hub. It probably better to use a picture:

Table3
View looking down on tabletop, showing legs and central hub.

I haven’t fully fleshed out the tabletop, just drawn some lines on the circular top to represent the gaps between the timbers so that I could get the right dimensions.

Looking from the underside, you can see the legs are anchored to two crossed horizontals forming a cross:

Table3 (1)
Underside showing legs intersecting at central hub and crossed horizontal support under tabletop

The offset symmetry looks slightly unusual, but the advantage is the structure is incredibly stable, it’s doesn’t rely on fancy woodworking joints, failure prone glue or tight tolerances to achieve rigidity – it is inherent in the structure. More practically, the angled leg configuration means no one sitting at the table has to contend with a leg getting in the way of their knees… or at least that’s the idea.

So on with the build. The wood consists entirely of treated CLS construction timber, either 89mmx38mm or 140mmx38mm which I got from my local Wickes, but these can be had from any builder’s merchant.  I cut the hub, legs and supports and started bolting them together. Not shown on the Sketchup model are the fastening arrangements – partly because they were not required to work out the geometry, partly because I hadn’t entirely figured them out and partly because I couldn’t be bothered adding them.

20170701_125807
Legs and supports of table

I used 4 M8 studs through the hub to attach the legs, two in each direction, offset 5mm vertically from the centre line to allow them to cross over. The hub, a 140mm square piece of timber was pre-drilled with a 40mm hole for an umbrella, while the horizontal supports and table top were drilled post-assembly with much swearing. 8mm coach bolts were used to attached the legs to the horizontals, two per leg.

The tabletop was made from 89×38 timbers screwed to the support from underneath using “decking” screws – “green organic” coated, whatever that is, presumably plastic. I’ve used a lot of these type of screws, all the bits of my shed that are not held together by coachbolt are held together with various sizes of these.

Anyways, the tabletop timbers were cut to the length indicated by the model ar right angles, then to make the whole thing round, I used my ancient long-suffering Ryobi jigsaw screwed to an improvised arm pivoting around the centre. This was not ideal as 38mm of timber is a bit much for your average jigsaw! The blade weaved around a bit and I had to finish it off a bit with a surform and plane, but I saw this as the safe option. The alternative would have been a router, which is great for two of the four quadrants of the circle, but is at great risk of splitting the timber when it’s working against the grain. Going slow and in incremental steps would have probably done it, but I was too impatient for that! So without further ado, here the finished product, looking very meta with the model of its creation sitting on its top!

20170702_170239

Update: You can now find the design online in the Sketchup 3d Warehouse

Solar Sensomatic

Despite being constantly disappointed by just how frustratingly sporadic solar energy can be in the UK, I keep thinking I can use it for some ultra low power application for which the greyest of grey skies is sufficient to power it throughout the year, day and night. It’s possible I’ve not tried hard enough yet, but so far I never cease to be amazed at how little you can count on the sun to be there when you need it.

Anyways, here’s my latest effort, something of a quick and dirty mashup between a commercial solar PIR lamp and an ESP 12e. I was curious to see if I could get a commercially viable  solar powered ‘novelty’ product to provide enough power to communicate events in some useful medium like Wi-Fi, rather than some proprietary RF protocol or impractically short range BLE.

So the donor hardware was an Mpow Solar Motion Sensor Light. These have got an 8 LED light panel, a small solar panel, a PIR sensor and a removable 18650 Li-Ion battery. After buying a couple of these, I started to explore their innards and found a slightly useful teardown confirming that the main control chip is completely unheard of. I reverse engineered the PCB to work out where the bits I need were and made some gentle modifications.

 

Note I’ve not scrutinized the details of the charge management IC, but it appears this solar light has no under-temperature charge protection. Theoretically this can cause the battery to fail due to anode plating in sub-zero conditions = potential fire. I have screwed my units to the neighbour’s fence – frankly I’d be doing them a favour if it burnt down as it’s had it anyway, but do be a little thoughtful when using these units!

For the first incarnation, I used an ESP12e breakout board to hold an ESP12e module and used that to anchor a bunch of surface mount components to make it bootable and interface with the solar module. A small strip of veroboard holds an AD124 3.3v ultra LDO regulator and a couple of 1uF capacitors for supply decoupling. I brought out the necessary pins for programming on a flying 0.1″ header socket, with the result looking like this:

fitting

Going even more old-skool, here’s a hand-drawn schematic:

schematic

The interesting bit here is the wake-up/reset circuitry. The ESP8266 requires a short pulse on the reset pin to get it out of deep sleep mode while the PIR sensor produces positive pulse of a few seconds. To reconcile these things, a simple positive edge detector is formed with a transistor fed by a high pass R-C filter. GPIO12 is used to allow the software to sample the state of the sensor output while GPIO14 is driven and held low by the software on wake-up to prevent the sensor resetting the ESP once it’s already awake. A diode between GPIO0 and reset allows the ESP’s own sleep timer to wake it up without holding the pin high and interfering with the operation of the transistor. Instead a 10k resistor holds the pin high and this also allows external resets when programming as well.

The Mpow light has four modes: off, low level light at night with no motion sensing, low level light with full power if motion detected and full power if motion detected with no light otherwise. The mode is selected by a slider switch. I didn’t want the light to come on at all so I used the first switch setting and cut the track that would enable the light.

cut-track

For the ESP12e, I used the NodeMCU firmware. You can build it here. If you slavishly follow what I do you will need to enable the MQTT module and the cjson module (since I did this, it’s now called sjson module. Code updates required as the NodeMCU folk care little about backward compatibility)

The Lua code I wrote for the ESP can be found here. What does it actually do, I hear you ask? Good question. On detecting movement, the esp, if sleeping wakes up, connects to wi-fi and publishes a 1 to the topic set in the mqttCfg.sensorTopic in the config.lua file. It then stays awake for 10s or so unless there is another pulse from the sensor which will cause it to stay awake a little longer. It will also publish the battery voltage to mqttCfg.battTopic. If the battery voltage is healthy, it will stay awake for another 10s for movement, restarting the clock if movement is detected. If the battery voltage is low, all the timers are shortened to try and save power. After it times out, it goes to deep  sleep for 30 minutes or so. If it isn’t re-awakened by the sensor, it wakes up, send a status message of it has sufficient power before going to sleep again.

So how well does it go during the depths of winter? Well not as well as I’d have hoped for. At present, rapidly approaching the winter solstice, the first prototype is operating about 5 hours a day before it goes into self-preservation mode. Of course firing up the Wi-fi every 10 minutes to send a battery voltage is not going to help the longevity, but at present I’m more interested in seeing how it behaves than getting ultimate performance. The second prototype is set to wake every 30 minutes and also included some ‘tweaks’ to avoid Wifi recalibration on every wake cycle – so far this has proven less successful, disappearing for days at a time. I suspect the Wi-fi performance of the second ESP12e is worse as it also struggles with range and this is no doubt going to increase power drain as more energy is required to transfer data. I will probably continue to tweak every now and then and hopefully more can be had from it.

So not an unmitigated success, but still quite promising as the sort of energy a sub 1W solar cell can produce in overcast conditions is generally pitiful – being able to send regular comms over Wi-fi on such power makes for useful IoT applications. The ESP8266 used in the ESP12e module is not ideal for such applications, but it has the advantage of being cheap to the point of being “disposable”. The ESP32 would probably be a better candidate for more serious IoT applications as it has some ultra low power I/O processing and considerably less ropey and more refined deep sleep capabilities.

 

Wemo Smart Plug to MQTT

The Belkin Wemo smart plug is an early example of a Wi-Fi controlled smart plug that can be controlled with a smart phone and integrated with IFTTT and Alexa and the like. We’ve had a couple kicking around for vital but more-or-less standalone functions, such as allowing me to turn on the coffee machine from bed and turning all the extraneous sound and lighting equipment on and off in our lab, because the socket’s too hard to reach.

51pxhok1fnl-_sl1001_

I’ve had some bash scripts courtesy of this blog which I’ve occasionally used to control these devices from my PC. I finally decided I should integrate them properly with the home so I set about writing a glue script to discover and publish the details of the devices and to allow remote control via the excellent MQTTDash. Without further ado, here it is:

#!/bin/bash

BASE_TOPIC="home/controller/powerswitch/wemo"
declare -A WEMAP

trap "exit" INT TERM
trap "kill 0" EXIT

function log ()
{
	echo "$(date) $*"
}

function do_soap () {
	local URL="$1/upnp/control/basicevent1"
	local CMD="$2"
	local SUBJ="$3"
	local RES="$4"
	local PARAM="$5"

	local SOAP='<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>'"<u:$CMD xmlns:u=\"urn:Belkin:service:basicevent:1\"><$SUBJ>$PARAM</$SUBJ></u:$CMD>"'</s:Body></s:Envelope>'


	curl -0 -A '' -X POST -H 'Accept: ' -H 'Content-type: text/xml; charset="utf-8"' \
		-H "SOAPACTION: \"urn:Belkin:service:basicevent:1#$CMD\"" \
		--data "$SOAP" -s "$URL" \
	                | sed -E -e "/<\\/?$RES>/ ! d ; y/ /_/ ; s|.*>(.*)</.*>|\\1|" | tr -d "\r"
}

function getname () {
	do_soap "$1" GetFriendlyName FriendlyName FriendlyName
}

function getsig () {
	do_soap "$1" GetSignalStrength GetSignalStrength SignalStrength 0
}

function getstate () {
	do_soap "$1" GetBinaryState BinaryState BinaryState 1
}

function setstate () {
	do_soap "$1" SetBinaryState BinaryState BinaryState "$2"
}

function update () {

	local NAME="$1"
	local ADDR="$2"

	STATUS=$(jq -c -n "{ state: $(( $(getstate $ADDR) + 0 )) } + { address: \"$ADDR\" } + { signalstrength: $(( $(getsig $ADDR) + 0 )) }")
	mosquitto_pub -r -t "$BASE_TOPIC/$NAME/status" -m "$STATUS"
}

function discover () {
	local NAME=
	local ADDR=
	gssdp-discover -n 5 -t urn:Belkin:service:basicevent:1 \
		| sed -E -e  '/Location:/ ! d; s|.*(http://.*)/.*|\1|' \
		| while read ADDR
		do
			NAME=$(getname "$ADDR")
			[ -n "$NAME" ] && update "$NAME" "$ADDR"
		done
}

function listen () {
	mosquitto_sub -v -t "$BASE_TOPIC/#" \
	| while read LINE
	do
		if [[ $LINE =~ ^([^\ ]*)\ (.*)$ ]]
		then
			local TOPIC="${BASH_REMATCH[1]}"
			local MSG="${BASH_REMATCH[2]}"
			log "Rxd on '$TOPIC': $MSG"
			if [[ $TOPIC =~ ^.*/([^/]*)/status$ ]]
			then
				local NAME="${BASH_REMATCH[1]}"
				local ADDR=$(echo "$MSG" | jq '.address' | tr -d '"' )
				log "Update '$NAME' => $ADDR"
				[ -n "$NAME" ] && WEMAP[$NAME]="$ADDR"
			fi
			if [[ $TOPIC =~ ^.*/([^/]*)/switch$ ]]
			then
				local NAME="${BASH_REMATCH[1]}"
				log "Set $NAME to $MSG"
				ADDR="${WEMAP[$NAME]}"
				if [ -n "$ADDR" ]
				then
					log "Address for $NAME: $ADDR"
					setstate "$ADDR" "$MSG"
					update "$NAME" "$ADDR"
				else
					log "Unknown address $ADDR for $NAME"
				fi
			fi
		fi
	done
}

( while discover ; do sleep 300 ; done ; ) &

while true
do
	log "Listening for messages"
	listen
	log "Listening pipeline collapsed, retrying in 10s"
	sleep 10
done

In retrospect Bash wasn’t the best tool, but it does the job. To use this you will require few packages, namely gupnp for the discovery utility, jq for creating JSON payloads and the mosquitto MQTT clients. In Debian/Raspbian, you would need to do run the following:

sudo apt-get install gupnp-tools jq mosquitto-clients

To summarize, the script creates a child process which, every five minutes, looks for all the devices on the LAN and queries their status. It publishes this info along with the device’s IP address/port in JSON form to a MQTT topic containing it’s “Friendly Name”. For example, our coffee machine (a Rancilio Silvia) gets an entry like this posted to the topic “home/controller/powerswitch/wemo/Miss_Silvia/status”:

{"state":0,"address":"http://192.168.0.21:49153","signalstrength":15}

A loop in the primary thread waits for messages whose topic starts with  “home/controller/powerswitch/wemo/”, picking up all these status messages and maintaining a map of friendly names to addresse/port pairs.  Additionally it will also pick up any switching requests, with a topic in the form of home/controller/powerswitch/wemo/FriendlyName/switch, containing a payload of just a 0 or a 1.

I run the script in a screen session launched from /etc/rc.local, i.e.:

#!/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

su -c "screen -dmS wemomqtt /home/dan/bin/wemo-to-mqtt.sh" dan

You can do a “screen -r wemomqtt” to look at it’s status. A more canonical solution is to create a systemd service for it and replace the “echo $(date)” in the log function above with the “logger” command to route its output to the system logger.

 

Moorland Power Station

On account of the odd positioning and historic slings and arrows thrown at our home in the past, our front yard is much bigger than our ‘courtyard’ style back yard. As such, we want to pack as much as we can in the front yard, making it another room, an extension of the house and of our slightly warped personalities. Since our last home I have created a growing lighting infrastructure based on DMX, Raspberry Pis, OLA, a MySQL back end and a home grown front end. It was our goal to extend this into the front garden, partly for safety and security reasons, but mostly because… well because we need to… it would be cool, right?

So the idea of keeping our front garden permanently lit doesn’t sit well with my already guilty conscience over power consumption and carbon foot print, so my mission is to make our garden self-sufficient, to create a mini power station from which any amount of frivolity can be powered.

First step is the power generation and storage infrastructure. We needed something to put the batteries in and house the control electronics. Rather than over-design and build some hand crafted structure, we decided to buy something cheep and cheerful from the interwebs. We decided the Moorland Slim Garden Shed made of Solid Wood would do the job for the princely sum of £104 or so. The fact that we also live on a moor made the name appropriate and the project would forever more be dubbed the “Moorland Power Station”.

As you might expect for something so cheap, it came flat packed in many small pieces with and assortment of screws and some less than clear assembly instructions on how to put it together:

IMG_20161113_124024.jpg

On assembly, it was short a few screws and for someone who generally considers themself reasonably competent at such things I found the instructions somewhat lacking in details and when it came to fixing the roof section on to the main body, they had omitted the pre-drilled holes, leaving me to guess exactly what the designers had in mind. Worse than all that, once I had it constructed, it rained heavily, causing the timber to swell and the doors bowed to the point where the cladding came away from its supports:

IMG_20161126_123505.jpg

Also after a couple of weeks the weight of batteries caused the bottom of it to break away from the rest of the structure on account of the pre-existing screws not being put in the right place. Anyway the moral of the story is don’t buy one of these things, it’s crap!

Anyways I shall condense down the various upheavals that have taken place in the system. We started with two 50W panels sitting in the small, but sunny patch at the front of our yard, then subsequently added two 100W panels to catch the afternoon/evening sun, but more importantly to help catch the frail diffuse sunlight resulting from the frequent cloud cover this country knows and loves.

20170730_192823

The control systems in the Moorland has changed around a bit over the months, but the current incarnation looks as follows:

20170805_194141.jpg

We have here:

  • A Raspberry Pi Model B with an RS-485 driver IC connected to its UART0 for DMX and a Wi-Fi dongle to connect back to the house.
  • Three, four channel DMX controlled 700mA LED drivers controlling various lights in the garden with a few channels to spare,
  • An MPPT solar regulator with Modbus diagnostics/configuration port  (RS-485), connected back to the Pi via USB to RS-485 Dongle. (Replacing a cheap and cheerful PWM charger  which I played with and decided was just throwing away too much energy)
  • A home-brew ESP12e based current/voltage monitor, now made redundant by the new solar regulator and waiting for a new task
  • A DC-DC converter to power the Pi and
  • A bunch of DC circuit breakers on a DIN rail

Down the bottom, we have two 100Ah leisure batteries, providing the storage and we now have an IP camera watching the driveway and adding a couple of watts to the load.

While the garden lighting can pull more than 50W flat-chat, the problem at the moment is the quiescent power draw at nearly 12 W. Replacing the ancient Pi and Wi-Fi dongle with a Pi Zero W may well help with this and I also have plans for some power shedding circuitry to cut things off as the batteries run down. In the meantime, I have a 24V mains powered battery charger I can manually switch on if the battery voltage starts to get a bit dire. I have only had to do this couple of nights so far this year, but haven’t hit the full depths of winter in its current configuration yet.

So, on to the interesting bit: getting data from the system. Apart from it’s Maximum Peak Power Tracking capability, I bought the solar regulator, a Tracer 1215BN, mostly because it had an interface I could connect to and retrieve all manner of interesting data from. The interface in question takes the form of an RJ-45 jack, with the centre pins carrying a bi-directional RS-485  connection. The protocol is Modbus, a fairly old industrial bus primarily for interfacing with PLCs and other industrial gear. Before I bought the thing I had found the specifics of it registers on the net, you can find them at http://www.solar-elektro.cz/data/dokumenty/1733_modbus_protocol.pdf.

It would’ve been fairly simple to hack something up to collect the data from the regulator using a number of libraries, but instead I came across collectd, a Linux daemon for collecting all manner of system stats with all manner of plug-ins, including a Modbus plugin. This handy tool provides the ability to publish its data to another collectd instance, via MQTT or direct to Influxdb or Graphite. Only downside of using the built-in Modbus plug-in is that it only supports big-endian word ordering for 32 bit registers while the Tracer uses little-endian ordering, meaning the 32 bit registers can’t be read in full without either modifying the plug-in or adding a custom filter to do the word swapping. For my purposes, most of what I was interested in was either in single 16 bit registers or would fit in the bottom word of a 32 bit  registers anyway.

For those looking to replicate this, you can find the Modbus configuration below, set up to read every the values every ten seconds (note if you are using Raspian or Debian, you will need version 9, “Stretch” to get the Modbus plug-in out of the box and Influx/Grafana as below):

LoadPlugin modbus

<Plugin modbus>
 <Data "solar_volts">
 RegisterBase 0x3100
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "solar_volts_x100"
 </Data>
 <Data "solar_amps">
 RegisterBase 0x3101
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "solar_amps_x100"
 </Data>
 <Data "batt_volts">
 RegisterBase 0x3104
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "batt_volts_x100"
 </Data>
 <Data "batt_charge_amps">
 RegisterBase 0x3105
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "batt_charge_amps_x100"
 </Data>
 <Data "load_volts">
 RegisterBase 0x310C
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "load_volts_x100"
 </Data>
 <Data "load_amps">
 RegisterBase 0x310D
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "load_amps_x100"
 </Data>
 <Data "batt_degc">
 RegisterBase 0x3110
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "battdegc_x100"
 </Data>
 <Data "charger_internal_degc">
 RegisterBase 0x3111
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "charger_degc_x100"
 </Data>
 <Data "charger_heatsink_degc">
 RegisterBase 0x3112
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "charger_heatsink_degc_x100"
 </Data>
 <Data "batt_charge_percent">
 RegisterBase 0x311A
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "batt_charge_percent_x100"
 </Data>
 <Data "batt_remote_degc">
 RegisterBase 0x311B
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "batt_remote_degc_x100"
 </Data>
 <Data "batt_status">
 RegisterBase 0x3200
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "batt_status"
 </Data>
 <Data "charger_status">
 RegisterBase 0x3201
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "charger_status"
 </Data>
 <Data "batt_net_amps">
 RegisterBase 0x331B
 RegisterCmd ReadInput
 RegisterType Int16
 Type gauge
 Instance "batt_net_amps_x100"
 </Data>

# Watts are 32 bit little endian and we only read big here. Take first word only
 <Data "batt_charge_watts">
 RegisterBase 0x3106
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "batt_charge_watts_x100"
 </Data>
 <Data "load_watts">
 RegisterBase 0x310E
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "load_watts_x100"
 </Data>
 <Data "consumed_today_kwh">
 RegisterBase 0x3304
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "consumed_today_kwh_x100"
 </Data>
 <Data "generated_today_kwh">
 RegisterBase 0x330C
 RegisterCmd ReadInput
 RegisterType Uint16
 Type gauge
 Instance "generated_today_kwh_x100"
 </Data>


# <Data "">
# RegisterBase 0x3
# RegisterCmd ReadInput
# RegisterType Uint16
# Type gauge
# Instance "_x100"
# </Data>

<Host "MoorLandPi">
 Device "/dev/ttyUSB0"
 BaudRate 115200
 Interval 10

<Slave 1>
 Instance "solar-charger" # optional
 Collect "solar_volts"
 Collect "solar_amps"
 Collect "batt_volts"
 Collect "batt_charge_amps"
 Collect "load_volts"
 Collect "load_amps"
 Collect "load_watts"
 Collect "batt_degc"
 Collect "charger_internal_degc"
 Collect "charger_heatsink_degc"
 Collect "batt_charge_percent"
 Collect "batt_remote_degc"
 Collect "batt_status"
 Collect "charger_status"
 Collect "batt_net_amps"

Collect "batt_charge_watts"
 Collect "load_watts"
 Collect "consumed_today_kwh"
 Collect "generated_today_kwh"

</Slave>
 </Host>
</Plugin>

Note that most of the registers are integers with 100x scaling of the actual values. For all of these I append a _x100 suffix. I then set up a filter in collectd that finds parameters with this suffix, divides them by 100 and strips the suffix of the end. The collectd documentation is a little thin on it documentation for filters and scaling, but I eventually managed to find some useful examples to fill in the gaps. Here’s what I ended up with:

LoadPlugin match_regex
LoadPlugin target_scale
LoadPlugin target_replace

# Filter chain config

<Chain "PreCache">
 <Rule "Scale x100">
 # Find scaling factor as suffix
  <Match "regex">
   TypeInstance "_x100$"
  </Match>
  # Divide by factor
  <Target "scale">
   Factor 0.01
  </Target>
  # Strip scaling factor from instance name
  <Target "replace">
   TypeInstance "_[^_]*$" ""
  </Target>
 </Rule>
</Chain>

These can be added to the main collectd.conf file or more sensibly, put in separate files under the /etc/collectd/collectd.conf.d directory, where they won’t interfere with upgrades etc. You can configure collectd to send directly to an Influxdb server; In my case I chose to send the data via MQTT, then use another collectd instance to receive it and send the result to Influx. This may or my not work better on account of the collectd protocol being UDP based while MQTT uses TCP – potentially better over a lossy Wi-Fi link. To get Influxdb to accept data from collectd, you just need to enable it in the [[collectd]] section of the /etc/influxdb/influxdb.conf file and ensure collectd is set to send data to the that address in it network plugin settings.

To turn all this data into purty pictures, I use and recommend Grafana, now also part of the Debian/Raspbian Stretch distribution, saving much pain when installing to a Pi. Grafana is reasonably straightforward to get going, once you add an Influxdb data source, you can add as many graphs and other gewgaws as you please:

moorland-grafana-cropped.png

 

Pipe Dreams

Our back yard consists of a tiny courtyard, long and narrow, mostly covered in nasty old concrete. It is a challenging area to grow things, especially with the 6 foot+ fence necessary to get some privacy from the neighbors. To get some happy greenery we wanted to go up. We had already tried hanging baskets, but they have a tendancy to dry out quickly and we’re just not the type of people who are rigourous or organized enough to respond to the needs of such delicate things.

I had a thought… something about pipe organs. What about narrow, but voluminous plant pots? High up and multi-leveled to catch the sun and get a cascade of greenery. I did my best to convey the vision to Will and he got it. The pipe project was born.

My thought was 250mm pipes of varying length, clustered in groups, filled with soil. Looking at the cost of such pipes versus the cost of slightly smaller 200mm pipes made me decide the latter was perhaps the safer option given the large number of unknowns in the project.

So a couple of bottles of red and a few days later three 6 metre pipes turn up in our front yard. How to cut them? I had various thoughts involving everything from hand saws to various cutting contraptions, but hadn’t really come up with a convincing plan. Eventually I decided I needed some wheels… casters of the fixed variety. I found some some suitably cheap ones with bearings and rubber tyres from Amazon and ordered a bunch. From there I improvised a mostly safe device out of scraps of timber and a couple of hinges that would accommodate my circular saw:

20170319_144433.jpg

Once I got the hang of it, this worked remarkably well. The slightly uneven ground and various inaccuracies in the setup meant that the cut had a tendancy to wander – exactly as I feared it might. However, it became apparent that the slack in the caster bearings and general wobble etc meant it was possible to guide the path of the saw somewhat just by pushing or pulling the pipe the right direction – all I had to do was mark out a line to cut to then gently push or pull as I turned the pipe around into the saw.

The plans to fix the pipes together had about as much pre-planning as the cutting process. My general thoughts were to bind them together with straps of some kind, but experimenting with some ratchet straps, it became clear this wouldn’t stop the whole assembly from tipping over – straps couldn’t exert enough tension to stop the pipes from sliding against each other without also deforming them. I decided to bolt them together, but only at the tops as I wanted to make sure the whole setup would stay configurable. So the bolts stop them from sliding against each other and therefore keep them upright, but straps keep them firmly bundled together. To plug the ends, I mixed up postcrete in sturdy water proof plastic bags, then dropped said bags down the pipe, allowing the concrete to set with a flat bottom. I drilled a series of holes in a line a couple of feet from the bottom of each pipe for drainage. The holes all faced the centre, where each bunch of three pipes met. I stuck some hessian in place to try and stop dirt from washing out the holes.

20170401_122805.jpg

After deciding ratchet straps were too ugly I decided cable ties were the answer – I already had some 1030mm x 12.7 mm ties from previous experiments and they did the job nicely:

20170326_180941.jpg

So, initial planting plus a host of more conventional plants in large pots makes for a promising start:

20170416_155047.jpgA season later and we’ve had some poorly plant, but mostly a load of growth:

20170906_153411_HDR.jpg

By the way, that is a Gunnera Mantica growing out of one of those – almost everyone who knows what that is says we’re crazy and the pipe will burst as the plant attempts to break free of its shackles. My faith is in the wonders of modern materials science. I’m sure this is exactly the sort of thing they were thinking when they designed that pipe.

All in all, so far so good. Only hiccup is that the concrete and plastic bag method of plugging the bottom didn’t seal it that well. Water seeps out slowly from the bottom long after the pipes are watered, turning the surrounding concrete green with moss/algae. I’m not fussed. Green is better than crappy concrete colour.

Random Garden Furniture

Sometimes you just wanna go low tech. I have recently found great satisfaction in making stuff for the garden. While I am of course a completely rational engineer, driven only by the ruthless pursuit of functionality, I seem to have a habit of adding unnecessary constraints to my designs to make things interesting. What we’re really talking about are aesthetic demands like symmetry, minimalism and a general feeling of mathematical and mechanical purity.

When started building my shed, the first thing I did was buy a sliding compound mitre saw,  (Bosch PCM 8 S) a magnificent device, provided chopping lengths of timber at arbitrary angles is your thing. As it happened I discovered chopping timber at arbitrary angles was my thing and I wanted more.

Once the shed was finished or at least its first iteration was done, we moved onto making a nice garden to enjoy and Will wanted a garden bench he could lie on. I was unimpressed by the solidity of designs I had seen in local shops and decided it would be an interesting challenge to build a sturdy seat from the same planed, treated construction timber I had build the shed from.

I wanted a design that didn’t rely on glue or clever carpentry joints to support the seat and back, instead something that is quick and simple to build  that will make the most of the available tools and materials. After some headscratching and scribbling a lot of incoherent drawings on paper, I resorted to sketch-up:

bench-su.jpg

Building it was a doddle – all the pieces are made from the same timber, 89x38mm, planed treated construction timber. The supports were cut at all manner of weird angles – none of of them a problem with a good mitre saw to hand. Behold:

20170501_154440.jpg

I was concerned during the design process the seat may need some shoring up to support it in the middle and to stop it wobbling laterally and had plans to add a supporting bar between the legs, but it was more than sturdy enough.

20170501_164349.jpg

Buoyed by this success I would go on to use this combination of timber, sketch-up and saw again; more to follow…

Update: Model available via Sketchup 3d Warehouse