core/homeassistant/components/raincloud/__init__.py

175 lines
4.8 KiB
Python

"""Support for Melnor RainCloud sprinkler water timer."""
from datetime import timedelta
import logging
from requests.exceptions import ConnectTimeout, HTTPError
import voluptuous as vol
from homeassistant.const import (
ATTR_ATTRIBUTION,
CONF_PASSWORD,
CONF_SCAN_INTERVAL,
CONF_USERNAME,
)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import track_time_interval
_LOGGER = logging.getLogger(__name__)
ALLOWED_WATERING_TIME = [5, 10, 15, 30, 45, 60]
ATTRIBUTION = "Data provided by Melnor Aquatimer.com"
CONF_WATERING_TIME = "watering_minutes"
NOTIFICATION_ID = "raincloud_notification"
NOTIFICATION_TITLE = "Rain Cloud Setup"
DATA_RAINCLOUD = "raincloud"
DOMAIN = "raincloud"
DEFAULT_WATERING_TIME = 15
KEY_MAP = {
"auto_watering": "Automatic Watering",
"battery": "Battery",
"is_watering": "Watering",
"manual_watering": "Manual Watering",
"next_cycle": "Next Cycle",
"rain_delay": "Rain Delay",
"status": "Status",
"watering_time": "Remaining Watering Time",
}
ICON_MAP = {
"auto_watering": "mdi:autorenew",
"battery": "",
"is_watering": "",
"manual_watering": "mdi:water-pump",
"next_cycle": "mdi:calendar-clock",
"rain_delay": "mdi:weather-rainy",
"status": "",
"watering_time": "mdi:water-pump",
}
UNIT_OF_MEASUREMENT_MAP = {
"auto_watering": "",
"battery": "%",
"is_watering": "",
"manual_watering": "",
"next_cycle": "",
"rain_delay": "days",
"status": "",
"watering_time": "min",
}
BINARY_SENSORS = ["is_watering", "status"]
SENSORS = ["battery", "next_cycle", "rain_delay", "watering_time"]
SWITCHES = ["auto_watering", "manual_watering"]
SCAN_INTERVAL = timedelta(seconds=20)
SIGNAL_UPDATE_RAINCLOUD = "raincloud_update"
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period,
}
)
},
extra=vol.ALLOW_EXTRA,
)
def setup(hass, config):
"""Set up the Melnor RainCloud component."""
conf = config[DOMAIN]
username = conf.get(CONF_USERNAME)
password = conf.get(CONF_PASSWORD)
scan_interval = conf.get(CONF_SCAN_INTERVAL)
try:
from raincloudy.core import RainCloudy
raincloud = RainCloudy(username=username, password=password)
if not raincloud.is_connected:
raise HTTPError
hass.data[DATA_RAINCLOUD] = RainCloudHub(raincloud)
except (ConnectTimeout, HTTPError) as ex:
_LOGGER.error("Unable to connect to Rain Cloud service: %s", str(ex))
hass.components.persistent_notification.create(
"Error: {}<br />"
"You will need to restart hass after fixing."
"".format(ex),
title=NOTIFICATION_TITLE,
notification_id=NOTIFICATION_ID,
)
return False
def hub_refresh(event_time):
"""Call Raincloud hub to refresh information."""
_LOGGER.debug("Updating RainCloud Hub component")
hass.data[DATA_RAINCLOUD].data.update()
dispatcher_send(hass, SIGNAL_UPDATE_RAINCLOUD)
# Call the Raincloud API to refresh updates
track_time_interval(hass, hub_refresh, scan_interval)
return True
class RainCloudHub:
"""Representation of a base RainCloud device."""
def __init__(self, data):
"""Initialize the entity."""
self.data = data
class RainCloudEntity(Entity):
"""Entity class for RainCloud devices."""
def __init__(self, data, sensor_type):
"""Initialize the RainCloud entity."""
self.data = data
self._sensor_type = sensor_type
self._name = "{0} {1}".format(self.data.name, KEY_MAP.get(self._sensor_type))
self._state = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
async def async_added_to_hass(self):
"""Register callbacks."""
async_dispatcher_connect(
self.hass, SIGNAL_UPDATE_RAINCLOUD, self._update_callback
)
def _update_callback(self):
"""Call update method."""
self.schedule_update_ha_state(True)
@property
def unit_of_measurement(self):
"""Return the units of measurement."""
return UNIT_OF_MEASUREMENT_MAP.get(self._sensor_type)
@property
def device_state_attributes(self):
"""Return the state attributes."""
return {ATTR_ATTRIBUTION: ATTRIBUTION, "identifier": self.data.serial}
@property
def icon(self):
"""Return the icon to use in the frontend, if any."""
return ICON_MAP.get(self._sensor_type)