pax_global_header 0000666 0000000 0000000 00000000064 14545226752 0014526 g ustar 00root root 0000000 0000000 52 comment=7f3c210b54dcd418128a489f8417432c9d6dc997
rfverbruggen-rachiopy-7f3c210/ 0000775 0000000 0000000 00000000000 14545226752 0016367 5 ustar 00root root 0000000 0000000 rfverbruggen-rachiopy-7f3c210/.all-contributorsrc 0000664 0000000 0000000 00000001123 14545226752 0022215 0 ustar 00root root 0000000 0000000 {
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"commitType": "docs",
"commitConvention": "angular",
"contributors": [
{
"login": "brg468",
"name": "Brian Rogers",
"avatar_url": "https://avatars.githubusercontent.com/u/19143191?v=4",
"profile": "https://github.com/brg468",
"contributions": [
"code",
"doc",
"test"
]
}
],
"contributorsPerLine": 7,
"skipCi": true,
"repoType": "github",
"repoHost": "https://github.com",
"projectName": "rachiopy",
"projectOwner": "rfverbruggen"
}
rfverbruggen-rachiopy-7f3c210/.all-contributorsrc.json 0000664 0000000 0000000 00000000102 14545226752 0023161 0 ustar 00root root 0000000 0000000 {
"projectName": "rachiopy",
"projectOwner": "rfverbruggen"
}
rfverbruggen-rachiopy-7f3c210/.github/ 0000775 0000000 0000000 00000000000 14545226752 0017727 5 ustar 00root root 0000000 0000000 rfverbruggen-rachiopy-7f3c210/.github/workflows/ 0000775 0000000 0000000 00000000000 14545226752 0021764 5 ustar 00root root 0000000 0000000 rfverbruggen-rachiopy-7f3c210/.github/workflows/codeql-analysis.yml 0000664 0000000 0000000 00000004621 14545226752 0025602 0 ustar 00root root 0000000 0000000 # For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ dev, master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ dev ]
schedule:
- cron: '28 6 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# âšī¸ Command-line programs to run using the OS shell.
# đ https://git.io/JvXDl
# âī¸ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
rfverbruggen-rachiopy-7f3c210/.github/workflows/lint.yml 0000664 0000000 0000000 00000001555 14545226752 0023463 0 ustar 00root root 0000000 0000000 name: Run linters
on: [push, pull_request]
jobs:
test:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f requirements_test.txt ]; then pip install -r requirements_test.txt; fi
- name: Run pylint
run: pylint rachiopy tests
- name: Run flake8
run: flake8
- name: Run pydocstyle
run: pydocstyle {posargs:rachiopy tests}
rfverbruggen-rachiopy-7f3c210/.github/workflows/publish.yml 0000664 0000000 0000000 00000002245 14545226752 0024160 0 ustar 00root root 0000000 0000000 name: Publish Python distributions to PyPI
on:
release:
types: [published]
jobs:
build-n-publish:
name: Build and publish Python distributions to PyPI
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/project/RachioPy
permissions:
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- uses: actions/checkout@master
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -r requirements.txt
- name: Run unit tests
run: python -m unittest discover -v tests
- name: Build distribution
run: python setup.py sdist bdist_wheel
- name: Publish distribution to Test PyPI
if: startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
- name: Publish distribution to PyPI
if: startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@release/v1
rfverbruggen-rachiopy-7f3c210/.github/workflows/publish_test.yml 0000664 0000000 0000000 00000002004 14545226752 0025210 0 ustar 00root root 0000000 0000000 name: Publish Python distributions to Test PyPI
on:
push:
branches:
- dev
jobs:
build-n-publish:
name: Build and publish Python distributions to Test PyPI
runs-on: ubuntu-latest
environment:
name: pypi
url: https://test.pypi.org/project/RachioPy
permissions:
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- uses: actions/checkout@master
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -r requirements.txt
- name: Run unit tests
run: python -m unittest discover -v tests
- name: Build distribution
run: python setup.py sdist bdist_wheel
- name: Publish package distributions to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
rfverbruggen-rachiopy-7f3c210/.github/workflows/test.yml 0000664 0000000 0000000 00000001635 14545226752 0023473 0 ustar 00root root 0000000 0000000 name: Run unit tests
on: [push, pull_request]
jobs:
test:
# The type of runner that the job will run on
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f requirements_test.txt ]; then pip install -r requirements_test.txt; fi
- name: Run unittests
run: python -m unittest discover -v tests
rfverbruggen-rachiopy-7f3c210/.gitignore 0000664 0000000 0000000 00000001353 14545226752 0020361 0 ustar 00root root 0000000 0000000 # Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
.python-version
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# VSCode
.vscode/ rfverbruggen-rachiopy-7f3c210/.hound.yml 0000664 0000000 0000000 00000000062 14545226752 0020303 0 ustar 00root root 0000000 0000000 fail_on_violations: false
python:
enabled: true rfverbruggen-rachiopy-7f3c210/.pylintrc 0000664 0000000 0000000 00000000040 14545226752 0020226 0 ustar 00root root 0000000 0000000 [MESSAGES CONTROL]
disable=R0801 rfverbruggen-rachiopy-7f3c210/.readthedocs.yml 0000664 0000000 0000000 00000000371 14545226752 0021456 0 ustar 00root root 0000000 0000000 # .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
rfverbruggen-rachiopy-7f3c210/LICENSE.txt 0000664 0000000 0000000 00000002063 14545226752 0020213 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2017 Robbert Verbruggen
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.
rfverbruggen-rachiopy-7f3c210/README.md 0000664 0000000 0000000 00000002745 14545226752 0017656 0 ustar 00root root 0000000 0000000 # Rachiopy
[](#contributors-)
This python package provides a interface to the Rachio public API.
## Usage
```python
from rachiopy import Rachio
r = Rachio("authtoken")
r.person.info()
```
For the complete documentation visit [read the docs](https://rachiopy.readthedocs.io/en/latest/).
## Contributors
rfverbruggen-rachiopy-7f3c210/docs/ 0000775 0000000 0000000 00000000000 14545226752 0017317 5 ustar 00root root 0000000 0000000 rfverbruggen-rachiopy-7f3c210/docs/Makefile 0000664 0000000 0000000 00000001172 14545226752 0020760 0 ustar 00root root 0000000 0000000 # Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
rfverbruggen-rachiopy-7f3c210/docs/conf.py 0000664 0000000 0000000 00000003640 14545226752 0020621 0 ustar 00root root 0000000 0000000 # Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
sys.setrecursionlimit(1500)
# -- Project information -----------------------------------------------------
project = 'RachioPy'
copyright = '2020, Robbert Verbruggen'
author = 'Robbert Verbruggen'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'classic'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# set the master doc
master_doc = 'index'
rfverbruggen-rachiopy-7f3c210/docs/device.rst 0000664 0000000 0000000 00000000117 14545226752 0021307 0 ustar 00root root 0000000 0000000 Device module
===================
.. automodule:: rachiopy.device
:members: rfverbruggen-rachiopy-7f3c210/docs/flexschedulerule.rst 0000664 0000000 0000000 00000000147 14545226752 0023416 0 ustar 00root root 0000000 0000000 Flexschedulerule module
=======================
.. automodule:: rachiopy.flexschedulerule
:members: rfverbruggen-rachiopy-7f3c210/docs/index.rst 0000664 0000000 0000000 00000002364 14545226752 0021165 0 ustar 00root root 0000000 0000000 ===================
Welcome to RachioPy
===================
This python package provides a interface to the Rachio public API.
Library Installation
====================
.. code-block:: bash
$ pip install rachiopy
Getting Started
===============
.. code-block:: python
from rachiopy import Rachio
r = Rachio("8e600a4c-0027-4a9a-9bda-dc8d5c90350d")
resp, content = r.person.info()
print (resp["status"])
print (content["id"])
This prints:
.. code-block:: text
200
ccd8bb4d-d7ef-407c-b029-1c578c7a98d8
Source code
===========
The project is hosted on GitHub
Please feel free to file an issue on the bug tracker if you have found a bug
or have some suggestion in order to improve the library.
Dependencies
============
- Python 3.6+
- requests
Authors and License
===================
The rachiopy package is written mostly by Robbert Verbruggen.
It's MIT licensed and freely available.
Feel free to improve this package and send a pull request to GitHub.
Table Of Contents
=================
.. toctree::
:maxdepth: 2
person
device
zone
schedulerule
flexschedulerule
notification
rachioobject
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
rfverbruggen-rachiopy-7f3c210/docs/make.bat 0000664 0000000 0000000 00000001370 14545226752 0020725 0 ustar 00root root 0000000 0000000 @ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd
rfverbruggen-rachiopy-7f3c210/docs/notification.rst 0000664 0000000 0000000 00000000133 14545226752 0022534 0 ustar 00root root 0000000 0000000 Notification module
===================
.. automodule:: rachiopy.notification
:members: rfverbruggen-rachiopy-7f3c210/docs/person.rst 0000664 0000000 0000000 00000000117 14545226752 0021356 0 ustar 00root root 0000000 0000000 Person module
===================
.. automodule:: rachiopy.person
:members: rfverbruggen-rachiopy-7f3c210/docs/rachioobject.rst 0000664 0000000 0000000 00000000133 14545226752 0022502 0 ustar 00root root 0000000 0000000 RachioObject module
===================
.. automodule:: rachiopy.rachioobject
:members: rfverbruggen-rachiopy-7f3c210/docs/schedulerule.rst 0000664 0000000 0000000 00000000133 14545226752 0022532 0 ustar 00root root 0000000 0000000 Schedulerule module
===================
.. automodule:: rachiopy.schedulerule
:members: rfverbruggen-rachiopy-7f3c210/docs/zone.rst 0000664 0000000 0000000 00000000113 14545226752 0021017 0 ustar 00root root 0000000 0000000 Zone module
===================
.. automodule:: rachiopy.zone
:members: rfverbruggen-rachiopy-7f3c210/rachiopy/ 0000775 0000000 0000000 00000000000 14545226752 0020205 5 ustar 00root root 0000000 0000000 rfverbruggen-rachiopy-7f3c210/rachiopy/__init__.py 0000664 0000000 0000000 00000002252 14545226752 0022317 0 ustar 00root root 0000000 0000000 """Main rachiopy module."""
from rachiopy.rachioobject import RachioObject
from rachiopy.person import Person
from rachiopy.device import Device
from rachiopy.flexschedulerule import FlexSchedulerule
from rachiopy.notification import Notification
from rachiopy.schedulerule import Schedulerule
from rachiopy.zone import Zone
from rachiopy.valve import Valve
from rachiopy.summary import SummaryServce
from rachiopy.program import Program
class Rachio(RachioObject):
"""Object representing the Rachio API."""
# pylint: disable=too-many-instance-attributes
def __init__(self, authtoken: str):
"""Initialze the Rachio API wrapper.
:param authtoken: The API authentication token.
:type authtoken: str
"""
super().__init__(authtoken)
self.person = Person(authtoken)
self.device = Device(authtoken)
self.flexschedulerule = FlexSchedulerule(authtoken)
self.notification = Notification(authtoken)
self.schedulerule = Schedulerule(authtoken)
self.zone = Zone(authtoken)
self.valve = Valve(authtoken)
self.summary = SummaryServce(authtoken)
self.program = Program(authtoken)
rfverbruggen-rachiopy-7f3c210/rachiopy/device.py 0000664 0000000 0000000 00000017315 14545226752 0022025 0 ustar 00root root 0000000 0000000 """Device module handling /device/ API calls."""
from rachiopy.rachioobject import RachioObject
class Device(RachioObject):
"""Device class with /device/ API calls."""
def get(self, dev_id: str):
"""Retrieve the information for a device entity.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicdeviceid
:param dev_id: Device's unique id
:type dev_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"device/{dev_id}"
return self.get_request(path)
def current_schedule(self, dev_id: str):
"""Retrieve current schedule running, if any.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicdeviceidcurrent_schedule
:param dev_id: Device's unique id
:type dev_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"device/{dev_id}/current_schedule"
return self.get_request(path)
def event(self, dev_id: str, starttime: int, endtime: int):
"""Retrieve events for a device entity.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicdeviceideventstarttimestarttimeendtimeendtim
:param dev_id: Device's unique id
:type dev_id: str
:param starttime: Query start time milliseconds unix epoch
:type starttime: int
:param endtime: Query end time milliseconds unix epoch
:type endtime: int
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"device/{dev_id}/event?startTime={starttime}&endTime={endtime}"
return self.get_request(path)
def forecast(self, dev_id: str, units="US"):
"""Retrieve current and predicted forecast.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicdeviceidforecastunitsunits
:param dev_id: Device's unique id
:type dev_id: str
:param units: Forecast data units, one of US or METRIC, defaults to US
:type units: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
assert units in ["US", "METRIC"], "units must be either US or METRIC"
path = f"device/{dev_id}/forecast?units={units}"
return self.get_request(path)
def stop_water(self, dev_id: str):
"""Stop all watering on device.
For more info of the content in the response see:
https://rachio.readme.io/docs/devicestop_water
:param dev_id: Device's unique id
:type dev_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"id": dev_id}
return self.put_request("device/stop_water", payload)
def rain_delay(self, dev_id: str, duration: int):
"""Rain delay device.
For more info of the content in the response see:
https://rachio.readme.io/docs/devicestop_water
:param dev_id: Device's unique id
:type dev_id: str
:param duration: Duration in seconds (Range is 0 - 604800 (7 days) )
:type duration: int
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
assert 0 <= duration <= 604800, "duration must be between 0 and 604800"
payload = {"id": dev_id, "duration": duration}
return self.put_request("device/rain_delay", payload)
def turn_on(self, dev_id: str):
"""Turn ON all features of the device.
schedules, weather intelligence, water budget, etc.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicdeviceon-1
:param dev_id: Device's unique id
:type dev_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"id": dev_id}
return self.put_request("device/on", payload)
def turn_off(self, dev_id: str):
"""Turn OFF all features of the device.
schedules, weather intelligence, water budget, etc.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicdeviceoff-1
:param dev_id: Device's unique id
:type dev_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"id": dev_id}
return self.put_request("device/off", payload)
def pause_zone_run(self, dev_id: str, duration: int):
"""Pause a zone run for device.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicdevicepause_zone_run
:param dev_id: Device's unique id
:type dev_id: str
:param duration: Duration in seconds (Range is 0 - 3600 (1 hour) )
:type duration: int
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
assert 0 <= duration <= 3600, "duration must be between 0 and 3600"
payload = {"id": dev_id, "duration": duration}
return self.put_request("device/pause_zone_run", payload)
def resume_zone_run(self, dev_id: str):
"""Resume a zone run for device.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicdeviceresume_zone_run
:param dev_id: Device's unique id
:type dev_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"id": dev_id}
return self.put_request("device/resume_zone_run", payload)
rfverbruggen-rachiopy-7f3c210/rachiopy/flexschedulerule.py 0000664 0000000 0000000 00000001627 14545226752 0024130 0 ustar 00root root 0000000 0000000 """Flexschedulerule module handling /flexschedulerule/ API calls."""
from rachiopy.rachioobject import RachioObject
class FlexSchedulerule(RachioObject):
"""FlexSchedulerule class with methods for /flexschedulerule/ calls."""
def get(self, flex_sched_rule_id: str):
"""Retrieve the information for a flexscheduleRule entity.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicflexscheduleruleid
:param flex_sched_rule_id: FlexScheduleRule's unique id
:type flex_sched_rule_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
path = f"flexschedulerule/{flex_sched_rule_id}"
return self.get_request(path)
rfverbruggen-rachiopy-7f3c210/rachiopy/notification.py 0000664 0000000 0000000 00000011347 14545226752 0023253 0 ustar 00root root 0000000 0000000 """Notification module handling /notification/ API calls."""
from rachiopy.rachioobject import RachioObject
class Notification(RachioObject):
"""Notification class with methods for /notification/ API calls."""
def get_webhook_event_type(self):
"""Retrieve the list of events types.
Event types that are available to any webhook for subscription.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicnotificationwebhook_event_type
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
return self.get_request("notification/webhook_event_type")
def get_device_webhook(self, dev_id: str):
"""Retrieve all webhooks for a device.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicnotificationdeviceidwebhook
:param dev_id: Device's unique id
:type dev_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
path = f"notification/{dev_id}/webhook"
return self.get_request(path)
def add(self, dev_id: str, external_id: str, url: str, event_types):
"""Add a webhook to a device.
externalId can be used as opaque data that
is tied to your company, and passed back in each webhook event
response.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicnotificationwebhook
:param dev_id: Device's unique id
:type dev_id: str
:param external_id: External company ID
:type exteranl_id: str
:param url: External webhook URL
:type url: str
:param event_type: Event types
:type event_type: Object[]
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
payload = {
"device": {"id": dev_id},
"externalId": external_id,
"url": url,
"eventTypes": event_types,
}
return self.post_request("notification/webhook", payload)
def update(self, hook_id: str, external_id: str, url: str, event_types):
"""Update a webhook.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicnotificationwebhook-1
:param hook_id: Webhook's unique id
:type hook_id: str
:param external_id: External company ID
:type exteranl_id: str
:param url: External webhook URL
:type url: str
:param event_type: Event types
:type event_type: Object[]
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
payload = {
"id": hook_id,
"externalId": external_id,
"url": url,
"eventTypes": event_types,
}
return self.put_request("notification/webhook", payload)
def delete(self, hook_id: str):
"""Remove a webhook.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicnotificationwebhookid
:param hook_id: Webhook's unique id
:type hook_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
path = f"notification/webhook/{hook_id}"
return self.delete_request(path)
def get(self, hook_id: str):
"""Get a webhook.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicnotificationdeviceidwebhook
:param hook_id: Webhook's unique id
:type hook_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
path = f"notification/webhook/{hook_id}"
return self.get_request(path)
rfverbruggen-rachiopy-7f3c210/rachiopy/person.py 0000664 0000000 0000000 00000002560 14545226752 0022070 0 ustar 00root root 0000000 0000000 """Person module handling /person/ API calls."""
from rachiopy.rachioobject import RachioObject
class Person(RachioObject):
"""Person class with methods for /person/ API calls."""
def info(self):
"""Retrieve the id for the person entity currently logged in.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicpersoninfo
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
return self.get_request("person/info")
def get(self, user_id: str):
"""Retrieve the information for a person entity.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicpersonid
:param user_id: Person's unique id
:type user_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"person/{user_id}"
return self.get_request(path)
rfverbruggen-rachiopy-7f3c210/rachiopy/program.py 0000664 0000000 0000000 00000006621 14545226752 0022233 0 ustar 00root root 0000000 0000000 """Program module for the smart hose timer."""
from rachiopy.rachioobject import RachioObject
class Program(RachioObject):
"""Program class for the smart hose timer."""
def list_programs(self, valve_id: str):
"""Retreive the list of programs (schedules) for a valve.
For more info of the content in the response see:
https://rachio.readme.io/docs/programservice_listprograms
:param valve_id: Valve's unique id
:type valve_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
path = f"program/listPrograms/{valve_id}"
return self.valve_get_request(path)
def get_program(self, program_id: str):
"""Retreive the information for a specific program.
For more info of the content in the response see:
https://rachio.readme.io/docs/programservice_getprogram
:param program_id: Program's unique id
:type program_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"program/getProgram/{program_id}"
return self.valve_get_request(path)
def create_skip_overrides(self, program_id: str, timestamp: str):
"""Create manual skips for the specific program run time.
You can retrieve the runtimes from SummaryService.getValveDayViews
For more info of the content in the response see:
https://rachio.readme.io/docs/programservice_createskipoverrides
:param program_id: Program's unique id
:type program_id: str
:param timestamp: Timestamp of the run to skip
:type timestamp: timestamp
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"programId": program_id, "timestamp": timestamp}
return self.valve_post_request("program/createSkipOverrides", payload)
def delete_skip_overrides(self, program_id: str, timestamp: str):
"""Cancel program skips for the specified program run time.
You can retrieve upcoming skips from SummaryService.getValveDayViews
For more info of the content in the response see:
https://rachio.readme.io/docs/programservice_deleteskipoverrides
:param program_id: Program's unique id
:type program_id: str
:param timestamp: Timestamp of the run skip to delete
:type timestamp: timestamp
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"programId": program_id, "timestamp": timestamp}
return self.valve_post_request("program/deleteSkipOverrides", payload)
rfverbruggen-rachiopy-7f3c210/rachiopy/rachioobject.py 0000664 0000000 0000000 00000014736 14545226752 0023226 0 ustar 00root root 0000000 0000000 """RachioObject module containing a helper class for all API calls."""
import json
from requests import Session
_API_URL = "https://api.rach.io/1/public"
_VALVE_URL = "https://cloud-rest.rach.io"
class RachioObject:
"""The Rachio base object."""
def __init__(self, authtoken: str, http_session=None, timeout=25):
"""Rachioobject class initializer.
:param authtoken: The API authentication token.
:type authtoken: str
:param http_session: The HTTP Session
:type http_session: Session
:param timeout: How long to wait for the server to send data before
giving up, as a float, or a (connect timeout, read timeout) tuple.
:type timeout: float
:type timeout: tuple
"""
self.authtoken = authtoken
self._headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {authtoken}",
}
self._http_session = http_session or Session()
self.timeout = timeout
def _request(self, path: str, method: str, body=None):
"""Make a request to the API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
if body is not None:
body = json.dumps(body)
url = f"{_API_URL}/{path}"
response = self._http_session.request(
method, url, headers=self._headers, data=body, timeout=self.timeout
)
content_type = response.headers.get("content-type")
headers = {k.lower(): v for k, v in response.headers.items()}
headers["status"] = response.status_code
if content_type and content_type.startswith("application/json"):
return headers, response.json()
return headers, response.text
def get_request(self, path: str, body=None):
"""Make a GET request to the API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
return self._request(path, "GET", body)
def put_request(self, path: str, body=None):
"""Make a PUT request to the API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
return self._request(path, "PUT", body)
def post_request(self, path: str, body=None):
"""Make a POST request to the API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
return self._request(path, "POST", body)
def delete_request(self, path: str, body=None):
"""Make a DELETE request to the API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
return self._request(path, "DELETE", body)
def _valve_request(self, path: str, method: str, body=None):
"""Make a request to the API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
if body is not None:
body = json.dumps(body)
url = f"{_VALVE_URL}/{path}"
response = self._http_session.request(
method, url, headers=self._headers, data=body, timeout=self.timeout
)
content_type = response.headers.get("content-type")
headers = {k.lower(): v for k, v in response.headers.items()}
headers["status"] = response.status_code
if content_type and content_type.startswith("application/json"):
return headers, response.json()
return headers, response.text
def valve_get_request(self, path: str, body=None):
"""Make a GET request to the valve API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
return self._valve_request(path, "GET", body)
def valve_put_request(self, path: str, body=None):
"""Make a PUT request to the valve API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
return self._valve_request(path, "PUT", body)
def valve_post_request(self, path: str, body=None):
"""Make a POST request to the valve API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
return self._valve_request(path, "POST", body)
def valve_delete_request(self, path: str, body=None):
"""Make a DELETE request to the valve API.
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
return self._valve_request(path, "DELETE", body)
rfverbruggen-rachiopy-7f3c210/rachiopy/schedulerule.py 0000664 0000000 0000000 00000006304 14545226752 0023246 0 ustar 00root root 0000000 0000000 """Schedulerule module handling /scheduerule/ API calls."""
from decimal import Decimal
from rachiopy.rachioobject import RachioObject
class Schedulerule(RachioObject):
"""Schedulerule class with methods for /schedulerule/ API calls."""
def skip(self, sched_rule_id: str):
"""Skip a schedule rule (watering time).
For more info of the content in the response see:
https://rachio.readme.io/docs/scheduleruleskip
:param sched_rule_id: Schedule rule's unique id
:type sched_rule_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
payload = {"id": sched_rule_id}
return self.put_request("schedulerule/skip", payload)
def start(self, sched_rule_id: str):
"""Start a schedule rule (watering time).
For more info of the content in the response see:
https://rachio.readme.io/docs/schedulerulestart
:param sched_rule_id: Schedule rule's unique id
:type sched_rule_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
payload = {"id": sched_rule_id}
return self.put_request("schedulerule/start", payload)
def seasonal_adjustment(self, sched_rule_id: str, adjustment: Decimal):
"""Seasonal adjustment for a schedule rule (watering time).
This adjustment amount will be applied to the overall run time of the
selected schedule while overriding any current adjustments.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicscheduleruleseasonal_adjustment
:param sched_rule_id: Schedule rule's unique id
:type sched_rule_id: str
:param adjustment: Seasonal adjustment percent from 100% to -100%
(valid data range is 1 to -1)
:type adjustment: Decimal
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
payload = {"id": sched_rule_id, "adjustment": adjustment}
return self.put_request("schedulerule/seasonal_adjustment", payload)
def get(self, sched_rule_id: str):
"""Retrieve the information for a scheduleRule entity.
For more info of the content in the response see:
https://rachio.readme.io/docs/publicscheduleruleid
:param sched_rule_id: Schedule rule's unique id
:type sched_rule_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
path = f"schedulerule/{sched_rule_id}"
return self.get_request(path)
rfverbruggen-rachiopy-7f3c210/rachiopy/summary.py 0000664 0000000 0000000 00000002064 14545226752 0022256 0 ustar 00root root 0000000 0000000 """Smart Hose Timer scheudle summary calls."""
from rachiopy.rachioobject import RachioObject
class SummaryServce(RachioObject):
"""Scheudle summary class."""
def get_valve_day_views(self, base_id: str, start, end):
"""List historical and upcoming valve runs and skips.
For more info of the content in the response see:
https://rachio.readme.io/docs/summaryservice_getvalvedayviews
:param base_id: Base's unique id
:type dev_id: str
:param start: Start date
:type start: Object[]
:param end: End date
:type end: Object[]
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body.
:rtype: tuple
"""
payload = {
"resourceId": {"baseStationId": base_id},
"start": start,
"end": end,
}
return self.valve_post_request("summary/getValveDayViews", payload)
rfverbruggen-rachiopy-7f3c210/rachiopy/valve.py 0000664 0000000 0000000 00000012331 14545226752 0021674 0 ustar 00root root 0000000 0000000 """Valve Service."""
from rachiopy.rachioobject import RachioObject
class Valve(RachioObject):
"""Valve class for smart hose timer."""
def get_base_station(self, base_id: str):
"""Retreive the information for a specific base station.
For more info of the content in the response see:
https://rachio.readme.io/docs/valveservice_getbasestation
:param base_id: Base station's unique id
:type user_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"valve/getBaseStation/{base_id}"
return self.valve_get_request(path)
def get_valve(self, valve_id: str):
"""Retrieve the information for a specific smart valve.
For more info of the content in the response see:
https://rachio.readme.io/docs/valveservice_getvalve
:param valve_id: Valve's unique id
:type user_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"valve/getValve/{valve_id}"
return self.valve_get_request(path)
def list_base_stations(self, user_id: str):
"""Retrieve all base stations for a given user ID.
For more info of the content in the response see:
https://rachio.readme.io/docs/valveservice_listbasestations
:param user_id: Person's unique id
:type user_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"valve/listBaseStations/{user_id}"
return self.valve_get_request(path)
def list_valves(self, base_id: str):
"""Retreive all valves on a given base station.
For more info of the content in the response see:
https://rachio.readme.io/docs/valveservice_listvalves
:param base_id: Base station's unique id
:type user_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"valve/listValves/{base_id}"
return self.valve_get_request(path)
def set_default_runtime(self, valve_id: str, duration: int):
"""Set the runtime for a valve when the button is pressed.
For more info of the content in the response see:
https://rachio.readme.io/docs/valveservice_setdefaultruntime
:param valve_id: Valve's unique id
:type user_id: str
:param duration: Duration in seconds
:type duration: int
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"valveId": valve_id, "defaultRuntimeSeconds": duration}
return self.valve_put_request("valve/setDefaultRuntime", payload)
def start_watering(self, valve_id: str, duration: int):
"""Start a valve.
For more info of the content in the response see:
https://rachio.readme.io/docs/valveservice_startwatering
:param valve_id: Valve's unique id
:type user_id: str
:param duration: Duration in seconds
:type duration: int
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
assert 0 <= duration <= 86400, "duration must be in range 0-86400"
payload = {"valveId": valve_id, "durationSeconds": duration}
return self.valve_put_request("valve/startWatering", payload)
def stop_watering(self, valve_id: str):
"""Stop a valve.
For more info of the content in the response see:
https://rachio.readme.io/docs/valveservice_stopwatering
:param valve_id: Valve's unique id
:type user_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"valveId": valve_id}
return self.valve_put_request("valve/stopWatering", payload)
rfverbruggen-rachiopy-7f3c210/rachiopy/zone.py 0000664 0000000 0000000 00000012276 14545226752 0021542 0 ustar 00root root 0000000 0000000 """Zone module handling /zone/ API calls."""
from decimal import Decimal
from rachiopy.rachioobject import RachioObject
class Zone(RachioObject):
"""Zone class with methods for /zone/ API calls."""
def start(self, zone_id: str, duration: int):
"""Start a zone.
For more info of the content in the response see:
https://rachio.readme.io/docs/zonestart
:param zone_id: Zone's unique id
:type zone_id: str
:param duration: Duration in seconds (Range is 0 - 10800 (3 Hours) )
:type duration: int
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
assert 0 <= duration <= 10800, "duration must be in range 0-10800"
payload = {"id": zone_id, "duration": duration}
return self.put_request("zone/start", payload)
def start_multiple(self, zones):
"""Start multiple zones.
For more info of the content in the response see:
https://rachio.readme.io/docs/publiczonestart_multiple
:param zones: Zone's unique id, duration, and sort order
:type zones: Object[]
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"zones": zones}
return self.put_request("zone/start_multiple", payload)
def schedule(self):
"""Create an empty zone schedule."""
return ZoneSchedule(self)
def set_moisture_percent(self, zone_id: str, percent: Decimal):
"""Set zone moisture percent.
For more info of the content in the response see:
https://rachio.readme.io/docs/publiczonesetmoisturepercent
:param zone_id: Zone's unique id
:type zone_id: str
:param percent: Soil moisture percent (Range is 0 - 1 )
:type percent: Decimal
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
assert 0 <= percent <= 1, "percent must be in range 0.0-1.0"
payload = {"id": zone_id, "percent": percent}
return self.put_request("zone/setMoisturePercent", payload)
def set_moisture_level(self, zone_id: str, level: Decimal):
"""Set zone moisture level.
For more info of the content in the response see:
https://rachio.readme.io/docs/publiczonesetmoisturelevel
:param zone_id: Zone's unique id
:type zone_id: str
:param level: Soil moisture level in mm (Range is 0 - Maximum Moisture
in mm (depth of water + (10% depth of water))
:type level: Decimal
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
payload = {"id": zone_id, "level": level}
return self.put_request("zone/setMoistureLevel", payload)
def get(self, zone_id: str):
"""Retrieve the information for a zone entity.
For more info of the content in the response see:
https://rachio.readme.io/docs/publiczoneid
:param zone_id: Zone's unique id
:type zone_id: str
:return: The return value is a tuple of (response, content), the first
being and instance of the httplib2.Response class, the second
being a string that contains the response entity body (Python
object if it contains JSON).
:rtype: tuple
"""
path = f"zone/{zone_id}"
return self.get_request(path)
class ZoneSchedule:
"""Help with starting multiple zones."""
def __init__(self, zone_api: Zone):
"""Zoneschedule class initializer."""
self._api = zone_api
self._zones = []
def enqueue(self, zone_id: str, duration: int):
"""Add a zone and duration to the schedule.
:param zone_id: Zone's unique id
:type zone_id: str
:param duration: Duration in seconds (Range is 0 - 10800 (3 Hours) )
:type duration: int
"""
self._zones.append((zone_id, duration))
def start(self):
"""Start the schedule."""
zones = [
{"id": data[0], "duration": data[1], "sortOrder": count}
for (count, data) in enumerate(self._zones, 1)
]
self._api.start_multiple(zones)
def __enter__(self):
"""Allow a schedule to be created in a with block."""
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""Allow the schedule to be executed by leaving with block."""
self.start()
rfverbruggen-rachiopy-7f3c210/requirements.txt 0000664 0000000 0000000 00000000011 14545226752 0021643 0 ustar 00root root 0000000 0000000 requests
rfverbruggen-rachiopy-7f3c210/requirements_test.txt 0000664 0000000 0000000 00000000054 14545226752 0022711 0 ustar 00root root 0000000 0000000 flake8
pydocstyle
pylint
coverage
jsonschema rfverbruggen-rachiopy-7f3c210/setup.py 0000664 0000000 0000000 00000002646 14545226752 0020111 0 ustar 00root root 0000000 0000000 """Rachiopy setup script."""
from setuptools import find_packages, setup
from datetime import datetime
from pathlib import Path
NOW = datetime.now().strftime("%m%d%Y%H%M%S")
VERSION = "1.1.0"
GITHUB_USERNAME = "rfverbruggen"
GITHUB_REPOSITORY = "rachiopy"
GITHUB_PATH = f"{GITHUB_USERNAME}/{GITHUB_REPOSITORY}"
GITHUB_URL = f"https://github.com/{GITHUB_PATH}"
DOWNLOAD_URL = f"{GITHUB_URL}/archive/{VERSION}.tar.gz"
PROJECT_URLS = {"Bug Reports": f"{GITHUB_URL}/issues"}
PACKAGES = find_packages(exclude=["tests", "tests.*"])
# read the contents of your README file
this_directory = Path(__file__).parent
long_description = (this_directory / "README.md").read_text()
setup(
name="RachioPy",
version=VERSION,
author="Robbert Verbruggen",
author_email="rfverbruggen@icloud.com",
packages=PACKAGES,
install_requires=["requests"],
url=GITHUB_URL,
download_url=DOWNLOAD_URL,
project_urls=PROJECT_URLS,
license="MIT",
description="A Python module for the Rachio API.",
long_description=long_description,
long_description_content_type='text/markdown',
platforms="Cross Platform",
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Topic :: Software Development",
],
)
rfverbruggen-rachiopy-7f3c210/tests/ 0000775 0000000 0000000 00000000000 14545226752 0017531 5 ustar 00root root 0000000 0000000 rfverbruggen-rachiopy-7f3c210/tests/__init__.py 0000664 0000000 0000000 00000000034 14545226752 0021637 0 ustar 00root root 0000000 0000000 """Rachiopy test module."""
rfverbruggen-rachiopy-7f3c210/tests/constants.py 0000664 0000000 0000000 00000000754 14545226752 0022125 0 ustar 00root root 0000000 0000000 """Constants for test execution."""
from unittest.mock import Mock
from requests import Response
BASE_API_URL = "https://api.rach.io/1/public"
VALVE_API_URL = "https://cloud-rest.rach.io"
AUTHTOKEN = "1c1d9f3d-39c9-42b1-abc0-066f5a05cdef"
RESPONSE200 = Mock(spec=Response)
RESPONSE200.status_code = 200
RESPONSE200.headers = {"content-type": "application/json"}
RESPONSE200.json.return_value = {}
RESPONSE204 = Mock(spec=Response)
RESPONSE204.headers = {}
RESPONSE204.status_code = 204
rfverbruggen-rachiopy-7f3c210/tests/test_device.py 0000664 0000000 0000000 00000017456 14545226752 0022416 0 ustar 00root root 0000000 0000000 """Device object test module"""
import unittest
import uuid
import json
from unittest.mock import patch
from random import randrange
from rachiopy import Device
from tests.constants import BASE_API_URL, AUTHTOKEN, RESPONSE200, RESPONSE204
class TestDeviceMethods(unittest.TestCase):
"""Class containing the Device object test cases."""
def setUp(self):
self.device = Device(AUTHTOKEN)
def test_init(self):
"""Test if the constructor works as expected."""
self.assertEqual(self.device.authtoken, AUTHTOKEN)
@patch("requests.Session.request")
def test_get(self, mock):
"""Test if the get method works as expected."""
mock.return_value = RESPONSE200
deviceid = str(uuid.uuid4())
self.device.get(deviceid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/{deviceid}",
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_current_schedule(self, mock):
"""Test if the current schedule method works as expected."""
mock.return_value = RESPONSE200
deviceid = str(uuid.uuid4())
self.device.current_schedule(deviceid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/{deviceid}/current_schedule",
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_event(self, mock):
"""Test if the event method works as expected."""
mock.return_value = RESPONSE200
deviceid = str(uuid.uuid4())
starttime = 1414818000000
endtime = 1415739608103
self.device.event(deviceid, starttime, endtime)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1],
f"{BASE_API_URL}/device/"
f"{deviceid}/event?startTime="
f"{starttime}&endTime="
f"{endtime}",
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_forecast(self, mock):
"""Test if the forecast method works as expected."""
mock.return_value = RESPONSE200
deviceid = str(uuid.uuid4())
self.device.forecast(deviceid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/{deviceid}/forecast?units=US",
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
self.device.forecast(deviceid, "US")
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/{deviceid}/forecast?units=US",
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
self.device.forecast(deviceid, "METRIC")
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1],
f"{BASE_API_URL}/device/{deviceid}/forecast?units=METRIC",
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
# Check that values should be within range.
self.assertRaises(AssertionError, self.device.forecast, deviceid, "")
@patch("requests.Session.request")
def test_stop_water(self, mock):
"""Test if the stop water method works as expected."""
mock.return_value = RESPONSE204
deviceid = str(uuid.uuid4())
self.device.stop_water(deviceid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/stop_water",
)
self.assertEqual(args[0], "PUT")
self.assertEqual(kwargs["data"], json.dumps({"id": deviceid}))
@patch("requests.Session.request")
def test_rain_delay(self, mock):
"""Test if the rain delay method works as expected."""
mock.return_value = RESPONSE204
deviceid = str(uuid.uuid4())
duration = randrange(604800)
self.device.rain_delay(deviceid, duration)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/rain_delay",
)
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"], json.dumps({"id": deviceid, "duration": duration})
)
# Check that values should be within range.
self.assertRaises(AssertionError, self.device.rain_delay, deviceid, -1)
self.assertRaises(
AssertionError, self.device.rain_delay, deviceid, 604801
)
@patch("requests.Session.request")
def test_turn_on(self, mock):
"""Test if the turn on method works as expected."""
mock.return_value = RESPONSE204
deviceid = str(uuid.uuid4())
self.device.turn_on(deviceid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/on",
)
self.assertEqual(args[0], "PUT")
self.assertEqual(kwargs["data"], json.dumps({"id": deviceid}))
@patch("requests.Session.request")
def test_turn_off(self, mock):
"""Test if the turn off method works as expected."""
mock.return_value = RESPONSE204
deviceid = str(uuid.uuid4())
self.device.turn_off(deviceid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/off",
)
self.assertEqual(args[0], "PUT")
self.assertEqual(kwargs["data"], json.dumps({"id": deviceid}))
@patch("requests.Session.request")
def test_pause_zone_run(self, mock):
"""Test if the pause zone run method works as expected."""
mock.return_value = RESPONSE204
deviceid = str(uuid.uuid4())
duration = randrange(3600)
self.device.pause_zone_run(deviceid, duration)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/pause_zone_run",
)
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"], json.dumps({"id": deviceid, "duration": duration})
)
# Check that values should be within range.
self.assertRaises(
AssertionError, self.device.pause_zone_run, deviceid, -1
)
self.assertRaises(
AssertionError, self.device.pause_zone_run, deviceid, 3601
)
@patch("requests.Session.request")
def test_resume_zone_run(self, mock):
"""Test if the resume zone run method works as expected."""
mock.return_value = RESPONSE204
deviceid = str(uuid.uuid4())
self.device.resume_zone_run(deviceid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/device/resume_zone_run",
)
self.assertEqual(args[0], "PUT")
self.assertEqual(kwargs["data"], json.dumps({"id": deviceid}))
rfverbruggen-rachiopy-7f3c210/tests/test_flexschedulerule.py 0000664 0000000 0000000 00000002201 14545226752 0024500 0 ustar 00root root 0000000 0000000 """FlexScheduleRule object test module"""
import unittest
from unittest.mock import patch
import uuid
from rachiopy import FlexSchedulerule
from tests.constants import BASE_API_URL, AUTHTOKEN, RESPONSE200
class TestFlexScheduleRuleMethods(unittest.TestCase):
"""Class containing the FlexScheduleRule object test cases."""
def setUp(self):
self.flexschedulerule = FlexSchedulerule(AUTHTOKEN)
def test_init(self):
"""Test if the constructor works as expected."""
self.assertEqual(self.flexschedulerule.authtoken, AUTHTOKEN)
@patch("requests.Session.request")
def test_get(self, mock):
"""Test if the get method works as expected."""
mock.return_value = RESPONSE200
flexscheduleruleid = uuid.uuid4()
self.flexschedulerule.get(flexscheduleruleid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1],
f"{BASE_API_URL}/flexschedulerule/{flexscheduleruleid}",
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
rfverbruggen-rachiopy-7f3c210/tests/test_notification.py 0000664 0000000 0000000 00000011161 14545226752 0023630 0 ustar 00root root 0000000 0000000 """Notification object test module"""
import unittest
from unittest.mock import patch
import uuid
import json
from rachiopy import Notification
from tests.constants import BASE_API_URL, AUTHTOKEN, RESPONSE200, RESPONSE204
class TestNotificationMethods(unittest.TestCase):
"""Class containing the Notification object test cases."""
def setUp(self):
self.notification = Notification(AUTHTOKEN)
def test_init(self):
"""Test if the constructor works as expected."""
self.assertEqual(self.notification.authtoken, AUTHTOKEN)
@patch("requests.Session.request")
def test_get_webhook_eventtype(self, mock):
"""Test if the get webhook eventtype method works as expected."""
mock.return_value = RESPONSE200
self.notification.get_webhook_event_type()
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/notification/webhook_event_type"
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_get_device_webhook(self, mock):
"""Test if the get device webhook method works as expected."""
mock.return_value = RESPONSE200
deviceid = str(uuid.uuid4())
self.notification.get_device_webhook(deviceid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/notification/{deviceid}/webhook"
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_add(self, mock):
"""Test if the add method works as expected."""
mock.return_value = RESPONSE200
deviceid = str(uuid.uuid4())
externalid = "Test ID"
url = "https://www.mydomain.com/another_webhook_new_url"
eventtypes = [{"id": "1"}, {"id": "2"}]
self.notification.add(deviceid, externalid, url, eventtypes)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/notification/webhook")
self.assertEqual(args[0], "POST")
self.assertEqual(
kwargs["data"],
json.dumps(
{
"device": {"id": deviceid},
"externalId": externalid,
"url": url,
"eventTypes": eventtypes,
}
),
)
@patch("requests.Session.request")
def test_update(self, mock):
"""Test if the update method works as expected."""
mock.return_value = RESPONSE200
hookid = str(uuid.uuid4())
externalid = "Test ID"
url = "https://www.mydomain.com/another_webhook_new_url"
eventtypes = [{"id": "1"}, {"id": "2"}]
self.notification.update(hookid, externalid, url, eventtypes)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/notification/webhook")
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"],
json.dumps(
{
"id": hookid,
"externalId": externalid,
"url": url,
"eventTypes": eventtypes,
}
),
)
@patch("requests.Session.request")
def test_delete(self, mock):
"""Test if the delete method works as expected."""
mock.return_value = RESPONSE204
hookid = str(uuid.uuid4())
self.notification.delete(hookid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/notification/webhook/{hookid}"
)
self.assertEqual(args[0], "DELETE")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_get(self, mock):
"""Test if the get method works as expected."""
mock.return_value = RESPONSE200
hookid = str(uuid.uuid4())
self.notification.get(hookid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/notification/webhook/{hookid}"
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
rfverbruggen-rachiopy-7f3c210/tests/test_person.py 0000664 0000000 0000000 00000002663 14545226752 0022457 0 ustar 00root root 0000000 0000000 """Person object test module"""
import unittest
from unittest.mock import patch
import uuid
from rachiopy import Person
from tests.constants import BASE_API_URL, AUTHTOKEN, RESPONSE200
class TestPersonMethods(unittest.TestCase):
"""Class containing the Rachio object test cases."""
def setUp(self):
self.person = Person(AUTHTOKEN)
def test_init(self):
"""Test if the constructor works as expected."""
self.assertEqual(self.person.authtoken, AUTHTOKEN)
@patch("requests.Session.request")
def test_info(self, mock):
"""Test if the info method works as expected."""
mock.return_value = RESPONSE200
self.person.info()
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/person/info")
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_get(self, mock):
"""Test if the get method works as expected."""
mock.return_value = RESPONSE200
personid = uuid.uuid4()
self.person.get(personid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/person/{personid}")
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
rfverbruggen-rachiopy-7f3c210/tests/test_program.py 0000664 0000000 0000000 00000006067 14545226752 0022622 0 ustar 00root root 0000000 0000000 """Program object test module"""
import unittest
import uuid
import json
from unittest.mock import patch
from rachiopy import Program
from tests.constants import VALVE_API_URL, AUTHTOKEN, RESPONSE200
class TestProgramMethods(unittest.TestCase):
"""Class containing the Program object tests."""
def setUp(self):
self.program = Program(AUTHTOKEN)
def test_init(self):
"""Test if the constructor works as expected."""
self.assertEqual(self.program.authtoken, AUTHTOKEN)
@patch("requests.Session.request")
def test_list_programs(self, mock):
"""Test if the list programs method works as expected."""
mock.return_value = RESPONSE200
valveid = str(uuid.uuid4())
self.program.list_programs(valveid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{VALVE_API_URL}/program/listPrograms/{valveid}"
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_get_program(self, mock):
"""Test if the get program method works as expected."""
mock.return_value = RESPONSE200
programid = str(uuid.uuid4())
self.program.get_program(programid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{VALVE_API_URL}/program/getProgram/{programid}"
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_create_skip_overrides(self, mock):
"""Test if the create skip overrides method works as expected."""
mock.return_value = RESPONSE200
programid = str(uuid.uuid4())
timestamp = 1414818000000
self.program.create_skip_overrides(programid, timestamp)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{VALVE_API_URL}/program/createSkipOverrides"
)
self.assertEqual(args[0], "POST")
self.assertEqual(
kwargs["data"],
json.dumps({"programId": programid, "timestamp": timestamp}),
)
@patch("requests.Session.request")
def test_delete_skip_overrides(self, mock):
"""Test if the delete skip overrides method works as expected."""
mock.return_value = RESPONSE200
programid = str(uuid.uuid4())
timestamp = 1414818000000
self.program.delete_skip_overrides(programid, timestamp)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{VALVE_API_URL}/program/deleteSkipOverrides"
)
self.assertEqual(args[0], "POST")
self.assertEqual(
kwargs["data"],
json.dumps({"programId": programid, "timestamp": timestamp}),
)
rfverbruggen-rachiopy-7f3c210/tests/test_rachio.py 0000664 0000000 0000000 00000001701 14545226752 0022406 0 ustar 00root root 0000000 0000000 """Rachio object test module"""
import unittest
from rachiopy import Rachio
from tests.constants import AUTHTOKEN
class TestRachioMethods(unittest.TestCase):
"""Class containing the Rachio object test cases."""
def test_init(self):
"""Test if the constructor works as expected."""
rachio = Rachio(AUTHTOKEN)
self.assertEqual(rachio.authtoken, AUTHTOKEN)
self.assertEqual(rachio.person.authtoken, AUTHTOKEN)
self.assertEqual(rachio.device.authtoken, AUTHTOKEN)
self.assertEqual(rachio.zone.authtoken, AUTHTOKEN)
self.assertEqual(rachio.schedulerule.authtoken, AUTHTOKEN)
self.assertEqual(rachio.flexschedulerule.authtoken, AUTHTOKEN)
self.assertEqual(rachio.notification.authtoken, AUTHTOKEN)
self.assertEqual(rachio.valve.authtoken, AUTHTOKEN)
self.assertEqual(rachio.summary.authtoken, AUTHTOKEN)
self.assertEqual(rachio.program.authtoken, AUTHTOKEN)
rfverbruggen-rachiopy-7f3c210/tests/test_schedulerule.py 0000664 0000000 0000000 00000005652 14545226752 0023636 0 ustar 00root root 0000000 0000000 """ScheduleRule object test module"""
import unittest
from unittest.mock import patch
import uuid
import json
from rachiopy import Schedulerule
from tests.constants import BASE_API_URL, AUTHTOKEN, RESPONSE200, RESPONSE204
class TestScheduleRuleMethods(unittest.TestCase):
"""Class containing the ScheduleRule object test cases."""
def setUp(self):
self.schedulerule = Schedulerule(AUTHTOKEN)
def test_init(self):
"""Test if the constructor works as expected."""
self.assertEqual(self.schedulerule.authtoken, AUTHTOKEN)
@patch("requests.Session.request")
def test_get(self, mock):
"""Test if the get method works as expected."""
mock.return_value = RESPONSE200
scheduleruleid = str(uuid.uuid4())
self.schedulerule.get(scheduleruleid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/schedulerule/{scheduleruleid}"
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_skip(self, mock):
"""Test if the skip method works as expected."""
mock.return_value = RESPONSE204
scheduleruleid = str(uuid.uuid4())
self.schedulerule.skip(scheduleruleid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/schedulerule/skip")
self.assertEqual(args[0], "PUT")
self.assertEqual(kwargs["data"], json.dumps({"id": scheduleruleid}))
@patch("requests.Session.request")
def test_start(self, mock):
"""Test if the start method works as expected."""
mock.return_value = RESPONSE204
scheduleruleid = str(uuid.uuid4())
self.schedulerule.start(scheduleruleid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/schedulerule/start")
self.assertEqual(args[0], "PUT")
self.assertEqual(kwargs["data"], json.dumps({"id": scheduleruleid}))
@patch("requests.Session.request")
def test_seasonal_adjustment(self, mock):
"""Test if the seasonal adjustment method works as expected."""
mock.return_value = RESPONSE200
scheduleruleid = str(uuid.uuid4())
adjustment = 0.2
self.schedulerule.seasonal_adjustment(scheduleruleid, adjustment)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{BASE_API_URL}/schedulerule/seasonal_adjustment"
)
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"],
json.dumps({"id": scheduleruleid, "adjustment": adjustment}),
)
rfverbruggen-rachiopy-7f3c210/tests/test_summary.py 0000664 0000000 0000000 00000002614 14545226752 0022642 0 ustar 00root root 0000000 0000000 """Summary object test module"""
import unittest
import uuid
import json
from unittest.mock import patch
from rachiopy import SummaryServce
from tests.constants import VALVE_API_URL, AUTHTOKEN, RESPONSE200
class TestSummaryMethod(unittest.TestCase):
"""Class containing the Summary object test."""
def setUp(self):
self.summary = SummaryServce(AUTHTOKEN)
def test_init(self):
"""Test if the constructor works as expected."""
self.assertEqual(self.summary.authtoken, AUTHTOKEN)
@patch("requests.Session.request")
def test_get_valve_day_views(self, mock):
"""Test if the get day views method works as expected."""
mock.return_value = RESPONSE200
deviceid = str(uuid.uuid4())
start = {"year": 2023, "month": 1, "day": 1}
end = {"year": 2023, "month": 1, "day": 30}
self.summary.get_valve_day_views(deviceid, start, end)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{VALVE_API_URL}/summary/getValveDayViews")
self.assertEqual(args[0], "POST")
self.assertEqual(
kwargs["data"],
json.dumps(
{
"resourceId": {"baseStationId": deviceid},
"start": start,
"end": end,
}
),
)
rfverbruggen-rachiopy-7f3c210/tests/test_valve.py 0000664 0000000 0000000 00000013511 14545226752 0022260 0 ustar 00root root 0000000 0000000 """Valve object test module"""
import unittest
from unittest.mock import patch
import uuid
import json
from random import randrange
from rachiopy import Valve
from tests.constants import VALVE_API_URL, AUTHTOKEN, RESPONSE200, RESPONSE204
class TestValveMethods(unittest.TestCase):
"""Class containing the Valve object test cases."""
def setUp(self):
self.valve = Valve(AUTHTOKEN)
def test_init(self):
"""Test if the constructor works as expected."""
self.assertEqual(self.valve.authtoken, AUTHTOKEN)
@patch("requests.Session.request")
def test_get_valve(self, mock):
"""Test if the get_valve method works as expected."""
mock.return_value = RESPONSE200
valveid = uuid.uuid4()
self.valve.get_valve(valveid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{VALVE_API_URL}/valve/getValve/{valveid}")
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_get_base_station(self, mock):
"""Test if the get_base_station method works as expected."""
mock.return_value = RESPONSE200
baseid = str(uuid.uuid4())
self.valve.get_base_station(baseid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{VALVE_API_URL}/valve/getBaseStation/{baseid}"
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_list_base_stations(self, mock):
"""Test if the list_base_stations method works as expected."""
mock.return_value = RESPONSE200
userid = str(uuid.uuid4())
self.valve.list_base_stations(userid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(
args[1], f"{VALVE_API_URL}/valve/listBaseStations/{userid}"
)
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_list_valves(self, mock):
"""Test if the list_valves method works as expected."""
mock.return_value = RESPONSE200
baseid = str(uuid.uuid4())
self.valve.list_valves(baseid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{VALVE_API_URL}/valve/listValves/{baseid}")
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_set_default_runtime(self, mock):
"""Test if the set_default_runtime method works as expected."""
mock.return_value = RESPONSE200
valveid = str(uuid.uuid4())
duration = randrange(86400)
self.valve.set_default_runtime(valveid, duration)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{VALVE_API_URL}/valve/setDefaultRuntime")
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"],
json.dumps(
{"valveId": valveid, "defaultRuntimeSeconds": duration}
),
)
@patch("requests.Session.request")
def test_set_default_runtime_exception(self, mock):
"""Test if the set_default_runtime method catches incorrect values."""
mock.return_value = RESPONSE200
valveid = str(uuid.uuid4())
duration1 = randrange(-50, -1)
duration2 = randrange(86401, 86500)
# Check that values should be within range.
self.assertRaises(
AssertionError, self.valve.start_watering, valveid, duration1
)
self.assertRaises(
AssertionError, self.valve.start_watering, valveid, duration2
)
@patch("requests.Session.request")
def test_start_watering(self, mock):
"""Test if the start_watering method works as expected."""
mock.return_value = RESPONSE204
valveid = str(uuid.uuid4())
duration = randrange(86400)
self.valve.start_watering(valveid, duration)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{VALVE_API_URL}/valve/startWatering")
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"],
json.dumps({"valveId": valveid, "durationSeconds": duration}),
)
@patch("requests.Session.request")
def test_start_watering_exception(self, mock):
"""Test if the start_watering method catches incorrect values."""
mock.return_value = RESPONSE204
valveid = str(uuid.uuid4())
duration1 = randrange(-50, -1)
duration2 = randrange(86401, 86500)
# Check that values should be within range.
self.assertRaises(
AssertionError, self.valve.start_watering, valveid, duration1
)
self.assertRaises(
AssertionError, self.valve.start_watering, valveid, duration2
)
@patch("requests.Session.request")
def test_stop_watering(self, mock):
"""Test if the stop_watering method works as expected."""
mock.return_value = RESPONSE204
valveid = str(uuid.uuid4())
self.valve.stop_watering(valveid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{VALVE_API_URL}/valve/stopWatering")
self.assertEqual(args[0], "PUT")
self.assertEqual(kwargs["data"], json.dumps({"valveId": valveid}))
rfverbruggen-rachiopy-7f3c210/tests/test_zone.py 0000664 0000000 0000000 00000015557 14545226752 0022132 0 ustar 00root root 0000000 0000000 """Zone object test module"""
import unittest
from unittest.mock import patch
import uuid
import random
import json
from random import randrange
from rachiopy import Zone
from rachiopy.zone import ZoneSchedule
from tests.constants import BASE_API_URL, AUTHTOKEN, RESPONSE200, RESPONSE204
class TestZoneMethods(unittest.TestCase):
"""Class containing the Zone object test cases."""
def setUp(self):
self.zone = Zone(AUTHTOKEN)
zone1id = str(uuid.uuid4())
zone2id = str(uuid.uuid4())
zone3id = str(uuid.uuid4())
duration1 = randrange(10800)
duration2 = randrange(10800)
duration3 = randrange(10800)
self.zones = []
self.zones.append((zone1id, duration1))
self.zones.append((zone2id, duration2))
self.zones.append((zone3id, duration3))
def test_init(self):
"""Test if the constructor works as expected."""
self.assertEqual(self.zone.authtoken, AUTHTOKEN)
@patch("requests.Session.request")
def test_get(self, mock):
"""Test if the get method works as expected."""
mock.return_value = RESPONSE200
zoneid = uuid.uuid4()
self.zone.get(zoneid)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/zone/{zoneid}")
self.assertEqual(args[0], "GET")
self.assertEqual(kwargs["data"], None)
@patch("requests.Session.request")
def test_start(self, mock):
"""Test if the start method works as expected."""
mock.return_value = RESPONSE204
zoneid = str(uuid.uuid4())
duration = randrange(10800)
self.zone.start(zoneid, duration)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/zone/start")
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"], json.dumps({"id": zoneid, "duration": duration})
)
# Check that values should be within range.
self.assertRaises(AssertionError, self.zone.start, zoneid, -1)
self.assertRaises(AssertionError, self.zone.start, zoneid, 10801)
@patch("requests.Session.request")
def test_start_multiple(self, mock):
"""Test if the start multiple method works as expected."""
mock.return_value = RESPONSE204
zones = [
{"id": data[0], "duration": data[1], "sortOrder": count}
for (count, data) in enumerate(self.zones, 1)
]
self.zone.start_multiple(zones)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/zone/start_multiple")
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"],
json.dumps(
{
"zones": [
{
"id": data[0],
"duration": data[1],
"sortOrder": count,
}
for (count, data) in enumerate(self.zones, 1)
]
}
),
)
@patch("requests.Session.request")
def test_set_moisture_percent(self, mock):
"""Test if the set moisture percent method works as expected."""
mock.return_value = RESPONSE204
zoneid = str(uuid.uuid4())
percent = round(random.random(), 1)
self.zone.set_moisture_percent(zoneid, percent)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/zone/setMoisturePercent")
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"], json.dumps({"id": zoneid, "percent": percent})
)
# Check that values should be within range.
self.assertRaises(
AssertionError, self.zone.set_moisture_percent, zoneid, -0.1
)
self.assertRaises(
AssertionError, self.zone.set_moisture_percent, zoneid, 1.1
)
@patch("requests.Session.request")
def test_set_moisture_level(self, mock):
"""Test if the set moisture level method works as expected."""
mock.return_value = RESPONSE204
zoneid = str(uuid.uuid4())
level = round(random.uniform(0.0, 100.0), 2)
self.zone.set_moisture_level(zoneid, level)
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/zone/setMoistureLevel")
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"], json.dumps({"id": zoneid, "level": level})
)
@patch("requests.Session.request")
def test_zoneschedule(self, mock):
"""Test if the zoneschedule helper class works as expected."""
mock.return_value = RESPONSE204
zoneschedule = self.zone.schedule()
for zone in self.zones:
zoneschedule.enqueue(zone[0], zone[1])
zoneschedule.start()
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/zone/start_multiple")
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"],
json.dumps(
{
"zones": [
{
"id": data[0],
"duration": data[1],
"sortOrder": count,
}
for (count, data) in enumerate(self.zones, 1)
]
}
),
)
@patch("requests.Session.request")
def test_zoneschedule_with_statement(self, mock):
"""Test if the zoneschedule with statement works as expected."""
mock.return_value = RESPONSE204
with ZoneSchedule(self.zone) as zoneschedule:
for zone in self.zones:
zoneschedule.enqueue(zone[0], zone[1])
args, kwargs = mock.call_args
# Check that the mock function is called with the rights args.
self.assertEqual(args[1], f"{BASE_API_URL}/zone/start_multiple")
self.assertEqual(args[0], "PUT")
self.assertEqual(
kwargs["data"],
json.dumps(
{
"zones": [
{
"id": data[0],
"duration": data[1],
"sortOrder": count,
}
for (count, data) in enumerate(self.zones, 1)
]
}
),
)
rfverbruggen-rachiopy-7f3c210/tox.ini 0000664 0000000 0000000 00000001564 14545226752 0017710 0 ustar 00root root 0000000 0000000 [tox]
envlist = clean, py{38,39,310,311,312}, pylint, flake8, pydocstyle, stats
ignore_basepython_conflict = true
[testenv:clean]
commands=
coverage erase
[testenv]
basepython = {env:PYTHON3_PATH:python3}
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements_test.txt
commands =
{envbindir}/python -m unittest discover -v []
coverage run -a setup.py test
[testenv:pylint]
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements_test.txt
commands =
pylint {posargs} rachiopy tests
[testenv:flake8]
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements_test.txt
commands =
flake8 {posargs}
[testenv:pydocstyle]
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements_test.txt
commands =
pydocstyle {posargs:rachiopy tests}
[testenv:stats]
commands=
coverage report
coverage html