mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
commit
38da81c308
@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
})
|
||||
|
||||
REQUIREMENTS = ['python-miio==0.3.5']
|
||||
REQUIREMENTS = ['python-miio==0.3.6']
|
||||
|
||||
ATTR_TEMPERATURE = 'temperature'
|
||||
ATTR_HUMIDITY = 'humidity'
|
||||
|
@ -83,9 +83,9 @@ NODE_FILTERS = {
|
||||
},
|
||||
'fan': {
|
||||
'uom': [],
|
||||
'states': ['on', 'off', 'low', 'medium', 'high'],
|
||||
'states': ['off', 'low', 'medium', 'high'],
|
||||
'node_def_id': ['FanLincMotor'],
|
||||
'insteon_type': ['1.46.']
|
||||
'insteon_type': []
|
||||
},
|
||||
'cover': {
|
||||
'uom': ['97'],
|
||||
@ -99,7 +99,7 @@ NODE_FILTERS = {
|
||||
'node_def_id': ['DimmerLampSwitch', 'DimmerLampSwitch_ADV',
|
||||
'DimmerSwitchOnly', 'DimmerSwitchOnly_ADV',
|
||||
'DimmerLampOnly', 'BallastRelayLampSwitch',
|
||||
'BallastRelayLampSwitch_ADV', 'RelayLampSwitch',
|
||||
'BallastRelayLampSwitch_ADV',
|
||||
'RemoteLinc2', 'RemoteLinc2_ADV'],
|
||||
'insteon_type': ['1.']
|
||||
},
|
||||
@ -431,8 +431,11 @@ class ISYDevice(Entity):
|
||||
def unique_id(self) -> str:
|
||||
"""Get the unique identifier of the device."""
|
||||
# pylint: disable=protected-access
|
||||
if hasattr(self._node, '_id'):
|
||||
return self._node._id
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Get the name of the device."""
|
||||
|
@ -237,7 +237,6 @@ class LightTemplate(Light):
|
||||
@asyncio.coroutine
|
||||
def async_update(self):
|
||||
"""Update the state from the template."""
|
||||
print("ASYNC UPDATE")
|
||||
if self._template is not None:
|
||||
try:
|
||||
state = self._template.async_render().lower()
|
||||
@ -262,7 +261,7 @@ class LightTemplate(Light):
|
||||
self._state = None
|
||||
|
||||
if 0 <= int(brightness) <= 255:
|
||||
self._brightness = brightness
|
||||
self._brightness = int(brightness)
|
||||
else:
|
||||
_LOGGER.error(
|
||||
'Received invalid brightness : %s' +
|
||||
|
@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
})
|
||||
|
||||
REQUIREMENTS = ['python-miio==0.3.5']
|
||||
REQUIREMENTS = ['python-miio==0.3.6']
|
||||
|
||||
# The light does not accept cct values < 1
|
||||
CCT_MIN = 1
|
||||
|
@ -370,7 +370,8 @@ class PlexClient(MediaPlayerDevice):
|
||||
self._is_player_available = False
|
||||
self._media_position = self._session.viewOffset
|
||||
self._media_content_id = self._session.ratingKey
|
||||
self._media_content_rating = self._session.contentRating
|
||||
self._media_content_rating = getattr(
|
||||
self._session, 'contentRating', None)
|
||||
|
||||
self._set_player_state()
|
||||
|
||||
|
@ -12,8 +12,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
def purge_old_data(instance, purge_days):
|
||||
"""Purge events and states older than purge_days ago."""
|
||||
from .models import States, Events
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy.sql import exists
|
||||
from sqlalchemy import func
|
||||
|
||||
purge_before = dt_util.utcnow() - timedelta(days=purge_days)
|
||||
|
||||
@ -21,18 +20,10 @@ def purge_old_data(instance, purge_days):
|
||||
# For each entity, the most recent state is protected from deletion
|
||||
# s.t. we can properly restore state even if the entity has not been
|
||||
# updated in a long time
|
||||
states_alias = orm.aliased(States, name='StatesAlias')
|
||||
protected_states = session.query(States.state_id, States.event_id)\
|
||||
.filter(~exists()
|
||||
.where(States.entity_id ==
|
||||
states_alias.entity_id)
|
||||
.where(states_alias.last_updated >
|
||||
States.last_updated))\
|
||||
.all()
|
||||
protected_states = session.query(func.max(States.state_id)) \
|
||||
.group_by(States.entity_id).all()
|
||||
|
||||
protected_state_ids = tuple((state[0] for state in protected_states))
|
||||
protected_event_ids = tuple((state[1] for state in protected_states
|
||||
if state[1] is not None))
|
||||
|
||||
deleted_rows = session.query(States) \
|
||||
.filter((States.last_updated < purge_before)) \
|
||||
@ -45,6 +36,13 @@ def purge_old_data(instance, purge_days):
|
||||
# Otherwise, if the SQL server has "ON DELETE CASCADE" as default, it
|
||||
# will delete the protected state when deleting its associated
|
||||
# event. Also, we would be producing NULLed foreign keys otherwise.
|
||||
protected_events = session.query(States.event_id) \
|
||||
.filter(States.state_id.in_(protected_state_ids)) \
|
||||
.filter(States.event_id.isnot(None)) \
|
||||
.all()
|
||||
|
||||
protected_event_ids = tuple((state[0] for state in protected_events))
|
||||
|
||||
deleted_rows = session.query(Events) \
|
||||
.filter((Events.time_fired < purge_before)) \
|
||||
.filter(~Events.event_id.in_(
|
||||
|
@ -21,7 +21,7 @@ from homeassistant.const import (
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
REQUIREMENTS = ['python-miio==0.3.5']
|
||||
REQUIREMENTS = ['python-miio==0.3.6']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -126,6 +126,8 @@ class SQLSensor(Entity):
|
||||
except sqlalchemy.exc.SQLAlchemyError as err:
|
||||
_LOGGER.error("Error executing query %s: %s", self._query, err)
|
||||
return
|
||||
finally:
|
||||
sess.close()
|
||||
|
||||
for res in result:
|
||||
_LOGGER.debug(res.items())
|
||||
@ -141,5 +143,3 @@ class SQLSensor(Entity):
|
||||
data, None)
|
||||
else:
|
||||
self._state = data
|
||||
|
||||
sess.close()
|
||||
|
@ -7,7 +7,6 @@ https://home-assistant.io/components/sensor.yr/
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from datetime import timedelta
|
||||
from random import randrange
|
||||
from xml.parsers.expat import ExpatError
|
||||
|
||||
@ -22,16 +21,17 @@ from homeassistant.const import (
|
||||
ATTR_ATTRIBUTION, CONF_NAME)
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.event import (
|
||||
async_track_point_in_utc_time, async_track_utc_time_change)
|
||||
from homeassistant.helpers.event import (async_track_utc_time_change,
|
||||
async_call_later)
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
REQUIREMENTS = ['xmltodict==0.11.0']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_ATTRIBUTION = "Weather forecast from yr.no, delivered by the Norwegian " \
|
||||
"Meteorological Institute and the NRK."
|
||||
CONF_ATTRIBUTION = "Weather forecast from met.no, delivered " \
|
||||
"by the Norwegian Meteorological Institute."
|
||||
# https://api.met.no/license_data.html
|
||||
|
||||
SENSOR_TYPES = {
|
||||
'symbol': ['Symbol', None],
|
||||
@ -91,11 +91,8 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
async_add_devices(dev)
|
||||
|
||||
weather = YrData(hass, coordinates, forecast, dev)
|
||||
# Update weather on the hour, spread seconds
|
||||
async_track_utc_time_change(
|
||||
hass, weather.async_update, minute=randrange(1, 10),
|
||||
second=randrange(0, 59))
|
||||
yield from weather.async_update()
|
||||
async_track_utc_time_change(hass, weather.updating_devices, minute=31)
|
||||
yield from weather.fetching_data()
|
||||
|
||||
|
||||
class YrSensor(Entity):
|
||||
@ -153,27 +150,21 @@ class YrData(object):
|
||||
self._url = 'https://aa015h6buqvih86i1.api.met.no/'\
|
||||
'weatherapi/locationforecast/1.9/'
|
||||
self._urlparams = coordinates
|
||||
self._nextrun = None
|
||||
self._forecast = forecast
|
||||
self.devices = devices
|
||||
self.data = {}
|
||||
self.hass = hass
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update(self, *_):
|
||||
def fetching_data(self, *_):
|
||||
"""Get the latest data from yr.no."""
|
||||
import xmltodict
|
||||
|
||||
def try_again(err: str):
|
||||
"""Retry in 15 minutes."""
|
||||
_LOGGER.warning("Retrying in 15 minutes: %s", err)
|
||||
self._nextrun = None
|
||||
nxt = dt_util.utcnow() + timedelta(minutes=15)
|
||||
if nxt.minute >= 15:
|
||||
async_track_point_in_utc_time(self.hass, self.async_update,
|
||||
nxt)
|
||||
|
||||
if self._nextrun is None or dt_util.utcnow() >= self._nextrun:
|
||||
"""Retry in 15 to 20 minutes."""
|
||||
minutes = 15 + randrange(6)
|
||||
_LOGGER.error("Retrying in %i minutes: %s", minutes, err)
|
||||
async_call_later(self.hass, minutes*60, self.fetching_data)
|
||||
try:
|
||||
websession = async_get_clientsession(self.hass)
|
||||
with async_timeout.timeout(10, loop=self.hass.loop):
|
||||
@ -190,14 +181,19 @@ class YrData(object):
|
||||
|
||||
try:
|
||||
self.data = xmltodict.parse(text)['weatherdata']
|
||||
model = self.data['meta']['model']
|
||||
if '@nextrun' not in model:
|
||||
model = model[0]
|
||||
self._nextrun = dt_util.parse_datetime(model['@nextrun'])
|
||||
except (ExpatError, IndexError) as err:
|
||||
try_again(err)
|
||||
return
|
||||
|
||||
yield from self.updating_devices()
|
||||
async_call_later(self.hass, 60*60, self.fetching_data)
|
||||
|
||||
@asyncio.coroutine
|
||||
def updating_devices(self, *_):
|
||||
"""Find the current data from self.data."""
|
||||
if not self.data:
|
||||
return
|
||||
|
||||
now = dt_util.utcnow()
|
||||
forecast_time = now + dt_util.dt.timedelta(hours=self._forecast)
|
||||
|
||||
|
@ -25,7 +25,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
})
|
||||
|
||||
REQUIREMENTS = ['python-miio==0.3.5']
|
||||
REQUIREMENTS = ['python-miio==0.3.6']
|
||||
|
||||
ATTR_POWER = 'power'
|
||||
ATTR_TEMPERATURE = 'temperature'
|
||||
|
@ -19,7 +19,7 @@ from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, CONF_HOST, CONF_NAME, CONF_TOKEN, STATE_OFF, STATE_ON)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['python-miio==0.3.5']
|
||||
REQUIREMENTS = ['python-miio==0.3.6']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 63
|
||||
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)
|
||||
|
@ -922,7 +922,7 @@ python-juicenet==0.0.5
|
||||
# homeassistant.components.remote.xiaomi_miio
|
||||
# homeassistant.components.switch.xiaomi_miio
|
||||
# homeassistant.components.vacuum.xiaomi_miio
|
||||
python-miio==0.3.5
|
||||
python-miio==0.3.6
|
||||
|
||||
# homeassistant.components.media_player.mpd
|
||||
python-mpd2==0.5.5
|
||||
|
@ -586,7 +586,7 @@ class TestTemplateLight:
|
||||
state = self.hass.states.get('light.test_template_light')
|
||||
assert state is not None
|
||||
|
||||
assert state.attributes.get('brightness') == '42'
|
||||
assert state.attributes.get('brightness') == 42
|
||||
|
||||
def test_friendly_name(self):
|
||||
"""Test the accessibility of the friendly_name attribute."""
|
||||
|
Loading…
x
Reference in New Issue
Block a user