fredag den 23. december 2016

Using Home-Assistant to smarten my home and playing around with IoT, and even dumber things (433mhz)

Intro:

I admit that I'm somewhat of a geek, and one of my many intersts is home-automation, robotics and IoT, so ofcourse I NEED to have this in our house.
The only problem is that:
  • I don't really want to pay all that much for it
  • Don't want to be locked into one vendor/technology
  • Would like it to do so much more than any commercial solutions I'v found so far can do.
  • I would like to integrate with what we already got/have at home.

So far I been using a raspberry pi with some 433Mhz transmit and receive modules (link).
The TX module works ok, but the receiver is bad, and only works within ~3 meters. So I upgraded the receiver to a RXB6 (link), and now the range is at least 30 meters (even without any antenna soldered onto the PCB).

So what do I control?

  • Power-sockets (link):
    We have a bunch (+20) of 230V power-sockets (3 sockets cost less than 20$ US, including a remote).
    These control some of our lights.
  • Some relays (link):
    These help toggle other lights, and other stuff that either just needs a small flick (as they only turn on for a short time, and back off again), or don't run on 230V.

On the software side, here's how I controlled it

  • rc-switch (link)
    To send and receive codes.
  • IFTTT (link)
    To automate some of the lights, so the outside lights turn on at sunset, and off at sunrise.
  • PHP to implement some webservices, so IFTTT could talk to rc-switch, and also our smartphones could be used as a remote.
  • Simplepush (link) to push out notifications from my system to phones


What about input/sensors?

Oh yes, I've got that too:
  • PIR sensors (link)
    For motion detection.
    Though we have a 6 kg cat, it's never triggerd a false alarm from these, which is quite nice.
  • Door/Window sensors (link):
    These a magnetic sensors, and are placed on doors and windows. 


Now there are some problems with this setup/system

  1. Automation is hardcoded, or not easy to change.
  2. There's no nice interface.
  3. I'm missing a whole lot of features.

I would like a better interface, and a mobile client.
I would also like to control and monitor more of the stuff that I already have.

For instance, I would like to monitor the temperature/humidity in our basement, so we can avoid any potential problems with moisture.

I also have several RGB led strips that are currently controlled by a crappy IR remote, so they aren't really used, even though they are really good at setting a mood.

The smoke detectors we have it this house are linked, so if one ones, they all sound. They emit on 433Mhz as well. I want these integrated as well.
And while we're at it, why not use these as sirens if/when the alarm goes off.

Our doorbell, why not also integrate that (433 wireless as well)?

While I like developing the backend, and device stuff, web and mobile interfaces aren't really my thing, so I've been looking for something to help me in this deparment.

A note on the price

Well, as I said in the beginning, I think the solutions on the market today are too expensive.
Here in Denmark (and most of europe) there an alarm company called Verisure, that also frequently calls me. They offer Smoke detectors, PIR's, door/window sensors, camera's and remote power sockets.
They don't mention prices on their website, but they offered me a package containing (the home plus):

  • 2 camera's (with PIR)
  • 2 smoke detectors (with temperature and humidity logger)
  • 3 door/windows contacts
  • 1 remote power socket
  • 1 voice box
  • 1 keypad
  • 1 keyfob
  • 1 central unit (with battery backup)
And the price you ask?
986 US$ (yes, almost one thousand US dollars - and no, I'm not missing a comma).
And then you of course also need to pay for the installation: 281 US$
And lastly (whch is the "best" part), it's not when you equipment! You're just renting it, and if you cancel your subscription you'll have to deliver it all back.
Now the subscription is "only" 45 US$ pr. month.

Ouch!

Okay, you'll never have to worry about changing the batteries, because that's included in the subscription.

Their website does not mention any prices, but always just offers a "lets call you" option (which is why they keep calling me, as I did this once).

During one of these calls I asked what an extra smoke detector costs, and this is what I got: One-time fee of  140 US$ (999 dkr.), and a monthly free of 5 US$.


They have good rating on trustpilot, seem like serious, and know what they talk about, but for those prices, they really also should!

So lets take a look at the prices, for a home-made alarm (of course all prices are one-time, and the equiptment is yours afterwards, and there's no mondtly fee. You just need to change the batteries once a while):

  • Smoke detectors: Oddly expensive, but I have yet to find these "linked" ones on ebay) - link: 16 US$ - 109 dkr.
  • PIR - link: 4 US$ - 28 dkr.
  • Door/window sensor - link: 3 US$ - 17 dkr.
  • Temperature/Humidity sensor - link: 6 US$ - 37 dkr.
  • RFID/NFC tags - link:  4 US$ - 27 dkr (for 10!) or less than 0,5$ each.
  • Power socket: - link: 14 US$ - 94 dkr. (for 3, including remote!) or 4$ each.
And you the controller you'll need:
  • Raspberry Pi (I'm using a RPI2) - 35 US$
  • Micro-sd card (or plain if you use a RPI1) - 5 US$
  • Power adapter - 5 US$
  • 433 RX module (RXB6) - 2 US$
  • 433 TX module (link) - 1 US$ (for a TX/RX pair)
So a comparable system would be:
  • Smoke detectors: 2x16 = 32 US$
  • PIRS = 2x4 = 8 US$
  • Door/windo sensors: 3x3 = 9 US$
  • Temperature/Humidity sensors: 2x6 = 12 US$
  • Power sockets: 1x14 US$
  • Controller:
    • Raspberry pi3 - 35 US$
    • SD-card - 5 US$
    • Power adapter - 5 US$
    • 433Mhz TX/RX modules - 3 US$

In total: 123 US$ (if you need all of the things)
SD-card, power adapter, and if you're reading this, raspberry pi, you might already have.

Now of course they are not 100% comparable.
For instance I'm using a old google nexus 10 tablet (with nfc) as control panel.
Otherwise you can use your phone as control panel.

One important thing the our home-made system is missing are the camera's, but I'll come back later and show you how to integrate these (any ip-camera will do, or you can even use a old usb webcam, and connect it to the rpi).


Again the whole point is to use sensors that are cheap and what you already got at home.


Meet Home-Assistant:

As I don't like playing around with web-interfaces as much as other software I've been looking for open-source solutions to help me out.
I've found two interesting projects:
openHab and Home-Assistant.
openHab is implemented in Java, and HA in python.

I haven't used python before, but HA seems to have more momentum, so I choose this.
Out-of-the-box it does not have the capability to receive 433 codes from rc-switch, you I'll show how to implement a component for this.

Here's my notes on setting it up.


HA Setup-Guide:

Requirements:

  • 433Mhz modules (RX6B receiver is best)
  • Raspberry pi
  • switches/pir's/more

Software install:

Install arch linux

Go to https://archlinuxarm.org/ and follow the instructions to install arch linux on your pi flavor (I'm using a RPI2).

After arch linux for ARM is installed on the SD-card, boot the rpi, and ssh into the booted device (or login locally) as alarm:

Change default alarm
passwd
And root password
su
passwd

Update pacman 
pacman -Syu

Localize system

timedatectl set-timezone Europe/Copenhagen
hostnamectl set-hostname rfcac
nano /etc/locale.gen
(uncomment da_DK.UTF-8)
locale-gen
localectl set-keymap dk

Install Home-Assistant

Install python 3:
pacman -S python python-pip

If you what to use netdisco (which is also a part of the first demo), you'll need gcc as well:
pacman -S gcc 

Install Home-Assistant (HASS):
pip3 install homeassistant 

You can check that it works by running:
hass --open-ui

Note that that it takes a while for hass to first start as it needs to download missing modules. This is also true when adding new modules to the configuration.

Test the install:
Point your browser to http://localhost:8123


We'll create a systemd unit file to run hass on boot (/etc/systemd/system/hass.service):
[Unit]
Description=Home Assistant
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/hass
[Install]
WantedBy=multi-user.target

After creating the file, re-read all unit files:
systemctl daemon-reload
And make sure it's started when your raspberry boots:
systemctl enable hass


Components
In Home-Assistant we'll be using two components to control our 433Mhz traffic.
One is built-in, and is called "Raspberry Pi RF Switch".


rfcac
The other is a homemade one, if called rfcac.
You'll need to create the file rfcac.py in a custom_components directory under the homeassistant config directory:
/root/.homeassistant/custom_components/binary_sensor/rfcac.py:
"""
Binary sensor for 433 interface
Params:
 * name: sensor-name
 * code: 433 code for the sensor (sniff it with rpi_rf_receive or rcswitch
 * type: sensor type (see https://home-assistant.io/components/binary_sensor/ for supported types)
"""
import os
from homeassistant.components.binary_sensor import BinarySensorDevice

def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the rfcac binary sensor platform."""
    add_devices([RFcacBinarySensor(config['name'], config['code'], config['type'])])
"""
    add_devices([
        RFcacBinarySensor('TV-Stue', '1234', 'motion'),
        RFcacBinarySensor('Kokken', '123', 'motion'),
    ])
"""
class RFcacBinarySensor(BinarySensorDevice):
    """A RFcac binary sensor."""
    def __init__(self, name, code, sensor_class):
        """Initialize the sensor."""
        self._name = name
        self._state = False
        self._code = str(code)
        self._sensor_type = sensor_class
        self.update()
    @property
    def sensor_class(self):
        """Return the class of this sensor."""
        return self._sensor_type
    @property
    def should_poll(self):
        """Poll for now, to read the file state"""
        return True
    @property
    def name(self):
        """Return the name of the binary sensor."""
        return self._name
    @property
    def is_on(self):
        """Return true if the binary sensor is on."""
        return self._state
    def update(self):
        """Update the state of the sensor"""
        """self._state = False"""
        self._state = os.path.isfile('/tmp/rfcac/' + self._code)
        if self._state:
            os.remove('/tmp/rfcac/' + self._code)

The rfcac modules consumes codes read from /tmp/rfcac/*
It scan this directory for codes (see rescan interval in config file below), and if a code is configured, the sensor is triggered.

rfcac system service
This script uses the rpi_rf_receive command from the rpi_rf module, and places the codes read from rpi_rf_receive into /tmp/rfcac.

Install rpi_rf module using the python installer:
pip3 install rpi-rf

The script: /root/433mhz_receive.sh:
#!/bin/bash
#Create /tmp/rfcac directory
mkdir -p /tmp/rfcac
#Read 433Mhz codes, and append to our rxLog
/usr/bin/rpi-rf_receive &> /tmp/rfcac/rx.log &
#read lines from rx log, and place code into /tmp/rfcac/
tail -f /tmp/rfcac/rx.log |
  while IFS= read -r line
  do
     code=`echo "$line" | cut -d' ' -f6`
    touch /tmp/rfcac/$code
  done

Also remember to make it executable:
chmod +x /root/433mhz_receive.sh

And a systemd unit file, to lauch to on boot (/etc/systemd/system/rfcac.service):
[Unit]
Description=RFcac
After=network.target
[Service]
Type=simple
ExecStart=/root/433mhz_receive.sh
[Install]
WantedBy=multi-user.target


To make in run on boot (remember to run daemon-reload):
systemctl enable rfcac

configuration.yaml:
homeassistant:
  # Name of the location where Home Assistant is running
  name: Vibevaenget 4
  # Location required to calculate the time the sun rises and sets
  latitude: 55.8494015
  longitude: 9.8414076
  # Impacts weather/sunrise data (altitude above sea level in meters)
  elevation: 5
  # metric for Metric, imperial for Imperial
  unit_system: metric
  # Pick yours from here: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
  time_zone: Europe/Copenhagen
# Show links to resources in log and frontend
#introduction:
# Enables the frontend
frontend:
http:
  # Uncomment this to add a password (recommended!)
   api_password:
# Checks for available updates
updater:
# Discover some devices automatically
#discovery:
# Allows you to issue voice commands from the frontend in enabled browsers
conversation:
# Enables support for tracking state changes over time.
history:
# View all events in a logbook
logbook:
# Track the sun
sun:
zone 1:
  name: home
  latitude: 55.8494015
  longitude: 9.8414076
  radius: 200
  icon: mdi:home
zone 2:
  name: dis
  latitude: 56.069829
  longitude: 9.9784613
  radius: 200
  icon: mdi:factory

# Weather Prediction
sensor 1:
  platform: yr
sensor 2:
#Travel times
#https://maps.googleapis.com/maps/api/distancematrix/json?origins=Vibev%C3%A6nget+4,Horsens|Denmark&destinations=H%C3%B8jbjerg|Denmark&key=AIzaSyCtVwdi82LakzZso0mmmwWdIsB-6AuNRfg
  platform: google_travel_time
  api_key: AIzaSyCtVwdi82LakzZso0mmmwWdIsB-6AuNRfg
  origin: zone.home
  destination: zone.dis
#Hardware Sensors
sensor 3:
  - platform: systemmonitor
    resources:
      - type: disk_use_percent
        arg: /
      - type: disk_use_percent
        arg: /tmp
      - type: memory_free
      - type: memory_use_percent
      - type: processor_use
      - type: last_boot
binary_sensor 1:
   platform: rfcac
   name: Kokken
   code: 4523456
   type: motion
   scan_interval: 1
binary_sensor 2:
   platform: rfcac
   name: TV-Stue
   code: 213411
   type: motion
   scan_interval: 1
binary_sensor 3:
   platform: rfcac
   name: V. Skab
   code: 31441141
   type: motion
   scan_interval: 1

#433
switch:
  platform: rpi_rf
  gpio: 17
  switches:
   #Udelys
    foran_lys:
      #4a
      code_on: 5522769
      code_off: 5522772
    have_lys:
      #4b
      code_on: 5525841
      code_off: 5525844
    garage_lys:
      #4c
      code_on: 5526609
      code_off: 5526612
   #Underlys
    toilet_lys:
      #3a
      code_on: 5326161
      code_off: 5326164
    gang_lys:
      #3b
      code_on: 5329233
      code_off: 5329236

#IP Camera's (https://home-assistant.io/components/camera/)
camera 1:
  - platform: generic
    still_image_url: http://192.168.2.245:8001/snapshot?rand=1481214732238
    name: Foran
    username:
    password:
camera 2:
  - platform: generic
    still_image_url: http://192.168.2.246:8001/snapshot?rand=1481214732238
    name: Garage
    username:
    password:
#Traffic
#camera 3:
#  - platform: generic
#    still_image_url: https://www.google.dk/maps/@55.8488738,9.8445633,10z/data=!5m1!1e1
#Alarm (https://home-assistant.io/components/alarm_control_panel.manual/)
alarm_control_panel:
  platform: manual
  name: Alle
  code:
  disarm_after_trigger: false
  pending_time: 10
  trigger_time: 3600
automation:
  alias: All alarms
  hide_entity: True
  trigger:
    platform: state
    entity_id: binary_sensor.tvstue, binary_sensor.kokken, binary_sensor.rcph_skab
    state: 'on'
  condition:
    condition: or
    conditions:
      - condition: state
        entity_id: alarm_control_panel.alle
        state: 'armed_home'
      - condition: state
        entity_id: alarm_control_panel.alle
        state: 'armed_away'
  action:
    - service: alarm_control_panel.alarm_trigger
      entity_id: alarm_control_panel.alle
#    - service: notify.instapush
#      data:
#        message: "Alarm"
automation 2:
  alias: Alarm notify
  hide_entity: True
  trigger:
    platform: state
    entity_id: alarm_control_panel.alle
  action:
   - service: notify.instapush2
     data:
       message: "Alarm state changed: {{ states.alarm_control_panel.alle.state }}"
notify 1:
  - name: instapush
    platform: instapush
    api_key:
    app_secret:
    event: zoneTriggered
    tracker: zone
notify 2:
  - name: instapush2
    platform: instapush
    api_key:
    app_secret:
    event: msg
    tracker: msg

Troubleshooting

If you intend to use the netdisco module, you'll also need to install gcc. If you forget to install it, the hass-log will show this:
INFO:homeassistant.util.package:Attempting install of netdisco==0.8.1
Command "/usr/bin/python -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-jm9r4b2z/netifaces/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-qtnuyhoe-record/install-record.txt --single-version-externally-managed --compile --home=/tmp/tmpgirlvw2j" failed with error code 1 in /tmp/pip-build-jm9r4b2z/netifaces/

Install gcc:
pacman -S gcc


Secure your communication with HA using SSL

Update 2016-02-20: I can no longer recommend using StartCom SSL certificates, as they are no longer trusted in Chrome (as of version 56) nor in Mozilla and possible others.

(using StartCom's StartSSL - free personal SSL certificate)

While it's important (at least for me) to be able to reach my control panel from outside out home), it's equally important that it's secure (it is after all also our alarm system).

Now, HA does have a guide to setup ssl using Let's encrypt, but the certificates are only valid for 90 days, and I've always used StartCom StartSSL, so here's how to use it (these certificates are valid for 3 years, and free for personal use).

Go to startssl.com, and either login or create an account.
Follow the steps to create a class 1 DV certificate.
Since I'm using linux, I used openssl to generate mine (using the command specified by StartSSL's instructions), and just pasted the content of my "yourname.csr" into their webpage.

After generating the certificate, place the private key file (yourname.key) on the raspberry pi along side the 1__bundle.crt file from the NginxServer.zip file form the downloaded certificate file package from StartSSL:

Here how my config looks:
http:
  # Uncomment this to add a password (recommended!)
   api_password:
   ssl_certificate: /hass/ssl/StartCom_ssl_2016-12-22/2_urup.net_bundle.crt
   ssl_key: /hass/ssl/StartCom_ssl_2016-12-22/yourname.key


Okay, so that should be it. Now you can access you installation securely from https://:8123

Remember to specify https, and not just http.


Note - decrypt the private key:
If you private key is encrypted and requires a passphrase, you'll either need to decrypt to, or start HA manually, so you can enter the passphrase when HA starts.

Here's how to remove the passphrase:
cd /hass/ssl/StartCom_ssl_2016-12-22/
openssl rsa -in yourname.key -out privatekey_decrypted.key

And then in the configuration.yaml file, we should use the now decrypted key:
http:
  # Uncomment this to add a password (recommended!)
   api_password:
   ssl_certificate: /hass/ssl/StartCom_ssl_2016-12-22/2_urup.net.crt
   ssl_key: /hass/ssl/StartCom_ssl_2016-12-22/privatekey_decrypted.key

Note 2 - certificates:
The zip file you download from StartSSL contains several other zip files:
ApacheServer.zip, IISServer.zip, NginxServer.zip and OtherServer.zip.
It would be nice if the included a little readme about whats in these, but they don't, so here's the short version:
I first tried to use the certificate from ApacheServer/2_urup.net.crt.
This actually worked just fine on my laptop (running chrome 54), but when accessing the page form my phone (running android 6.0), it complained "Server certificate not trusted".
A bit of googling and I found out that chrome on pc will automatically build the certificate chain, while chrome on android will not.
The whole problem is that while android trusts StartCom as a root CA, the certificate we're getting is issued by StartSSL DV1 (which is issued by the trusted root CA).

On Chrome/linux it will automatically go up the chain, and try to validate all issuers until it find a trusted CA.

On chrome/android it will not!
We thus need a certificate that also contains the parent certificates until it's trusted by android.

In my case this means I need to include StartSSL DV1.
Luckily this is already included in the downloaded file from StartSSL, and it's the one file thats in NginxServer.zip.

Just on a little side note for Apache users, I read that Apache deprecated the
"SSLCertificateChainFile" in version 2.4.8, so you'll also need to use the full certificate from now on.

Update 2016-02-20: I can no longer recommend using StartCom SSL certificates, as they are no longer trusted in Chrome (as of version 56) nor in Mozilla and possible others.

Conclusion

If you've followed this guide you should now have a running, secure setup, where you can send and receive 433 codes to control power switches.

This post got way longer than anticipated, so setting up and connecting the smoke detectors and other sensors will come in another post.

If you have any questions or comments, please feel free to comment.

In the next part I'm also talk a bit about 433 security (and jamming), which is a problem for any wireless system.