deconz: Refactor (#1476)

* deconz: Refactor

* Disable shellcheck warning

* Fix wiringpi

* Bump version 6.0.0

* fix osram ota

* Revert file & update changelog

* Small bugfixes

* Exclude

Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>
This commit is contained in:
Franck Nijhof
2020-07-20 14:01:25 +02:00
committed by GitHub
parent 014774af6f
commit d0a50b9750
25 changed files with 302 additions and 224 deletions

View File

@@ -1,5 +1,14 @@
# Changelog
## 6.0.0
- Use debian buster for all arch types
- Migrate to new S6-Overlay
- Fix LEDVANCE / OSRAM otau firmware downloader
- Bump deCONZ to 2.05.79
- New deCONZ firmware management on startup
- Exclude OTAU folder from snapshot
## 5.3.6
- Bump deCONZ to 2.05.78

View File

@@ -34,9 +34,9 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/* \
&& if [ "${BUILD_ARCH}" = "armhf" ]; \
then \
curl -q -L -o /wiringpi.deb https://project-downloads.drogon.net/wiringpi-latest.deb \
&& dpkg -i /wiringpi.deb \
&& rm -rf /wiringpi.deb; \
curl -q -L -o /tmp/wiringpi.deb https://project-downloads.drogon.net/wiringpi-latest.deb \
&& dpkg --force-architecture -i /tmp/wiringpi.deb \
&& rm -rf /tmp/wiringpi.deb; \
fi
# Install deCONZ
@@ -55,9 +55,4 @@ RUN if [ "${BUILD_ARCH}" = "armhf" ]; \
&& chown root:root /usr/bin/deCONZ* \
&& sed -i 's/\/root/\/data/' /etc/passwd
COPY data/ika-otau-dl.sh /bin/
COPY data/ledvance-otau-dl.sh /bin/
COPY data/nginx.conf /etc/nginx/nginx.conf
COPY data/run.sh data/discovery.sh /
CMD ["/run.sh"]
COPY rootfs /

View File

@@ -1,10 +1,10 @@
{
"build_from": {
"aarch64": "homeassistant/aarch64-base-debian:stretch",
"amd64": "homeassistant/amd64-base-ubuntu:18.04",
"armhf": "homeassistant/armhf-base-raspbian:stretch"
"aarch64": "homeassistant/aarch64-base-debian:buster",
"amd64": "homeassistant/amd64-base-debian:buster",
"armhf": "homeassistant/armhf-base-debian:buster"
},
"args": {
"DECONZ_VERSION": "2.05.78"
"DECONZ_VERSION": "2.05.79"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "deCONZ",
"version": "5.3.6",
"version": "6.0.0",
"slug": "deconz",
"description": "Control a Zigbee network with ConBee or RaspBee by Dresden Elektronik",
"arch": ["amd64", "armhf", "aarch64"],
@@ -29,6 +29,9 @@
"apparmor": false,
"privileged": ["SYS_MODULE", "SYS_RAWIO"],
"devices": ["/dev/bus/usb:/dev/bus/usb:rwm", "/dev/mem:/dev/mem:rw"],
"snapshot_exclude": [
"/data/otau/*"
],
"options": {
"device": null,
"vnc_password": ""

View File

@@ -1,68 +0,0 @@
#!/usr/bin/env bashio
DATA_STORE="/data/.local/share/dresden-elektronik/deCONZ/zll.db"
function hassio_discovery() {
local api_key
local config
local query
local retries
local serial
# Remove old discovery data storage (cleanup)
# We now query the deCONZ database for it directly.
if bashio::fs.file_exists /data/hassio.json; then
rm /data/hassio.json
fi
# Try to get API key from deCONZ database
query='SELECT apikey FROM auth WHERE devicetype="Home Assistant" ORDER BY createdate DESC LIMIT 1'
api_key=$(sqlite3 "${DATA_STORE}" "${query}" .exit)
if ! bashio::var.has_value "${api_key}"; then
# Register an API key for Home Assistant
if ! result="$(curl --silent --show-error --request POST -d '{"devicetype": "Home Assistant"}' "http://127.0.0.1:40850/api")";
then
bashio::log.debug "${result}"
bashio::exit.nok "Can't get API key from deCONZ gateway"
fi
api_key="$(bashio::jq "${result}" '.[0].success.username')"
fi
# Try to get the bridge ID/serial, try to avoid using 0000000000000000
retries=25
serial="0000000000000000"
while [[ "${serial}" = "0000000000000000" ]]; do
bashio::log.debug "Waiting for bridge ID..."
sleep 10
# If we tried 25 times, just abort.
if [[ "${retries}" -eq 0 ]]; then
bashio::exit.nok "Failed to get a valid bridge ID. Discovery aborted."
fi
# Get bridge ID from API
if ! result="$(curl --silent --show-error --request GET "http://127.0.0.1:40850/api/${api_key}/config")";
then
bashio::log.debug "${result}"
bashio::exit.nok "Can't get data from deCONZ gateway"
fi
serial="$(bashio::jq "${result}" '.bridgeid')"
((retries--))
done
# Create config payload for Home Assistant
config=$(bashio::var.json \
host "$(bashio::addon.ip_address)" \
port "^40850" \
api_key "${api_key}" \
serial "${serial}" \
)
# Send discovery info
if bashio::discovery "deconz" "${config}" > /dev/null; then
bashio::log.info "Successfully send discovery information to Home Assistant."
else
bashio::log.error "Discovery message to Home Assistant failed!"
fi
}

View File

@@ -1,32 +0,0 @@
#!/bin/bash
URL_IKEA="http://fw.ota.homesmart.ikea.net/feed/version_info.json"
while true
do
# fetch data
if ! IKEA_DATA="$(curl -sL ${URL_IKEA})"; then
echo "[Info] Can't fetch data from ikea!"
sleep 18000
continue
fi
IKEA_DATA_SIZE="$(echo "${IKEA_DATA}" | jq --raw-output '. | length')"
for (( i=0; i < "${IKEA_DATA_SIZE}"; i++ )); do
OTAU_URL=$(echo "${IKEA_DATA}" | jq --raw-output ".[$i].fw_binary_url // empty")
if [ -z "${OTAU_URL}" ]; then
continue
fi
OTAU_FILE="/data/otau/${OTAU_URL##*/}"
if [ -f "${OTAU_FILE}" ]; then
continue
fi
curl -s -L -o "${OTAU_FILE}" "${OTAU_URL}"
done
sleep 259200
done

View File

@@ -1,42 +0,0 @@
#!/bin/bash
URL_OSRAM="https://api.update.ledvance.com/v1/zigbee/firmwares"
while true
do
# fetch data
if ! OSRAM_DATA="$(curl -sL ${URL_OSRAM})"; then
echo "[Info] Can't fetch data from osram!"
sleep 18000
continue
fi
OSRAM_DATA_SIZE="$(echo "${OSRAM_DATA}" | jq --raw-output '.firmwares | length')"
DL_DONE=0
for (( i=0; i < "${OSRAM_DATA_SIZE}"; i++ )); do
OSRAM_COMPANY=$( echo "${OSRAM_DATA}" | jq --raw-output ".firmwares[$i].identity.company // empty" 2>/dev/null)
OSRAM_PRODUCT=$( echo "${OSRAM_DATA}" | jq --raw-output ".firmwares[$i].identity.product // empty" 2>/dev/null)
OTAU_FILENAME=$( echo "${OSRAM_DATA}" | jq --raw-output ".firmwares[$i].name // empty" 2>/dev/null)
OTAU_URL="$URL_OSRAM/download/${OSRAM_COMPANY}/${OSRAM_PRODUCT}/latest"
if [ -z "${OTAU_URL}" ]; then
continue
fi
OTAU_FILE="/data/otau/${OTAU_FILENAME}"
if [ -f "${OTAU_FILE}" ] && [[ $(file --mime-type -b "${OTAU_FILE}") == "application/octet-stream" ]] ; then
continue
fi
curl -s -L -o "${OTAU_FILE}" "${OTAU_URL}"
((DL_DONE++))
if [ "$((DL_DONE % 10))" == "0" ]; then
# LEDVANCE/OSRAM API RateLimits : The rate limit 10 calls per 60 seconds or quota 100 MB per month.
DL_DONE=0
sleep 65
fi
done
sleep 259200
done

View File

@@ -0,0 +1,6 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Manage deCONZ firmware
# ==============================================================================
bashio::log.info "$(/usr/bin/GCFFlasher_internal -l)"

View File

@@ -0,0 +1,6 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Configure NGINX for use with deCONZ
# ==============================================================================
ingress_entry=$(bashio::addon.ingress_entry)
sed -i "s#%%ingress_entry%%#${ingress_entry}#g" /etc/nginx/nginx.conf

View File

@@ -0,0 +1,19 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Configure VNC for use with deCONZ
# ==============================================================================
# Check if VNC is enabled
VNC_PORT="$(bashio::addon.port 5900)"
if ! bashio::var.has_value "${VNC_PORT}"; then
# VNC is not enabled, skip this.
bashio::exit.ok
fi
# Require password when VNC is enabled
if ! bashio::config.has_value 'vnc_password'; then
bashio::exit.nok "VNC has been enabled, but no password has been set!"
fi
VNC_PASSWORD=$(bashio::config 'vnc_password')
echo "${VNC_PASSWORD}" | tigervncpasswd -f > /root/.vncpasswd

View File

@@ -0,0 +1,70 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Send deCONZ discovery information to Home Assistant
# ==============================================================================
readonly DATA_STORE="/data/.local/share/dresden-elektronik/deCONZ/zll.db"
declare api_key
declare config
declare query
declare retries
declare serial
# Wait for deCONZ to start before continuing
bashio::net.wait_for 40850
# Remove old discovery data storage (cleanup)
# We now query the deCONZ database for it directly.
if bashio::fs.file_exists /data/hassio.json; then
rm /data/hassio.json
fi
# Try to get API key from deCONZ database
query='SELECT apikey FROM auth WHERE devicetype="Home Assistant" ORDER BY createdate DESC LIMIT 1'
api_key=$(sqlite3 "${DATA_STORE}" "${query}" .exit)
if ! bashio::var.has_value "${api_key}"; then
# Register an API key for Home Assistant
if ! result="$(curl --silent --show-error --request POST -d '{"devicetype": "Home Assistant"}' "http://127.0.0.1:40850/api")";
then
bashio::log.debug "${result}"
bashio::exit.nok "Can't get API key from deCONZ gateway"
fi
api_key="$(bashio::jq "${result}" '.[0].success.username')"
fi
# Try to get the bridge ID/serial, try to avoid using 0000000000000000
retries=25
serial="0000000000000000"
while [[ "${serial}" = "0000000000000000" ]]; do
bashio::log.debug "Waiting for bridge ID..."
sleep 10
# If we tried 25 times, just abort.
if [[ "${retries}" -eq 0 ]]; then
bashio::exit.nok "Failed to get a valid bridge ID. Discovery aborted."
fi
# Get bridge ID from API
if ! result="$(curl --silent --show-error --request GET "http://127.0.0.1:40850/api/${api_key}/config")";
then
bashio::log.debug "${result}"
bashio::exit.nok "Can't get data from deCONZ gateway"
fi
serial="$(bashio::jq "${result}" '.bridgeid')"
((retries--))
done
# Create config payload for Home Assistant
config=$(bashio::var.json \
host "$(bashio::addon.ip_address)" \
port "^40850" \
api_key "${api_key}" \
serial "${serial}" \
)
# Send discovery info
if bashio::discovery "deconz" "${config}" > /dev/null; then
bashio::log.info "Successfully send discovery information to Home Assistant."
else
bashio::log.error "Discovery message to Home Assistant failed!"
fi

View File

@@ -0,0 +1,8 @@
#!/usr/bin/execlineb -S1
# ==============================================================================
# Take down the S6 supervision tree based on service exit code
# ==============================================================================
if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -1,20 +1,7 @@
#!/usr/bin/env bashio
set -e
# Init own udev service
/lib/systemd/systemd-udevd --daemon
bashio::hardware.trigger
# Ensure otau folder exists
mkdir -p "/data/otau"
# shellcheck disable=SC1091
. /discovery.sh
WAIT_PIDS=()
# Default QT platform
PLATFORM="minimal"
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Start deCONZ service
# ==============================================================================
# Lookup udev link
bashio::log.info "Waiting for device..."
@@ -48,23 +35,19 @@ bashio::config.has_value 'dbg_zcl' \
bashio::config.has_value 'dbg_zdp' \
&& DBG_ZDP="$(bashio::config 'dbg_zdp')" || DBG_ZDP=0
# Check if VNC is enabled
# VNC is not enabled as a seperate service, as it cannot handle multiple
# session when running in the foreground.
PLATFORM="minimal"
VNC_PORT="$(bashio::addon.port 5900)"
if bashio::var.has_value "${VNC_PORT}"; then
TMP_FOLDER=$(mktemp -d)
export XDG_RUNTIME_DIR="${TMP_FOLDER}"
export DISPLAY=":0"
PLATFORM="xcb"
# Require password when VNC is enabled
if ! bashio::config.has_value 'vnc_password'; then
bashio::exit.nok "VNC has been enabled, but no password has been set!"
fi
bashio::log.info "Starting VNC server..."
VNC_PASSWORD=$(bashio::config 'vnc_password')
echo "${VNC_PASSWORD}" | tigervncpasswd -f > /root/.vncpasswd
tigervncserver \
-name "Home Assistant - deCONZ" \
-geometry 1920x1080 \
@@ -73,11 +56,19 @@ if bashio::var.has_value "${VNC_PORT}"; then
-PasswordFile /root/.vncpasswd \
"${DISPLAY}" \
&> /dev/null
# Wait for VNC server to start before continuing
bashio::log.info "Waiting for VNC to start"
bashio::net.wait_for "${VNC_PORT}"
fi
# Send out discovery information to Home Assistant
./discovery &
# Start deCONZ
bashio::log.info "Starting the deCONZ gateway..."
deCONZ \
exec deCONZ \
-platform "${PLATFORM}" \
--auto-connect=1 \
--dbg-info="${DBG_INFO}" \
@@ -88,45 +79,4 @@ deCONZ \
--upnp=0 \
--http-port=40850 \
--ws-port=8081 \
--dev="${DECONZ_DEVICE}" &
WAIT_PIDS+=($!)
# Wait for deCONZ to start before continuing
bashio::net.wait_for 40850
# Start Nginx proxy
bashio::log.info "Starting Nginx..."
ingress_entry=$(bashio::addon.ingress_entry)
sed -i "s#%%ingress_entry%%#${ingress_entry}#g" /etc/nginx/nginx.conf
nginx &
WAIT_PIDS+=($!)
# Register stop
function stop_addon() {
bashio::log.debug "Kill Processes..."
kill -15 "${WAIT_PIDS[@]}"
wait "${WAIT_PIDS[@]}"
bashio::log.debug "Done."
}
trap "stop_addon" SIGTERM SIGHUP
# Start Home Assistant discovery
bashio::log.info "Running Home Assistant discovery task..."
hassio_discovery &
# Start OTA updates for deCONZ
bashio::log.info "Running the deCONZ OTA updater..."
deCONZ-otau-dl.sh &> /dev/null &
# Start OTA updates for IKEA
bashio::log.info "Running the IKEA OTA updater..."
ika-otau-dl.sh &> /dev/null &
# Start OTA updates for LEDVANCE/OSRAM
bashio::log.info "Running the LEDVANCE/OSRAM OTA updater..."
ledvance-otau-dl.sh &> /dev/null &
# Wait until all is done
bashio::log.info "deCONZ is set up and running!"
wait "${WAIT_PIDS[@]}"
--dev="${DECONZ_DEVICE}"

View File

@@ -0,0 +1,8 @@
#!/usr/bin/execlineb -S1
# ==============================================================================
# Take down the S6 supervision tree based on service exit code
# ==============================================================================
if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bashio
# ==============================================================================
# Start NGINX service
# ==============================================================================
# Wait for deCONZ to start before continuing
bashio::net.wait_for 40850
bashio::log.info "Starting Nginx..."
exec nginx

View File

@@ -0,0 +1,8 @@
#!/usr/bin/execlineb -S1
# ==============================================================================
# Take down the S6 supervision tree based on service exit code
# ==============================================================================
if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bashio
# ==============================================================================
# Download available firmware update for IKEA
# ==============================================================================
# Start OTA updates for deCONZ
bashio::log.info "Running the deCONZ OTA updater..."
deCONZ-otau-dl.sh &> /dev/null
exec sleep 259200

View File

@@ -0,0 +1,8 @@
#!/usr/bin/execlineb -S1
# ==============================================================================
# Take down the S6 supervision tree based on service exit code
# ==============================================================================
if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bashio
# ==============================================================================
# Download available firmware update for IKEA
# ==============================================================================
readonly URL_IKEA="http://fw.ota.homesmart.ikea.net/feed/version_info.json"
# Ensure otau folder exists
mkdir -p "/data/otau"
bashio::log.info "Running the IKEA OTA updater..."
if ! IKEA_DATA="$(curl -sL ${URL_IKEA})"; then
bashio::log.info "Can't fetch data from ikea!"
exec sleep 18000
fi
IKEA_DATA_SIZE="$(echo "${IKEA_DATA}" | jq --raw-output '. | length')"
for (( i=0; i < "${IKEA_DATA_SIZE}"; i++ )); do
OTAU_URL=$(echo "${IKEA_DATA}" | jq --raw-output ".[$i].fw_binary_url // empty")
if [ -z "${OTAU_URL}" ]; then
continue
fi
OTAU_FILE="/data/otau/${OTAU_URL##*/}"
if [ -f "${OTAU_FILE}" ]; then
continue
fi
curl -s -L -o "${OTAU_FILE}" "${OTAU_URL}"
done
exec sleep 259200

View File

@@ -0,0 +1,8 @@
#!/usr/bin/execlineb -S1
# ==============================================================================
# Take down the S6 supervision tree based on service exit code
# ==============================================================================
if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env bashio
# ==============================================================================
# Download available firmware update for OSRAM Ledvance
# ==============================================================================
readonly URL_OSRAM="https://api.update.ledvance.com/v1/zigbee/firmwares"
# Ensure otau folder exists
mkdir -p "/data/otau"
bashio::log.info "Running the OSRAM LEdvance OTA updater..."
# fetch data
if ! OSRAM_DATA="$(curl -sL ${URL_OSRAM})"; then
bashio::log.info "Can't fetch data from osram!"
exec sleep 18000
fi
OSRAM_DATA_SIZE="$(echo "${OSRAM_DATA}" | jq --raw-output '.firmwares | length')"
DL_DONE=0
for (( i=0; i < "${OSRAM_DATA_SIZE}"; i++ )); do
OSRAM_COMPANY=$( echo "${OSRAM_DATA}" | jq --raw-output ".firmwares[$i].identity.company // empty" 2>/dev/null)
OSRAM_PRODUCT=$( echo "${OSRAM_DATA}" | jq --raw-output ".firmwares[$i].identity.product // empty" 2>/dev/null)
OTAU_FILENAME=$( echo "${OSRAM_DATA}" | jq --raw-output ".firmwares[$i].name // empty" 2>/dev/null)
OTAU_URL="$URL_OSRAM/download/${OSRAM_COMPANY}/${OSRAM_PRODUCT}/latest"
OTAU_FILE="/data/otau/${OTAU_FILENAME}"
if [ -e "${OTAU_FILE}" ]; then
continue
fi
curl -s -L -o "${OTAU_FILE}" "${OTAU_URL}" || true
((DL_DONE+1))
if [ "$((DL_DONE % 10))" == "0" ]; then
# LEDVANCE/OSRAM API RateLimits : The rate limit 10 calls per 60 seconds or quota 100 MB per month.
DL_DONE=0
exec sleep 65
fi
done
exec sleep 259200

View File

@@ -0,0 +1,8 @@
#!/usr/bin/execlineb -S1
# ==============================================================================
# Take down the S6 supervision tree based on service exit code
# ==============================================================================
if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bashio
# ==============================================================================
# Start udevd service
# ==============================================================================
# Triggers udev reload in the background
./trigger &
bashio::log.info "Starting udevd..."
exec /lib/systemd/systemd-udevd 2>/dev/null

View File

@@ -0,0 +1,12 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Trigger a uDEV reload
# ==============================================================================
# Give udevd time to start
sleep 3
bashio::hardware.trigger
# Again, just to be sure
sleep 10
bashio::hardware.trigger