Controlling roller shutters using a Shelly 2.5, ESPHome and Home Assistant

Our house has roller shutters on all windows and most of them have an electric motor to open and close them. The motors are Schellenberg shaft motors (not sure this is the right English term), that you can configure end positions for and then by applying current to the right pair of pins they move the shutters up and down until the current is removed or one of the endstops is reached. As the motors were installed over a long period of time, the attached control units varied in functionality: different ways to program open/close times, with and without battery for the clock/settings etc, but they all had something in common: no central management and pretty ugly. We decided to replace those control units with regular 2 gang light switches that match the other switches in the house. And as we didn't want to lose the automatic open/close timer, we had to add some smarts to it.

Shelly 2.5 and ESPHome

Say hello to Shelly 2.5! The Shelly 2.5 is an ESP8266 with two relays attached to it in a super tiny package you can hide in the wall behind a regular switch. Pretty nifty. It originally comes with a Mongoose OS based firmware and an own app, but ain't nobody needs that, especially nobody who wants to implement some crude logic. That said, the original firmware isn't bad. It has a no-cloud mode, a REST API and does support MQTT for integration into Home Assistant and others.

My ESP firmware of choice is ESPHome, which you can flash easily onto a Shelly (no matter 1, 2 or 2.5) using a USB TTL adapter that provides 3.3V. Home Assistant has native ESPHome support with auto-discovery, which is much nicer than manually attaching things to MQTT topics.

To get ESPHome compiled for the Shelly 2.5, we'll need a basic configuration like this:

esphome:
  name: shelly25
  platform: ESP8266
  board: modwifi
  arduino_version: 2.4.2

We're using board: modwifi as the Shelly 2.5 (and all other Shellys) has 2MB flash and the usually recommended esp01_1m would only use 1MB of that - otherwise the configurations are identical (see the PlatformIO entries for modwifi and esp01_1m). And arduino_version: 2.4.2 is what the Internet suggests is the most stable SDK version, and who will argue with the Internet?!

Now an ESP8266 without network connection is boring, so we add a WiFi configuration:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  power_save_mode: none

The !secret commands load the named variables from secrets.yaml. While testing, I found the network connection of the Shelly very unreliable, especially when placed inside the wall and thus having rather bad bad reception (-75dBm according to ESPHome). However, setting power_save_mode: none explicitly seems to have fixed this, even if NONE is supposed to be the default on ESP8266.

At this point the Shelly has a working firmware and WiFi, but does not expose any of its features: no switches, no relays, no power meters.

To fix that we first need to find out the GPIO pins all these are connected to. Thankfully we can basically copy paste the definition from the Tasmota (another open-source firmware for ESPs) template:

pin_led1: GPIO0
pin_button1: GPIO2
pin_relay1: GPIO4
pin_switch2n: GPIO5
pin_sda: GPIO12
pin_switch1n: GPIO13
pin_scl: GPIO14
pin_relay2: GPIO15
pin_ade7953: GPIO16
pin_temp: A0

If we place that into the substitutions section of the ESPHome config, we can use the names everywhere and don't have to remember the pin numbers.

The configuration for the ADE7953 power sensor and the NTC temperature sensor are taken verbatim from the ESPHome documentation, so there is no need to repeat them here.

The configuration for the switches and relays are also rather straight forward:

binary_sensor:
  - platform: gpio
    pin: ${pin_switch1n}
    name: "Switch #1"
    internal: true
    id: switch1

  - platform: gpio
    pin: ${pin_switch2n}
    name: "Switch #2"
    internal: true
    id: switch2

switch:
  - platform: gpio
    pin: ${pin_relay1}
    name: "Relay #1"
    internal: true
    id: relay1
    interlock: &interlock_group [relay1, relay2]

  - platform: gpio
    pin: ${pin_relay2}
    name: "Relay #2"
    internal: true
    id: relay2
    interlock: *interlock_group

All marked as internal: true, as we don't need them visible in Home Assistant.

ESPHome and Schellenberg roller shutters

Now that we have a working Shelly 2.5 with ESPHome, how do we control Schellenberg (and other) roller shutters with it?

Well, first of all we need to connect the Up and Down wires of the shutter motor to the two relays of the Shelly. And if they would not be marked as internal: true, they would show up in Home Assistant and we would be able to flip them on and off, moving the shutters. But this would also mean that we need to flip them off each time after use, as while the motor knows when to stop and will do so, applying current to both wires at the same time produces rather interesting results. So instead of fiddling around with the relays directly, we define a time-based cover in our configuration:

cover:
  - platform: time_based
    name: "${location} Rolladen"
    id: rolladen

    open_action:
      - switch.turn_on: relay2
    open_duration: ${open_duration}

    close_action:
      - switch.turn_on: relay1
    close_duration: ${close_duration}

    stop_action:
      - switch.turn_off: relay1
      - switch.turn_off: relay2

We use a time-based cover because that's the easiest thing that will also turn the relays off for us after the shutters have been opened/closed, as the motor does not "report" any state back. We could use the integrated power meter of the Shelly to turn off when the load falls under a threshold, but I was too lazy and this works just fine as it is.

Next, let's add the physical switches to it. We could just add on_press automations to the binary GPIO sensors we configured for the two switch inputs the Shelly has. But if you have kids at home, you'll know that they like to press ALL THE THINGS and what could be better than a small kill-switch against small fingers?

switch:
  [ previous definitions go here ]

  - platform: template
    id: block_control
    name: "${location} Block Control"
    optimistic: true

  - platform: template
    name: "Move UP"
    internal: true
    lambda: |-
      if (id(switch1).state && !id(block_control).state) {
        return true;
      } else {
        return false;
      }
    on_turn_on:
      then:
        cover.open: rolladen
    on_turn_off:
      then:
        cover.stop: rolladen

  - platform: template
    name: "Move DOWN"
    internal: true
    lambda: |-
      if (id(switch2).state && !id(block_control).state) {
        return true;
      } else {
        return false;
      }
    on_turn_on:
      then:
        cover.close: rolladen
    on_turn_off:
      then:
        cover.stop: rolladen

This adds three more template switches. The first one, "Block Control", is exposed to Home Assistant, has no lambda definition and is set to optimistic: true, which makes is basically a dumb switch that can be flipped at will and the only thing it does is storing the binary on/off state. The two others are almost identical. The name differs, obviously, and so does the on_turn_on automation (one triggers the cover to open, the other to close). And the really interesting part is the lambda that monitors one of the physical switches and if that is turned on, plus "Block Control" is off, reports the switch as turned on, thus triggering the automation. With this we can now block the physical switches via Home Assistant, while still being able to control the shutters via the same.

All this (and a bit more) can be found in my esphome-configs repository on GitHub, enjoy!

Not-So-Self-Hosting

I planned to write about this for quite some time now (last time end of April), and now, thanks to the GitHub acquisition by Microsoft and all that #movingtogitlab traffic, I am finally sitting here and writing these lines.

This post is not about Microsoft, GitHub or GitLab, and it's neither about any other SaaS solution out there, the named companies and products are just examples. It's more about "do you really want to self-host?"

Every time a big company acquires, shuts down or changes an online service (SaaS - Software as a Service), you hear people say "told you so, you should better have self-hosted from the beginning". And while I do run quite a lot of own infrastructure, I think this statement is too general and does not work well for many users out there.

Software as a Service

There are many code-hosting SaaS offerings: GitHub (proprietary), GitLab (open core), Pagure (FOSS) to name just a few. And while their licenses, ToS, implementations and backgrounds differ, they have a few things in common.

Benefits:

  • (sort of) centralized service
  • free (as in beer) tier available
  • high number of users (and potential collaborators)
  • high number of hosted projects
  • good (fsvo "good") connection from around the globe
  • no maintenance required from the users

Limitations:

  • dependency on the interest/goodwill of the owner to continue the service
  • some features might require signing up for a paid tier

Overall, SaaS is handy if you're lazy, just want to get the job done and benefit from others being able to easily contribute to your code.

Hosted Solutions

All of the above mentioned services also offer a hosted solution: GitHub Enterprise, GitLab CE and EE, Pagure.

As those are software packages you can install essentially everywhere, you can host the service "in your basement", in the cloud or in any data center you have hardware or VMs running.

However, with self-hosting, the above list of common things shifts quite a bit.

Benefits:

  • the service is configured and secured exactly like you need it
  • the data remains inside your network/security perimeter if you want it

Limitations:

  • requires users to create an own account on your instance for collaboration
  • probably low number of users (and potential collaborators)
  • connection depends on your hosting connection
  • infrastructure (hardware, VM, OS, software) requires regular maintenance
  • dependency on your (free) time to keep the service running
  • dependency on your provider (network/hardware/VM/cloud)

I think especially the first and last points are very important here.

First, many contributions happen because someone sees something small and wants to improve it, be it a typo in the documentation, a formatting error in the manpage or a trivial improvement of the code. But these contributions only happen when the complexity to submit it is low. Nobody not already involved in OpenStack would submit a typo-fix to their Gerrit which needs a Launchpad account… A small web-edit on GitHub or GitLab on the other hand is quickly done, because "everybody" has an account anyways.

Second, while it is called "self-hosting", in most cases it's more of a "self-running" or "self-maintaining" as most people/companies don't own the whole infrastructure stack.

Let's take this website as an example (even though it does not host any Git repositories): the webserver runs in a container (LXC) on a VM I rent from netcup. In the past, netcup used to get their infrastructure from Hetzner - however I am not sure that this is still the case. So worst case, the hosting of this website depends on me maintaining the container and the container host, netcup maintaining the virtualization infrastructure and Hetzner maintaining the actual data center. This also implies that I have to trust those companies and their suppliers as I only "own" the VM upwards, not the underlying infrastructure and not the supporting infrastructure (network etc).

SaaS vs Hosted

There is no silver bullet to that. One important question is "how much time/effort can you afford?" and another "which security/usability constraints do you have?".

Hosted for a dedicated group

If you need a solution for a dedicated group (your work, a big FOSS project like Debian or a social group like riseup), a hosted solution seems like a good idea. Just ensure that you have enough infrastructure and people to maintain it as a 24x7 service or at least close to that, for a long time, as people will depend on your service.

The same also applies if you need/want to host your code inside your network/security perimeter.

Hosted for an individual

Contrary to a group, I don't think a hosted solution makes sense for an individual most of the time. The burden of maintenance quite often outweighs the benefits, especially as you'll have to keep track of (security) updates for the software and the underlying OS as otherwise the "I own my data" benefit becomes "everyone owns me" quite quickly. You also have to pay for the infrastructure, even if the OS and the software are FOSS.

You're also probably missing out on potential contributors, which might have an account on the common SaaS platforms, but won't submit a pull-request for a small change if they have to register on your individual instance.

SaaS for a dedicated group

If you don't want to maintain an own setup (resources/costs), you can also use a SaaS platform for a group. Some SaaS vendors will charge you for some features (they have to pay their staff and bills too!), but it's probably still cheaper than having the right people in-house unless you have them anyways.

You also benefit from a networking effect, as other users of the same SaaS platform can contribute to your projects "at no cost".

Saas for an individual

For an individual, a SaaS solution is probably the best fit as it's free (as in beer) in the most cases and allows the user to do what they intend to do, instead of shaving yaks and stacking turtles (aka maintaining infrastructure instead of coding).

And you again get the networking effect of the drive-by contributors who would not sign up for a quick fix.

Selecting the right SaaS

When looking for a SaaS solution, try to answer the following questions:

  • Do you trust the service to be present next year? In ten years? Is there a sustainable business model?
  • Do you trust the service with your data?
  • Can you move between SaaS and hosted easily?
  • Can you move to a different SaaS (or hosted solution) easily?
  • Does it offer all the features and integrations you want/need?
  • Can you leverage the network effect of being on the same platform as others?

Selecting the right hosted solution

And answer these when looking for a hosted one:

  • Do you trust the vendor to ship updates next year? In ten years?
  • Do you understand the involved software stack and willing to debug it when things go south?
  • Can you get additional support from the vendor (for money)?
  • Does it offer all the features and integrations you want/need?

So, do you really want to self-host?

I can't speak for you, but for my part, I don't want to run a full-blown Git hosting just for my projects, GitHub is just fine for that. And yes, GitLab would be equally good, but there is little reason to move at the moment.

And yes, I do run my own Nextcloud instance, mostly because I don't want to backup the pictures from my phone to "a cloud". YMMV.

starting the correct Chromium profile when opening links from IRC

I am using Chromium/Chrome as my main browser and I also use its profile/people feature to separate my work profile (bookmarks, cookies, etc) from my private one.

However, Chromium always opens links in the last window (and by that profile) that was in foreground last. And that is pretty much not what I want. Especially if I open a link from IRC and it might lead to some shady rick-roll page.

Thankfully, getting the list of available Chromium profiles is pretty easy and so is displaying a few buttons using Python.

To do so I wrote cadmium, which scans the available Chromium profiles and allows to start either of them, or Chromium's Incognito Mode. On machines with SELinux it can even launch Chromium in the SELinux sandbox.

No more links opened in the wrong profile. Yay!

Breaking glass, OnePlus service and Android backups

While visiting our Raleigh office, I managed to crack the glass on the screen of my OnePlus 3. Luckily it was a clean crack from the left upper corner, to the right lower one. The crack was not really interfering with neither touch nor display, so I had not much pressure in fixing it.

eBay lists new LCD sets for 110-130€, and those still require manual work of getting the LCD assembly out of the case, replacing it, etc. There are also glass-only sets for ~20€, but these require the complete removal of the glued glass part from the screen, and reattaching it, nothing you want to do at home. But there is also still the vendor, who can fix it, right? Internet suggested they would do it for about 100€, which seemed fair.

As people have been asking about the support experience, here is a quick write up what happened:

  • Opened the RMA request online on Sunday, providing a brief description of the issue and some photos

  • Monday morning answer from the support team, confirming this is way out of warranty, but I can get the device fixed for about 93€

  • After confirming that the extra cost is expected, I had an UPS sticker to ship the device to CTDI in Poland

  • UPS even tried a pick-up on Tuesday, but I was not properly prepared, so I dropped the device later at a local UPS point

  • It arrived in Poland on Wednesday

  • On Thursday the device was inspected, pictures made etc

  • Friday morning I had a quote in my inbox, asking me to pay 105€ - the service partner decided to replace the front camera too, which was not part of the original 93€ approximation.

  • Paid the money with my credit card and started waiting.

  • The actual repair happened on Monday.

  • Quality controlled on Tuesday.

  • Shipped to me on Wednesday.

  • Arrived at my door on Thursday.

All in all 9 working days, which is not great, but good enough IMHO. And the repair is good, and it was not (too) expensive. So I am a happy user of an OnePlus 3 again.

Well, almost. Before sending the device for repairs, had to take a backup and wipe it. I would not send it with my, even encrypted, data on it. And backups and Android is something special.

Android will backup certain data to Google, if you allow it to. Apps can forbid that. Sadly this also blocks non-cloud backups with adb backup. So to properly backup your system, you either need root or you create a full backup of the system in the recovery and restore that.

I did the backup using TWRP, transferred it to my laptop, wiped the device, sent it in, got it back, copied the backup to the phone, restored it and... Was locked out of the device, it would not take my password anymore. Well, it seems that happens, just delete some files and it will be fine.

It's 2017, are backups of mobile devices really supposed to be that hard?!