I used this tutorial to create a local “add on” for a pi-plates relay board (RELAYplate – Pi-Plates).
My solution uses a tiny python web server running in an “add on” container. The piplates
python library is used to drive the relays.
To control the relays from Home Assistant I use rest_command
to send messages to the web server. e.g. In configuration.yaml
I have something like this to implement Window Covers controlled by the relays.
rest_command:
open_sheer:
url: "http://localhost:8492/press/0/1"
close_sheer:
url: "http://localhost:8492/press/0/2"
open_east_curtian:
url: "http://localhost:8492/press/0/3"
close_east_curtian:
url: "http://localhost:8492/press/0/4"
open_north_curtian:
url: "http://localhost:8492/press/0/5"
close_north_curtian:
url: "http://localhost:8492/press/0/6"
cover:
- platform: template
covers:
sheer:
device_class: curtain
unique_id: bedroom.sheer
friendly_name: "Sheer"
open_cover:
service: rest_command.open_sheer
close_cover:
service: rest_command.close_sheer
east_curtian:
device_class: curtain
unique_id: bedroom.east_curtian
friendly_name: "West Curtian"
open_cover:
service: rest_command.open_east_curtian
close_cover:
service: rest_command.close_east_curtian
north_curtian:
device_class: curtain
unique_id: bedroom.north_curtian
friendly_name: "North Curtian"
open_cover:
service: rest_command.open_north_curtian
close_cover:
service: rest_command.close_north_curtian
I ended up with the following files under addons/pi_plates
…
Dockerfile
:
This installs the python pi-plates
library and its dependencies.
ARG BUILD_FROM
FROM $BUILD_FROM
ENV LANG C.UTF-8
RUN apk add --no-cache --virtual .build-deps \
python3-dev \
gcc \
make \
linux-headers \
musl \
musl-dev \
libc-dev \
py3-pip \
&& apk add --no-cache \
py3-six \
python3 \
&& pip install wheel \
&& CFLAGS="-fcommon" pip install RPi.GPIO \
&& CFLAGS="-fcommon" pip install spidev \
&& pip install pi-plates \
&& apk del .build-deps
COPY relay_server.py http_server.py /
COPY run.sh /
RUN chmod a+x /run.sh
CMD [ "/run.sh" ]
config.json
This tells Home Assistant to open TCP port 8492 and enable access to the SPI and GPIO hardware devices.
{
"name": "Pi Plates",
"version": "10",
"slug": "pi_plates",
"description": "Interace with Relay Boards from pi-plates.com",
"arch": ["aarch64"],
"startup": "application",
"boot": "auto",
"options": {},
"schema": {},
"ports": {
"8492/tcp": 8492
},
"devices": ["/dev/spidev0.1", "/dev/gpiomem"]
}
run.sh
:
This starts two python servers, one to control the relay board and one to communicate with Home Assistant via HTTP.
#!/usr/bin/with-contenv bashio
/relay_server.py &
/http_server.py
relay_server.py
:
This server waits for commands to be written to /var/run/relay_server
then calls the piplates relayOFF()
and relayON()
functions
#!/usr/bin/python3
import piplates.RELAYplate as RELAY
import sys
import os
import errno
import time
FIFO = "/var/run/relay_server"
try:
os.mkfifo(FIFO)
except OSError as oe:
if oe.errno != errno.EEXIST:
raise
os.chmod(FIFO, 0o0666)
RELAY.relayALL(0, 0)
RELAY.relayALL(1, 0)
print("FIFO Server on /var/run/relay_server")
while True:
with open(FIFO) as fifo:
while True:
data = fifo.readline()
print(data)
if len(data) == 0:
break
f, a, b = data.rstrip().split(",")
a = int(a)
b = int(b)
if f == "press":
RELAY.relayOFF(a, b)
time.sleep(0.1)
RELAY.relayON(a, b)
time.sleep(0.2)
RELAY.relayOFF(a, b)
else:
getattr(RELAY, f)(a, b)
http_server.py
:
This server listens for HTTP requests and writes commands to /var/run/relay_server
.
#!/usr/bin/python3
from http.server import BaseHTTPRequestHandler, HTTPServer
class RelayServer(BaseHTTPRequestHandler):
def do_GET(self):
x, a, b, c = self.path.split("/")
with open('/var/run/relay_server', 'w') as f:
f.write(a + ',' + b + ',' + c + '\n')
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write("ok".encode("utf8"))
print("HTTP Server listening on port 8492")
HTTPServer(("0.0.0.0", 8492), RelayServer).serve_forever()
The following two scripts were useful for building and running the docker image outside Home Assistant for debugging.
build.sh
:
#!/bin/bash
docker build \
--build-arg BUILD_FROM="homeassistant/aarch64-base:latest" \
-t local/pi_plates .
debug.sh
:
#!/bin/bash
docker run --rm \
-p 8492:8492 \
--device /dev/spidev0.1:/dev/spidev0.1 \
--device /dev/gpiomem:/dev/gpiomem \
-it local/pi_plates \
/bin/bash