2026-01-25 10:37:47 -05:00
{
config ,
pkgs ,
lib ? pkgs . lib ,
...
}:
with lib ; let
cfg = config . services . oott ;
in {
# Service options
2026-01-25 11:42:39 -05:00
options . services . oott = rec {
enable = mkOption {
type = types . bool ;
default = false ;
description = ''
Whether to run the oott service
'' ;
2026-01-25 10:37:47 -05:00
};
2026-01-27 13:13:02 -05:00
database . path = mkOption {
type = types . path ;
description = "Full path to store the database at" ;
default = "/var/lib/oott.db" ;
};
2026-01-25 10:37:47 -05:00
networking . interface = mkOption {
2026-05-29 07:35:25 -04:00
type = types . nullOr types . str ;
description = "Network interface to use for scans. If not set, the first non-loopback connected interface is used automatically." ;
default = null ;
2026-01-25 10:37:47 -05:00
};
log . level = mkOption {
type = types . str ;
description = "Log level for the oott service" ;
default = "info" ;
};
2026-06-01 19:00:56 -04:00
arp_scanner . enabled = mkOption {
type = types . bool ;
description = "Whether to run the ARP scanner." ;
default = true ;
};
2026-05-29 09:37:33 -04:00
arp_scanner . wait_between_scans = mkOption {
2026-01-27 13:13:02 -05:00
type = types . str ;
description = "Wait time between scans. This does not include the scan time." ;
2026-05-29 09:37:33 -04:00
default = "30m" ;
2026-01-27 13:13:02 -05:00
};
2026-05-29 09:37:33 -04:00
arp_scanner . sender_timeout = mkOption {
2026-01-27 13:13:02 -05:00
type = types . str ;
description = "If the ARP sender process takes longer than this it will be stopped (for a class C network - 254 IPs - it should take less than a minute)." ;
default = "1m" ;
};
2026-05-29 09:37:33 -04:00
arp_scanner . scan_duration = mkOption {
2026-01-27 13:13:02 -05:00
type = types . str ;
description = "How long to wait for response packets on each scan (5m to 10m is a good timeframe for a class B or C network)." ;
default = "10m" ;
};
2026-06-01 19:00:56 -04:00
mdns_scanner . enabled = mkOption {
type = types . bool ;
description = "Whether to run the mDNS/Bonjour scanner." ;
default = true ;
};
2026-05-29 09:37:33 -04:00
mdns_scanner . probe_timeout = mkOption {
type = types . str ;
description = "When an mDNS-discovered IP is not in the OS ARP cache, how long to wait for a targeted ARP probe reply to resolve its MAC address." ;
default = "2s" ;
};
2026-06-01 19:00:56 -04:00
ssdp_scanner . enabled = mkOption {
type = types . bool ;
description = "Whether to run the SSDP/UPnP scanner." ;
default = true ;
};
2026-06-01 17:58:13 -04:00
ssdp_scanner . probe_timeout = mkOption {
type = types . str ;
description = "When an SSDP/UPnP-discovered IP is not in the OS ARP cache, how long to wait for a targeted ARP probe reply to resolve its MAC address." ;
default = "2s" ;
};
2026-06-01 19:00:56 -04:00
dhcp_scanner . enabled = mkOption {
type = types . bool ;
description = "Whether to run the DHCP scanner." ;
default = true ;
};
2026-01-27 13:13:02 -05:00
notifications . method = mkOption {
type = types . str ;
description = "For now just pushover, you can set this to none to avoid sending notifications (it will just log)." ;
default = "pushover" ;
};
notifications . notify_when_not_seen_for = mkOption {
type = types . str ;
description = "Send a notification if a device comes back online after not being seen for this timeframe." ;
default = "1w" ;
};
notifications . pushover . token = mkOption {
type = types . str ;
description = "Your pushover token goes here, just copy&paste from their website after creating the app." ;
default = "" ;
};
notifications . pushover . user_key = mkOption {
type = types . str ;
description = "User key goes here, this is the account wide code for pushover." ;
default = "" ;
};
2026-05-28 09:18:46 -04:00
retention . window = mkOption {
type = types . str ;
description = "How long to retain device events and notifications. Records older than this are purged daily. Accepts duration strings (e.g. 90d, 1y, 6m)." ;
default = "365d" ;
};
2026-01-25 10:37:47 -05:00
};
# Service implementation
config = mkIf cfg . enable {
environment . systemPackages = [ pkgs . oott ];
systemd . services . oott = {
description = "oott - network device scanner" ;
wantedBy = [ "multi-user.target" ];
serviceConfig = {
2026-01-27 13:13:02 -05:00
ExecStart = " ${ pkgs . oott } /bin/oott --config ${
2026-01-27 08:38:40 -05:00
builtins . toFile "oott.json"
( generators . toJSON {} cfg )
2026-01-26 10:41:00 -05:00
} " ;
2026-01-25 10:37:47 -05:00
ProtectHome = "read-only" ;
Restart = "on-failure" ;
Type = "exec" ;
};
};
};
}