Step 7 – Power Management (Make WAIT Meaningful)
After Step 6, the system is:
- reliable
- observable
- polite under failure
Step 7 makes it energy-aware.
This step answers:
“What should the device do while nothing useful is happening?”
1. Purpose of Step 7
Most of the device’s lifetime is spent in:
WAIT
IDLE
If power management is not addressed:
- batteries drain quickly
- devices run hot
- energy budgets are unpredictable
Step 7 ensures:
- WAIT actually saves power
- retries do not waste energy
- power behavior is explainable
2. Power Management Philosophy
Senior firmware rule:
“Sleep whenever you are not making progress.”
Important clarifications:
- Power management is a policy, not a driver feature
- WAIT is the only state allowed to sleep deeply
- Other states must remain responsive
3. Power Domains (Mental Model)
Think in terms of power domains:
| Domain | Examples |
|---|---|
| CPU | active vs idle |
| Radio | Wi-Fi / BLE on/off |
| Peripherals | I2C, sensors |
Step 7 coordinates these domains at the application level.
4. WAIT State Becomes Power-Aware
WAIT already enforces time. Now it also enforces low power.
Conceptual behavior:
WAIT:
- shut down radio if possible
- allow RTOS idle
- sleep for retry_delay
WAIT still does not decide policy. It only executes it.
5. Application Context Update
struct app_ctx {
enum app_state state;
enum app_state recovery_state;
int32_t last_temp_mdeg;
uint32_t retry_count;
int last_error;
k_timeout_t retry_delay;
bool low_power_allowed;
struct mcp9808_ctx sensor;
struct net_ctx net;
struct http_ctx http;
};
low_power_allowed is a policy flag, not a hardware detail.
6. Deciding When Low Power Is Allowed
Rules:
- Allowed in WAIT
- Allowed in IDLE
-
NOT allowed in:
- SENSOR_INIT
- NET_INIT
- SAMPLE
- SEND
Reason:
- those states expect forward progress
This keeps timing predictable.
7. WAIT State (Power-Aware Form)
Conceptual implementation:
case APP_STATE_WAIT:
if (ctx->low_power_allowed) {
net_suspend(&ctx->net);
}
k_sleep(ctx->retry_delay);
if (ctx->low_power_allowed) {
net_resume(&ctx->net);
}
ctx->state = ctx->recovery_state;
break;
Notes:
- Radio suspend/resume is explicit
- WAIT still owns all sleeping
8. Why We Do NOT Sleep in Other States
Sleeping in other states causes:
- hidden latency
- missed events
- unpredictable behavior
By centralizing sleep:
- timing is explicit
- debugging is easier
- watchdog integration is simpler
9. Logging Power Transitions
Power transitions are logged sparingly:
Entering low-power WAIT for 60s
Exiting low-power WAIT
This helps:
- battery debugging
- field diagnostics
10. Interaction with Retry Policy
Backoff + power saving work together:
- short backoff → light sleep
- long backoff → deep sleep
Policy mapping is simple and explainable.
11. What Step 7 Deliberately Avoids
- No dynamic frequency scaling
- No complex sleep states
- No hardware-specific tuning
Those belong to product-specific optimization later.
12. Success Criteria for Step 7
Step 7 is complete when:
- Device sleeps during WAIT
- No sleep occurs during active states
- Power behavior matches retry policy
- Logs explain power transitions
13. Architectural Status After Step 7
After Step 7, the system is:
- architecturally complete
- operationally mature
- energy-aware
This is the baseline for real IoT products.
14. Next Steps
Optional next steps:
- Step 8: Data buffering / batching
- Step 9: OTA updates
- Step 10: Watchdog integration
None of these change core control flow.