This repository has no description
3.6 kB
110 lines
1{ config, pkgs, ... }:
2let
3 domain = "where.is.lassul.us";
4 # home-assistant on styx, reached over retiolum (same as hass/proxy.nix).
5 hass = "http://styx.r:8123";
6 entity = "person.lass";
7 stateDir = "/var/lib/where-lassul-us";
8
9 leaflet = pkgs.fetchzip {
10 url = "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz";
11 hash = "sha256-zzU1O3AxsGn+r3/iL7GJr+LAjLozP0NaJ5DXnZvpllI=";
12 };
13
14 webroot = pkgs.runCommand "${domain}-webroot" { } ''
15 mkdir -p $out/leaflet
16 cp ${./index.html} $out/index.html
17 cp ${leaflet}/dist/leaflet.js ${leaflet}/dist/leaflet.css $out/leaflet/
18 cp -r ${leaflet}/dist/images $out/leaflet/images
19 '';
20
21 # Pull the last 24h of ${entity} from the hass history API and boil it down
22 # to [{t, lat, lon, acc}] for the page. hass returns every state write
23 # (~1000/day), so consecutive identical coordinates are collapsed.
24 fetch = pkgs.writeShellApplication {
25 name = "where-lassul-us-fetch";
26 runtimeInputs = [
27 pkgs.curl
28 pkgs.jq
29 pkgs.coreutils
30 ];
31 text = ''
32 since=$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)
33 curl -fsS \
34 -H "Authorization: Bearer $(cat "$CREDENTIALS_DIRECTORY/token")" \
35 "${hass}/api/history/period/$since?filter_entity_id=${entity}&significant_changes_only=0" \
36 | jq -c '
37 .[0]
38 | map(select(.attributes.latitude != null))
39 | map({
40 t: .last_updated,
41 lat: .attributes.latitude,
42 lon: .attributes.longitude,
43 acc: .attributes.gps_accuracy,
44 state: .state
45 })
46 | reduce .[] as $p ([];
47 if length > 0 and .[-1].lat == $p.lat and .[-1].lon == $p.lon
48 then .[:-1] + [$p]
49 else . + [$p]
50 end)
51 | { updated: (now | todate), points: . }
52 ' > "${stateDir}/location.json.tmp"
53 mv "${stateDir}/location.json.tmp" "${stateDir}/location.json"
54 '';
55 };
56in
57{
58 imports = [ ../default.nix ];
59
60 clan.core.vars.generators.where-lassul-us = {
61 files.token = { };
62 prompts.token = {
63 description = ''
64 home-assistant long-lived access token (profile -> security ->
65 long-lived access tokens) with read access to ${entity}.
66 '';
67 type = "hidden";
68 persist = true;
69 };
70 script = ''
71 tr -d '\n' < "$prompts/token" > "$out/token"
72 '';
73 };
74
75 # Static user rather than DynamicUser: the latter hides StateDirectory under
76 # /var/lib/private (0700), which nginx cannot traverse.
77 users.users.where-lassul-us = {
78 isSystemUser = true;
79 group = "where-lassul-us";
80 };
81 users.groups.where-lassul-us = { };
82
83 systemd.services.where-lassul-us-fetch = {
84 description = "fetch ${entity} trail from home-assistant for ${domain}";
85 after = [ "network-online.target" ];
86 wants = [ "network-online.target" ];
87 startAt = "*:0/2";
88 serviceConfig = {
89 Type = "oneshot";
90 User = "where-lassul-us";
91 Group = "where-lassul-us";
92 StateDirectory = "where-lassul-us";
93 StateDirectoryMode = "0755";
94 UMask = "0022";
95 LoadCredential = [ "token:${config.clan.core.vars.generators.where-lassul-us.files.token.path}" ];
96 ExecStart = "${fetch}/bin/where-lassul-us-fetch";
97 };
98 };
99
100 services.nginx.virtualHosts.${domain} = {
101 enableACME = true;
102 forceSSL = true;
103 root = webroot;
104 locations."= /location.json".extraConfig = ''
105 alias ${stateDir}/location.json;
106 default_type application/json;
107 add_header Cache-Control "no-cache";
108 '';
109 };
110}