Skip to content

Commit

Permalink
Merge pull request #55 from brg468/valve-support
Browse files Browse the repository at this point in the history
Smart Hose Timer Support
  • Loading branch information
rfverbruggen authored Jan 2, 2024
2 parents 0adc64d + 04562d3 commit a4682aa
Show file tree
Hide file tree
Showing 10 changed files with 672 additions and 1 deletion.
7 changes: 7 additions & 0 deletions rachiopy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
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.
Expand All @@ -25,3 +29,6 @@ def __init__(self, authtoken: str):
self.notification = Notification(authtoken)
self.schedulerule = Schedulerule(authtoken)
self.zone = Zone(authtoken)
self.valve = Valve(authtoken)
self.summary = SummaryServce(authtoken)
self.program = Program(authtoken)
86 changes: 86 additions & 0 deletions rachiopy/program.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""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)
74 changes: 73 additions & 1 deletion rachiopy/rachioobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from requests import Session

_API_URL = "https://api.rach.io/1/public"
_VALVE_URL = "https://cloud-rest.rach.io"


class RachioObject:
Expand Down Expand Up @@ -32,7 +33,7 @@ def __init__(self, authtoken: str, http_session=None, timeout=25):
self.timeout = timeout

def _request(self, path: str, method: str, body=None):
"""Make a request from the API.
"""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
Expand Down Expand Up @@ -100,3 +101,74 @@ def delete_request(self, path: str, body=None):
: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)
34 changes: 34 additions & 0 deletions rachiopy/summary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""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)
140 changes: 140 additions & 0 deletions rachiopy/valve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
"""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)
1 change: 1 addition & 0 deletions tests/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
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"

Expand Down
Loading

0 comments on commit a4682aa

Please sign in to comment.