fix: minor fixes
Some checks failed
🧪 Integration Testing / 🔧 Test Integration (2025.9.4, 3.10) (push) Failing after 32s
🧪 Integration Testing / 🔧 Test Integration (2025.9.4, 3.11) (push) Failing after 14s
🧪 Integration Testing / 🔧 Test Integration (2025.9.4, 3.12) (push) Failing after 15s
🧪 Integration Testing / 🔧 Test Integration (2025.9.4, 3.13) (push) Failing after 1m57s
🧪 Integration Testing / 🔧 Test Integration (2025.9.4, 3.9) (push) Failing after 28s
🛡️ Code Quality & Security Check / 🔍 Code Quality Analysis (push) Failing after 19s

Signed-off-by: Rafal Zielinski <sq4ind@gmail.com>
This commit is contained in:
2025-09-28 13:55:19 +01:00
parent e29f7c025b
commit 329de0de5d
6 changed files with 25 additions and 17 deletions

View File

@@ -12,8 +12,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
python-version: ['3.11', '3.12'] python-version: ['3.9','3.10','3.11','3.12','3.13']
home-assistant-version: ['2023.12.0', '2024.1.0'] home-assistant-version: ['2025.9.4']
steps: steps:
- name: 📥 Checkout Code - name: 📥 Checkout Code

View File

@@ -24,7 +24,7 @@ jobs:
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install flake8 black isort mypy bandit safety pip install flake8 black isort mypy bandit safety
pip install homeassistant==2023.12.0 pip install homeassistant==2025.9.4
pip install -r requirements-dev.txt || echo "No dev requirements found" pip install -r requirements-dev.txt || echo "No dev requirements found"
- name: 🎨 Check Code Formatting (Black) - name: 🎨 Check Code Formatting (Black)

View File

@@ -18,6 +18,7 @@ from .api import AdGuardHomeAPI
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up AdGuard Control Hub from a config entry.""" """Set up AdGuard Control Hub from a config entry."""
session = async_get_clientsession(hass, entry.data.get(CONF_VERIFY_SSL, True)) session = async_get_clientsession(hass, entry.data.get(CONF_VERIFY_SSL, True))
@@ -34,8 +35,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# Test the connection # Test the connection
try: try:
await api.test_connection() await api.test_connection()
_LOGGER.info("Successfully connected to AdGuard Home at %s:%s", _LOGGER.info("Successfully connected to AdGuard Home at %s:%s",
entry.data[CONF_HOST], entry.data[CONF_PORT]) entry.data[CONF_HOST], entry.data[CONF_PORT])
except Exception as err: except Exception as err:
_LOGGER.error("Failed to connect to AdGuard Home: %s", err) _LOGGER.error("Failed to connect to AdGuard Home: %s", err)
raise ConfigEntryNotReady(f"Unable to connect: {err}") raise ConfigEntryNotReady(f"Unable to connect: {err}")
@@ -57,6 +58,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
_LOGGER.info("AdGuard Control Hub setup complete") _LOGGER.info("AdGuard Control Hub setup complete")
return True return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload AdGuard Control Hub config entry.""" """Unload AdGuard Control Hub config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
@@ -66,6 +68,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return unload_ok return unload_ok
class AdGuardControlHubCoordinator(DataUpdateCoordinator): class AdGuardControlHubCoordinator(DataUpdateCoordinator):
"""AdGuard Control Hub data update coordinator.""" """AdGuard Control Hub data update coordinator."""
@@ -88,7 +91,7 @@ class AdGuardControlHubCoordinator(DataUpdateCoordinator):
# Fetch all data concurrently for better performance # Fetch all data concurrently for better performance
results = await asyncio.gather( results = await asyncio.gather(
self.api.get_clients(), self.api.get_clients(),
self.api.get_statistics(), self.api.get_statistics(),
self.api.get_status(), self.api.get_status(),
return_exceptions=True, return_exceptions=True,
) )
@@ -103,7 +106,7 @@ class AdGuardControlHubCoordinator(DataUpdateCoordinator):
# Update stored data (use empty dict if fetch failed) # Update stored data (use empty dict if fetch failed)
self._clients = { self._clients = {
client["name"]: client client["name"]: client
for client in (clients.get("clients", []) if not isinstance(clients, Exception) else []) for client in (clients.get("clients", []) if not isinstance(clients, Exception) else [])
} }
self._statistics = statistics if not isinstance(statistics, Exception) else {} self._statistics = statistics if not isinstance(statistics, Exception) else {}
@@ -123,7 +126,7 @@ class AdGuardControlHubCoordinator(DataUpdateCoordinator):
"""Return clients data.""" """Return clients data."""
return self._clients return self._clients
@property @property
def statistics(self): def statistics(self):
"""Return statistics data.""" """Return statistics data."""
return self._statistics return self._statistics
@@ -131,4 +134,4 @@ class AdGuardControlHubCoordinator(DataUpdateCoordinator):
@property @property
def protection_status(self): def protection_status(self):
"""Return protection status data.""" """Return protection status data."""
return self._protection_status return self._protection_status

View File

@@ -7,11 +7,12 @@ from .const import API_ENDPOINTS
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
class AdGuardHomeAPI: class AdGuardHomeAPI:
"""API wrapper for AdGuard Home.""" """API wrapper for AdGuard Home."""
def __init__(self, host: str, port: int = 3000, username: str = None, def __init__(self, host: str, port: int = 3000, username: str = None,
password: str = None, ssl: bool = False, session = None): password: str = None, ssl: bool = False, session=None):
self.host = host self.host = host
self.port = port self.port = port
self.username = username self.username = username
@@ -88,7 +89,8 @@ class AdGuardHomeAPI:
return None return None
async def update_client_blocked_services(self, client_name: str, blocked_services: list, schedule: dict = None) -> dict: async def update_client_blocked_services(self, client_name: str, blocked_services: list,
schedule: dict = None) -> dict:
"""Update blocked services for a specific client.""" """Update blocked services for a specific client."""
client = await self.get_client_by_name(client_name) client = await self.get_client_by_name(client_name)
if not client: if not client:
@@ -139,4 +141,4 @@ class AdGuardHomeAPI:
elif not enabled and service_id in service_ids: elif not enabled and service_id in service_ids:
service_ids.remove(service_id) service_ids.remove(service_id)
return await self.update_client_blocked_services(client_name, service_ids) return await self.update_client_blocked_services(client_name, service_ids)

View File

@@ -1,13 +1,12 @@
{ {
"domain": "adguard_hub", "domain": "adguard_hub",
"name": "AdGuard Control Hub", "name": "AdGuard Control Hub",
"codeowners": ["@your-gitea-username"], "codeowners": ["@sq4ind"],
"config_flow": true, "config_flow": true,
"dependencies": [], "dependencies": [],
"documentation": "https://your-gitea-domain.com/your-username/adguard-control-hub", "documentation": "https://git.sq4ind.eu/sq4ind/adguard-control-hub",
"integration_type": "hub", "integration_type": "hub",
"iot_class": "local_polling", "iot_class": "local_polling",
"issue_tracker": "https://your-gitea-domain.com/your-username/adguard-control-hub/issues",
"requirements": [ "requirements": [
"aiohttp>=3.8.0" "aiohttp>=3.8.0"
], ],

View File

@@ -11,6 +11,7 @@ from .const import DOMAIN, ICON_PROTECTION, ICON_PROTECTION_OFF, ICON_CLIENT, MA
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback): async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback):
"""Set up AdGuard Control Hub switch platform.""" """Set up AdGuard Control Hub switch platform."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"] coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
@@ -26,6 +27,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
async_add_entities(entities) async_add_entities(entities)
class AdGuardBaseSwitch(CoordinatorEntity, SwitchEntity): class AdGuardBaseSwitch(CoordinatorEntity, SwitchEntity):
"""Base class for AdGuard switches.""" """Base class for AdGuard switches."""
@@ -39,6 +41,7 @@ class AdGuardBaseSwitch(CoordinatorEntity, SwitchEntity):
"model": "AdGuard Home", "model": "AdGuard Home",
} }
class AdGuardProtectionSwitch(AdGuardBaseSwitch): class AdGuardProtectionSwitch(AdGuardBaseSwitch):
"""Switch to control global AdGuard protection.""" """Switch to control global AdGuard protection."""
@@ -63,6 +66,7 @@ class AdGuardProtectionSwitch(AdGuardBaseSwitch):
await self.api.set_protection(False) await self.api.set_protection(False)
await self.coordinator.async_request_refresh() await self.coordinator.async_request_refresh()
class AdGuardClientSwitch(AdGuardBaseSwitch): class AdGuardClientSwitch(AdGuardBaseSwitch):
"""Switch to control client-specific protection.""" """Switch to control client-specific protection."""
@@ -86,4 +90,4 @@ class AdGuardClientSwitch(AdGuardBaseSwitch):
async def async_turn_off(self, **kwargs): async def async_turn_off(self, **kwargs):
# This would update client settings - simplified for basic functionality # This would update client settings - simplified for basic functionality
_LOGGER.info("Would disable protection for %s", self.client_name) _LOGGER.info("Would disable protection for %s", self.client_name)
await self.coordinator.async_request_refresh() await self.coordinator.async_request_refresh()