diff --git a/.coveragerc b/.coveragerc index 8cc8077312a..71e0f0471f2 100644 --- a/.coveragerc +++ b/.coveragerc @@ -244,6 +244,9 @@ omit = homeassistant/components/notify/twilio_sms.py homeassistant/components/notify/twilio_call.py + homeassistant/components/upcloud.py + homeassistant/components/*/upcloud.py + homeassistant/components/usps.py homeassistant/components/*/usps.py diff --git a/homeassistant/components/binary_sensor/upcloud.py b/homeassistant/components/binary_sensor/upcloud.py new file mode 100644 index 00000000000..dd76231ad75 --- /dev/null +++ b/homeassistant/components/binary_sensor/upcloud.py @@ -0,0 +1,42 @@ +""" +Support for monitoring the state of UpCloud servers. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/binary_sensor.upcloud/ +""" +import logging + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.binary_sensor import ( + BinarySensorDevice, PLATFORM_SCHEMA) +from homeassistant.components.upcloud import ( + UpCloudServerEntity, CONF_SERVERS, DATA_UPCLOUD) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['upcloud'] + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_SERVERS): vol.All(cv.ensure_list, [cv.string]), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the UpCloud server binary sensor.""" + upcloud = hass.data[DATA_UPCLOUD] + + servers = config.get(CONF_SERVERS) + + devices = [UpCloudBinarySensor(upcloud, uuid) for uuid in servers] + + add_devices(devices, True) + + +class UpCloudBinarySensor(UpCloudServerEntity, BinarySensorDevice): + """Representation of an UpCloud server sensor.""" + + def __init__(self, upcloud, uuid): + """Initialize a new UpCloud sensor.""" + UpCloudServerEntity.__init__(self, upcloud, uuid) diff --git a/homeassistant/components/switch/upcloud.py b/homeassistant/components/switch/upcloud.py new file mode 100644 index 00000000000..32d47670429 --- /dev/null +++ b/homeassistant/components/switch/upcloud.py @@ -0,0 +1,52 @@ +""" +Support for interacting with UpCloud servers. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/switch.upcloud/ +""" +import logging + +import voluptuous as vol + +from homeassistant.const import STATE_OFF +import homeassistant.helpers.config_validation as cv +from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) +from homeassistant.components.upcloud import ( + UpCloudServerEntity, CONF_SERVERS, DATA_UPCLOUD) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['upcloud'] + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_SERVERS): vol.All(cv.ensure_list, [cv.string]), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the UpCloud server switch.""" + upcloud = hass.data[DATA_UPCLOUD] + + servers = config.get(CONF_SERVERS) + + devices = [UpCloudSwitch(upcloud, uuid) for uuid in servers] + + add_devices(devices, True) + + +class UpCloudSwitch(UpCloudServerEntity, SwitchDevice): + """Representation of an UpCloud server switch.""" + + def __init__(self, upcloud, uuid): + """Initialize a new UpCloud server switch.""" + UpCloudServerEntity.__init__(self, upcloud, uuid) + + def turn_on(self, **kwargs): + """Start the server.""" + if self.state == STATE_OFF: + self.data.start() + + def turn_off(self, **kwargs): + """Stop the server.""" + if self.is_on: + self.data.stop() diff --git a/homeassistant/components/upcloud.py b/homeassistant/components/upcloud.py new file mode 100644 index 00000000000..e653e55b93b --- /dev/null +++ b/homeassistant/components/upcloud.py @@ -0,0 +1,170 @@ +""" +Support for UpCloud. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/upcloud/ +""" +import asyncio +import logging +from datetime import timedelta + +import voluptuous as vol + +from homeassistant.const import ( + CONF_USERNAME, CONF_PASSWORD, CONF_SCAN_INTERVAL, + STATE_ON, STATE_OFF, STATE_PROBLEM, STATE_UNKNOWN) +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 + +REQUIREMENTS = ['upcloud-api==0.4.2'] + +_LOGGER = logging.getLogger(__name__) + +ATTR_CORE_NUMBER = 'core_number' +ATTR_HOSTNAME = 'hostname' +ATTR_MEMORY_AMOUNT = 'memory_amount' +ATTR_STATE = 'state' +ATTR_TITLE = 'title' +ATTR_UUID = 'uuid' +ATTR_ZONE = 'zone' + +CONF_SERVERS = 'servers' + +DATA_UPCLOUD = 'data_upcloud' +DOMAIN = 'upcloud' + +DEFAULT_COMPONENT_NAME = 'UpCloud {}' +DEFAULT_COMPONENT_DEVICE_CLASS = 'power' + +UPCLOUD_PLATFORMS = ['binary_sensor', 'switch'] + +SCAN_INTERVAL = timedelta(seconds=60) + +SIGNAL_UPDATE_UPCLOUD = "upcloud_update" + +STATE_MAP = { + "started": STATE_ON, + "stopped": STATE_OFF, + "error": STATE_PROBLEM, +} + +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 UpCloud component.""" + import upcloud_api + + conf = config[DOMAIN] + username = conf.get(CONF_USERNAME) + password = conf.get(CONF_PASSWORD) + scan_interval = conf.get(CONF_SCAN_INTERVAL) + + manager = upcloud_api.CloudManager(username, password) + + try: + manager.authenticate() + hass.data[DATA_UPCLOUD] = UpCloud(manager) + except upcloud_api.UpCloudAPIError: + _LOGGER.error("Authentication failed.") + return False + + def upcloud_update(event_time): + """Call UpCloud to update information.""" + _LOGGER.debug("Updating UpCloud component") + hass.data[DATA_UPCLOUD].update() + dispatcher_send(hass, SIGNAL_UPDATE_UPCLOUD) + + # Call the UpCloud API to refresh data + track_time_interval(hass, upcloud_update, scan_interval) + + return True + + +class UpCloud(object): + """Handle all communication with the UpCloud API.""" + + def __init__(self, manager): + """Initialize the UpCloud connection.""" + self.data = {} + self.manager = manager + + def update(self): + """Update data from UpCloud API.""" + self.data = { + server.uuid: server for server in self.manager.get_servers() + } + + +class UpCloudServerEntity(Entity): + """Entity class for UpCloud servers.""" + + def __init__(self, upcloud, uuid): + """Initialize the UpCloud server entity.""" + self._upcloud = upcloud + self.uuid = uuid + self.data = None + + @property + def name(self): + """Return the name of the component.""" + try: + return DEFAULT_COMPONENT_NAME.format(self.data.title) + except (AttributeError, KeyError, TypeError): + return DEFAULT_COMPONENT_NAME.format(self.uuid) + + @asyncio.coroutine + def async_added_to_hass(self): + """Register callbacks.""" + async_dispatcher_connect( + self.hass, SIGNAL_UPDATE_UPCLOUD, self._update_callback) + + def _update_callback(self): + """Call update method.""" + self.schedule_update_ha_state(True) + + @property + def icon(self): + """Return the icon of this server.""" + return 'mdi:server' if self.is_on else 'mdi:server-off' + + @property + def state(self): + """Return state of the server.""" + try: + return STATE_MAP.get(self.data.state, STATE_UNKNOWN) + except AttributeError: + return STATE_UNKNOWN + + @property + def is_on(self): + """Return true if the server is on.""" + return self.state == STATE_ON + + @property + def device_class(self): + """Return the class of this server.""" + return DEFAULT_COMPONENT_DEVICE_CLASS + + @property + def device_state_attributes(self): + """Return the state attributes of the UpCloud server.""" + return { + x: getattr(self.data, x, None) + for x in (ATTR_UUID, ATTR_TITLE, ATTR_HOSTNAME, ATTR_ZONE, + ATTR_STATE, ATTR_CORE_NUMBER, ATTR_MEMORY_AMOUNT) + } + + def update(self): + """Update data of the UpCloud server.""" + self.data = self._upcloud.data.get(self.uuid) diff --git a/requirements_all.txt b/requirements_all.txt index b3f5ee7508a..f6f8472776b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1207,6 +1207,9 @@ twilio==5.7.0 # homeassistant.components.sensor.uber uber_rides==0.6.0 +# homeassistant.components.upcloud +upcloud-api==0.4.2 + # homeassistant.components.sensor.ups upsmychoice==1.0.6