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:
parent
b09b13f552
commit
fb94aaa5a1
4 changed files with 53 additions and 31 deletions
|
@ -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 []
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue