diff --git a/.coveragerc b/.coveragerc index 2ea0f11a6bd..f0953f49cd5 100644 --- a/.coveragerc +++ b/.coveragerc @@ -24,6 +24,9 @@ omit = homeassistant/components/device_tracker/tomato.py homeassistant/components/device_tracker/netgear.py homeassistant/components/device_tracker/nmap_tracker.py + homeassistant/components/light/vera.py + homeassistant/components/sensor/vera.py + homeassistant/components/switch/vera.py [report] diff --git a/.gitmodules b/.gitmodules index 6e49e76698a..2e43a7d4dd0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "homeassistant/components/frontend/www_static/polymer/home-assistant-js"] path = homeassistant/components/frontend/www_static/polymer/home-assistant-js url = https://github.com/balloob/home-assistant-js.git +[submodule "homeassistant/external/vera"] + path = homeassistant/external/vera + url = https://github.com/jamespcole/home-assistant-vera-api.git diff --git a/homeassistant/components/light/vera.py b/homeassistant/components/light/vera.py new file mode 100644 index 00000000000..46fd3b54bb4 --- /dev/null +++ b/homeassistant/components/light/vera.py @@ -0,0 +1,94 @@ +""" +Support for Vera lights. + +Configuration: +This component is useful if you wish for switches connected to your Vera +controller to appear as lights in homeassistant. All switches will be added +as a light unless you exclude them in the config. + +To use the Vera lights you will need to add something like the following to +your config/configuration.yaml + +light: + platform: vera + vera_controller_url: http://YOUR_VERA_IP:3480/ + device_data: + 12: + name: My awesome switch + exclude: true + 13: + name: Another switch + +VARIABLES: + +vera_controller_url +*Required +This is the base URL of your vera controller including the port number if not +running on 80 +Example: http://192.168.1.21:3480/ + + +device_data +*Optional +This contains an array additional device info for your Vera devices. It is not +required and if not specified all lights configured in your Vera controller +will be added with default values. You should use the id of your vera device +as the key for the device within device_data + + +These are the variables for the device_data array: + +name +*Optional +This parameter allows you to override the name of your Vera device in the HA +interface, if not specified the value configured for the device in your Vera +will be used + + +exclude +*Optional +This parameter allows you to exclude the specified device from homeassistant, +it should be set to "true" if you want this device excluded + +""" +import logging +from requests.exceptions import RequestException +from homeassistant.components.switch.vera import VeraSwitch +# pylint: disable=no-name-in-module, import-error +import homeassistant.external.vera.vera as veraApi + +_LOGGER = logging.getLogger(__name__) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices_callback, discovery_info=None): + """ Find and return Vera lights. """ + + base_url = config.get('vera_controller_url') + if not base_url: + _LOGGER.error( + "The required parameter 'vera_controller_url'" + " was not found in config" + ) + return False + + device_data = config.get('device_data', {}) + + controller = veraApi.VeraController(base_url) + devices = [] + try: + devices = controller.get_devices('Switch') + except RequestException: + # There was a network related error connecting to the vera controller + _LOGGER.exception("Error communicating with Vera API") + return False + + lights = [] + for device in devices: + extra_data = device_data.get(device.deviceId, {}) + exclude = extra_data.get('exclude', False) + + if exclude is not True: + lights.append(VeraSwitch(device, extra_data)) + + add_devices_callback(lights) diff --git a/homeassistant/components/sensor/vera.py b/homeassistant/components/sensor/vera.py new file mode 100644 index 00000000000..71531253207 --- /dev/null +++ b/homeassistant/components/sensor/vera.py @@ -0,0 +1,163 @@ +""" +Support for Vera sensors. + +Configuration: +To use the Vera sensors you will need to add something like the following to +your config/configuration.yaml + +sensor: + platform: vera + vera_controller_url: http://YOUR_VERA_IP:3480/ + device_data: + 12: + name: My awesome sensor + exclude: true + 13: + name: Another sensor + +VARIABLES: + +vera_controller_url +*Required +This is the base URL of your vera controller including the port number if not +running on 80 +Example: http://192.168.1.21:3480/ + + +device_data +*Optional +This contains an array additional device info for your Vera devices. It is not +required and if not specified all sensors configured in your Vera controller +will be added with default values. You should use the id of your vera device +as the key for the device within device_data + +These are the variables for the device_data array: + +name +*Optional +This parameter allows you to override the name of your Vera device in the HA +interface, if not specified the value configured for the device in your Vera +will be used + + +exclude +*Optional +This parameter allows you to exclude the specified device from homeassistant, +it should be set to "true" if you want this device excluded + +""" +import logging +import time +from requests.exceptions import RequestException + +from homeassistant.helpers import Device +from homeassistant.const import ( + ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME) +# pylint: disable=no-name-in-module, import-error +import homeassistant.external.vera.vera as veraApi + +_LOGGER = logging.getLogger(__name__) + + +# pylint: disable=unused-argument +def get_devices(hass, config): + """ Find and return Vera Sensors. """ + + base_url = config.get('vera_controller_url') + if not base_url: + _LOGGER.error( + "The required parameter 'vera_controller_url'" + " was not found in config" + ) + return False + + device_data = config.get('device_data', {}) + + vera_controller = veraApi.VeraController(base_url) + categories = ['Temperature Sensor', 'Light Sensor', 'Sensor'] + devices = [] + try: + devices = vera_controller.get_devices(categories) + except RequestException: + # There was a network related error connecting to the vera controller + _LOGGER.exception("Error communicating with Vera API") + return False + + vera_sensors = [] + for device in devices: + extra_data = device_data.get(device.deviceId, {}) + exclude = extra_data.get('exclude', False) + + if exclude is not True: + vera_sensors.append(VeraSensor(device, extra_data)) + + return vera_sensors + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Performs setup for Vera controller devices """ + add_devices(get_devices(hass, config)) + + +class VeraSensor(Device): + """ Represents a Vera Sensor """ + extra_data = None + current_value = '' + + def __init__(self, vera_device, extra_data=None): + self.vera_device = vera_device + self.extra_data = extra_data + if self.extra_data and self.extra_data.get('name'): + self._name = self.extra_data.get('name') + else: + self._name = self.vera_device.name + + def __str__(self): + return "%s %s %s" % (self.name, self.vera_device.deviceId, self.state) + + @property + def state(self): + return self.current_value + + @property + def name(self): + """ Get the mame of the sensor. """ + return self._name + + @property + def state_attributes(self): + attr = super().state_attributes + if self.vera_device.has_battery: + attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%' + + if self.vera_device.is_armable: + armed = self.vera_device.refresh_value('Armed') + attr[ATTR_ARMED] = 'True' if armed == '1' else 'False' + + if self.vera_device.is_trippable: + last_tripped = self.vera_device.refresh_value('LastTrip') + trip_time_str = time.strftime( + "%Y-%m-%d %H:%M", + time.localtime(int(last_tripped)) + ) + attr[ATTR_LAST_TRIP_TIME] = trip_time_str + tripped = self.vera_device.refresh_value('Tripped') + attr[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False' + + attr['Vera Device Id'] = self.vera_device.vera_device_id + return attr + + def update(self): + if self.vera_device.category == "Temperature Sensor": + self.vera_device.refresh_value('CurrentTemperature') + current_temp = self.vera_device.get_value('CurrentTemperature') + vera_temp_units = self.vera_device.veraController.temperature_units + self.current_value = current_temp + '°' + vera_temp_units + elif self.vera_device.category == "Light Sensor": + self.vera_device.refresh_value('CurrentLevel') + self.current_value = self.vera_device.get_value('CurrentLevel') + elif self.vera_device.category == "Sensor": + tripped = self.vera_device.refresh_value('Tripped') + self.current_value = 'Tripped' if tripped == '1' else 'Not Tripped' + else: + self.current_value = 'Unknown' diff --git a/homeassistant/components/switch/vera.py b/homeassistant/components/switch/vera.py new file mode 100644 index 00000000000..800913e6850 --- /dev/null +++ b/homeassistant/components/switch/vera.py @@ -0,0 +1,167 @@ +""" +Support for Vera switches. + +Configuration: +To use the Vera lights you will need to add something like the following to +your config/configuration.yaml + +switch: + platform: vera + vera_controller_url: http://YOUR_VERA_IP:3480/ + device_data: + 12: + name: My awesome switch + exclude: true + 13: + name: Another Switch + +VARIABLES: + +vera_controller_url +*Required +This is the base URL of your vera controller including the port number if not +running on 80 +Example: http://192.168.1.21:3480/ + + +device_data +*Optional +This contains an array additional device info for your Vera devices. It is not +required and if not specified all lights configured in your Vera controller +will be added with default values. You should use the id of your vera device +as the key for the device within device_data + + +These are the variables for the device_data array: + + +name +*Optional +This parameter allows you to override the name of your Vera device in the HA +interface, if not specified the value configured for the device in your Vera +will be used + + +exclude +*Optional +This parameter allows you to exclude the specified device from homeassistant, +it should be set to "true" if you want this device excluded + +""" +import logging +import time +from requests.exceptions import RequestException + +from homeassistant.helpers import ToggleDevice +from homeassistant.const import ( + ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME) +# pylint: disable=no-name-in-module, import-error +import homeassistant.external.vera.vera as veraApi + +_LOGGER = logging.getLogger(__name__) + + +# pylint: disable=unused-argument +def get_devices(hass, config): + """ Find and return Vera switches. """ + + base_url = config.get('vera_controller_url') + if not base_url: + _LOGGER.error( + "The required parameter 'vera_controller_url'" + " was not found in config" + ) + return False + + device_data = config.get('device_data', {}) + + vera_controller = veraApi.VeraController(base_url) + devices = [] + try: + devices = vera_controller.get_devices(['Switch', 'Armable Sensor']) + except RequestException: + # There was a network related error connecting to the vera controller + _LOGGER.exception("Error communicating with Vera API") + return False + + vera_switches = [] + for device in devices: + extra_data = device_data.get(device.deviceId, {}) + exclude = extra_data.get('exclude', False) + + if exclude is not True: + vera_switches.append(VeraSwitch(device, extra_data)) + + return vera_switches + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Find and return Vera lights. """ + add_devices(get_devices(hass, config)) + + +class VeraSwitch(ToggleDevice): + """ Represents a Vera Switch """ + is_on_status = False + # for debouncing status check after command is sent + last_command_send = 0 + extra_data = None + + def __init__(self, vera_device, extra_data=None): + self.vera_device = vera_device + self.extra_data = extra_data + if self.extra_data and self.extra_data.get('name'): + self._name = self.extra_data.get('name') + else: + self._name = self.vera_device.name + + @property + def name(self): + """ Get the mame of the switch. """ + return self._name + + @property + def state_attributes(self): + attr = super().state_attributes + + if self.vera_device.has_battery: + attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%' + + if self.vera_device.is_armable: + armed = self.vera_device.refresh_value('Armed') + attr[ATTR_ARMED] = 'True' if armed == '1' else 'False' + + if self.vera_device.is_trippable: + last_tripped = self.vera_device.refresh_value('LastTrip') + trip_time_str = time.strftime( + "%Y-%m-%d %H:%M", + time.localtime(int(last_tripped)) + ) + attr[ATTR_LAST_TRIP_TIME] = trip_time_str + tripped = self.vera_device.refresh_value('Tripped') + attr[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False' + + attr['Vera Device Id'] = self.vera_device.vera_device_id + + return attr + + def turn_on(self, **kwargs): + self.last_command_send = time.time() + self.vera_device.switch_on() + self.is_on_status = True + + def turn_off(self, **kwargs): + self.last_command_send = time.time() + self.vera_device.switch_off() + self.is_on_status = False + + @property + def is_on(self): + """ True if device is on. """ + return self.is_on_status + + def update(self): + # We need to debounce the status call after turning switch on or off + # because the vera has some lag in updating the device status + if (self.last_command_send + 5) < time.time(): + self.is_on_status = self.vera_device.is_switched_on() diff --git a/homeassistant/const.py b/homeassistant/const.py index e90f1338b83..ed74f1edf4f 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -73,6 +73,16 @@ ATTR_LOCATION = "location" ATTR_BATTERY_LEVEL = "battery_level" +# For devices which support an armed state +ATTR_ARMED = "device_armed" + +# For sensors that support 'tripping', eg. motion and door sensors +ATTR_TRIPPED = "device_tripped" + +# For sensors that support 'tripping' this holds the most recent +# time the device was tripped +ATTR_LAST_TRIP_TIME = "last_tripped_time" + # #### SERVICES #### SERVICE_HOMEASSISTANT_STOP = "stop" diff --git a/homeassistant/external/vera b/homeassistant/external/vera new file mode 160000 index 00000000000..fedbb5c3af1 --- /dev/null +++ b/homeassistant/external/vera @@ -0,0 +1 @@ +Subproject commit fedbb5c3af1e5f36b7008d894e9fc1ecf3cc2ea8