Fix API regressions and refresh project docs

This commit is contained in:
Artem Kokos
2026-05-15 23:12:28 +07:00
parent 654f64bb90
commit 13fba2fa44
19 changed files with 3258 additions and 964 deletions

View File

@@ -1,6 +1,23 @@
import json
import asyncio
import socket
from dataclasses import dataclass
from typing import Any
@dataclass(frozen=True)
class WizResponse:
ok: bool
ip: str
kind: str
payload: dict[str, Any] | None = None
message: str | None = None
@property
def result(self) -> dict[str, Any]:
if not self.payload:
return {}
return self.payload.get("result", {})
class WizDriver:
@@ -41,24 +58,72 @@ class WizDriver:
"steampunk": 35,
}
async def send_udp(self, ip: str, payload: dict):
async def send_udp(self, ip: str, payload: dict) -> WizResponse:
loop = asyncio.get_running_loop()
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.settimeout(2.0)
data = json.dumps(payload).encode()
await loop.run_in_executor(None, sock.sendto, data, (ip, self.PORT))
try:
await loop.run_in_executor(None, sock.sendto, data, (ip, self.PORT))
except OSError as exc:
return WizResponse(
ok=False,
ip=ip,
kind="network_error",
message=f"Ошибка отправки UDP: {exc}",
)
try:
resp, _ = await loop.run_in_executor(None, sock.recvfrom, 1024)
return json.loads(resp.decode())
except socket.timeout:
return None
return WizResponse(
ok=False,
ip=ip,
kind="timeout",
message="Таймаут ответа от лампы",
)
except OSError as exc:
return WizResponse(
ok=False,
ip=ip,
kind="network_error",
message=f"Ошибка чтения UDP: {exc}",
)
async def set_pilot(self, ip: str, params: dict):
try:
decoded = json.loads(resp.decode())
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
return WizResponse(
ok=False,
ip=ip,
kind="protocol_error",
message=f"Невалидный ответ WiZ: {exc}",
)
if isinstance(decoded, dict) and "error" in decoded:
return WizResponse(
ok=False,
ip=ip,
kind="device_error",
payload=decoded,
message=str(decoded["error"]),
)
if not isinstance(decoded, dict):
return WizResponse(
ok=False,
ip=ip,
kind="protocol_error",
message="Ответ WiZ имеет неожиданный формат",
)
return WizResponse(ok=True, ip=ip, kind="ok", payload=decoded)
async def set_pilot(self, ip: str, params: dict) -> WizResponse:
payload = {"method": "setPilot", "params": params}
return await self.send_udp(ip, payload)
async def get_pilot(self, ip: str):
async def get_pilot(self, ip: str) -> WizResponse:
payload = {"method": "getPilot", "params": {}}
return await self.send_udp(ip, payload)