A simple API for RainMachine sprinkler controllers
Project description
💧 Regenmaschine: A Simple Python Library for RainMachine™
regenmaschine
(German for "rain machine") is a simple, clean, well-tested
Python library for interacting with
RainMachine™ smart sprinkler controllers.
It gives developers an easy API to manage their controllers over their local
LAN or remotely via the RainMachine™ cloud.
Python Versions
regenmaschine
is currently supported on:
- Python 3.5
- Python 3.6
- Python 3.7
However, running the test suite currently requires Python 3.6 or higher; tests run on Python 3.5 will fail.
Installation
pip install regenmaschine
Example
regenmaschine
starts within an
aiohttp ClientSession
:
import asyncio
from aiohttp import ClientSession
from regenmaschine import Client
async def main() -> None:
"""Create the aiohttp session and run the example."""
async with ClientSession() as websession:
# YOUR CODE HERE...
asyncio.get_event_loop().run_until_complete(main())
Creating a regenmaschine
Client
might be the easiest thing you do all day:
import asyncio
from aiohttp import ClientSession
from regenmaschine import Client
async def main() -> None:
"""Create the aiohttp session and run the example."""
async with ClientSession() as websession:
client = Client(websession)
asyncio.get_event_loop().run_until_complete(main())
Once you have a client, you can load a local controller (i.e., one that is accessible over the LAN) very easily:
import asyncio
from aiohttp import ClientSession
from regenmaschine import Client
async def main() -> None:
"""Create the aiohttp session and run the example."""
async with ClientSession() as websession:
client = Client(websession)
await client.load_local(
'192.168.1.101', 'my_password', port=8080, ssl=True)
controllers = client.controllers
# >>> {'ab:cd:ef:12:34:56': <LocalController>}
asyncio.get_event_loop().run_until_complete(main())
If you have 1, 2 or 100 other local controllers, you can load them in the same
way – client.controllers
will keep your controllers all organized.
What if you have controllers around the world and can't access them all over
the same local network? No problem! regenmaschine
allows you to load remote
controllers very easily, as well:
import asyncio
from aiohttp import ClientSession
from regenmaschine import Client
async def main() -> None:
"""Create the aiohttp session and run the example."""
async with ClientSession() as websession:
client = Client(websession)
await client.load_remote('rainmachine_email@host.com', 'my_password')
controllers = client.controllers
# >>> {'fe:dc:ba:98:76:54': <RemoteController>, ...}
asyncio.get_event_loop().run_until_complete(main())
Bonus tip: client.load_remote
will load all controllers owned by that email
address.
Regardless of the type of controller you have loaded (local or remote), the same properties and methods are available to each:
import asyncio
from aiohttp import ClientSession
import regenmaschine
async def main() -> None:
"""Create the aiohttp session and run the example."""
async with ClientSession() as websession:
client = Client(websession)
# Load a local controller:
await client.load_local(
'192.168.1.101', 'my_password', port=8080, ssl=True)
# Load all remote controllers associated with an account:
await client.load_remote('rainmachine_email@host.com', 'my_password')
# They all act the same! The only difference is that remote API calls
# will pass through the RainMachine™ cloud:
for mac_address, controller in client.controllers:
# Print some client properties:
print('Name: {0}'.format(controller.name))
print('Host: {0}'.format(controller.host))
print('MAC Address: {0}'.format(controller.mac))
print('API Version: {0}'.format(controller.api_version))
print('Software Version: {0}'.format(controller.software_version))
print('Hardware Version: {0}'.format(controller.hardware_version))
# Get all diagnostic information:
diagnostics = await controller.diagnostics.current()
# Get all weather parsers:
parsers = await controller.parsers.current():
# Get all programs:
programs = await controller.programs.all():
# Include inactive programs:
programs = await controller.programs.all(include_inactive=True):
# Get a specific program:
program_1 = await controller.programs.get(1)
# Enable or disable a specific program:
await controller.programs.enable(1)
await controller.programs.disable(1)
# Get the next run time for all programs:
runs = await controller.programs.next()
# Get all running programs:
programs = await controller.programs.running()
# Start and stop a program:
await controller.programs.start(1)
await controller.programs.stop(1)
# Get basic details about all zones:
zones = await controller.zones.all():
# Get advanced details about all zones:
zones = await controller.zones.all(details=True):
# Include inactive zones:
zones = await controller.zones.all(include_inactive=True):
# Get basic details about a specific zone:
zone_1 = await controller.zones.get(1)
# Get advanced details about a specific zone:
zone_1 = await controller.zones.get(1, details=True)
# Enable or disable a specific zone:
await controller.zones.enable(1)
await controller.zones.disable(1)
# Start a zone for 60 seconds:
await controller.zones.start(1, 60)
# ...and stop it:
await controller.zones.stop(1)
# Get the device name:
name = await controller.provisioning.device_name
# Get all provisioning settings:
settings = await controller.provisioning.settings()
# Get all networking info related to the device:
wifi = await controller.provisioning.wifi()
# Get various types of active watering restrictions:
current = await controller.restrictions.current()
universal = await controller.restrictions.universal()
hourly = await controller.restrictions.hourly():
raindelay = await controller.restrictions.raindelay()
# Get watering stats:
today = await controller.stats.on_date(date=datetime.date.today())
upcoming_days = await controller.stats.upcoming(details=True):
# Get info on various watering activities not already covered:
log = await controller.watering.log(date=datetime.date.today(), 2):
queue = await controller.watering.queue()
runs = await controller.watering.runs(date=datetime.date.today())
# Pause all watering activities for 30 seconds:
await controller.watering.pause_all(30)
# Unpause all watering activities:
await controller.watering.unpause_all()
# Stop all watering activities:
await controller.watering.stop_all()
asyncio.get_event_loop().run_until_complete(main())
Check out example.py
, the tests, and the source files themselves for method
signatures and more examples.
Loading Controllers Multiple Times
It is technically possible to load a controller multiple times. Let's pretend for a moment that:
- We have a local controller named
Home
(available at192.168.1.101
). - We have a remote controller named
Grandma's House
. - Both controllers live under our email address:
user@host.com
If we load them thus:
import asyncio
from aiohttp import ClientSession
from regenmaschine import Client
async def main() -> None:
"""Create the aiohttp session and run the example."""
async with ClientSession() as websession:
client = Client(websession)
# Load "Home" locally:
await client.load_local('192.168.1.101', 'my_password')
# Load all of my controllers remotely:
await client.load_remote('user@host.com', 'my_password')
asyncio.get_event_loop().run_until_complete(main())
...then we will have the following:
Home
will be aLocalController
and accessible over the LAN.Grandma's House
will be aRemoteController
and accessible only over the RainMachine™ cloud.
Notice that regenmaschine
is smart enough to not overwrite a controller that
already exists: even though Home
exists as a remote controller owned by
user@host.com
, it had already been loaded locally. By default,
regenmaschine
will only load a controller if it hasn't been loaded before
(locally or remotely). If you want to change this behavior, both load_local
and load_remote
accept an optional skip_existing
parameter:
import asyncio
from aiohttp import ClientSession
from regenmaschine import Client
async def main() -> None:
"""Create the aiohttp session and run the example."""
async with ClientSession() as websession:
client = Client(websession)
# Load all of my controllers remotely:
await client.load_remote('user@host.com', 'my_password')
# Load "Home" locally, overwriting the existing remote controller:
await client.load_local(
'192.168.1.101', 'my_password', skip_existing=False)
asyncio.get_event_loop().run_until_complete(main())
Contributing
- Check for open features/bugs or initiate a discussion on one.
- Fork the repository.
- Install the dev environment:
make init
. - Enter the virtual environment:
pipenv shell
- Code your new feature or bug fix.
- Write a test that covers your new functionality.
- Update
README.md
with any new documentation. - Run tests and ensure 100% code coverage:
make coverage
- Ensure you have no linting errors:
make lint
- Ensure you have no typed your code correctly:
make typing
- Add yourself to
AUTHORS.md
. - Submit a pull request!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file regenmaschine-1.5.0.tar.gz
.
File metadata
- Download URL: regenmaschine-1.5.0.tar.gz
- Upload date:
- Size: 19.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 853bc0669edc652d3510aa593d748746fc1d502d7235698d6fd1de1c1a97370e |
|
MD5 | 557833880056eec7fd255da179ca79d5 |
|
BLAKE2b-256 | 916be22842860e06599ee4628188cf285dd559e0ef720b9a1795e9b1d817372d |
File details
Details for the file regenmaschine-1.5.0-py3-none-any.whl
.
File metadata
- Download URL: regenmaschine-1.5.0-py3-none-any.whl
- Upload date:
- Size: 23.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 10af945cb3ae4d3cd044ad760a653856e971c85b22a68fc77e5943833cd1c1ef |
|
MD5 | 187802cac0dbfd9bb20423c62aa68b03 |
|
BLAKE2b-256 | 97e73dfa81bc5d76e95213196e79435a3bbb6d461161c5d1ebd09a4168de3824 |