Skip to content

Commit

Permalink
some code changes and hotfix for sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
Amateur-God committed Nov 3, 2024
1 parent fa80eb7 commit b3fb58e
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 132 deletions.
12 changes: 6 additions & 6 deletions custom_components/technitiumdns/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import aiohttp
import asyncio

Check warning

Code scanning / Pylint (reported by Codacy)

Missing module docstring Warning

Missing module docstring

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing module docstring Warning

Missing module docstring
import async_timeout
import logging
import aiohttp

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'aiohttp' (import-error) Warning

Unable to import 'aiohttp' (import-error)
import async_timeout

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'async_timeout' (import-error) Warning

Unable to import 'async_timeout' (import-error)

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -111,10 +111,10 @@ async def set_ad_blocking(self, enable):
return data
except aiohttp.ClientError as err:
_LOGGER.error("Error setting ad blocking: %s", err)
raise Exception(f"Error setting ad blocking: {err}")
except asyncio.TimeoutError:
raise Exception(f"Error setting ad blocking: {err}") from err
except asyncio.TimeoutError as e:

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "e" doesn't conform to snake_case naming style Warning

Variable name "e" doesn't conform to snake_case naming style

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "e" doesn't conform to snake_case naming style Warning

Variable name "e" doesn't conform to snake_case naming style
_LOGGER.error("Timeout error setting ad blocking")
raise Exception("Timeout error setting ad blocking")
raise Exception("Timeout error setting ad blocking") from e
except Exception as e:

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "e" doesn't conform to snake_case naming style Warning

Variable name "e" doesn't conform to snake_case naming style

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "e" doesn't conform to snake_case naming style Warning

Variable name "e" doesn't conform to snake_case naming style
_LOGGER.error("An error occurred: %s", e)
raise Exception(f"An error occurred: {e}")
raise Exception(f"An error occurred: {e}") from e
171 changes: 86 additions & 85 deletions custom_components/technitiumdns/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,85 +1,86 @@
"""Config flow for TechnitiumDNS integration."""

from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client
import aiohttp
import async_timeout
import voluptuous as vol

from .const import DOMAIN
from .api import TechnitiumDNSApi


@config_entries.HANDLERS.register(DOMAIN)
class TechnitiumDNSConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for TechnitiumDNS."""

VERSION = 1

async def async_step_user(self, user_input=None):
"""Handle the initial step."""
errors = {}
if user_input is not None:
try:
# Validate the input by trying to create the API object
api = TechnitiumDNSApi(user_input["api_url"], user_input["token"])
await api.get_statistics(user_input["stats_duration"])

return self.async_create_entry(
title=user_input["server_name"], data=user_input
)
except Exception as e:
errors["base"] = "auth"

data_schema = vol.Schema(
{
vol.Required("api_url"): str,
vol.Required("token"): str,
vol.Required("server_name"): str,
vol.Required("username"): str,
vol.Required("stats_duration"): vol.In(
["LastHour", "LastDay", "LastWeek", "LastMonth"]
),
}
)

return self.async_show_form(
step_id="user", data_schema=data_schema, errors=errors
)

async def _test_credentials(self, api_url, token, stats_duration):
"""Test the provided credentials."""
try:
session = aiohttp_client.async_get_clientsession(self.hass)
with async_timeout.timeout(10):
response = await session.get(
f"{api_url}/api/dashboard/stats/get?token={token}&type={stats_duration}&utc=true"
)
if (
response.status == 200
and (await response.json()).get("status") == "ok"
):
return True
except (aiohttp.ClientError, asyncio.TimeoutError):
pass
return False

@staticmethod
@callback
def async_get_options_flow(config_entry):
return TechnitiumDNSOptionsFlowHandler(config_entry)


class TechnitiumDNSOptionsFlowHandler(config_entries.OptionsFlow):
"""Handle an options flow for TechnitiumDNS."""

def __init__(self, config_entry):
self.config_entry = config_entry

async def async_step_init(self, user_input=None):
"""Manage the options."""
if user_input is not None:
return self.async_create_entry(title="", data=user_input)

return self.async_show_form(step_id="init", data_schema=vol.Schema({}))
"""Config flow for TechnitiumDNS integration."""


import asyncio
from homeassistant import config_entries

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'homeassistant' (import-error) Warning

Unable to import 'homeassistant' (import-error)
from homeassistant.core import callback

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'homeassistant.core' (import-error) Warning

Unable to import 'homeassistant.core' (import-error)
from homeassistant.helpers import aiohttp_client

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'homeassistant.helpers' (import-error) Warning

Unable to import 'homeassistant.helpers' (import-error)
import aiohttp

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'aiohttp' (import-error) Warning

Unable to import 'aiohttp' (import-error)
import async_timeout

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'async_timeout' (import-error) Warning

Unable to import 'async_timeout' (import-error)
import contextlib

Check warning

Code scanning / Pylint (reported by Codacy)

standard import "import contextlib" should be placed before "from homeassistant import config_entries" Warning

standard import "import contextlib" should be placed before "from homeassistant import config_entries"

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

standard import "import contextlib" should be placed before "from homeassistant import config_entries" Warning

standard import "import contextlib" should be placed before "from homeassistant import config_entries"
import voluptuous as vol

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'voluptuous' (import-error) Warning

Unable to import 'voluptuous' (import-error)

from .const import DOMAIN
from .api import TechnitiumDNSApi


@config_entries.HANDLERS.register(DOMAIN)
class TechnitiumDNSConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for TechnitiumDNS."""

VERSION = 1

async def async_step_user(self, user_input=None):
"""Handle the initial step."""
errors = {}
if user_input is not None:
try:
# Validate the input by trying to create the API object
api = TechnitiumDNSApi(user_input["api_url"], user_input["token"])
await api.get_statistics(user_input["stats_duration"])

return self.async_create_entry(
title=user_input["server_name"], data=user_input
)
except Exception as e:

Check warning

Code scanning / Prospector (reported by Codacy)

Unused variable 'e' (unused-variable) Warning

Unused variable 'e' (unused-variable)

Check notice

Code scanning / Pylint (reported by Codacy)

Unused variable 'e' Note

Unused variable 'e'

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "e" doesn't conform to snake_case naming style Warning

Variable name "e" doesn't conform to snake_case naming style

Check notice

Code scanning / Pylint (reported by Codacy)

Catching too general exception Exception Note

Catching too general exception Exception

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Catching too general exception Exception Note

Catching too general exception Exception

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "e" doesn't conform to snake_case naming style Warning

Variable name "e" doesn't conform to snake_case naming style

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Unused variable 'e' Note

Unused variable 'e'
errors["base"] = "auth"

data_schema = vol.Schema(
{
vol.Required("api_url"): str,
vol.Required("token"): str,
vol.Required("server_name"): str,
vol.Required("username"): str,
vol.Required("stats_duration"): vol.In(
["LastHour", "LastDay", "LastWeek", "LastMonth"]
),
}
)

return self.async_show_form(
step_id="user", data_schema=data_schema, errors=errors
)

async def _test_credentials(self, api_url, token, stats_duration):
"""Test the provided credentials."""
with contextlib.suppress(aiohttp.ClientError, asyncio.TimeoutError):
session = aiohttp_client.async_get_clientsession(self.hass)
with async_timeout.timeout(10):
response = await session.get(
f"{api_url}/api/dashboard/stats/get?token={token}&type={stats_duration}&utc=true"

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (101/100) Warning

Line too long (101/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (101/100) Warning

Line too long (101/100)
)
if (
response.status == 200

Check warning

Code scanning / Pylint (reported by Codacy)

Wrong hanging indentation before block (add 4 spaces). Warning

Wrong hanging indentation before block (add 4 spaces).
and (await response.json()).get("status") == "ok"

Check warning

Code scanning / Pylint (reported by Codacy)

Wrong hanging indentation before block (add 4 spaces). Warning

Wrong hanging indentation before block (add 4 spaces).
):
return True
return False

@staticmethod
@callback
def async_get_options_flow(config_entry):

Check warning

Code scanning / Pylint (reported by Codacy)

Missing method docstring Warning

Missing method docstring

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning

Missing function or method docstring
return TechnitiumDNSOptionsFlowHandler(config_entry)


class TechnitiumDNSOptionsFlowHandler(config_entries.OptionsFlow):

Check warning

Code scanning / Pylint (reported by Codacy)

Too few public methods (1/2) Warning

Too few public methods (1/2)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Too few public methods (1/2) Warning

Too few public methods (1/2)
"""Handle an options flow for TechnitiumDNS."""

def __init__(self, config_entry):
self.config_entry = config_entry

async def async_step_init(self, user_input=None):
"""Manage the options."""
if user_input is not None:
return self.async_create_entry(title="", data=user_input)

return self.async_show_form(step_id="init", data_schema=vol.Schema({}))
78 changes: 39 additions & 39 deletions custom_components/technitiumdns/const.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
"""Constants for the TechnitiumDNS integration."""

DOMAIN = "technitiumdns"

DURATION_OPTIONS = ["LastHour", "LastDay", "LastWeek", "LastMonth"]

AD_BLOCKING_SWITCH = "Enable Ad Blocking"

AD_BLOCKING_DURATION_OPTIONS = {
5: "Disable Ad Blocking for 5 Minutes",
10: "Disable Ad Blocking for 10 Minutes",
30: "Disable Ad Blocking for 30 Minutes",
60: "Disable Ad Blocking for 60 Minutes",
1440: "Disable Ad Blocking for 1 Day",
}

SENSOR_TYPES = {
"queries": {"name": "Total Queries", "state_class": "measurement", "device_class": "count"},
"blocked_queries": {"name": "Blocked Queries", "state_class": "measurement", "device_class": "count"},
"clients": {"name": "Clients", "state_class": "measurement", "device_class": "count"},
"update_available": {"name": "Update Available", "state_class": None, "device_class": "update"},
"no_error": {"name": "Total No Error", "state_class": "measurement", "device_class": "count"},
"server_failure": {"name": "Total Server Failure", "state_class": "measurement", "device_class": "count"},
"nx_domain": {"name": "Total NX Domain", "state_class": "measurement", "device_class": "count"},
"refused": {"name": "Total Refused", "state_class": "measurement", "device_class": "count"},
"authoritative": {"name": "Total Authoritative", "state_class": "measurement", "device_class": "count"},
"recursive": {"name": "Total Recursive", "state_class": "measurement", "device_class": "count"},
"cached": {"name": "Total Cached", "state_class": "measurement", "device_class": "count"},
"dropped": {"name": "Total Dropped", "state_class": "measurement", "device_class": "count"},
"zones": {"name": "Zones", "state_class": "measurement", "device_class": "count"},
"cached_entries": {"name": "Cached Entries", "state_class": "measurement", "device_class": "count"},
"allowed_zones": {"name": "Allowed Zones", "state_class": "measurement", "device_class": "count"},
"blocked_zones": {"name": "Blocked Zones", "state_class": "measurement", "device_class": "count"},
"allow_list_zones": {"name": "Allow List Zones", "state_class": "measurement", "device_class": "count"},
"block_list_zones": {"name": "Block List Zones", "state_class": "measurement", "device_class": "count"},
"top_clients": {"name": "Top Clients", "state_class": None, "device_class": None},
"top_domains": {"name": "Top Domains", "state_class": None, "device_class": None},
"top_blocked_domains": {"name": "Top Blocked Domains", "state_class": None, "device_class": None},
}
"""Constants for the TechnitiumDNS integration."""

DOMAIN = "technitiumdns"

DURATION_OPTIONS = ["LastHour", "LastDay", "LastWeek", "LastMonth"]

AD_BLOCKING_SWITCH = "Enable Ad Blocking"

AD_BLOCKING_DURATION_OPTIONS = {
5: "Disable Ad Blocking for 5 Minutes",
10: "Disable Ad Blocking for 10 Minutes",
30: "Disable Ad Blocking for 30 Minutes",
60: "Disable Ad Blocking for 60 Minutes",
1440: "Disable Ad Blocking for 1 Day",
}

SENSOR_TYPES = {
"queries": {"name": "Total Queries", "state_class": "measurement", "device_class": "count"},
"blocked_queries": {"name": "Blocked Queries", "state_class": "measurement", "device_class": "count"},

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (106/100) Warning

Line too long (106/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (106/100) Warning

Line too long (106/100)
"clients": {"name": "Clients", "state_class": "measurement", "device_class": "count"},
"update_available": {"name": "Update Available", "state_class": None, "device_class": "update"},
"no_error": {"name": "Total No Error", "state_class": "measurement", "device_class": "count"},
"server_failure": {"name": "Total Server Failure", "state_class": "measurement", "device_class": "count"},

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (110/100) Warning

Line too long (110/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (110/100) Warning

Line too long (110/100)
"nx_domain": {"name": "Total NX Domain", "state_class": "measurement", "device_class": "count"},
"refused": {"name": "Total Refused", "state_class": "measurement", "device_class": "count"},
"authoritative": {"name": "Total Authoritative", "state_class": "measurement", "device_class": "count"},

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (108/100) Warning

Line too long (108/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (108/100) Warning

Line too long (108/100)
"recursive": {"name": "Total Recursive", "state_class": "measurement", "device_class": "count"},
"cached": {"name": "Total Cached", "state_class": "measurement", "device_class": "count"},
"dropped": {"name": "Total Dropped", "state_class": "measurement", "device_class": "count"},
"zones": {"name": "Zones", "state_class": "measurement", "device_class": "count"},
"cached_entries": {"name": "Cached Entries", "state_class": "measurement", "device_class": "count"},

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (104/100) Warning

Line too long (104/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (104/100) Warning

Line too long (104/100)
"allowed_zones": {"name": "Allowed Zones", "state_class": "measurement", "device_class": "count"},

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (102/100) Warning

Line too long (102/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (102/100) Warning

Line too long (102/100)
"blocked_zones": {"name": "Blocked Zones", "state_class": "measurement", "device_class": "count"},

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (102/100) Warning

Line too long (102/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (102/100) Warning

Line too long (102/100)
"allow_list_zones": {"name": "Allow List Zones", "state_class": "measurement", "device_class": "count"},

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (108/100) Warning

Line too long (108/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (108/100) Warning

Line too long (108/100)
"block_list_zones": {"name": "Block List Zones", "state_class": "measurement", "device_class": "count"},

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (108/100) Warning

Line too long (108/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (108/100) Warning

Line too long (108/100)
"top_clients": {"name": "Top Clients", "state_class": None, "device_class": None},
"top_domains": {"name": "Top Domains", "state_class": None, "device_class": None},
"top_blocked_domains": {"name": "Top Blocked Domains", "state_class": None, "device_class": None},

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (102/100) Warning

Line too long (102/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (102/100) Warning

Line too long (102/100)
}
10 changes: 8 additions & 2 deletions custom_components/technitiumdns/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,14 @@ def state(self):
@property
def extra_state_attributes(self):
"""Return additional attributes in a table-friendly format based on sensor type."""
attributes = {}

attributes = {
"queries": self.coordinator.data.get("queries"),
"blocked_queries": self.coordinator.data.get("blocked_queries"),
"clients": self.coordinator.data.get("clients"),
"update_available": self.coordinator.data.get("update_available"),
}

# Add structured table data based on the sensor type
if self._sensor_type == 'top_clients':
attributes["top_clients_table"] = [
{"Client": client.get('name', 'Unknown'), "Hits": client.get('hits', 0)}
Expand Down

0 comments on commit b3fb58e

Please sign in to comment.