def test_load_yaml_config_raises_error_if_malformed_yaml(self): """Test error raised if invalid YAML.""" with open(YAML_PATH, 'w') as f: f.write(':') with self.assertRaises(BluMateError): config_util.load_yaml_config_file(YAML_PATH)
def test_load_yaml_config_raises_error_if_not_dict(self): """Test error raised when YAML file is not a dict.""" with open(YAML_PATH, 'w') as f: f.write('5') with self.assertRaises(BluMateError): config_util.load_yaml_config_file(YAML_PATH)
def test_load_yaml_config_raises_error_if_unsafe_yaml(self): """Test error raised if unsafe YAML.""" with open(YAML_PATH, 'w') as f: f.write('hello: !!python/object/apply:os.system') with self.assertRaises(BluMateError): config_util.load_yaml_config_file(YAML_PATH)
def setup(bmss, config): """Track states and offer events for sensors.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, bmss, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) def alarm_service_handler(service): """Map services to methods on Alarm.""" target_alarms = component.extract_from_service(service) code = service.data.get(ATTR_CODE) method = SERVICE_TO_METHOD[service.service] for alarm in target_alarms: getattr(alarm, method)(code) if alarm.should_poll: alarm.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) for service in SERVICE_TO_METHOD: bmss.services.register(DOMAIN, service, alarm_service_handler, descriptions.get(service), schema=ALARM_SERVICE_SCHEMA) return True
def setup(bmss, config): """Track states and offer events for sensors.""" component = EntityComponent(logging.getLogger(__name__), DOMAIN, bmss, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) def alarm_service_handler(service): """Map services to methods on Alarm.""" target_alarms = component.extract_from_service(service) code = service.data.get(ATTR_CODE) method = SERVICE_TO_METHOD[service.service] for alarm in target_alarms: getattr(alarm, method)(code) if alarm.should_poll: alarm.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) for service in SERVICE_TO_METHOD: bmss.services.register(DOMAIN, service, alarm_service_handler, descriptions.get(service), schema=ALARM_SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for garage door.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_GARAGE_DOORS) component.setup(config) def handle_garage_door_service(service): """Handle calls to the garage door services.""" target_locks = component.extract_from_service(service) for item in target_locks: if service.service == SERVICE_CLOSE: item.close_door() else: item.open_door() if item.should_poll: item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_OPEN, handle_garage_door_service, descriptions.get(SERVICE_OPEN), schema=GARAGE_DOOR_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_CLOSE, handle_garage_door_service, descriptions.get(SERVICE_CLOSE), schema=GARAGE_DOOR_SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for locks.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_LOCKS) component.setup(config) def handle_lock_service(service): """Handle calls to the lock services.""" target_locks = component.extract_from_service(service) code = service.data.get(ATTR_CODE) for item in target_locks: if service.service == SERVICE_LOCK: item.lock(code=code) else: item.unlock(code=code) if item.should_poll: item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_UNLOCK, handle_lock_service, descriptions.get(SERVICE_UNLOCK), schema=LOCK_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_LOCK, handle_lock_service, descriptions.get(SERVICE_LOCK), schema=LOCK_SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for locks.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_LOCKS) component.setup(config) def handle_lock_service(service): """Handle calls to the lock services.""" target_locks = component.extract_from_service(service) code = service.data.get(ATTR_CODE) for item in target_locks: if service.service == SERVICE_LOCK: item.lock(code=code) else: item.unlock(code=code) if item.should_poll: item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_UNLOCK, handle_lock_service, descriptions.get(SERVICE_UNLOCK), schema=LOCK_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_LOCK, handle_lock_service, descriptions.get(SERVICE_LOCK), schema=LOCK_SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for switches.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_SWITCHES) component.setup(config) def handle_switch_service(service): """Handle calls to the switch services.""" target_switches = component.extract_from_service(service) for switch in target_switches: if service.service == SERVICE_TURN_ON: switch.turn_on() elif service.service == SERVICE_TOGGLE: switch.toggle() else: switch.turn_off() if switch.should_poll: switch.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_switch_service, descriptions.get(SERVICE_TURN_OFF), schema=SWITCH_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service, descriptions.get(SERVICE_TURN_ON), schema=SWITCH_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_switch_service, descriptions.get(SERVICE_TOGGLE), schema=SWITCH_SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for garage door.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_GARAGE_DOORS) component.setup(config) def handle_garage_door_service(service): """Handle calls to the garage door services.""" target_locks = component.extract_from_service(service) for item in target_locks: if service.service == SERVICE_CLOSE: item.close_door() else: item.open_door() if item.should_poll: item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_OPEN, handle_garage_door_service, descriptions.get(SERVICE_OPEN), schema=GARAGE_DOOR_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_CLOSE, handle_garage_door_service, descriptions.get(SERVICE_CLOSE), schema=GARAGE_DOOR_SERVICE_SCHEMA) return True
def test_load_yaml_config_preserves_key_order(self): """Test removal of library.""" with open(YAML_PATH, 'w') as f: f.write('hello: 0\n') f.write('world: 1\n') self.assertEqual( [('hello', 0), ('world', 1)], list(config_util.load_yaml_config_file(YAML_PATH).items()))
def load_config(path, hass, consider_home, home_range): """Load devices from YAML configuration file.""" if not os.path.isfile(path): return [] return [ Device(hass, consider_home, home_range, device.get('track', False), str(dev_id).lower(), str(device.get('mac')).upper(), device.get('name'), device.get('picture'), device.get(CONF_AWAY_HIDE, DEFAULT_AWAY_HIDE)) for dev_id, device in load_yaml_config_file(path).items()]
def load_config(path, hass, consider_home, home_range): """Load devices from YAML configuration file.""" if not os.path.isfile(path): return [] return [ Device(hass, consider_home, home_range, device.get('track', False), str(dev_id).lower(), str(device.get('mac')).upper(), device.get('name'), device.get('picture'), device.get(CONF_AWAY_HIDE, DEFAULT_AWAY_HIDE)) for dev_id, device in load_yaml_config_file(path).items() ]
def setup(hass, config): """Setup the notify services.""" success = False descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) for platform, p_config in config_per_platform(config, DOMAIN): notify_implementation = bootstrap.prepare_setup_platform( hass, config, DOMAIN, platform) if notify_implementation is None: _LOGGER.error("Unknown notification service specified.") continue notify_service = notify_implementation.get_service(hass, p_config) if notify_service is None: _LOGGER.error("Failed to initialize notification service %s", platform) continue def notify_message(notify_service, call): """Handle sending notification message service calls.""" message = call.data[ATTR_MESSAGE] title = template.render( hass, call.data.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)) target = call.data.get(ATTR_TARGET) message = template.render(hass, message) data = call.data.get(ATTR_DATA) notify_service.send_message(message, title=title, target=target, data=data) service_call_handler = partial(notify_message, notify_service) service_notify = p_config.get(CONF_NAME, SERVICE_NOTIFY) hass.services.register(DOMAIN, service_notify, service_call_handler, descriptions.get(SERVICE_NOTIFY), schema=NOTIFY_SERVICE_SCHEMA) success = True return success
def test_create_default_config_detect_location(self, mock_print): """Test that detect location sets the correct config keys.""" config_util.ensure_config_exists(CONFIG_DIR) config = config_util.load_yaml_config_file(YAML_PATH) self.assertIn(DOMAIN, config) ha_conf = config[DOMAIN] expected_values = { CONF_LATITUDE: 2.0, CONF_LONGITUDE: 1.0, CONF_TEMPERATURE_UNIT: 'F', CONF_NAME: 'Home', CONF_TIME_ZONE: 'America/Los_Angeles' } self.assertEqual(expected_values, ha_conf) self.assertTrue(mock_print.called)
def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Ecobee Thermostat Platform.""" if discovery_info is None: return data = ecobee.NETWORK hold_temp = discovery_info['hold_temp'] _LOGGER.info( "Loading ecobee thermostat component with hold_temp set to %s", hold_temp) devices = [ Thermostat(data, index, hold_temp) for index in range(len(data.ecobee.thermostats)) ] add_devices(devices) def fan_min_on_time_set_service(service): """Set the minimum fan on time on the target thermostats.""" entity_id = service.data.get('entity_id') if entity_id: target_thermostats = [ device for device in devices if device.entity_id == entity_id ] else: target_thermostats = devices fan_min_on_time = service.data[ATTR_FAN_MIN_ON_TIME] for thermostat in target_thermostats: thermostat.set_fan_min_on_time(str(fan_min_on_time)) thermostat.update_ha_state(True) descriptions = load_yaml_config_file( path.join(path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_SET_FAN_MIN_ON_TIME, fan_min_on_time_set_service, descriptions.get(SERVICE_SET_FAN_MIN_ON_TIME), schema=SET_FAN_MIN_ON_TIME_SCHEMA)
def setup(hass, config): """Track states and offer events for roller shutters.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_ROLLERSHUTTERS) component.setup(config) def handle_rollershutter_service(service): """Handle calls to the roller shutter services.""" target_rollershutters = component.extract_from_service(service) for rollershutter in target_rollershutters: if service.service == SERVICE_MOVE_UP: rollershutter.move_up() elif service.service == SERVICE_MOVE_DOWN: rollershutter.move_down() elif service.service == SERVICE_STOP: rollershutter.stop() if rollershutter.should_poll: rollershutter.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_MOVE_UP, handle_rollershutter_service, descriptions.get(SERVICE_MOVE_UP), schema=ROLLERSHUTTER_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_MOVE_DOWN, handle_rollershutter_service, descriptions.get(SERVICE_MOVE_DOWN), schema=ROLLERSHUTTER_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_STOP, handle_rollershutter_service, descriptions.get(SERVICE_STOP), schema=ROLLERSHUTTER_SERVICE_SCHEMA) return True
def from_config_file(config_path, hass=None, verbose=False, skip_pip=True, log_rotate_days=None): """Read the configuration file and try to start all the functionality. Will add functionality to 'hass' parameter if given, instantiates a new BluMate object if 'hass' is not given. """ if hass is None: hass = core.BluMate() # Set config dir to directory holding config file config_dir = os.path.abspath(os.path.dirname(config_path)) hass.config.config_dir = config_dir mount_local_lib_path(config_dir) enable_logging(hass, verbose, log_rotate_days) try: config_dict = config_util.load_yaml_config_file(config_path) except BluMateError: return None return from_config_dict(config_dict, hass, enable_log=False, skip_pip=skip_pip)
def setup(hass, config): """Track states and offer events for media_players.""" component = EntityComponent(logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def media_player_service_handler(service): """Map services to methods on MediaPlayerDevice.""" method = SERVICE_TO_METHOD[service.service] for player in component.extract_from_service(service): getattr(player, method)() if player.should_poll: player.update_ha_state(True) for service in SERVICE_TO_METHOD: hass.services.register(DOMAIN, service, media_player_service_handler, descriptions.get(service), schema=MEDIA_PLAYER_SCHEMA) def volume_set_service(service): """Set specified volume on the media player.""" volume = service.data.get(ATTR_MEDIA_VOLUME_LEVEL) for player in component.extract_from_service(service): player.set_volume_level(volume) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service, descriptions.get(SERVICE_VOLUME_SET), schema=MEDIA_PLAYER_SET_VOLUME_SCHEMA) def volume_mute_service(service): """Mute (true) or unmute (false) the media player.""" mute = service.data.get(ATTR_MEDIA_VOLUME_MUTED) for player in component.extract_from_service(service): player.mute_volume(mute) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service, descriptions.get(SERVICE_VOLUME_MUTE), schema=MEDIA_PLAYER_MUTE_VOLUME_SCHEMA) def media_seek_service(service): """Seek to a position.""" position = service.data.get(ATTR_MEDIA_SEEK_POSITION) for player in component.extract_from_service(service): player.media_seek(position) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service, descriptions.get(SERVICE_MEDIA_SEEK), schema=MEDIA_PLAYER_MEDIA_SEEK_SCHEMA) def select_source_service(service): """Change input to selected source.""" input_source = service.data.get(ATTR_INPUT_SOURCE) for player in component.extract_from_service(service): player.select_source(input_source) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE, select_source_service, descriptions.get(SERVICE_SELECT_SOURCE), schema=MEDIA_PLAYER_SELECT_SOURCE_SCHEMA) def play_media_service(service): """Play specified media_id on the media player.""" media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE) media_id = service.data.get(ATTR_MEDIA_CONTENT_ID) enqueue = service.data.get(ATTR_MEDIA_ENQUEUE) kwargs = { ATTR_MEDIA_ENQUEUE: enqueue, } for player in component.extract_from_service(service): player.play_media(media_type, media_id, **kwargs) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, play_media_service, descriptions.get(SERVICE_PLAY_MEDIA), schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA) return True
def setup(hass, config): """Setup thermostats.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def away_mode_set_service(service): """Set away mode on target thermostats.""" target_thermostats = component.extract_from_service(service) away_mode = service.data[ATTR_AWAY_MODE] for thermostat in target_thermostats: if away_mode: thermostat.turn_away_mode_on() else: thermostat.turn_away_mode_off() thermostat.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, descriptions.get(SERVICE_SET_AWAY_MODE), schema=SET_AWAY_MODE_SCHEMA) def temperature_set_service(service): """Set temperature on the target thermostats.""" target_thermostats = component.extract_from_service(service) temperature = service.data[ATTR_TEMPERATURE] for thermostat in target_thermostats: thermostat.set_temperature(convert( temperature, hass.config.temperature_unit, thermostat.unit_of_measurement)) thermostat.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, descriptions.get(SERVICE_SET_TEMPERATURE), schema=SET_TEMPERATURE_SCHEMA) def fan_mode_set_service(service): """Set fan mode on target thermostats.""" target_thermostats = component.extract_from_service(service) fan_mode = service.data[ATTR_FAN] for thermostat in target_thermostats: if fan_mode: thermostat.turn_fan_on() else: thermostat.turn_fan_off() thermostat.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, descriptions.get(SERVICE_SET_FAN_MODE), schema=SET_FAN_MODE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for media_players.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def media_player_service_handler(service): """Map services to methods on MediaPlayerDevice.""" method = SERVICE_TO_METHOD[service.service] for player in component.extract_from_service(service): getattr(player, method)() if player.should_poll: player.update_ha_state(True) for service in SERVICE_TO_METHOD: hass.services.register(DOMAIN, service, media_player_service_handler, descriptions.get(service), schema=MEDIA_PLAYER_SCHEMA) def volume_set_service(service): """Set specified volume on the media player.""" volume = service.data.get(ATTR_MEDIA_VOLUME_LEVEL) for player in component.extract_from_service(service): player.set_volume_level(volume) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service, descriptions.get(SERVICE_VOLUME_SET), schema=MEDIA_PLAYER_SET_VOLUME_SCHEMA) def volume_mute_service(service): """Mute (true) or unmute (false) the media player.""" mute = service.data.get(ATTR_MEDIA_VOLUME_MUTED) for player in component.extract_from_service(service): player.mute_volume(mute) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service, descriptions.get(SERVICE_VOLUME_MUTE), schema=MEDIA_PLAYER_MUTE_VOLUME_SCHEMA) def media_seek_service(service): """Seek to a position.""" position = service.data.get(ATTR_MEDIA_SEEK_POSITION) for player in component.extract_from_service(service): player.media_seek(position) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service, descriptions.get(SERVICE_MEDIA_SEEK), schema=MEDIA_PLAYER_MEDIA_SEEK_SCHEMA) def select_source_service(service): """Change input to selected source.""" input_source = service.data.get(ATTR_INPUT_SOURCE) for player in component.extract_from_service(service): player.select_source(input_source) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE, select_source_service, descriptions.get(SERVICE_SELECT_SOURCE), schema=MEDIA_PLAYER_SELECT_SOURCE_SCHEMA) def play_media_service(service): """Play specified media_id on the media player.""" media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE) media_id = service.data.get(ATTR_MEDIA_CONTENT_ID) enqueue = service.data.get(ATTR_MEDIA_ENQUEUE) kwargs = { ATTR_MEDIA_ENQUEUE: enqueue, } for player in component.extract_from_service(service): player.play_media(media_type, media_id, **kwargs) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, play_media_service, descriptions.get(SERVICE_PLAY_MEDIA), schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA) return True
def setup(hass, config): """Setup thermostats.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def away_mode_set_service(service): """Set away mode on target thermostats.""" target_thermostats = component.extract_from_service(service) away_mode = service.data[ATTR_AWAY_MODE] for thermostat in target_thermostats: if away_mode: thermostat.turn_away_mode_on() else: thermostat.turn_away_mode_off() thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, descriptions.get(SERVICE_SET_AWAY_MODE), schema=SET_AWAY_MODE_SCHEMA) def temperature_set_service(service): """Set temperature on the target thermostats.""" target_thermostats = component.extract_from_service(service) temperature = service.data[ATTR_TEMPERATURE] for thermostat in target_thermostats: thermostat.set_temperature( convert(temperature, hass.config.temperature_unit, thermostat.unit_of_measurement)) thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, descriptions.get(SERVICE_SET_TEMPERATURE), schema=SET_TEMPERATURE_SCHEMA) def fan_mode_set_service(service): """Set fan mode on target thermostats.""" target_thermostats = component.extract_from_service(service) fan_mode = service.data[ATTR_FAN] for thermostat in target_thermostats: if fan_mode: thermostat.turn_fan_on() else: thermostat.turn_fan_off() thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, descriptions.get(SERVICE_SET_FAN_MODE), schema=SET_FAN_MODE_SCHEMA) return True
def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Sonos platform.""" import soco if discovery_info: player = soco.SoCo(discovery_info) if player.is_visible: add_devices([SonosDevice(hass, player)]) return True return False players = None hosts = config.get('hosts', None) if hosts: # Support retro compatibility with comma separated list of hosts # from config hosts = hosts.split(',') if isinstance(hosts, str) else hosts players = [] for host in hosts: players.append(soco.SoCo(socket.gethostbyname(host))) if not players: players = soco.discover( interface_addr=config.get('interface_addr', None)) if not players: _LOGGER.warning('No Sonos speakers found.') return False devices = [SonosDevice(hass, p) for p in players] add_devices(devices) _LOGGER.info('Added %s Sonos speakers', len(players)) def group_players_service(service): """Group media players, use player as coordinator.""" entity_id = service.data.get('entity_id') if entity_id: _devices = [ device for device in devices if device.entity_id == entity_id ] else: _devices = devices for device in _devices: device.group_players() device.update_ha_state(True) def snapshot(service): """Take a snapshot.""" entity_id = service.data.get('entity_id') if entity_id: _devices = [ device for device in devices if device.entity_id == entity_id ] else: _devices = devices for device in _devices: device.snapshot(service) device.update_ha_state(True) def restore(service): """Restore a snapshot.""" entity_id = service.data.get('entity_id') if entity_id: _devices = [ device for device in devices if device.entity_id == entity_id ] else: _devices = devices for device in _devices: device.restore(service) device.update_ha_state(True) descriptions = load_yaml_config_file( path.join(path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_GROUP_PLAYERS, group_players_service, descriptions.get(SERVICE_GROUP_PLAYERS)) hass.services.register(DOMAIN, SERVICE_SNAPSHOT, snapshot, descriptions.get(SERVICE_SNAPSHOT)) hass.services.register(DOMAIN, SERVICE_RESTORE, restore, descriptions.get(SERVICE_RESTORE)) return True
def setup(hass, config): """Expose light control via statemachine and services.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_LIGHTS) component.setup(config) # Load built-in profiles and custom profiles profile_paths = [os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE), hass.config.path(LIGHT_PROFILES_FILE)] profiles = {} for profile_path in profile_paths: if not os.path.isfile(profile_path): continue with open(profile_path) as inp: reader = csv.reader(inp) # Skip the header next(reader, None) try: for rec in reader: profile, color_x, color_y, brightness = PROFILE_SCHEMA(rec) profiles[profile] = (color_x, color_y, brightness) except vol.MultipleInvalid as ex: _LOGGER.error("Error parsing light profile from %s: %s", profile_path, ex) return False def handle_light_service(service): """Hande a turn light on or off service call.""" # Get the validated data params = service.data.copy() # Convert the entity ids to valid light ids target_lights = component.extract_from_service(service) params.pop(ATTR_ENTITY_ID, None) service_fun = None if service.service == SERVICE_TURN_OFF: service_fun = 'turn_off' elif service.service == SERVICE_TOGGLE: service_fun = 'toggle' if service_fun: for light in target_lights: getattr(light, service_fun)(**params) for light in target_lights: if light.should_poll: light.update_ha_state(True) return # Processing extra data for turn light on request. profile = profiles.get(params.pop(ATTR_PROFILE, None)) if profile: params.setdefault(ATTR_XY_COLOR, profile[:2]) params.setdefault(ATTR_BRIGHTNESS, profile[2]) color_name = params.pop(ATTR_COLOR_NAME, None) if color_name is not None: params[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name) for light in target_lights: light.turn_on(**params) for light in target_lights: if light.should_poll: light.update_ha_state(True) # Listen for light on and light off service calls. descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_light_service, descriptions.get(SERVICE_TURN_ON), schema=LIGHT_TURN_ON_SCHEMA) hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_light_service, descriptions.get(SERVICE_TURN_OFF), schema=LIGHT_TURN_OFF_SCHEMA) hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_light_service, descriptions.get(SERVICE_TOGGLE), schema=LIGHT_TOGGLE_SCHEMA) return True
def setup(hass, config): """Start the MQTT protocol service.""" # pylint: disable=too-many-locals conf = config.get(DOMAIN, {}) client_id = conf.get(CONF_CLIENT_ID) keepalive = conf.get(CONF_KEEPALIVE) broker_config = _setup_server(hass, config) broker_in_conf = True if CONF_BROKER in conf else False # Only auto config if no server config was passed in if broker_config and CONF_EMBEDDED not in conf: broker, port, username, password, certificate, protocol = broker_config # Embedded broker doesn't have some ssl variables client_key, client_cert, tls_insecure = None, None, None elif not broker_config and CONF_BROKER not in conf: _LOGGER.error('Unable to start broker and auto-configure MQTT.') return False if broker_in_conf: broker = conf[CONF_BROKER] port = conf[CONF_PORT] username = conf.get(CONF_USERNAME) password = conf.get(CONF_PASSWORD) certificate = conf.get(CONF_CERTIFICATE) client_key = conf.get(CONF_CLIENT_KEY) client_cert = conf.get(CONF_CLIENT_CERT) tls_insecure = conf.get(CONF_TLS_INSECURE) protocol = conf[CONF_PROTOCOL] # For cloudmqtt.com, secured connection, auto fill in certificate if certificate is None and 19999 < port < 30000 and \ broker.endswith('.cloudmqtt.com'): certificate = os.path.join(os.path.dirname(__file__), 'addtrustexternalcaroot.crt') global MQTT_CLIENT try: MQTT_CLIENT = MQTT(hass, broker, port, client_id, keepalive, username, password, certificate, client_key, client_cert, tls_insecure, protocol) except socket.error: _LOGGER.exception("Can't connect to the broker. " "Please check your settings and the broker " "itself.") return False def stop_mqtt(event): """Stop MQTT component.""" MQTT_CLIENT.stop() def start_mqtt(event): """Launch MQTT component when Home Assistant starts up.""" MQTT_CLIENT.start() hass.bus.listen_once(EVENT_BLUMATE_STOP, stop_mqtt) def publish_service(call): """Handle MQTT publish service calls.""" msg_topic = call.data[ATTR_TOPIC] payload = call.data.get(ATTR_PAYLOAD) payload_template = call.data.get(ATTR_PAYLOAD_TEMPLATE) qos = call.data[ATTR_QOS] retain = call.data[ATTR_RETAIN] try: payload = (payload if payload_template is None else template.render(hass, payload_template)) or '' except template.jinja2.TemplateError as exc: _LOGGER.error( "Unable to publish to '%s': rendering payload template of " "'%s' failed because %s.", msg_topic, payload_template, exc) return MQTT_CLIENT.publish(msg_topic, payload, qos, retain) hass.bus.listen_once(EVENT_BLUMATE_START, start_mqtt) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_PUBLISH, publish_service, descriptions.get(SERVICE_PUBLISH), schema=MQTT_PUBLISH_SCHEMA) return True
def test_load_yaml_config_converts_empty_files_to_dict(self): """Test that loading an empty file returns an empty dict.""" create_file(YAML_PATH) self.assertIsInstance(config_util.load_yaml_config_file(YAML_PATH), dict)
def setup(hass, config): """Setup hvacs.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def away_mode_set_service(service): """Set away mode on target hvacs.""" target_hvacs = component.extract_from_service(service) away_mode = service.data.get(ATTR_AWAY_MODE) if away_mode is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_AWAY_MODE, ATTR_AWAY_MODE) return for hvac in target_hvacs: if away_mode: hvac.turn_away_mode_on() else: hvac.turn_away_mode_off() if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, descriptions.get(SERVICE_SET_AWAY_MODE)) def aux_heat_set_service(service): """Set auxillary heater on target hvacs.""" target_hvacs = component.extract_from_service(service) aux_heat = service.data.get(ATTR_AUX_HEAT) if aux_heat is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_AUX_HEAT, ATTR_AUX_HEAT) return for hvac in target_hvacs: if aux_heat: hvac.turn_aux_heat_on() else: hvac.turn_aux_heat_off() if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_AUX_HEAT, aux_heat_set_service, descriptions.get(SERVICE_SET_AUX_HEAT)) def temperature_set_service(service): """Set temperature on the target hvacs.""" target_hvacs = component.extract_from_service(service) temperature = util.convert( service.data.get(ATTR_TEMPERATURE), float) if temperature is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_TEMPERATURE, ATTR_TEMPERATURE) return for hvac in target_hvacs: hvac.set_temperature(convert( temperature, hass.config.temperature_unit, hvac.unit_of_measurement)) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, descriptions.get(SERVICE_SET_TEMPERATURE)) def humidity_set_service(service): """Set humidity on the target hvacs.""" target_hvacs = component.extract_from_service(service) humidity = service.data.get(ATTR_HUMIDITY) if humidity is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_HUMIDITY, ATTR_HUMIDITY) return for hvac in target_hvacs: hvac.set_humidity(humidity) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_HUMIDITY, humidity_set_service, descriptions.get(SERVICE_SET_HUMIDITY)) def fan_mode_set_service(service): """Set fan mode on target hvacs.""" target_hvacs = component.extract_from_service(service) fan = service.data.get(ATTR_FAN_MODE) if fan is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_FAN_MODE, ATTR_FAN_MODE) return for hvac in target_hvacs: hvac.set_fan_mode(fan) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, descriptions.get(SERVICE_SET_FAN_MODE)) def operation_set_service(service): """Set operating mode on the target hvacs.""" target_hvacs = component.extract_from_service(service) operation_mode = service.data.get(ATTR_OPERATION_MODE) if operation_mode is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_OPERATION_MODE, ATTR_OPERATION_MODE) return for hvac in target_hvacs: hvac.set_operation_mode(operation_mode) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_OPERATION_MODE, operation_set_service, descriptions.get(SERVICE_SET_OPERATION_MODE)) def swing_set_service(service): """Set swing mode on the target hvacs.""" target_hvacs = component.extract_from_service(service) swing_mode = service.data.get(ATTR_SWING_MODE) if swing_mode is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_SWING_MODE, ATTR_SWING_MODE) return for hvac in target_hvacs: hvac.set_swing_mode(swing_mode) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_SWING_MODE, swing_set_service, descriptions.get(SERVICE_SET_SWING_MODE)) return True
def setup(hass, config): """Setup device tracker.""" yaml_path = hass.config.path(YAML_DEVICES) conf = config.get(DOMAIN, {}) if isinstance(conf, list) and len(conf) > 0: conf = conf[0] consider_home = timedelta( seconds=util.convert(conf.get(CONF_CONSIDER_HOME), int, DEFAULT_CONSIDER_HOME)) track_new = util.convert(conf.get(CONF_TRACK_NEW), bool, DEFAULT_CONF_TRACK_NEW) home_range = util.convert(conf.get(CONF_HOME_RANGE), int, DEFAULT_HOME_RANGE) devices = load_config(yaml_path, hass, consider_home, home_range) tracker = DeviceTracker(hass, consider_home, track_new, home_range, devices) def setup_platform(p_type, p_config, disc_info=None): """Setup a device tracker platform.""" platform = prepare_setup_platform(hass, config, DOMAIN, p_type) if platform is None: return try: if hasattr(platform, 'get_scanner'): scanner = platform.get_scanner(hass, {DOMAIN: p_config}) if scanner is None: _LOGGER.error('Error setting up platform %s', p_type) return setup_scanner_platform(hass, p_config, scanner, tracker.see) return if not platform.setup_scanner(hass, p_config, tracker.see): _LOGGER.error('Error setting up platform %s', p_type) except Exception: # pylint: disable=broad-except _LOGGER.exception('Error setting up platform %s', p_type) for p_type, p_config in config_per_platform(config, DOMAIN): setup_platform(p_type, p_config) def device_tracker_discovered(service, info): """Called when a device tracker platform is discovered.""" setup_platform(DISCOVERY_PLATFORMS[service], {}, info) discovery.listen(hass, DISCOVERY_PLATFORMS.keys(), device_tracker_discovered) def update_stale(now): """Clean up stale devices.""" tracker.update_stale(now) track_utc_time_change(hass, update_stale, second=range(0, 60, 5)) tracker.setup_group() def see_service(call): """Service to see a device.""" args = {key: value for key, value in call.data.items() if key in (ATTR_MAC, ATTR_DEV_ID, ATTR_HOST_NAME, ATTR_LOCATION_NAME, ATTR_GPS, ATTR_GPS_ACCURACY, ATTR_BATTERY)} tracker.see(**args) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_SEE, see_service, descriptions.get(SERVICE_SEE)) return True
def setup(hass, config): """Setup device tracker.""" yaml_path = hass.config.path(YAML_DEVICES) conf = config.get(DOMAIN, {}) if isinstance(conf, list) and len(conf) > 0: conf = conf[0] consider_home = timedelta(seconds=util.convert( conf.get(CONF_CONSIDER_HOME), int, DEFAULT_CONSIDER_HOME)) track_new = util.convert(conf.get(CONF_TRACK_NEW), bool, DEFAULT_CONF_TRACK_NEW) home_range = util.convert(conf.get(CONF_HOME_RANGE), int, DEFAULT_HOME_RANGE) devices = load_config(yaml_path, hass, consider_home, home_range) tracker = DeviceTracker(hass, consider_home, track_new, home_range, devices) def setup_platform(p_type, p_config, disc_info=None): """Setup a device tracker platform.""" platform = prepare_setup_platform(hass, config, DOMAIN, p_type) if platform is None: return try: if hasattr(platform, 'get_scanner'): scanner = platform.get_scanner(hass, {DOMAIN: p_config}) if scanner is None: _LOGGER.error('Error setting up platform %s', p_type) return setup_scanner_platform(hass, p_config, scanner, tracker.see) return if not platform.setup_scanner(hass, p_config, tracker.see): _LOGGER.error('Error setting up platform %s', p_type) except Exception: # pylint: disable=broad-except _LOGGER.exception('Error setting up platform %s', p_type) for p_type, p_config in config_per_platform(config, DOMAIN): setup_platform(p_type, p_config) def device_tracker_discovered(service, info): """Called when a device tracker platform is discovered.""" setup_platform(DISCOVERY_PLATFORMS[service], {}, info) discovery.listen(hass, DISCOVERY_PLATFORMS.keys(), device_tracker_discovered) def update_stale(now): """Clean up stale devices.""" tracker.update_stale(now) track_utc_time_change(hass, update_stale, second=range(0, 60, 5)) tracker.setup_group() def see_service(call): """Service to see a device.""" args = { key: value for key, value in call.data.items() if key in (ATTR_MAC, ATTR_DEV_ID, ATTR_HOST_NAME, ATTR_LOCATION_NAME, ATTR_GPS, ATTR_GPS_ACCURACY, ATTR_BATTERY) } tracker.see(**args) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_SEE, see_service, descriptions.get(SERVICE_SEE)) return True
def test_load_yaml_config_converts_empty_files_to_dict(self): """Test that loading an empty file returns an empty dict.""" create_file(YAML_PATH) self.assertIsInstance( config_util.load_yaml_config_file(YAML_PATH), dict)