def _get_location_from_entity(self, entity_id): """Get the location from the entity_id.""" state = self.hass.states.get(entity_id) if state is None: _LOGGER.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes (zone) if location.has_location(state): return _get_location_from_attributes(state) # Check if device is in a zone (device_tracker) zone_state = self.hass.states.get('zone.{}'.format(state.state)) if location.has_location(zone_state): _LOGGER.debug( "%s is in %s, getting zone location", entity_id, zone_state.entity_id ) return _get_location_from_attributes(zone_state) # If zone was not found in state then use the state as the location if entity_id.startswith('sensor.'): return state.state # When everything fails just return nothing return None
def zone_automation_listener(entity, from_s, to_s): """Listen for state changes and calls action.""" if from_s and not location.has_location(from_s) or \ not location.has_location(to_s): return zone_state = hass.states.get(zone_entity_id) if from_s: from_match = condition.zone(hass, zone_state, from_s) else: from_match = False to_match = condition.zone(hass, zone_state, to_s) # pylint: disable=too-many-boolean-expressions if event == EVENT_ENTER and not from_match and to_match or \ event == EVENT_LEAVE and from_match and not to_match: hass.async_add_job(action, { 'trigger': { 'platform': 'zone', 'entity_id': entity, 'from_state': from_s, 'to_state': to_s, 'zone': zone_state, 'event': event, }, })
def _get_location_from_entity(self, entity_id): """Get the location from the entity_id.""" state = self.hass.states.get(entity_id) if state is None: _LOGGER.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes. if location.has_location(state): _LOGGER.debug("Getting %s location", entity_id) return _get_location_from_attributes(state) # Check if device is inside a zone. zone_state = self.hass.states.get(f"zone.{state.state}") if location.has_location(zone_state): _LOGGER.debug("%s is in %s, getting zone location", entity_id, zone_state.entity_id) return _get_location_from_attributes(zone_state) # If zone was not found in state then use the state as the location. if entity_id.startswith("sensor."): return state.state # When everything fails just return nothing. return None
def zone_automation_listener(entity, from_s, to_s): """Listen for state changes and calls action.""" if from_s and not location.has_location(from_s) or not location.has_location(to_s): return zone_state = hass.states.get(zone_entity_id) if from_s: from_match = condition.zone(hass, zone_state, from_s) else: from_match = False to_match = condition.zone(hass, zone_state, to_s) # pylint: disable=too-many-boolean-expressions if event == EVENT_ENTER and not from_match and to_match or event == EVENT_LEAVE and from_match and not to_match: action( { "trigger": { "platform": "zone", "entity_id": entity, "from_state": from_s, "to_state": to_s, "zone": zone_state, "event": event, } } )
def _get_location_from_entity(self, entity_id): """Get the location from the entity_id.""" state = self.hass.states.get(entity_id) if state is None: _LOGGER.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes (zone) if location.has_location(state): return _get_location_from_attributes(state) # Check if device is in a zone (device_tracker) zone_state = self.hass.states.get('zone.{}'.format(state.state)) if location.has_location(zone_state): _LOGGER.debug("%s is in %s, getting zone location", entity_id, zone_state.entity_id) return _get_location_from_attributes(zone_state) # If zone was not found in state then use the state as the location if entity_id.startswith('sensor.'): return state.state # When everything fails just return nothing return None
def _get_location_from_entity(self, entity_id): """Get the location from the entity state or attributes.""" entity = self._hass.states.get(entity_id) if entity is None: _LOGGER.error("Unable to find entity %s", entity_id) self.valid_api_connection = False return None # Check if the entity has location attributes if location.has_location(entity): return self._get_location_from_attributes(entity) # Check if device is in a zone zone_entity = self._hass.states.get("zone.%s" % entity.state) if location.has_location(zone_entity): _LOGGER.debug( "%s is in %s, getting zone location", entity_id, zone_entity.entity_id ) return self._get_location_from_attributes(zone_entity) # If zone was not found in state then use the state as the location if entity_id.startswith("sensor."): return entity.state # When everything fails just return nothing return None
def zone_automation_listener(zone_event): """Listen for state changes and calls action.""" entity = zone_event.data.get("entity_id") from_s = zone_event.data.get("old_state") to_s = zone_event.data.get("new_state") if (from_s and not location.has_location(from_s) or not location.has_location(to_s)): return zone_state = hass.states.get(zone_entity_id) from_match = condition.zone(hass, zone_state, from_s) if from_s else False to_match = condition.zone(hass, zone_state, to_s) if to_s else False if (event == EVENT_ENTER and not from_match and to_match or event == EVENT_LEAVE and from_match and not to_match): description = f"{entity} {_EVENT_DESCRIPTION[event]} {zone_state.attributes[ATTR_FRIENDLY_NAME]}" hass.async_run_hass_job( job, { "trigger": { **trigger_data, "platform": platform_type, "entity_id": entity, "from_state": from_s, "to_state": to_s, "zone": zone_state, "event": event, "description": description, } }, to_s.context, )
def get_location_from_entity(hass, logger, entity_id): """Get the location from the entity state or attributes.""" entity = hass.states.get(entity_id) if entity is None: logger.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes if location.has_location(entity): return get_location_from_attributes(entity) # Check if device is in a zone zone_entity = hass.states.get(f"zone.{entity.state}") if location.has_location(zone_entity): logger.debug("%s is in %s, getting zone location", entity_id, zone_entity.entity_id) return get_location_from_attributes(zone_entity) # If zone was not found in state then use the state as the location if entity_id.startswith("sensor."): return entity.state # When everything fails just return nothing return None
def zone_automation_listener(entity, from_s, to_s): """Listen for state changes and calls action.""" if (from_s and not location.has_location(from_s) or not location.has_location(to_s)): return zone_state = hass.states.get(zone_entity_id) if from_s: from_match = condition.zone(hass, zone_state, from_s) else: from_match = False to_match = condition.zone(hass, zone_state, to_s) # pylint: disable=too-many-boolean-expressions if (event == EVENT_ENTER and not from_match and to_match or event == EVENT_LEAVE and from_match and not to_match): hass.async_run_job( action( { "trigger": { "platform": "zone", "entity_id": entity, "from_state": from_s, "to_state": to_s, "zone": zone_state, "event": event, } }, context=to_s.context, ))
async def _get_location_from_entity(self, entity_id: str) -> str | None: """Get the location from the entity state or attributes.""" entity = self.hass.states.get(entity_id) if entity is None: _LOGGER.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes if location.has_location(entity): return self._get_location_from_attributes(entity) # Check if device is in a zone zone_entity = self.hass.states.get(f"zone.{entity.state}") if location.has_location(zone_entity): _LOGGER.debug("%s is in %s, getting zone location", entity_id, zone_entity.entity_id) return self._get_location_from_attributes(zone_entity) # Check if state is valid coordinate set if self._entity_state_is_valid_coordinate_set(entity.state): return entity.state _LOGGER.error( "The state of %s is not a valid set of coordinates: %s", entity_id, entity.state, ) return None
def zone_automation_listener(entity, from_s, to_s): """Listen for state changes and calls action.""" if from_s and not location.has_location(from_s) or \ not location.has_location(to_s): return zone_state = hass.states.get(zone_entity_id) if from_s: from_match = condition.zone(hass, zone_state, from_s) else: from_match = False to_match = condition.zone(hass, zone_state, to_s) # pylint: disable=too-many-boolean-expressions if event == EVENT_ENTER and not from_match and to_match or \ event == EVENT_LEAVE and from_match and not to_match: hass.async_run_job( action, { 'trigger': { 'platform': 'zone', 'entity_id': entity, 'from_state': from_s, 'to_state': to_s, 'zone': zone_state, 'event': event, }, })
def _get_location_from_entity(self, entity_id): """Get the location from the entity state or attributes.""" entity = self._hass.states.get(entity_id) if entity is None: _LOGGER.error("Unable to find entity %s", entity_id) self.valid_api_connection = False return None # Check if the entity has location attributes if location.has_location(entity): return self._get_location_from_attributes(entity) # Check if device is in a zone zone_entity = self._hass.states.get("zone.%s" % entity.state) if location.has_location(zone_entity): _LOGGER.debug("%s is in %s, getting zone location", entity_id, zone_entity.entity_id) return self._get_location_from_attributes(zone_entity) # If zone was not found in state then use the state as the location if entity_id.startswith("sensor."): return entity.state # When everything fails just return nothing return None
def test_has_location_with_states_with_invalid_locations(self): """Set up the tests.""" state = State('hello.world', 'invalid', { ATTR_LATITUDE: 'no number', ATTR_LONGITUDE: 123.12 }) assert not location.has_location(state)
def test_has_location_with_states_with_valid_location(): """Set up the tests.""" state = State("hello.world", "invalid", { ATTR_LATITUDE: 123.12, ATTR_LONGITUDE: 123.12 }) assert location.has_location(state)
def closest(self, *args): """Find closest entity. Closest to home: closest(states) closest(states.device_tracker) closest('group.children') closest(states.group.children) Closest to a point: closest(23.456, 23.456, 'group.children') closest('zone.school', 'group.children') closest(states.zone.school, 'group.children') """ if len(args) == 1: latitude = self._hass.config.latitude longitude = self._hass.config.longitude entities = args[0] elif len(args) == 2: point_state = self._resolve_state(args[0]) if point_state is None: _LOGGER.warning('Closest:Unable to find state %s', args[0]) return None elif not loc_helper.has_location(point_state): _LOGGER.warning( 'Closest:State does not contain valid location: %s', point_state) return None latitude = point_state.attributes.get(ATTR_LATITUDE) longitude = point_state.attributes.get(ATTR_LONGITUDE) entities = args[1] else: latitude = convert(args[0], float) longitude = convert(args[1], float) if latitude is None or longitude is None: _LOGGER.warning( 'Closest:Received invalid coordinates: %s, %s', args[0], args[1]) return None entities = args[2] if isinstance(entities, (AllStates, DomainStates)): states = list(entities) else: if isinstance(entities, State): gr_entity_id = entities.entity_id else: gr_entity_id = str(entities) states = [self._hass.states.get(entity_id) for entity_id in group.expand_entity_ids(self._hass, [gr_entity_id])] return loc_helper.closest(latitude, longitude, states)
def test_has_location_with_states_with_invalid_locations(): """Set up the tests.""" state = State('hello.world', 'invalid', { ATTR_LATITUDE: 'no number', ATTR_LONGITUDE: 123.12 }) assert not location.has_location(state)
def test_has_location_with_states_with_valid_location(self): """Set up the tests.""" state = State('hello.world', 'invalid', { ATTR_LATITUDE: 123.12, ATTR_LONGITUDE: 123.12 }) self.assertTrue(location.has_location(state))
def closest(hass, *args): """Find closest entity. Closest to home: closest(states) closest(states.device_tracker) closest('group.children') closest(states.group.children) Closest to a point: closest(23.456, 23.456, 'group.children') closest('zone.school', 'group.children') closest(states.zone.school, 'group.children') As a filter: states | closest states.device_tracker | closest ['group.children', states.device_tracker] | closest 'group.children' | closest(23.456, 23.456) states.device_tracker | closest('zone.school') 'group.children' | closest(states.zone.school) """ if len(args) == 1: latitude = hass.config.latitude longitude = hass.config.longitude entities = args[0] elif len(args) == 2: point_state = _resolve_state(hass, args[0]) if point_state is None: _LOGGER.warning("Closest:Unable to find state %s", args[0]) return None if not loc_helper.has_location(point_state): _LOGGER.warning( "Closest:State does not contain valid location: %s", point_state) return None latitude = point_state.attributes.get(ATTR_LATITUDE) longitude = point_state.attributes.get(ATTR_LONGITUDE) entities = args[1] else: latitude = convert(args[0], float) longitude = convert(args[1], float) if latitude is None or longitude is None: _LOGGER.warning("Closest:Received invalid coordinates: %s, %s", args[0], args[1]) return None entities = args[2] states = expand(hass, entities) # state will already be wrapped here return loc_helper.closest(latitude, longitude, states)
def test_has_location_with_states_with_valid_location(self): """Setup the tests.""" state = State('hello.world', 'invalid', { ATTR_LATITUDE: 123.12, ATTR_LONGITUDE: 123.12 }) self.assertTrue(location.has_location(state))
def zone_automation_listener(zone_event): """Listen for state changes and calls action.""" entity = zone_event.data.get("entity_id") from_s = zone_event.data.get("old_state") to_s = zone_event.data.get("new_state") if (from_s and not location.has_location(from_s) or not location.has_location(to_s)): return if not (zone_state := hass.states.get(zone_entity_id)): _LOGGER.warning( "Automation '%s' is referencing non-existing zone '%s' in a zone trigger", automation_info["name"], zone_entity_id, ) return
def distance(hass, *args): """Calculate distance. Will calculate distance from home to a point or between points. Points can be passed in using state objects or lat/lng coordinates. """ locations = [] to_process = list(args) while to_process: value = to_process.pop(0) if isinstance(value, str) and not valid_entity_id(value): point_state = None else: point_state = _resolve_state(hass, value) if point_state is None: # We expect this and next value to be lat&lng if not to_process: _LOGGER.warning( "Distance:Expected latitude and longitude, got %s", value ) return None value_2 = to_process.pop(0) latitude = convert(value, float) longitude = convert(value_2, float) if latitude is None or longitude is None: _LOGGER.warning( "Distance:Unable to process latitude and longitude: %s, %s", value, value_2, ) return None else: if not loc_helper.has_location(point_state): _LOGGER.warning( "distance:State does not contain valid location: %s", point_state ) return None latitude = point_state.attributes.get(ATTR_LATITUDE) longitude = point_state.attributes.get(ATTR_LONGITUDE) locations.append((latitude, longitude)) if len(locations) == 1: return hass.config.distance(*locations[0]) return hass.config.units.length( loc_util.distance(*locations[0] + locations[1]), LENGTH_METERS )
def distance(self, *args): """Calculate distance. Will calculate distance from home to a point or between points. Points can be passed in using state objects or lat/lng coordinates. """ locations = [] to_process = list(args) while to_process: value = to_process.pop(0) point_state = self._resolve_state(value) if point_state is None: # We expect this and next value to be lat&lng if not to_process: _LOGGER.warning( "Distance:Expected latitude and longitude, got %s", value) return None value_2 = to_process.pop(0) latitude = convert(value, float) longitude = convert(value_2, float) if latitude is None or longitude is None: _LOGGER.warning("Distance:Unable to process latitude and " "longitude: %s, %s", value, value_2) return None else: if not loc_helper.has_location(point_state): _LOGGER.warning( "distance:State does not contain valid location: %s", point_state) return None latitude = point_state.attributes.get(ATTR_LATITUDE) longitude = point_state.attributes.get(ATTR_LONGITUDE) if latitude is None or longitude is None: _LOGGER.warning( "Distance:State does not contains a location: %s", value) return None locations.append((latitude, longitude)) if len(locations) == 1: return self._hass.config.distance(*locations[0]) return self._hass.config.units.length( loc_util.distance(*locations[0] + locations[1]), 'm')
def zone_automation_listener(zone_event): """Listen for state changes and calls action.""" entity = zone_event.data.get("entity_id") from_s = zone_event.data.get("old_state") to_s = zone_event.data.get("new_state") if ( from_s and not location.has_location(from_s) or not location.has_location(to_s) ): return zone_state = hass.states.get(zone_entity_id) from_match = condition.zone(hass, zone_state, from_s) if from_s else False to_match = condition.zone(hass, zone_state, to_s) if ( event == EVENT_ENTER and not from_match and to_match or event == EVENT_LEAVE and from_match and not to_match ): hass.async_run_job( action( { "trigger": { "platform": "zone", "entity_id": entity, "from_state": from_s, "to_state": to_s, "zone": zone_state, "event": event, } }, context=to_s.context, ) )
async def _get_location_from_entity(self, entity_id: str) -> Optional[str]: """Get the location from the entity state or attributes.""" entity = self._hass.states.get(entity_id) if entity is None: _LOGGER.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes if location.has_location(entity): return self._get_location_from_attributes(entity) # Check if device is in a zone zone_entity = self._hass.states.get("zone.{}".format(entity.state)) if location.has_location(zone_entity): _LOGGER.debug("%s is in %s, getting zone location", entity_id, zone_entity.entity_id) return self._get_location_from_attributes(zone_entity) # If zone was not found in state then use the state as the location if entity_id.startswith("sensor."): return entity.state
async def _get_location_from_entity(self, entity_id: str) -> Optional[str]: """Get the location from the entity state or attributes.""" entity = self.hass.states.get(entity_id) if entity is None: _LOGGER.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes if location.has_location(entity): return self._get_location_from_attributes(entity) # Check if device is in a zone zone_entity = self.hass.states.get("zone.{}".format(entity.state)) if location.has_location(zone_entity): _LOGGER.debug( "%s is in %s, getting zone location", entity_id, zone_entity.entity_id ) return self._get_location_from_attributes(zone_entity) # Resolve nested entity if entity.state is not entity_id: _LOGGER.debug("Getting nested entity for state: %s", entity.state) nested_entity = self.hass.states.get(entity.state) if nested_entity is not None: _LOGGER.debug("Resolving nested entity_id: %s", entity.state) return await self._get_location_from_entity(entity.state) # Check if state is valid coordinate set pattern = r"-?\d{1,2}\.\d+,-?\d{1,3}\.\d+" if re.fullmatch(pattern, entity.state): return entity.state _LOGGER.error( "The state of %s is not a valid set of coordinates: %s", entity_id, entity.state, ) return None
def _get_location_from_entity(self): """Get the origin from the entity state or attributes.""" entity = self._hass.states.get(self._origin_entity_id) if entity is None: _LOGGER.error("Unable to find entity %s", self._origin_entity_id) return None # Check if the entity has origin attributes if location.has_location(entity): return "%s,%s" % (entity.attributes.get(ATTR_LATITUDE), entity.attributes.get(ATTR_LONGITUDE)) # When everything fails just return nothing return None
def _get_location_from_entity(self, entity_id): """Get the origin from the entity state or attributes.""" entity = self._hass.states.get(entity_id) if entity is None: _LOGGER.error("Unable to find entity %s", entity_id) return None # Check if the entity has origin attributes if location.has_location(entity): return self._get_location_from_attributes(entity) # When everything fails just return nothing return None
def resolve_location(hass, logger, loc): """Resolve a location.""" if re.fullmatch(ENTITY_ID_PATTERN, loc): return get_location_from_entity(hass, logger, loc) return resolve_zone(hass, loc) def get_location_from_entity(hass, logger, entity_id): """Get the location from the entity_id.""" if (state := hass.states.get(entity_id)) is None: logger.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes. if location.has_location(state): logger.debug("Getting %s location", entity_id) return _get_location_from_attributes(state) # Check if device is inside a zone. zone_state = hass.states.get(f"zone.{state.state}") if location.has_location(zone_state): logger.debug("%s is in %s, getting zone location", entity_id, zone_state.entity_id) return _get_location_from_attributes(zone_state) # If zone was not found in state then use the state as the location. if entity_id.startswith("sensor."): return state.state # When everything fails just return nothing.
def test_has_location_with_states_with_invalid_locations(self): state = State('hello.world', 'invalid', { ATTR_LATITUDE: 'no number', ATTR_LONGITUDE: 123.12 }) self.assertFalse(location.has_location(state))
def test_has_location_with_invalid_states(): """Set up the tests.""" for state in (None, 1, "hello", object): assert not location.has_location(state)
def closest(self, *args): """Find closest entity. Closest to home: closest(states) closest(states.device_tracker) closest('group.children') closest(states.group.children) Closest to a point: closest(23.456, 23.456, 'group.children') closest('zone.school', 'group.children') closest(states.zone.school, 'group.children') """ if len(args) == 1: latitude = self._hass.config.latitude longitude = self._hass.config.longitude entities = args[0] elif len(args) == 2: point_state = self._resolve_state(args[0]) if point_state is None: _LOGGER.warning('Closest:Unable to find state %s', args[0]) return None elif not loc_helper.has_location(point_state): _LOGGER.warning( 'Closest:State does not contain valid location: %s', point_state) return None latitude = point_state.attributes.get(ATTR_LATITUDE) longitude = point_state.attributes.get(ATTR_LONGITUDE) entities = args[1] else: latitude = convert(args[0], float) longitude = convert(args[1], float) if latitude is None or longitude is None: _LOGGER.warning('Closest:Received invalid coordinates: %s, %s', args[0], args[1]) return None entities = args[2] if isinstance(entities, (AllStates, DomainStates)): states = list(entities) else: if isinstance(entities, State): gr_entity_id = entities.entity_id else: gr_entity_id = str(entities) group = get_component('group') states = [ self._hass.states.get(entity_id) for entity_id in group.expand_entity_ids( self._hass, [gr_entity_id]) ] return loc_helper.closest(latitude, longitude, states)
class HERETravelTimeSensor(SensorEntity): """Representation of a HERE travel time sensor.""" def __init__( self, name: str, origin: str, destination: str, origin_entity_id: str, destination_entity_id: str, here_data: HERETravelTimeData, ) -> None: """Initialize the sensor.""" self._name = name self._origin_entity_id = origin_entity_id self._destination_entity_id = destination_entity_id self._here_data = here_data self._unit_of_measurement = TIME_MINUTES self._attrs = { ATTR_UNIT_SYSTEM: self._here_data.units, ATTR_MODE: self._here_data.travel_mode, ATTR_TRAFFIC_MODE: self._here_data.traffic_mode, } if self._origin_entity_id is None: self._here_data.origin = origin if self._destination_entity_id is None: self._here_data.destination = destination async def async_added_to_hass(self) -> None: """Delay the sensor update to avoid entity not found warnings.""" @callback def delayed_sensor_update(event): """Update sensor after Home Assistant started.""" self.async_schedule_update_ha_state(True) self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, delayed_sensor_update) @property def native_value(self) -> str | None: """Return the state of the sensor.""" if self._here_data.traffic_mode and self._here_data.traffic_time is not None: return str(round(self._here_data.traffic_time / 60)) if self._here_data.base_time is not None: return str(round(self._here_data.base_time / 60)) return None @property def name(self) -> str: """Get the name of the sensor.""" return self._name @property def extra_state_attributes( self, ) -> dict[str, None | float | str | bool] | None: """Return the state attributes.""" if self._here_data.base_time is None: return None res = self._attrs if self._here_data.attribution is not None: res[ATTR_ATTRIBUTION] = self._here_data.attribution res[ATTR_DURATION] = self._here_data.base_time / 60 res[ATTR_DISTANCE] = self._here_data.distance res[ATTR_ROUTE] = self._here_data.route res[ATTR_DURATION_IN_TRAFFIC] = self._here_data.traffic_time / 60 res[ATTR_ORIGIN] = self._here_data.origin res[ATTR_DESTINATION] = self._here_data.destination res[ATTR_ORIGIN_NAME] = self._here_data.origin_name res[ATTR_DESTINATION_NAME] = self._here_data.destination_name return res @property def native_unit_of_measurement(self) -> str: """Return the unit this state is expressed in.""" return self._unit_of_measurement @property def icon(self) -> str: """Icon to use in the frontend depending on travel_mode.""" if self._here_data.travel_mode == TRAVEL_MODE_BICYCLE: return ICON_BICYCLE if self._here_data.travel_mode == TRAVEL_MODE_PEDESTRIAN: return ICON_PEDESTRIAN if self._here_data.travel_mode in TRAVEL_MODES_PUBLIC: return ICON_PUBLIC if self._here_data.travel_mode == TRAVEL_MODE_TRUCK: return ICON_TRUCK return ICON_CAR async def async_update(self) -> None: """Update Sensor Information.""" # Convert device_trackers to HERE friendly location if self._origin_entity_id is not None: self._here_data.origin = await self._get_location_from_entity( self._origin_entity_id) if self._destination_entity_id is not None: self._here_data.destination = await self._get_location_from_entity( self._destination_entity_id) await self.hass.async_add_executor_job(self._here_data.update) async def _get_location_from_entity(self, entity_id: str) -> str | None: """Get the location from the entity state or attributes.""" if (entity := self.hass.states.get(entity_id)) is None: _LOGGER.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes if location.has_location(entity): return self._get_location_from_attributes(entity) # Check if device is in a zone zone_entity = self.hass.states.get(f"zone.{entity.state}") if location.has_location(zone_entity): _LOGGER.debug("%s is in %s, getting zone location", entity_id, zone_entity.entity_id) return self._get_location_from_attributes(zone_entity) # Check if state is valid coordinate set if self._entity_state_is_valid_coordinate_set(entity.state): return entity.state _LOGGER.error( "The state of %s is not a valid set of coordinates: %s", entity_id, entity.state, ) return None
def test_has_location_with_invalid_states(self): """Setup the tests.""" for state in (None, 1, "hello", object): self.assertFalse(location.has_location(state))
def resolve_location(hass, logger, loc): """Resolve a location.""" if loc.split(".", 1)[0] in TRACKABLE_DOMAINS: return get_location_from_entity(hass, logger, loc) return resolve_zone(hass, loc) def get_location_from_entity(hass, logger, entity_id): """Get the location from the entity state or attributes.""" if (entity := hass.states.get(entity_id)) is None: logger.error("Unable to find entity %s", entity_id) return None # Check if the entity has location attributes if location.has_location(entity): return get_location_from_attributes(entity) # Check if device is in a zone zone_entity = hass.states.get(f"zone.{entity.state}") if location.has_location(zone_entity): logger.debug("%s is in %s, getting zone location", entity_id, zone_entity.entity_id) return get_location_from_attributes(zone_entity) # If zone was not found in state then use the state as the location if entity_id.startswith("sensor."): return entity.state # When everything fails just return nothing return None
def test_has_location_with_invalid_states(self): """Set up the tests.""" for state in (None, 1, "hello", object): self.assertFalse(location.has_location(state))