This commit is contained in:
mjallen18
2025-05-08 15:40:47 -05:00
parent b1c1d6f04c
commit 2b2fa1bdbc
12 changed files with 327 additions and 487 deletions

367
flake.lock generated
View File

@@ -1,5 +1,92 @@
{ {
"nodes": { "nodes": {
"Pi5-home-manager": {
"inputs": {
"nixpkgs": [
"Pi5-nixpkgs"
]
},
"locked": {
"lastModified": 1746632058,
"narHash": "sha256-Mp5Bbvb+YlFEZ76C/0wFS6C1lRfH3D60u465wFNlnS0=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "708074ae6db9e0468e4f48477f856e8c2d059795",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"Pi5-impermanence": {
"locked": {
"lastModified": 1737831083,
"narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=",
"owner": "nix-community",
"repo": "impermanence",
"rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "impermanence",
"type": "github"
}
},
"Pi5-nixos-hardware": {
"locked": {
"lastModified": 1746621361,
"narHash": "sha256-T9vOxEqI1j1RYugV0b9dgy0AreiZ9yBDKZJYyclF0og=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "2ea3ad8a1f26a76f8a8e23fc4f7757c46ef30ee5",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "master",
"repo": "nixos-hardware",
"type": "github"
}
},
"Pi5-nixpkgs": {
"locked": {
"lastModified": 1746461020,
"narHash": "sha256-7+pG1I9jvxNlmln4YgnlW4o+w0TZX24k688mibiFDUE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3730d8a308f94996a9ba7c7138ede69c1b9ac4ae",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"Pi5-sops-nix": {
"inputs": {
"nixpkgs": [
"Pi5-nixpkgs"
]
},
"locked": {
"lastModified": 1746485181,
"narHash": "sha256-PxrrSFLaC7YuItShxmYbMgSuFFuwxBB+qsl9BZUnRvg=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "e93ee1d900ad264d65e9701a5c6f895683433386",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"authentik-src": { "authentik-src": {
"flake": false, "flake": false,
"locked": { "locked": {
@@ -644,6 +731,40 @@
"type": "github" "type": "github"
} }
}, },
"libcamera-src": {
"flake": false,
"locked": {
"lastModified": 1725630279,
"narHash": "sha256-KH30jmHfxXq4j2CL7kv18DYECJRp9ECuWNPnqPZajPA=",
"owner": "raspberrypi",
"repo": "libcamera",
"rev": "69a894c4adad524d3063dd027f5c4774485cf9db",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"repo": "libcamera",
"rev": "69a894c4adad524d3063dd027f5c4774485cf9db",
"type": "github"
}
},
"libpisp-src": {
"flake": false,
"locked": {
"lastModified": 1724944683,
"narHash": "sha256-Fo2UJmQHS855YSSKKmGrsQnJzXog1cdpkIOO72yYAM4=",
"owner": "raspberrypi",
"repo": "libpisp",
"rev": "28196ed6edcfeda88d23cc5f213d51aa6fa17bb3",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "v1.0.7",
"repo": "libpisp",
"type": "github"
}
},
"napalm": { "napalm": {
"inputs": { "inputs": {
"flake-utils": [ "flake-utils": [
@@ -699,7 +820,7 @@
"inputs": { "inputs": {
"flake-compat": "flake-compat_3", "flake-compat": "flake-compat_3",
"nixpkgs": [ "nixpkgs": [
"nas-nixpkgs" "nas-nixpkgs-stable"
], ],
"nixpkgs-stable": "nixpkgs-stable_2", "nixpkgs-stable": "nixpkgs-stable_2",
"rust-overlay": "rust-overlay_2" "rust-overlay": "rust-overlay_2"
@@ -1137,93 +1258,6 @@
"type": "github" "type": "github"
} }
}, },
"pi4-home-manager": {
"inputs": {
"nixpkgs": [
"pi4-nixpkgs"
]
},
"locked": {
"lastModified": 1742416832,
"narHash": "sha256-ycok0eJJcoknqaibdv/TEEEOUqovC42XCqbfLDYmnoQ=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "eb0f617aecbaf1eff5bacec789891e775af2f5a3",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"pi4-impermanence": {
"locked": {
"lastModified": 1737831083,
"narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=",
"owner": "nix-community",
"repo": "impermanence",
"rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "impermanence",
"type": "github"
}
},
"pi4-nixos-hardware": {
"locked": {
"lastModified": 1742376361,
"narHash": "sha256-VFMgJkp/COvkt5dnkZB4D2szVdmF6DGm5ZdVvTUy61c=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "daaae13dff0ecc692509a1332ff9003d9952d7a9",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "master",
"repo": "nixos-hardware",
"type": "github"
}
},
"pi4-nixpkgs": {
"locked": {
"lastModified": 1742288794,
"narHash": "sha256-Txwa5uO+qpQXrNG4eumPSD+hHzzYi/CdaM80M9XRLCo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b6eaf97c6960d97350c584de1b6dcff03c9daf42",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"pi4-sops-nix": {
"inputs": {
"nixpkgs": [
"pi4-nixpkgs"
]
},
"locked": {
"lastModified": 1742406979,
"narHash": "sha256-r0aq70/3bmfjTP+JZs4+XV5SgmCtk1BLU4CQPWGtA7o=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "1770be8ad89e41f1ed5a60ce628dd10877cb3609",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"poetry2nix": { "poetry2nix": {
"inputs": { "inputs": {
"flake-utils": [ "flake-utils": [
@@ -1336,8 +1370,40 @@
"type": "github" "type": "github"
} }
}, },
"raspberry-pi-nix": {
"inputs": {
"libcamera-src": "libcamera-src",
"libpisp-src": "libpisp-src",
"nixpkgs": "nixpkgs_2",
"rpi-bluez-firmware-src": "rpi-bluez-firmware-src",
"rpi-firmware-nonfree-src": "rpi-firmware-nonfree-src",
"rpi-firmware-src": "rpi-firmware-src",
"rpi-linux-6_12_17-src": "rpi-linux-6_12_17-src",
"rpi-linux-6_6_78-src": "rpi-linux-6_6_78-src",
"rpi-linux-stable-src": "rpi-linux-stable-src",
"rpicam-apps-src": "rpicam-apps-src"
},
"locked": {
"lastModified": 1742223591,
"narHash": "sha256-ZNTz8r5jlJ1jvpqf5+aUYgpnYJSVX0iP14doOc1Hm0E=",
"owner": "nix-community",
"repo": "raspberry-pi-nix",
"rev": "3e8100d5e976a6a2be363015cb33463af9ef441a",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "raspberry-pi-nix",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"Pi5-home-manager": "Pi5-home-manager",
"Pi5-impermanence": "Pi5-impermanence",
"Pi5-nixos-hardware": "Pi5-nixos-hardware",
"Pi5-nixpkgs": "Pi5-nixpkgs",
"Pi5-sops-nix": "Pi5-sops-nix",
"desktop-chaotic": "desktop-chaotic", "desktop-chaotic": "desktop-chaotic",
"desktop-home-manager": "desktop-home-manager", "desktop-home-manager": "desktop-home-manager",
"desktop-impermanence": "desktop-impermanence", "desktop-impermanence": "desktop-impermanence",
@@ -1359,11 +1425,7 @@
"nix-darwin": "nix-darwin", "nix-darwin": "nix-darwin",
"nixpkgs-stable": "nixpkgs-stable_4", "nixpkgs-stable": "nixpkgs-stable_4",
"nixpkgs-unstable": "nixpkgs-unstable", "nixpkgs-unstable": "nixpkgs-unstable",
"pi4-home-manager": "pi4-home-manager", "raspberry-pi-nix": "raspberry-pi-nix",
"pi4-impermanence": "pi4-impermanence",
"pi4-nixos-hardware": "pi4-nixos-hardware",
"pi4-nixpkgs": "pi4-nixpkgs",
"pi4-sops-nix": "pi4-sops-nix",
"steamdeck-chaotic": "steamdeck-chaotic", "steamdeck-chaotic": "steamdeck-chaotic",
"steamdeck-home-manager": "steamdeck-home-manager", "steamdeck-home-manager": "steamdeck-home-manager",
"steamdeck-impermanence": "steamdeck-impermanence", "steamdeck-impermanence": "steamdeck-impermanence",
@@ -1375,6 +1437,125 @@
"steamdeck-steam-rom-manager": "steamdeck-steam-rom-manager" "steamdeck-steam-rom-manager": "steamdeck-steam-rom-manager"
} }
}, },
"rpi-bluez-firmware-src": {
"flake": false,
"locked": {
"lastModified": 1708969706,
"narHash": "sha256-KakKnOBeWxh0exu44beZ7cbr5ni4RA9vkWYb9sGMb8Q=",
"owner": "RPi-Distro",
"repo": "bluez-firmware",
"rev": "78d6a07730e2d20c035899521ab67726dc028e1c",
"type": "github"
},
"original": {
"owner": "RPi-Distro",
"ref": "bookworm",
"repo": "bluez-firmware",
"type": "github"
}
},
"rpi-firmware-nonfree-src": {
"flake": false,
"locked": {
"lastModified": 1723266537,
"narHash": "sha256-T7eTKXqY9cxEMdab8Snda4CEOrEihy5uOhA6Fy+Mhnw=",
"owner": "RPi-Distro",
"repo": "firmware-nonfree",
"rev": "4b356e134e8333d073bd3802d767a825adec3807",
"type": "github"
},
"original": {
"owner": "RPi-Distro",
"ref": "bookworm",
"repo": "firmware-nonfree",
"type": "github"
}
},
"rpi-firmware-src": {
"flake": false,
"locked": {
"lastModified": 1728405098,
"narHash": "sha256-4gnK0KbqFnjBmWia9Jt2gveVWftmHrprpwBqYVqE/k0=",
"owner": "raspberrypi",
"repo": "firmware",
"rev": "7bbb5f80d20a2335066a8781459c9f33e5eebc64",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "1.20241008",
"repo": "firmware",
"type": "github"
}
},
"rpi-linux-6_12_17-src": {
"flake": false,
"locked": {
"lastModified": 1740765145,
"narHash": "sha256-hoCsGc4+RC/2LmxDtswLBL5ZhWlw4vSiL4Vkl39r2MU=",
"owner": "raspberrypi",
"repo": "linux",
"rev": "5985ce32e511f4e8279a841a1b06a8c7d972b386",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "rpi-6.12.y",
"repo": "linux",
"type": "github"
}
},
"rpi-linux-6_6_78-src": {
"flake": false,
"locked": {
"lastModified": 1740503700,
"narHash": "sha256-Y8+ot4Yi3UKwlZK3ap15rZZ16VZDvmeFkD46+6Ku7bE=",
"owner": "raspberrypi",
"repo": "linux",
"rev": "2e071057fded90e789c0101498e45a1778be93fe",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "rpi-6.6.y",
"repo": "linux",
"type": "github"
}
},
"rpi-linux-stable-src": {
"flake": false,
"locked": {
"lastModified": 1728403745,
"narHash": "sha256-phCxkuO+jUGZkfzSrBq6yErQeO2Td+inIGHxctXbD5U=",
"owner": "raspberrypi",
"repo": "linux",
"rev": "5aeecea9f4a45248bcf564dec924965e066a7bfd",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "stable_20241008",
"repo": "linux",
"type": "github"
}
},
"rpicam-apps-src": {
"flake": false,
"locked": {
"lastModified": 1727515047,
"narHash": "sha256-qCYGrcibOeGztxf+sd44lD6VAOGoUNwRqZDdAmcTa/U=",
"owner": "raspberrypi",
"repo": "rpicam-apps",
"rev": "a8ccf9f3cd9df49875dfb834a2b490d41d226031",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "v1.5.2",
"repo": "rpicam-apps",
"type": "github"
}
},
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false, "flake": false,
"locked": { "locked": {

View File

@@ -69,12 +69,13 @@
# Authentik # Authentik
nas-authentik-nix = { nas-authentik-nix = {
url = "github:nix-community/authentik-nix"; url = "github:nix-community/authentik-nix";
inputs.nixpkgs.follows = "nas-nixpkgs";
}; };
# cosmic launcher # cosmic launcher
nas-cosmic = { nas-cosmic = {
url = "github:lilyinstarlight/nixos-cosmic"; url = "github:lilyinstarlight/nixos-cosmic";
inputs.nixpkgs.follows = "nas-nixpkgs"; inputs.nixpkgs.follows = "nas-nixpkgs-stable";
}; };
# crowdsec # crowdsec
@@ -113,36 +114,38 @@
}; };
##################################################### #####################################################
# Pi4 # # Pi5 #
##################################################### #####################################################
# nixpgs # nixpgs
pi4-nixpkgs = { Pi5-nixpkgs = {
url = "github:NixOS/nixpkgs/nixos-unstable"; url = "github:NixOS/nixpkgs/nixos-24.11";
}; };
# Home Manager # Home Manager
pi4-home-manager = { Pi5-home-manager = {
url = "github:nix-community/home-manager"; url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "pi4-nixpkgs"; inputs.nixpkgs.follows = "Pi5-nixpkgs";
}; };
# Impermenance # Impermenance
pi4-impermanence = { Pi5-impermanence = {
url = "github:nix-community/impermanence"; url = "github:nix-community/impermanence";
}; };
# Nix hardware # Nix hardware
pi4-nixos-hardware = { Pi5-nixos-hardware = {
url = "github:NixOS/nixos-hardware/master"; url = "github:NixOS/nixos-hardware/master";
}; };
# Sops-nix # Sops-nix
pi4-sops-nix = { Pi5-sops-nix = {
url = "github:Mic92/sops-nix"; url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "pi4-nixpkgs"; inputs.nixpkgs.follows = "Pi5-nixpkgs";
}; };
raspberry-pi-nix.url = "github:nix-community/raspberry-pi-nix";
##################################################### #####################################################
# Steamdeck # # Steamdeck #
##################################################### #####################################################
@@ -247,12 +250,13 @@
nas-nixos-hardware, nas-nixos-hardware,
nas-sops-nix, nas-sops-nix,
# Pi4 # Pi5
pi4-nixpkgs, Pi5-nixpkgs,
pi4-home-manager, Pi5-home-manager,
pi4-impermanence, Pi5-impermanence,
pi4-nixos-hardware, Pi5-nixos-hardware,
pi4-sops-nix, Pi5-sops-nix,
raspberry-pi-nix,
# Steamdeck # Steamdeck
steamdeck-nixpkgs, steamdeck-nixpkgs,
@@ -379,16 +383,18 @@
]; ];
}; };
# Pi4 # Pi5
"pi4" = pi4-nixpkgs.lib.nixosSystem { "pi5" = Pi5-nixpkgs.lib.nixosSystem {
system = "aarch64-linux"; system = "aarch64-linux";
modules = [ modules = [
pi4-nixos-hardware.nixosModules.raspberry-pi-4 Pi5-nixos-hardware.nixosModules.raspberry-pi-4
pi4-impermanence.nixosModules.impermanence Pi5-impermanence.nixosModules.impermanence
./hosts/pi4/configuration.nix ./hosts/pi5/configuration.nix
pi4-sops-nix.nixosModules.sops Pi5-sops-nix.nixosModules.sops
raspberry-pi-nix.nixosModules.raspberry-pi
raspberry-pi-nix.nixosModules.sd-image
pi4-home-manager.nixosModules.home-manager Pi5-home-manager.nixosModules.home-manager
{ {
home-manager.useGlobalPkgs = true; home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true; home-manager.useUserPackages = true;
@@ -396,8 +402,8 @@
{ ... }: { ... }:
{ {
imports = [ imports = [
./hosts/pi4/home.nix ./hosts/pi5/home.nix
pi4-sops-nix.homeManagerModules.sops Pi5-sops-nix.homeManagerModules.sops
]; ];
}; };
} }

View File

@@ -1,10 +0,0 @@
{ ... }:
{
services.adguardhome = {
enable = true;
allowDHCP = true;
port = 3000;
openFirewall = true;
mutableSettings = true;
};
}

View File

@@ -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;
};
};
}

View File

@@ -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"
];
};
}

View File

@@ -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;
};
}

18
hosts/pi5/boot.nix Executable file
View File

@@ -0,0 +1,18 @@
{ pkgs, lib, ... }:
{
boot = {
kernelPackages = lib.mkDefault pkgs.linuxKernel.packages.linux_rpi4;
initrd.availableKernelModules = [
"usbhid"
"usb_storage"
"vc4"
"pcie_brcmstb" # required for the pcie bus to work
"reset-raspberrypi" # required for vl805 firmware to load
];
loader = {
grub.enable = lib.mkDefault false;
generic-extlinux-compatible.enable = lib.mkForce true;
};
};
}

View File

@@ -11,22 +11,19 @@ let
wifiSecrets = config.sops.secrets."wifi-password".path; wifiSecrets = config.sops.secrets."wifi-password".path;
interface = "wlan0"; interface = "wlan0";
timezone = "America/Chicago"; timezone = "America/Chicago";
hostname = "pi4"; hostname = "pi5";
in in
{ {
imports = [ imports = [
# Include the results of the hardware scan.
./adguard.nix
./argononed.nix
./boot.nix ./boot.nix
./hardware-configuration.nix # ./hardware-configuration.nix
./impermanence.nix ./impermanence.nix
# ./sops.nix # ./sops.nix
./ups-monitor.nix
../default.nix ../default.nix
]; ];
raspberry-pi-nix.board = lib.mkForce "bcm2712";
# Enable nix flakes and nix-command tools # Enable nix flakes and nix-command tools
nix = { nix = {
settings = { settings = {
@@ -62,12 +59,6 @@ in
}; };
}; };
services.hardware.argonone.enable = true;
services.ups-monitor = {
enable = false;
};
hardware = { hardware = {
raspberry-pi."4".fkms-3d.enable = false; raspberry-pi."4".fkms-3d.enable = false;
raspberry-pi."4".apply-overlays-dtmerge.enable = false; raspberry-pi."4".apply-overlays-dtmerge.enable = false;