Power Management#
Power management estimates whether field IoT nodes can survive the planned
deployment. The pycsamt.iot.power helpers combine battery capacity,
reserve, active/sleep duty cycle, regulator losses, telemetry windows,
edge-processing overhead, auxiliary loads, and optional solar harvesting.
The examples below use synthetic L18-style field nodes. That is the right level for this page because power budgeting depends on device operations, not EDI impedance files. The three scenarios represent a solar-assisted node, a marginal node with high telemetry demand, and a critical node with small battery capacity and no harvesting.
Build Device Power Profiles#
Use pycsamt.iot.DevicePowerProfile when several field nodes share
the same recorder hardware. The profile stores hardware draw; each
pycsamt.iot.EnergyConfig stores deployment-specific conditions.
1from pycsamt.iot import DevicePowerProfile
2
3profile = DevicePowerProfile(
4 "amt-recorder",
5 active_power_w=1.6,
6 sleep_power_w=0.12,
7 telemetry_power_w=3.0,
8 edge_power_w=0.35,
9)
10
11configs = [
12 profile.apply(
13 battery_wh=160.0,
14 duty_cycle=0.35,
15 solar_wh_per_day=38.0,
16 charge_efficiency=0.85,
17 reserve_fraction=0.20,
18 regulator_efficiency=0.88,
19 telemetry_seconds_per_day=420.0,
20 edge_duty_cycle=0.35,
21 auxiliary_wh_per_day=1.5,
22 min_runtime_days=7.0,
23 device_id="l18-node-01",
24 ),
25 profile.apply(
26 battery_wh=95.0,
27 duty_cycle=0.55,
28 solar_wh_per_day=8.0,
29 charge_efficiency=0.80,
30 reserve_fraction=0.20,
31 regulator_efficiency=0.85,
32 telemetry_seconds_per_day=900.0,
33 edge_duty_cycle=0.55,
34 auxiliary_wh_per_day=2.0,
35 min_runtime_days=7.0,
36 device_id="l18-node-02",
37 ),
38 profile.apply(
39 battery_wh=48.0,
40 duty_cycle=0.85,
41 solar_wh_per_day=0.0,
42 reserve_fraction=0.15,
43 regulator_efficiency=0.82,
44 telemetry_seconds_per_day=1500.0,
45 edge_duty_cycle=0.80,
46 auxiliary_wh_per_day=3.0,
47 min_runtime_days=7.0,
48 device_id="l18-node-03",
49 ),
50]
Estimate One Device#
Use pycsamt.iot.estimate_energy_budget() for a single device. The
estimate reports daily load, daily harvest, net daily draw, runtime, state,
and machine-readable issues.
1from pycsamt.iot import estimate_energy_budget, power_summary_table
2
3estimate = estimate_energy_budget(configs[1])
4table = power_summary_table(estimate, device_ids=[configs[1].device_id])
5print(
6 table[
7 [
8 "device_id",
9 "state",
10 "runtime_days",
11 "load_wh_per_day",
12 "harvest_wh_per_day",
13 "net_wh_per_day",
14 "energy_margin_wh_per_day",
15 "issues",
16 ]
17 ].to_string(index=False)
18)
Output:
device_id state runtime_days load_wh_per_day harvest_wh_per_day net_wh_per_day energy_margin_wh_per_day issues
l18-node-02 critical 2.77963 33.741765 6.4 27.341765 -27.341765 daily_energy_deficit;runtime_below_minimum
Estimate A Deployment#
Use pycsamt.iot.estimate_deployment_energy() when several nodes must
be compared. runtime_days is infinite when daily harvest is greater
than or equal to daily load.
1from pycsamt.iot import estimate_deployment_energy
2
3deployment = estimate_deployment_energy(configs)
4print(
5 deployment[
6 [
7 "device_id",
8 "state",
9 "runtime_days",
10 "autonomy_days_no_harvest",
11 "load_wh_per_day",
12 "harvest_wh_per_day",
13 "net_wh_per_day",
14 "issues",
15 ]
16 ].copy().round(
17 {
18 "runtime_days": 2,
19 "autonomy_days_no_harvest": 2,
20 "load_wh_per_day": 2,
21 "harvest_wh_per_day": 2,
22 "net_wh_per_day": 2,
23 }
24 ).to_string(index=False)
25)
Output:
device_id state runtime_days autonomy_days_no_harvest load_wh_per_day harvest_wh_per_day net_wh_per_day issues
l18-node-01 sustaining inf 5.77 22.19 32.3 -10.11
l18-node-02 critical 2.78 2.25 33.74 6.4 27.34 daily_energy_deficit;runtime_below_minimum
l18-node-03 critical 0.80 0.80 51.30 0.0 51.30 daily_energy_deficit;runtime_below_minimum
Encode Power Telemetry#
An EnergyEstimate can be encoded as a power
packet and added to a pycsamt.iot.FieldSession. This keeps power
evidence next to edge QC, synchronisation, and station metadata.
1from pycsamt.iot import DeviceConfig, FieldSession
2
3devices = [
4 DeviceConfig(
5 cfg.device_id,
6 station=f"00{i}A",
7 channels=["ex", "ey", "hx", "hy"],
8 )
9 for i, cfg in enumerate(configs, start=1)
10]
11session = FieldSession("WILLY-L18-POWER-DEMO", devices=devices)
12
13for idx, (device, cfg) in enumerate(zip(devices, configs)):
14 packet = estimate_energy_budget(cfg).to_packet(
15 device,
16 timestamp=1_700_000_000.0 + 60.0 * idx,
17 survey_id=session.survey_id,
18 )
19 session.add_packet(packet)
20
21packet = session.packets[1]
22print(f"topic: {packet.topic}")
23print(f"state: {packet.payload['state']}")
24print(f"runtime_days: {packet.payload['runtime_days']:.2f}")
25print(f"payload keys: {', '.join(sorted(packet.payload))}")
Output:
topic: pycsamt/WILLY-L18-POWER-DEMO/002A/l18-node-02/power
state: critical
runtime_days: 2.78
payload keys: autonomy_days_no_harvest, auxiliary_wh_per_day, average_power_w, edge_wh_per_day, energy_margin_wh_per_day, harvest_wh_per_day, issues, load_wh_per_day, net_wh_per_day, reserve_wh, runtime_days, runtime_hours, state, telemetry_wh_per_day, usable_battery_wh
Plot Power Budgets#
The plotting helper summarises daily load and harvest, runtime, no-harvest autonomy, daily load components, and state counts.
1from pathlib import Path
2
3from pycsamt.iot import plot_power_budget
4
5out_dir = Path("docs/source/images/user_guide/iot")
6out_dir.mkdir(parents=True, exist_ok=True)
7
8plot_power_budget(
9 configs,
10 figsize=(10.8, 7.2),
11 title="L18 IoT power budget scenarios",
12 output_path=(
13 out_dir / "user-guide-iot-power-management-01.png"
14 ).as_posix(),
15 close=True,
16)
Field Interpretation#
l18-node-01 is sustaining because harvested energy exceeds daily load.
Its no-harvest autonomy is still finite, so the deployment remains exposed
to cloudy weather or panel failure. l18-node-02 and l18-node-03
both have a daily energy deficit and fall below the seven-day minimum
runtime. The third node is the highest-risk case because it has small
battery capacity, high duty cycle, long telemetry windows, and no harvest.
In field planning, revise the critical nodes before deployment: reduce duty cycle, shorten telemetry windows, add battery capacity, add solar harvesting, or lower auxiliary load. Record the final budget in the acquisition manifest so runtime assumptions remain auditable.