Fix UPS functionality for multiple devices

This commit is contained in:
tim
2026-05-02 23:25:15 +02:00
parent a74934c439
commit 75564f96f0
2 changed files with 211 additions and 40 deletions
+79 -10
View File
@@ -9,6 +9,7 @@ import socket
from collections import deque
from bmspy import client
from bmspy.classes import UPS, BMSScalarField
DAEMON_UPDATE_PERIOD = 30
@@ -18,6 +19,46 @@ warning_sent = False
alert_sent = False
def _get_field_value(device: UPS, field_name: str) -> float | None:
"""Return the raw_value of a named BMSScalarField from a UPS, or None if not found."""
for name, field in device.items():
if name == field_name and isinstance(field, BMSScalarField):
return field.raw_value
return None
def _resolve_ups_device(data: dict[str, UPS], requested: str | None) -> str | None:
"""Return the device name to monitor, or None and print an error if the selection is invalid.
Rules:
- No devices → error.
- requested is set and found → use it.
- requested is set but not found → error listing available devices.
- requested is None and exactly one device → use it.
- requested is None and multiple devices → error; user must specify one.
"""
if not data:
print("Error: no UPS devices found")
return None
if requested is not None:
if requested not in data:
print(
"Error: UPS '{}' not found. Available: {}".format(
requested, ", ".join(sorted(data))
)
)
return None
return requested
if len(data) > 1:
print(
"Error: multiple UPS devices found, specify one with --device: {}".format(
", ".join(sorted(data))
)
)
return None
return next(iter(data))
def handle_shutdown(action: str = "cancel", delay: int = 0, debug: int = 0) -> None:
"""Schedule or cancel a system shutdown; only schedules once per incident."""
global scheduled_shutdown
@@ -157,6 +198,14 @@ def main() -> None:
default="/run/bmspy/bms",
help="Socket to communicate with daemon",
)
parser.add_argument(
"--device",
dest="device",
action="store",
default=None,
metavar="NAME",
help="Name of the UPS device to monitor (required if multiple devices are available)",
)
parser.add_argument(
"--verbose",
"-v",
@@ -173,10 +222,19 @@ def main() -> None:
client.handle_registration(args.socket, "ups", debug)
atexit.register(client.handle_registration, args.socket, "ups", debug)
initial_data = client.read_data(args.socket, "ups")
device_name = _resolve_ups_device(initial_data, args.device)
if device_name is None:
return
history = deque()
while True:
data = client.read_data(args.socket, "ups")
history.append(data)
data = client.read_data(args.socket, "ups", device=device_name)
device_obj = data.get(device_name)
if device_obj is None:
time.sleep(DAEMON_UPDATE_PERIOD)
continue
history.append(device_obj)
# Remove the oldest data from the history
while len(history) > 10:
@@ -192,19 +250,30 @@ def main() -> None:
time.sleep(DAEMON_UPDATE_PERIOD)
continue
current_amps = float(data["bms_current_amps"]["raw_value"])
charge_ratio = float(data["bms_capacity_charge_ratio"]["raw_value"]) * 100
comparison_1_current_amps = float(comparison_1["bms_current_amps"]["raw_value"])
current_amps = float(_get_field_value(device_obj, "bms_current_amps") or 0.0)
charge_ratio = (
float(_get_field_value(device_obj, "bms_capacity_charge_ratio") or 0.0) * 100
)
comparison_1_current_amps = float(
_get_field_value(comparison_1, "bms_current_amps") or 0.0
)
comparison_1_charge_ratio = (
float(comparison_1["bms_capacity_charge_ratio"]["raw_value"]) * 100
float(_get_field_value(comparison_1, "bms_capacity_charge_ratio") or 0.0)
* 100
)
comparison_2_current_amps = float(
_get_field_value(comparison_2, "bms_current_amps") or 0.0
)
comparison_2_current_amps = float(comparison_2["bms_current_amps"]["raw_value"])
comparison_2_charge_ratio = (
float(comparison_2["bms_capacity_charge_ratio"]["raw_value"]) * 100
float(_get_field_value(comparison_2, "bms_capacity_charge_ratio") or 0.0)
* 100
)
comparison_3_current_amps = float(
_get_field_value(comparison_3, "bms_current_amps") or 0.0
)
comparison_3_current_amps = float(comparison_3["bms_current_amps"]["raw_value"])
comparison_3_charge_ratio = (
float(comparison_3["bms_capacity_charge_ratio"]["raw_value"]) * 100
float(_get_field_value(comparison_3, "bms_capacity_charge_ratio") or 0.0)
* 100
)
if debug > 1: