Firmware: - mDNS announcement as <hostname>.local (configurable via Kconfig) - Task watchdog with 30s timeout and auto-reboot on hang - STATUS now returns human-readable uptime (e.g., 3d2h15m) and hostname Pi-side tools: - esp-cmd: mDNS hostname resolution (esp-cmd amber-maple.local STATUS) - esp-fleet: parallel command to all sensors (esp-fleet status) Tested on amber-maple — mDNS resolves, watchdog active, fleet tool works.
66 lines
1.8 KiB
Python
Executable File
66 lines
1.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Send management commands to ESP32 CSI devices over UDP."""
|
|
|
|
import socket
|
|
import sys
|
|
|
|
DEFAULT_PORT = 5501
|
|
TIMEOUT = 2.0
|
|
|
|
USAGE = """\
|
|
Usage: esp-cmd <host> <command> [args...]
|
|
|
|
Host can be an IP address or mDNS hostname (e.g., amber-maple.local).
|
|
|
|
Commands:
|
|
STATUS Query device state (uptime, heap, RSSI, tx_power, rate)
|
|
REBOOT Restart the ESP32
|
|
IDENTIFY Blink LED solid for 5 seconds
|
|
RATE <10-100> Set ping frequency in Hz (saved to NVS)
|
|
POWER <2-20> Set TX power in dBm (saved to NVS)
|
|
|
|
Examples:
|
|
esp-cmd amber-maple.local STATUS
|
|
esp-cmd 192.168.129.30 RATE 50
|
|
esp-cmd amber-maple.local IDENTIFY"""
|
|
|
|
|
|
def resolve(host):
|
|
"""Resolve hostname to IP address (supports mDNS .local)."""
|
|
try:
|
|
result = socket.getaddrinfo(host, DEFAULT_PORT, socket.AF_INET, socket.SOCK_DGRAM)
|
|
return result[0][4][0]
|
|
except socket.gaierror as e:
|
|
print(f"ERR: cannot resolve {host}: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 3 or sys.argv[1] in ("-h", "--help"):
|
|
print(USAGE)
|
|
sys.exit(0 if sys.argv[1:] and sys.argv[1] in ("-h", "--help") else 2)
|
|
|
|
host = sys.argv[1]
|
|
cmd = " ".join(sys.argv[2:]).strip()
|
|
ip = resolve(host)
|
|
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
sock.settimeout(TIMEOUT)
|
|
|
|
try:
|
|
sock.sendto(cmd.encode(), (ip, DEFAULT_PORT))
|
|
data, _ = sock.recvfrom(512)
|
|
print(data.decode().strip())
|
|
except socket.timeout:
|
|
print(f"ERR: no reply from {host} ({ip}:{DEFAULT_PORT}), timeout {TIMEOUT}s", file=sys.stderr)
|
|
sys.exit(1)
|
|
except OSError as e:
|
|
print(f"ERR: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
finally:
|
|
sock.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|