Converts RainMachine to hub model (part 2) (#14225)

* Converts RainMachine to hub model (part 2)

* Small style adjustments for consistency

* Moving MAC calculation to one-time call in component

* Removing unneeded attribute

* Bumping Travis

* Lint
This commit is contained in:
Aaron Bach 2018-05-01 13:36:43 -06:00 committed by Paulus Schoutsen
parent 8d5c3a2b91
commit 7a05471912
2 changed files with 41 additions and 32 deletions

View file

@ -8,11 +8,10 @@ import logging
from datetime import timedelta from datetime import timedelta
import voluptuous as vol import voluptuous as vol
from requests.exceptions import ConnectTimeout
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv, discovery
from homeassistant.const import ( from homeassistant.const import (
CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, CONF_SSL) CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, CONF_SSL, CONF_SWITCHES)
REQUIREMENTS = ['regenmaschine==0.4.1'] REQUIREMENTS = ['regenmaschine==0.4.1']
@ -24,6 +23,8 @@ DOMAIN = 'rainmachine'
NOTIFICATION_ID = 'rainmachine_notification' NOTIFICATION_ID = 'rainmachine_notification'
NOTIFICATION_TITLE = 'RainMachine Component Setup' NOTIFICATION_TITLE = 'RainMachine Component Setup'
CONF_ZONE_RUN_TIME = 'zone_run_time'
DEFAULT_ATTRIBUTION = 'Data provided by Green Electronics LLC' DEFAULT_ATTRIBUTION = 'Data provided by Green Electronics LLC'
DEFAULT_PORT = 8080 DEFAULT_PORT = 8080
DEFAULT_SSL = True DEFAULT_SSL = True
@ -31,6 +32,11 @@ DEFAULT_SSL = True
MIN_SCAN_TIME = timedelta(seconds=1) MIN_SCAN_TIME = timedelta(seconds=1)
MIN_SCAN_TIME_FORCED = timedelta(milliseconds=100) MIN_SCAN_TIME_FORCED = timedelta(milliseconds=100)
SWITCH_SCHEMA = vol.Schema({
vol.Optional(CONF_ZONE_RUN_TIME):
cv.positive_int
})
CONFIG_SCHEMA = vol.Schema( CONFIG_SCHEMA = vol.Schema(
{ {
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
@ -38,6 +44,7 @@ CONFIG_SCHEMA = vol.Schema(
vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean,
vol.Optional(CONF_SWITCHES): SWITCH_SCHEMA,
}) })
}, },
extra=vol.ALLOW_EXTRA) extra=vol.ALLOW_EXTRA)
@ -47,6 +54,7 @@ def setup(hass, config):
"""Set up the RainMachine component.""" """Set up the RainMachine component."""
from regenmaschine import Authenticator, Client from regenmaschine import Authenticator, Client
from regenmaschine.exceptions import HTTPError from regenmaschine.exceptions import HTTPError
from requests.exceptions import ConnectTimeout
conf = config[DOMAIN] conf = config[DOMAIN]
ip_address = conf[CONF_IP_ADDRESS] ip_address = conf[CONF_IP_ADDRESS]
@ -54,11 +62,14 @@ def setup(hass, config):
port = conf[CONF_PORT] port = conf[CONF_PORT]
ssl = conf[CONF_SSL] ssl = conf[CONF_SSL]
_LOGGER.debug('Setting up RainMachine client')
try: try:
auth = Authenticator.create_local( auth = Authenticator.create_local(
ip_address, password, port=port, https=ssl) ip_address, password, port=port, https=ssl)
client = Client(auth) client = Client(auth)
hass.data[DATA_RAINMACHINE] = client mac = client.provision.wifi()['macAddress']
hass.data[DATA_RAINMACHINE] = (client, mac)
except (HTTPError, ConnectTimeout, UnboundLocalError) as exc_info: except (HTTPError, ConnectTimeout, UnboundLocalError) as exc_info:
_LOGGER.error('An error occurred: %s', str(exc_info)) _LOGGER.error('An error occurred: %s', str(exc_info))
hass.components.persistent_notification.create( hass.components.persistent_notification.create(
@ -68,4 +79,11 @@ def setup(hass, config):
title=NOTIFICATION_TITLE, title=NOTIFICATION_TITLE,
notification_id=NOTIFICATION_ID) notification_id=NOTIFICATION_ID)
return False return False
_LOGGER.debug('Setting up switch platform')
switch_config = conf.get(CONF_SWITCHES, {})
discovery.load_platform(hass, 'switch', DOMAIN, switch_config, config)
_LOGGER.debug('Setup complete')
return True return True

View file

@ -2,40 +2,33 @@
from logging import getLogger from logging import getLogger
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.rainmachine import ( from homeassistant.components.rainmachine import (
DATA_RAINMACHINE, DEFAULT_ATTRIBUTION, MIN_SCAN_TIME, MIN_SCAN_TIME_FORCED) CONF_ZONE_RUN_TIME, DATA_RAINMACHINE, DEFAULT_ATTRIBUTION, MIN_SCAN_TIME,
from homeassistant.components.switch import PLATFORM_SCHEMA, SwitchDevice MIN_SCAN_TIME_FORCED)
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_DEVICE_CLASS from homeassistant.components.switch import SwitchDevice
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.util import Throttle from homeassistant.util import Throttle
_LOGGER = getLogger(__name__)
DEPENDENCIES = ['rainmachine'] DEPENDENCIES = ['rainmachine']
_LOGGER = getLogger(__name__)
ATTR_CYCLES = 'cycles' ATTR_CYCLES = 'cycles'
ATTR_TOTAL_DURATION = 'total_duration' ATTR_TOTAL_DURATION = 'total_duration'
CONF_ZONE_RUN_TIME = 'zone_run_time' DEFAULT_ZONE_RUN = 60 * 10
DEFAULT_ZONE_RUN_SECONDS = 60 * 10
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_ZONE_RUN_TIME, default=DEFAULT_ZONE_RUN_SECONDS):
cv.positive_int
})
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set this component up under its platform.""" """Set this component up under its platform."""
client = hass.data.get(DATA_RAINMACHINE) if discovery_info is None:
device_name = client.provision.device_name()['name'] return
device_mac = client.provision.wifi()['macAddress']
_LOGGER.debug('Config received: %s', config) _LOGGER.debug('Config received: %s', discovery_info)
zone_run_time = config[CONF_ZONE_RUN_TIME] zone_run_time = discovery_info.get(CONF_ZONE_RUN_TIME, DEFAULT_ZONE_RUN)
client, device_mac = hass.data.get(DATA_RAINMACHINE)
entities = [] entities = []
for program in client.programs.all().get('programs', {}): for program in client.programs.all().get('programs', {}):
@ -44,7 +37,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
_LOGGER.debug('Adding program: %s', program) _LOGGER.debug('Adding program: %s', program)
entities.append( entities.append(
RainMachineProgram(client, device_name, device_mac, program)) RainMachineProgram(client, device_mac, program))
for zone in client.zones.all().get('zones', {}): for zone in client.zones.all().get('zones', {}):
if not zone.get('active'): if not zone.get('active'):
@ -52,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
_LOGGER.debug('Adding zone: %s', zone) _LOGGER.debug('Adding zone: %s', zone)
entities.append( entities.append(
RainMachineZone(client, device_name, device_mac, zone, RainMachineZone(client, device_mac, zone,
zone_run_time)) zone_run_time))
add_devices(entities, True) add_devices(entities, True)
@ -61,18 +54,16 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class RainMachineEntity(SwitchDevice): class RainMachineEntity(SwitchDevice):
"""A class to represent a generic RainMachine entity.""" """A class to represent a generic RainMachine entity."""
def __init__(self, client, device_name, device_mac, entity_json): def __init__(self, client, device_mac, entity_json):
"""Initialize a generic RainMachine entity.""" """Initialize a generic RainMachine entity."""
self._api_type = 'remote' if client.auth.using_remote_api else 'local' self._api_type = 'remote' if client.auth.using_remote_api else 'local'
self._client = client self._client = client
self._entity_json = entity_json self._entity_json = entity_json
self.device_mac = device_mac self.device_mac = device_mac
self.device_name = device_name
self._attrs = { self._attrs = {
ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION, ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION
ATTR_DEVICE_CLASS: self.device_name
} }
@property @property
@ -156,10 +147,10 @@ class RainMachineProgram(RainMachineEntity):
class RainMachineZone(RainMachineEntity): class RainMachineZone(RainMachineEntity):
"""A RainMachine zone.""" """A RainMachine zone."""
def __init__(self, client, device_name, device_mac, zone_json, def __init__(self, client, device_mac, zone_json,
zone_run_time): zone_run_time):
"""Initialize a RainMachine zone.""" """Initialize a RainMachine zone."""
super().__init__(client, device_name, device_mac, zone_json) super().__init__(client, device_mac, zone_json)
self._run_time = zone_run_time self._run_time = zone_run_time
self._attrs.update({ self._attrs.update({
ATTR_CYCLES: self._entity_json.get('noOfCycles'), ATTR_CYCLES: self._entity_json.get('noOfCycles'),