Source code for raincloudy.controller
# -*- coding: utf-8 -*-
"""RainCloud Controller."""
import raincloudy
from raincloudy.faucet import RainCloudyFaucet
from raincloudy.const import (
STATUS_ENDPOINT, HEADERS, HOME_ENDPOINT, SETUP_ENDPOINT)
from raincloudy.helpers import (
generate_soup_html, find_controller_or_faucet_name)
[docs]class RainCloudyController():
"""RainCloudy Controller object."""
def __init__(self, parent, controller_id, faucets=None):
"""
Initialize RainCloudy Controller object.
:param parent: RainCloudy parent object
:param controller_id: Control Unit ID
:param valve_id: Value Unit ID assigned controller
:type parent: RainCloudy object
:type controller_id: string
:type valve_id: string
:return: RainCloudyController object
:rtype: RainCloudyController object
"""
self.attributes = None
self._parent = parent
self._controller_id = controller_id
self._verify_parent()
# faucets associated with controller
self.faucets = []
# load assigned faucets
self._assign_faucets(faucets)
# populate controller attributes
self.update()
def _verify_parent(self):
"""Verify parent type."""
if not isinstance(self._parent, raincloudy.core.RainCloudy):
raise TypeError("Invalid parent object.")
def _assign_faucets(self, faucets):
"""Assign RainCloudyFaucet objects to self.faucets."""
if not faucets:
raise TypeError("Controller does not have a faucet assigned.")
for faucet_id in faucets:
self.faucets.append(
RainCloudyFaucet(self._parent, self, faucet_id))
def __repr__(self):
"""Object representation."""
try:
return "<{0}: {1}>".format(self.__class__.__name__, self.name)
except AttributeError:
return "<{0}: {1}>".format(self.__class__.__name__, self.id)
[docs] def post(self, ddata, url=SETUP_ENDPOINT, referer=SETUP_ENDPOINT):
"""Method to update some attributes on namespace."""
headers = HEADERS.copy()
if referer is None:
headers.pop('Referer')
else:
headers['Referer'] = referer
# append csrftoken
if 'csrfmiddlewaretoken' not in ddata.keys():
ddata['csrfmiddlewaretoken'] = self._parent.csrftoken
req = self._parent.client.post(url, headers=headers, data=ddata)
if req.status_code == 200:
self.update()
def _get_cu_and_fu_status(self):
"""Submit GET request to update information."""
# adjust headers
headers = HEADERS.copy()
headers['Accept'] = '*/*'
headers['X-Requested-With'] = 'XMLHttpRequest'
headers['X-CSRFToken'] = self._parent.csrftoken
args = '?controller_serial=' + self.serial \
+ '&faucet_serial=' + self.faucet.serial
req = self._parent.client.get(STATUS_ENDPOINT + args,
headers=headers)
# token probably expired, then try again
if req.status_code == 403:
self._parent.login()
self.update()
elif req.status_code == 200:
self.attributes = req.json()
else:
req.raise_for_status()
def _refresh_html_home(self):
"""
Function to refresh the self._parent.html['home'] object
which provides the status if zones are scheduled to
start automatically (program_toggle).
"""
req = self._parent.client.get(HOME_ENDPOINT)
if req.status_code == 403:
self._parent.login()
self.update()
elif req.status_code == 200:
self._parent.html['home'] = generate_soup_html(req.text)
else:
req.raise_for_status()
[docs] def update(self):
"""
Call 2 methods to update zone attributes and html['home'] object
"""
# update zone attributes
self._get_cu_and_fu_status()
# update self._parent.html['home'] for gathering
# auto_watering status (program_toggle tag)
self._refresh_html_home()
@property
def serial(self):
"""Return controller id."""
return self._controller_id
# pylint: disable=invalid-name
@property
def id(self):
"""Return controller id."""
return self.serial
@property
def name(self):
"""Return controller name."""
return \
find_controller_or_faucet_name(self._parent.html['home'],
'controller')
@name.setter
def name(self, value):
"""Set a new name to controller."""
data = {
'_set_controller_name': 'Set Name',
'controller_name': value,
}
self.post(data, url=SETUP_ENDPOINT, referer=SETUP_ENDPOINT)
@property
def status(self):
"""Return controller status."""
return self.attributes['controller_status']
@property
def current_time(self):
"""Return controller current time."""
return self.attributes['current_time']
@property
def faucet(self):
"""Show current linked faucet."""
if hasattr(self, 'faucets'):
if len(self.faucets) > 1:
# in the future, we should support more faucets
raise TypeError("Only one faucet per account.")
return self.faucets[0]
raise AttributeError("There is no faucet assigned.")
# vim:sw=4:ts=4:et: