bachya/regenmaschine

View on GitHub
regenmaschine/endpoints/zone.py

Summary

Maintainability
A
0 mins
Test Coverage
"""Define an object to interact with zones."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, cast

from regenmaschine.endpoints import EndpointManager


class Zone(EndpointManager):
    """Define a zone object."""

    async def _post(self, zone_id: int, json: dict[str, Any]) -> dict[str, Any]:
        """Post data to a (non)existing zone.

        Args:
            zone_id: A zone ID.
            json: An API request payload.

        Returns:
            An API response payload.
        """
        return await self.controller.request(
            "post", f"zone/{zone_id}/properties", json=json
        )

    async def all(
        self, *, details: bool = False, include_inactive: bool = False
    ) -> dict[int, dict[str, Any]]:
        """Return all zones (with optional advanced properties).

        Args:
            details: Whether extra details should be included.
            include_inactive: Whether to include inactive programs.

        Returns:
            An API response payload.
        """
        raw_zones = await self.controller.request("get", "zone")
        zone_details: dict | None = None

        if details:
            zone_details = await self.controller.request("get", "zone/properties")

        zones: dict[int, dict[str, Any]] = {}
        for zone in raw_zones["zones"]:
            if details:
                if TYPE_CHECKING:
                    assert zone_details is not None
                [extra] = [z for z in zone_details["zones"] if z["uid"] == zone["uid"]]
                zone_data = {**zone, **extra}
            else:
                if "active" not in zone:
                    zone["active"] = True
                zone_data = zone

            if zone_data["active"] or include_inactive:
                zones[zone_data["uid"]] = zone_data

        return zones

    async def disable(self, zone_id: int) -> dict[str, Any]:
        """Disable a zone.

        Args:
            zone_id: A zone ID.

        Returns:
            An API response payload.
        """
        return await self._post(zone_id, {"active": False})

    async def enable(self, zone_id: int) -> dict[str, Any]:
        """Enable a zone.

        Args:
            zone_id: A zone ID.

        Returns:
            An API response payload.
        """
        return await self._post(zone_id, {"active": True})

    async def get(self, zone_id: int, *, details: bool = False) -> dict[str, Any]:
        """Return a specific zone.

        Args:
            zone_id: A zone ID.
            details: Whether extra details should be included.

        Returns:
            An API response payload.
        """
        zone = await self.controller.request("get", f"zone/{zone_id}")
        if not details:
            return zone
        zone_details = await self.controller.request(
            "get", f"zone/{zone_id}/properties"
        )
        return {**zone, **zone_details}

    async def running(self) -> list[dict[str, Any]]:
        """Return all running zones.

        Returns:
            An API response payload.
        """
        data = await self.controller.request("get", "watering/zone")
        return cast(list[dict[str, Any]], data["zones"])

    async def start(self, zone_id: int, time: int) -> dict[str, Any]:
        """Start a zone.

        Note that in addition to including it in the query URL, the zone ID must be
        provided in the request body to accommodate 1st generation controllers.

        Args:
            zone_id: A zone ID.
            time: The number of seconds to run the zone for.

        Returns:
            An API response payload.
        """
        return await self.controller.request(
            "post", f"zone/{zone_id}/start", json={"time": time, "zid": zone_id}
        )

    async def stop(self, zone_id: int) -> dict[str, Any]:
        """Stop a zone.

        Note that in addition to including it in the query URL, the zone ID must be
        provided in the request body to accommodate 1st generation controllers.

        Args:
            zone_id: A zone ID.

        Returns:
            An API response payload.
        """
        return await self.controller.request(
            "post", f"zone/{zone_id}/stop", json={"zid": zone_id}
        )