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 = opp.states.get(zone_entity_id) if from_s: from_match = condition.zone(opp, zone_state, from_s) else: from_match = False to_match = condition.zone(opp, 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): opp.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, ))
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 = opp.states.get(zone_entity_id) from_match = condition.zone(opp, zone_state, from_s) if from_s else False to_match = condition.zone(opp, 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]}" opp.async_run_opp_job( job, { "trigger": { "platform": platform_type, "entity_id": entity, "from_state": from_s, "to_state": to_s, "zone": zone_state, "event": event, "description": description, "id": trigger_id, } }, 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.opp.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.opp.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 get_location_from_entity(opp, logger, entity_id): """Get the location from the entity state or attributes.""" entity = opp.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 = opp.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 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 get_location_from_entity(opp, logger, entity_id): """Get the location from the entity_id.""" state = opp.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 = opp.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 closest(opp, *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 = opp.config.latitude longitude = opp.config.longitude entities = args[0] elif len(args) == 2: point_state = _resolve_state(opp, 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(opp, entities) # state will already be wrapped here return loc_helper.closest(latitude, longitude, states)
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 distance(opp, *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(opp, 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 opp.config.distance(*locations[0]) return opp.config.units.length( loc_util.distance(*locations[0] + locations[1]), LENGTH_METERS)
def test_has_location_with_invalid_states(): """Set up the tests.""" for state in (None, 1, "hello", object): assert not location.has_location(state)