Skip to content

Commit bc1d975

Browse files
authored
Merge pull request #38 from Shocker/fix-string-sensors
2 parents 0c338d9 + 57c7f1e commit bc1d975

7 files changed

Lines changed: 56 additions & 54 deletions

File tree

custom_components/http_agent/binary_sensor.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
DOMAIN,
2020
)
2121
from .coordinator import HTTPAgentCoordinator
22+
from .helpers import get_sensor_config
2223

2324
_LOGGER = logging.getLogger(__name__)
2425

@@ -65,16 +66,7 @@ def __init__(
6566
self._attr_name = sensor_name
6667
self._attr_unique_id = f"{entry.entry_id}_{sensor_name}"
6768

68-
# Find sensor config
69-
self.sensor_config = None
70-
data = dict(entry.data)
71-
if entry.options:
72-
data.update(entry.options)
73-
74-
for config in data[CONF_SENSORS]:
75-
if config[CONF_SENSOR_NAME] == sensor_name:
76-
self.sensor_config = config
77-
break
69+
self.sensor_config = get_sensor_config(entry, sensor_name)
7870

7971
@property
8072
def name(self) -> str:

custom_components/http_agent/config_flow.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,10 @@ async def async_step_sensor_config(
278278
sensor_config = dict(self.current_sensor)
279279
sensor_config.update(user_input)
280280

281+
# HA forms can return None for empty optional text fields.
282+
if sensor_config.get(CONF_SENSOR_UNIT) is None:
283+
sensor_config[CONF_SENSOR_UNIT] = ""
284+
281285
# Add optional fields that may not be in user_input
282286
optional_fields = [
283287
CONF_SENSOR_STATE,
@@ -665,11 +669,12 @@ async def async_step_modify_sensor(
665669
sensor_config[CONF_SENSOR_DEVICE_CLASS] = user_input[
666670
CONF_SENSOR_DEVICE_CLASS
667671
]
668-
if user_input.get(CONF_SENSOR_UNIT):
669-
sensor_config[CONF_SENSOR_UNIT] = user_input[CONF_SENSOR_UNIT]
670672

671-
# Add tracker fields if it's a device tracker
672673
sensor_type = sensor_config[CONF_SENSOR_TYPE]
674+
if sensor_type in ("sensor", "number"):
675+
sensor_config[CONF_SENSOR_UNIT] = user_input.get(CONF_SENSOR_UNIT) or ""
676+
677+
# Add tracker fields if it's a device tracker
673678
if sensor_type == "device_tracker":
674679
if user_input.get(CONF_TRACKER_LATITUDE):
675680
sensor_config[CONF_TRACKER_LATITUDE] = user_input[
@@ -718,9 +723,7 @@ async def async_step_modify_sensor(
718723
default=sensor.get(CONF_SENSOR_DEVICE_CLASS, ""),
719724
)
720725
] = vol.In(device_classes)
721-
schema_dict[
722-
vol.Optional(CONF_SENSOR_UNIT, default=sensor.get(CONF_SENSOR_UNIT, ""))
723-
] = str
726+
schema_dict[vol.Optional(CONF_SENSOR_UNIT)] = str
724727
elif sensor_type == "binary_sensor":
725728
device_classes = {"": ""} | {dc: dc for dc in BINARY_SENSOR_DEVICE_CLASSES}
726729
schema_dict[
@@ -737,9 +740,7 @@ async def async_step_modify_sensor(
737740
default=sensor.get(CONF_SENSOR_DEVICE_CLASS, ""),
738741
)
739742
] = vol.In(device_classes)
740-
schema_dict[
741-
vol.Optional(CONF_SENSOR_UNIT, default=sensor.get(CONF_SENSOR_UNIT, ""))
742-
] = str
743+
schema_dict[vol.Optional(CONF_SENSOR_UNIT)] = str
743744
elif sensor_type == "device_tracker":
744745
# Add device tracker specific fields
745746
schema_dict[
@@ -767,10 +768,13 @@ async def async_step_modify_sensor(
767768
] = vol.In(["none", "gps", "router", "bluetooth", "bluetooth_le"])
768769

769770
schema = vol.Schema(schema_dict)
771+
suggested_values: dict[str, Any] = {}
772+
if sensor_type in ("sensor", "number"):
773+
suggested_values[CONF_SENSOR_UNIT] = sensor.get(CONF_SENSOR_UNIT) or ""
770774

771775
return self.async_show_form(
772776
step_id="modify_sensor",
773-
data_schema=schema,
777+
data_schema=self.add_suggested_values_to_schema(schema, suggested_values),
774778
)
775779

776780
async def async_step_add_sensor(
@@ -806,6 +810,10 @@ async def async_step_sensor_config(
806810
sensor_config = dict(self.current_sensor)
807811
sensor_config.update(user_input)
808812

813+
# HA forms can return None for empty optional text fields.
814+
if sensor_config.get(CONF_SENSOR_UNIT) is None:
815+
sensor_config[CONF_SENSOR_UNIT] = ""
816+
809817
# Add optional fields that may not be in user_input
810818
optional_fields = [
811819
CONF_SENSOR_STATE,

custom_components/http_agent/coordinator.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
from datetime import timedelta
77
import json
88
import logging
9+
import re
910
from typing import Any
1011
from xml.etree import ElementTree as ET
1112

1213
import aiohttp
1314
from bs4 import BeautifulSoup
14-
import re
1515

1616
from homeassistant.core import HomeAssistant
1717
from homeassistant.helpers.template import Template
@@ -348,7 +348,7 @@ def _extract_regex_value(self, text: str, selector: str) -> Any:
348348

349349
last_slash = selector.rfind("/")
350350
pattern = selector[1:last_slash]
351-
flags_str = selector[last_slash + 1:]
351+
flags_str = selector[last_slash + 1 :]
352352

353353
flag_map = {
354354
"i": re.I,
@@ -372,11 +372,13 @@ def _extract_regex_value(self, text: str, selector: str) -> Any:
372372

373373
try:
374374
match = re.search(pattern, text, re_flags)
375-
if match:
375+
if match and match.lastindex is not None:
376376
if match.lastindex == 1:
377377
return match.group(1)
378378
elif match.lastindex > 1:
379-
return "|".join(match.group(i) for i in range(1, match.lastindex + 1))
379+
return "|".join(
380+
match.group(i) for i in range(1, match.lastindex + 1)
381+
)
380382
except Exception:
381383
pass
382384

custom_components/http_agent/device_tracker.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
DOMAIN,
2020
)
2121
from .coordinator import HTTPAgentCoordinator
22+
from .helpers import get_sensor_config
2223

2324
_LOGGER = logging.getLogger(__name__)
2425

@@ -65,16 +66,7 @@ def __init__(
6566
self._attr_name = sensor_name
6667
self._attr_unique_id = f"{entry.entry_id}_{sensor_name}"
6768

68-
# Find sensor config
69-
self.sensor_config = None
70-
data = dict(entry.data)
71-
if entry.options:
72-
data.update(entry.options)
73-
74-
for config in data[CONF_SENSORS]:
75-
if config[CONF_SENSOR_NAME] == sensor_name:
76-
self.sensor_config = config
77-
break
69+
self.sensor_config = get_sensor_config(entry, sensor_name)
7870

7971
@property
8072
def name(self) -> str:
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Helper utilities for HTTP Agent entities."""
2+
3+
from typing import Any
4+
5+
from homeassistant.config_entries import ConfigEntry
6+
7+
from .const import CONF_SENSOR_NAME, CONF_SENSOR_UNIT, CONF_SENSORS
8+
9+
10+
def get_sensor_config(entry: ConfigEntry, sensor_name: str) -> dict[str, Any] | None:
11+
"""Return sensor config by name from merged entry data and options."""
12+
data = dict(entry.data)
13+
if entry.options:
14+
data.update(entry.options)
15+
16+
for config in data.get(CONF_SENSORS, []):
17+
if config.get(CONF_SENSOR_NAME) == sensor_name:
18+
# Ensure measurement unit is explicitly set to None if not provided to prevent casting to int by HA core
19+
if not config.get(CONF_SENSOR_UNIT):
20+
config[CONF_SENSOR_UNIT] = None
21+
22+
return config
23+
24+
return None

custom_components/http_agent/number.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
DOMAIN,
2121
)
2222
from .coordinator import HTTPAgentCoordinator
23+
from .helpers import get_sensor_config
2324

2425
_LOGGER = logging.getLogger(__name__)
2526

@@ -69,16 +70,7 @@ def __init__(
6970
# Number entities are read-only for HTTP Agent
7071
self._attr_mode = "box"
7172

72-
# Find sensor config
73-
self.sensor_config = None
74-
data = dict(entry.data)
75-
if entry.options:
76-
data.update(entry.options)
77-
78-
for config in data[CONF_SENSORS]:
79-
if config[CONF_SENSOR_NAME] == sensor_name:
80-
self.sensor_config = config
81-
break
73+
self.sensor_config = get_sensor_config(entry, sensor_name)
8274

8375
@property
8476
def name(self) -> str:

custom_components/http_agent/sensor.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
DOMAIN,
2121
)
2222
from .coordinator import HTTPAgentCoordinator
23+
from .helpers import get_sensor_config
2324

2425
_LOGGER = logging.getLogger(__name__)
2526

@@ -96,16 +97,7 @@ def __init__(
9697
self._attr_name = sensor_name
9798
self._attr_unique_id = f"{entry.entry_id}_{sensor_name}"
9899

99-
# Find sensor config
100-
self.sensor_config = None
101-
data = dict(entry.data)
102-
if entry.options:
103-
data.update(entry.options)
104-
105-
for config in data[CONF_SENSORS]:
106-
if config[CONF_SENSOR_NAME] == sensor_name:
107-
self.sensor_config = config
108-
break
100+
self.sensor_config = get_sensor_config(entry, sensor_name)
109101

110102
@property
111103
def name(self) -> str:

0 commit comments

Comments
 (0)