Add module.nix

This commit is contained in:
niten 2023-04-24 09:49:57 -07:00
parent ff0822d1bc
commit 08f8d721fa
4 changed files with 98 additions and 13 deletions

View File

@ -17,7 +17,7 @@
packages = rec {
default = snooper-server;
snooper-server = helpers.packages."${system}".mkClojureBin {
name = "org.fudo/snooper";
name = "org.fudo/snooper-server";
primaryNamespace = "snooper.cli";
src = ./.;
};

71
module.nix Normal file
View File

@ -0,0 +1,71 @@
packages:
{ config, lib, pkgs, ... }:
with lib;
let
snooper-server = packages."${pkgs.system}.snooper-server";
cfg = config.services.snooper;
in {
options.services.snooper = with types; {
enable = mkEnableOption "Enable Snooper notifiaction server.";
verbose = mkEnableOption "Generate verbose logs and output.";
event-topics = mkOption {
type = listOf str;
description = "MQTT topics on which to listen for detection events.";
};
notification-topic = mkOption {
type = str;
description = "MQTT topic on which to send notifications.";
};
mqtt-client = {
host = mkOption {
type = str;
description = "Hostname of the MQTT server.";
};
port = mkOption {
type = port;
description = "Port on which the MQTT server is listening.";
default = 1883;
};
username = mkOption {
type = str;
description = "User as which to connect to the MQTT server.";
};
password-file = mkOption {
type = str;
description =
"File (on the local host) containing the password for the MQTT server.";
};
};
};
config = mkIf cfg.enable {
systemd.services.snooper = {
path = [ snooper-server ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
DynamicUser = true;
LoadCredential = [ "mqtt.passwd:${cfg.mqtt-client.password-file}" ];
ExecStart = pkgs.writeShellScript "snooper-server.sh"
(concatStringsSep " " ([
"snooper-server"
"--mqtt-host=${cfg.mqtt.host}"
"--mqtt-port=${toString cfg.mqtt.port}"
"--mqtt-user=${cfg.mqtt.username}"
"--mqtt-password-file=$CREDENTIALS_DIRECTORY/mqtt.passwd"
"--notification-topic=${cfg.notification-topic}"
] ++ (map (topic: "--event-topic=${topic}") cfg.event-topics)
++ (optional cfg.verbose "--verbose")));
};
};
};
}

View File

@ -5,10 +5,12 @@
[clojure.string :as str]
[snooper.core :as snooper]
[milquetoast.client :as mqtt]
[fudo-clojure.logging :as log]))
[fudo-clojure.logging :as log])
(:gen-class))
(def cli-opts
[["-v" "--verbose" "Provide verbose output."]
["-h" "--help" "Print this message."]
[nil "--mqtt-host HOSTNAME" "Hostname of MQTT server."]
[nil "--mqtt-port PORT" "Port on which to connect to the MQTT server."
@ -44,13 +46,15 @@
(defn -main [& args]
(let [required-args #{:mqtt-host :mqtt-port :mqtt-user :mqtt-password-file :event-topic :notification-topic}
{:keys [options _ errors summary]} (parse-opts args required-args cli-opts)]
(when (:help options) (msg-quit 0 (usage summary)))
(when (seq errors) (msg-quit 1 (usage summary errors)))
(let [{:keys [mqtt-host
mqtt-port
mqtt-user
mqtt-password-file
notification-topic
event-topic]} options
event-topic
verbose]} options
catch-shutdown (async/chan)
mqtt-client (mqtt/connect-json! :host mqtt-host
:port mqtt-port
@ -59,13 +63,18 @@
(slurp)
(str/trim)))
logger (log/print-logger)]
(snooper/listen! :mqtt-client mqtt-client
(when verbose
(println (format "launching snooper server to listen on %s and report events on %s"
event-topic notification-topic)))
(snooper/listen! :mqtt-client mqtt-client
:notification-topic notification-topic
:event-topics event-topic
:logger logger)
:logger logger
:verbose verbose)
(.addShutdownHook (Runtime/getRuntime)
(Thread. (fn [] (>!! catch-shutdown true))))
(<!! catch-shutdown)
(println "stopping snooper server")
;; Stopping the MQTT will stop tattler
(mqtt/stop! mqtt-client)
(System/exit 0))))

View File

@ -1,18 +1,21 @@
(ns snooper.core
(:require [clojure.core.async :refer [go-loop alts! chan]]
(:require [clojure.core.async :refer [go-loop alts!]]
[clojure.pprint :refer [pprint]]
[fudo-clojure.logging :as log]
[milquetoast.client :as mqtt]
[malli.core :as t]))
(defn pthru [o] (clojure.pprint/pprint o) o)
(def critical-objects [:person :bear])
(def normal-objects [:cat :dog])
(defn- verbose-pthru [verbose obj]
(when verbose (pprint obj))
obj)
(defn- objects-criticality [objs]
(cond (some (partial contains? objs) critical-objects) :high
(some (partial contains? objs) normal-objects) :medium
:else nil))
:else :low))
(defn- objects-probability [objs]
(let [prob (apply max (vals objs))]
@ -58,7 +61,7 @@
(defmethod event-summary :possibly [{:keys [description location]}]
(format "There could possibly be %s at the %s" description location))
(defmethod event-summary :likely [{:keys [description location]}]
(format "There's might %s at the %s" description location))
(format "There might be %s at the %s" description location))
(defmethod event-summary :probably [{:keys [description location]}]
(format "There's probably %s at the %s" description location))
(defmethod event-summary :definitely [{:keys [description location]}]
@ -84,17 +87,19 @@
[& {mqtt-client :mqtt-client
notification-topic :notification-topic
event-topics :event-topics
logger :logger}]
logger :logger
verbose :verbose}]
(let [incoming (map (partial mqtt/subscribe! mqtt-client) event-topics)
valid-evt? (t/validator MotionEvent)]
(go-loop [evts (alts! incoming)]
(let [evt (first evts)]
(clojure.pprint/pprint evt)
(when verbose (pprint evt))
(cond (nil? evt) (log/info! logger "stopping")
(valid-evt? evt) (do (log/info! logger (format "received motion event id %s from %s"
(:id evt)
(:topic evt)))
(mqtt/send! mqtt-client notification-topic (pthru (translate-event (:payload evt))))
(mqtt/send! mqtt-client notification-topic
(verbose-pthru verbose (translate-event (:payload evt))))
(recur (alts! incoming)))
:else (do (log/error! logger (format "invalid motion event: %s" evt))
(recur (alts! incoming))))))))