Add in Alexa Last used Sensor. #768

This commit is contained in:
ccostan 2020-06-07 14:29:26 -04:00
parent f9094e57d4
commit 93c5bb6837
34 changed files with 441 additions and 233 deletions

View File

@ -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",

View File

@ -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",

View File

@ -15,7 +15,7 @@
"manage": "διαχειρίζονται",
"netdaemon": "NetDaemon",
"netdaemon_apps": "NetDaemon Apps",
"plugin": "Πρόσθετο",
"plugin": "Lovelace",
"plugins": "Πρόσθετα",
"python_script": "Πρόγραμμα Python",
"python_scripts": "Προγράμματα Python",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -15,7 +15,7 @@
"manage": "управлять",
"netdaemon": "NetDaemon",
"netdaemon_apps": "Приложения NetDaemon",
"plugin": "Плагин",
"plugin": "Lovelace",
"plugins": "Плагины",
"python_script": "Скрипт Python",
"python_scripts": "Скрипты Python",

View File

@ -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",

View File

@ -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(

View File

@ -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))

View File

@ -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,
}

View File

@ -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 = [

View File

@ -42,6 +42,7 @@ class HacsFrontend:
version_running = None
version_available = None
version_expected = None
update_pending = False

View File

@ -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/"

View File

@ -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:

View File

@ -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."""

View File

@ -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:

View File

@ -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"

View File

@ -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"

View File

@ -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)

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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__

View File

@ -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}).")

View File

@ -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

View File

@ -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 = {

View File

@ -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,13 +336,14 @@ 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
elif action == "set_version":
repository.data.selected_tag = data
await repository.update_repository()
repository.state = None
elif action == "install":
@ -347,6 +362,18 @@ async def hacs_repository_data(hass, connection, msg):
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"], {}))

View File

@ -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.