please let me seek assistance here. Until 115 I still had AD3 running and working perfectly, with below 2 automations. AD3 now no longer works, and what’s more, it is gone from the Add-on store?
Ill post these 2 scripts here hoping any one of you guru’s is able to re-write them for AD 4
they are very useful scripts:
the first adds geocoded location info to life360 sensors (I dont use the App sensors), and the second is a last_motion automation, listing the last recorded motion sensor.
Hope you can help:
Geocoded sensors, address.py
"""Address AppDaemon app."""
# pylint: disable=attribute-defined-outside-init, unused-argument, too-many-arguments
import appdaemon.plugins.hass.hassapi as hass
#
# Address App
# requires: "geopy" https://pypi.org/project/geopy/
#
#
# Args:
# entity: entity_id of a device_tracker entity, example "device_tracker.my_entity"
#
class Address(hass.Hass):
"""Address class."""
def initialize(self):
"""initialize Address."""
self.log("App started.")
entity_config = self.args["entity"]
if isinstance(entity_config, str):
entities = []
entities.append(entity_config)
else:
entities = entity_config
for entity in entities:
self.listen_state(self.get_address, entity)
self.log("State listener for {} started.".format(entity))
def get_address(self, entity, attribute, old, new, kwargs):
"""Set the state + attributes of a defined device_tracker entity."""
from geopy.geocoders import Nominatim
geo = Nominatim(user_agent="AppDaemon")
lat = self.get_state(entity, attribute="latitude")
long = self.get_state(entity, attribute="longitude")
if lat is None or long is None:
self.log("{} does not have lat/long attributes.".format(entity))
return
lat_long = "{}, {}".format(lat, long)
data = geo.reverse(lat_long)
raw = data.raw["address"]
attributes = self.get_state(entity, attribute="all")["attributes"]
for attr in raw:
attributes[attr] = raw[attr]
self.log("Updating state for {}".format(entity))
self.set_state(entity, attributes=attributes)
and binary_sensors recording multi_bin_sensor_history.py
:
# -*- coding: utf-8 -*-
"""
Binary sensor custom history as AppDaemon App for Home Assistant.
Listen to multiple binary sensors to reflect the last activation,
maintaining a history of the lasts activations.
* Sensor State: `Friendly name`
* Sensor attributes:
`history_1: Friendly name: activation_timestamp`,
`history_2: Friendly name: activation_timestamp`,
...
Yaml config goes like this:
LastMotionHistory:
class: MultiBinSensor
module: multi_bin_sensor_history
new_entity: sensor.last_motion
max_history: 10
binary_sensors:
binary_sensor.hue_motion_sensor_1_motion: Cocina
binary_sensor.hue_motion_sensor_2_motion: Office
format_last_changed: '%H:%M:%S'
icon: mdi:motion-sensor
friendly_name: Last motion
"""
from collections import deque
from typing import Deque, Dict
import appdaemon.plugins.hass.hassapi as hass
_ATTR_NAME = "history_"
class MultiBinSensor(hass.Hass):
_entity: str
_date_format: str
_history: Deque[str]
_friendly_names: Dict[str, str]
_entity_attributes: Dict[str, str]
def initialize(self):
"""AppDaemon required method for app init."""
self._entity = self.args.get("new_entity")
icon = self.args.get("icon", "mdi:motion-sensor")
friendly_name = self.args.get("friendly_name", "Last motion")
self._entity_attributes = {"icon": icon, "friendly_name": friendly_name}
self._date_format = self.args.get("format_last_changed")
# Set up state history for attributes
self._history = deque([], maxlen=int(self.args.get("max_history")))
# Listen for binary sensor activations and store friendly names for them
bin_sensors: Dict[str, str] = self.args.get("binary_sensors")
self._friendly_names = {}
for sensor, pretty_name in bin_sensors.items():
self._friendly_names[sensor] = pretty_name
self.listen_state(self._bin_sensor_activation, sensor, new="on")
# recover old values, if any
old_attrs = self.get_state(self._entity, attribute="all")
if old_attrs:
state = old_attrs.get("state", "unknown")
for k, old_value in reversed(old_attrs.get("attributes", {}).items()):
if k.startswith(_ATTR_NAME) and ": " in old_value:
self._history.append(old_value)
# Re-Publish old state
self._set_new_sensor_state(state)
def _set_new_sensor_state(self, state):
"""Publish a new state for the sensor."""
history_attrs = {
f"{_ATTR_NAME}{i}": old_state
for i, old_state in enumerate(reversed(self._history))
if i > 0
}
attributes = {**self._entity_attributes, **history_attrs}
self.set_state(self._entity, state=state, attributes=attributes)
def _bin_sensor_activation(self, entity, attribute, old, new, kwargs):
"""Listen to bin sensors turning on, update history and publish a new state."""
location = self._friendly_names[entity]
pretty_date_now = self.datetime().strftime(self._date_format)
# Add to history
self._history.append(f"{location}: {pretty_date_now}")
# Publish new state
self._set_new_sensor_state(location)
apps.yaml
configs for both scripts:
# https://github.com/ludeeus/ad-address
# https://community.home-assistant.io/t/how-to-iterate-over-a-timezone-list-in-python-to-find-country-code/123262/53
address:
module: address
class: Address
entity:
- device_tracker.life360_marijn
- device_tracker.life360_w
- device_tracker.life360_d1
- device_tracker.life360_d2
- device_tracker.life360_d3
- device_tracker.life360_d4
and
LastMotionHistory:
class: MultiBinSensor
module: multi_bin_sensor_history
new_entity: sensor.last_motion
max_history: 10
binary_sensors:
binary_sensor.laundry_sensor_motion: Laundry
binary_sensor.dining_table_sensor_motion: Dining
binary_sensor.auditorium_sensor_motion: Auditorium
binary_sensor.frontdoor_sensor_motion: Frontdoor
binary_sensor.library_sensor_motion: Library
binary_sensor.corridor_sensor_motion: Corridor
binary_sensor.corridor_terrace_sensor_motion: Corridor terrace
binary_sensor.master_bedroom_sensor_motion: Master bedroom
binary_sensor.corridor_office_sensor_motion: Corridor office
binary_sensor.front_room_sensor_motion: Front room
binary_sensor.guest_room_sensor_motion: Guest room
binary_sensor.dorm_sensor_motion: Dorm
etc etc etc
format_last_changed: '%H:%M:%S'
friendly_name: Last motion
thanks for having a look! Much appreciated.