824 lines
23 KiB
Nix
824 lines
23 KiB
Nix
|
{ self, cfg, pkgs, lib, ... }:
|
||
|
let
|
||
|
createMlatService =
|
||
|
(name: feedConfig:
|
||
|
let
|
||
|
uuidFile = pkgs.writeTextFile {
|
||
|
name = "${name}-uuid";
|
||
|
text = "${feedConfig.uuid}";
|
||
|
};
|
||
|
options = [
|
||
|
"--input-type"
|
||
|
feedConfig.mlat.input.type
|
||
|
"--no-udp"
|
||
|
"--input-connect"
|
||
|
"${feedConfig.mlat.input.host}:${toString feedConfig.mlat.input.port}"
|
||
|
"--server"
|
||
|
feedConfig.mlat.server
|
||
|
"--user"
|
||
|
feedConfig.username
|
||
|
"--lat"
|
||
|
cfg.latitude
|
||
|
"--lon"
|
||
|
cfg.longitude
|
||
|
"--alt"
|
||
|
(toString cfg.altitude)
|
||
|
"--uuid-file"
|
||
|
"${uuidFile}"
|
||
|
] ++ (
|
||
|
if feedConfig.mlat.privacy
|
||
|
then
|
||
|
[
|
||
|
"--privacy"
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
map (result: "--result ${result}") feedConfig.mlat.results
|
||
|
);
|
||
|
in
|
||
|
{
|
||
|
enable = feedConfig.mlat.enable;
|
||
|
description = "${name} MLAT client.";
|
||
|
wants = [ "network.target" ];
|
||
|
after = [ "network.target" ];
|
||
|
unitConfig = {
|
||
|
Documentation = "https://github.com/makrsmark/mlat-client/";
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
Type = "simple";
|
||
|
User = "${name}";
|
||
|
RuntimeDirectory = "${name}-mlat";
|
||
|
RuntimeDirectoryMode = "0755";
|
||
|
ExecStart = "${self.packages.${pkgs.system}.adsbfi-mlat-client}/bin/mlat-client ${lib.concatStringsSep " " options}";
|
||
|
SyslogIdentifier = "${name}-mlat";
|
||
|
Restart = "on-failure";
|
||
|
RestartSec = 30;
|
||
|
Nice = -1;
|
||
|
};
|
||
|
wantedBy = [ "multi-user.target" ];
|
||
|
}
|
||
|
|
||
|
);
|
||
|
createFeedService = (name: feedConfig:
|
||
|
let
|
||
|
uuidFile = pkgs.writeTextFile {
|
||
|
name = "${name}-uuid";
|
||
|
text = "${feedConfig.uuid}";
|
||
|
};
|
||
|
connectors = map
|
||
|
(
|
||
|
connector: "--net-connector ${connector}"
|
||
|
)
|
||
|
(
|
||
|
map
|
||
|
(
|
||
|
connector: (
|
||
|
lib.concatStringsSep "," (
|
||
|
[
|
||
|
connector.primary.host
|
||
|
(toString connector.primary.port)
|
||
|
connector.protocol
|
||
|
] ++ (
|
||
|
if connector.silentFail
|
||
|
then
|
||
|
[
|
||
|
"silent_fail"
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if connector.secondary != null
|
||
|
then
|
||
|
[
|
||
|
connector.secondary.host
|
||
|
(toString connector.secondary.port)
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
feedConfig.feed.connectors
|
||
|
);
|
||
|
options = [
|
||
|
"--quiet"
|
||
|
"--net"
|
||
|
"--net-only"
|
||
|
"--write-json"
|
||
|
"%t/${name}-feed"
|
||
|
"--net-beast-reduce-interval 0.5"
|
||
|
"--net-heartbeat 60"
|
||
|
"--net-ro-size 1280"
|
||
|
"--net-ro-interval 0.2"
|
||
|
"--net-ro-port 0"
|
||
|
"--net-sbs-port 0"
|
||
|
"--net-bi-port ${toString feedConfig.feed.beastInputPort}"
|
||
|
"--net-bo-port 0"
|
||
|
"--net-ri-port 0"
|
||
|
"--write-json-every 1"
|
||
|
"--lat"
|
||
|
cfg.latitude
|
||
|
"--lon"
|
||
|
cfg.longitude
|
||
|
"--max-range 450"
|
||
|
"--json-location-accuracy 2"
|
||
|
"--range-outline-hours 24"
|
||
|
"--uuid-file"
|
||
|
"${uuidFile}"
|
||
|
] ++ connectors;
|
||
|
in
|
||
|
{
|
||
|
enable = feedConfig.feed.enable;
|
||
|
description = "ADSB.fi feeder.";
|
||
|
wants = [ "network.target" ];
|
||
|
after = [ "network.target" ];
|
||
|
unitConfig = {
|
||
|
Documentation = "https://github.com/widehopf/readsb/";
|
||
|
StartLimitIntervalSec = 1;
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
Type = "simple";
|
||
|
User = "${name}";
|
||
|
RuntimeDirectory = "${name}-feed";
|
||
|
RuntimeDirectoryMode = "0755";
|
||
|
ExecStart = "${self.packages.${pkgs.system}.adsbfi-readsb}/bin/readsb ${lib.concatStringsSep " " options}";
|
||
|
SyslogIdentifier = "${name}-feed";
|
||
|
Restart = "on-failure";
|
||
|
RestartSec = 30;
|
||
|
StartLimitBurst = 100;
|
||
|
Nice = -1;
|
||
|
};
|
||
|
wantedBy = [ "multi-user.target" ];
|
||
|
}
|
||
|
);
|
||
|
in
|
||
|
lib.mkIf cfg.enable {
|
||
|
|
||
|
assertions = [
|
||
|
{
|
||
|
assertion = cfg.dump1090.device.type == "rtlsdr";
|
||
|
message = "not set up for anything but rtlsdr yet";
|
||
|
}
|
||
|
{
|
||
|
assertion = !(cfg.dump1090.device.type == "rtlsdr" && cfg.dump1090.device.rtlsdr.serial != null && cfg.dump1090.device.rtlsdr.index != null);
|
||
|
message = "rtlsdr device cannot be selected by both serial and index";
|
||
|
}
|
||
|
{
|
||
|
assertion = !(!cfg.dump978.enable && cfg.skyaware978.enable);
|
||
|
message = "The skyaware978 service cannot be enabled if the dump978 service is disabled.";
|
||
|
}
|
||
|
];
|
||
|
|
||
|
boot.blacklistedKernelModules = [
|
||
|
"dvb_usb_rtl28xxu"
|
||
|
];
|
||
|
|
||
|
services.udev.packages = [
|
||
|
pkgs.rtl-sdr
|
||
|
];
|
||
|
|
||
|
users.groups.plugdev = { };
|
||
|
|
||
|
users.groups.dump1090 = { };
|
||
|
users.users.dump1090 = {
|
||
|
isSystemUser = true;
|
||
|
group = "dump1090";
|
||
|
extraGroups = [ "plugdev" ];
|
||
|
};
|
||
|
|
||
|
users.groups.piaware = { };
|
||
|
users.users.piaware = {
|
||
|
isSystemUser = true;
|
||
|
group = "piaware";
|
||
|
};
|
||
|
|
||
|
systemd.services."dump1090-fa" =
|
||
|
let
|
||
|
rtlsdrOptions =
|
||
|
if cfg.dump1090.device.type == "rtlsdr"
|
||
|
then
|
||
|
(
|
||
|
if cfg.dump1090.device.rtlsdr.serial != null
|
||
|
then
|
||
|
[
|
||
|
"--device-index"
|
||
|
cfg.dump1090.device.rtlsdr.serial
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++
|
||
|
(
|
||
|
if cfg.dump1090.device.rtlsdr.index != null
|
||
|
then
|
||
|
[
|
||
|
"--device-index"
|
||
|
(toString cfg.dump1090.device.rtlsdr.index)
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if cfg.dump1090.device.rtlsdr.enableAgc
|
||
|
then
|
||
|
[
|
||
|
"--enable-agc"
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if cfg.dump1090.device.rtlsdr.frequencyCorrection != null
|
||
|
then
|
||
|
[
|
||
|
"--ppm"
|
||
|
(toString cfg.dump1090.device.rtlsdr.frequencyCorrection)
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if cfg.dump1090.device.rtlsdr.directSamplingMode != null
|
||
|
then
|
||
|
[
|
||
|
"--direct"
|
||
|
(toString cfg.dump1090.device.rtlsdr.directSamplingMode)
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
)
|
||
|
else
|
||
|
[ ];
|
||
|
adaptiveDynamicRangeOptions =
|
||
|
if cfg.dump1090.adaptiveDynamicRange.enable
|
||
|
then
|
||
|
[
|
||
|
"--adaptive-range"
|
||
|
] ++
|
||
|
(
|
||
|
if cfg.dump1090.adaptiveDynamicRange.target != null
|
||
|
then
|
||
|
[ "--adaptive-range-target" (toString cfg.dump1090.adaptiveDynamicRange.target) ]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++
|
||
|
(
|
||
|
if cfg.dump1090.adaptiveDynamicRange.alpha != null
|
||
|
then
|
||
|
[ "--adaptive-range-alpha" (toString cfg.dump1090.adaptiveDynamicRange.alpha) ]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++
|
||
|
(
|
||
|
if cfg.dump1090.adaptiveDynamicRange.percentile != null
|
||
|
then
|
||
|
[ "--adaptive-range-percentile" (toString cfg.dump1090.adaptiveDynamicRange.percentile) ]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++
|
||
|
(
|
||
|
if cfg.dump1090.adaptiveDynamicRange.changeDelay != null
|
||
|
then
|
||
|
[ "--adaptive-range-change-delay" (toString cfg.dump1090.adaptiveDynamicRange.changeDelay) ]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++
|
||
|
(
|
||
|
if cfg.dump1090.adaptiveDynamicRange.scanDelay != null
|
||
|
then
|
||
|
[ "--adaptive-range-scan-delay" (toString cfg.dump1090.adaptiveDynamicRange.scanDelay) ]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++
|
||
|
(
|
||
|
if cfg.dump1090.adaptiveDynamicRange.rescanDelay != null
|
||
|
then
|
||
|
[ "--adaptive-range-rescan-delay" (toString cfg.dump1090.adaptiveDynamicRange.rescanDelay) ]
|
||
|
else
|
||
|
[ ]
|
||
|
)
|
||
|
else
|
||
|
[ ];
|
||
|
options = [
|
||
|
"--quiet"
|
||
|
"--device-type"
|
||
|
cfg.dump1090.device.type
|
||
|
] ++ rtlsdrOptions ++ adaptiveDynamicRangeOptions ++ (
|
||
|
if cfg.dump1090.device.gain != null
|
||
|
then
|
||
|
[
|
||
|
"--gain"
|
||
|
(toString cfg.dump1090.device.gain)
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if cfg.dump1090.errorCorrection
|
||
|
then
|
||
|
[ "--fix" ]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ [
|
||
|
"--lat"
|
||
|
cfg.latitude
|
||
|
"--lon"
|
||
|
cfg.longitude
|
||
|
] ++
|
||
|
(
|
||
|
if cfg.dump1090.maxRange != null
|
||
|
then
|
||
|
[
|
||
|
"--max-range"
|
||
|
(toString cfg.dump1090.maxRange)
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if cfg.dump1090.network.raw.input.enable
|
||
|
then
|
||
|
[
|
||
|
"--net-ri-port"
|
||
|
(lib.concatStringsSep "," (map toString cfg.dump1090.network.raw.input.ports))
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if cfg.dump1090.network.raw.output.enable
|
||
|
then
|
||
|
[
|
||
|
"--net-ro-port"
|
||
|
(lib.concatStringsSep "," (map toString cfg.dump1090.network.raw.output.ports))
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if cfg.dump1090.network.raw.output.size != null
|
||
|
then
|
||
|
[
|
||
|
"--net-ro-size"
|
||
|
(toString cfg.dump1090.network.raw.output.size)
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if cfg.dump1090.network.raw.output.interval != null
|
||
|
then
|
||
|
[
|
||
|
"--net-ro-interval"
|
||
|
(toString cfg.dump1090.network.raw.output.interval)
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++
|
||
|
(
|
||
|
if cfg.dump1090.network.baseStation.enable
|
||
|
then
|
||
|
[
|
||
|
"--net-sbs-port"
|
||
|
(lib.concatStringsSep "," (map toString cfg.dump1090.network.baseStation.ports))
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++
|
||
|
(
|
||
|
if cfg.dump1090.network.beast.input.enable
|
||
|
then
|
||
|
[
|
||
|
"--net-bi-port"
|
||
|
(lib.concatStringsSep "," (map toString cfg.dump1090.network.beast.input.ports))
|
||
|
]
|
||
|
else [ ]
|
||
|
) ++
|
||
|
(
|
||
|
if cfg.dump1090.network.beast.output.enable
|
||
|
then
|
||
|
[
|
||
|
"--net-bo-port"
|
||
|
(lib.concatStringsSep "," (map toString cfg.dump1090.network.beast.output.ports))
|
||
|
]
|
||
|
else [ ]
|
||
|
) ++ [
|
||
|
"--json-location-accuracy"
|
||
|
(toString cfg.dump1090.jsonLocationAccuracy)
|
||
|
"--write-json"
|
||
|
"%t/dump1090-fa"
|
||
|
] ++ cfg.dump1090.extraOptions;
|
||
|
in
|
||
|
{
|
||
|
enable = cfg.dump1090.enable;
|
||
|
description = "dump1090 ADS-B receiver (FlightAware customization)";
|
||
|
wants = [ "network.target" ];
|
||
|
after = [ "network.target" ];
|
||
|
unitConfig = {
|
||
|
Documentation = "https://flightaware.com/adsb/piaware/";
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
Type = "simple";
|
||
|
User = "dump1090";
|
||
|
RuntimeDirectory = "dump1090-fa";
|
||
|
RuntimeDirectoryMode = "0755";
|
||
|
ExecStart = "${self.packages.${pkgs.system}.dump1090-fa}/bin/dump1090 ${lib.concatStringsSep " " options}";
|
||
|
SyslogIdentifier = "dump1090-fa";
|
||
|
Restart = "on-failure";
|
||
|
RestartSec = 30;
|
||
|
RestartPreventExitStatus = "64";
|
||
|
Nice = -5;
|
||
|
};
|
||
|
wantedBy = [ "multi-user.target" ];
|
||
|
};
|
||
|
|
||
|
users.groups.skyaware = { };
|
||
|
users.users.skyaware = {
|
||
|
isSystemUser = true;
|
||
|
group = "skyaware";
|
||
|
};
|
||
|
|
||
|
systemd.services."skyaware978" = {
|
||
|
enable = cfg.skyaware978.enable;
|
||
|
description = "skyaware978 ADS-B UAT web display";
|
||
|
wants = [ "network.target" ];
|
||
|
after = [ "network.target" "dump978-fa.service" ];
|
||
|
unitConfig = {
|
||
|
Documentation = "https://flightaware.com/adsb/piaware/";
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
Type = "simple";
|
||
|
User = "skyaware";
|
||
|
RuntimeDirectory = "skyaware978";
|
||
|
RuntimeDirectoryMode = "0755";
|
||
|
ExecStart = "${self.packages.${pkgs.system}.dump978-fa}/bin/skyaware978 --lat ${cfg.latitude} --lon ${cfg.longitude} --json-dir %t/skyaware978";
|
||
|
SyslogIdentifier = "skyaware978";
|
||
|
Restart = "on-failure";
|
||
|
RestartSec = 30;
|
||
|
RestartPreventExitStatus = "64";
|
||
|
};
|
||
|
wantedBy = [ "dump978-fa.service" ];
|
||
|
};
|
||
|
|
||
|
users.groups.adsbexchange = { };
|
||
|
users.users.adsbexchange = {
|
||
|
isSystemUser = true;
|
||
|
group = "adsbexchange";
|
||
|
};
|
||
|
|
||
|
systemd.services."adsbexchange-mlat" =
|
||
|
let
|
||
|
uuidFile = pkgs.writeTextFile {
|
||
|
name = "adsbx-uuid";
|
||
|
text = "${cfg.adsbexchange.uuid}";
|
||
|
};
|
||
|
options = [
|
||
|
"--input-type"
|
||
|
cfg.adsbexchange.mlat.input.type
|
||
|
"--no-udp"
|
||
|
"--input-connect"
|
||
|
"${cfg.adsbexchange.mlat.input.host}:${toString cfg.adsbexchange.mlat.input.port}"
|
||
|
"--server"
|
||
|
cfg.adsbexchange.mlat.server
|
||
|
"--user"
|
||
|
cfg.adsbexchange.username
|
||
|
"--lat"
|
||
|
cfg.latitude
|
||
|
"--lon"
|
||
|
cfg.longitude
|
||
|
"--alt"
|
||
|
(toString cfg.altitude)
|
||
|
"--uuid-file"
|
||
|
"${uuidFile}"
|
||
|
] ++ (
|
||
|
if cfg.adsbexchange.mlat.privacy
|
||
|
then
|
||
|
[
|
||
|
"--privacy"
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
map (result: "--result ${result}") cfg.adsbexchange.mlat.results
|
||
|
);
|
||
|
in
|
||
|
{
|
||
|
enable = cfg.adsbexchange.mlat.enable;
|
||
|
description = "ADS-B Exchange MLAT client.";
|
||
|
wants = [ "network.target" ];
|
||
|
after = [ "network.target" ];
|
||
|
unitConfig = {
|
||
|
Documentation = "https://github.com/makrsmark/mlat-client/";
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
Type = "simple";
|
||
|
User = "adsbexchange";
|
||
|
RuntimeDirectory = "adsbexchange-mlat";
|
||
|
RuntimeDirectoryMode = "0755";
|
||
|
ExecStart = "${self.packages.${pkgs.system}.adsbfi-mlat-client}/bin/mlat-client ${lib.concatStringsSep " " options}";
|
||
|
SyslogIdentifier = "adsbexchange-mlat";
|
||
|
Restart = "on-failure";
|
||
|
RestartSec = 30;
|
||
|
Nice = -1;
|
||
|
};
|
||
|
wantedBy = [ "multi-user.target" ];
|
||
|
};
|
||
|
|
||
|
systemd.services."adsbexchange-feed" =
|
||
|
let
|
||
|
uuidFile = pkgs.writeTextFile {
|
||
|
name = "adsbx-uuid";
|
||
|
text = "${cfg.adsbexchange.uuid}";
|
||
|
};
|
||
|
options = [
|
||
|
"--quiet"
|
||
|
"--net"
|
||
|
"--net-only"
|
||
|
"--write-json"
|
||
|
"%t/adsbexchange-feed"
|
||
|
"--net-beast-reduce-interval 0.5"
|
||
|
"--net-connector feed1.adsbexchange.com,30004,beast_reduce_out,feed2.adsbexchange.com,64004"
|
||
|
"--net-heartbeat 60"
|
||
|
"--net-ro-size 1280"
|
||
|
"--net-ro-interval 0.2"
|
||
|
"--net-ro-port 0"
|
||
|
"--net-sbs-port 0"
|
||
|
"--net-bi-port ${toString cfg.adsbexchange.feed.beastInputPort}"
|
||
|
"--net-bo-port 0"
|
||
|
"--net-ri-port 0"
|
||
|
"--write-json-every 1"
|
||
|
"--lat"
|
||
|
cfg.latitude
|
||
|
"--lon"
|
||
|
cfg.longitude
|
||
|
"--max-range 450"
|
||
|
"--json-location-accuracy 2"
|
||
|
"--range-outline-hours 24"
|
||
|
"--uuid-file"
|
||
|
"${uuidFile}"
|
||
|
"--net-connector 127.0.0.1,30978,uat_in,silent_fail"
|
||
|
"--net-connector 127.0.0.1,30005,beast_in,silent_fail"
|
||
|
];
|
||
|
in
|
||
|
{
|
||
|
enable = cfg.adsbexchange.feed.enable;
|
||
|
description = "ADS-B Exchange feeder.";
|
||
|
wants = [ "network.target" ];
|
||
|
after = [ "network.target" ];
|
||
|
unitConfig = {
|
||
|
Documentation = "https://github.com/wiedehopf/readsb/";
|
||
|
StartLimitIntervalSec = 1;
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
Type = "simple";
|
||
|
User = "adsbexchange";
|
||
|
RuntimeDirectory = "adsbexchange-feed";
|
||
|
RuntimeDirectoryMode = "0755";
|
||
|
ExecStart = "${self.packages.${pkgs.system}.adsbfi-readsb}/bin/readsb ${lib.concatStringsSep " " options}";
|
||
|
SyslogIdentifier = "adsbexchange-feed";
|
||
|
Restart = "on-failure";
|
||
|
RestartSec = 30;
|
||
|
StartLimitBurst = 100;
|
||
|
Nice = -1;
|
||
|
};
|
||
|
wantedBy = [ "multi-user.target" ];
|
||
|
};
|
||
|
|
||
|
##
|
||
|
## ADSB.fi
|
||
|
##
|
||
|
|
||
|
users.groups.adsbfi = { };
|
||
|
users.users.adsbfi = {
|
||
|
isSystemUser = true;
|
||
|
group = "adsbexchange";
|
||
|
};
|
||
|
|
||
|
systemd.services."adsbfi-mlat" =
|
||
|
let
|
||
|
uuidFile = pkgs.writeTextFile {
|
||
|
name = "adsbfi-uuid";
|
||
|
text = "${cfg.adsbfi.uuid}";
|
||
|
};
|
||
|
options = [
|
||
|
"--input-type"
|
||
|
cfg.adsbfi.mlat.input.type
|
||
|
"--no-udp"
|
||
|
"--input-connect"
|
||
|
"${cfg.adsbfi.mlat.input.host}:${toString cfg.adsbfi.mlat.input.port}"
|
||
|
"--server"
|
||
|
cfg.adsbfi.mlat.server
|
||
|
"--user"
|
||
|
cfg.adsbfi.username
|
||
|
"--lat"
|
||
|
cfg.latitude
|
||
|
"--lon"
|
||
|
cfg.longitude
|
||
|
"--alt"
|
||
|
(toString cfg.altitude)
|
||
|
"--uuid-file"
|
||
|
"${uuidFile}"
|
||
|
] ++ (
|
||
|
if cfg.adsbfi.mlat.privacy
|
||
|
then
|
||
|
[
|
||
|
"--privacy"
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
map (result: "--result ${result}") cfg.adsbfi.mlat.results
|
||
|
);
|
||
|
in
|
||
|
{
|
||
|
enable = cfg.adsbfi.mlat.enable;
|
||
|
description = "ADSB.fi MLAT client.";
|
||
|
wants = [ "network.target" ];
|
||
|
after = [ "network.target" ];
|
||
|
unitConfig = {
|
||
|
Documentation = "https://github.com/makrsmark/mlat-client/";
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
Type = "simple";
|
||
|
User = "adsbfi";
|
||
|
RuntimeDirectory = "adsbfi-mlat";
|
||
|
RuntimeDirectoryMode = "0755";
|
||
|
ExecStart = "${self.packages.${pkgs.system}.adsbfi-mlat-client}/bin/mlat-client ${lib.concatStringsSep " " options}";
|
||
|
SyslogIdentifier = "adsbfi-mlat";
|
||
|
Restart = "on-failure";
|
||
|
RestartSec = 30;
|
||
|
Nice = -1;
|
||
|
};
|
||
|
wantedBy = [ "multi-user.target" ];
|
||
|
};
|
||
|
|
||
|
systemd.services."adsbfi-feed" =
|
||
|
let
|
||
|
uuidFile = pkgs.writeTextFile {
|
||
|
name = "adsbfi-uuid";
|
||
|
text = "${cfg.adsbfi.uuid}";
|
||
|
};
|
||
|
connectors = map
|
||
|
(
|
||
|
connector: "--net-connector ${connector}"
|
||
|
)
|
||
|
(
|
||
|
map
|
||
|
(
|
||
|
connector: (
|
||
|
lib.concatStringsSep "," (
|
||
|
[
|
||
|
connector.primary.host
|
||
|
(toString connector.primary.port)
|
||
|
connector.protocol
|
||
|
] ++ (
|
||
|
if connector.silentFail
|
||
|
then
|
||
|
[
|
||
|
"silent_fail"
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
) ++ (
|
||
|
if connector.secondary != null
|
||
|
then
|
||
|
[
|
||
|
connector.secondary.host
|
||
|
(toString connector.secondary.port)
|
||
|
]
|
||
|
else
|
||
|
[ ]
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
cfg.adsbfi.feed.connectors
|
||
|
);
|
||
|
options = [
|
||
|
"--quiet"
|
||
|
"--net"
|
||
|
"--net-only"
|
||
|
"--write-json"
|
||
|
"%t/adsbfi-feed"
|
||
|
"--net-beast-reduce-interval 0.5"
|
||
|
"--net-heartbeat 60"
|
||
|
"--net-ro-size 1280"
|
||
|
"--net-ro-interval 0.2"
|
||
|
"--net-ro-port 0"
|
||
|
"--net-sbs-port 0"
|
||
|
"--net-bi-port ${toString cfg.adsbfi.feed.beastInputPort}"
|
||
|
"--net-bo-port 0"
|
||
|
"--net-ri-port 0"
|
||
|
"--write-json-every 1"
|
||
|
"--lat"
|
||
|
cfg.latitude
|
||
|
"--lon"
|
||
|
cfg.longitude
|
||
|
"--max-range 450"
|
||
|
"--json-location-accuracy 2"
|
||
|
"--range-outline-hours 24"
|
||
|
"--uuid-file"
|
||
|
"${uuidFile}"
|
||
|
] ++ connectors;
|
||
|
in
|
||
|
{
|
||
|
enable = cfg.adsbfi.feed.enable;
|
||
|
description = "ADSB.fi feeder.";
|
||
|
wants = [ "network.target" ];
|
||
|
after = [ "network.target" ];
|
||
|
unitConfig = {
|
||
|
Documentation = "https://github.com/widehopf/readsb/";
|
||
|
StartLimitIntervalSec = 1;
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
Type = "simple";
|
||
|
User = "adsbfi";
|
||
|
RuntimeDirectory = "adsbfi-feed";
|
||
|
RuntimeDirectoryMode = "0755";
|
||
|
ExecStart = "${self.packages.${pkgs.system}.adsbfi-readsb}/bin/readsb ${lib.concatStringsSep " " options}";
|
||
|
SyslogIdentifier = "adsbfi-feed";
|
||
|
Restart = "on-failure";
|
||
|
RestartSec = 30;
|
||
|
StartLimitBurst = 100;
|
||
|
Nice = -1;
|
||
|
};
|
||
|
wantedBy = [ "multi-user.target" ];
|
||
|
};
|
||
|
|
||
|
##
|
||
|
## theairtraffic.com
|
||
|
##
|
||
|
|
||
|
users.groups.theairtraffic = { };
|
||
|
users.users.theairtraffic = {
|
||
|
isSystemUser = true;
|
||
|
group = "theairtraffic";
|
||
|
};
|
||
|
|
||
|
systemd.services."theairtraffic-mlat" = createMlatService "theairtraffic" cfg.theairtraffic;
|
||
|
systemd.services."theairtraffic-feed" = createFeedService "theairtraffic" cfg.theairtraffic;
|
||
|
|
||
|
systemd.tmpfiles.rules = [
|
||
|
"d /var/cache/piaware 0755 piaware piaware - -"
|
||
|
];
|
||
|
|
||
|
systemd.services."piaware" =
|
||
|
let
|
||
|
config = pkgs.writeTextFile {
|
||
|
name = "piaware.conf";
|
||
|
text = ''
|
||
|
# https://flightaware.com/adsb/piaware/advanced_configuration
|
||
|
allow-auto-updates no
|
||
|
allow-manual-updates no
|
||
|
allow-mlat ${if cfg.piaware.allowMLAT then "yes" else "no"}
|
||
|
allow-modeac ${if cfg.piaware.allowModeAC then "yes" else "no"}
|
||
|
feeder-id ${cfg.piaware.feederId}
|
||
|
'';
|
||
|
};
|
||
|
in
|
||
|
{
|
||
|
enable = cfg.piaware.enable;
|
||
|
description = "FlightAware ADS-B uploader";
|
||
|
wants = [ "network-online.target" ];
|
||
|
after = [ "dump1090-fa.service" "network-online.target" "time-sync.target" ];
|
||
|
unitConfig = {
|
||
|
Documentation = "https://flightaware.com/adsb/piaware/";
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
Type = "simple";
|
||
|
User = "piaware";
|
||
|
RuntimeDirectory = "piaware";
|
||
|
ExecStart = "${self.packages.${pkgs.system}.piaware}/bin/piaware -p %t/piaware/piaware.pid -plainlog -configfile ${config} -statusfile %t/piaware/status.json";
|
||
|
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||
|
Restart = "on-failure";
|
||
|
RestartPreventExitStatus = "4 6";
|
||
|
};
|
||
|
wantedBy = [ "multi-user.target" ];
|
||
|
reloadTriggers = [
|
||
|
"/etc/piaware.conf"
|
||
|
];
|
||
|
};
|
||
|
|
||
|
services.nginx = {
|
||
|
enable = true;
|
||
|
virtualHosts = {
|
||
|
"_" = {
|
||
|
root = self.packages.${pkgs.system}.dump1090-fa.html;
|
||
|
locations = {
|
||
|
"=/status.json" = {
|
||
|
alias = "/run/piaware/status.json";
|
||
|
extraConfig = ''
|
||
|
add_header Access-Control-Allow-Origin *;
|
||
|
'';
|
||
|
};
|
||
|
"/data/" = {
|
||
|
alias = "/run/dump1090-fa/";
|
||
|
extraConfig = ''
|
||
|
add_header Access-Control-Allow-Origin *;
|
||
|
'';
|
||
|
};
|
||
|
"/data-978/" = {
|
||
|
root = "/run/skyaware978/";
|
||
|
extraConfig = ''
|
||
|
add_header Access-Control-Allow-Origin *;
|
||
|
'';
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
}
|