Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
aneisch committed Sep 28, 2024
1 parent e965db4 commit bfdc3ba
Show file tree
Hide file tree
Showing 1,196 changed files with 10,358 additions and 1,064 deletions.
38 changes: 20 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Build Status](https://github.com/aneisch/home-assistant-config/actions/workflows/check-ha-release-compatibility.yml/badge.svg)](https://github.com/aneisch/home-assistant-config/actions)
[![GitHub last commit](https://img.shields.io/github/last-commit/aneisch/home-assistant-config)](https://github.com/aneisch/home-assistant-config/commits/master)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/aneisch/home-assistant-config)](https://github.com/aneisch/home-assistant-config/graphs/commit-activity)
[![HA Version](https://img.shields.io/badge/Running%20Home%20Assistant-2024.8.3%20(Latest)-brightgreen)](https://github.com/home-assistant/home-assistant/releases/latest)
[![HA Version](https://img.shields.io/badge/Running%20Home%20Assistant-2024.9.3%20(Latest)-brightgreen)](https://github.com/home-assistant/home-assistant/releases/latest)
<br><a href="https://www.buymeacoffee.com/aneisch" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-black.png" width="150px" height="35px" alt="Buy Me A Coffee" style="height: 35px !important;width: 150px !important;" ></a>

I do my best to keep [Home Assistant](https://github.com/home-assistant/home-assistant) on the [latest release](https://github.com/home-assistant/home-assistant/releases/latest). I'm heavily utilizing [AppDaemon](http://appdaemon.readthedocs.io/en/latest/) and [NodeRed](https://flows.nodered.org/node/node-red-contrib-home-assistant-websocket) for advanced/templated automations. See [Appdaemon config](https://github.com/aneisch/home-assistant-config/tree/master/extras/appdaemon) and my NodeRed screenshots below for details. Most of my setup is run as Docker containers (see [docker-compose](https://github.com/aneisch/home-assistant-config/tree/master/extras/docker-compose) for container list).
Expand Down Expand Up @@ -58,55 +58,55 @@ Home Assistant and other containers have ingress handled automatically by [Traef
## Some statistics about my installation:
Description | value
-- | --
Lines of ESPHome YAML | 3254
Lines of Home Assistant YAML | 9685
[Integrations](https://www.home-assistant.io/integrations/) in use | 62
Lines of ESPHome YAML | 3250
Lines of Home Assistant YAML | 9707
[Integrations](https://www.home-assistant.io/integrations/) in use | 64
Zigbee devices in [`zha`](https://www.home-assistant.io/integrations/zha/) | 26
Z-Wave devices in [`zwave_js`](https://www.home-assistant.io/integrations/zwave_js/) | 37

Description | value
-- | --
Entities in the [`automation`](https://www.home-assistant.io/components/automation) domain | 129
Entities in the [`binary_sensor`](https://www.home-assistant.io/components/binary_sensor) domain | 157
Entities in the [`button`](https://www.home-assistant.io/components/button) domain | 46
Entities in the [`automation`](https://www.home-assistant.io/components/automation) domain | 130
Entities in the [`binary_sensor`](https://www.home-assistant.io/components/binary_sensor) domain | 162
Entities in the [`button`](https://www.home-assistant.io/components/button) domain | 48
Entities in the [`camera`](https://www.home-assistant.io/components/camera) domain | 16
Entities in the [`climate`](https://www.home-assistant.io/components/climate) domain | 1
Entities in the [`climate`](https://www.home-assistant.io/components/climate) domain | 2
Entities in the [`conversation`](https://www.home-assistant.io/components/conversation) domain | 2
Entities in the [`counter`](https://www.home-assistant.io/components/counter) domain | 1
Entities in the [`cover`](https://www.home-assistant.io/components/cover) domain | 16
Entities in the [`datetime`](https://www.home-assistant.io/components/datetime) domain | 6
Entities in the [`device_tracker`](https://www.home-assistant.io/components/device_tracker) domain | 4
Entities in the [`device_tracker`](https://www.home-assistant.io/components/device_tracker) domain | 6
Entities in the [`event`](https://www.home-assistant.io/components/event) domain | 14
Entities in the [`fan`](https://www.home-assistant.io/components/fan) domain | 3
Entities in the [`group`](https://www.home-assistant.io/components/group) domain | 19
Entities in the [`image`](https://www.home-assistant.io/components/image) domain | 8
Entities in the [`input_boolean`](https://www.home-assistant.io/components/input_boolean) domain | 30
Entities in the [`input_boolean`](https://www.home-assistant.io/components/input_boolean) domain | 31
Entities in the [`input_datetime`](https://www.home-assistant.io/components/input_datetime) domain | 33
Entities in the [`input_number`](https://www.home-assistant.io/components/input_number) domain | 6
Entities in the [`input_select`](https://www.home-assistant.io/components/input_select) domain | 19
Entities in the [`input_text`](https://www.home-assistant.io/components/input_text) domain | 16
Entities in the [`light`](https://www.home-assistant.io/components/light) domain | 39
Entities in the [`lock`](https://www.home-assistant.io/components/lock) domain | 4
Entities in the [`lock`](https://www.home-assistant.io/components/lock) domain | 5
Entities in the [`media_player`](https://www.home-assistant.io/components/media_player) domain | 19
Entities in the [`notify`](https://www.home-assistant.io/components/notify) domain | 2
Entities in the [`number`](https://www.home-assistant.io/components/number) domain | 15
Entities in the [`number`](https://www.home-assistant.io/components/number) domain | 16
Entities in the [`person`](https://www.home-assistant.io/components/person) domain | 2
Entities in the [`plant`](https://www.home-assistant.io/components/plant) domain | 1
Entities in the [`remote`](https://www.home-assistant.io/components/remote) domain | 4
Entities in the [`script`](https://www.home-assistant.io/components/script) domain | 51
Entities in the [`select`](https://www.home-assistant.io/components/select) domain | 4
Entities in the [`sensor`](https://www.home-assistant.io/components/sensor) domain | 523
Entities in the [`script`](https://www.home-assistant.io/components/script) domain | 52
Entities in the [`select`](https://www.home-assistant.io/components/select) domain | 8
Entities in the [`sensor`](https://www.home-assistant.io/components/sensor) domain | 543
Entities in the [`setter`](https://www.home-assistant.io/components/setter) domain | 1
Entities in the [`siren`](https://www.home-assistant.io/components/siren) domain | 1
Entities in the [`sun`](https://www.home-assistant.io/components/sun) domain | 1
Entities in the [`switch`](https://www.home-assistant.io/components/switch) domain | 186
Entities in the [`switch`](https://www.home-assistant.io/components/switch) domain | 189
Entities in the [`timer`](https://www.home-assistant.io/components/timer) domain | 6
Entities in the [`tts`](https://www.home-assistant.io/components/tts) domain | 1
Entities in the [`update`](https://www.home-assistant.io/components/update) domain | 81
Entities in the [`update`](https://www.home-assistant.io/components/update) domain | 84
Entities in the [`vacuum`](https://www.home-assistant.io/components/vacuum) domain | 1
Entities in the [`weather`](https://www.home-assistant.io/components/weather) domain | 1
Entities in the [`zone`](https://www.home-assistant.io/components/zone) domain | 6
**Total state objects** | **1475**
**Total state objects** | **1520**
## The HACS integrations/plugins that I use:

**Appdaemon**:<br>
Expand All @@ -128,12 +128,14 @@ Entities in the [`zone`](https://www.home-assistant.io/components/zone) domain |
[AlexxIT/WebRTC](https://github.com/AlexxIT/WebRTC)<br>
[PiotrMachowski/Home-Assistant-custom-components-Xiaomi-Cloud-Map-Extractor](https://github.com/PiotrMachowski/Home-Assistant-custom-components-Xiaomi-Cloud-Map-Extractor)<br>
[alandtse/alexa_media_player](https://github.com/alandtse/alexa_media_player)<br>
[alandtse/tesla](https://github.com/alandtse/tesla)<br>
[blakeblackshear/frigate-hass-integration](https://github.com/blakeblackshear/frigate-hass-integration)<br>
[claytonjn/hass-circadian_lighting](https://github.com/claytonjn/hass-circadian_lighting)<br>
[custom-components/readme](https://github.com/custom-components/readme)<br>
[dlashua/hass-setter](https://github.com/dlashua/hass-setter)<br>
[frenck/spook](https://github.com/frenck/spook)<br>
[hacs/integration](https://github.com/hacs/integration)<br>
[magico13/ha-emporia-vue](https://github.com/magico13/ha-emporia-vue)<br>
[moralmunky/Home-Assistant-Mail-And-Packages](https://github.com/moralmunky/Home-Assistant-Mail-And-Packages)<br>
[rospogrigio/localtuya](https://github.com/rospogrigio/localtuya)<br>
[rroller/dahua](https://github.com/rroller/dahua)<br>
Expand Down
1 change: 1 addition & 0 deletions alexa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ smart_home:
- switch.ferris_wheel
- switch.nativity
- switch.santa_tree
- script.surround_mute

entity_config:
climate.thermostat:
Expand Down
18 changes: 18 additions & 0 deletions automations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,8 @@
- Error
- Waste container warning
- Warning
- Water empty
- Internal Error
condition: []
action:
- action: notify.signal_homeassistant
Expand All @@ -1246,3 +1248,19 @@
'
mode: single
- id: '1727469189792'
alias: Total Power Alert
description: ''
trigger:
- platform: numeric_state
entity_id:
- sensor.total_power
above: 18000
condition: []
action:
- action: script.notify_wrapper
data:
message: Total power has exceeded 18k Watts! Currently {{trigger.to_state.state}}
data:
priority: 1
mode: single
2 changes: 1 addition & 1 deletion configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ readme:
# ORDER BY
# COUNT(*) DESC;
recorder:
db_url: mysql://homeassistant:[email protected]/homeassistant?charset=utf8
db_url: mysql://homeassistant:[email protected]/homeassistant?charset=utf8mb4
purge_keep_days: 182
commit_interval: 30
exclude:
Expand Down
6 changes: 3 additions & 3 deletions custom_components/alexa_media/.translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"debug": "Erweitertes Debugging",
"email": "E-Mail-Adresse",
"exclude_devices": "Ausgeschlossene Geräte (Komma getrennt)",
"extended_entity_discovery": "Include devices connected via Echo",
"extended_entity_discovery": "Über Echo verbundene Geräte einbeziehen",
"hass_url": "Home Assistant-URL",
"include_devices": "Eingebundene Geräte (Komma getrennt)",
"otp_secret": "Integrierter 2FA-App-Schlüssel (automatisch generierte 2FA-Code)",
Expand Down Expand Up @@ -62,8 +62,8 @@
"queue_delay": "Sekunden zu warten, um Befehle in die Warteschlange zu stellen",
"scan_interval": "Sekunden zwischen den Scans"
},
"description": "Required *",
"title": "Alexa Media Player - Reconfiguration"
"description": "Erforderlich *",
"title": "Alexa Media Player - Neukonfiguration"
}
}
},
Expand Down
86 changes: 61 additions & 25 deletions custom_components/alexa_media/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
hide_serial,
obfuscate,
)
from alexapy.helpers import delete_cookie as alexapy_delete_cookie
import async_timeout
from homeassistant import util
from homeassistant.components.persistent_notification import (
Expand Down Expand Up @@ -53,7 +54,7 @@
import voluptuous as vol

from .alexa_entity import AlexaEntityData, get_entity_data, parse_alexa_entities
from .config_flow import in_progess_instances
from .config_flow import in_progress_instances
from .const import (
ALEXA_COMPONENTS,
CONF_ACCOUNTS,
Expand Down Expand Up @@ -1297,15 +1298,19 @@ async def http2_error_handler(message):


async def async_unload_entry(hass, entry) -> bool:
"""Unload a config entry."""
"""Unload a config entry"""
email = entry.data["email"]
login_obj = hass.data[DATA_ALEXAMEDIA]["accounts"][email]["login_obj"]
_LOGGER.debug("Attempting to unload entry for %s", hide_email(email))
_LOGGER.debug("Unloading entry: %s", hide_email(email))
for component in ALEXA_COMPONENTS + DEPENDENT_ALEXA_COMPONENTS:
_LOGGER.debug("Forwarding unload entry to %s", component)
await hass.config_entries.async_forward_entry_unload(entry, component)
# notify has to be handled manually as the forward does not work yet
await notify_async_unload_entry(hass, entry)
try:
if component == "notify":
await notify_async_unload_entry(hass, entry)
else:
_LOGGER.debug("Forwarding unload entry to %s", component)
await hass.config_entries.async_forward_entry_unload(entry, component)
except Exception as ex:
_LOGGER.error("Error unloading: %s", component)
await close_connections(hass, email)
for listener in hass.data[DATA_ALEXAMEDIA]["accounts"][email][DATA_LISTENER]:
listener()
Expand Down Expand Up @@ -1341,22 +1346,6 @@ async def async_unload_entry(hass, entry) -> bool:
_LOGGER.debug("Removing alexa_media data structure")
if hass.data.get(DATA_ALEXAMEDIA):
hass.data.pop(DATA_ALEXAMEDIA)
# Delete cookiefile
if callable(getattr(AlexaLogin, "delete_cookiefile", None)):
try:
await login_obj.delete_cookiefile()
_LOGGER.debug("Deleted cookiefile")
except Exception as ex:
_LOGGER.error(
"Failed to delete cookiefile: %s",
ex,
)
else:
_LOGGER.warn(
"Could not remove cookiefile: /config/.storage/alexa_media.%s.pickle."
" Please manually delete the file.",
email,
)
else:
_LOGGER.debug(
"Unable to remove alexa_media data structure: %s",
Expand All @@ -1366,6 +1355,53 @@ async def async_unload_entry(hass, entry) -> bool:
return True


async def async_remove_entry(hass, entry) -> bool:
"""Handle removal of an entry."""
email = entry.data["email"]
obfuscated_email = hide_email(email)
_LOGGER.debug("Removing config entry: %s", hide_email(email))
login_obj = AlexaLogin(
url="",
email=email,
password="",
outputpath=hass.config.path,
)
# Delete cookiefile
cookiefile = hass.config.path(f".storage/{DOMAIN}.{email}.pickle")
obfuscated_cookiefile = hass.config.path(
f".storage/{DOMAIN}.{obfuscated_email}.pickle"
)
if callable(getattr(AlexaLogin, "delete_cookiefile", None)):
try:
await login_obj.delete_cookiefile()
_LOGGER.debug("Cookiefile %s deleted.", obfuscated_cookiefile)
except Exception as ex:
_LOGGER.error(
"delete_cookiefile() exception: %s;"
" Manually delete cookiefile before re-adding the integration: %s",
ex,
obfuscated_cookiefile,
)
else:
if os.path.exists(cookiefile):
try:
await alexapy_delete_cookie(cookiefile)
_LOGGER.debug(
"Successfully deleted cookiefile: %s", obfuscated_cookiefile
)
except (OSError, EOFError, TypeError, AttributeError) as ex:
_LOGGER.error(
"alexapy_delete_cookie() exception: %s;"
" Manually delete cookiefile before re-adding the integration: %s",
ex,
obfuscated_cookiefile,
)
else:
_LOGGER.error("Cookiefile not found: %s", obfuscated_cookiefile)
_LOGGER.debug("Config entry %s removed.", obfuscated_email)
return True


async def close_connections(hass, email: str) -> None:
"""Clear open aiohttp connections for email."""
if (
Expand Down Expand Up @@ -1415,7 +1451,7 @@ async def test_login_status(hass, config_entry, login) -> bool:
if login.status and login.status.get("login_successful"):
return True
account = config_entry.data
_LOGGER.debug("Logging in: %s %s", obfuscate(account), in_progess_instances(hass))
_LOGGER.debug("Logging in: %s %s", obfuscate(account), in_progress_instances(hass))
_LOGGER.debug("Login stats: %s", login.stats)
message: str = (
f"Reauthenticate {login.email} on the [Integrations](/config/integrations) page. "
Expand All @@ -1434,7 +1470,7 @@ async def test_login_status(hass, config_entry, login) -> bool:
f"{account[CONF_EMAIL]} - {account[CONF_URL]}"
)
if flow:
if flow.get("flow_id") in in_progess_instances(hass):
if flow.get("flow_id") in in_progress_instances(hass):
_LOGGER.debug("Existing config flow detected")
return False
_LOGGER.debug("Stopping orphaned config flow %s", flow.get("flow_id"))
Expand Down
5 changes: 3 additions & 2 deletions custom_components/alexa_media/alexa_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,10 +350,11 @@ def parse_temperature_from_coordinator(
coordinator: DataUpdateCoordinator, entity_id: str
) -> Optional[str]:
"""Get the temperature of an entity from the coordinator data."""
value = parse_value_from_coordinator(
temperature = parse_value_from_coordinator(
coordinator, entity_id, "Alexa.TemperatureSensor", "temperature"
)
return value.get("value") if value and "value" in value else None
_LOGGER.debug("parse_temperature_from_coordinator: %s", temperature)
return temperature


def parse_air_quality_from_coordinator(
Expand Down
16 changes: 11 additions & 5 deletions custom_components/alexa_media/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,13 @@ def configured_instances(hass):


@callback
def in_progess_instances(hass):
"""Return a set of in progress Alexa Media flows."""
return {entry["flow_id"] for entry in hass.config_entries.flow.async_progress()}
def in_progress_instances(hass):
"""Return a set of in-progress Alexa Media flows."""
return {
entry["flow_id"]
for entry in hass.config_entries.flow.async_progress()
if entry["handler"] == DOMAIN # Ensure only Alexa Media flows are included
}


@config_entries.HANDLERS.register(DOMAIN)
Expand Down Expand Up @@ -646,7 +650,8 @@ async def _test_login(self):
event_data={"email": hide_email(email), "url": login.url},
)
async_dismiss_persistent_notification(
f"alexa_media_{slugify(email)}{slugify(login.url[7:])}"
self.hass,
notification_id=f"alexa_media_{slugify(email)}{slugify(login.url[7:])}",
)
if not self.hass.data[DATA_ALEXAMEDIA]["accounts"].get(
self.config[CONF_EMAIL]
Expand Down Expand Up @@ -699,7 +704,8 @@ async def _test_login(self):
_LOGGER.debug("Login failed: %s", login.status.get("login_failed"))
await login.close()
async_dismiss_persistent_notification(
f"alexa_media_{slugify(email)}{slugify(login.url[7:])}"
self.hass,
notification_id=f"alexa_media_{slugify(email)}{slugify(login.url[7:])}",
)
return self.async_abort(reason="login_failed")
new_schema = self._update_schema_defaults()
Expand Down
Loading

0 comments on commit bfdc3ba

Please sign in to comment.