This commit is contained in:
2026-08-24 16:40:48 +03:00
parent f7e99516bf
commit 32abb8bf0a
73 changed files with 12364 additions and 9292 deletions
+52
View File
@@ -15,6 +15,10 @@
http://<ip>:8765/cleaning?result=pending
http://<ip>:8765/nested?status=ready
http://<ip>:8765/reset — сброс счётчиков poll
Latch/reset (plain-text OK, как у заказчика):
http://<ip>:8765/api/click/btn?bid=01*04*01 — вызов (trigger)
http://<ip>:8765/api/click/btn?bid=01*04*00 — сброс (reset)
"""
from __future__ import annotations
@@ -34,6 +38,25 @@ def _now() -> str:
_poll_lock = threading.Lock()
_poll_counts: dict[str, int] = {}
_latch_lock = threading.Lock()
_latch_active: dict[str, bool] = {}
def _latch_key(handler: BaseHTTPRequestHandler, bid: str) -> str:
"""Group trigger/reset pairs by bid prefix (01*04*01 / 01*04*00 -> 01*04)."""
parts = bid.split("*")
if len(parts) >= 2:
return "*".join(parts[:-1])
return handler.client_address[0]
def _bid_action(bid: str) -> str:
parts = bid.split("*")
if parts and parts[-1] == "00":
return "reset"
if parts and parts[-1] == "01":
return "trigger"
return "unknown"
def _poll_key(handler: BaseHTTPRequestHandler, qs: dict) -> str:
@@ -104,6 +127,30 @@ class ButtonTestHandler(BaseHTTPRequestHandler):
self._send_json(200, {"status": "ok", "bid": bid, "ts": time.time()})
return True
if path == "/api/click/btn":
bid = (qs.get("bid") or ["?"])[0]
action = _bid_action(bid)
key = _latch_key(self, bid)
note = ""
with _latch_lock:
if action == "trigger":
if _latch_active.get(key):
note = " (already active)"
else:
_latch_active[key] = True
elif action == "reset":
if _latch_active.get(key):
_latch_active[key] = False
note = " (cleared)"
else:
note = " (was idle)"
print(
f"[{_now()}] /api/click/btn bid={bid} action={action} key={key}{note}",
flush=True,
)
self._send(200, "OK")
return True
if path == "/slow":
sec = float((qs.get("sec") or ["3"])[0])
sec = max(0.0, min(sec, 60.0))
@@ -235,6 +282,11 @@ GET /poll?pending=3&key=btn1 -> отдельный счётчик на кно
GET /reset -> сброс всех счётчиков
GET /reset?key=btn1 -> сброс одного
=== Latch/reset (bodyMatch: plain OK) ===
GET /api/click/btn?bid=01*04*01 -> trigger, тело "OK"
GET /api/click/btn?bid=01*04*00 -> reset, тело "OK"
(последний сегмент bid: 01=вызов, 00=сброс; в консоли видно состояние)
=== Прочее ===
GET /cleaning?result=ok|pending|error
GET /nested?status=ready -> {"data":{"status":"ready"}}