diff --git a/config/custom_components/hacs/.translations/da.json b/config/custom_components/hacs/.translations/da.json index 89d82d11..8b3358ee 100644 --- a/config/custom_components/hacs/.translations/da.json +++ b/config/custom_components/hacs/.translations/da.json @@ -1,6 +1,7 @@ { "common": { "about": "Om", + "add": "tilføj", "appdaemon_apps": "AppDaemon-apps", "appdaemon_plural": "AppDaemon-apps", "background_task": "Baggrundsopgave kører. Denne side vil genindlæses automatisk.", @@ -10,6 +11,7 @@ "documentation": "Dokumentation", "element": "element", "hacs_is_disabled": "HACS er deaktiveret", + "install": "Installer", "installed": "installeret", "integration": "Integration", "integration_plural": "Integrationer", @@ -28,10 +30,12 @@ "python_script_plural": "Python-scripts", "python_scripts": "Python-scripts", "repositories": "Repositories", + "repository": "Repository", "settings": "indstillinger", "theme": "Tema", "theme_plural": "Temaer", "themes": "Temaer", + "uninstall": "Afinstaller", "version": "Version" }, "config": { @@ -77,6 +81,92 @@ "upgrade_all": "Dette vil opdatere alle repositories. Sørg for at du har læst udgivelsesnoterne for dem alle, inden du fortsætter.", "yes": "Ja" }, + "dialog_about": { + "frontend_version": "Frontend-version", + "installed_repositories": "Installerede repositories", + "integration_version": "Integrationsversion", + "useful_links": "Nyttige links" + }, + "dialog_add_repo": { + "limit": "Kun de første 100 repositories vises. Brug søgningen til at filtrere, hvad du har brug for", + "no_match": "Der blev ikke fundet nogen repositories, der matcher dit filter", + "sort_by": "Sorter efter", + "title": "Tilføj repository" + }, + "dialog_custom_repositories": { + "category": "Kategori", + "no_category": "Manglende kategori", + "no_repository": "Manglende repository", + "title": "Brugerdefinerede repositories", + "url_placeholder": "Tilføj brugerdefineret repository-webadresse" + }, + "dialog_info": { + "author": "Udvikler", + "downloads": "Downloads", + "install": "Installer dette repository i HACS", + "loading": "Indlæser oplysninger...", + "no_info": "Udvikleren har ikke givet flere oplysninger om dette repository", + "open_repo": "Åbn repository", + "stars": "Stjerner", + "version_installed": "Installeret version" + }, + "dialog_install": { + "restart": "Husk, at du skal genstarte Home Assistant, før ændringer af integrationer (custom_components) træder i kræft.", + "select_version": "Vælg version", + "show_beta": "Vis betaversioner", + "type": "Type", + "url": "Webadresse" + }, + "dialog_update": { + "available_version": "Tilgængelig version", + "changelog": "Udgivelsesnoter", + "installed_version": "Installeret version", + "title": "Ventende opdatering" + }, + "entry": { + "information": "Oplysninger", + "intro": "Opdateringer og vigtige meddelelser vises her, hvis der er nogen", + "messages": { + "disabled": { + "content": "Tjek din logfil for flere detaljer", + "title": "HACS er deaktiveret" + }, + "has_pending_tasks": { + "content": "Nogle repositories vises muligvis ikke, før dette er fuldført", + "title": "Baggrundsopgaver venter" + }, + "resources": { + "content": "Du har {number} Lovelace-elementer, der ikke er indlæst korrekt i Lovelace.", + "title": "Ikke indlæst i Lovelace" + }, + "restart": { + "content": "Du har {number} integrationer, der kræver en genstart af Home Assistant. Du kan genstarte fra 'Serveradministration'-sektionen under Indstillinger i Home Assistant-brugerfladen.", + "title": "Afventer genstart" + }, + "startup": { + "content": "HACS starter op. Der kan i dette tidsrum mangle nogle oplysninger, eller de kan være ukorekte.", + "title": "HACS starter op" + }, + "wrong_frontend_installed": { + "content": "Du har version {running} af HACS-frontend installeret, men version {expected} var forventet, hvis dette ser du denne besked. Home Assistant kunne ikke installere den nye version. Prøv at genstarte Home Assistant.", + "title": "Uventet frontend-version" + }, + "wrong_frontend_loaded": { + "content": "Du kører version {running} af HACS-frontend, men version {expected} var forventet. Du bør rydde din browser-cache.", + "title": "Uventet frontend-version" + } + }, + "pending_updates": "Ventende opdateringer" + }, + "menu": { + "about": "Om HACS", + "clear": "Ryd alle nye", + "custom_repositories": "Brugerdefinerede repositories", + "dismiss": "Afvis alle nye repositories", + "documentation": "Dokumentation", + "open_issue": "Opret issue", + "reload": "Genindlæs vindue" + }, "options": { "step": { "user": { @@ -104,6 +194,18 @@ "restart": "Du skal genstarte Home Assistant.", "restart_pending": "Afventer genstart" }, + "repository_card": { + "dismiss": "Afvis", + "hide": "Skjul", + "information": "Oplysninger", + "new_repository": "Nyt repository", + "not_loaded": "Ikke indlæst", + "open_issue": "Opret issue", + "pending_restart": "Afventer genstart", + "pending_update": "Ventende opdatering", + "reinstall": "Geninstaller", + "report": "Rapporter til fjernelse" + }, "repository": { "add_to_lovelace": "Tilføj til Lovelace", "authors": "Forfattere", @@ -138,6 +240,9 @@ "update_information": "Opdater oplysninger", "upgrade": "Opdater" }, + "search": { + "placeholder": "Søg efter repository" + }, "sections": { "about": { "description": "Vis information om HACS", @@ -188,7 +293,13 @@ "last_updated": "Sidst opdateret", "name": "Navn", "new_repositories": "Nye repositories", - "pending_upgrades": "Afventende opdateringer", + "new_repositories_note": "Du har over 10 nye repositories, der vises her, hvis du vil rydde dem alle, skal du klikke på de 3 prikker i øverste højre hjørne og afvise dem alle.", + "no_repositories": "Ingen repositories", + "no_repositories_desc1": "Det ser ud til, at du ikke har nogen repositories installeret i denne sektion endnu.", + "no_repositories_desc2": "Klik på + i nederste hjørne for at tilføje dit første!", + "no_repositories_found_desc1": "Der blev ikke fundet installerede repositories, der matcher \"{searchInput}\" i denne sektion.", + "no_repositories_found_desc2": "Prøv at søge efter noget andet!", + "pending_upgrades": "Ventende opdateringer", "placeholder_search": "Indtast en søgeterm...", "sort": "sorter", "stars": "Stjerner", diff --git a/config/custom_components/hacs/.translations/de.json b/config/custom_components/hacs/.translations/de.json index de4341e0..bfa51f14 100644 --- a/config/custom_components/hacs/.translations/de.json +++ b/config/custom_components/hacs/.translations/de.json @@ -80,6 +80,32 @@ "upgrade_all": "Hierdurch werden all diese Repositories aktualisiert. Stelle sicher, dass du die Versionshinweise vorher gelesen hast.", "yes": "Ja" }, + "dialog_add_repo": { + "sort_by": "Sortiere nach" + }, + "dialog_install": { + "restart": "Denken Sie daran, dass Sie Home Assistant neu starten müssen, bevor Änderungen an Integrationen (custom_components) angewendet werden." + }, + "entry": { + "messages": { + "resources": { + "content": "Sie haben {number} Lovelace-Elemente, die in Lovelace nicht richtig geladen sind.", + "title": "Nicht in Lovelace geladen" + }, + "restart": { + "content": "Sie haben {number} -Integrationen, die einen Neustart von Home Assistant erfordern. Dies können Sie im Abschnitt 'Server Controls' im Konfigurationsteil der Home Assistant-Benutzeroberfläche tun.", + "title": "Ausstehender Neustart" + }, + "wrong_frontend_installed": { + "content": "Sie haben {running} des HACS-Frontends installiert, aber Version {expected} wurde erwartet. Wenn diese Meldung angezeigt wird, dass Home Assistant die neue Version nicht installieren konnte, starten Sie Home Assistant neu.", + "title": "Unerwartete Frontend-Version" + }, + "wrong_frontend_loaded": { + "content": "Sie führen die Version {running} des HACS-Frontends aus, aber es wurde die Version {expected} erwartet. Sie sollten Ihren Browser-Cache leeren.", + "title": "Unerwartete Frontend-Version" + } + } + }, "menu": { "dismiss": "Alle neuen Repositories ausblenden" }, @@ -111,7 +137,11 @@ "restart_pending": "Neustart ausstehend" }, "repository_card": { - "dismiss": "Ausblenden" + "dismiss": "Ausblenden", + "not_loaded": "Nicht geladen", + "open_source": "Quelldateien öffnen", + "pending_restart": "Ausstehender Neustart", + "report": "Melden zur Entfernung des Repositorys" }, "repository": { "add_to_lovelace": "Zu Lovelace hinzufügen", diff --git a/config/custom_components/hacs/.translations/el.json b/config/custom_components/hacs/.translations/el.json index 25baa2c4..1761e67d 100644 --- a/config/custom_components/hacs/.translations/el.json +++ b/config/custom_components/hacs/.translations/el.json @@ -15,7 +15,7 @@ "manage": "διαχειρίζονται", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDaemon Apps", - "plugin": "Πρόσθετο", + "plugin": "Lovelace", "plugins": "Πρόσθετα", "python_script": "Πρόγραμμα Python", "python_scripts": "Προγράμματα Python", diff --git a/config/custom_components/hacs/.translations/en.json b/config/custom_components/hacs/.translations/en.json index c5e50ac1..46dd4e25 100644 --- a/config/custom_components/hacs/.translations/en.json +++ b/config/custom_components/hacs/.translations/en.json @@ -140,9 +140,25 @@ "content": "Some repositories might not show untill this is completed", "title": "Background tasks pending" }, + "resources": { + "content": "You have {number} Lovelace elements that are not loaded properly in Lovelace.", + "title": "Not loaded in Lovelace" + }, + "restart": { + "content": "You have {number} integrations that requires a restart of Home Assistant, you can do that from the 'Server Controls' section under the configuration part of Home Assistant UI.", + "title": "Pending restart" + }, "startup": { "content": "HACS is starting up, during this time some information might be missing or incorrect", "title": "HACS is starting up" + }, + "wrong_frontend_installed": { + "content": "You have {running} of the HACS frontend installed, but version {expected} was expected, if this you see this message Home Assistant was not able to install the new version, try restarting Home Assistant.", + "title": "Unexpected frontend version" + }, + "wrong_frontend_loaded": { + "content": "You are running version {running} of the HACS frontend, but version {expected} was expected, you should clear your browser cache.", + "title": "Unexpected frontend version" } }, "pending_updates": "Pending updates" @@ -188,8 +204,10 @@ "hide": "Hide", "information": "Information", "new_repository": "New repository", + "not_loaded": "Not loaded", "open_issue": "Open issue", "open_source": "Open source", + "pending_restart": "Pending restart", "pending_update": "Pending update", "reinstall": "Reinstall", "report": "Report for removal", @@ -286,6 +304,8 @@ "no_repositories": "No repositories", "no_repositories_desc1": "It seems like you don't have any repositories installed in this section yet.", "no_repositories_desc2": "Click on the + in the bottom corner to add your first!", + "no_repositories_found_desc1": "No installed repositories matching \"{searchInput}\" found in this section.", + "no_repositories_found_desc2": "Try searching for something else!", "pending_upgrades": "Pending upgrades", "placeholder_search": "Please enter a search term...", "sort": "sort", diff --git a/config/custom_components/hacs/.translations/fr.json b/config/custom_components/hacs/.translations/fr.json index c4c5d44b..b7c16105 100644 --- a/config/custom_components/hacs/.translations/fr.json +++ b/config/custom_components/hacs/.translations/fr.json @@ -15,8 +15,8 @@ "manage": "gérer", "netdaemon": "NetDaemon", "netdaemon_apps": "Applications NetDaemon", - "plugin": "Plugin", - "plugins": "Plugins", + "plugin": "Lovelace", + "plugins": "Éléments Lovelace", "python_script": "Script Python", "python_scripts": "Scripts Python", "repositories": "Dépôts", diff --git a/config/custom_components/hacs/.translations/hu.json b/config/custom_components/hacs/.translations/hu.json index 91d4c37f..ae56280c 100644 --- a/config/custom_components/hacs/.translations/hu.json +++ b/config/custom_components/hacs/.translations/hu.json @@ -76,7 +76,7 @@ "home_assistant_is_restarting": "Várj, a Home Assistant éppen újraindul.", "home_assistant_version_not_correct": "A Home Assistant '{haversion}' verzióját használod, de ehhez a tárolóhoz legalább a(z) '{minversion}' verzióra van szükség.", "no": "Nem", - "no_upgrades": "Nincs függőben lévő frissítés", + "no_upgrades": "Nincsenek elérhető frissítések", "ok": "OK", "overwrite": "Ezzel felül fogod írni.", "reload_data": "Ez újratölti a HACS által ismert összes tároló adatát, ami némi időbe telhet.", @@ -93,7 +93,8 @@ }, "dialog_add_repo": { "limit": "Csak az első 100 tároló jelenik meg, használd a keresőt a találatok szűkítéséhez", - "no_match": "Nincs a szűrőnek megfelelő tároló", + "no_match": "Nincs a szűrésnek megfelelő tároló", + "sort_by": "Rendezés", "title": "Tároló hozzáadása" }, "dialog_custom_repositories": { @@ -109,11 +110,13 @@ "install": "Tároló telepítése HACS-ben", "loading": "Információ betöltése...", "no_info": "A fejlesztő nem adott meg több információt ehhez a tárolóhoz", + "open_issues": "Jelentett problémák", "open_repo": "Tároló megnyitása", "stars": "Csillagok", "version_installed": "Telepített verzió" }, "dialog_install": { + "restart": "Ne feledd, hogy az egyéni integrációk (custom_components) módosításainak alkalmazásához újra kell indítanod a Home Assistant alkalmazást.", "select_version": "Verzió kiválasztása", "show_beta": "Béta verziók megjelenítése", "type": "Típus", @@ -123,29 +126,32 @@ "available_version": "Elérhető verzió", "changelog": "Változási napló", "installed_version": "Telepített verzió", - "title": "Frissítés függőben" + "title": "Frissítés érhető el" }, "entry": { "information": "Információ", + "intro": "A frissítések és a fontos üzenetek itt jelennek meg, ha vannak", "messages": { "disabled": { "content": "További részletek a naplófájlban", "title": "A HACS le van tiltva" }, "has_pending_tasks": { + "content": "Előfordulhat, hogy egyes tárolók nem jelennek meg, amíg ez be nem fejeződik", "title": "Függőben lévő háttérfeladatok" }, "startup": { "content": "A HACS éppen indul, ezidő alatt egyes információk hiányozhatnak vagy helytelenek lehetnek", - "title": "A HACS indul" + "title": "A HACS éppen indul" } }, - "pending_updates": "Függő frissítések" + "pending_updates": "Frissítések érhetők el" }, "menu": { "about": "HACS névjegye", "clear": "Új jelölések törlése", "custom_repositories": "Egyéni tárolók", + "dismiss": "Minden új tároló elvetése", "documentation": "Dokumentáció", "open_issue": "Probléma jelentése", "reload": "Ablak újratöltése" @@ -178,15 +184,16 @@ "restart_pending": "Újraindítás függőben" }, "repository_card": { + "dismiss": "elvetés", "hide": "Elrejtés", "information": "Információ", "new_repository": "Új tároló", "open_issue": "Probléma jelentése", "open_source": "Forrás megnyitása", - "pending_update": "Függő frissítés", + "pending_update": "Frissítés érhető el", "reinstall": "Újratelepítés", "report": "Jelentés eltávolításra", - "update_information": "Frissítési információk" + "update_information": "Frissítési információ" }, "repository": { "add_to_lovelace": "Hozzáadás a Lovelace-hez", @@ -275,9 +282,11 @@ "last_updated": "Utolsó frissítés", "name": "Név", "new_repositories": "Új tárolók", - "no_repositories": "Nincs tároló", - "no_repositories_desc1": "Úgy tűnik, még nincsenek telepítve tárolók ebben a részben.", - "pending_upgrades": "Függőben lévő frissítések", + "new_repositories_note": "Több mint 10 új tároló látható. Ha törölni szeretnéd őket, akkor kattints a jobb felső sarokban lévő 3 pontra, és válaszd ki a 'Minden új tároló elvetése' menüpontot.", + "no_repositories": "Nincsenek tárolók", + "no_repositories_desc1": "Úgy tűnik, még nincsenek telepítve tárolók ebben a szekcióban.", + "no_repositories_desc2": "Kattints az alsó sarokban található + jelre az első hozzáadásához!", + "pending_upgrades": "Frissítések érhetők el", "placeholder_search": "Kérlek adj meg egy keresési kifejezést...", "sort": "rendezés", "stars": "Csillag", diff --git a/config/custom_components/hacs/.translations/it.json b/config/custom_components/hacs/.translations/it.json index c386ee87..4b028832 100644 --- a/config/custom_components/hacs/.translations/it.json +++ b/config/custom_components/hacs/.translations/it.json @@ -15,7 +15,7 @@ "manage": "gestione", "netdaemon": "NetDaemon", "netdaemon_apps": "Applicazioni NetDaemon", - "plugin": "Plugin", + "plugin": "Lovelace", "plugins": "Plugin", "python_script": "Script python", "python_scripts": "Script python", diff --git a/config/custom_components/hacs/.translations/nl.json b/config/custom_components/hacs/.translations/nl.json index b092ce38..907c8441 100644 --- a/config/custom_components/hacs/.translations/nl.json +++ b/config/custom_components/hacs/.translations/nl.json @@ -15,7 +15,7 @@ "manage": "beheer", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDaemon Apps", - "plugin": "Plugin", + "plugin": "Lovelace", "plugins": "Plugins", "python_script": "Python Script", "python_scripts": "Python Scripts", diff --git a/config/custom_components/hacs/.translations/nn.json b/config/custom_components/hacs/.translations/nn.json index fe8f97b5..0bb5cb73 100644 --- a/config/custom_components/hacs/.translations/nn.json +++ b/config/custom_components/hacs/.translations/nn.json @@ -22,9 +22,9 @@ "netdaemon": "NetDaemon", "netdaemon_apps": "NetDeamon-appar", "netdaemon_plural": "NetDaemon-appar", - "plugin": "Tillegg", + "plugin": "Lovelace", "plugin_plural": "Lovelace-element", - "plugins": "Tillegg", + "plugins": "Lovelace-element", "python_script": "Pythonskript", "python_script_plural": "Pythonskript", "python_scripts": "Pythonskript", diff --git a/config/custom_components/hacs/.translations/pl.json b/config/custom_components/hacs/.translations/pl.json index 6c71e312..63147e4e 100644 --- a/config/custom_components/hacs/.translations/pl.json +++ b/config/custom_components/hacs/.translations/pl.json @@ -21,9 +21,9 @@ "netdaemon": "NetDaemon", "netdaemon_apps": "Aplikacje NetDaemon", "netdaemon_plural": "Aplikacje NetDaemon", - "plugin": "Wtyczka", + "plugin": "Lovelace", "plugin_plural": "Elementy Lovelace", - "plugins": "Wtyczki", + "plugins": "Elementy Lovelace", "python_script": "Skrypt Python", "python_script_plural": "Skrypty języka Python", "python_scripts": "Skrypty Python", @@ -131,7 +131,7 @@ "note_plugin": "musisz jeszcze dodać wtyczkę do konfiguracji interfejsu użytkownika (plik 'ui-lovelace.yaml' lub edytor interfejsu użytkownika)", "note_plugin_post_107": "nadal musisz dodać go do konfiguracji Lovelace ('configuration.yaml' lub edytora zasobów '\/config\/lovelace\/resources')", "open_issue": "Powiadom o problemie", - "open_plugin": "Otwórz dodatek", + "open_plugin": "Otwórz element", "reinstall": "Przeinstaluj", "repository": "Repozytorium", "restart_home_assistant": "Uruchom ponownie Home Assistant'a", diff --git a/config/custom_components/hacs/.translations/ru.json b/config/custom_components/hacs/.translations/ru.json index 117df45a..1fcc30e1 100644 --- a/config/custom_components/hacs/.translations/ru.json +++ b/config/custom_components/hacs/.translations/ru.json @@ -15,7 +15,7 @@ "manage": "управлять", "netdaemon": "NetDaemon", "netdaemon_apps": "Приложения NetDaemon", - "plugin": "Плагин", + "plugin": "Lovelace", "plugins": "Плагины", "python_script": "Скрипт Python", "python_scripts": "Скрипты Python", diff --git a/config/custom_components/hacs/.translations/sv.json b/config/custom_components/hacs/.translations/sv.json index 3d84d5cf..b0d8887f 100644 --- a/config/custom_components/hacs/.translations/sv.json +++ b/config/custom_components/hacs/.translations/sv.json @@ -15,7 +15,7 @@ "manage": "hantera", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDaemon Applikationer", - "plugin": "Plugin", + "plugin": "Lovelace", "plugins": "Plugins", "python_script": "Python skript", "python_scripts": "Python skript", diff --git a/config/custom_components/hacs/__init__.py b/config/custom_components/hacs/__init__.py index 236e569c..d9c89909 100644 --- a/config/custom_components/hacs/__init__.py +++ b/config/custom_components/hacs/__init__.py @@ -15,13 +15,14 @@ from homeassistant.exceptions import ConfigEntryNotReady, ServiceNotFound from homeassistant.helpers.aiohttp_client import async_create_clientsession from homeassistant.helpers.event import async_call_later -from custom_components.hacs.configuration_schema import hacs_config_combined +from custom_components.hacs.configuration_schema import hacs_config_combined, FRONTEND_REPO, FRONTEND_REPO_URL from custom_components.hacs.const import DOMAIN, ELEMENT_TYPES, STARTUP, VERSION from custom_components.hacs.constrains import check_constrains from custom_components.hacs.helpers.remaining_github_calls import get_fetch_updates_for from custom_components.hacs.hacsbase.configuration import Configuration from custom_components.hacs.hacsbase.data import HacsData from custom_components.hacs.setup import ( + clear_storage, add_sensor, load_hacs_repository, setup_frontend, @@ -41,10 +42,18 @@ async def async_setup(hass, config): return True if hacs.configuration and hacs.configuration.config_type == "flow": return True + + configuration = config[DOMAIN] + + if configuration.get(FRONTEND_REPO) and configuration.get(FRONTEND_REPO_URL): + hacs.logger.critical("Could not setup HACS, set only one of ('frontend_repo', 'frontend_repo_url)") + + return False + hass.data[DOMAIN] = config hacs.hass = hass hacs.session = async_create_clientsession(hass) - hacs.configuration = Configuration.from_dict(config[DOMAIN]) + hacs.configuration = Configuration.from_dict(configuration) hacs.configuration.config = config hacs.configuration.config_type = "yaml" await startup_wrapper_for_yaml() @@ -102,6 +111,7 @@ async def startup_wrapper_for_yaml(): async def hacs_startup(): """HACS startup tasks.""" hacs = get_hacs() + if hacs.configuration.debug: try: await hacs.hass.services.async_call( @@ -125,6 +135,8 @@ async def hacs_startup(): hacs.system.config_path = hacs.hass.config.path() hacs.system.ha_version = HAVERSION + await hacs.hass.async_add_executor_job(clear_storage) + hacs.system.lovelace_mode = lovelace_info.get("mode", "yaml") hacs.system.disabled = False hacs.github = GitHub( diff --git a/config/custom_components/hacs/config_flow.py b/config/custom_components/hacs/config_flow.py index 7f55b4c7..f531a756 100644 --- a/config/custom_components/hacs/config_flow.py +++ b/config/custom_components/hacs/config_flow.py @@ -91,5 +91,7 @@ class HacsOptionsFlowHandler(config_entries.OptionsFlow): schema = {vol.Optional("not_in_use", default=""): str} else: schema = hacs_config_option_schema(self.config_entry.options) + del schema["frontend_repo"] + del schema["frontend_repo_url"] return self.async_show_form(step_id="user", data_schema=vol.Schema(schema)) diff --git a/config/custom_components/hacs/configuration_schema.py b/config/custom_components/hacs/configuration_schema.py index 92bfe758..3a7ef0d1 100644 --- a/config/custom_components/hacs/configuration_schema.py +++ b/config/custom_components/hacs/configuration_schema.py @@ -7,6 +7,8 @@ from .const import LOCALE TOKEN = "token" SIDEPANEL_TITLE = "sidepanel_title" SIDEPANEL_ICON = "sidepanel_icon" +FRONTEND_REPO = "frontend_repo" +FRONTEND_REPO_URL = "frontend_repo_url" APPDAEMON = "appdaemon" NETDAEMON = "netdaemon" @@ -40,6 +42,8 @@ def hacs_config_option_schema(options: dict = {}) -> dict: RELEASE_LIMIT: 5, SIDEPANEL_ICON: "hacs:hacs", SIDEPANEL_TITLE: "HACS", + FRONTEND_REPO: "", + FRONTEND_REPO_URL: "", } return { vol.Optional(SIDEPANEL_TITLE, default=options.get(SIDEPANEL_TITLE)): str, @@ -50,6 +54,8 @@ def hacs_config_option_schema(options: dict = {}) -> dict: vol.Optional(NETDAEMON, default=options.get(NETDAEMON)): bool, vol.Optional(DEBUG, default=options.get(DEBUG)): bool, vol.Optional(EXPERIMENTAL, default=options.get(EXPERIMENTAL)): bool, + vol.Optional(FRONTEND_REPO, default=options.get(FRONTEND_REPO)): str, + vol.Optional(FRONTEND_REPO_URL, default=options.get(FRONTEND_REPO_URL)): str, } diff --git a/config/custom_components/hacs/const.py b/config/custom_components/hacs/const.py index ba166cdc..d3a85d4d 100644 --- a/config/custom_components/hacs/const.py +++ b/config/custom_components/hacs/const.py @@ -1,7 +1,7 @@ """Constants for HACS""" NAME_LONG = "HACS (Home Assistant Community Store)" NAME_SHORT = "HACS" -VERSION = "1.0.3" +VERSION = "1.1.0" DOMAIN = "hacs" PROJECT_URL = "https://github.com/hacs/integration/" CUSTOM_UPDATER_LOCATIONS = [ diff --git a/config/custom_components/hacs/hacsbase/__init__.py b/config/custom_components/hacs/hacsbase/__init__.py index 35a4fb94..3cd9f2f4 100644 --- a/config/custom_components/hacs/hacsbase/__init__.py +++ b/config/custom_components/hacs/hacsbase/__init__.py @@ -42,6 +42,7 @@ class HacsFrontend: version_running = None version_available = None + version_expected = None update_pending = False diff --git a/config/custom_components/hacs/hacsbase/configuration.py b/config/custom_components/hacs/hacsbase/configuration.py index 91dfb0f5..2b1bbb3c 100644 --- a/config/custom_components/hacs/hacsbase/configuration.py +++ b/config/custom_components/hacs/hacsbase/configuration.py @@ -20,6 +20,8 @@ class Configuration: dev: bool = False frontend_mode: str = "Grid" frontend_compact: bool = False + frontend_repo: str = "" + frontend_repo_url: str = "" options: dict = {} onboarding_done: bool = False plugin_path: str = "www/community/" diff --git a/config/custom_components/hacs/helpers/information.py b/config/custom_components/hacs/helpers/information.py index 003497cd..a6dc13b6 100644 --- a/config/custom_components/hacs/helpers/information.py +++ b/config/custom_components/hacs/helpers/information.py @@ -1,6 +1,7 @@ """Return repository information if any.""" import json from aiogithubapi import AIOGitHubAPIException, GitHub +from custom_components.hacs.globals import get_hacs from custom_components.hacs.handler.template import render_template from custom_components.hacs.hacsbase.exceptions import HacsException @@ -63,6 +64,28 @@ async def get_releases(repository, prerelease=False, returnlimit=5): raise HacsException(exception) +def get_frontend_version(): + """get the frontend version from the manifest.""" + manifest = read_hacs_manifest() + frontend = 0 + for requirement in manifest.get("requirements", []): + if requirement.startswith("hacs_frontend"): + frontend = requirement.split("==")[1] + break + return frontend + + +def read_hacs_manifest(): + """Reads the HACS manifest file and returns the contents.""" + hacs = get_hacs() + content = {} + with open( + f"{hacs.system.config_path}/custom_components/hacs/manifest.json" + ) as manifest: + content = json.loads(manifest.read()) + return content + + async def get_integration_manifest(repository): """Return the integration manifest.""" if repository.data.content_in_root: diff --git a/config/custom_components/hacs/helpers/install.py b/config/custom_components/hacs/helpers/install.py index ba8ff4e3..281ce011 100644 --- a/config/custom_components/hacs/helpers/install.py +++ b/config/custom_components/hacs/helpers/install.py @@ -1,7 +1,6 @@ """Install helper for repositories.""" import os import tempfile -from custom_components.hacs.globals import get_hacs from custom_components.hacs.hacsbase.exceptions import HacsException from custom_components.hacs.hacsbase.backup import Backup, BackupNetDaemon from custom_components.hacs.helpers.download import download_content @@ -74,42 +73,6 @@ async def install_repository(repository): else: repository.data.installed_version = version - await reload_after_install(repository) - installation_complete(repository) - - -async def reload_after_install(repository): - """Reload action after installation success.""" - if repository.data.category == "integration": - if repository.data.config_flow: - if repository.data.full_name != "hacs/integration": - await repository.reload_custom_components() - repository.pending_restart = True - - elif repository.data.category == "theme": - try: - await repository.hacs.hass.services.async_call( - "frontend", "reload_themes", {} - ) - except Exception: # pylint: disable=broad-except - pass - elif repository.data.category == "netdaemon": - try: - await repository.hacs.hass.services.async_call( - "hassio", "addon_restart", {"addon": "c6a2317c_netdaemon"} - ) - except Exception: # pylint: disable=broad-except - pass - - -def installation_complete(repository): - """Action to run when the installation is complete.""" - hacs = get_hacs() - hacs.hass.bus.async_fire( - "hacs/repository", - {"id": 1337, "action": "install", "repository": repository.data.full_name}, - ) - def version_to_install(repository): """Determine which version to isntall.""" diff --git a/config/custom_components/hacs/helpers/register_repository.py b/config/custom_components/hacs/helpers/register_repository.py index 9eebebb9..ff38be8a 100644 --- a/config/custom_components/hacs/helpers/register_repository.py +++ b/config/custom_components/hacs/helpers/register_repository.py @@ -5,7 +5,6 @@ from custom_components.hacs.hacsbase.exceptions import ( HacsException, HacsExpectedException, ) -from queueman import concurrent # @concurrent(15, 5) @@ -27,7 +26,7 @@ async def register_repository(full_name, category, check=True, ref=None, action= repository = RERPOSITORY_CLASSES[category](full_name) if check: try: - await repository.registration(ref) + await repository.async_registration(ref) if hacs.system.status.new: repository.data.new = False if repository.validate.errors: diff --git a/config/custom_components/hacs/http.py b/config/custom_components/hacs/http.py index 721b098e..3beff370 100644 --- a/config/custom_components/hacs/http.py +++ b/config/custom_components/hacs/http.py @@ -7,6 +7,8 @@ from hacs_frontend import locate_gz, locate_debug_gz from custom_components.hacs.globals import get_hacs +IGNORE = ["class-map.js.map"] + class HacsFrontend(HomeAssistantView): """Base View Class for HACS.""" @@ -24,15 +26,37 @@ async def get_file_response(requested_file): """Get file.""" hacs = get_hacs() + if requested_file in IGNORE: + hacs.logger.debug(f"Ignoring request for {requested_file}") + return web.Response(status=200) + if requested_file.startswith("frontend-"): if hacs.configuration.debug: servefile = await hacs.hass.async_add_executor_job(locate_debug_gz) hacs.logger.debug("Serving DEBUG frontend") + elif hacs.configuration.frontend_repo_url: + hacs.logger.debug("Serving REMOTE DEVELOPMENT frontend") + request = await hacs.session.get(f"{hacs.configuration.frontend_repo_url}/main.js") + if request.status == 200: + result = await request.read() + response = web.Response(body=result) + response.headers["Cache-Control"] = "no-store, max-age=0" + response.headers["Pragma"] = "no-store" + return response + elif hacs.configuration.frontend_repo: + hacs.logger.debug("Serving LOCAL DEVELOPMENT frontend") + servefile = f"{hacs.configuration.frontend_repo}/hacs_frontend/main.js" else: servefile = await hacs.hass.async_add_executor_job(locate_gz) if os.path.exists(servefile): - return web.FileResponse(servefile) + response = web.FileResponse(servefile) + if hacs.configuration.frontend_repo: + response.headers["Cache-Control"] = "no-store, max-age=0" + response.headers["Pragma"] = "no-store" + + return response + elif requested_file == "iconset.js": return web.FileResponse( f"{hacs.system.config_path}/custom_components/hacs/iconset.js" diff --git a/config/custom_components/hacs/manifest.json b/config/custom_components/hacs/manifest.json index 84b2f999..9f449cd2 100644 --- a/config/custom_components/hacs/manifest.json +++ b/config/custom_components/hacs/manifest.json @@ -8,13 +8,14 @@ "lovelace" ], "documentation": "https://hacs.xyz/docs/configuration/start", + "issue_tracker": "https://github.com/hacs/integration/issues", "domain": "hacs", "name": "HACS", "requirements": [ "aiofiles==0.5.0", "aiogithubapi==1.0.4", "backoff==1.10.0", - "hacs_frontend==202005242033", + "hacs_frontend==202006071141", "integrationhelper==0.2.2", "semantic_version==2.8.5", "queueman==0.5" diff --git a/config/custom_components/hacs/repositories/appdaemon.py b/config/custom_components/hacs/repositories/appdaemon.py index 7a34fdce..c495a487 100644 --- a/config/custom_components/hacs/repositories/appdaemon.py +++ b/config/custom_components/hacs/repositories/appdaemon.py @@ -50,20 +50,6 @@ class HacsAppdaemon(HacsRepository): self.logger.error(error) return self.validate.success - async def registration(self, ref=None): - """Registration.""" - if ref is not None: - self.ref = ref - self.force_branch = True - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - - # Set local path - self.content.path.local = self.localpath - async def update_repository(self, ignore_issues=False): """Update.""" await self.common_update(ignore_issues) diff --git a/config/custom_components/hacs/repositories/integration.py b/config/custom_components/hacs/repositories/integration.py index 2aa6f641..33020301 100644 --- a/config/custom_components/hacs/repositories/integration.py +++ b/config/custom_components/hacs/repositories/integration.py @@ -1,4 +1,5 @@ """Class for integrations in HACS.""" +# pylint: disable=attribute-defined-outside-init from integrationhelper import Logger from homeassistant.loader import async_get_custom_components @@ -6,7 +7,6 @@ from homeassistant.loader import async_get_custom_components from custom_components.hacs.hacsbase.exceptions import HacsException from custom_components.hacs.helpers.filters import get_first_directory_in_directory from custom_components.hacs.helpers.information import get_integration_manifest -from custom_components.hacs.helpers.action import run_action_checks from custom_components.hacs.repositories.repository import HacsRepository @@ -27,6 +27,16 @@ class HacsIntegration(HacsRepository): """Return localpath.""" return f"{self.hacs.system.config_path}/custom_components/{self.data.domain}" + async def async_post_installation(self): + """Run post installation steps.""" + if self.data.config_flow: + if self.data.full_name != "hacs/integration": + await self.reload_custom_components() + if self.data.first_install: + self.pending_restart = False + return + self.pending_restart = True + async def validate_repository(self): """Validate.""" await self.common_validate() @@ -50,9 +60,6 @@ class HacsIntegration(HacsRepository): raise HacsException(exception) self.logger.error(exception) - if self.hacs.action: - await run_action_checks(self) - # Handle potential errors if self.validate.errors: for error in self.validate.errors: @@ -60,20 +67,6 @@ class HacsIntegration(HacsRepository): self.logger.error(error) return self.validate.success - async def registration(self, ref=None): - """Registration.""" - if ref is not None: - self.ref = ref - self.force_branch = True - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - - # Set local path - self.content.path.local = self.localpath - async def update_repository(self, ignore_issues=False): """Update.""" await self.common_update(ignore_issues) @@ -98,3 +91,4 @@ class HacsIntegration(HacsRepository): self.logger.info("Reloading custom_component cache") del self.hacs.hass.data["custom_components"] await async_get_custom_components(self.hacs.hass) + self.logger.info("Custom_component cache reloaded") diff --git a/config/custom_components/hacs/repositories/netdaemon.py b/config/custom_components/hacs/repositories/netdaemon.py index 3691acb3..83a5e132 100644 --- a/config/custom_components/hacs/repositories/netdaemon.py +++ b/config/custom_components/hacs/repositories/netdaemon.py @@ -58,20 +58,6 @@ class HacsNetdaemon(HacsRepository): self.logger.error(error) return self.validate.success - async def registration(self, ref=None): - """Registration.""" - if ref is not None: - self.ref = ref - self.force_branch = True - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - - # Set local path - self.content.path.local = self.localpath - async def update_repository(self, ignore_issues=False): """Update.""" await self.common_update(ignore_issues) @@ -89,3 +75,12 @@ class HacsNetdaemon(HacsRepository): # Set local path self.content.path.local = self.localpath + + async def async_post_installation(self): + """Run post installation steps.""" + try: + await self.hacs.hass.services.async_call( + "hassio", "addon_restart", {"addon": "c6a2317c_netdaemon"} + ) + except Exception: # pylint: disable=broad-except + pass diff --git a/config/custom_components/hacs/repositories/plugin.py b/config/custom_components/hacs/repositories/plugin.py index a0b2db08..6fe164c1 100644 --- a/config/custom_components/hacs/repositories/plugin.py +++ b/config/custom_components/hacs/repositories/plugin.py @@ -2,10 +2,9 @@ import json from integrationhelper import Logger -from .repository import HacsRepository -from ..hacsbase.exceptions import HacsException - +from custom_components.hacs.hacsbase.exceptions import HacsException from custom_components.hacs.helpers.information import find_file_name +from custom_components.hacs.repositories.repository import HacsRepository class HacsPlugin(HacsRepository): @@ -18,11 +17,14 @@ class HacsPlugin(HacsRepository): self.data.file_name = None self.data.category = "plugin" self.information.javascript_type = None - self.content.path.local = ( - f"{self.hacs.system.config_path}/www/community/{full_name.split('/')[-1]}" - ) + self.content.path.local = self.localpath self.logger = Logger(f"hacs.repository.{self.data.category}.{full_name}") + @property + def localpath(self): + """Return localpath.""" + return f"{self.hacs.system.config_path}/www/community/{self.data.full_name.split('/')[-1]}" + async def validate_repository(self): """Validate.""" # Run common validation steps. @@ -46,17 +48,6 @@ class HacsPlugin(HacsRepository): self.logger.error(error) return self.validate.success - async def registration(self, ref=None): - """Registration.""" - if ref is not None: - self.ref = ref - self.force_branch = True - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - async def update_repository(self, ignore_issues=False): """Update.""" await self.common_update(ignore_issues) @@ -65,7 +56,9 @@ class HacsPlugin(HacsRepository): find_file_name(self) if self.content.path.remote is None: - self.validate.errors.append("Repostitory structure not compliant") + self.validate.errors.append( + f"Repostitory structure for {self.ref.replace('tags/','')} is not compliant" + ) if self.content.path.remote == "release": self.content.single = True diff --git a/config/custom_components/hacs/repositories/python_script.py b/config/custom_components/hacs/repositories/python_script.py index 2440dd46..5ee1ecfe 100644 --- a/config/custom_components/hacs/repositories/python_script.py +++ b/config/custom_components/hacs/repositories/python_script.py @@ -17,10 +17,15 @@ class HacsPythonScript(HacsRepository): self.data.full_name = full_name self.data.category = "python_script" self.content.path.remote = "python_scripts" - self.content.path.local = f"{self.hacs.system.config_path}/python_scripts" + self.content.path.local = self.localpath self.content.single = True self.logger = Logger(f"hacs.repository.{self.data.category}.{full_name}") + @property + def localpath(self): + """Return localpath.""" + return f"{self.hacs.system.config_path}/python_scripts" + async def validate_repository(self): """Validate.""" # Run common validation steps. @@ -49,17 +54,8 @@ class HacsPythonScript(HacsRepository): self.logger.error(error) return self.validate.success - async def registration(self, ref=None): + async def async_post_registration(self): """Registration.""" - if ref is not None: - self.ref = ref - self.force_branch = True - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - # Set name find_file_name(self) diff --git a/config/custom_components/hacs/repositories/removed.py b/config/custom_components/hacs/repositories/removed.py index 69955ebe..c8a45bad 100644 --- a/config/custom_components/hacs/repositories/removed.py +++ b/config/custom_components/hacs/repositories/removed.py @@ -15,3 +15,7 @@ class RemovedRepository: for key in data: if key in self.__dict__: setattr(self, key, data[key]) + + def to_json(self): + """Return a JSON representation of the data.""" + return self.__dict__ diff --git a/config/custom_components/hacs/repositories/repository.py b/config/custom_components/hacs/repositories/repository.py index 8e6bb95e..bfb187db 100644 --- a/config/custom_components/hacs/repositories/repository.py +++ b/config/custom_components/hacs/repositories/repository.py @@ -9,9 +9,9 @@ from aiogithubapi import AIOGitHubAPIException from .manifest import HacsManifest from ..helpers.misc import get_repository_name from ..handler.download import async_download_file, async_save_file -from ..helpers.misc import version_left_higher_then_right -from ..helpers.install import install_repository, version_to_install +from ..helpers.install import version_to_install +from custom_components.hacs.repositories.helpers import RepositoryHelpers from custom_components.hacs.hacsbase.exceptions import HacsException from custom_components.hacs.store import async_remove_store from custom_components.hacs.globals import get_hacs @@ -98,7 +98,7 @@ class RepositoryContent: single = False -class HacsRepository: +class HacsRepository(RepositoryHelpers): """HacsRepository.""" def __init__(self): @@ -122,49 +122,6 @@ class HacsRepository: self.treefiles = [] self.ref = None - @property - def pending_upgrade(self): - """Return pending upgrade.""" - if not self.can_install: - return False - if self.data.installed: - if self.data.selected_tag is not None: - if self.data.selected_tag == self.data.default_branch: - if self.data.installed_commit != self.data.last_commit: - return True - return False - if self.display_installed_version != self.display_available_version: - return True - return False - - @property - def custom(self): - """Return flag if the repository is custom.""" - if self.data.full_name.split("/")[0] in ["custom-components", "custom-cards"]: - return False - if str(self.data.id) in [str(x) for x in self.hacs.common.default]: - return False - if self.data.full_name == "hacs/integration": - return False - return True - - @property - def can_install(self): - """Return bool if repository can be installed.""" - target = None - if self.data.homeassistant is not None: - target = self.data.homeassistant - if self.data.homeassistant is not None: - target = self.data.homeassistant - - if target is not None: - if self.data.releases: - if not version_left_higher_then_right( - self.hacs.system.ha_version, target - ): - return False - return True - @property def display_name(self): """Return display name.""" @@ -288,10 +245,6 @@ class HacsRepository: # Update "info.md" self.information.additional_info = await get_info_md_content(self) - async def install(self): - """Common installation steps of the repository.""" - await install_repository(self) - async def download_zip(self, validate): """Download ZIP archive from repository release.""" try: @@ -353,6 +306,8 @@ class HacsRepository: json.loads(manifest.content) ) self.data.update_data(json.loads(manifest.content)) + if self.hacs.action: + self.logger.info(json.loads(manifest.content)) except (AIOGitHubAPIException, Exception) as exception: # Gotta Catch 'Em All if self.hacs.action: raise HacsException(f"hacs.json file is not valid ({exception}).") diff --git a/config/custom_components/hacs/repositories/theme.py b/config/custom_components/hacs/repositories/theme.py index a631f1c9..94131def 100644 --- a/config/custom_components/hacs/repositories/theme.py +++ b/config/custom_components/hacs/repositories/theme.py @@ -14,10 +14,23 @@ class HacsTheme(HacsRepository): self.data.full_name = full_name self.data.category = "theme" self.content.path.remote = "themes" - self.content.path.local = f"{self.hacs.system.config_path}/themes/" + self.content.path.local = self.localpath self.content.single = False self.logger = Logger(f"hacs.repository.{self.data.category}.{full_name}") + @property + def localpath(self): + """Return localpath.""" + return f"{self.hacs.system.config_path}/themes/{self.data.file_name.replace('.yaml', '')}" + + async def async_post_installation(self): + """Run post installation steps.""" + try: + await self.hacs.hass.services.async_call("frontend", "reload_themes", {}) + self.logger.info("Themes reloaded") + except Exception: # pylint: disable=broad-except + pass + async def validate_repository(self): """Validate.""" # Run common validation steps. @@ -44,20 +57,11 @@ class HacsTheme(HacsRepository): self.logger.error(error) return self.validate.success - async def registration(self, ref=None): + async def async_post_registration(self): """Registration.""" - if ref is not None: - self.ref = ref - self.force_branch = True - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - # Set name find_file_name(self) - self.content.path.local = f"{self.hacs.system.config_path}/themes/{self.data.file_name.replace('.yaml', '')}" + self.content.path.local = self.localpath async def update_repository(self, ignore_issues=False): """Update.""" @@ -69,4 +73,4 @@ class HacsTheme(HacsRepository): # Update name find_file_name(self) - self.content.path.local = f"{self.hacs.system.config_path}/themes/{self.data.file_name.replace('.yaml', '')}" + self.content.path.local = self.localpath diff --git a/config/custom_components/hacs/setup.py b/config/custom_components/hacs/setup.py index 746b5d98..3d21aa7f 100644 --- a/config/custom_components/hacs/setup.py +++ b/config/custom_components/hacs/setup.py @@ -1,15 +1,30 @@ """Setup functions for HACS.""" # pylint: disable=bad-continuation +import os from hacs_frontend.version import VERSION as FE_VERSION from homeassistant.helpers import discovery from custom_components.hacs.hacsbase.exceptions import HacsException from custom_components.hacs.const import VERSION, DOMAIN from custom_components.hacs.globals import get_hacs -from custom_components.hacs.helpers.information import get_repository +from custom_components.hacs.helpers.information import ( + get_repository, + get_frontend_version, +) from custom_components.hacs.helpers.register_repository import register_repository +def clear_storage(): + """Clear old files from storage.""" + hacs = get_hacs() + storagefiles = ["hacs"] + for s_f in storagefiles: + path = f"{hacs.system.config_path}/.storage/{s_f}" + if os.path.isfile(path): + hacs.logger.info(f"Cleaning up old storage file {path}") + os.remove(path) + + async def load_hacs_repository(): """Load HACS repositroy.""" hacs = get_hacs() @@ -79,6 +94,9 @@ async def setup_frontend(): hacs.hass.http.register_view(HacsFrontend()) hacs.frontend.version_running = FE_VERSION + hacs.frontend.version_expected = await hacs.hass.async_add_executor_job( + get_frontend_version + ) # Add to sidepanel custom_panel_config = { diff --git a/config/custom_components/hacs/ws_api_handlers.py b/config/custom_components/hacs/ws_api_handlers.py index ec982058..9bb4ee81 100644 --- a/config/custom_components/hacs/ws_api_handlers.py +++ b/config/custom_components/hacs/ws_api_handlers.py @@ -9,7 +9,7 @@ import homeassistant.helpers.config_validation as cv from .hacsbase.exceptions import HacsException from .store import async_load_from_store, async_save_to_store -from custom_components.hacs.globals import get_hacs +from custom_components.hacs.globals import get_hacs, removed_repositories from custom_components.hacs.helpers.register_repository import register_repository @@ -22,6 +22,7 @@ async def setup_ws_api(hass): websocket_api.async_register_command(hass, hacs_repository_data) websocket_api.async_register_command(hass, check_local_path) websocket_api.async_register_command(hass, hacs_status) + websocket_api.async_register_command(hass, hacs_removed) websocket_api.async_register_command(hass, acknowledge_critical_repository) websocket_api.async_register_command(hass, get_critical_repositories) @@ -31,7 +32,7 @@ async def setup_ws_api(hass): { vol.Required("type"): "hacs/settings", vol.Optional("action"): cv.string, - vol.Optional("category"): cv.string, + vol.Optional("categories"): cv.ensure_list, } ) async def hacs_settings(hass, connection, msg): @@ -70,7 +71,7 @@ async def hacs_settings(hass, connection, msg): elif action == "clear_new": for repo in hacs.repositories: - if repo.data.new: + if repo.data.new and repo.data.category in msg.get("categories", []): hacs.logger.debug(f"Clearing new flag from '{repo.data.full_name}'") repo.data.new = False else: @@ -92,6 +93,8 @@ async def hacs_config(hass, connection, msg): content["frontend_compact"] = config.frontend_compact content["onboarding_done"] = config.onboarding_done content["version"] = hacs.version + content["frontend_expected"] = hacs.frontend.version_expected + content["frontend_running"] = hacs.frontend.version_running content["dev"] = config.dev content["debug"] = config.debug content["country"] = config.country @@ -118,6 +121,16 @@ async def hacs_status(hass, connection, msg): connection.send_message(websocket_api.result_message(msg["id"], content)) +@websocket_api.async_response +@websocket_api.websocket_command({vol.Required("type"): "hacs/removed"}) +async def hacs_removed(hass, connection, msg): + """Get information about removed repositories.""" + content = [] + for repo in removed_repositories: + content.append(repo.to_json()) + connection.send_message(websocket_api.result_message(msg["id"], content)) + + @websocket_api.async_response @websocket_api.websocket_command({vol.Required("type"): "hacs/repositories"}) async def hacs_repositories(hass, connection, msg): @@ -201,6 +214,7 @@ async def hacs_repository(hass, connection, msg): repository.status.updated_info = True elif action == "install": + repository.data.new = False was_installed = repository.data.installed await repository.install() if not was_installed: @@ -210,6 +224,7 @@ async def hacs_repository(hass, connection, msg): repository.data.new = False elif action == "uninstall": + repository.data.new = False await repository.uninstall() elif action == "hide": @@ -249,16 +264,15 @@ async def hacs_repository(hass, connection, msg): await hacs.data.async_write() message = None except AIOGitHubAPIException as exception: - message = str(exception) - hass.bus.async_fire("hacs/error", {"message": str(exception)}) + message = exception except AttributeError as exception: message = f"Could not use repository with ID {repo_id} ({exception})" except Exception as exception: # pylint: disable=broad-except - message = str(exception) + message = exception if message is not None: hacs.logger.error(message) - hass.bus.async_fire("hacs/error", {"message": message}) + hass.bus.async_fire("hacs/error", {"message": str(exception)}) repository.state = None connection.send_message(websocket_api.result_message(msg["id"], {})) @@ -322,30 +336,43 @@ async def hacs_repository_data(hass, connection, msg): return hacs.logger.debug(f"Running {action} for {repository.data.full_name}") + try: + if action == "set_state": + repository.state = data - if action == "set_state": - repository.state = data + elif action == "set_version": + repository.data.selected_tag = data + await repository.update_repository() - elif action == "set_version": - repository.data.selected_tag = data - await repository.update_repository() - repository.state = None + repository.state = None - elif action == "install": - was_installed = repository.data.installed - repository.data.selected_tag = data - await repository.update_repository() - await repository.install() - repository.state = None - if not was_installed: - hass.bus.async_fire("hacs/reload", {"force": True}) + elif action == "install": + was_installed = repository.data.installed + repository.data.selected_tag = data + await repository.update_repository() + await repository.install() + repository.state = None + if not was_installed: + hass.bus.async_fire("hacs/reload", {"force": True}) - elif action == "add": - repository.state = None + elif action == "add": + repository.state = None - else: - repository.state = None - hacs.logger.error(f"WS action '{action}' is not valid") + else: + repository.state = None + hacs.logger.error(f"WS action '{action}' is not valid") + + message = None + except AIOGitHubAPIException as exception: + message = exception + except AttributeError as exception: + message = f"Could not use repository with ID {repo_id} ({exception})" + except Exception as exception: # pylint: disable=broad-except + message = exception + + if message is not None: + hacs.logger.error(message) + hass.bus.async_fire("hacs/error", {"message": str(exception)}) await hacs.data.async_write() connection.send_message(websocket_api.result_message(msg["id"], {})) diff --git a/config/packages/alexa_media_player.yaml b/config/packages/alexa_media_player.yaml new file mode 100755 index 00000000..1b9ef851 --- /dev/null +++ b/config/packages/alexa_media_player.yaml @@ -0,0 +1,33 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +# Alexa Media Sensor Support - Relies on Custom Component +#------------------------------------------- + +sensor: + - platform: template + sensors: + last_alexa: + entity_id: + - media_player.bedroom + - media_player.carlos_2nd_echo + - media_player.front_room_flex + - media_player.justin_room + - media_player.kitchen + - media_player.living_room + - media_player.master_bathroom + - media_player.master_bedroom + - media_player.office + - media_player.paige_room + - media_player.tap + - media_player.upstairs + value_template: > + {{ states.media_player | selectattr('attributes.last_called','eq',True) | map(attribute='entity_id') | first }} + +#------------------------------------------- + +############################################################################## +### Automations - Detect when things are not right. Like any Good Watchdog. +############################################################################## +#automation: +#Tweets pushed out to twitter.