This commit is contained in:
2023-02-26 11:43:30 +01:00
parent 5128fa7358
commit 29a74e2546
198 changed files with 17865 additions and 20642 deletions

View File

@@ -1 +1 @@
2022.12.8
2023.2.5

35
airsonos.xml Normal file
View File

@@ -0,0 +1,35 @@
<?xml version="1.0"?>
<main_log>info</main_log>
<upnp_log>info</upnp_log>
<util_log>warn</util_log>
<raop_log>info</raop_log>
<log_limit>-1</log_limit>
<max_players>32</max_players>
<binding>?</binding>
<ports>0:0</ports>
<enabled>1</enabled>
<max_volume>100</max_volume>
<http_length>-1</http_length>
<upnp_max>1</upnp_max>
<codec>flc</codec>
<metadata>1</metadata>
<flush>1</flush>
<artwork></artwork>
<latency>1000:2000</latency>
<drift>0</drift>
<pcm>http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000</pcm>
<wav>http-get:*:audio/wav:DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000</wav>
<flac>http-get:*:audio/flac:DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000</flac>
<mp3>http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000</mp3>
<device>
<udn>uuid:RINCON_38420B93464001400</udn>
<name>Keuken+</name>
<mac>bb:bb:0b:93:46:40</mac>
<enabled>1</enabled>
</device>
<device>
<udn>uuid:BO5EBO5E-F00D-F00D-FEED-506583CEC197</udn>
<name>Bose woonkamer+</name>
<mac>bb:bb:7f:f3:34:e1</mac>
<enabled>1</enabled>
</device>

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,9 @@
script: !include scripts.yaml
scene: !include scenes.yaml
frontend:
themes: !include_dir_merge_named themes/
homeassistant:
#packages: !include_dir_named packages/
packages: !include_dir_named "integrations"

View File

@@ -15,7 +15,7 @@ SENSOR_TYPES = {
SENSOR_LOCATIONS_TO_URL = {
"trashapi": [
"http://trashapi.azurewebsites.net/trash?Location={0}&ZipCode={1}&HouseNumber={2}&HouseNumberSuffix={3}&DiftarCode={4}"
"http://trashapi.azurewebsites.net/trash?Location={0}&ZipCode={1}&HouseNumber={2}&HouseNumberSuffix={3}&District={4}&DiftarCode={5}&ShowWholeYear={6}"
]
}
@@ -66,6 +66,8 @@ CONF_LOCATION = "location"
CONF_POSTCODE = "postcode"
CONF_STREET_NUMBER = "streetnumber"
CONF_STREET_NUMBER_SUFFIX = "streetnumbersuffix"
CONF_DISTRICT = "district"
CONF_GET_WHOLE_YEAR = "getwholeyear"
CONF_DATE_FORMAT = "dateformat"
CONF_TIMESPAN_IN_DAYS = "timespanindays"
CONF_LOCALE = "locale"
@@ -82,6 +84,7 @@ ATTR_YEAR_MONTH_DAY_DATE = "year_month_day_date"
ATTR_FRIENDLY_NAME = "friendly_name"
ATTR_LAST_COLLECTION_DATE = "last_collection_date"
ATTR_TOTAL_COLLECTIONS_THIS_YEAR = "total_collections_this_year"
ATTR_WHOLE_YEAR_DATES = "whole_year_dates"
_LOGGER = logging.getLogger(__name__)

View File

@@ -16,38 +16,48 @@ class TrashApiAfval(object):
postcode,
street_number,
street_number_suffix,
district,
diftar_code,
get_whole_year,
resources,
):
_LOGGER.debug("Updating Waste collection dates")
try:
API_ENDPOINT = SENSOR_LOCATIONS_TO_URL["trashapi"][0].format(
location, postcode, street_number, street_number_suffix, diftar_code
location,
postcode,
street_number,
street_number_suffix,
district,
diftar_code,
get_whole_year,
)
r = requests.get(url=API_ENDPOINT)
dataList = r.json()
# Place all possible values in the dictionary even if they are not necessary
waste_dict = {}
waste_array = []
# _LOGGER.warning(dataList)
for data in dataList:
# find gft.
if "gft" in resources and data["name"].lower() == "gft":
waste_dict["gft"] = data["date"].split("T")[0]
# find kerstboom.
if "kerstboom" in resources and data["name"].lower() == "kerstboom":
waste_dict["kerstboom"] = data["date"].split("T")[0]
# find papier
if "papier" in resources and data["name"].lower() == "papier":
waste_dict["papier"] = data["date"].split("T")[0]
# find pbd.
if "pbd" in resources and data["name"].lower() == "pbd":
waste_dict["pbd"] = data["date"].split("T")[0]
# find gft, kerstboom, papier, pbd, takken or textiel
if (
("gft" in resources and data["name"].lower() == "gft")
or (
"kerstboom" in resources and data["name"].lower() == "kerstboom"
)
or ("papier" in resources and data["name"].lower() == "papier")
or ("pbd" in resources and data["name"].lower() == "pbd")
or ("takken" in resources and data["name"].lower() == "takken")
or ("textiel" in resources and data["name"].lower() == "textiel")
):
waste_array.append(
{data["name"].lower(): data["date"].split("T")[0]}
)
# find restafval.
if "restafval" in resources and data["name"].lower() == "restafval":
if (
@@ -56,18 +66,20 @@ class TrashApiAfval(object):
data["date"].split("T")[0], "%Y-%m-%d"
).date()
):
waste_dict["restafval"] = data["date"].split("T")[0]
waste_array.append(
{data["name"].lower(): data["date"].split("T")[0]}
)
else:
waste_dict["restafvaldiftardate"] = data["date"].split("T")[0]
waste_dict["restafvaldiftarcollections"] = data["totalThisYear"]
# find takken
if "takken" in resources and data["name"].lower() == "takken":
waste_dict["takken"] = data["date"].split("T")[0]
# find textiel
if "textiel" in resources and data["name"].lower() == "textiel":
waste_dict["textiel"] = data["date"].split("T")[0]
waste_array.append(
{"restafvaldiftardate": data["date"].split("T")[0]}
)
waste_array.append(
{"restafvaldiftarcollections": data["totalThisYear"]}
)
return waste_dict
# _LOGGER.warning(waste_array)
return waste_array
except urllib.error.URLError as exc:
_LOGGER.error("Error occurred while fetching data: %r", exc.reason)
return False

View File

@@ -1,7 +1,7 @@
{
"domain": "afvalinfo",
"name": "Afvalinfo",
"version": "1.0.9",
"version": "1.1.0",
"documentation": "https://github.com/heyajohnny/afvalinfo",
"issue_tracker": "https://github.com/heyajohnny/afvalinfo/issues",
"dependencies": [],

View File

@@ -16,10 +16,12 @@ from .const.const import (
MIN_TIME_BETWEEN_UPDATES,
_LOGGER,
CONF_CITY,
CONF_DISTRICT,
CONF_LOCATION,
CONF_POSTCODE,
CONF_STREET_NUMBER,
CONF_STREET_NUMBER_SUFFIX,
CONF_GET_WHOLE_YEAR,
CONF_DATE_FORMAT,
CONF_TIMESPAN_IN_DAYS,
CONF_NO_TRASH_TEXT,
@@ -36,6 +38,7 @@ from .const.const import (
ATTR_FRIENDLY_NAME,
ATTR_LAST_COLLECTION_DATE,
ATTR_TOTAL_COLLECTIONS_THIS_YEAR,
ATTR_WHOLE_YEAR_DATES,
SENSOR_TYPES,
)
@@ -57,12 +60,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
vol.Required(CONF_POSTCODE, default="3361AB"): cv.string,
vol.Required(CONF_STREET_NUMBER, default="1"): cv.string,
vol.Optional(CONF_STREET_NUMBER_SUFFIX, default=""): cv.string,
vol.Optional(CONF_DISTRICT, default=""): cv.string,
vol.Optional(CONF_DATE_FORMAT, default="%d-%m-%Y"): cv.string,
vol.Optional(CONF_TIMESPAN_IN_DAYS, default="365"): cv.string,
vol.Optional(CONF_LOCALE, default="en"): cv.string,
vol.Optional(CONF_ID, default=""): cv.string,
vol.Optional(CONF_NO_TRASH_TEXT, default="none"): cv.string,
vol.Optional(CONF_DIFTAR_CODE, default=""): cv.string,
vol.Optional(CONF_GET_WHOLE_YEAR, default="false"): cv.string,
}
)
@@ -76,12 +81,14 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
postcode = config.get(CONF_POSTCODE).strip()
street_number = config.get(CONF_STREET_NUMBER)
street_number_suffix = config.get(CONF_STREET_NUMBER_SUFFIX)
district = config.get(CONF_DISTRICT)
date_format = config.get(CONF_DATE_FORMAT).strip()
timespan_in_days = config.get(CONF_TIMESPAN_IN_DAYS)
locale = config.get(CONF_LOCALE)
id_name = config.get(CONF_ID)
no_trash_text = config.get(CONF_NO_TRASH_TEXT)
diftar_code = config.get(CONF_DIFTAR_CODE)
get_whole_year = config.get(CONF_GET_WHOLE_YEAR)
try:
resources = config[CONF_RESOURCES].copy()
@@ -102,7 +109,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
postcode,
street_number,
street_number_suffix,
district,
diftar_code,
get_whole_year,
resourcesMinusTodayAndTomorrow,
)
except urllib.error.HTTPError as error:
@@ -139,6 +148,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
timespan_in_days,
locale,
id_name,
get_whole_year,
)
)
@@ -175,7 +185,9 @@ class AfvalinfoData(object):
postcode,
street_number,
street_number_suffix,
district,
diftar_code,
get_whole_year,
resources,
):
self.data = None
@@ -183,7 +195,9 @@ class AfvalinfoData(object):
self.postcode = postcode
self.street_number = street_number
self.street_number_suffix = street_number_suffix
self.district = district
self.diftar_code = diftar_code
self.get_whole_year = get_whole_year
self.resources = resources
@Throttle(MIN_TIME_BETWEEN_UPDATES)
@@ -194,7 +208,9 @@ class AfvalinfoData(object):
self.postcode,
self.street_number,
self.street_number_suffix,
self.district,
self.diftar_code,
self.get_whole_year,
self.resources,
)
@@ -209,6 +225,7 @@ class AfvalinfoSensor(Entity):
timespan_in_days,
locale,
id_name,
get_whole_year,
):
self.data = data
self.type = sensor_type
@@ -217,6 +234,7 @@ class AfvalinfoSensor(Entity):
self.timespan_in_days = timespan_in_days
self.locale = locale
self._name = sensor_friendly_name
self._get_whole_year = get_whole_year
self.entity_id = "sensor." + (
(
SENSOR_PREFIX
@@ -241,6 +259,7 @@ class AfvalinfoSensor(Entity):
self._year_month_day_date = None
self._last_collection_date = None
self._total_collections_this_year = None
self._whole_year_dates = None
@property
def name(self):
@@ -266,98 +285,119 @@ class AfvalinfoSensor(Entity):
ATTR_IS_COLLECTION_DATE_TODAY: self._is_collection_date_today,
ATTR_LAST_COLLECTION_DATE: self._last_collection_date,
ATTR_TOTAL_COLLECTIONS_THIS_YEAR: self._total_collections_this_year,
ATTR_WHOLE_YEAR_DATES: self._whole_year_dates,
}
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
self.data.update()
waste_data = self.data.data
waste_array = self.data.data
self._error = False
try:
if waste_data:
# Loop through all the dates to put the dates in the whole_year_dates attribute
if self._get_whole_year == "True":
whole_year_dates = []
for waste_data in waste_array:
if self.type in waste_data:
collection_date = datetime.strptime(
waste_data[self.type], "%Y-%m-%d"
).date()
whole_year_dates.append(
datetime.strptime(waste_data[self.type], "%Y-%m-%d").date()
)
# Date in date format "%Y-%m-%d"
self._year_month_day_date = str(collection_date)
self._whole_year_dates = whole_year_dates
if collection_date:
# Set the values of the sensor
self._last_update = datetime.today().strftime("%d-%m-%Y %H:%M")
try:
if waste_array:
for waste_data in waste_array:
if self.type in waste_data:
collection_date = datetime.strptime(
waste_data[self.type], "%Y-%m-%d"
).date()
# Is the collection date today?
self._is_collection_date_today = date.today() == collection_date
# Date in date format "%Y-%m-%d"
self._year_month_day_date = str(collection_date)
if (
self.type == "restafval"
and "restafvaldiftardate" in waste_data
):
self._last_collection_date = str(
datetime.strptime(
waste_data["restafvaldiftardate"], "%Y-%m-%d"
).date()
if collection_date:
# Set the values of the sensor
self._last_update = datetime.today().strftime(
"%d-%m-%Y %H:%M"
)
self._total_collections_this_year = waste_data[
"restafvaldiftarcollections"
]
# Days until collection date
delta = collection_date - date.today()
self._days_until_collection_date = delta.days
# Is the collection date today?
self._is_collection_date_today = (
date.today() == collection_date
)
# Only show the value if the date is lesser than or equal to (today + timespan_in_days)
if collection_date <= date.today() + relativedelta(
days=int(self.timespan_in_days)
):
# if the date does not contain a named day or month, return the date as normal
if (
self.date_format.find("a") == -1
and self.date_format.find("A") == -1
and self.date_format.find("b") == -1
and self.date_format.find("B") == -1
self.type == "restafval"
and "restafvaldiftardate" in waste_data
):
self._state = collection_date.strftime(self.date_format)
# else convert the named values to the locale names
self._last_collection_date = str(
datetime.strptime(
waste_data["restafvaldiftardate"], "%Y-%m-%d"
).date()
)
self._total_collections_this_year = waste_data[
"restafvaldiftarcollections"
]
# Days until collection date
delta = collection_date - date.today()
self._days_until_collection_date = delta.days
# Only show the value if the date is lesser than or equal to (today + timespan_in_days)
if collection_date <= date.today() + relativedelta(
days=int(self.timespan_in_days)
):
# if the date does not contain a named day or month, return the date as normal
if (
self.date_format.find("a") == -1
and self.date_format.find("A") == -1
and self.date_format.find("b") == -1
and self.date_format.find("B") == -1
):
self._state = collection_date.strftime(
self.date_format
)
# else convert the named values to the locale names
else:
edited_date_format = self.date_format.replace(
"%a", "EEE"
)
edited_date_format = edited_date_format.replace(
"%A", "EEEE"
)
edited_date_format = edited_date_format.replace(
"%b", "MMM"
)
edited_date_format = edited_date_format.replace(
"%B", "MMMM"
)
# half babel, half date string... something like EEEE 04-MMMM-2020
half_babel_half_date = collection_date.strftime(
edited_date_format
)
# replace the digits with qquoted digits 01 --> '01'
half_babel_half_date = re.sub(
r"(\d+)", r"'\1'", half_babel_half_date
)
# transform the EEE, EEEE etc... to a real locale date, with babel
locale_date = format_date(
collection_date,
half_babel_half_date,
locale=self.locale,
)
self._state = locale_date
break # we have a result, break the loop
else:
edited_date_format = self.date_format.replace(
"%a", "EEE"
)
edited_date_format = edited_date_format.replace(
"%A", "EEEE"
)
edited_date_format = edited_date_format.replace(
"%b", "MMM"
)
edited_date_format = edited_date_format.replace(
"%B", "MMMM"
)
# half babel, half date string... something like EEEE 04-MMMM-2020
half_babel_half_date = collection_date.strftime(
edited_date_format
)
# replace the digits with qquoted digits 01 --> '01'
half_babel_half_date = re.sub(
r"(\d+)", r"'\1'", half_babel_half_date
)
# transform the EEE, EEEE etc... to a real locale date, with babel
locale_date = format_date(
collection_date,
half_babel_half_date,
locale=self.locale,
)
self._state = locale_date
self._hidden = True
else:
self._hidden = True
else:
raise ValueError()
else:
raise ValueError()
# collection_date empty
raise ValueError()
# else:
# No matching result data for current waste type, no problem
else:
raise ValueError()
except ValueError:
@@ -369,4 +409,5 @@ class AfvalinfoSensor(Entity):
# self._is_collection_date_today = False
# self._last_collection_date = None
# self._total_collections_this_year = None
# self._whole_year_dates = None
self._last_update = datetime.today().strftime("%d-%m-%Y %H:%M")

View File

@@ -12,8 +12,7 @@ def get_waste_data_raw(
postal_code,
street_number,
suffix,
): # sourcery skip: avoid-builtin-shadow
):
if provider not in SENSOR_COLLECTORS_ICALENDAR.keys():
raise ValueError(f"Invalid provider: {provider}, please verify")

View File

@@ -17,6 +17,7 @@ def get_waste_data_raw(
try:
bag_id = None
suffix = suffix.strip().upper()
_verify = provider != "suez"
url = f"{SENSOR_COLLECTORS_OPZET[provider]}/rest/adressen/{postal_code}-{street_number}"
raw_response = requests.get(url, verify=_verify)

View File

@@ -5,7 +5,7 @@ _LOGGER = logging.getLogger(__name__)
API = "api"
NAME = "afvalwijzer"
VERSION = "2022.11.02"
VERSION = "2023.01.01"
ISSUE_URL = "https://github.com/xirixiz/homeassistant-afvalwijzer/issues"
SENSOR_COLLECTOR_TO_URL = {

View File

@@ -1,7 +1,7 @@
{
"domain": "afvalwijzer",
"name": "Afvalwijzer",
"version": "2022.11.02",
"version": "2023.01.01",
"iot_class": "cloud_polling",
"documentation": "https://github.com/xirixiz/homeassistant-afvalwijzer/blob/master/README.md",
"issue_tracker": "https://github.com/xirixiz/homeassistant-afvalwijzer/issues",
@@ -11,4 +11,4 @@
"@xirixiz"
],
"requirements": []
}
}

View File

@@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
vol.Optional(CONF_SUFFIX, default=""): cv.string,
vol.Optional(CONF_EXCLUDE_PICKUP_TODAY, default="true"): cv.string,
vol.Optional(CONF_EXCLUDE_LIST, default=""): cv.string,
vol.Optional(CONF_DEFAULT_LABEL, default="Geen"): cv.string,
vol.Optional(CONF_DEFAULT_LABEL, default="geen"): cv.string,
vol.Optional(CONF_ID.strip().lower(), default=""): cv.string,
}
)
@@ -77,7 +77,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
except ValueError as err:
_LOGGER.error(f"Check afvalwijzer platform settings {err.args}")
fetch_data = AfvalwijzerData(config)
fetch_data = AfvalwijzerData(hass, config)
waste_types_provider = collector.waste_types_provider
_LOGGER.debug(f"Generating waste_types_provider list = {waste_types_provider}")
@@ -98,7 +98,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
class AfvalwijzerData(object):
def __init__(self, config):
def __init__(self, hass, config):
self._hass = hass
self.config = config
@Throttle(MIN_TIME_BETWEEN_UPDATES)

View File

@@ -24,7 +24,7 @@ from ..collector.main_collector import MainCollector
# Common
suffix = ""
exclude_pickup_today = "True"
default_label = "Geen"
default_label = "geen"
exclude_list = ""
# DeAfvalapp
@@ -42,6 +42,11 @@ exclude_list = ""
# postal_code = "5146eg"
# street_number = "1"
provider = "rmn"
postal_code = "3701XK"
street_number = "24"
suffix = "b"
# Opzet
# provider = "prezero"
# postal_code = "6665CN"
@@ -54,9 +59,9 @@ exclude_list = ""
# suffix = "C"
# Ximmio
provider = "meerlanden"
postal_code = "2121xt"
street_number = "38"
# provider = "meerlanden"
# postal_code = "2121xt"
# street_number = "38"
# Ximmio
# provider = "acv"

View File

@@ -25,6 +25,7 @@ import voluptuous as vol
from .base import HacsBase
from .const import DOMAIN, MINIMUM_HA_VERSION, STARTUP
from .data_client import HacsDataClient
from .enums import ConfigurationType, HacsDisabledReason, HacsStage, LovelaceMode
from .frontend import async_register_frontend
from .utils.configuration_schema import hacs_config_combined
@@ -87,6 +88,10 @@ async def async_initialize_integration(
hacs.hass = hass
hacs.queue = QueueManager(hass=hass)
hacs.data = HacsData(hacs=hacs)
hacs.data_client = HacsDataClient(
session=clientsession,
client_name=f"HACS/{integration.version}",
)
hacs.system.running = True
hacs.session = clientsession
@@ -153,8 +158,9 @@ async def async_initialize_integration(
hacs.disable_hacs(HacsDisabledReason.RESTORE)
return False
can_update = await hacs.async_can_update()
hacs.log.debug("Can update %s repositories", can_update)
if not hacs.configuration.experimental:
can_update = await hacs.async_can_update()
hacs.log.debug("Can update %s repositories", can_update)
hacs.set_active_categories()
@@ -168,7 +174,7 @@ async def async_initialize_integration(
hacs.log.info("Update entities are only supported when using UI configuration")
else:
hass.config_entries.async_setup_platforms(
await hass.config_entries.async_forward_entry_setups(
config_entry,
[Platform.SENSOR, Platform.UPDATE]
if hacs.configuration.experimental

View File

@@ -28,11 +28,17 @@ from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.const import EVENT_HOMEASSISTANT_FINAL_WRITE, Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.issue_registry import async_create_issue, IssueSeverity
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.loader import Integration
from homeassistant.util import dt
from custom_components.hacs.repositories.base import (
HACS_MANIFEST_KEYS_TO_EXPORT,
REPOSITORY_KEYS_TO_EXPORT,
)
from .const import DOMAIN, TV, URL_BASE
from .data_client import HacsDataClient
from .enums import (
ConfigurationType,
HacsCategory,
@@ -47,6 +53,7 @@ from .exceptions import (
HacsException,
HacsExecutionStillInProgress,
HacsExpectedException,
HacsNotModifiedException,
HacsRepositoryArchivedException,
HacsRepositoryExistException,
HomeAssistantCoreRepositoryException,
@@ -166,6 +173,7 @@ class HacsStatus:
new: bool = False
active_frontend_endpoint_plugin: bool = False
active_frontend_endpoint_theme: bool = False
inital_fetch_done: bool = False
@dataclass
@@ -176,6 +184,7 @@ class HacsSystem:
running: bool = False
stage = HacsStage.SETUP
action: bool = False
generator: bool = False
@property
def disabled(self) -> bool:
@@ -265,7 +274,7 @@ class HacsRepositories:
self._default_repositories.add(repo_id)
def set_repository_id(self, repository, repo_id):
def set_repository_id(self, repository: HacsRepository, repo_id: str):
"""Update a repository id."""
existing_repo_id = str(repository.data.id)
if existing_repo_id == repo_id:
@@ -350,6 +359,7 @@ class HacsBase:
configuration = HacsConfiguration()
core = HacsCore()
data: HacsData | None = None
data_client: HacsDataClient | None = None
frontend_version: str | None = None
github: GitHub | None = None
githubapi: GitHubAPI | None = None
@@ -546,8 +556,6 @@ class HacsBase:
if check:
try:
await repository.async_registration(ref)
if self.status.new:
repository.data.new = False
if repository.validate.errors:
self.common.skip.append(repository.data.full_name)
if not self.status.startup:
@@ -561,7 +569,11 @@ class HacsBase:
repository.logger.info("%s Validation completed", repository.string)
else:
repository.logger.info("%s Registration completed", repository.string)
except (HacsRepositoryExistException, HacsRepositoryArchivedException):
except (HacsRepositoryExistException, HacsRepositoryArchivedException) as exception:
if self.system.generator:
repository.logger.error(
"%s Registration Failed - %s", repository.string, exception
)
return
except AIOGitHubAPIException as exception:
self.common.skip.append(repository.data.full_name)
@@ -569,6 +581,9 @@ class HacsBase:
f"Validation for {repository_full_name} failed with {exception}."
) from exception
if self.status.new:
repository.data.new = False
if repository_id is not None:
repository.data.id = repository_id
@@ -588,34 +603,7 @@ class HacsBase:
async def startup_tasks(self, _=None) -> None:
"""Tasks that are started after setup."""
self.set_stage(HacsStage.STARTUP)
try:
repository = self.repositories.get_by_full_name(HacsGitHubRepo.INTEGRATION)
if repository is None:
await self.async_register_repository(
repository_full_name=HacsGitHubRepo.INTEGRATION,
category=HacsCategory.INTEGRATION,
default=True,
)
repository = self.repositories.get_by_full_name(HacsGitHubRepo.INTEGRATION)
if repository is None:
raise HacsException("Unknown error")
repository.data.installed = True
repository.data.installed_version = self.integration.version.string
repository.data.new = False
repository.data.releases = True
self.repository = repository.repository_object
self.repositories.mark_default(repository)
except HacsException as exception:
if "403" in str(exception):
self.log.critical(
"GitHub API is ratelimited, or the token is wrong.",
)
else:
self.log.critical("Could not load HACS! - %s", exception)
self.disable_hacs(HacsDisabledReason.LOAD_HACS)
await self.async_load_hacs_from_github()
if critical := await async_load_from_store(self.hass, "critical"):
for repo in critical:
@@ -626,16 +614,38 @@ class HacsBase:
)
break
if not self.configuration.experimental:
self.recuring_tasks.append(
self.hass.helpers.event.async_track_time_interval(
self.async_update_downloaded_repositories, timedelta(hours=48)
)
)
self.recuring_tasks.append(
self.hass.helpers.event.async_track_time_interval(
self.async_update_all_repositories,
timedelta(hours=96),
)
)
else:
self.recuring_tasks.append(
self.hass.helpers.event.async_track_time_interval(
self.async_load_hacs_from_github,
timedelta(hours=48),
)
)
self.recuring_tasks.append(
self.hass.helpers.event.async_track_time_interval(
self.async_get_all_category_repositories, timedelta(hours=3)
self.async_update_downloaded_custom_repositories, timedelta(hours=48)
)
)
self.recuring_tasks.append(
self.hass.helpers.event.async_track_time_interval(
self.async_update_all_repositories, timedelta(hours=25)
self.async_get_all_category_repositories, timedelta(hours=6)
)
)
self.recuring_tasks.append(
self.hass.helpers.event.async_track_time_interval(
self.async_check_rate_limit, timedelta(minutes=5)
@@ -646,14 +656,10 @@ class HacsBase:
self.async_prosess_queue, timedelta(minutes=10)
)
)
self.recuring_tasks.append(
self.hass.helpers.event.async_track_time_interval(
self.async_update_downloaded_repositories, timedelta(hours=2)
)
)
self.recuring_tasks.append(
self.hass.helpers.event.async_track_time_interval(
self.async_handle_critical_repositories, timedelta(hours=2)
self.async_handle_critical_repositories, timedelta(hours=6)
)
)
@@ -661,6 +667,8 @@ class HacsBase:
EVENT_HOMEASSISTANT_FINAL_WRITE, self.data.async_force_write
)
self.log.debug("There are %s scheduled recurring tasks", len(self.recuring_tasks))
self.status.startup = False
self.async_dispatch(HacsDispatchEvent.STATUS, {})
@@ -758,6 +766,42 @@ class HacsBase:
if self.configuration.netdaemon:
self.enable_hacs_category(HacsCategory.NETDAEMON)
async def async_load_hacs_from_github(self, _=None) -> None:
"""Load HACS from GitHub."""
if self.configuration.experimental and self.status.inital_fetch_done:
return
try:
repository = self.repositories.get_by_full_name(HacsGitHubRepo.INTEGRATION)
if repository is None:
await self.async_register_repository(
repository_full_name=HacsGitHubRepo.INTEGRATION,
category=HacsCategory.INTEGRATION,
default=True,
)
repository = self.repositories.get_by_full_name(HacsGitHubRepo.INTEGRATION)
elif self.configuration.experimental and not self.status.startup:
self.log.error("Scheduling update of hacs/integration")
self.queue.add(repository.common_update())
if repository is None:
raise HacsException("Unknown error")
repository.data.installed = True
repository.data.installed_version = self.integration.version.string
repository.data.new = False
repository.data.releases = True
self.repository = repository.repository_object
self.repositories.mark_default(repository)
except HacsException as exception:
if "403" in str(exception):
self.log.critical(
"GitHub API is ratelimited, or the token is wrong.",
)
else:
self.log.critical("Could not load HACS! - %s", exception)
self.disable_hacs(HacsDisabledReason.LOAD_HACS)
async def async_get_all_category_repositories(self, _=None) -> None:
"""Get all category repositories."""
if self.system.disabled:
@@ -765,11 +809,62 @@ class HacsBase:
self.log.info("Loading known repositories")
await asyncio.gather(
*[
self.async_get_category_repositories(HacsCategory(category))
self.async_get_category_repositories_experimental(category)
if self.configuration.experimental
else self.async_get_category_repositories(HacsCategory(category))
for category in self.common.categories or []
]
)
async def async_get_category_repositories_experimental(self, category: str) -> None:
"""Update all category repositories."""
self.log.debug("Fetching updated content for %s", category)
try:
category_data = await self.data_client.get_data(category)
except HacsNotModifiedException:
self.log.debug("No updates for %s", category)
return
except HacsException as exception:
self.log.error("Could not update %s - %s", category, exception)
return
await self.data.register_unknown_repositories(category_data, category)
for repo_id, repo_data in category_data.items():
repo = repo_data["full_name"]
if self.common.renamed_repositories.get(repo):
repo = self.common.renamed_repositories[repo]
if self.repositories.is_removed(repo):
continue
if repo in self.common.archived_repositories:
continue
if repository := self.repositories.get_by_full_name(repo):
self.repositories.set_repository_id(repository, repo_id)
self.repositories.mark_default(repository)
if repository.data.last_fetched is None or (
repository.data.last_fetched.timestamp() < repo_data["last_fetched"]
):
repository.data.update_data({**dict(REPOSITORY_KEYS_TO_EXPORT), **repo_data})
if (manifest := repo_data.get("manifest")) is not None:
repository.repository_manifest.update_data(
{**dict(HACS_MANIFEST_KEYS_TO_EXPORT), **manifest}
)
if category == "integration":
self.status.inital_fetch_done = True
if self.stage == HacsStage.STARTUP:
for repository in self.repositories.list_all:
if (
repository.data.category == category
and not repository.data.installed
and not self.repositories.is_default(repository.data.id)
):
repository.logger.debug(
"%s Unregister stale custom repository", repository.string
)
self.repositories.unregister(repository)
async def async_get_category_repositories(self, category: HacsCategory) -> None:
"""Get repositories from category."""
if self.system.disabled:
@@ -845,7 +940,7 @@ class HacsBase:
return
can_update = await self.async_can_update()
self.log.debug(
"Can update %s repositories, " "items in queue %s",
"Can update %s repositories, items in queue %s",
can_update,
self.queue.pending_tasks,
)
@@ -867,9 +962,12 @@ class HacsBase:
self.log.info("Loading removed repositories")
try:
removed_repositories = await self.async_github_get_hacs_default_file(
HacsCategory.REMOVED
)
if self.configuration.experimental:
removed_repositories = await self.data_client.get_data("removed")
else:
removed_repositories = await self.async_github_get_hacs_default_file(
HacsCategory.REMOVED
)
except HacsException:
return
@@ -915,7 +1013,7 @@ class HacsBase:
async def async_update_downloaded_repositories(self, _=None) -> None:
"""Execute the task."""
if self.system.disabled:
if self.system.disabled or self.configuration.experimental:
return
self.log.info("Starting recurring background task for downloaded repositories")
@@ -925,6 +1023,21 @@ class HacsBase:
self.log.debug("Recurring background task for downloaded repositories done")
async def async_update_downloaded_custom_repositories(self, _=None) -> None:
"""Execute the task."""
if self.system.disabled or not self.configuration.experimental:
return
self.log.info("Starting recurring background task for downloaded custom repositories")
for repository in self.repositories.list_downloaded:
if (
repository.data.category in self.common.categories
and not self.repositories.is_default(repository.data.id)
):
self.queue.add(repository.update_repository(ignore_issues=True))
self.log.debug("Recurring background task for downloaded custom repositories done")
async def async_handle_critical_repositories(self, _=None) -> None:
"""Handle critical repositories."""
critical_queue = QueueManager(hass=self.hass)
@@ -933,8 +1046,11 @@ class HacsBase:
was_installed = False
try:
critical = await self.async_github_get_hacs_default_file("critical")
except GitHubNotModifiedException:
if self.configuration.experimental:
critical = await self.data_client.get_data("critical")
else:
critical = await self.async_github_get_hacs_default_file("critical")
except (GitHubNotModifiedException, HacsNotModifiedException):
return
except HacsException:
pass

View File

@@ -17,6 +17,8 @@ PACKAGE_NAME = "custom_components.hacs"
DEFAULT_CONCURRENT_TASKS = 15
DEFAULT_CONCURRENT_BACKOFF_TIME = 1
HACS_REPOSITORY_ID = "172733314"
HACS_ACTION_GITHUB_API_HEADERS = {
"User-Agent": "HACS/action",
"Accept": ACCEPT_HEADERS["preview"],

View File

@@ -4,7 +4,7 @@ import sys
if sys.version_info.minor >= 11:
# Needs Python 3.11
from enum import StrEnum ## pylint: disable=no-name-in-module
from enum import StrEnum # # pylint: disable=no-name-in-module
else:
try:
# https://github.com/home-assistant/core/blob/dev/homeassistant/backports/enum.py

View File

@@ -8,13 +8,12 @@ from homeassistant.components.http import HomeAssistantView
from homeassistant.core import HomeAssistant, callback
from .const import DOMAIN, URL_BASE
from .hacs_frontend import locate_dir, VERSION as FE_VERSION
from .hacs_frontend import VERSION as FE_VERSION, locate_dir
from .hacs_frontend_experimental import (
locate_dir as experimental_locate_dir,
VERSION as EXPERIMENTAL_FE_VERSION,
locate_dir as experimental_locate_dir,
)
if TYPE_CHECKING:
from .base import HacsBase

View File

@@ -1,9 +1,9 @@
try {
new Function("import('/hacsfiles/frontend/main-c4dd4de7.js')")();
new Function("import('/hacsfiles/frontend/main-aeda8d41.js')")();
} catch (err) {
var el = document.createElement('script');
el.src = '/hacsfiles/frontend/main-c4dd4de7.js';
el.src = '/hacsfiles/frontend/main-aeda8d41.js';
el.type = 'module';
document.body.appendChild(el);
}

View File

@@ -1,3 +1,3 @@
{
"./src/main.ts": "main-c4dd4de7.js"
"./src/main.ts": "main-aeda8d41.js"
}

View File

@@ -1 +1 @@
VERSION="20221217163936"
VERSION="20230127100107"

View File

@@ -19,5 +19,5 @@
"requirements": [
"aiogithubapi>=22.10.1"
],
"version": "1.29.0"
"version": "1.30.1"
}

View File

@@ -1,13 +1,14 @@
"""Repairs platform for HACS."""
from __future__ import annotations
from typing import Any
import voluptuous as vol
from typing import Any
from homeassistant import data_entry_flow
from homeassistant.components.repairs import RepairsFlow
from homeassistant.core import HomeAssistant
import voluptuous as vol
from custom_components.hacs.base import HacsBase
from .const import DOMAIN

View File

@@ -50,16 +50,27 @@ if TYPE_CHECKING:
TOPIC_FILTER = (
"add-on",
"addon",
"app",
"appdaemon-apps",
"appdaemon",
"custom-card",
"custom-cards",
"custom-component",
"custom-components",
"customcomponents",
"hacktoberfest",
"hacs-default",
"hacs-integration",
"hacs-repository",
"hacs",
"hass",
"hassio",
"home-assistant-custom",
"home-assistant-frontend",
"home-assistant-hacs",
"home-assistant-sensor",
"home-assistant",
"home-automation",
"homeassistant-components",
@@ -68,16 +79,45 @@ TOPIC_FILTER = (
"homeassistant",
"homeautomation",
"integration",
"lovelace-ui",
"lovelace",
"media-player",
"mediaplayer",
"netdaemon",
"plugin",
"python_script",
"python-script",
"python",
"sensor",
"smart-home",
"smarthome",
"theme",
"themes",
"custom-cards",
"home-assistant-frontend",
"home-assistant-hacs",
"home-assistant-custom",
"lovelace-ui",
)
REPOSITORY_KEYS_TO_EXPORT = (
# Keys can not be removed from this list until v3
# If keys are added, the action need to be re-run with force
("description", ""),
("downloads", 0),
("domain", None),
("etag_repository", None),
("full_name", ""),
("last_commit", None),
("last_updated", 0),
("last_version", None),
("manifest_name", None),
("open_issues", 0),
("stargazers_count", 0),
("topics", []),
)
HACS_MANIFEST_KEYS_TO_EXPORT = (
# Keys can not be removed from this list until v3
# If keys are added, the action need to be re-run with force
("country", []),
("name", None),
)
@@ -120,7 +160,6 @@ class RepositoryData:
new: bool = True
open_issues: int = 0
published_tags: list[str] = []
pushed_at: str = ""
releases: bool = False
selected_tag: str = None
show_beta: bool = False
@@ -147,32 +186,24 @@ class RepositoryData:
def update_data(self, data: dict, action: bool = False) -> None:
"""Update data of the repository."""
for key in data:
for key, value in data.items():
if key not in self.__dict__:
continue
if key == "pushed_at":
if data[key] == "":
continue
if "Z" in data[key]:
setattr(
self,
key,
datetime.strptime(data[key], "%Y-%m-%dT%H:%M:%SZ"),
)
else:
setattr(self, key, datetime.strptime(data[key], "%Y-%m-%dT%H:%M:%S"))
if key == "last_fetched" and isinstance(value, float):
setattr(self, key, datetime.fromtimestamp(value))
elif key == "id":
setattr(self, key, str(data[key]))
setattr(self, key, str(value))
elif key == "country":
if isinstance(data[key], str):
setattr(self, key, [data[key]])
if isinstance(value, str):
setattr(self, key, [value])
else:
setattr(self, key, data[key])
setattr(self, key, value)
elif key == "topics" and not action:
setattr(self, key, [topic for topic in data[key] if topic not in TOPIC_FILTER])
setattr(self, key, [topic for topic in value if topic not in TOPIC_FILTER])
else:
setattr(self, key, data[key])
setattr(self, key, value)
@attr.s(auto_attribs=True)
@@ -215,6 +246,20 @@ class HacsManifest:
setattr(manifest_data, key, value)
return manifest_data
def update_data(self, data: dict) -> None:
"""Update the manifest data."""
for key, value in data.items():
if key not in self.__dict__:
continue
if key == "country":
if isinstance(value, str):
setattr(self, key, [value])
else:
setattr(self, key, value)
else:
setattr(self, key, value)
class RepositoryReleases:
"""RepositoyReleases."""
@@ -449,6 +494,10 @@ class HacsRepository:
self.logger.debug("%s Did not update, content was not modified", self.string)
return
if self.repository_object:
self.data.last_updated = self.repository_object.attributes.get("pushed_at", 0)
self.data.last_fetched = datetime.utcnow()
# Set topics
self.data.topics = self.data.topics
@@ -497,7 +546,7 @@ class HacsRepository:
self.additional_info = await self.async_get_info_file_contents()
# Set last fetch attribute
self.data.last_fetched = datetime.now()
self.data.last_fetched = datetime.utcnow()
return True
@@ -1011,7 +1060,11 @@ class HacsRepository:
self.hacs.common.renamed_repositories[
self.data.full_name
] = repository_object.full_name
raise HacsRepositoryExistException
if not self.hacs.system.generator:
raise HacsRepositoryExistException
self.logger.error(
"%s Repository has been renamed - %s", self.string, repository_object.full_name
)
self.data.update_data(
repository_object.attributes,
action=self.hacs.system.action,

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Any
from homeassistant.helpers.issue_registry import async_create_issue, IssueSeverity
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.loader import async_get_custom_components
from ..const import DOMAIN

View File

@@ -1,5 +1,6 @@
"""Sensor platform for HACS."""
from __future__ import annotations
from typing import TYPE_CHECKING
from homeassistant.components.sensor import SensorEntity

View File

@@ -7,6 +7,7 @@ from .base import HacsBase
from .const import DOMAIN
GITHUB_STATUS = "https://www.githubstatus.com/"
CLOUDFLARE_STATUS = "https://www.cloudflarestatus.com/"
@callback
@@ -39,4 +40,9 @@ async def system_health_info(hass):
if hacs.system.disabled:
data["Disabled"] = hacs.system.disabled_reason
if hacs.configuration.experimental:
data["HACS Data"] = system_health.async_check_can_reach_url(
hass, "https://data-v2.hacs.xyz/data.json", CLOUDFLARE_STATUS
)
return data

View File

@@ -90,6 +90,17 @@ class HacsRepositoryUpdateEntity(HacsRepositoryEntity, UpdateEntity):
if self.repository.pending_restart or not self.repository.can_download:
return None
if self.latest_version not in self.repository.data.published_tags:
releases = await self.repository.get_releases(
prerelease=self.repository.data.show_beta,
returnlimit=self.hacs.configuration.release_limit,
)
if releases:
self.repository.data.releases = True
self.repository.releases.objects = releases
self.repository.data.published_tags = [x.tag_name for x in releases]
self.repository.data.last_version = next(iter(self.repository.data.published_tags))
release_notes = ""
if len(self.repository.releases.objects) > 0:
release = self.repository.releases.objects[0]

View File

@@ -1,38 +1,45 @@
"""Data handler for HACS."""
from __future__ import annotations
import asyncio
from datetime import datetime
from typing import Any
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util import json as json_util
from ..base import HacsBase
from ..enums import HacsDisabledReason, HacsDispatchEvent, HacsGitHubRepo
from ..const import HACS_REPOSITORY_ID
from ..enums import HacsDisabledReason, HacsDispatchEvent
from ..repositories.base import TOPIC_FILTER, HacsManifest, HacsRepository
from .logger import LOGGER
from .path import is_safe
from .store import async_load_from_store, async_save_to_store
DEFAULT_BASE_REPOSITORY_DATA = (
EXPORTED_BASE_DATA = (
("new", False),
("full_name", ""),
)
EXPORTED_REPOSITORY_DATA = EXPORTED_BASE_DATA + (
("authors", []),
("category", ""),
("description", ""),
("domain", None),
("downloads", 0),
("etag_repository", None),
("full_name", ""),
("last_updated", 0),
("hide", False),
("last_updated", 0),
("new", False),
("stargazers_count", 0),
("topics", []),
)
DEFAULT_EXTENDED_REPOSITORY_DATA = (
EXPORTED_DOWNLOADED_REPOSITORY_DATA = EXPORTED_REPOSITORY_DATA + (
("archived", False),
("config_flow", False),
("default_branch", None),
("description", ""),
("first_install", False),
("installed_commit", None),
("installed", False),
@@ -41,12 +48,9 @@ DEFAULT_EXTENDED_REPOSITORY_DATA = (
("manifest_name", None),
("open_issues", 0),
("published_tags", []),
("pushed_at", ""),
("releases", False),
("selected_tag", None),
("show_beta", False),
("stargazers_count", 0),
("topics", []),
)
@@ -80,6 +84,8 @@ class HacsData:
"ignored_repositories": self.hacs.common.ignored_repositories,
},
)
if self.hacs.configuration.experimental:
await self._async_store_experimental_content_and_repos()
await self._async_store_content_and_repos()
async def _async_store_content_and_repos(self, _=None): # bb: ignore
@@ -94,40 +100,94 @@ class HacsData:
for event in (HacsDispatchEvent.REPOSITORY, HacsDispatchEvent.CONFIG):
self.hacs.async_dispatch(event, {})
async def _async_store_experimental_content_and_repos(self, _=None): # bb: ignore
"""Store the main repos file and each repo that is out of date."""
# Repositories
self.content = {}
for repository in self.hacs.repositories.list_all:
if repository.data.category in self.hacs.common.categories:
self.async_store_experimental_repository_data(repository)
await async_save_to_store(self.hacs.hass, "data", {"repositories": self.content})
@callback
def async_store_repository_data(self, repository: HacsRepository) -> dict:
"""Store the repository data."""
data = {"repository_manifest": repository.repository_manifest.manifest}
for key, default_value in DEFAULT_BASE_REPOSITORY_DATA:
if (value := repository.data.__getattribute__(key)) != default_value:
for key, default in (
EXPORTED_DOWNLOADED_REPOSITORY_DATA
if repository.data.installed
else EXPORTED_REPOSITORY_DATA
):
if (value := getattr(repository.data, key, default)) != default:
data[key] = value
if repository.data.installed:
for key, default_value in DEFAULT_EXTENDED_REPOSITORY_DATA:
if (value := repository.data.__getattribute__(key)) != default_value:
data[key] = value
if repository.data.installed_version:
data["version_installed"] = repository.data.installed_version
if repository.data.last_fetched:
data["last_fetched"] = repository.data.last_fetched.timestamp()
self.content[str(repository.data.id)] = data
@callback
def async_store_experimental_repository_data(self, repository: HacsRepository) -> None:
"""Store the experimental repository data for non downloaded repositories."""
data = {}
self.content.setdefault(repository.data.category, [])
if repository.data.installed:
data["repository_manifest"] = repository.repository_manifest.manifest
for key, default in EXPORTED_DOWNLOADED_REPOSITORY_DATA:
if (value := getattr(repository.data, key, default)) != default:
data[key] = value
if repository.data.installed_version:
data["version_installed"] = repository.data.installed_version
if repository.data.last_fetched:
data["last_fetched"] = repository.data.last_fetched.timestamp()
else:
for key, default in EXPORTED_BASE_DATA:
if (value := getattr(repository.data, key, default)) != default:
data[key] = value
self.content[repository.data.category].append({"id": str(repository.data.id), **data})
async def restore(self):
"""Restore saved data."""
self.hacs.status.new = False
repositories = {}
hacs = {}
try:
hacs = await async_load_from_store(self.hacs.hass, "hacs") or {}
except HomeAssistantError:
hacs = {}
pass
try:
repositories = await async_load_from_store(self.hacs.hass, "repositories") or {}
data = (
await async_load_from_store(
self.hacs.hass,
"data" if self.hacs.configuration.experimental else "repositories",
)
or {}
)
if data and self.hacs.configuration.experimental:
for category, entries in data.get("repositories", {}).items():
for repository in entries:
repositories[repository["id"]] = {"category": category, **repository}
else:
repositories = (
data or await async_load_from_store(self.hacs.hass, "repositories") or {}
)
except HomeAssistantError as exception:
self.hacs.log.error(
"Could not read %s, restore the file from a backup - %s",
self.hacs.hass.config.path(".storage/hacs.repositories"),
self.hacs.hass.config.path(
".storage/hacs.data"
if self.hacs.configuration.experimental
else ".storage/hacs.repositories"
),
exception,
)
self.hacs.disable_hacs(HacsDisabledReason.RESTORE)
@@ -136,6 +196,8 @@ class HacsData:
if not hacs and not repositories:
# Assume new install
self.hacs.status.new = True
if self.hacs.configuration.experimental:
return True
self.logger.info("<HacsData restore> Loading base repository information")
repositories = await self.hacs.hass.async_add_executor_job(
json_util.load_json,
@@ -186,28 +248,34 @@ class HacsData:
return False
return True
async def register_unknown_repositories(self, repositories):
async def register_unknown_repositories(self, repositories, category: str | None = None):
"""Registry any unknown repositories."""
register_tasks = [
self.hacs.async_register_repository(
repository_full_name=repo_data["full_name"],
category=repo_data["category"],
category=repo_data.get("category", category),
check=False,
repository_id=entry,
)
for entry, repo_data in repositories.items()
if entry != "0" and not self.hacs.repositories.is_registered(repository_id=entry)
if entry != "0"
and not self.hacs.repositories.is_registered(repository_id=entry)
and repo_data.get("category", category) is not None
]
if register_tasks:
await asyncio.gather(*register_tasks)
@callback
def async_restore_repository(self, entry, repository_data):
def async_restore_repository(self, entry: str, repository_data: dict[str, Any]):
"""Restore repository."""
full_name = repository_data["full_name"]
if not (repository := self.hacs.repositories.get_by_full_name(full_name)):
self.logger.error("<HacsData restore> Did not find %s (%s)", full_name, entry)
repository: HacsRepository | None = None
if full_name := repository_data.get("full_name"):
repository = self.hacs.repositories.get_by_full_name(full_name)
if not repository:
repository = self.hacs.repositories.get_by_id(entry)
if not repository:
return
# Restore repository attributes
self.hacs.repositories.set_repository_id(repository, entry)
repository.data.authors = repository_data.get("authors", [])
@@ -238,7 +306,7 @@ class HacsData:
repository.data.last_fetched = datetime.fromtimestamp(last_fetched)
repository.repository_manifest = HacsManifest.from_dict(
repository_data.get("repository_manifest", {})
repository_data.get("manifest") or repository_data.get("repository_manifest") or {}
)
if repository.localpath is not None and is_safe(self.hacs, repository.localpath):
@@ -248,6 +316,6 @@ class HacsData:
if repository.data.installed:
repository.data.first_install = False
if full_name == HacsGitHubRepo.INTEGRATION:
if entry == HACS_REPOSITORY_ID:
repository.data.installed_version = self.hacs.version
repository.data.installed = True

File diff suppressed because one or more lines are too long

View File

@@ -66,8 +66,9 @@ async def hacs_repositories_list(
"topics": repo.data.topics,
}
for repo in hacs.repositories.list_all
if repo.data.category in (msg.get("categories") or hacs.common.categories)
if repo.data.category in msg.get("categories", hacs.common.categories)
and not repo.ignored_by_country_configuration
and (not hacs.configuration.experimental or repo.data.last_fetched)
],
)
)
@@ -201,8 +202,6 @@ async def hacs_repositories_remove(
):
"""Remove custom repositoriy."""
hacs: HacsBase = hass.data.get(DOMAIN)
hacs.log.warning(connection.context)
hacs.log.warning(msg)
repository = hacs.repositories.get_by_id(msg["repository"])
repository.remove()

View File

@@ -10,7 +10,8 @@ from homeassistant.const import (
CONF_SCAN_INTERVAL,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.exceptions import ConfigEntryNotReady, ConfigEntryAuthFailed
from hyundai_kia_connect_api.exceptions import *
import hashlib
from .const import (
@@ -52,9 +53,10 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
await coordinator.async_config_entry_first_refresh()
except Exception as ex:
raise ConfigEntryNotReady(f"Config Not Ready: {ex}")
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][config_entry.unique_id] = coordinator
hass.config_entries.async_setup_platforms(config_entry, PLATFORMS)
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
async_setup_services(hass)
return True

Some files were not shown because too many files have changed in this diff Show More