Beispiel #1
0
    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,
                ))
Beispiel #2
0
    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,
            )
Beispiel #3
0
    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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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)
Beispiel #7
0
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)
Beispiel #8
0
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)
Beispiel #9
0
def test_has_location_with_invalid_states():
    """Set up the tests."""
    for state in (None, 1, "hello", object):
        assert not location.has_location(state)