mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 17:27:10 +00:00
Merge remote-tracking branch 'balloob/dev' into update_notify
Conflicts: homeassistant/components/frontend/version.py homeassistant/components/frontend/www_static/frontend.html
This commit is contained in:
commit
9b5385c565
@ -84,6 +84,7 @@ omit =
|
||||
homeassistant/components/sensor/glances.py
|
||||
homeassistant/components/sensor/mysensors.py
|
||||
homeassistant/components/sensor/openweathermap.py
|
||||
homeassistant/components/switch/orvibo.py
|
||||
homeassistant/components/sensor/rest.py
|
||||
homeassistant/components/sensor/rpi_gpio.py
|
||||
homeassistant/components/sensor/sabnzbd.py
|
||||
|
@ -87,7 +87,10 @@ def setup(hass, config):
|
||||
|
||||
if camera:
|
||||
response = camera.camera_image()
|
||||
handler.wfile.write(response)
|
||||
if response is not None:
|
||||
handler.wfile.write(response)
|
||||
else:
|
||||
handler.send_response(HTTP_NOT_FOUND)
|
||||
else:
|
||||
handler.send_response(HTTP_NOT_FOUND)
|
||||
|
||||
@ -129,7 +132,8 @@ def setup(hass, config):
|
||||
while True:
|
||||
|
||||
img_bytes = camera.camera_image()
|
||||
|
||||
if img_bytes is None:
|
||||
continue
|
||||
headers_str = '\r\n'.join((
|
||||
'Content-length: {}'.format(len(img_bytes)),
|
||||
'Content-type: image/jpeg',
|
||||
|
@ -42,11 +42,19 @@ class GenericCamera(Camera):
|
||||
def camera_image(self):
|
||||
""" Return a still image reponse from the camera. """
|
||||
if self._username and self._password:
|
||||
response = requests.get(
|
||||
self._still_image_url,
|
||||
auth=HTTPBasicAuth(self._username, self._password))
|
||||
try:
|
||||
response = requests.get(
|
||||
self._still_image_url,
|
||||
auth=HTTPBasicAuth(self._username, self._password))
|
||||
except requests.exceptions.RequestException as error:
|
||||
_LOGGER.error('Error getting camera image: %s', error)
|
||||
return None
|
||||
else:
|
||||
response = requests.get(self._still_image_url)
|
||||
try:
|
||||
response = requests.get(self._still_image_url)
|
||||
except requests.exceptions.RequestException as error:
|
||||
_LOGGER.error('Error getting camera image: %s', error)
|
||||
return None
|
||||
|
||||
return response.content
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -37,6 +37,7 @@ CONF_EVENT_DATA = "event_data"
|
||||
CONF_DELAY = "delay"
|
||||
|
||||
ATTR_LAST_ACTION = 'last_action'
|
||||
ATTR_CAN_CANCEL = 'can_cancel'
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -113,6 +114,8 @@ class Script(ToggleEntity):
|
||||
self._cur = -1
|
||||
self._last_action = None
|
||||
self._listener = None
|
||||
self._can_cancel = not any(CONF_DELAY in action for action
|
||||
in self.sequence)
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
@ -126,7 +129,9 @@ class Script(ToggleEntity):
|
||||
@property
|
||||
def state_attributes(self):
|
||||
""" Returns the state attributes. """
|
||||
attrs = {}
|
||||
attrs = {
|
||||
ATTR_CAN_CANCEL: self._can_cancel
|
||||
}
|
||||
|
||||
if self._last_action:
|
||||
attrs[ATTR_LAST_ACTION] = self._last_action
|
||||
|
@ -70,6 +70,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
elif value.command_class == zwave.COMMAND_CLASS_SENSOR_MULTILEVEL:
|
||||
add_devices([ZWaveMultilevelSensor(value)])
|
||||
|
||||
elif (value.command_class == zwave.COMMAND_CLASS_METER and
|
||||
value.type == zwave.TYPE_DECIMAL):
|
||||
add_devices([ZWaveMultilevelSensor(value)])
|
||||
|
||||
|
||||
class ZWaveSensor(Entity):
|
||||
""" Represents a Z-Wave sensor. """
|
||||
|
@ -16,7 +16,8 @@ from homeassistant.helpers.entity import ToggleEntity
|
||||
|
||||
from homeassistant.const import (
|
||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
||||
from homeassistant.components import group, discovery, wink, isy994, verisure
|
||||
from homeassistant.components import (
|
||||
group, discovery, wink, isy994, verisure, zwave)
|
||||
|
||||
DOMAIN = 'switch'
|
||||
DEPENDENCIES = []
|
||||
@ -38,7 +39,8 @@ DISCOVERY_PLATFORMS = {
|
||||
discovery.SERVICE_WEMO: 'wemo',
|
||||
wink.DISCOVER_SWITCHES: 'wink',
|
||||
isy994.DISCOVER_SWITCHES: 'isy994',
|
||||
verisure.DISCOVER_SWITCHES: 'verisure'
|
||||
verisure.DISCOVER_SWITCHES: 'verisure',
|
||||
zwave.DISCOVER_SWITCHES: 'zwave',
|
||||
}
|
||||
|
||||
PROP_TO_ATTR = {
|
||||
|
75
homeassistant/components/switch/orvibo.py
Normal file
75
homeassistant/components/switch/orvibo.py
Normal file
@ -0,0 +1,75 @@
|
||||
"""
|
||||
homeassistant.components.switch.orvibo
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Support for Orvibo S20 Wifi Smart Switches.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/switch.orvibo/
|
||||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
|
||||
from orvibo.s20 import S20, S20Exception
|
||||
|
||||
DEFAULT_NAME = "Orvibo S20 Switch"
|
||||
REQUIREMENTS = ['orvibo==1.0.0']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||
""" Find and return S20 switches. """
|
||||
if config.get('host') is None:
|
||||
_LOGGER.error("Missing required variable: host")
|
||||
return
|
||||
try:
|
||||
s20 = S20(config.get('host'))
|
||||
add_devices_callback([S20Switch(config.get('name', DEFAULT_NAME),
|
||||
s20)])
|
||||
except S20Exception:
|
||||
_LOGGER.exception("S20 couldn't be initialized")
|
||||
|
||||
|
||||
class S20Switch(SwitchDevice):
|
||||
""" Represents an S20 switch. """
|
||||
def __init__(self, name, s20):
|
||||
self._name = name
|
||||
self._s20 = s20
|
||||
self._state = False
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
""" Poll. """
|
||||
return True
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
""" The name of the switch. """
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
""" True if device is on. """
|
||||
return self._state
|
||||
|
||||
def update(self):
|
||||
""" Update device state. """
|
||||
try:
|
||||
self._state = self._s20.on
|
||||
except S20Exception:
|
||||
_LOGGER.exception("Error while fetching S20 state")
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
""" Turn the device on. """
|
||||
try:
|
||||
self._s20.on = True
|
||||
except S20Exception:
|
||||
_LOGGER.exception("Error while turning on S20")
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
""" Turn the device off. """
|
||||
try:
|
||||
self._s20.on = False
|
||||
except S20Exception:
|
||||
_LOGGER.exception("Error while turning off S20")
|
76
homeassistant/components/switch/zwave.py
Normal file
76
homeassistant/components/switch/zwave.py
Normal file
@ -0,0 +1,76 @@
|
||||
"""
|
||||
homeassistant.components.switch.zwave
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Zwave platform that handles simple binary switches.
|
||||
"""
|
||||
# pylint: disable=import-error
|
||||
from openzwave.network import ZWaveNetwork
|
||||
from pydispatch import dispatcher
|
||||
|
||||
import homeassistant.components.zwave as zwave
|
||||
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
""" Find and return demo switches. """
|
||||
if discovery_info is None:
|
||||
return
|
||||
|
||||
node = zwave.NETWORK.nodes[discovery_info[zwave.ATTR_NODE_ID]]
|
||||
value = node.values[discovery_info[zwave.ATTR_VALUE_ID]]
|
||||
|
||||
if value.command_class != zwave.COMMAND_CLASS_SWITCH_BINARY:
|
||||
return
|
||||
if value.type != zwave.TYPE_BOOL:
|
||||
return
|
||||
if value.genre != zwave.GENRE_USER:
|
||||
return
|
||||
|
||||
value.set_change_verified(False)
|
||||
add_devices([ZwaveSwitch(value)])
|
||||
|
||||
|
||||
class ZwaveSwitch(SwitchDevice):
|
||||
""" Provides a zwave switch. """
|
||||
def __init__(self, value):
|
||||
self._value = value
|
||||
self._node = value.node
|
||||
|
||||
self._state = value.data
|
||||
|
||||
dispatcher.connect(
|
||||
self._value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED)
|
||||
|
||||
def _value_changed(self, value):
|
||||
""" Called when a value has changed on the network. """
|
||||
if self._value.value_id == value.value_id:
|
||||
self._state = value.data
|
||||
self.update_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
""" No polling needed for a demo switch. """
|
||||
return False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
""" Returns the name of the device if any. """
|
||||
name = self._node.name or "{}".format(self._node.product_name)
|
||||
|
||||
return "{}".format(name or self._value.label)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
""" True if device is on. """
|
||||
return self._state
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
""" Turn the device on. """
|
||||
self._node.set_switch(self._value.value_id, True)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
""" Turn the device off. """
|
||||
self._node.set_switch(self._value.value_id, False)
|
@ -20,13 +20,18 @@ REQUIREMENTS = ['pydispatcher==2.0.5']
|
||||
CONF_USB_STICK_PATH = "usb_path"
|
||||
DEFAULT_CONF_USB_STICK_PATH = "/zwaveusbstick"
|
||||
CONF_DEBUG = "debug"
|
||||
CONF_POLLING_INTERVAL = "polling_interval"
|
||||
|
||||
DISCOVER_SENSORS = "zwave.sensors"
|
||||
DISCOVER_SWITCHES = "zwave.switch"
|
||||
DISCOVER_LIGHTS = "zwave.light"
|
||||
|
||||
COMMAND_CLASS_SWITCH_MULTILEVEL = 38
|
||||
|
||||
COMMAND_CLASS_SWITCH_BINARY = 37
|
||||
COMMAND_CLASS_SENSOR_BINARY = 48
|
||||
COMMAND_CLASS_SENSOR_MULTILEVEL = 49
|
||||
COMMAND_CLASS_METER = 50
|
||||
COMMAND_CLASS_BATTERY = 128
|
||||
|
||||
GENRE_WHATEVER = None
|
||||
@ -35,20 +40,28 @@ GENRE_USER = "User"
|
||||
TYPE_WHATEVER = None
|
||||
TYPE_BYTE = "Byte"
|
||||
TYPE_BOOL = "Bool"
|
||||
TYPE_DECIMAL = "Decimal"
|
||||
|
||||
# list of tuple (DOMAIN, discovered service, supported command
|
||||
# classes, value type)
|
||||
DISCOVERY_COMPONENTS = [
|
||||
('sensor',
|
||||
DISCOVER_SENSORS,
|
||||
[COMMAND_CLASS_SENSOR_BINARY, COMMAND_CLASS_SENSOR_MULTILEVEL],
|
||||
[COMMAND_CLASS_SENSOR_BINARY,
|
||||
COMMAND_CLASS_SENSOR_MULTILEVEL,
|
||||
COMMAND_CLASS_METER],
|
||||
TYPE_WHATEVER,
|
||||
GENRE_WHATEVER),
|
||||
GENRE_USER),
|
||||
('light',
|
||||
DISCOVER_LIGHTS,
|
||||
[COMMAND_CLASS_SWITCH_MULTILEVEL],
|
||||
TYPE_BYTE,
|
||||
GENRE_USER),
|
||||
('switch',
|
||||
DISCOVER_SWITCHES,
|
||||
[COMMAND_CLASS_SWITCH_BINARY],
|
||||
TYPE_BOOL,
|
||||
GENRE_USER),
|
||||
]
|
||||
|
||||
ATTR_NODE_ID = "node_id"
|
||||
@ -165,6 +178,10 @@ def setup(hass, config):
|
||||
""" Called when Home Assistant starts up. """
|
||||
NETWORK.start()
|
||||
|
||||
polling_interval = config[DOMAIN].get(CONF_POLLING_INTERVAL, None)
|
||||
if polling_interval is not None:
|
||||
NETWORK.setPollInterval(polling_interval)
|
||||
|
||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave)
|
||||
|
||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave)
|
||||
|
@ -156,3 +156,6 @@ evohomeclient==0.2.3
|
||||
|
||||
# Pushetta (notify.pushetta)
|
||||
pushetta==1.0.15
|
||||
|
||||
# Orvibo S10
|
||||
orvibo==1.0.0
|
||||
|
@ -88,6 +88,8 @@ class TestScript(unittest.TestCase):
|
||||
|
||||
self.assertEqual(1, len(calls))
|
||||
self.assertEqual('world', calls[0].data.get('hello'))
|
||||
self.assertEqual(
|
||||
True, self.hass.states.get(ENTITY_ID).attributes.get('can_cancel'))
|
||||
|
||||
def test_calling_service_old(self):
|
||||
calls = []
|
||||
@ -172,6 +174,9 @@ class TestScript(unittest.TestCase):
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(script.is_on(self.hass, ENTITY_ID))
|
||||
self.assertEqual(
|
||||
False,
|
||||
self.hass.states.get(ENTITY_ID).attributes.get('can_cancel'))
|
||||
|
||||
self.assertEqual(
|
||||
event,
|
||||
|
Loading…
x
Reference in New Issue
Block a user