{"id":15679931,"url":"https://github.com/bachya/regenmaschine","last_synced_at":"2025-10-05T00:36:20.677Z","repository":{"id":22286563,"uuid":"94730967","full_name":"bachya/regenmaschine","owner":"bachya","description":"💧 A simple, clean, well-tested Python library for interacting with RainMachine™ smart sprinkler controllers","archived":false,"fork":false,"pushed_at":"2025-09-01T12:07:28.000Z","size":2266,"stargazers_count":12,"open_issues_count":8,"forks_count":9,"subscribers_count":3,"default_branch":"dev","last_synced_at":"2025-09-02T13:16:18.078Z","etag":null,"topics":["asyncio","home-automation","python3","rest-api","sprinkler-controller"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bachya.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-06-19T03:03:14.000Z","updated_at":"2025-08-31T20:52:36.000Z","dependencies_parsed_at":"2023-11-20T17:49:02.859Z","dependency_job_id":"800c0644-78ed-47d5-9ee0-6c98e829d769","html_url":"https://github.com/bachya/regenmaschine","commit_stats":{"total_commits":893,"total_committers":12,"mean_commits":74.41666666666667,"dds":0.5072788353863382,"last_synced_commit":"0d52cc9d7809c2ae05cf7c7ae273be28b8881c8a"},"previous_names":[],"tags_count":83,"template":false,"template_full_name":null,"purl":"pkg:github/bachya/regenmaschine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bachya%2Fregenmaschine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bachya%2Fregenmaschine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bachya%2Fregenmaschine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bachya%2Fregenmaschine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bachya","download_url":"https://codeload.github.com/bachya/regenmaschine/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bachya%2Fregenmaschine/sbom","scorecard":{"id":222553,"data":{"date":"2025-08-11","repo":{"name":"github.com/bachya/regenmaschine","commit":"1c530f75d22a3917bf608fc14752f8adbc3db6a0"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.4,"checks":[{"name":"Code-Review","score":-1,"reason":"Found no human activity in the last 30 changesets","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/codeql.yml:1","Warn: no topLevel permission defined: .github/workflows/labels.yml:1","Warn: no topLevel permission defined: .github/workflows/lock.yml:1","Warn: no topLevel permission defined: .github/workflows/publish.yml:1","Warn: no topLevel permission defined: .github/workflows/release-drafter.yml:1","Warn: no topLevel permission defined: .github/workflows/stale.yml:1","Warn: no topLevel permission defined: .github/workflows/static-analysis.yml:1","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/codeql.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/codeql.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/codeql.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/labels.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/labels.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/labels.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/labels.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/lock.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/lock.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/publish.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/publish.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-drafter.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/release-drafter.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/stale.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/stale.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/static-analysis.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/static-analysis.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/static-analysis.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/static-analysis.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/static-analysis.yml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/static-analysis.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/static-analysis.yml:52: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/static-analysis.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/static-analysis.yml:65: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/static-analysis.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:59: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:75: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:90: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:93: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:97: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:107: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:122: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:140: update your workflow using https://app.stepsecurity.io/secureworkflow/bachya/regenmaschine/test.yml/dev?enable=pin","Warn: pipCommand not pinned by hash: script/setup:9","Warn: pipCommand not pinned by hash: .github/workflows/publish.yml:25","Warn: pipCommand not pinned by hash: .github/workflows/static-analysis.yml:47","Warn: pipCommand not pinned by hash: .github/workflows/test.yml:54","Warn: pipCommand not pinned by hash: .github/workflows/test.yml:117","Info:   0 out of  21 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   5 third-party GitHubAction dependencies pinned","Info:   0 out of   5 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":5,"reason":"5 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-27mf-ghqm-j3j8","Warn: Project is vulnerable to: GHSA-8495-4g3g-x7pr","Warn: Project is vulnerable to: GHSA-9548-qrrj-x5pj","Warn: Project is vulnerable to: PYSEC-2025-49 / GHSA-5rjg-fvgr-3xxf","Warn: Project is vulnerable to: PYSEC-2024-187 / GHSA-rqc4-2hc7-8c8v"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: SAST configuration detected: CodeQL","Info: all commits (30) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T02:56:14.667Z","repository_id":22286563,"created_at":"2025-08-17T02:56:14.667Z","updated_at":"2025-08-17T02:56:14.667Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278395882,"owners_count":25979685,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","home-automation","python3","rest-api","sprinkler-controller"],"created_at":"2024-10-03T16:39:14.643Z","updated_at":"2025-10-05T00:36:20.658Z","avatar_url":"https://github.com/bachya.png","language":"Python","funding_links":["https://www.buymeacoffee.com/bachya1208P"],"categories":[],"sub_categories":[],"readme":"# 💧 Regenmaschine: A Simple Python Library for RainMachine™\n\n[![CI][ci-badge]][ci]\n[![PyPI][pypi-badge]][pypi]\n[![Version][version-badge]][version]\n[![License][license-badge]][license]\n[![Code Coverage][codecov-badge]][codecov]\n[![Maintainability][maintainability-badge]][maintainability]\n\n\u003ca href=\"https://www.buymeacoffee.com/bachya1208P\" target=\"_blank\"\u003e\u003cimg src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\" alt=\"Buy Me A Coffee\" height=\"41\" width=\"174\"\u003e\u003c/a\u003e\n\n`regenmaschine` (German for \"rain machine\") is a simple, clean, well-tested\nPython library for interacting with\n[RainMachine™ smart sprinkler controllers][regenmaschine]. It gives developers an easy\nAPI to manage their controllers over their local LAN or remotely via the RainMachine™\ncloud.\n\n- [Remote Access Announcement](#remote-access-announcement-2022-06-26)\n- [Python Versions](#python-versions)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Loading Controllers Multiple Times](#loading-controllers-multiple-times)\n- [Contributing](#contributing)\n\n# Remote Access Announcement (2022-06-26)\n\nOn June 2, 2022, RainMachine announced a [Premium Services][rainmachine-premium]\naddition; under this new model, remote access is _only_ available to subscribers of\nthese Premium Services.\n\nI do not currently intend to subscribe to Premium Services; as such, the remote access\nabilities of `regenmaschine` will remain as-is from here on out unless spurred on by\nothers. They may stop working at any time. PRs from subscribing users are always\nwelcome.\n\n# Python Versions\n\n`regenmaschine` is currently supported on:\n\n- Python 3.10\n- Python 3.11\n- Python 3.12\n\n# Installation\n\n```bash\npip install regenmaschine\n```\n\n# Usage\n\nCreating a `regenmaschine` `Client` might be the easiest thing you do all day:\n\n```python\nimport asyncio\n\nfrom aiohttp import ClientSession\n\nfrom regenmaschine import Client\n\n\nasync def main() -\u003e None:\n    \"\"\"Run!\"\"\"\n    client = Client()\n\n    # ...\n\n\nasyncio.run(main())\n```\n\nBy default, the library creates a new connection to the sprinkler controller with each\ncoroutine. If you are calling a large number of coroutines (or merely want to squeeze\nout every second of runtime savings possible), an [`aiohttp`][aiohttp] `ClientSession` can\nbe used for connection pooling:\n\nSee the module docstrings throughout the library for full info on all parameters, return\ntypes, etc.\n\n```python\nimport asyncio\n\nfrom aiohttp import ClientSession\n\nfrom regenmaschine import Client\n\n\nasync def main() -\u003e None:\n    \"\"\"Run!\"\"\"\n    async with ClientSession() as session:\n        client = Client(session=session)\n\n\nasyncio.run(main())\n```\n\n## Loading Local (Accessible Over the LAN) Controllers\n\nOnce you have a client, you can load a local controller (i.e., one that is\naccessible over the LAN) very easily:\n\n```python\nimport asyncio\n\nfrom aiohttp import ClientSession\n\nfrom regenmaschine import Client\n\n\nasync def main() -\u003e None:\n    \"\"\"Run!\"\"\"\n    async with ClientSession() as session:\n        client = Client(session=session)\n\n        await client.load_local(\"192.168.1.101\", \"my_password\", port=8080, use_ssl=True)\n\n        controllers = client.controllers\n        # \u003e\u003e\u003e {'ab:cd:ef:12:34:56': \u003cLocalController\u003e}\n\n\nasyncio.run(main())\n```\n\n## Loading Remote (Accessible Over the RainMachine Cloud) Controllers\n\nIf you have 1, 2 or 100 other local controllers, you can load them in the same\nway – `client.controllers` will keep your controllers all organized.\n\nWhat if you have controllers around the world and can't access them all over\nthe same local network? No problem! `regenmaschine` allows you to load remote\ncontrollers very easily, as well:\n\n```python\nimport asyncio\n\nfrom aiohttp import ClientSession\n\nfrom regenmaschine import Client\n\n\nasync def main() -\u003e None:\n    \"\"\"Run!\"\"\"\n    async with ClientSession() as session:\n        client = Client(session=session)\n\n        await client.load_remote(\"rainmachine_email@host.com\", \"my_password\")\n\n        controllers = client.controllers\n        # \u003e\u003e\u003e {'xx:xx:xx:xx:xx:xx': \u003cRemoteController\u003e, ...}\n\n\nasyncio.run(main())\n```\n\nBonus tip: `client.load_remote` will load _all_ controllers owned by that email\naddress.\n\n## Using the Controller\n\nRegardless of the type of controller you have loaded (local or remote), the\nsame properties and methods are available to each:\n\n```python\nimport asyncio\nimport datetime\n\nfrom aiohttp import ClientSession\n\nfrom regenmaschine import Client\n\n\nasync def main() -\u003e None:\n    \"\"\"Run!\"\"\"\n    async with ClientSession() as session:\n        client = Client(session=session)\n\n        # Load a local controller:\n        await client.load_local(\"192.168.1.101\", \"my_password\", port=8080, use_ssl=True)\n\n        # Load all remote controllers associated with an account:\n        await client.load_remote(\"rainmachine_email@host.com\", \"my_password\")\n\n        # They all act the same! The only difference is that remote API calls\n        # will pass through the RainMachine™ cloud:\n        for mac_address, controller in client.controllers:\n            # Print some client properties:\n            print(f\"Name: {controller.name}\")\n            print(f\"Host: {controller.host}\")\n            print(f\"MAC Address: {controller.mac}\")\n            print(f\"API Version: {controller.api_version}\")\n            print(f\"Software Version: {controller.software_version}\")\n            print(f\"Hardware Version: {controller.hardware_version}\")\n\n            # Get all diagnostic information:\n            diagnostics = await controller.diagnostics.current()\n\n            # Get all weather parsers:\n            parsers = await controller.parsers.current()\n\n            # Get all programs:\n            programs = await controller.programs.all()\n\n            # Include inactive programs:\n            programs = await controller.programs.all(include_inactive=True)\n\n            # Get a specific program:\n            program_1 = await controller.programs.get(1)\n\n            # Enable or disable a specific program:\n            await controller.programs.enable(1)\n            await controller.programs.disable(1)\n\n            # Get the next run time for all programs:\n            runs = await controller.programs.next()\n\n            # Get all running programs:\n            programs = await controller.programs.running()\n\n            # Start and stop a program:\n            await controller.programs.start(1)\n            await controller.programs.stop(1)\n\n            # Get basic details about all zones:\n            zones = await controller.zones.all()\n\n            # Get advanced details about all zones:\n            zones = await controller.zones.all(details=True)\n\n            # Include inactive zones:\n            zones = await controller.zones.all(include_inactive=True)\n\n            # Get basic details about a specific zone:\n            zone_1 = await controller.zones.get(1)\n\n            # Get advanced details about a specific zone:\n            zone_1 = await controller.zones.get(1, details=True)\n\n            # Enable or disable a specific zone:\n            await controller.zones.enable(1)\n            await controller.zones.disable(1)\n\n            # Start a zone for 60 seconds:\n            await controller.zones.start(1, 60)\n\n            # ...and stop it:\n            await controller.zones.stop(1)\n\n            # Get all running zones:\n            programs = await controller.zones.running()\n\n            # Get the device name:\n            name = await controller.provisioning.device_name\n\n            # Get all provisioning settings:\n            settings = await controller.provisioning.settings()\n\n            # Get all networking info related to the device:\n            wifi = await controller.provisioning.wifi()\n\n            # Get various types of active watering restrictions:\n            current = await controller.restrictions.current()\n            universal = await controller.restrictions.universal()\n            hourly = await controller.restrictions.hourly()\n            raindelay = await controller.restrictions.raindelay()\n\n            # Set universal restrictions – note that the payload is the same structure\n            # as returned by controller.restrictions.universal():\n            await controller.restrictions.set_universal(\n                {\n                    \"hotDaysExtraWatering\": False,\n                    \"freezeProtectEnabled\": True,\n                }\n            )\n\n            # Get watering stats:\n            today = await controller.stats.on_date(datetime.date.today())\n            upcoming_days = await controller.stats.upcoming(details=True)\n\n            # Get info on various watering activities not already covered:\n            log = await controller.watering.log(datetime.date.today(), 2)\n            queue = await controller.watering.queue()\n            runs = await controller.watering.runs(datetime.date.today())\n\n            # Pause all watering activities for 30 seconds:\n            await controller.watering.pause_all(30)\n\n            # Unpause all watering activities:\n            await controller.watering.unpause_all()\n\n            # Stop all watering activities:\n            await controller.watering.stop_all()\n\n            # See if a firmware update is available:\n            update_data = await controller.machine.get_firmware_update_status()\n            # ...and request the update:\n            update_data = await controller.machine.update_firmware()\n\n            # Reboot the controller:\n            update_data = await controller.machine.reboot()\n\n            # Return the current flow meter data:\n            flowmeter = await controller.watering.flowmeter()\n\n            # Add values to flowmeter counters from an external smart water meter\n            # not wired directly to the controller.\n            # Units can be \"clicks\", \"gal\", \"m3\" and \"litre\".\n            await controller.watering.post_flowmeter({\"value\": 2000, \"units\": \"clicks\"})\n\n\nasyncio.run(main())\n```\n\nCheck out `example.py`, the tests, and the source files themselves for method\nsignatures and more examples. For additional reference, the full RainMachine™ API\ndocumentation is available [here][rainmachine-api].\n\n# Loading Controllers Multiple Times\n\nIt is technically possible to load a controller multiple times. Let's pretend\nfor a moment that:\n\n- We have a local controller named `Home` (available at `192.168.1.101`).\n- We have a remote controller named `Grandma's House`.\n- Both controllers live under our email address: `user@host.com`\n\nIf we load them thus:\n\n```python\nimport asyncio\n\nfrom aiohttp import ClientSession\n\nfrom regenmaschine import Client\n\n\nasync def main() -\u003e None:\n    \"\"\"Run!\"\"\"\n    async with ClientSession() as session:\n        client = Client(session=session)\n\n        # Load \"Home\" locally:\n        await client.load_local(\"192.168.1.101\", \"my_password\")\n\n        # Load all of my controllers remotely:\n        await client.load_remote(\"user@host.com\", \"my_password\")\n\n\nasyncio.run(main())\n```\n\n...then we will have the following:\n\n1. `Home` will be a `LocalController` and accessible over the LAN.\n2. `Grandma's House` will be a `RemoteController` and accessible only over the\n   RainMachine™ cloud.\n\nNotice that `regenmaschine` is smart enough to not overwrite a controller that\nalready exists: even though `Home` exists as a remote controller owned by\n`user@host.com`, it had already been loaded locally. By default,\n`regenmaschine` will only load a controller if it hasn't been loaded before\n(locally _or_ remotely). If you want to change this behavior, both `load_local`\nand `load_remote` accept an optional `skip_existing` parameter:\n\n```python\nimport asyncio\n\nfrom aiohttp import ClientSession\n\nfrom regenmaschine import Client\n\n\nasync def main() -\u003e None:\n    \"\"\"Run!\"\"\"\n    async with ClientSession() as session:\n        client = Client(session=session)\n\n        # Load all of my controllers remotely:\n        await client.load_remote(\"user@host.com\", \"my_password\")\n\n        # Load \"Home\" locally, overwriting the existing remote controller:\n        await client.load_local(\"192.168.1.101\", \"my_password\", skip_existing=False)\n\n\nasyncio.run(main())\n```\n\n# Contributing\n\nThanks to all of [our contributors][contributors] so far!\n\n1. [Check for open features/bugs][issues] or [initiate a discussion on one][new-issue].\n2. [Fork the repository][fork].\n3. (_optional, but highly recommended_) Create a virtual environment: `python3 -m venv .venv`\n4. (_optional, but highly recommended_) Enter the virtual environment: `source ./.venv/bin/activate`\n5. Install the dev environment: `script/setup`\n6. Code your new feature or bug fix on a new branch.\n7. Write tests that cover your new functionality.\n8. Run tests and ensure 100% code coverage: `poetry run pytest --cov regenmaschine tests`\n9. Update `README.md` with any new documentation.\n10. Submit a pull request!\n\n[aiohttp]: https://github.com/aio-libs/aiohttp\n[ci-badge]: https://img.shields.io/github/actions/workflow/status/bachya/regenmaschine/test.yml\n[ci]: https://github.com/bachya/regenmaschine/actions\n[codecov-badge]: https://codecov.io/gh/bachya/regenmaschine/branch/dev/graph/badge.svg\n[codecov]: https://codecov.io/gh/bachya/regenmaschine\n[contributors]: https://github.com/bachya/regenmaschine/graphs/contributors\n[fork]: https://github.com/bachya/regenmaschine/fork\n[issues]: https://github.com/bachya/regenmaschine/issues\n[license-badge]: https://img.shields.io/pypi/l/regenmaschine.svg\n[license]: https://github.com/bachya/regenmaschine/blob/main/LICENSE\n[maintainability-badge]: https://api.codeclimate.com/v1/badges/cb14e60d5f5a4c2ccb2c/maintainability\n[maintainability]: https://codeclimate.com/github/bachya/regenmaschine/maintainability\n[new-issue]: https://github.com/bachya/regenmaschine/issues/new\n[pypi-badge]: https://img.shields.io/pypi/v/regenmaschine.svg\n[pypi]: https://pypi.python.org/pypi/regenmaschine\n[rainmachine-api]: https://rainmachine.docs.apiary.io/\n[rainmachine-premium]: https://www.rainmachine.com/premium/\n[regenmaschine]: http://www.rainmachine.com/\n[version-badge]: https://img.shields.io/pypi/pyversions/regenmaschine.svg\n[version]: https://pypi.python.org/pypi/regenmaschine\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbachya%2Fregenmaschine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbachya%2Fregenmaschine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbachya%2Fregenmaschine/lists"}