feat: add --reset and --trigger-error-state to hendi_ctrl_app.py

--trigger-error-state deliberately reproduces the Hendi's
ungraceful-disconnect lockout (remoteEnable(True) without a matching
disable) so it can be tested on demand. --reset toggles the reset
line, but per hardware testing it does NOT clear that lockout - only
the device's physical knob/power cycle does.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GpePKZiEZWbGo9HrfuML6U
This commit is contained in:
2026-07-02 17:35:05 +02:00
co-authored by Claude Sonnet 5
parent 5522b9c491
commit d079db8b37
+25
View File
@@ -41,6 +41,24 @@ def test_heater(hendi):
hendi.setSwitch(0)
def trigger_error_state(hendi):
"""Enables remote control and deliberately exits without disabling it
again - reproduces the Hendi's "not closed gracefully" lockout (its
built-in security feature that fails subsequent connect attempts)
on demand, instead of waiting for an actual crash to trigger it."""
print("Triggering error state: enabling remote control, exiting without releasing it")
hendi.remoteEnable(True)
def reset(hendi):
"""Toggles the reset line. Confirmed on hardware that this does NOT
clear the ungraceful-disconnect lockout (see trigger_error_state()) -
only the device's physical knob/power cycle does that."""
print("Resetting Hendi (toggling DTR/RTS)")
hendi.reset()
time.sleep(1.0)
def update_firmware(hendi, filename):
hendi.firmware_update(filename)
@@ -49,15 +67,20 @@ def main():
parser = ap.ArgumentParser(description=__doc__)
parser.add_argument("--serial-port", default=DEFAULT_PORT)
parser.add_argument("--baudrate", type=int, default=DEFAULT_BAUDRATE)
parser.add_argument("--reset", action="store_true", help="toggle the reset line (does not clear the ungraceful-disconnect lockout - use the device's knob for that)")
parser.add_argument("--version", action="store_true", help="print software identifier/version")
parser.add_argument("--capabilities", action="store_true", help="print power/digit capability info")
parser.add_argument("--test-converter", action="store_true", help="round-trip the watts<->digits polynomials")
parser.add_argument("--test-heater", action="store_true", help="drive the heater through its power range")
parser.add_argument("--trigger-error-state", action="store_true",
help="enable remote control and exit without disabling it, to deliberately reproduce the ungraceful-disconnect lockout")
parser.add_argument("--update-firmware", metavar="FILE", help="flash the given firmware file")
args = parser.parse_args()
hendi = HendiCtrl(args.serial_port, args.baudrate)
if args.reset:
reset(hendi)
if args.version:
print_version(hendi)
if args.capabilities:
@@ -66,6 +89,8 @@ def main():
test_converter(hendi)
if args.test_heater:
test_heater(hendi)
if args.trigger_error_state:
trigger_error_state(hendi)
if args.update_firmware:
update_firmware(hendi, args.update_firmware)