mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
commit
080f56e0f5
@ -39,7 +39,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
username = config.get(CONF_USERNAME)
|
||||
password = config.get(CONF_PASSWORD)
|
||||
|
||||
add_devices([AlarmDotCom(hass, name, code, username, password)])
|
||||
add_devices([AlarmDotCom(hass, name, code, username, password)], True)
|
||||
|
||||
|
||||
class AlarmDotCom(alarm.AlarmControlPanel):
|
||||
@ -54,12 +54,17 @@ class AlarmDotCom(alarm.AlarmControlPanel):
|
||||
self._code = str(code) if code else None
|
||||
self._username = username
|
||||
self._password = password
|
||||
self._state = STATE_UNKNOWN
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return True
|
||||
|
||||
def update(self):
|
||||
"""Fetch the latest state."""
|
||||
self._state = self._alarm.state
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the alarm."""
|
||||
@ -73,11 +78,11 @@ class AlarmDotCom(alarm.AlarmControlPanel):
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the device."""
|
||||
if self._alarm.state == 'Disarmed':
|
||||
if self._state == 'Disarmed':
|
||||
return STATE_ALARM_DISARMED
|
||||
elif self._alarm.state == 'Armed Stay':
|
||||
elif self._state == 'Armed Stay':
|
||||
return STATE_ALARM_ARMED_HOME
|
||||
elif self._alarm.state == 'Armed Away':
|
||||
elif self._state == 'Armed Away':
|
||||
return STATE_ALARM_ARMED_AWAY
|
||||
else:
|
||||
return STATE_UNKNOWN
|
||||
|
@ -91,7 +91,7 @@ class GenericCamera(Camera):
|
||||
if url == self._last_url and self._limit_refetch:
|
||||
return self._last_image
|
||||
|
||||
# aiohttp don't support DigestAuth jet
|
||||
# aiohttp don't support DigestAuth yet
|
||||
if self._authentication == HTTP_DIGEST_AUTHENTICATION:
|
||||
def fetch():
|
||||
"""Read image from a URL."""
|
||||
@ -109,15 +109,17 @@ class GenericCamera(Camera):
|
||||
else:
|
||||
try:
|
||||
with async_timeout.timeout(10, loop=self.hass.loop):
|
||||
respone = yield from self.hass.websession.get(
|
||||
url,
|
||||
auth=self._auth
|
||||
)
|
||||
self._last_image = yield from respone.read()
|
||||
yield from respone.release()
|
||||
response = yield from self.hass.websession.get(
|
||||
url, auth=self._auth)
|
||||
self._last_image = yield from response.read()
|
||||
yield from response.release()
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.error('Timeout getting camera image')
|
||||
return self._last_image
|
||||
except (aiohttp.errors.ClientError,
|
||||
aiohttp.errors.ClientDisconnectedError) as err:
|
||||
_LOGGER.error('Error getting new camera image: %s', err)
|
||||
return self._last_image
|
||||
|
||||
self._last_url = url
|
||||
return self._last_image
|
||||
|
@ -9,13 +9,14 @@ import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import aiohttp
|
||||
from aiohttp import web
|
||||
from aiohttp.web_exceptions import HTTPGatewayTimeout
|
||||
import async_timeout
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_NAME, CONF_USERNAME, CONF_PASSWORD,
|
||||
CONF_URL, CONF_WHITELIST, CONF_VERIFY_SSL)
|
||||
CONF_URL, CONF_WHITELIST, CONF_VERIFY_SSL, EVENT_HOMEASSISTANT_STOP)
|
||||
from homeassistant.components.camera import (
|
||||
Camera, PLATFORM_SCHEMA)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
@ -57,6 +58,16 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
"""Setup a Synology IP Camera."""
|
||||
if not config.get(CONF_VERIFY_SSL):
|
||||
connector = aiohttp.TCPConnector(verify_ssl=False)
|
||||
else:
|
||||
connector = None
|
||||
|
||||
websession_init = aiohttp.ClientSession(
|
||||
loop=hass.loop,
|
||||
connector=connector
|
||||
)
|
||||
|
||||
# Determine API to use for authentication
|
||||
syno_api_url = SYNO_API_URL.format(
|
||||
config.get(CONF_URL), WEBAPI_PATH, QUERY_CGI)
|
||||
@ -69,13 +80,12 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
}
|
||||
try:
|
||||
with async_timeout.timeout(TIMEOUT, loop=hass.loop):
|
||||
query_req = yield from hass.websession.get(
|
||||
query_req = yield from websession_init.get(
|
||||
syno_api_url,
|
||||
params=query_payload,
|
||||
verify_ssl=config.get(CONF_VERIFY_SSL)
|
||||
params=query_payload
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.error("Timeout on %s", syno_api_url)
|
||||
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
|
||||
_LOGGER.exception("Error on %s", syno_api_url)
|
||||
return False
|
||||
|
||||
query_resp = yield from query_req.json()
|
||||
@ -93,12 +103,26 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
|
||||
session_id = yield from get_session_id(
|
||||
hass,
|
||||
websession_init,
|
||||
config.get(CONF_USERNAME),
|
||||
config.get(CONF_PASSWORD),
|
||||
syno_auth_url,
|
||||
config.get(CONF_VERIFY_SSL)
|
||||
syno_auth_url
|
||||
)
|
||||
|
||||
websession_init.detach()
|
||||
|
||||
# init websession
|
||||
websession = aiohttp.ClientSession(
|
||||
loop=hass.loop, connector=connector, cookies={'id': session_id})
|
||||
|
||||
@asyncio.coroutine
|
||||
def _async_close_websession(event):
|
||||
"""Close webssesion on shutdown."""
|
||||
yield from websession.close()
|
||||
|
||||
hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_STOP, _async_close_websession)
|
||||
|
||||
# Use SessionID to get cameras in system
|
||||
syno_camera_url = SYNO_API_URL.format(
|
||||
config.get(CONF_URL), WEBAPI_PATH, camera_api)
|
||||
@ -110,14 +134,12 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
}
|
||||
try:
|
||||
with async_timeout.timeout(TIMEOUT, loop=hass.loop):
|
||||
camera_req = yield from hass.websession.get(
|
||||
camera_req = yield from websession.get(
|
||||
syno_camera_url,
|
||||
params=camera_payload,
|
||||
verify_ssl=config.get(CONF_VERIFY_SSL),
|
||||
cookies={'id': session_id}
|
||||
params=camera_payload
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.error("Timeout on %s", syno_camera_url)
|
||||
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
|
||||
_LOGGER.exception("Error on %s", syno_camera_url)
|
||||
return False
|
||||
|
||||
camera_resp = yield from camera_req.json()
|
||||
@ -126,13 +148,14 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
|
||||
# add cameras
|
||||
devices = []
|
||||
tasks = []
|
||||
for camera in cameras:
|
||||
if not config.get(CONF_WHITELIST):
|
||||
camera_id = camera['id']
|
||||
snapshot_path = camera['snapshot_path']
|
||||
|
||||
device = SynologyCamera(
|
||||
hass,
|
||||
websession,
|
||||
config,
|
||||
camera_id,
|
||||
camera['name'],
|
||||
@ -141,15 +164,13 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
camera_path,
|
||||
auth_path
|
||||
)
|
||||
tasks.append(device.async_read_sid())
|
||||
devices.append(device)
|
||||
|
||||
yield from asyncio.gather(*tasks, loop=hass.loop)
|
||||
hass.loop.create_task(async_add_devices(devices))
|
||||
yield from async_add_devices(devices)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_session_id(hass, username, password, login_url, valid_cert):
|
||||
def get_session_id(hass, websession, username, password, login_url):
|
||||
"""Get a session id."""
|
||||
auth_payload = {
|
||||
'api': AUTH_API,
|
||||
@ -162,13 +183,12 @@ def get_session_id(hass, username, password, login_url, valid_cert):
|
||||
}
|
||||
try:
|
||||
with async_timeout.timeout(TIMEOUT, loop=hass.loop):
|
||||
auth_req = yield from hass.websession.get(
|
||||
auth_req = yield from websession.get(
|
||||
login_url,
|
||||
params=auth_payload,
|
||||
verify_ssl=valid_cert
|
||||
params=auth_payload
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.error("Timeout on %s", login_url)
|
||||
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
|
||||
_LOGGER.exception("Error on %s", login_url)
|
||||
return False
|
||||
|
||||
auth_resp = yield from auth_req.json()
|
||||
@ -180,36 +200,22 @@ def get_session_id(hass, username, password, login_url, valid_cert):
|
||||
class SynologyCamera(Camera):
|
||||
"""An implementation of a Synology NAS based IP camera."""
|
||||
|
||||
def __init__(self, config, camera_id, camera_name,
|
||||
snapshot_path, streaming_path, camera_path, auth_path):
|
||||
def __init__(self, hass, websession, config, camera_id,
|
||||
camera_name, snapshot_path, streaming_path, camera_path,
|
||||
auth_path):
|
||||
"""Initialize a Synology Surveillance Station camera."""
|
||||
super().__init__()
|
||||
self.hass = hass
|
||||
self._websession = websession
|
||||
self._name = camera_name
|
||||
self._username = config.get(CONF_USERNAME)
|
||||
self._password = config.get(CONF_PASSWORD)
|
||||
self._synology_url = config.get(CONF_URL)
|
||||
self._api_url = config.get(CONF_URL) + 'webapi/'
|
||||
self._login_url = config.get(CONF_URL) + '/webapi/' + 'auth.cgi'
|
||||
self._camera_name = config.get(CONF_CAMERA_NAME)
|
||||
self._stream_id = config.get(CONF_STREAM_ID)
|
||||
self._valid_cert = config.get(CONF_VERIFY_SSL)
|
||||
self._camera_id = camera_id
|
||||
self._snapshot_path = snapshot_path
|
||||
self._streaming_path = streaming_path
|
||||
self._camera_path = camera_path
|
||||
self._auth_path = auth_path
|
||||
self._session_id = None
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_read_sid(self):
|
||||
"""Get a session id."""
|
||||
self._session_id = yield from get_session_id(
|
||||
self.hass,
|
||||
self._username,
|
||||
self._password,
|
||||
self._login_url,
|
||||
self._valid_cert
|
||||
)
|
||||
|
||||
def camera_image(self):
|
||||
"""Return bytes of camera image."""
|
||||
@ -230,14 +236,12 @@ class SynologyCamera(Camera):
|
||||
}
|
||||
try:
|
||||
with async_timeout.timeout(TIMEOUT, loop=self.hass.loop):
|
||||
response = yield from self.hass.websession.get(
|
||||
response = yield from self._websession.get(
|
||||
image_url,
|
||||
params=image_payload,
|
||||
verify_ssl=self._valid_cert,
|
||||
cookies={'id': self._session_id}
|
||||
params=image_payload
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.error("Timeout on %s", image_url)
|
||||
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
|
||||
_LOGGER.exception("Error on %s", image_url)
|
||||
return None
|
||||
|
||||
image = yield from response.read()
|
||||
@ -260,13 +264,12 @@ class SynologyCamera(Camera):
|
||||
}
|
||||
try:
|
||||
with async_timeout.timeout(TIMEOUT, loop=self.hass.loop):
|
||||
stream = yield from self.hass.websession.get(
|
||||
stream = yield from self._websession.get(
|
||||
streaming_url,
|
||||
payload=streaming_payload,
|
||||
verify_ssl=self._valid_cert,
|
||||
cookies={'id': self._session_id}
|
||||
params=streaming_payload
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
|
||||
_LOGGER.exception("Error on %s", streaming_url)
|
||||
raise HTTPGatewayTimeout()
|
||||
|
||||
response = web.StreamResponse()
|
||||
@ -281,7 +284,7 @@ class SynologyCamera(Camera):
|
||||
break
|
||||
response.write(data)
|
||||
finally:
|
||||
self.hass.loop.create_task(stream.release())
|
||||
self.hass.async_add_job(stream.release())
|
||||
yield from response.write_eof()
|
||||
|
||||
@property
|
||||
|
@ -56,6 +56,8 @@ class KNXThermostat(KNXMultiAddressDevice, ClimateDevice):
|
||||
self._unit_of_measurement = TEMP_CELSIUS # KNX always used celsius
|
||||
self._away = False # not yet supported
|
||||
self._is_fan_on = False # not yet supported
|
||||
self._current_temp = None
|
||||
self._target_temp = None
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
@ -70,16 +72,12 @@ class KNXThermostat(KNXMultiAddressDevice, ClimateDevice):
|
||||
@property
|
||||
def current_temperature(self):
|
||||
"""Return the current temperature."""
|
||||
from knxip.conversion import knx2_to_float
|
||||
|
||||
return knx2_to_float(self.value('temperature'))
|
||||
return self._current_temp
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
"""Return the temperature we try to reach."""
|
||||
from knxip.conversion import knx2_to_float
|
||||
|
||||
return knx2_to_float(self.value('setpoint'))
|
||||
return self._target_temp
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
@ -94,3 +92,12 @@ class KNXThermostat(KNXMultiAddressDevice, ClimateDevice):
|
||||
def set_operation_mode(self, operation_mode):
|
||||
"""Set operation mode."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def update(self):
|
||||
"""Update KNX climate."""
|
||||
from knxip.conversion import knx2_to_float
|
||||
|
||||
super().update()
|
||||
|
||||
self._current_temp = knx2_to_float(self.value('temperature'))
|
||||
self._target_temp = knx2_to_float(self.value('setpoint'))
|
||||
|
@ -161,8 +161,6 @@ class KNXGroupAddress(Entity):
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return True if the value is not 0 is on, else False."""
|
||||
if self.should_poll:
|
||||
self.update()
|
||||
return self._state != 0
|
||||
|
||||
@property
|
||||
|
@ -23,6 +23,7 @@ REQUIREMENTS = ['https://github.com/Danielhiversen/flux_led/archive/0.8.zip'
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_AUTOMATIC_ADD = 'automatic_add'
|
||||
ATTR_MODE = 'mode'
|
||||
|
||||
DOMAIN = 'flux_led'
|
||||
|
||||
@ -31,6 +32,8 @@ SUPPORT_FLUX_LED = (SUPPORT_BRIGHTNESS | SUPPORT_EFFECT |
|
||||
|
||||
DEVICE_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_NAME): cv.string,
|
||||
vol.Optional(ATTR_MODE, default='rgbw'):
|
||||
vol.All(cv.string, vol.In(['rgbw', 'rgb'])),
|
||||
})
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
@ -48,6 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
device = {}
|
||||
device['name'] = device_config[CONF_NAME]
|
||||
device['ipaddr'] = ipaddr
|
||||
device[ATTR_MODE] = device_config[ATTR_MODE]
|
||||
light = FluxLight(device)
|
||||
if light.is_valid:
|
||||
lights.append(light)
|
||||
@ -65,6 +69,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
if ipaddr in light_ips:
|
||||
continue
|
||||
device['name'] = device['id'] + " " + ipaddr
|
||||
device[ATTR_MODE] = 'rgbw'
|
||||
light = FluxLight(device)
|
||||
if light.is_valid:
|
||||
lights.append(light)
|
||||
@ -82,6 +87,7 @@ class FluxLight(Light):
|
||||
|
||||
self._name = device['name']
|
||||
self._ipaddr = device['ipaddr']
|
||||
self._mode = device[ATTR_MODE]
|
||||
self.is_valid = True
|
||||
self._bulb = None
|
||||
try:
|
||||
@ -132,7 +138,11 @@ class FluxLight(Light):
|
||||
if rgb:
|
||||
self._bulb.setRgb(*tuple(rgb))
|
||||
elif brightness:
|
||||
self._bulb.setWarmWhite255(brightness)
|
||||
if self._mode == 'rgbw':
|
||||
self._bulb.setWarmWhite255(brightness)
|
||||
elif self._mode == 'rgb':
|
||||
(red, green, blue) = self._bulb.getRgb()
|
||||
self._bulb.setRgb(red, green, blue, brightness=brightness)
|
||||
elif effect == EFFECT_RANDOM:
|
||||
self._bulb.setRgb(random.randrange(0, 255),
|
||||
random.randrange(0, 255),
|
||||
|
@ -79,16 +79,16 @@ class PanasonicVieraTVDevice(MediaPlayerDevice):
|
||||
self._playing = True
|
||||
self._state = STATE_UNKNOWN
|
||||
self._remote = remote
|
||||
self._volume = 0
|
||||
|
||||
def update(self):
|
||||
"""Retrieve the latest data."""
|
||||
try:
|
||||
self._muted = self._remote.get_mute()
|
||||
self._volume = self._remote.get_volume() / 100
|
||||
self._state = STATE_ON
|
||||
except OSError:
|
||||
self._state = STATE_OFF
|
||||
return False
|
||||
return True
|
||||
|
||||
def send_key(self, key):
|
||||
"""Send a key to the tv and handles exceptions."""
|
||||
@ -113,13 +113,7 @@ class PanasonicVieraTVDevice(MediaPlayerDevice):
|
||||
@property
|
||||
def volume_level(self):
|
||||
"""Volume level of the media player (0..1)."""
|
||||
volume = 0
|
||||
try:
|
||||
volume = self._remote.get_volume() / 100
|
||||
self._state = STATE_ON
|
||||
except OSError:
|
||||
self._state = STATE_OFF
|
||||
return volume
|
||||
return self._volume
|
||||
|
||||
@property
|
||||
def is_volume_muted(self):
|
||||
|
@ -21,9 +21,7 @@ from homeassistant.const import (
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['https://github.com/SoCo/SoCo/archive/'
|
||||
'cf8c2701165562eccbf1ecc879bf7060ceb0993e.zip#'
|
||||
'SoCo==0.12']
|
||||
REQUIREMENTS = ['SoCo==0.12']
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -18,7 +18,7 @@ from homeassistant.const import (CONF_NAME, CONF_HOST, STATE_OFF, STATE_ON,
|
||||
STATE_PLAYING, STATE_IDLE)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['rxv==0.3.0']
|
||||
REQUIREMENTS = ['rxv==0.3.1']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -35,6 +35,7 @@ CONF_SOURCE_IGNORE = 'source_ignore'
|
||||
CONF_ZONE_IGNORE = 'zone_ignore'
|
||||
|
||||
DEFAULT_NAME = 'Yamaha Receiver'
|
||||
KNOWN = 'yamaha_known_receivers'
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
@ -50,6 +51,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Setup the Yamaha platform."""
|
||||
import rxv
|
||||
# keep track of configured receivers so that we don't end up
|
||||
# discovering a receiver dynamically that we have static config
|
||||
# for.
|
||||
if hass.data.get(KNOWN, None) is None:
|
||||
hass.data[KNOWN] = set()
|
||||
|
||||
name = config.get(CONF_NAME)
|
||||
host = config.get(CONF_HOST)
|
||||
@ -62,12 +68,17 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
model = discovery_info[1]
|
||||
ctrl_url = discovery_info[2]
|
||||
desc_url = discovery_info[3]
|
||||
if ctrl_url in hass.data[KNOWN]:
|
||||
_LOGGER.info("%s already manually configured", ctrl_url)
|
||||
return
|
||||
receivers = rxv.RXV(
|
||||
ctrl_url,
|
||||
model_name=model,
|
||||
friendly_name=name,
|
||||
unit_desc_url=desc_url).zone_controllers()
|
||||
_LOGGER.info("Receivers: %s", receivers)
|
||||
# when we are dynamically discovered config is empty
|
||||
zone_ignore = []
|
||||
elif host is None:
|
||||
receivers = []
|
||||
for recv in rxv.find():
|
||||
@ -78,6 +89,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
|
||||
for receiver in receivers:
|
||||
if receiver.zone not in zone_ignore:
|
||||
hass.data[KNOWN].add(receiver.ctrl_url)
|
||||
add_devices([
|
||||
YamahaDevice(name, receiver, source_ignore, source_names)])
|
||||
|
||||
|
@ -113,15 +113,24 @@ class KNXSensorFloatClass(KNXGroupAddress, KNXSensorBaseClass):
|
||||
self._unit_of_measurement = unit_of_measurement
|
||||
self._minimum_value = minimum_sensor_value
|
||||
self._maximum_value = maximum_sensor_value
|
||||
self._value = None
|
||||
|
||||
KNXGroupAddress.__init__(self, hass, config)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the Value of the KNX Sensor."""
|
||||
return self._value
|
||||
|
||||
def update(self):
|
||||
"""Update KNX sensor."""
|
||||
from knxip.conversion import knx2_to_float
|
||||
|
||||
super().update()
|
||||
|
||||
self._value = None
|
||||
|
||||
if self._data:
|
||||
from knxip.conversion import knx2_to_float
|
||||
value = knx2_to_float(self._data)
|
||||
if self._minimum_value <= value <= self._maximum_value:
|
||||
return value
|
||||
return None
|
||||
self._value = value
|
||||
|
@ -98,6 +98,7 @@ class TellstickSensor(Entity):
|
||||
self.datatype = datatype
|
||||
self.sensor = sensor
|
||||
self._unit_of_measurement = sensor_info.unit or None
|
||||
self._value = None
|
||||
|
||||
self._name = '{} {}'.format(name, sensor_info.name)
|
||||
|
||||
@ -109,9 +110,13 @@ class TellstickSensor(Entity):
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the sensor."""
|
||||
return self.sensor.value(self.datatype).value
|
||||
return self._value
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement of this entity, if any."""
|
||||
return self._unit_of_measurement
|
||||
|
||||
def update(self):
|
||||
"""Update tellstick sensor."""
|
||||
self._value = self.sensor.value(self.datatype).value
|
||||
|
@ -10,7 +10,7 @@ import logging
|
||||
from xml.parsers.expat import ExpatError
|
||||
|
||||
import async_timeout
|
||||
from aiohttp.web import HTTPException
|
||||
import aiohttp
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
@ -154,12 +154,9 @@ class YrData(object):
|
||||
try_again('{} returned {}'.format(self._url, resp.status))
|
||||
return
|
||||
text = yield from resp.text()
|
||||
self.hass.loop.create_task(resp.release())
|
||||
except asyncio.TimeoutError as err:
|
||||
try_again(err)
|
||||
return
|
||||
except HTTPException as err:
|
||||
resp.close()
|
||||
self.hass.async_add_job(resp.release)
|
||||
except (asyncio.TimeoutError, aiohttp.errors.ClientError,
|
||||
aiohttp.errors.ClientDisconnectedError) as err:
|
||||
try_again(err)
|
||||
return
|
||||
|
||||
@ -218,4 +215,5 @@ class YrData(object):
|
||||
dev._state = new_state
|
||||
tasks.append(dev.async_update_ha_state())
|
||||
|
||||
yield from asyncio.gather(*tasks, loop=self.hass.loop)
|
||||
if tasks:
|
||||
yield from asyncio.wait(tasks, loop=self.hass.loop)
|
||||
|
@ -27,10 +27,10 @@ DEPENDENCIES = ['pilight']
|
||||
COMMAND_SCHEMA = pilight.RF_CODE_SCHEMA.extend({
|
||||
vol.Optional('on'): cv.positive_int,
|
||||
vol.Optional('off'): cv.positive_int,
|
||||
vol.Optional(CONF_UNIT): cv.string,
|
||||
vol.Optional(CONF_UNIT): cv.positive_int,
|
||||
vol.Optional(CONF_ID): cv.positive_int,
|
||||
vol.Optional(CONF_STATE): cv.string,
|
||||
vol.Optional(CONF_SYSTEMCODE): cv.string,
|
||||
vol.Optional(CONF_SYSTEMCODE): cv.positive_int,
|
||||
})
|
||||
|
||||
SWITCHES_SCHEMA = vol.Schema({
|
||||
|
@ -12,11 +12,12 @@ import voluptuous as vol
|
||||
from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA)
|
||||
from homeassistant.const import (CONF_NAME, CONF_RESOURCE, CONF_TIMEOUT)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.template import Template
|
||||
|
||||
CONF_BODY_OFF = 'body_off'
|
||||
CONF_BODY_ON = 'body_on'
|
||||
DEFAULT_BODY_OFF = 'OFF'
|
||||
DEFAULT_BODY_ON = 'ON'
|
||||
DEFAULT_BODY_OFF = Template('OFF')
|
||||
DEFAULT_BODY_ON = Template('ON')
|
||||
DEFAULT_NAME = 'REST Switch'
|
||||
DEFAULT_TIMEOUT = 10
|
||||
CONF_IS_ON_TEMPLATE = 'is_on_template'
|
||||
|
@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
data = WeatherData(owm, latitude, longitude)
|
||||
|
||||
add_devices([OpenWeatherMapWeather(
|
||||
name, data, hass.config.units.temperature_unit)])
|
||||
name, data, hass.config.units.temperature_unit)], True)
|
||||
|
||||
|
||||
class OpenWeatherMapWeather(WeatherEntity):
|
||||
@ -78,8 +78,7 @@ class OpenWeatherMapWeather(WeatherEntity):
|
||||
self._name = name
|
||||
self._owm = owm
|
||||
self._temperature_unit = temperature_unit
|
||||
self.date = None
|
||||
self.update()
|
||||
self.data = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -2,7 +2,7 @@
|
||||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 32
|
||||
PATCH_VERSION = '2'
|
||||
PATCH_VERSION = '3'
|
||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
||||
REQUIRED_PYTHON_VER = (3, 4, 2)
|
||||
|
@ -242,7 +242,7 @@ class Entity(object):
|
||||
|
||||
end = timer()
|
||||
|
||||
if end - start > 0.2:
|
||||
if end - start > 0.4:
|
||||
_LOGGER.warning('Updating state for %s took %.3f seconds. '
|
||||
'Please report platform to the developers at '
|
||||
'https://goo.gl/Nvioub', self.entity_id,
|
||||
|
@ -24,6 +24,9 @@ PyMata==2.13
|
||||
# homeassistant.components.rpi_gpio
|
||||
# RPi.GPIO==0.6.1
|
||||
|
||||
# homeassistant.components.media_player.sonos
|
||||
SoCo==0.12
|
||||
|
||||
# homeassistant.components.notify.twitter
|
||||
TwitterAPI==2.4.2
|
||||
|
||||
@ -157,9 +160,6 @@ https://github.com/GadgetReactor/pyHS100/archive/1f771b7d8090a91c6a58931532e4273
|
||||
# homeassistant.components.switch.dlink
|
||||
https://github.com/LinuxChristian/pyW215/archive/v0.3.5.zip#pyW215==0.3.5
|
||||
|
||||
# homeassistant.components.media_player.sonos
|
||||
https://github.com/SoCo/SoCo/archive/cf8c2701165562eccbf1ecc879bf7060ceb0993e.zip#SoCo==0.12
|
||||
|
||||
# homeassistant.components.media_player.webostv
|
||||
# homeassistant.components.notify.webostv
|
||||
https://github.com/TheRealLink/pylgtv/archive/v0.1.2.zip#pylgtv==0.1.2
|
||||
@ -464,7 +464,7 @@ radiotherm==1.2
|
||||
# rpi-rf==0.9.5
|
||||
|
||||
# homeassistant.components.media_player.yamaha
|
||||
rxv==0.3.0
|
||||
rxv==0.3.1
|
||||
|
||||
# homeassistant.components.media_player.samsungtv
|
||||
samsungctl==0.5.1
|
||||
|
Loading…
x
Reference in New Issue
Block a user