Load yaml using validator and include consider_home (#3743)

* Load yaml using validator, consider_home

* timedelta, track_if_away

* improve voluptuous

* Add default back

* Change time_period validation order
This commit is contained in:
Johann Kellerman 2016-10-08 03:08:33 +02:00 committed by Paulus Schoutsen
parent b09b13f552
commit fb94aaa5a1
4 changed files with 53 additions and 31 deletions

View file

@ -46,7 +46,6 @@ CONF_TRACK_NEW = 'track_new_devices'
DEFAULT_TRACK_NEW = True
CONF_CONSIDER_HOME = 'consider_home'
DEFAULT_CONSIDER_HOME = 180 # seconds
CONF_SCAN_INTERVAL = 'interval_seconds'
DEFAULT_SCAN_INTERVAL = 12
@ -70,8 +69,10 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
_CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.All(cv.ensure_list, [
vol.Schema({
vol.Optional(CONF_TRACK_NEW): cv.boolean,
vol.Optional(CONF_CONSIDER_HOME): cv.positive_int # seconds
vol.Optional(CONF_TRACK_NEW, default=DEFAULT_TRACK_NEW): cv.boolean,
vol.Optional(
CONF_CONSIDER_HOME, default=timedelta(seconds=180)): vol.All(
cv.time_period, cv.positive_timedelta)
}, extra=vol.ALLOW_EXTRA)])}, extra=vol.ALLOW_EXTRA)
DISCOVERY_PLATFORMS = {
@ -118,9 +119,8 @@ def setup(hass: HomeAssistantType, config: ConfigType):
return False
else:
conf = conf[0] if len(conf) > 0 else {}
consider_home = timedelta(
seconds=conf.get(CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME))
track_new = conf.get(CONF_TRACK_NEW, DEFAULT_TRACK_NEW)
consider_home = conf[CONF_CONSIDER_HOME]
track_new = conf[CONF_TRACK_NEW]
devices = load_config(yaml_path, hass, consider_home)
@ -282,7 +282,7 @@ class Device(Entity):
def __init__(self, hass: HomeAssistantType, consider_home: timedelta,
track: bool, dev_id: str, mac: str, name: str=None,
picture: str=None, gravatar: str=None,
away_hide: bool=False) -> None:
hide_if_away: bool=False) -> None:
"""Initialize a device."""
self.hass = hass
self.entity_id = ENTITY_ID_FORMAT.format(dev_id)
@ -307,7 +307,7 @@ class Device(Entity):
else:
self.config_picture = picture
self.away_hide = away_hide
self.away_hide = hide_if_away
@property
def name(self):
@ -398,15 +398,29 @@ class Device(Entity):
def load_config(path: str, hass: HomeAssistantType, consider_home: timedelta):
"""Load devices from YAML configuration file."""
dev_schema = vol.Schema({
vol.Required('name'): cv.string,
vol.Optional('track', default=False): cv.boolean,
vol.Optional('mac', default=None): vol.Any(None, vol.All(cv.string,
vol.Upper)),
vol.Optional(CONF_AWAY_HIDE, default=DEFAULT_AWAY_HIDE): cv.boolean,
vol.Optional('gravatar', default=None): vol.Any(None, cv.string),
vol.Optional('picture', default=None): vol.Any(None, cv.string),
vol.Optional(CONF_CONSIDER_HOME, default=consider_home): vol.All(
cv.time_period, cv.positive_timedelta)
})
try:
return [
Device(hass, consider_home, device.get('track', False),
str(dev_id).lower(), None if device.get('mac') is None
else str(device.get('mac')).upper(),
device.get('name'), device.get('picture'),
device.get('gravatar'),
device.get(CONF_AWAY_HIDE, DEFAULT_AWAY_HIDE))
for dev_id, device in load_yaml_config_file(path).items()]
result = []
devices = load_yaml_config_file(path)
for dev_id, device in devices.items():
try:
device = dev_schema(device)
device['dev_id'] = cv.slug(dev_id)
except vol.Invalid as exp:
log_exception(exp, dev_id, devices)
else:
result.append(Device(hass, **device))
return result
except (HomeAssistantError, FileNotFoundError):
# When YAML file could not be loaded/did not contain a dict
return []

View file

@ -167,7 +167,16 @@ def time_period_str(value: str) -> timedelta:
return offset
time_period = vol.Any(time_period_str, timedelta, time_period_dict)
def time_period_seconds(value: Union[int, str]) -> timedelta:
"""Validate and transform seconds to a time offset."""
try:
return timedelta(seconds=int(value))
except (ValueError, TypeError):
raise vol.Invalid('Expected seconds, got {}'.format(value))
time_period = vol.Any(time_period_str, time_period_seconds, timedelta,
time_period_dict)
def match_all(value):

View file

@ -59,15 +59,13 @@ class TestComponentsDeviceTracker(unittest.TestCase):
def test_reading_broken_yaml_config(self): # pylint: disable=no-self-use
"""Test when known devices contains invalid data."""
files = {'empty.yaml': '',
'bad.yaml': '100',
'ok.yaml': 'my_device:\n name: Device'}
'nodict.yaml': '100',
'allok.yaml': 'my_device:\n name: Device'}
args = {'hass': self.hass, 'consider_home': timedelta(seconds=60)}
with patch_yaml_files(files):
# File is empty
assert device_tracker.load_config('empty.yaml', None, False) == []
# File contains a non-dict format
assert device_tracker.load_config('bad.yaml', None, False) == []
# A file that works fine
assert len(device_tracker.load_config('ok.yaml', None, False)) == 1
assert device_tracker.load_config('empty.yaml', **args) == []
assert device_tracker.load_config('nodict.yaml', **args) == []
assert len(device_tracker.load_config('allok.yaml', **args)) == 1
def test_reading_yaml_config(self):
"""Test the rendering of the YAML configuration."""
@ -75,7 +73,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
device = device_tracker.Device(
self.hass, timedelta(seconds=180), True, dev_id,
'AB:CD:EF:GH:IJ', 'Test name', picture='http://test.picture',
away_hide=True)
hide_if_away=True)
device_tracker.update_config(self.yaml_devices, dev_id, device)
self.assertTrue(setup_component(self.hass, device_tracker.DOMAIN,
TEST_PLATFORM))
@ -211,7 +209,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
device = device_tracker.Device(
self.hass, timedelta(seconds=180), True, dev_id, None,
friendly_name, picture, away_hide=True)
friendly_name, picture, hide_if_away=True)
device_tracker.update_config(self.yaml_devices, dev_id, device)
self.assertTrue(setup_component(self.hass, device_tracker.DOMAIN,
@ -228,7 +226,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
entity_id = device_tracker.ENTITY_ID_FORMAT.format(dev_id)
device = device_tracker.Device(
self.hass, timedelta(seconds=180), True, dev_id, None,
away_hide=True)
hide_if_away=True)
device_tracker.update_config(self.yaml_devices, dev_id, device)
scanner = get_component('device_tracker.test').SCANNER
@ -246,7 +244,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
entity_id = device_tracker.ENTITY_ID_FORMAT.format(dev_id)
device = device_tracker.Device(
self.hass, timedelta(seconds=180), True, dev_id, None,
away_hide=True)
hide_if_away=True)
device_tracker.update_config(self.yaml_devices, dev_id, device)
scanner = get_component('device_tracker.test').SCANNER

View file

@ -200,17 +200,18 @@ def test_time_period():
schema = vol.Schema(cv.time_period)
for value in (
None, '', 1234, 'hello:world', '12:', '12:34:56:78',
None, '', 'hello:world', '12:', '12:34:56:78',
{}, {'wrong_key': -10}
):
with pytest.raises(vol.MultipleInvalid):
schema(value)
for value in (
'8:20', '23:59', '-8:20', '-23:59:59', '-48:00', {'minutes': 5}
'8:20', '23:59', '-8:20', '-23:59:59', '-48:00', {'minutes': 5}, 1, '5'
):
schema(value)
assert timedelta(seconds=180) == schema('180')
assert timedelta(hours=23, minutes=59) == schema('23:59')
assert -1 * timedelta(hours=1, minutes=15) == schema('-1:15')