merge
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
{ ... }:
|
||||
{
|
||||
services.adguardhome = {
|
||||
enable = true;
|
||||
allowDHCP = true;
|
||||
port = 3000;
|
||||
openFirewall = true;
|
||||
mutableSettings = true;
|
||||
};
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{ argononed, ... }:
|
||||
{
|
||||
imports = [ "${argononed}/OS/nixos" ];
|
||||
|
||||
services.argonone = {
|
||||
enable = true;
|
||||
logLevel = 4;
|
||||
settings = {
|
||||
fanTemp0 = 36; fanSpeed0 = 10;
|
||||
fanTemp1 = 41; fanSpeed1 = 50;
|
||||
fanTemp2 = 46; fanSpeed2 = 80;
|
||||
hysteresis = 4;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
boot = {
|
||||
kernelPackages = pkgs.linuxPackages_latest;
|
||||
initrd.availableKernelModules = [
|
||||
"xhci_pci"
|
||||
"usbhid"
|
||||
"usb_storage"
|
||||
];
|
||||
# We're using EFI so enable systemd-boot
|
||||
loader = {
|
||||
systemd-boot.enable = true;
|
||||
generic-extlinux-compatible.enable = lib.mkForce false;
|
||||
};
|
||||
kernelParams = [
|
||||
# "snd_bcm2835.enable_hdmi=1"
|
||||
"brcmfmac.roamoff=1"
|
||||
"brcmfmac.feature_disable=0x282000"
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
# Edit this configuration file to define what should be installed on
|
||||
# your system. Help is available in the configuration.nix(5) man page, on
|
||||
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
user = "matt";
|
||||
password = "$y$j9T$EkPXmsmIMFFZ.WRrBYCxS1$P0kwo6e4.WM5DsqUcEqWC3MrZp5KfCjxffraMFZWu06";
|
||||
SSID = "Joey's Jungle 5G";
|
||||
wifiSecrets = config.sops.secrets."wifi-password".path;
|
||||
interface = "wlan0";
|
||||
timezone = "America/Chicago";
|
||||
hostname = "pi4";
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
# Include the results of the hardware scan.
|
||||
./adguard.nix
|
||||
./argononed.nix
|
||||
./boot.nix
|
||||
./hardware-configuration.nix
|
||||
./impermanence.nix
|
||||
# ./sops.nix
|
||||
./ups-monitor.nix
|
||||
../default.nix
|
||||
];
|
||||
|
||||
|
||||
# Enable nix flakes and nix-command tools
|
||||
nix = {
|
||||
settings = {
|
||||
substituters = [
|
||||
# "https://cache.mjallen.dev"
|
||||
"https://nix-community.cachix.org"
|
||||
"https://cache.nixos.org/"
|
||||
];
|
||||
trusted-public-keys = [
|
||||
# "cache.mjallen.dev-1:IzFmKCd8/gggI6lcCXsW65qQwiCLGFFN9t9s2iw7Lvc="
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
];
|
||||
warn-dirty = lib.mkForce false;
|
||||
experimental-features = lib.mkForce [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
trusted-users = lib.mkDefault [
|
||||
"root"
|
||||
"@wheel"
|
||||
user
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
services.xserver = {
|
||||
enable = false;
|
||||
desktopManager = {
|
||||
budgie.enable = false;
|
||||
};
|
||||
displayManager = {
|
||||
lightdm.enable = false;
|
||||
};
|
||||
};
|
||||
|
||||
services.hardware.argonone.enable = true;
|
||||
|
||||
services.ups-monitor = {
|
||||
enable = false;
|
||||
};
|
||||
|
||||
hardware = {
|
||||
raspberry-pi."4".fkms-3d.enable = false;
|
||||
raspberry-pi."4".apply-overlays-dtmerge.enable = false;
|
||||
raspberry-pi."4".audio.enable = false;
|
||||
raspberry-pi."4".bluetooth.enable = false;
|
||||
raspberry-pi."4".dwc2.enable = false;
|
||||
raspberry-pi."4".xhci.enable = false;
|
||||
};
|
||||
|
||||
# Set your time zone.
|
||||
time.timeZone = timezone;
|
||||
|
||||
networking = {
|
||||
networkmanager.enable = lib.mkForce false;
|
||||
hostName = hostname;
|
||||
wireless = {
|
||||
enable = false;
|
||||
secretsFile = wifiSecrets;
|
||||
networks."${SSID}".psk = "ext:PSK";
|
||||
interfaces = [ interface ];
|
||||
};
|
||||
|
||||
defaultGateway.address = "10.0.1.1";
|
||||
nameservers = [ "10.0.1.1" ];
|
||||
|
||||
interfaces.enabcm6e4ei0.ipv4.addresses = [ {
|
||||
address = "10.0.1.2";
|
||||
prefixLength = 24;
|
||||
} ];
|
||||
|
||||
firewall = {
|
||||
enable = true;
|
||||
allowPing = true;
|
||||
allowedTCPPorts = [ 80 53 ];
|
||||
allowedUDPPorts = [ 80 53 ];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.btattach = {
|
||||
before = [ "bluetooth.service" ];
|
||||
after = [ "dev-ttyAMA0.device" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.bluez}/bin/btattach -B /dev/ttyAMA0 -P bcm -S 3000000";
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
argononed
|
||||
vim
|
||||
libraspberrypi
|
||||
raspberrypi-eeprom
|
||||
raspberrypifw
|
||||
raspberrypiWirelessFirmware
|
||||
raspberrypi-armstubs
|
||||
htop
|
||||
git
|
||||
];
|
||||
|
||||
services.openssh.enable = true;
|
||||
|
||||
programs.nix-index = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
enableZshIntegration = true;
|
||||
};
|
||||
|
||||
users = {
|
||||
mutableUsers = false;
|
||||
users."${user}" = {
|
||||
isNormalUser = true;
|
||||
initialHashedPassword = password;
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"docker"
|
||||
];
|
||||
shell = pkgs.zsh;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "none";
|
||||
fsType = "tmpfs";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/7EC2-DEAC";
|
||||
fsType = "vfat";
|
||||
options = [ "fmask=0022" "dmask=0022" ];
|
||||
};
|
||||
|
||||
fileSystems."/boot/firmware" =
|
||||
{ device = "/dev/disk/by-uuid/7E6D-6434";
|
||||
fsType = "vfat";
|
||||
options = [ "fmask=0022" "dmask=0022" ];
|
||||
};
|
||||
|
||||
fileSystems."/nix" =
|
||||
{ device = "/dev/disk/by-uuid/9141e15a-2ac8-4344-affe-8408800a442b";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=nix" ];
|
||||
};
|
||||
|
||||
fileSystems."/etc" =
|
||||
{ device = "/dev/disk/by-uuid/9141e15a-2ac8-4344-affe-8408800a442b";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=etc" ];
|
||||
};
|
||||
|
||||
fileSystems."/var/log" =
|
||||
{ device = "/dev/disk/by-uuid/9141e15a-2ac8-4344-affe-8408800a442b";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=log" ];
|
||||
};
|
||||
|
||||
fileSystems."/root" =
|
||||
{ device = "/dev/disk/by-uuid/9141e15a-2ac8-4344-affe-8408800a442b";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=root" ];
|
||||
};
|
||||
|
||||
fileSystems."/home" =
|
||||
{ device = "/dev/disk/by-uuid/9141e15a-2ac8-4344-affe-8408800a442b";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=home" ];
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/d390a564-9ef9-4c7d-ae1a-93951e9873dd"; }
|
||||
];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.end0.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.wlan0.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
{ ... }:
|
||||
let
|
||||
shellAliases = {
|
||||
ll = "ls -alh";
|
||||
update-boot = "sudo nixos-rebuild boot --max-jobs 10 --build-host admin@10.0.1.18";
|
||||
update-switch = "sudo nixos-rebuild switch --max-jobs 10 --build-host admin@10.0.1.18";
|
||||
update-flake = "sudo nix flake update ~/nix-config";
|
||||
update-nas = "nixos-rebuild switch --use-remote-sudo --target-host admin@10.0.1.18 --build-host admin@10.0.1.18 --flake ~/nix-config#jallen-nas";
|
||||
nas-ssh = "kitten ssh admin@10.0.1.18";
|
||||
};
|
||||
|
||||
gitAliases = {
|
||||
co = "checkout";
|
||||
ci = "commit";
|
||||
cia = "commit --amend";
|
||||
s = "status";
|
||||
st = "status";
|
||||
b = "branch";
|
||||
p = "pull --rebase";
|
||||
pu = "push";
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
home.username = "matt";
|
||||
home.homeDirectory = "/home/matt";
|
||||
home.stateVersion = "23.11";
|
||||
|
||||
sops = {
|
||||
age.keyFile = "/home/matt/.config/sops/age/keys.txt";
|
||||
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
|
||||
validateSopsFiles = false;
|
||||
secrets = {
|
||||
"ssh-keys-public/pi4" = {
|
||||
path = "/home/matt/.ssh/id_ed25519.pub";
|
||||
mode = "0644";
|
||||
};
|
||||
"ssh-keys-private/pi4" = {
|
||||
path = "/home/matt/.ssh/id_ed25519";
|
||||
mode = "0600";
|
||||
};
|
||||
"ssh-keys-public/desktop-nixos" = {
|
||||
path = "/home/matt/.ssh/authorized_keys";
|
||||
mode = "0600";
|
||||
};
|
||||
|
||||
"ssh-keys-public/desktop-nixos-root" = {
|
||||
path = "/home/matt/.ssh/authorized_keys2";
|
||||
mode = "0600";
|
||||
};
|
||||
|
||||
"ssh-keys-public/desktop-windows" = {
|
||||
path = "/home/matt/.ssh/authorized_keys3";
|
||||
mode = "0600";
|
||||
};
|
||||
|
||||
"ssh-keys-public/macbook-macos" = {
|
||||
path = "/home/matt/.ssh/authorized_keys4";
|
||||
mode = "0600";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
programs = {
|
||||
fish.enable = false;
|
||||
mangohud.enable = true;
|
||||
java.enable = true;
|
||||
home-manager.enable = true;
|
||||
|
||||
zsh = {
|
||||
enable = true;
|
||||
enableCompletion = true;
|
||||
autosuggestion.enable = true;
|
||||
syntaxHighlighting.enable = true;
|
||||
|
||||
shellAliases = shellAliases;
|
||||
|
||||
oh-my-zsh = {
|
||||
enable = true;
|
||||
plugins = [ "git" ];
|
||||
theme = "fishy";
|
||||
};
|
||||
};
|
||||
|
||||
git = {
|
||||
enable = true;
|
||||
userName = "mjallen18";
|
||||
userEmail = "matt.l.jallen@gmail.com";
|
||||
aliases = gitAliases;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{ ... }:
|
||||
{
|
||||
# Set up impernance configuration for things like bluetooth
|
||||
# In this configuration with /etc and /var/log being persistent, only directories outside of that need to be done here. See hardware configuration for all mountpoints.
|
||||
|
||||
environment.persistence."/nix/persist/system" = {
|
||||
hideMounts = true;
|
||||
directories = [
|
||||
"/var/lib/bluetooth"
|
||||
"/var/lib/nixos"
|
||||
"/var/lib/libvirt"
|
||||
"/var/lib/systemd/coredump"
|
||||
{
|
||||
directory = "/var/lib/private";
|
||||
mode = "u=rwx,g=,o=";
|
||||
}
|
||||
"/etc/NetworkManager/system-connections"
|
||||
{
|
||||
directory = "/etc/nix";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "u=rwx,g=rx,o=rx";
|
||||
}
|
||||
];
|
||||
# files = [
|
||||
# "/etc/machine-id"
|
||||
# { file = "/etc/nix/id_rsa"; parentDirectory = { mode = "u=rwx,g=,o="; }; }
|
||||
# ];
|
||||
};
|
||||
|
||||
security.sudo.extraConfig = ''
|
||||
# rollback results in sudo lectures after each reboot
|
||||
Defaults lecture = never
|
||||
'';
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{ ... }:
|
||||
{
|
||||
sops = {
|
||||
defaultSopsFile = ../../secrets/secrets.yaml;
|
||||
age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
||||
|
||||
secrets = {
|
||||
"wifi" = { };
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,310 +0,0 @@
|
||||
# /etc/nixos/modules/ups-monitor/default.nix
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.ups-monitor;
|
||||
|
||||
pythonScript = pkgs.writeText "ups_monitor.py" ''
|
||||
import smbus
|
||||
import time
|
||||
import logging
|
||||
import json
|
||||
from datetime import datetime
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sqlite3
|
||||
import signal
|
||||
import sys
|
||||
|
||||
class INA219:
|
||||
def __init__(self, i2c_bus=1, addr=0x40):
|
||||
self.bus = smbus.SMBus(i2c_bus)
|
||||
self.addr = addr
|
||||
self._cal_value = 0
|
||||
self._current_lsb = 0
|
||||
self._power_lsb = 0
|
||||
self.set_calibration_32V_2A()
|
||||
|
||||
def read(self,address):
|
||||
data = self.bus.read_i2c_block_data(self.addr, address, 2)
|
||||
return ((data[0] * 256 ) + data[1])
|
||||
|
||||
def write(self,address,data):
|
||||
temp = [0,0]
|
||||
temp[1] = data & 0xFF
|
||||
temp[0] =(data & 0xFF00) >> 8
|
||||
self.bus.write_i2c_block_data(self.addr,address,temp)
|
||||
|
||||
def set_calibration_32V_2A(self):
|
||||
self._current_lsb = .1
|
||||
self._cal_value = 4096
|
||||
self._power_lsb = .002
|
||||
self.write(0x05, self._cal_value)
|
||||
self.bus_voltage_range = 0x01
|
||||
self.gain = 0x03
|
||||
self.bus_adc_resolution = 0x0D
|
||||
self.shunt_adc_resolution = 0x0D
|
||||
self.mode = 0x07
|
||||
self.config = self.bus_voltage_range << 13 | \
|
||||
self.gain << 11 | \
|
||||
self.bus_adc_resolution << 7 | \
|
||||
self.shunt_adc_resolution << 3 | \
|
||||
self.mode
|
||||
self.write(0x00, self.config)
|
||||
|
||||
def getBusVoltage_V(self):
|
||||
self.write(0x05, self._cal_value)
|
||||
self.read(0x02)
|
||||
return (self.read(0x02) >> 3) * 0.004
|
||||
|
||||
def getShuntVoltage_mV(self):
|
||||
self.write(0x05, self._cal_value)
|
||||
value = self.read(0x01)
|
||||
if value > 32767:
|
||||
value -= 65535
|
||||
return value * 0.01
|
||||
|
||||
def getCurrent_mA(self):
|
||||
value = self.read(0x04)
|
||||
if value > 32767:
|
||||
value -= 65535
|
||||
return value * self._current_lsb
|
||||
|
||||
def getPower_W(self):
|
||||
self.write(0x05, self._cal_value)
|
||||
value = self.read(0x03)
|
||||
if value > 32767:
|
||||
value -= 65535
|
||||
return value * self._power_lsb
|
||||
|
||||
class UPSMonitor:
|
||||
def __init__(self, i2c_address, log_interval, battery_warning_threshold,
|
||||
voltage_warning_threshold, log_dir):
|
||||
self.ina219 = INA219(addr=i2c_address)
|
||||
self.log_interval = log_interval
|
||||
self.battery_warning_threshold = battery_warning_threshold
|
||||
self.voltage_warning_threshold = voltage_warning_threshold
|
||||
self.log_dir = Path(log_dir)
|
||||
self.running = True
|
||||
|
||||
self.log_dir.mkdir(parents=True, exist_ok=True)
|
||||
self._setup_logging()
|
||||
self._setup_database()
|
||||
|
||||
signal.signal(signal.SIGINT, self._signal_handler)
|
||||
signal.signal(signal.SIGTERM, self._signal_handler)
|
||||
|
||||
def _setup_logging(self):
|
||||
self.logger = logging.getLogger('UPSMonitor')
|
||||
self.logger.setLevel(logging.INFO)
|
||||
|
||||
fh = logging.FileHandler(self.log_dir / 'ups_monitor.log')
|
||||
fh.setLevel(logging.INFO)
|
||||
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.INFO)
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
||||
fh.setFormatter(formatter)
|
||||
ch.setFormatter(formatter)
|
||||
|
||||
self.logger.addHandler(fh)
|
||||
self.logger.addHandler(ch)
|
||||
|
||||
def _setup_database(self):
|
||||
db_path = self.log_dir / 'ups_metrics.db'
|
||||
self.conn = sqlite3.connect(str(db_path))
|
||||
cursor = self.conn.cursor()
|
||||
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS metrics (
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
bus_voltage REAL,
|
||||
shunt_voltage REAL,
|
||||
current REAL,
|
||||
power REAL,
|
||||
battery_percentage REAL
|
||||
)
|
||||
''')
|
||||
self.conn.commit()
|
||||
|
||||
def _signal_handler(self, signum, frame):
|
||||
self.logger.info("Received shutdown signal, cleaning up...")
|
||||
self.running = False
|
||||
self.conn.close()
|
||||
sys.exit(0)
|
||||
|
||||
def _calculate_battery_percentage(self, voltage):
|
||||
p = (voltage - 6) / 2.4 * 100
|
||||
return max(0, min(100, p))
|
||||
|
||||
def _check_thresholds(self, voltage, battery_percentage):
|
||||
if battery_percentage <= self.battery_warning_threshold:
|
||||
self.logger.warning(
|
||||
f"Low battery warning: {battery_percentage:.1f}%")
|
||||
|
||||
if voltage <= self.voltage_warning_threshold:
|
||||
self.logger.warning(
|
||||
f"Low voltage warning: {voltage:.2f}V")
|
||||
|
||||
def _store_metrics(self, metrics):
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute('''
|
||||
INSERT INTO metrics (
|
||||
bus_voltage, shunt_voltage, current, power, battery_percentage
|
||||
) VALUES (?, ?, ?, ?, ?)
|
||||
''', (
|
||||
metrics['bus_voltage'],
|
||||
metrics['shunt_voltage'],
|
||||
metrics['current'],
|
||||
metrics['power'],
|
||||
metrics['battery_percentage']
|
||||
))
|
||||
self.conn.commit()
|
||||
|
||||
def get_metrics(self):
|
||||
bus_voltage = self.ina219.getBusVoltage_V()
|
||||
shunt_voltage = self.ina219.getShuntVoltage_mV() / 1000
|
||||
current = self.ina219.getCurrent_mA() / 1000
|
||||
power = self.ina219.getPower_W()
|
||||
battery_percentage = self._calculate_battery_percentage(bus_voltage)
|
||||
|
||||
return {
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'bus_voltage': bus_voltage,
|
||||
'shunt_voltage': shunt_voltage,
|
||||
'current': current,
|
||||
'power': power,
|
||||
'battery_percentage': battery_percentage
|
||||
}
|
||||
|
||||
def run(self):
|
||||
self.logger.info("Starting UPS monitoring service...")
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
metrics = self.get_metrics()
|
||||
self._store_metrics(metrics)
|
||||
self._check_thresholds(
|
||||
metrics['bus_voltage'],
|
||||
metrics['battery_percentage']
|
||||
)
|
||||
|
||||
self.logger.info(
|
||||
f"Status: {metrics['battery_percentage']:.1f}% | "
|
||||
f"Voltage: {metrics['bus_voltage']:.2f}V | "
|
||||
f"Current: {metrics['current']:.3f}A | "
|
||||
f"Power: {metrics['power']:.2f}W"
|
||||
)
|
||||
|
||||
time.sleep(self.log_interval)
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error in monitoring loop: {str(e)}")
|
||||
time.sleep(self.log_interval)
|
||||
|
||||
if __name__ == '__main__':
|
||||
monitor = UPSMonitor(
|
||||
i2c_address=int(os.getenv('UPS_I2C_ADDRESS', '0x42'), 16),
|
||||
log_interval=int(os.getenv('UPS_LOG_INTERVAL', '2')),
|
||||
battery_warning_threshold=float(os.getenv('UPS_BATTERY_WARNING_THRESHOLD', '20')),
|
||||
voltage_warning_threshold=float(os.getenv('UPS_VOLTAGE_WARNING_THRESHOLD', '6.5')),
|
||||
log_dir=os.getenv('UPS_LOG_DIR', '/var/log/ups_monitor')
|
||||
)
|
||||
monitor.run()
|
||||
'';
|
||||
|
||||
pythonEnv = pkgs.python3.withPackages (ps: with ps; [
|
||||
smbus2
|
||||
]);
|
||||
|
||||
in {
|
||||
options.services.ups-monitor = {
|
||||
enable = mkEnableOption "UPS HAT monitoring service";
|
||||
|
||||
i2cAddress = mkOption {
|
||||
type = types.str;
|
||||
default = "0x42";
|
||||
description = "I2C address of the UPS HAT";
|
||||
};
|
||||
|
||||
logInterval = mkOption {
|
||||
type = types.int;
|
||||
default = 2;
|
||||
description = "Interval between log entries in seconds";
|
||||
};
|
||||
|
||||
batteryWarningThreshold = mkOption {
|
||||
type = types.float;
|
||||
default = 20.0;
|
||||
description = "Battery percentage threshold for warnings";
|
||||
};
|
||||
|
||||
voltageWarningThreshold = mkOption {
|
||||
type = types.float;
|
||||
default = 6.5;
|
||||
description = "Voltage threshold for warnings";
|
||||
};
|
||||
|
||||
logDir = mkOption {
|
||||
type = types.str;
|
||||
default = "/var/log/ups_monitor";
|
||||
description = "Directory for storing logs and metrics";
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "root";
|
||||
description = "User to run the service as";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "root";
|
||||
description = "Group to run the service as";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.ups-monitor = {
|
||||
description = "UPS HAT Monitoring Service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
environment = {
|
||||
UPS_I2C_ADDRESS = cfg.i2cAddress;
|
||||
UPS_LOG_INTERVAL = toString cfg.logInterval;
|
||||
UPS_BATTERY_WARNING_THRESHOLD = toString cfg.batteryWarningThreshold;
|
||||
UPS_VOLTAGE_WARNING_THRESHOLD = toString cfg.voltageWarningThreshold;
|
||||
UPS_LOG_DIR = cfg.logDir;
|
||||
PYTHONPATH = "${pythonEnv}/${pythonEnv.python.sitePackages}";
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${pythonEnv}/bin/python3 ${pythonScript}";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
Restart = "always";
|
||||
RestartSec = "10s";
|
||||
|
||||
# Hardening options
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
ReadWritePaths = [ cfg.logDir ];
|
||||
CapabilityBoundingSet = [ "CAP_SYS_RAWIO" ];
|
||||
DeviceAllow = [ "/dev/i2c-1 rw" ];
|
||||
};
|
||||
};
|
||||
|
||||
# Ensure the log directory exists and has correct permissions
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '${cfg.logDir}' 0750 ${cfg.user} ${cfg.group} -"
|
||||
];
|
||||
|
||||
# Enable I2C
|
||||
hardware.i2c.enable = true;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user