Commit 557b259
power.routeros: power_on must promote saved 'off' to 'forced-on' (#104)
## Why
\`RouterOSController\` saves the port's previous \`poe-out\` mode on
\`power_off\` so \`power_on\` can put it back where it was — that
preserves "auto-on" vs "forced-on" distinctions correctly. But if the
port was already \"off\" when \`power_off\` ran (recovering a parked
camera; bench is dark on a fresh shell), the saved \"previous\" mode is
literally \"off\", and \`power_on\` then \"restored\" the port to off.
Cycling a powered-down port left it powered down forever, which silently
broke every recovery flow that started from off.
Surfaced while testing #103 — every fresh script that started with
\`power_off → power_on\` left the camera unpowered, until I switched to
\`_set_poe(port, 'forced-on')\` directly as a workaround.
## What
\`power_on\` must always result in a powered port. If the saved mode is
\"off\", promote to \"forced-on\" and log the promotion (visible at
\`-v\`):
\`\`\`python
async def power_on(self, port: str) -> None:
restore_mode = self._saved_poe_out.pop(port, \"forced-on\")
if restore_mode == \"off\":
logger.info(\"PoE ON: %s on %s (saved state was 'off' — promoting to
'forced-on')\", port, self._host)
restore_mode = \"forced-on\"
else:
logger.info(\"PoE ON: %s on %s (restoring %s)\", port, self._host,
restore_mode)
await self._set_poe(port, restore_mode)
\`\`\`
## Test plan
- [x] \`uv run pytest tests/ -x --ignore=tests/fuzz\` — **527 passed, 2
skipped** (5 new tests)
- [x] \`uv run ruff check\` + \`mypy\` on changed files — clean
- [x] Verified on real hardware (MikroTik 10.216.128.2 / ether8,
currently powered down):
\`\`\`
before: ether8 poe-out='off'
power_off: saved='off'
power_on: saved=None, port now 'forced-on'
\`\`\`
5 new tests in \`tests/test_power.py::TestRouterOSPowerOnOff\` covering
forced-on round-trip, auto-on round-trip (preserved — not blindly
clobbered to forced-on), **off→on promotion (the bug)**, no-prior-off
default, and double-power_off-doesn't-clobber-saved-state edge cases.
They use a \`_PoeStateRouterOS\` subclass that stubs the two network
primitives so we can exercise the save/restore state machine without a
real switch.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Dmitry Ilyin <widgetii@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 4193805 commit 557b259
2 files changed
Lines changed: 89 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
365 | 365 | | |
366 | 366 | | |
367 | 367 | | |
368 | | - | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
369 | 383 | | |
370 | 384 | | |
371 | 385 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
0 commit comments