Add required battery_size to devices, filter install panels by size

This commit is contained in:
2026-04-19 14:48:55 -05:00
parent aabe273172
commit 3e75bb3ab4
8 changed files with 238 additions and 77 deletions
+58 -22
View File
@@ -634,8 +634,10 @@ def create_app(config_object="config"):
devices = db.query(Device).order_by(Device.name).all()
device_types = sorted({d.device_type for d in devices if d.device_type})
device_locations = sorted({d.location for d in devices if d.location})
device_battery_sizes = sorted({d.battery_size for d in devices if d.battery_size})
return render_template("device_list.html", devices=devices,
device_types=device_types, device_locations=device_locations)
device_types=device_types, device_locations=device_locations,
device_battery_sizes=device_battery_sizes)
# ------------------------------------------------------------------ #
# Devices — add
@@ -646,19 +648,31 @@ def create_app(config_object="config"):
all_devices = db.query(Device).all()
device_types = sorted({d.device_type for d in all_devices if d.device_type})
device_locations = sorted({d.location for d in all_devices if d.location})
device_battery_sizes = sorted({d.battery_size for d in all_devices if d.battery_size})
if request.method == "POST":
name = request.form.get("name", "").strip()
slots_raw = request.form.get("battery_slots", "1").strip()
notes = request.form.get("notes", "").strip() or None
device_type = request.form.get("device_type", "").strip() or None
battery_size = request.form.get("battery_size", "").strip() or None
location = request.form.get("location", "").strip() or None
if not name:
flash("Device name is required.", "error")
return render_template("device_add.html",
device_types=device_types,
device_locations=device_locations), 400
device_locations=device_locations,
device_battery_sizes=device_battery_sizes), 400
if not battery_size:
flash("Battery size is required.", "error")
return render_template("device_add.html",
device_types=device_types,
device_locations=device_locations,
device_battery_sizes=device_battery_sizes,
form_name=name, form_notes=notes or "",
form_device_type=request.form.get("device_type", "")), 400
try:
slots = int(slots_raw)
@@ -669,6 +683,7 @@ def create_app(config_object="config"):
return render_template("device_add.html",
device_types=device_types,
device_locations=device_locations,
device_battery_sizes=device_battery_sizes,
form_name=name, form_notes=notes or "",
form_device_type=request.form.get("device_type", "")), 400
@@ -677,19 +692,22 @@ def create_app(config_object="config"):
return render_template("device_add.html",
device_types=device_types,
device_locations=device_locations,
device_battery_sizes=device_battery_sizes,
form_name=name, form_slots=slots,
form_notes=notes or "",
form_device_type=request.form.get("device_type", "")), 400
device = Device(name=name, battery_slots=slots, notes=notes,
device_type=device_type, location=location)
device_type=device_type, battery_size=battery_size,
location=location)
db.add(device)
db.commit()
flash(f"Device '{name}' added.", "success")
return redirect(url_for("device_list"))
return render_template("device_add.html", device_types=device_types,
device_locations=device_locations)
device_locations=device_locations,
device_battery_sizes=device_battery_sizes)
# ------------------------------------------------------------------ #
# Devices — detail
@@ -700,12 +718,22 @@ def create_app(config_object="config"):
device = db.get(Device, device_id)
if device is None:
abort(404)
brands = [r[0] for r in db.query(Battery.brand).distinct().order_by(Battery.brand).all()]
available_batteries = (db.query(Battery)
.filter_by(status="available")
.order_by(Battery.label).all())
device_types = sorted({d.device_type for d in db.query(Device).all() if d.device_type})
device_locations = sorted({d.location for d in db.query(Device).all() if d.location})
all_devices = db.query(Device).all()
brands_q = db.query(Battery.brand).filter(Battery.status == "available")
if device.battery_size:
brands_q = brands_q.filter(
(Battery.size == device.battery_size) | (Battery.size == None)
)
brands = [r[0] for r in brands_q.distinct().order_by(Battery.brand).all()]
avail_q = db.query(Battery).filter_by(status="available")
if device.battery_size:
avail_q = avail_q.filter(
(Battery.size == device.battery_size) | (Battery.size == None)
)
available_batteries = avail_q.order_by(Battery.label).all()
device_types = sorted({d.device_type for d in all_devices if d.device_type})
device_locations = sorted({d.location for d in all_devices if d.location})
device_battery_sizes = sorted({d.battery_size for d in all_devices if d.battery_size})
ha_live_pct = None
if ha_client.enabled and device.ha_entity_id:
ha_live_pct = ha_client.get_state(device.ha_entity_id, timeout=1)
@@ -727,6 +755,7 @@ def create_app(config_object="config"):
available_batteries=available_batteries,
device_types=device_types,
device_locations=device_locations,
device_battery_sizes=device_battery_sizes,
ha_enabled=ha_client.enabled,
ha_live_pct=ha_live_pct)
@@ -763,6 +792,7 @@ def create_app(config_object="config"):
device.battery_slots = slots
device.notes = notes
device.device_type = device_type
device.battery_size = request.form.get("battery_size", "").strip() or None
device.location = request.form.get("location", "").strip() or None
device.ha_entity_id = request.form.get("ha_entity_id", "").strip() or None
db.commit()
@@ -807,11 +837,12 @@ def create_app(config_object="config"):
# Validate availability before writing anything
for brand, qty in pairs:
available_count = (
db.query(func.count(Battery.id))
.filter_by(brand=brand, status="available")
.scalar()
)
avail_q = db.query(func.count(Battery.id)).filter_by(brand=brand, status="available")
if device.battery_size:
avail_q = avail_q.filter(
(Battery.size == device.battery_size) | (Battery.size == None)
)
available_count = avail_q.scalar()
if available_count < qty:
flash(
f"Need {qty} {brand}, but only {available_count} available.",
@@ -822,13 +853,12 @@ def create_app(config_object="config"):
# All checks passed — perform installs
total_installed = 0
for brand, qty in pairs:
batch = (
db.query(Battery)
.filter_by(brand=brand, status="available")
.order_by(Battery.id)
.limit(qty)
.all()
)
batch_q = db.query(Battery).filter_by(brand=brand, status="available")
if device.battery_size:
batch_q = batch_q.filter(
(Battery.size == device.battery_size) | (Battery.size == None)
)
batch = batch_q.order_by(Battery.id).limit(qty).all()
for b in batch:
b.status = "installed"
b.device_id = device.id
@@ -870,6 +900,12 @@ def create_app(config_object="config"):
f"{', '.join(existing_brands)}. Mixing brands is not recommended.",
"warning",
)
if device.battery_size and battery.size and battery.size != device.battery_size:
flash(
f"Warning: {device.name} requires {device.battery_size} batteries, "
f"but {battery.label} is {battery.size}.",
"warning",
)
battery.status = "installed"
battery.device_id = device.id
db.commit()