Power-off spike (Part A) on the N100: plugswitch, wall-power figures, the hub's view
gates / gates (push) Successful in 6m35s

plugswitch.py refuses 'off' unless 20 s of readings show the N100 is already off (standby + 1 W,
no ping); 7 tests, each check red-proofed. By hand: guest shutdown 12 s, host off, 0.0 W; the hub
stayed silent and 'ONLINE' for 18 min; plug off/on did not start the N100, its power button did
(dashboard in 42 s). Wall figures into SIZING.md 4 and sizing.json power (8.5 / 20.7 / 0.0 W).
This commit is contained in:
2026-10-13 19:15:08 +02:00
parent 6a1f715a87
commit b4dcf4b373
32 changed files with 1410 additions and 20 deletions
+40
View File
@@ -0,0 +1,40 @@
#!/usr/bin/env python3
"""Pins plugswitch.py's rule: `off` only when 20 s of readings show the machine is off."""
import os, sys, unittest
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from plugswitch import off_allowed # noqa: E402
OFF = [(t, 0.4, False) for t in range(0, 20, 2)]
class Rule(unittest.TestCase):
def test_off_machine_allowed(self):
self.assertTrue(off_allowed(OFF, 0.3)[0])
def test_running_machine_refused_by_watts(self):
s = OFF[:5] + [(10, 7.2, False)] + OFF[6:]
ok, why = off_allowed(s, 0.3)
self.assertFalse(ok); self.assertIn('draws power', why)
def test_ping_answer_refused(self):
s = OFF[:-1] + [(18, 0.4, True)]
ok, why = off_allowed(s, 0.3)
self.assertFalse(ok); self.assertIn('ping', why)
def test_failed_read_refused(self):
s = OFF[:3] + [(6, None, False)] + OFF[4:]
self.assertFalse(off_allowed(s, 0.3)[0])
def test_short_window_refused(self):
self.assertFalse(off_allowed(OFF[:4], 0.3)[0])
def test_no_standby_refused(self):
self.assertFalse(off_allowed(OFF, None)[0])
def test_edge_exactly_at_limit_refused(self):
s = OFF[:-1] + [(18, 1.3, False)]
self.assertFalse(off_allowed(s, 0.3)[0])
if __name__ == '__main__':
unittest.main()