File source: http://commons.wikimedia.org/wiki/File:Honeywell_round_thermostat.jpg

So the original home automation is the thermostat. And many of us will have grown up with the Honeywell T87.  This will have been mounted to that lovely faux wood panelling in your house :). It worked in a very simple model: there was 2 wires that came from your furnace. One had 24VAC, and the other was connected to a relay that the far side was the other leg of the 24VAC. When you shorted the wires, the heat came on.

As people started to get lazy rich,  they bought central air conditioning, and a 2nd pair of wires was run, same principle.

As the 1970’s oil embargo occurred, people started to care about power usage, and we added another wire, the ‘common’, which was always live, and could run the electronics in a very modest smart thermostat (one with a timer). Those who didn’t have the smart timer set the heat back before bed (in my house as a kid the heat was set back to ~12-14 at night).

Then we started to want to run the circulate fan independently of the heat, to have 2-stage heat, 2-stage ac, heat pumps, etc. And we started to need bigger and fatter bundles of wires from the basement to the thermostat. And this became a problem in retrofit, often hard to run.

Niche products were created (e.g. the ‘add a common‘ adapters that used simple diode methods to ‘route’ into one leg or the other). These are recommended if you buy a Nest or Ecobee and need a Common (always-on power).

Looking at my furnaces, they are continuously variable heat aperture, and continuously variable fan speed. It seems a shame that i’ve jumpered them to ‘comfort-r‘ and left it to sort itself out.

But its 2017, there has to be a better way. We could trivially use wireless and some GPIO on a micro (e.g. slap an 8266 @ the furnace end with some mosfets). But then we’d have a solution that would not be an open platform, it wouldn’t work with all of the various and sundry thermostats that are now ‘wall jewellery’, we’d have yet another single-purpose gadget.

OK, we could expand that, and use a wireless thing on each end, gpio in becomes gpio out, a ‘parallel to wireless to parallel’ bus. So now to the wireless. You would want something w/ zero setup that worked even if the power was out somewhere (e.g. no hub). For this we could use bluetooth, zigbee, zwave, lorawan, wifi, … an embarassment of riches.

  • OK, bluetooth. It doesn’t have great range, it just won’t be reliable.
  • Zigbee. We need a hub
  • ZWave. We need a hub
  • Lorawan. Well, this is intriguing, this should work.
  • Wifi. We need a hub.

So, we can look at using lorawan. But is there another simpler way?

Lets think back to one of the other early leaders in home automation. X10. We all succumbed and bought the starter kit that the pop-under banner adds of 1999 told us to (remember those? they were awful!). How did X10 work? Well it used the ‘zero-crossing’. It would embed a digital signal in the 110V (and higher for other folks!) wire. 60 times a second the voltage would swing from positive to negative, going through zero-volts. At this time, the X10 would chirp out a bit of information and thus need no (additional) wires, and yet not need a wireless hub.

Now back to our thermostat. We could take the 24VAC common pair, and embed info in that zero-cross of that, and need no other wires. Every thermostat ever (including that T87) had a single or more pair of wires.

We could create a small widget that had a breakout board at each end, and would be transparent.

Now, lets look at other applications. Your doorbell is 24VAC, your sprinklers are, perhaps other devices. This hypothetical device that has a COGS of ~$5 per end could have a big addressable market.

Who’s in?

So Home Assistant, Google Home, IFTT, all great products. And the whole is greater than the sum of the parts.

Up until now, to enable music in my Living Room, there have been several choices:

  1. Use the Google Home, its got an ‘ok’ speaker
  2. Use the Sonos through a Denon AVRX4000, this drives the in-wall speakers
  3. Use the ‘Vorke Z1‘ through the Denon
  4. Use the ExpressVu through the Denon
  5. Whistle?

But the Sonos+Denon is the best. And you have several methods. You could use the Harmony remote, select ‘listen to music’, and this would then turn the Denon on, set it to ‘CD’ input on zone-1, and from there you could either use its screen sort-of to control the Sonos (start/stop/volume), or the Sonos remote, or your phone. We’ll give this a 6/10 for simplicity.

Or you could use your phone to drive Home Assistant, turn the Denon on in zone-1, set it to CD, etc. And then use it to control the Sonos. We’ll give that a 7/10.

But both became cumbersome when confronted with the Denon as a dual zone device (runs the Kitchen and the Living Room). There has to be a better way.

So lets look. There’s really no point in separate music in these two rooms (they are too close together). So really I just want the Kitchen zone on the AVR to be on/off, and follow the zone 1.

And, I just want to be able to speak to it, why mess with my phone or remote? But Google Assistant is not yet integrated with Sonos (side note, Sonos has just released speakers with Assistant, so I guess that direction works, but here we are talking my 10-year old Sonos and in-wall speakers).

OK, so enter IFTT. We can use that to glue the 3 together.

So, what are the steps?

  1. Create a scene in Home Assistant (music on, music off)
  2. Create an Automation in Home Assistant (when the music comes on, turn the Denon on in both zones, and set the input)
  3. Create an IFTT recipe “when I say X on assistant, call web request with JSON post to scene”

Success! So now we can say “Hey google, party on” and the music comes on (I’m feeling lucky channel!) in both rooms, on the built-in speakers.

I had tried to sort this out with the Harmony, but it was quite puzzled by the Denon being a 2-zone device, it would always turn the other zone off.

With the price of one bitcoin heading into cost of a new car territory, there’s a lot of hype around blockchain. And most of it is focused around financial systems, e.g. ledger management, etc. One of the unique properties of blockchain is all parties know the same information, and cannot falsify it. This makes it really neat for e.g. counter-party risk swaps, derivatives, etc, that the more complex financial services are focused on.

But what about the bread and butter of main street industry? Its around inventory management. And recently we have seen some big names (Kobe, Mitsubishi) admit to falsifying test records (or applying improper test process), calling into question the safety of downstream items. And we have issues with fraud and counterfeit parts which can cause real issues (e.g. who would want to fly on an aircraft with a counterfeit flux capacitor?).

Aircraft parts are all stamped with a unique serial number. But you can counterfeit these by just stamping the same number, or finding end of life parts and recycling their numbers. Imagine that ‘Rolex’ you bought on ebay. Did you really get a great deal, or did you get a class-A copywatch? Its got a serial #, why not just check? O wait…

This in turn can cause uncertainty on purchasing said aircraft, was it maintained properly, are all the parts real, etc.

Now imagine this applies to all industries. Food safety? Where was that fish caught? Was that taco recalled? Was one of the ingredients later found out to be horse? is this really tuna in my sashimi, or is it butterfish and pink die?

Compounding this problem of inventory management is the complexity of our global supply chain. Buy a car, it has thousands of components, each of which might have hundreds of sub-components etc. And those are made by a large set of manufacturers. This AC Delco radio might have a Panasonic LCD, which in turn uses AC Delco transistors. Each time something crosses the boundary of company A to company B, there is a mediation of sorts. Each has its own inventory management and unique part number and serial. So you have a mapping. And, this gets wrong (shocking), or people don’t bother, and track by lot (here’s your lot of 1M transistors).

What if we could construct a universal inventory management system. One that all companies would be able to use and trust. One that it would be impossible to counterfeit parts. A given part could be in only one spot in the universe at a time. The serial of each device would be its hash. You can’t fool it, everyone has access to the same info, and the cost of keeping it up to date is small, without errors introduced by mapping. When a safety recall or other audit is needed, you can find where it is, and how it got there.

OK, so here’s the plan. We start coding this afternoon. We do our ICO next friday. And in a couple of weeks after that, we pass SAP in market capitalisation.

Who’s in?

So a side affect of this mornings issue with the UPS is I have a new power supply, and it has usb-accessible sensors. If we build OpenCorsairLink, we can access them:

# OpenCorsairLink.elf --device 0
Dev=0, CorsairLink Device Found: HX750i!

Vendor: CORSAIR
Product: HX750i
Firmware: NA
Temperature 0: 40.50 C
Temperature 1: 33.50 C
Powered: 13161 (0d.  3h)
Uptime: 13161 (0d.  3h)
Supply Voltage: 115.00
Total Watts: 116.00
Output 12v:
        Voltage 12.16
        Amps  7.50
        Watts 88.00
Output 5v:
        Voltage  5.00
        Amps  5.00
        Watts 25.00
Output 3.3v:
        Voltage  3.31
        Amps  0.62
        Watts  2.00

Seems like the kind of thing you’d want to graph right? And netdata is the tool of choice for system graphing.

So first, we want to make the device readable by netdata (rather than having it run as root!). So lets put a rule in udev:

# cat /lib/udev/rules.d/50-corsair.rules
 SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="1c05", GROUP="netdata", MODE="0664"

done. Restart the systemd-udevd, and trygger:

systemctl restart systemd-udevd.service
udevadm trigger

OK, now check the permissions worked:

# ls -al /dev/bus/usb/001/003 
crw-rw-r-- 1 root netdata 189, 2 Nov 26 16:50 /dev/bus/usb/001/003

done.

OK, now we need to parse that output. Its not overly complex, not designed for simple scraping, but should be trivial with some Python.

OK, lets put this script in /usr/libexec/netdata/python.d, and we are golden!

# -*- coding: utf-8 -*-
# Description: OpenCorsairLink netdata python module
# Author: Don Bowman (db@donbowman.ca)

#from bases.FrameworkServices.ExecutableService import ExecutableService
from base import ExecutableService

# default module values (can be overridden per job in `config`)
update_every = 5
priority = 60000
retries = 5

# charts order (can be overridden if you want less charts, or different order)
ORDER = ['temp', 'input_voltage', 'output_wattage',
 'out_v', 'out_a', 'out_w',
]

CHARTS = {
    # id: {
    #     'options': [name, title, units, family, context, charttype],
    #     'lines': [
    #         [unique_dimension_name, name, algorithm, multiplier, divisor]
    #     ]}
    'temp': {
        'options': [None, "PSU Temp0", "C", 'psu', 'psu.temp0', 'line'],
        'lines': [
            ['temp0',   'temp0', 'absolute', 1, 100],
            ['temp1',   'temp1', 'absolute', 1, 100]
        ]},
    'input_voltage': {
        'options': [None, "PSU Input Voltage", "V", 'psu', 'psu.input_voltage', 'line'],
        'lines': [
            ['input_voltage',   'input_voltage', 'absolute', 1, 100]
        ]},
    'output_wattage': {
        'options': [None, "PSU Output Wattage", "V", 'psu', 'psu.output_wattage', 'line'],
        'lines': [
            ['output_wattage',   'output_wattage', 'absolute', 1, 100]
        ]},
    'out_v': {
        'options': [None, "PSU Voltage", "V", 'psu', 'psu.out_v', 'line'],
        'lines': [
            ['out_12v_v',   'out_12v_v', 'absolute', 1, 100],
            ['out_5v_v',   'out_5v_v', 'absolute', 1, 100],
            ['out_3v_v',   'out_3v_v', 'absolute', 1, 100]
        ]},
    'out_a': {
        'options': [None, "PSU Amperage", "A", 'psu', 'psu.out_a', 'line'],
        'lines': [
            ['out_12v_a',   'out_12v_a', 'absolute', 1, 100],
            ['out_5v_a',   'out_5v_a', 'absolute', 1, 100],
            ['out_3v_a',   'out_3v_a', 'absolute', 1, 100]
        ]},
    'out_w': {
        'options': [None, "PSU Wattage", "W", 'psu', 'psu.out_w', 'line'],
        'lines': [
            ['out_12v_w',   'out_12v_w', 'absolute', 1, 100],
            ['out_5v_w',   'out_5v_w', 'absolute', 1, 100],
            ['out_3v_w',   'out_3v_w', 'absolute', 1, 100]
        ]},
}

class Service(ExecutableService):
    def __init__(self, configuration=None, name=None):
        ExecutableService.__init__(self, configuration=configuration, name=name)
        self.command = "OpenCorsairLink.elf --device 0"
        self.order = ORDER
        self.definitions = CHARTS

    def _get_data(self):
        """
        Format data received from shell command
        :return: dict
        """
        raw_data = self._get_raw_data()
        self.debug('raw_data: <<%s>>' % raw_data)
        if not raw_data:
            return None

        ckeys = {}
        ckeys['Temperature 0'] = 'temp0'
        ckeys['Temperature 1'] = 'temp1'
        ckeys['Supply Voltage'] = 'input_voltage'
        ckeys['Total Watts'] = 'output_wattage'
        ckeys['Output 12v'] = '12v'
        ckeys['Output 5v'] = '5v'
        ckeys['Output 3.3v'] = '3v'

        data = {}
        lm = ''
        raw_data = ''.join(raw_data)
        self.debug('==================================')
        for l in raw_data.split('\n'):
            l = ''.join(l.strip())
            self.debug('l: <<%s>>' % l)
            fields = l.split(':')
            if len(fields) > 1:
                keyn = ''.join(fields[0]).strip()
                keyv = ''.join(fields[1]).strip()
                if keyn in ckeys:
                    x = ckeys.get(keyn,"None")
                    if len(keyv):
                        keyv = keyv.split(' ')[0]
                        data[x] = int ( float(keyv) * 100)
                    lm = x
            elif len(lm) > 0:
                fields = l.split(' ')
                if (fields[0] == 'Voltage'):
                    data['out_%s_v' % lm] = int( float(fields[-1]) * 100)
                elif (fields[0] == 'Amps'):
                    data['out_%s_a' % lm] = int( float(fields[-1]) * 100)
                elif (fields[0] == 'Watts'):
                    data['out_%s_w' % lm] = int( float(fields[-1]) * 100)

        self.debug('data: <<%s>>' % data)
        return data

OK so I got up this am, and the nas that runs my home assistant, blog, cloud, plex, … was offline. And you notice this because the lights don’t work 🙂 (note to self: more backup lighting in my office!)

OK, make some iced tea, head down to the basement to check it out. All lights are off. Check the UPS, UPS reads OK, the big compute server is rumbling along, so it can’t be the UPS (foreshadowing, more on this later).

OK, unwire it (2 x GE, 4x USB, 1 x power, 1x HDMI) from behind. Remove and place on bench (it is $#!% heavy with all the drives etc!).

Plug in direct to the wall. No lights. DMM shows no +12 or +5. Conclusion: bad power supply. These things happen, this is a 750W Seasonic that has run @ 100% duty cycle for ~7 years, its not inconceivable. Wait a few minutes for Canada Computers to open, head there. Pick up a new Corsair HX750i. Get home, unpack, think, hey, shortcut, i’ll just use the in-place wires from the Seasonic, they are both modular, should be the same right? Plug it all in, nothing starts. Hmm. Curse, realise that the pinouts are *different* for the same keyed connectors. Reroute and replace all the wiring (and loose some blood, this case is very sharp inside due to some previous experiments). OK, now turn it on, and it works. Great. But… I’m 4 molex connectors short to do the case fans (side note: is there any more wretched connector than the PC Molex?)

OK, now what should i do? I reconfirm the Seasonic cables are incorrect. I briefly consider rewiring the Molex, but future me would hate that, so, no. Then I remember the desktop PC has a Corsair in it, and has some spares, so I raid its parts bin, and we are good. (The backup plan was a NZXT GRID+ V2, which would have let me control these 5 fans, and some double-sided tape).

OK, put it back on the server shelf, plug it in. And here is where something miraculous happened. I mean something that has nearly infinitely poor odds of occurring. I reached around behind this large, deep server, and plugged in 4 USB cables in the dark without seeing them. And 100% of them were the right orientation on the first try. I mean, come on, what are the odds? Its well known that a USB type A plug exists in some weird tri-state logic universe where you try it one way, doesn’t work, flip it, doesn’t work, flip it again, and it works. To get 4 in a row, in the dark, not seeing, blind? OMG.

OK, hit the power, and, nothing. WTF? Now lets go back to that foreshadowing moment. The nas is run off a different UPS than the big compute server. One that is tucked away at the bottom out of sight. And sure enough, that UPS is off. So how come the problem followed it to the bench where i plugged it in direct? Turns out that breaker is off. Argh. So i checked the wrong UPS, and then double-checked with an off-circuit. So its likely my Seasonic is good (and all the pain re-wiring!), and I have a UPS fault. I manually reset the UPS and it comes up, but in bypass (it shows fully charged battery but fault). Sigh.

So I run the power cord to the compute server’s UPS (which has margin to spare), and lick my wounds, write this blog, and stare at the Seasonic, cables, blood, and time.

So what are the odds? The odds of the first chain were unlikely in the negative direction, and the odds of the 4xUSB insertion were unlikely in the positive direction. Does this mean my Karma balances today?

ps, I’m guessing tomorrow’s adventure might entail finding what’s in a TrippLite pure-sine-wave UPS…