pax_global_header00006660000000000000000000000064145144276500014522gustar00rootroot0000000000000052 comment=65fc2e5550134e91aa122918fa8939e115f48d29 h3l1o5-pyyardian-775dbb4/000077500000000000000000000000001451442765000151535ustar00rootroot00000000000000h3l1o5-pyyardian-775dbb4/.gitignore000066400000000000000000000000611451442765000171400ustar00rootroot00000000000000.venv dist build *.egg-info __pycache__ .DS_Storeh3l1o5-pyyardian-775dbb4/LICENSE000066400000000000000000000020601451442765000161560ustar00rootroot00000000000000MIT License Copyright (c) 2023 Aeon Matrix Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.h3l1o5-pyyardian-775dbb4/LICENSE.txt000066400000000000000000000020431451442765000167750ustar00rootroot00000000000000Copyright (c) 2023 Aeon Matrix Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.h3l1o5-pyyardian-775dbb4/README.md000066400000000000000000000002261451442765000164320ustar00rootroot00000000000000 Python module for interacting with the Yardian irrigation controller. This module communicates directly towards the IP address of the Yardian device.h3l1o5-pyyardian-775dbb4/publish.sh000077500000000000000000000000511451442765000171540ustar00rootroot00000000000000python setup.py sdist twine upload dist/*h3l1o5-pyyardian-775dbb4/pyyardian/000077500000000000000000000000001451442765000171535ustar00rootroot00000000000000h3l1o5-pyyardian-775dbb4/pyyardian/__init__.py000066400000000000000000000002571451442765000212700ustar00rootroot00000000000000from .async_client import AsyncYardianClient, YardianDeviceState from .exceptions import NotAuthorizedException, NetworkException from .typing import DeviceInfo, OperationInfoh3l1o5-pyyardian-775dbb4/pyyardian/async_client.py000066400000000000000000000072611451442765000222060ustar00rootroot00000000000000import aiohttp from dataclasses import dataclass from .const import MODEL_DETAIL, DEFAULT_TIMEOUT from .exceptions import NotAuthorizedException, NetworkException from .typing import DeviceInfo, OperationInfo @dataclass class YardianDeviceState: """Data retrieved from a Yardian device.""" zones: list[list] active_zones: set[int] class AsyncYardianClient: def __init__( self, websession: aiohttp.ClientSession, host: str, token: str ) -> None: self._websession = websession self._base_url = f"http://{host}:880" self._base_header = { "Yardian-Token": token } self._device_info = None async def fetch_oper_info(self) -> OperationInfo: try: resp = await ( await self._websession.request( "GET", f"{self._base_url}/API_MGR_GET_OPERINFO", headers=self._base_header, timeout=DEFAULT_TIMEOUT, ) ).json() except: raise NetworkException() else: iCode = resp.get("iCode", 0) if iCode == 0: return resp["result"] elif iCode == -1000: raise NotAuthorizedException() else: raise Exception() async def fetch_device_info(self) -> DeviceInfo: try: resp = await ( await self._websession.request( "GET", f"{self._base_url}/API_GET_DEVICEINFO", headers=self._base_header, timeout=DEFAULT_TIMEOUT, ) ).json() except: raise NetworkException() else: iCode = resp.get("iCode", 0) if iCode == 0: return resp | MODEL_DETAIL[resp["model"]] elif iCode == -1000: raise NotAuthorizedException() else: raise Exception() async def fetch_active_zones(self): try: resp = await ( await self._websession.request( "GET", f"{self._base_url}/API_ZONE_GET_OPENINGZONE", headers=self._base_header, timeout=DEFAULT_TIMEOUT, ) ).json() except: raise NetworkException() else: iCode = resp.get("iCode", 0) if iCode == 0: return resp["result"] elif iCode == -1000: raise NotAuthorizedException() else: raise Exception() async def fetch_zone_info(self, amount=8): oper_info = await self.fetch_oper_info() return oper_info["zones"][:amount] async def fetch_device_state(self): if not self._device_info: self._device_info = await self.fetch_device_info() zones = await self.fetch_zone_info(self._device_info['zones']) active_zones = await self.fetch_active_zones() return YardianDeviceState(zones=zones, active_zones=active_zones) async def start_irrigation(self, zone_id, duration): body = { "sEvent": "AE_IRR_START_INST", "sPayload": f"[[-1, 0, 0, {zone_id}, {duration * 60}]]", } await self._websession.request( "POST", self._base_url, headers=self._base_header, json=body, timeout=DEFAULT_TIMEOUT ) async def stop_irrigation(self): body = { "sEvent": "AE_IRR_STOP_TASK", } await self._websession.request( "POST", self._base_url, headers=self._base_header, json=body, timeout=DEFAULT_TIMEOUT ) h3l1o5-pyyardian-775dbb4/pyyardian/const.py000066400000000000000000000006411451442765000206540ustar00rootroot00000000000000import pyyardian MODEL_DETAIL = { "YDN1600": {"name": "Yardian", "zones": 12}, "YDN1602": {"name": "Yardian", "zones": 8}, "PRO1600": {"name": "Yardian Pro", "zones": 12}, "PRO1602": {"name": "Yardian Pro", "zones": 8}, "PRO1900": {"name": "Yardian Pro", "zones": 12}, "PRO1902": {"name": "Yardian Pro", "zones": 8}, "PRO1906": {"name": "Yardian Pro", "zones": 6}, } DEFAULT_TIMEOUT = 30h3l1o5-pyyardian-775dbb4/pyyardian/exceptions.py000066400000000000000000000003041451442765000217030ustar00rootroot00000000000000class NotAuthorizedException(Exception): """Exception raised when the client is not authorized.""" class NetworkException(Exception): """Exception raised when cannot connect to device."""h3l1o5-pyyardian-775dbb4/pyyardian/typing.py000066400000000000000000000011621451442765000210370ustar00rootroot00000000000000from typing import TypedDict, Any class OperationInfo(TypedDict, total=False): sIotcUid: str iTimezoneOffset: int fFreezePrevent: int iRainDelay: int iStandby: int bPopSwitch: bool iMasterValveId: int viMdArgu: list[int] iSensorDelay: int iWaterHammerDuration: int iAlwaysOnZoneId: int iScarecrowZoneId: int iScarecrowDurationSec: int DSFactor: int region: str sensor1: dict[str, Any] sensor2: dict[str, Any] zones: list[list[Any]] class DeviceInfo(TypedDict, total=False): name: str model: str serialNumber: str yid: str zones: inth3l1o5-pyyardian-775dbb4/requirement_dev.txt000066400000000000000000000000451451442765000211110ustar00rootroot00000000000000aiohttp==3.8.5 setuptools wheel twineh3l1o5-pyyardian-775dbb4/setup.cfg000066400000000000000000000000771451442765000170000ustar00rootroot00000000000000[metadata] description-file=README.md license_files=LICENSE.rsth3l1o5-pyyardian-775dbb4/setup.py000066400000000000000000000011341451442765000166640ustar00rootroot00000000000000 from setuptools import setup, find_packages setup( name="pyyardian", version="1.2.0", license="MIT", author="Marty Sun", author_email="marty.sun@aeonmatrix.com", description="A module for interacting with the Yardian irrigation controller", long_description=" Python module for interacting with the Yardian irrigation controller. This module communicates directly towards the IP address of the Yardian device.", long_description_content_type="text/markdown", url="https://github.com/h3l1o5/pyyardian", install_requires=["aiohttp"], packages=find_packages() )h3l1o5-pyyardian-775dbb4/test.py000066400000000000000000000004761451442765000165130ustar00rootroot00000000000000import aiohttp import asyncio from pyyardian.async_client import AsyncYardianClient async def main(): async with aiohttp.ClientSession() as session: cli = AsyncYardianClient(session, "host", "access_token") print(await cli.fetch_device_state()) if __name__ == "__main__": asyncio.run(main())