chore(quality): manifest keys, ConfigEntryNotReady, remove dead sqlite code

- manifest: add single_config_entry, integration_type "device", loggers
  ["aioecowitt"]; drop empty homekit/ssdp/zeroconf placeholders.
- Q10: raise ConfigEntryNotReady (not PlatformNotReady) when route registration
  fails in async_setup_entry; drop the now-unused import.
- Q11: delete the ~105-line commented-out sqlite3 statistics-migration block in
  utils.py (would have been blocking I/O in the event loop) and its dead import.

Deferred (with reason): quality_scale (needs a rule audit + quality_scale.yaml),
device-identifier 2-tuple and suggested_entity_id (entity-naming/identity changes,
to land with the planned integration rename), CoordinatorEntity generics in
sensor.py (would introduce a circular import - intentionally untyped).
Note: the health-probe protocol gate was reverted - the proxy add-on can front
WU/WSLink/Ecowitt, so polling must stay unconditional.

308 passing, 100% coverage; ruff clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SchiZzA 2026-06-21 19:01:32 +02:00
parent 418d0c7546
commit df8e503d2c
No known key found for this signature in database
5 changed files with 16 additions and 118 deletions

View File

@ -36,7 +36,7 @@ from py_typecheck import checked, checked_or
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady, PlatformNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.event import async_track_time_interval
from .const import ( from .const import (
@ -178,7 +178,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: SWSConfigEntry) -> bool:
else: else:
if not register_path(hass, coordinator, coordinator_health, entry): if not register_path(hass, coordinator, coordinator_health, entry):
_LOGGER.error("Fatal: path not registered!") _LOGGER.error("Fatal: path not registered!")
raise PlatformNotReady raise ConfigEntryNotReady("Webhook routes could not be registered")
routes = hass.data[DOMAIN].get("routes") routes = hass.data[DOMAIN].get("routes")
if routes is not None: if routes is not None:

View File

@ -226,7 +226,11 @@ class HealthCoordinator(DataUpdateCoordinator):
) )
async def _async_update_data(self) -> dict[str, Any]: async def _async_update_data(self) -> dict[str, Any]:
"""Refresh add-on health metadata from the WSLink proxy.""" """Refresh add-on health metadata from the WSLink proxy.
The proxy add-on can front any protocol (WU / WSLink / Ecowitt), so the probe
is not gated on a specific protocol option - it always runs.
"""
session = async_get_clientsession(self.hass, False) session = async_get_clientsession(self.hass, False)
url = get_url(self.hass) url = get_url(self.hass)
ip = await async_get_source_ip(self.hass) ip = await async_get_source_ip(self.hass)

View File

@ -9,14 +9,16 @@
"http" "http"
], ],
"documentation": "https://github.com/schizza/SWS-12500-custom-component", "documentation": "https://github.com/schizza/SWS-12500-custom-component",
"homekit": {}, "integration_type": "device",
"iot_class": "local_push", "iot_class": "local_push",
"issue_tracker": "https://github.com/schizza/SWS-12500-custom-component/issues", "issue_tracker": "https://github.com/schizza/SWS-12500-custom-component/issues",
"loggers": [
"aioecowitt"
],
"requirements": [ "requirements": [
"typecheck-runtime==0.2.0", "typecheck-runtime==0.2.0",
"aioecowitt==2025.9.2" "aioecowitt==2025.9.2"
], ],
"ssdp": [], "single_config_entry": true,
"version": "2.0.0-pre1", "version": "2.0.0-pre1"
"zeroconf": []
} }

View File

@ -27,7 +27,6 @@ from homeassistant.helpers.translation import async_get_translations
from .const import ( from .const import (
AZIMUT, AZIMUT,
CONNECTION_GATED_SENSORS, CONNECTION_GATED_SENSORS,
# DATABASE_PATH,
DEV_DBG, DEV_DBG,
OUTSIDE_HUMIDITY, OUTSIDE_HUMIDITY,
OUTSIDE_TEMP, OUTSIDE_TEMP,
@ -397,110 +396,3 @@ def battery_5step_to_pct(value: str) -> int | None:
return None return None
return round(int(value) / 5 * 100) return round(int(value) / 5 * 100)
#
# def long_term_units_in_statistics_meta():
# """Get units in long term statitstics."""
# sensor_units = []
# if not Path(DATABASE_PATH).exists():
# _LOGGER.error("Database file not found: %s", DATABASE_PATH)
# return False
#
# conn = sqlite3.connect(DATABASE_PATH)
# db = conn.cursor()
#
# try:
# db.execute(
# """
# SELECT statistic_id, unit_of_measurement from statistics_meta
# WHERE statistic_id LIKE 'sensor.weather_station_sws%'
# """
# )
# rows = db.fetchall()
# sensor_units = {
# statistic_id: f"{statistic_id} ({unit})" for statistic_id, unit in rows
# }
#
# except sqlite3.Error as e:
# _LOGGER.error("Error during data migration: %s", e)
# finally:
# conn.close()
#
# return sensor_units
#
#
# async def migrate_data(hass: HomeAssistant, sensor_id: str | None = None) -> int | bool:
# """Migrate data from mm/d to mm."""
#
# _LOGGER.debug("Sensor %s is required for data migration", sensor_id)
# updated_rows = 0
#
# if not Path(DATABASE_PATH).exists():
# _LOGGER.error("Database file not found: %s", DATABASE_PATH)
# return False
#
# conn = sqlite3.connect(DATABASE_PATH)
# db = conn.cursor()
#
# try:
# _LOGGER.info(sensor_id)
# db.execute(
# """
# UPDATE statistics_meta
# SET unit_of_measurement = 'mm'
# WHERE statistic_id = ?
# AND unit_of_measurement = 'mm/d';
# """,
# (sensor_id,),
# )
# updated_rows = db.rowcount
# conn.commit()
# _LOGGER.info(
# "Data migration completed successfully. Updated rows: %s for %s",
# updated_rows,
# sensor_id,
# )
#
# except sqlite3.Error as e:
# _LOGGER.error("Error during data migration: %s", e)
# finally:
# conn.close()
# return updated_rows
#
#
# def migrate_data_old(sensor_id: str | None = None):
# """Migrate data from mm/d to mm."""
# updated_rows = 0
#
# if not Path(DATABASE_PATH).exists():
# _LOGGER.error("Database file not found: %s", DATABASE_PATH)
# return False
#
# conn = sqlite3.connect(DATABASE_PATH)
# db = conn.cursor()
#
# try:
# _LOGGER.info(sensor_id)
# db.execute(
# """
# UPDATE statistics_meta
# SET unit_of_measurement = 'mm'
# WHERE statistic_id = ?
# AND unit_of_measurement = 'mm/d';
# """,
# (sensor_id,),
# )
# updated_rows = db.rowcount
# conn.commit()
# _LOGGER.info(
# "Data migration completed successfully. Updated rows: %s for %s",
# updated_rows,
# sensor_id,
# )
#
# except sqlite3.Error as e:
# _LOGGER.error("Error during data migration: %s", e)
# finally:
# conn.close()
# return updated_rows

View File

@ -199,8 +199,8 @@ async def test_async_setup_entry_creates_runtime_data_and_forwards_platforms(
async def test_async_setup_entry_fatal_when_register_path_returns_false( async def test_async_setup_entry_fatal_when_register_path_returns_false(
hass_with_http, monkeypatch hass_with_http, monkeypatch
): ):
"""Cover the fatal branch when `register_path` returns False -> PlatformNotReady.""" """Cover the fatal branch when `register_path` returns False -> ConfigEntryNotReady."""
from homeassistant.exceptions import PlatformNotReady from homeassistant.exceptions import ConfigEntryNotReady
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
@ -223,7 +223,7 @@ async def test_async_setup_entry_fatal_when_register_path_returns_false(
AsyncMock(return_value=True), AsyncMock(return_value=True),
) )
with pytest.raises(PlatformNotReady): with pytest.raises(ConfigEntryNotReady):
await async_setup_entry(hass_with_http, entry) await async_setup_entry(hass_with_http, entry)