a
This commit is contained in:
@@ -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"}}
|
||||
|
||||
Reference in New Issue
Block a user