nixos-configuration/pkgs/myintercom-doorbell/module.nix
2025-04-16 22:54:28 +02:00

157 lines
5 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.services.myintercom-doorbell;
mediamtxConfig = pkgs.writeTextFile {
name = "myintercom-doorbell-cam-proxy-config";
text = lib.generators.toJSON { } {
paths.sprechanlage = {
source = "rtsp://${cfg.username}:__PASSWORD__@${cfg.host}/axis-media/media.amp?videocodec=h264&resolution=1280x720&fps=8&audio=0";
rtspTransport = "tcp";
};
protocols = [ "tcp" ];
hls = false;
rtmp = false;
rtsp = false;
srt = false;
webrtc = true;
webrtcAdditionalHosts = [ cfg.cam.bindAddress ];
webrtcLocalTCPAddress = "${cfg.cam.bindAddress}:${toString cfg.cam.webrtcIceTcpPort}";
};
};
in
{
options.services.myintercom-doorbell = with lib; with lib.types; {
enable = mkEnableOption "Enable myintercom service";
cam = {
enable = mkEnableOption "Enable cam proxy service";
bindAddress = mkOption {
type = types.str;
description = "The Address the service binds to.";
example = "10.0.0.1";
};
webrtcPort = mkOption {
type = types.port;
description = "Port the WebRTC service binds to.";
default = 8889;
};
webrtcIceTcpPort = mkOption {
type = types.port;
description = "Port (udp) the WebRTC ICE service binds to.";
default = 8189;
};
};
host = mkOption {
type = types.str;
description = "The Hostname of myintercom.";
example = "myintercom.lan.example.net";
};
username = mkOption {
type = types.str;
description = "Username for basic auth.";
};
passwordFile = mkOption {
type = types.path;
description = "Path to the file that contains the basic auth password.";
};
audiosocket = {
address = mkOption {
type = types.str;
description = "Address the AudioSocket binds to.";
default = "127.0.0.1";
};
port = mkOption {
type = types.port;
description = "Port the AudioSocket binds to.";
default = 9092;
};
uuid = mkOption {
type = types.str;
example = "e461837f-22b0-4652-955f-e1a444f3a42e";
};
};
callerId = mkOption {
type = types.str;
description = "The display name to show when the doorbell rings a phone.";
example = "Doorbell";
};
dialTime = mkOption {
type = types.int;
description = "The duration how long to wait for the call to be answered.";
default = 45;
};
};
config = lib.mkIf cfg.enable {
environment.etc."myintercom-doorbell/settings.json".text = builtins.toJSON {
inherit (cfg) host;
inherit (cfg) username;
inherit (cfg) passwordFile;
audiosocket = {
inherit (cfg.audiosocket) address;
inherit (cfg.audiosocket) port;
inherit (cfg.audiosocket) uuid;
};
inherit (cfg) callerId;
inherit (cfg) dialTime;
};
systemd.services = {
myintercom-doorbell-poll = {
inherit (cfg) enable;
description = "Polls myintercom doorbell ring button status.";
after = [ "asterisk.service" "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
User = "asterisk";
# @TODO: Use unstable only until 23.11 is released
ExecStart = "${pkgs.myintercom-doorbell}/bin/myintercom-doorbell-poll";
};
};
myintercom-doorbell-audiosocket = {
inherit (cfg) enable;
description = "myintercom doorbell AudioSocket for Asterisk";
requires = [ "asterisk.service" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
DynamicUser = true;
CapabilityBoundingSet = null;
PrivateUsers = true;
ProtectHome = true;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
SystemCallFilter = "@system-service";
LoadCredential = "password:${cfg.passwordFile}";
Environment = [
"LISTEN_ADDRESS=${cfg.audiosocket.address}"
"LISTEN_PORT=${toString cfg.audiosocket.port}"
"HOST=${cfg.host}"
"USERNAME=${cfg.username}"
"PASSWORD_FILE=%d/password"
];
ExecStart = "${pkgs.myintercom-doorbell}/bin/myintercom-doorbell-audiosocket";
};
};
myintercom-doorbell-cam-proxy = {
inherit (cfg.cam) enable;
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
description = "Proxies the videostream of myintercom doorbell.";
script = ''
sed "s:__PASSWORD__:$(cat "$PASSWORD_FILE"):" "${mediamtxConfig}" | ${pkgs.master.mediamtx}/bin/mediamtx /dev/stdin
'';
serviceConfig = {
Type = "simple";
DynamicUser = true;
LoadCredential = "password:${cfg.passwordFile}";
Environment = [
"PASSWORD_FILE=%d/password"
];
};
};
};
};
}