fix(rpi4): set up deconz

This commit is contained in:
Felix Schröter 2020-10-07 14:37:57 +02:00
parent 2f33e6835a
commit 2a135612ab
No known key found for this signature in database
GPG key ID: 910ACB9F6BD26F58
4 changed files with 205 additions and 1 deletions

View file

@ -29,7 +29,12 @@
nix.registry.nixpkgs.flake = nixpkgs; nix.registry.nixpkgs.flake = nixpkgs;
nixpkgs.overlays = [ nur.overlay ]; nixpkgs.overlays = [
nur.overlay
(self: super: {
deconz = pkgs.qt5.callPackage ./pkgs/deconz { };
})
];
imports = imports =
[ hardwareConfig home-manager.nixosModules.home-manager config ]; [ hardwareConfig home-manager.nixosModules.home-manager config ];

42
pkgs/deconz/default.nix Normal file
View file

@ -0,0 +1,42 @@
{ stdenv, fetchurl, mkDerivation, dpkg, autoPatchelfHook
, qtserialport, qtwebsockets
, libredirect, makeWrapper, gzip, gnutar
}:
mkDerivation rec {
name = "deconz-${version}";
version = "2.05.82";
src = fetchurl {
url = "https://deconz.dresden-elektronik.de/raspbian/alpha/deconz_${version}-debian-stretch-beta_arm64.deb";
sha256 = "cCH7XhRXCHKm5AVsM19TyHwAjhbTv4qyDx2GamuDWQw=";
};
nativeBuildInputs = [ dpkg autoPatchelfHook makeWrapper ];
buildInputs = [ qtserialport qtwebsockets ];
unpackPhase = "dpkg-deb -x $src .";
installPhase = ''
mkdir -p "$out"
cp -r usr/* .
cp -r share/deCONZ/plugins/* lib/
cp -r . $out
wrapProgram "$out/bin/deCONZ" \
--set LD_PRELOAD "${libredirect}/lib/libredirect.so" \
--set NIX_REDIRECTS "/usr/share=$out/share:/usr/bin=$out/bin" \
--prefix PATH : "${stdenv.lib.makeBinPath [ gzip gnutar ]}"
'';
meta = with stdenv.lib; {
description = "Manage ZigBee network with ConBee, ConBee II or RaspBee hardware";
# 2019-08-19: The homepage links to old software that doesn't even work --
# it fails to detect ConBee2.
homepage = "https://www.dresden-elektronik.de/funktechnik/products/software/pc-software/deconz/?L=1";
license = licenses.unfree;
platforms = with platforms; linux;
maintainers = with maintainers; [ felschr ];
};
}

123
services/deconz.nix Normal file
View file

@ -0,0 +1,123 @@
# FIXME: These two auth issues:
# https://github.com/dresden-elektronik/deconz-rest-plugin/issues/1788 ("Auth problems on non-80 http port")
# https://github.com/dresden-elektronik/deconz-rest-plugin/issues/1792 ("Trying to change password: "Service not available. Try again later.")
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.local.services.deconz;
name = "deconz";
stateDir = "/var/lib/${name}";
in
{
options.local.services.deconz = {
enable = mkEnableOption "deCONZ, a ZigBee gateway";
package = mkOption {
type = types.package;
default = pkgs.deconz;
defaultText = "pkgs.deconz";
description = "Which deCONZ package to use.";
};
device = mkOption {
type = types.str;
default = "";
description = ''
Force deCONZ to use a specific USB device (e.g. /dev/ttyACM0). By
default it does a search.
'';
};
httpPort = mkOption {
type = types.port;
default = 80;
description = "TCP port for the web server.";
};
wsPort = mkOption {
type = types.port;
default = 443;
description = "TCP port for the WebSocket.";
};
openFirewall = mkEnableOption "open up the service ports in the firewall";
allowRebootSystem = mkEnableOption "allow rebooting the system";
allowRestartService = mkEnableOption "allow killing/restarting processes";
allowSetSystemTime = mkEnableOption "allow setting the system time";
extraOpts = mkOption {
type = types.listOf types.str;
default = [
"--auto-connect=1"
"--dbg-info=1"
];
description = ''
Extra command line options for deCONZ.
These options seem undocumented, but some examples can be found here:
https://github.com/marthoc/docker-deconz/blob/master/amd64/root/start.sh
'';
};
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [
cfg.httpPort
cfg.wsPort
];
systemd.services.deconz = {
description = "deCONZ ZigBee gateway";
wantedBy = [ "multi-user.target" ];
preStart = ''
# The service puts a nix store path reference in here, and that path can
# be garbage collected. Ensure the file gets "refreshed" on every start.
rm -f ${stateDir}/.local/share/dresden-elektronik/deCONZ/zcldb.txt
'';
serviceConfig = {
ExecStart =
"${cfg.package}/bin/deCONZ"
+ " -platform minimal"
+ " --http-port=${toString cfg.httpPort}"
+ " --ws-port=${toString cfg.wsPort}"
+ (if cfg.device != "" then " --dev=${cfg.device}" else "")
+ " " + (lib.concatStringsSep " " cfg.extraOpts);
Restart = "on-failure";
AmbientCapabilities =
let
# ref. upstream deconz.service
caps = lib.optionals (cfg.httpPort < 1024 || cfg.wsPort < 1024) [ "CAP_NET_BIND_SERVICE" ]
++ lib.optionals (cfg.allowRebootSystem) [ "CAP_SYS_BOOT" ]
++ lib.optionals (cfg.allowRestartService) [ "CAP_KILL" ]
++ lib.optionals (cfg.allowSetSystemTime) [ "CAP_SYS_TIME" ];
in
lib.concatStringsSep " " caps;
UMask = "0027";
User = name;
StateDirectory = name;
WorkingDirectory = stateDir;
ProtectSystem = "strict";
ProtectHome = true;
ReadWritePaths = "/tmp";
};
};
users.users.deconz = {
group = name;
isSystemUser = true;
home = stateDir;
extraGroups = [ "dialout" ]; # for access to /dev/ttyACM0 (ConBee)
};
users.groups.deconz = {};
};
}

View file

@ -1,9 +1,38 @@
{ config, pkgs, ... }: { config, pkgs, ... }:
with pkgs; with pkgs;
let
pydeconz = python3.pkgs.buildPythonPackage rec {
pname = "pydeconz";
version = "73";
src = python3.pkgs.fetchPypi {
inherit pname version;
sha256 = "Lm7J0p2dp2gyesDpgN0WGpxPewC1z/IUy0CDEqofQGA=";
};
propagateBuildInputs = with python3Packages; [ setuptools ];
buildInputs = with python3Packages; [ aiohttp ];
doCheck = false;
};
in
{ {
imports = [ ./deconz.nix ];
environment.systemPackages = with pkgs; [ deconz ];
local.services.deconz = {
enable = true;
httpPort = 8080;
wsPort = 1443;
openFirewall = true;
};
services.home-assistant = { services.home-assistant = {
enable = true; enable = true;
package = home-assistant.override {
extraPackages = ps: with ps; [ pydeconz ];
};
openFirewall = true; openFirewall = true;
config = { config = {
homeassistant = { homeassistant = {
@ -28,6 +57,11 @@ with pkgs;
mqtt_topic = "owntracks/#"; mqtt_topic = "owntracks/#";
secret = "!secret owntracks_secret"; secret = "!secret owntracks_secret";
}; };
deconz = {
host = "localhost";
port = 8080;
api_key = "!secret deconz_apikey";
};
}; };
# configWritable = true; # doesn't work atm # configWritable = true; # doesn't work atm
}; };