From 402b1e6a024de5c9a2d13ffe93d14463a3d4845e Mon Sep 17 00:00:00 2001 From: William Floyd Date: Thu, 22 Apr 2021 01:18:12 -0500 Subject: [PATCH] home-automation: Add at school post. --- .../posts/home-automation-at-school/index.md | 320 ++++++++++++++++++ .../media/20200813_023018.jpg | 3 + .../home-automation-at-school/media/src/.env | 0 .../media/src/20200813_023018.jpg | 3 + .../media/src/20200813_023018.jpg.hash | 1 + 5 files changed, 327 insertions(+) create mode 100644 content/posts/home-automation-at-school/index.md create mode 100644 content/posts/home-automation-at-school/media/20200813_023018.jpg create mode 100644 content/posts/home-automation-at-school/media/src/.env create mode 100644 content/posts/home-automation-at-school/media/src/20200813_023018.jpg create mode 100644 content/posts/home-automation-at-school/media/src/20200813_023018.jpg.hash diff --git a/content/posts/home-automation-at-school/index.md b/content/posts/home-automation-at-school/index.md new file mode 100644 index 0000000..897ce2e --- /dev/null +++ b/content/posts/home-automation-at-school/index.md @@ -0,0 +1,320 @@ +--- +title: "Home Automation at School" +date: "2021-04-21" +author: "William Floyd" +featured_image: "media/20200813_023018.jpg" +categories: [ + "Software" +] +tags: [ + "School", + "Home Assistant", + "Home Automation", + "ESPHome", + "IOT" +] +--- + +I love home automation - I've spent far longer writing automation routines and hacking together my own devices and programs than I have ever saved by doing so, and that's perfectly fine. +One unique aspect of my setup, however, is that I cannot control the network I must use - in my Uni dorm, I am not allowed to run my own router, and so all IoT devices must connect to the school wireless network. +There abound dozens of Google Home devices, Chromecasts, and so on, all accessible on the same network - but not from the wired connection that my server/desktop uses. + +Here then is my solution: MQTT everything I can. +From my lights, so light sensor, to coffee maker to desktop software, I bounce it through a MQTT server hosted on a VPS. +I use Home Assistant, so automatic discovery is easy on most things, especially ESPHome. +In fact, I disabled direct Home Assistant connectivity entirely on these devices, which works well enough for me to live with. + +# But how to flash? + +Given that my Home Assistant instance isn't even on the same network as the IoT devices, how do I update the firmware? +Using my laptop, I can connect to the wireless network that they reside on, and using IP address sensors reported by these devices, flash them directly without needing local discovery. +In fact, I can easily automate this for myself using a couple scripts and a minimal number of hard-coded values: + +`hassio.sh` +``` +#!/bin/bash + +export HASS_SERVER=https://:443 +export HASS_TOKEN='' + +hass-cli ${@} + +exit + +``` + +`lamps.sh` +``` +#!/bin/bash + +declare -A aa + +aa["gosund_lb1_1.yaml"]="sensor.desk_lamp_ip_address" +aa["gosund_lb1_2.yaml"]="sensor.bed_lamp_ip_address" +aa["gosund_lb1_3.yaml"]="sensor.floor_lamp_girlfriend_ip_address" +aa["gosund_lb1_4.yaml"]="sensor.desk_lamp_girlfriend_ip_address" +aa["gosund_lb1_5.yaml"]="sensor.floor_lamp_ip_address" + +__flash() { + + __config="${1}" + __entity_name="${aa[${__config}]}" + echo "Getting ${__config} IP..." + + __ip="$( + ./hassio.sh -o yaml state get \ + "${__entity_name}" | + grep -E '^ *state' | sed -e 's/.* //' + )" + + echo "IP: ${__ip}" + + if [ "${__ip}" == 'unavailable' ]; then + echo 'Ignoring...' + else + echo "Flashing..." + ./esphome.sh "${__config}" run --upload-port="${__ip}" + fi + + echo + +} + +if [ "${#}" -gt 0 ]; then + until [ "${#}" == 0 ]; do + __flash "${1}" + shift + done +else + for __config in ${!aa[@]}; do + __flash "${__config}" + done +fi + +exit +``` + +this allows me to mostly painlessly flash my devices, though truth be told there is little need. + +# Custom software + +I developed for myself a tool in Golang to help tie more of my devices together. +It is rather uncreatively/cryptically named `ha-mqtt-iot` - that is, "Home Assistant MQTT Internet of Things". +I may rename this some day, but why bother. +It is similar to IOTLink (which is Windows only), and HASS Workstation Service - they are great projects, but this one is mine, even if it is poorly written. + +The gist of the software is that most (all?) device types supported by Home Assistant may be implemented using a selection of user defined commands. +The most prominent examples in my case are in order to enable/disable dark mode on my desktop. +I automate this according to ambient light in my room, to better match the aesthetic I want. +Additionally, I can use it to turn my desktop monitor off, without resorting to using a relay outlet, and even change the color temperature of my system. +The script I use for this looks like the following: + +``` +#!/bin/bash + +__monitor_i2c='dev:/dev/i2c-3' +__monitor_dpms='0xd6' +__monitor_brightness='0x10' +__monitor_standby='4' +__monitor_off='5' +__monitor_on='1' + +__unknown() { + echo "Unknown ${1}" +} + +f2i() { + awk 'BEGIN{for (i=1; i/dev/null -r "${__monitor_brightness}" "${__monitor_i2c}" | tail -n 1 | grep -o '/[0-9]*/100' | sed -e 's|^/||' -e 's|/.*||')" + ;; + +*) + __unknown "root command ${com}" + ;; +esac + +exit +``` + +Note that the display doesn't respond to being turned back on, so this is somewhat incomplete, but it's good enough for my needs. +The corresponding portion of the config for `ha-mqtt-iot` looks like the following: + +``` + "lights": [ + { + "info": { + "name": "Desktop Monitor", + "id": "monitor" + }, + "command": [ + "./scripts/monitor.sh", + "command" + ], + "command_state": [ + "./scripts/monitor.sh", + "command-state" + ], + "command_color_temp": [ + "./scripts/monitor.sh", + "color-temp" + ], + "command_color_temp_state": [ + "./scripts/monitor.sh", + "color-temp-state" + ], + "command_brightness": [ + "./scripts/monitor.sh", + "brightness" + ], + "command_brightness_state": [ + "./scripts/monitor.sh", + "brightness-state" + ], + "brightness_scale": 100, + "update_interval": 5 + } + ] +``` + +Pretty simple. +This makes custom system sensors trivial. +For example, to show my system IP, I use the following: + +``` + "sensors": [ + { + "info": { + "name": "IP Address Desktop Solus", + "id": "ip-address-desktop-solus", + "icon": "mdi:ip-network" + }, + "command_state": [ + "/bin/bash", + "-c", + "ip -j address show eno1 | jq -r '.[0].addr_info[0].local'" + ], + "update_interval": 10 + } + ] +``` + +Some common use cases are built in as well. +Currently, this includes laptop displays (as lights) and batteries (as sensors), as well as Crypto prices (though the CoinGecko Golang library). +These are really easy to call. +An exhaustive example is quite short: + +``` + "builtin": { + "prefix": "Name Prefix ", + "backlight": { + "enable": true, + "temperature": false, + "range": { + "minimum": 0.025, + "maximum": 0.95 + } + }, + "battery": { + "enable": true + }, + "crypto": [ + { + "coin_name": "dogecoin", + "currency_name": "usd", + "update_interval": 1, + "icon": "mdi:currency-usd" + } + ] + } +``` + +This lets me tailor my setup to each machine I'm using, while still enjoying the benefits of Home Assistant MQTT Discovery. +The primary limitation at present is the inability to signal to `ha-mqtt-iot` from another process - it can only poll for changes. +This will be addressed one day, when it is important for my own needs. + +# How to host? + +But the question is now, how do I access my HomeAssistant instance if it's also hosted at school? +I most certainly don't have a public IP, so in comes AutoSSH. +I'm not sure which is the best one at this stage, but refer to [this](https://github.com/psallandre/hassio-addons-autossh) repo and check the various forks of the parent project. + +I have configured on my VPS a docker image that accepts reverse SSH tunnelling, authorized only to the key of the HA addon. +From my `docker-compose.yml`: + +``` + homeassistant: + image: "docker.io/panubo/sshd" + container_name: homeassistant + environment: + - TCP_FORWARDING=true + - GATEWAY_PORTS=true + - SSH_ENABLE_ROOT=true + - DISABLE_SFTP=true + volumes: + - "./hassio/authorized_keys:/root/.ssh/authorized_keys:ro" + - ./docker-config/hassio/data/:/data + - ./docker-config/hassio/keys/:/etc/ssh/keys + ports: + - ":22" + restart: unless-stopped + hostname: "homeassistant" +``` + +This is then reverse proxied to using Caddy, to expose the website on a subdomain of a website. +From my `Caddyfile`: + +``` +.{$MY_DOMAIN} { + reverse_proxy homeassistant:8123 + encode gzip +} +``` + +Pretty simple, but not without some hiccups now and again - I occasionally have to restart the sshd docker on my VPS if something goes wrong with HomeAssistant. + +# Bonus: Android tie in + +I use Sleep As Android to track my sleeping patterns, and as my alarm clock. +Using Tasker, I can run an action when I begin sleep tracking, which (using a HomeAssistant plugin for Tasker) can call a script on my HomeAssistant instance to turn off my lights (only if I'm home, of course). +Similarly, it turns on my bedhead light when my alarm goes off in the morning, and could optionally make me coffee... \ No newline at end of file diff --git a/content/posts/home-automation-at-school/media/20200813_023018.jpg b/content/posts/home-automation-at-school/media/20200813_023018.jpg new file mode 100644 index 0000000..5e2df25 --- /dev/null +++ b/content/posts/home-automation-at-school/media/20200813_023018.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc5115c96d70071bc134893b68db5cc99ab25941dac81088337bcdc9f29a4cde +size 120031 diff --git a/content/posts/home-automation-at-school/media/src/.env b/content/posts/home-automation-at-school/media/src/.env new file mode 100644 index 0000000..e69de29 diff --git a/content/posts/home-automation-at-school/media/src/20200813_023018.jpg b/content/posts/home-automation-at-school/media/src/20200813_023018.jpg new file mode 100644 index 0000000..2e9a91d --- /dev/null +++ b/content/posts/home-automation-at-school/media/src/20200813_023018.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:146a5bbeb1bf784d5d05805ae30a9dc77a776cf5ec718b26727b99ace654396d +size 4262649 diff --git a/content/posts/home-automation-at-school/media/src/20200813_023018.jpg.hash b/content/posts/home-automation-at-school/media/src/20200813_023018.jpg.hash new file mode 100644 index 0000000..62ddec2 --- /dev/null +++ b/content/posts/home-automation-at-school/media/src/20200813_023018.jpg.hash @@ -0,0 +1 @@ +53c5b1ff22f195fa815e9202d5c7c804