|
22 | 22 | UIWidget, |
23 | 23 | UpdateBoxStatus, |
24 | 24 | ) |
| 25 | +from pyoverkiz.enums.command import OverkizCommand, OverkizCommandParam |
25 | 26 | from pyoverkiz.enums.protocol import Protocol |
26 | 27 | from pyoverkiz.obfuscate import obfuscate_email, obfuscate_id, obfuscate_string |
27 | 28 | from pyoverkiz.types import DATA_TYPE_TO_PYTHON, StateType |
@@ -465,19 +466,44 @@ def __len__(self) -> int: |
465 | 466 | get = __getitem__ |
466 | 467 |
|
467 | 468 |
|
468 | | -class Command(dict): |
| 469 | +@define(init=False, kw_only=True) |
| 470 | +class Command: |
469 | 471 | """Represents an OverKiz Command.""" |
470 | 472 |
|
471 | | - name: str |
472 | | - parameters: list[str | int | float] | None |
| 473 | + type: int | None = None |
| 474 | + name: OverkizCommand |
| 475 | + parameters: list[str | int | float | OverkizCommandParam] | None |
473 | 476 |
|
474 | 477 | def __init__( |
475 | | - self, name: str, parameters: list[str | int | float] | None = None, **_: Any |
| 478 | + self, |
| 479 | + name: OverkizCommand, |
| 480 | + parameters: list[str | int | float | OverkizCommandParam] | None = None, |
| 481 | + type: int | None = None, |
| 482 | + **_: Any, |
476 | 483 | ): |
477 | 484 | """Initialize a command instance and mirror fields into dict base class.""" |
478 | 485 | self.name = name |
479 | 486 | self.parameters = parameters |
480 | | - dict.__init__(self, name=name, parameters=parameters) |
| 487 | + self.type = type |
| 488 | + |
| 489 | + def to_payload(self) -> dict[str, object]: |
| 490 | + """Return a JSON-serializable payload for this command. |
| 491 | +
|
| 492 | + The payload uses snake_case keys; the client will convert to camelCase |
| 493 | + and apply small key fixes (like `deviceURL`) before sending. |
| 494 | + """ |
| 495 | + payload: dict[str, object] = {"name": str(self.name)} |
| 496 | + |
| 497 | + if self.type is not None: |
| 498 | + payload["type"] = self.type |
| 499 | + |
| 500 | + if self.parameters is not None: |
| 501 | + payload["parameters"] = [ |
| 502 | + p if isinstance(p, (str, int, float, bool)) else str(p) |
| 503 | + for p in self.parameters # type: ignore[arg-type] |
| 504 | + ] |
| 505 | + |
| 506 | + return payload |
481 | 507 |
|
482 | 508 |
|
483 | 509 | @define(init=False, kw_only=True) |
@@ -600,10 +626,22 @@ class Action: |
600 | 626 | device_url: str |
601 | 627 | commands: list[Command] |
602 | 628 |
|
603 | | - def __init__(self, device_url: str, commands: list[dict[str, Any]]): |
| 629 | + def __init__(self, device_url: str, commands: list[dict[str, Any] | Command]): |
604 | 630 | """Initialize Action from API data and convert nested commands.""" |
605 | 631 | self.device_url = device_url |
606 | | - self.commands = [Command(**c) for c in commands] if commands else [] |
| 632 | + self.commands = [ |
| 633 | + c if isinstance(c, Command) else Command(**c) for c in commands |
| 634 | + ] |
| 635 | + |
| 636 | + def to_payload(self) -> dict[str, object]: |
| 637 | + """Return a JSON-serializable payload for this action (snake_case). |
| 638 | +
|
| 639 | + The final camelCase conversion is handled by the client. |
| 640 | + """ |
| 641 | + return { |
| 642 | + "device_url": self.device_url, |
| 643 | + "commands": [c.to_payload() for c in self.commands], |
| 644 | + } |
607 | 645 |
|
608 | 646 |
|
609 | 647 | @define(init=False, kw_only=True) |
|
0 commit comments