Skip to content

Commit 0f4ecb8

Browse files
Merge pull request #85 from andrew-codechimp/equal-updates
Equal updates
2 parents c1314ef + 7bdb4b4 commit 0f4ecb8

16 files changed

Lines changed: 228 additions & 58 deletions

File tree

.devcontainer-lock.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"features": {
3+
"ghcr.io/devcontainers-extra/features/apt-packages:1": {
4+
"version": "1.0.6",
5+
"resolved": "ghcr.io/devcontainers-extra/features/apt-packages@sha256:55c54412112da81b9381e470cdbbe55278564950d1ff536ce925b1e8e096babd",
6+
"integrity": "sha256:55c54412112da81b9381e470cdbbe55278564950d1ff536ce925b1e8e096babd"
7+
},
8+
"ghcr.io/devcontainers/features/git:1": {
9+
"version": "1.3.5",
10+
"resolved": "ghcr.io/devcontainers/features/git@sha256:27905dc196c01f77d6ba8709cb82eeaf330b3b108772e2f02d1cd0d826de1251",
11+
"integrity": "sha256:27905dc196c01f77d6ba8709cb82eeaf330b3b108772e2f02d1cd0d826de1251"
12+
},
13+
"ghcr.io/devcontainers/features/node:2": {
14+
"version": "2.0.0",
15+
"resolved": "ghcr.io/devcontainers/features/node@sha256:fedd4c11f7adfb64283b578dddc7da906728daa25fa293351c9d913231acf12f",
16+
"integrity": "sha256:fedd4c11f7adfb64283b578dddc7da906728daa25fa293351c9d913231acf12f"
17+
}
18+
}
19+
}

.vscode/settings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
{
22
"git.autofetch": true,
33
"python.createEnvironment.trigger": "off",
4+
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
5+
"python.analysis.extraPaths": [
6+
"${workspaceFolder}",
7+
"${workspaceFolder}/custom_components"
8+
],
9+
"python.analysis.diagnosticSeverityOverrides": {
10+
"reportUnsortedImports": "none"
11+
},
412
"editor.defaultFormatter": "charliermarsh.ruff",
513
"editor.formatOnSave": true,
614
"editor.codeActionsOnSave": {

custom_components/periodic_min_max/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,24 @@
99
import voluptuous as vol
1010
from awesomeversion.awesomeversion import AwesomeVersion
1111

12-
from homeassistant.core import HomeAssistant, callback
12+
from homeassistant.config_entries import ConfigEntry
1313
from homeassistant.const import (
1414
CONF_ENTITY_ID,
1515
__version__ as HA_VERSION, # noqa: N812
1616
)
17-
from homeassistant.helpers import entity_registry as er, config_validation as cv
18-
from homeassistant.config_entries import ConfigEntry
19-
from homeassistant.helpers.typing import ConfigType
17+
from homeassistant.core import HomeAssistant, callback
18+
from homeassistant.helpers import config_validation as cv, entity_registry as er
2019
from homeassistant.helpers.helper_integration import (
2120
async_handle_source_entity_changes,
2221
async_remove_helper_config_entry_from_source_device,
2322
)
23+
from homeassistant.helpers.typing import ConfigType
2424

2525
from .const import (
2626
DOMAIN,
2727
LOGGER,
28-
PLATFORMS,
2928
MIN_HA_VERSION,
29+
PLATFORMS,
3030
)
3131
from .services import async_setup_services
3232

custom_components/periodic_min_max/config_flow.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22

33
from __future__ import annotations
44

5-
from typing import Any, cast
65
from collections.abc import Mapping
6+
from typing import Any, cast
77

88
import voluptuous as vol
99

10-
from homeassistant.const import CONF_TYPE, CONF_ENTITY_ID
11-
from homeassistant.helpers import selector
10+
from homeassistant.components.input_number import DOMAIN as INPUT_NUMBER_DOMAIN
1211
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
1312
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
14-
from homeassistant.components.input_number import DOMAIN as INPUT_NUMBER_DOMAIN
13+
from homeassistant.const import CONF_ENTITY_ID, CONF_TYPE
14+
from homeassistant.helpers import selector
1515
from homeassistant.helpers.schema_config_entry_flow import (
16-
SchemaFlowFormStep,
1716
SchemaConfigFlowHandler,
17+
SchemaFlowFormStep,
1818
)
1919

20-
from .const import DOMAIN
20+
from .const import CONF_EQUAL_UPDATES, DOMAIN
2121

2222
_STATISTIC_MEASURES = ["min", "max"]
2323

@@ -35,6 +35,7 @@
3535
options=_STATISTIC_MEASURES, translation_key=CONF_TYPE
3636
),
3737
),
38+
vol.Required(CONF_EQUAL_UPDATES, default=False): selector.BooleanSelector(),
3839
}
3940
)
4041

custom_components/periodic_min_max/const.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@
1313

1414
PLATFORMS = [Platform.SENSOR]
1515

16+
CONF_EQUAL_UPDATES = "equal_updates"
17+
1618
ATTR_LAST_MODIFIED = "last_modified"

custom_components/periodic_min_max/sensor.py

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,36 @@
22

33
from __future__ import annotations
44

5-
from typing import Any
65
from datetime import datetime
6+
from typing import Any
77

88
import voluptuous as vol
99

10-
from homeassistant.core import Event, HomeAssistant, EventStateChangedData, callback
11-
from homeassistant.util import dt as dt_util
10+
from homeassistant.components.sensor import (
11+
SensorDeviceClass,
12+
SensorEntity,
13+
SensorStateClass,
14+
)
15+
from homeassistant.config_entries import ConfigEntry
1216
from homeassistant.const import (
13-
CONF_TYPE,
14-
STATE_UNKNOWN,
17+
ATTR_UNIT_OF_MEASUREMENT,
1518
CONF_ENTITY_ID,
19+
CONF_TYPE,
1620
STATE_UNAVAILABLE,
17-
ATTR_UNIT_OF_MEASUREMENT,
21+
STATE_UNKNOWN,
1822
)
23+
from homeassistant.core import Event, EventStateChangedData, HomeAssistant, callback
1924
from homeassistant.helpers import device_registry as dr, entity_registry as er
25+
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
2026
from homeassistant.helpers.event import (
21-
async_track_state_change_event,
2227
async_track_entity_registry_updated_event,
23-
)
24-
from homeassistant.config_entries import ConfigEntry
25-
from homeassistant.helpers.typing import StateType
26-
from homeassistant.components.sensor import (
27-
SensorEntity,
28-
SensorStateClass,
29-
SensorDeviceClass,
28+
async_track_state_change_event,
3029
)
3130
from homeassistant.helpers.restore_state import RestoreEntity
32-
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
31+
from homeassistant.helpers.typing import StateType
32+
from homeassistant.util import dt as dt_util
3333

34-
from .const import (
35-
LOGGER,
36-
ATTR_LAST_MODIFIED,
37-
)
34+
from .const import ATTR_LAST_MODIFIED, CONF_EQUAL_UPDATES, LOGGER
3835

3936
ATTR_MIN_VALUE = "min_value"
4037
ATTR_MAX_VALUE = "max_value"
@@ -91,6 +88,7 @@ async def async_setup_entry(
9188
device_id = source_entity.device_id if source_entity else None
9289

9390
sensor_type = config_entry.options[CONF_TYPE]
91+
equal_updates = config_entry.options.get(CONF_EQUAL_UPDATES, False)
9492

9593
async def async_registry_updated(
9694
event: Event[er.EventEntityRegistryUpdatedData],
@@ -138,6 +136,7 @@ async def async_registry_updated(
138136
source_entity_id,
139137
config_entry.title,
140138
sensor_type,
139+
equal_updates,
141140
config_entry.entry_id,
142141
)
143142
]
@@ -155,18 +154,20 @@ class PeriodicMinMaxSensor(SensorEntity, RestoreEntity):
155154
_state_had_real_change = False
156155
_attr_last_modified: str = dt_util.utcnow().isoformat()
157156

158-
def __init__(
157+
def __init__( # noqa: PLR0913
159158
self,
160159
hass: HomeAssistant,
161160
source_entity_id: str,
162161
name: str | None,
163162
sensor_type: str,
163+
equal_updates: bool,
164164
unique_id: str | None,
165165
) -> None:
166166
"""Initialize the min/max sensor."""
167167
self._attr_unique_id = unique_id
168168
self._source_entity_id = source_entity_id
169169
self._sensor_type = sensor_type
170+
self._equal_updates = equal_updates
170171

171172
if name:
172173
self._attr_name = name
@@ -325,18 +326,23 @@ def _calc_values(self) -> None:
325326
"""Calculate the values."""
326327
self._state_had_real_change = False
327328

328-
"""Calculate min value, honoring unknown states."""
329+
if self._state in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
330+
return
331+
329332
if self._sensor_attr == ATTR_MIN_VALUE:
330-
if self._state not in [STATE_UNKNOWN, STATE_UNAVAILABLE] and (
331-
self.min_value is None or self.min_value > self._state
333+
if self.min_value is None or (
334+
self.min_value >= self._state
335+
if self._equal_updates
336+
else self.min_value > self._state
332337
):
333338
self.min_value = self._state
334339
self._state_had_real_change = True
335340

336-
"""Calculate max value, honoring unknown states."""
337341
if self._sensor_attr == ATTR_MAX_VALUE:
338-
if self._state not in [STATE_UNKNOWN, STATE_UNAVAILABLE] and (
339-
self.max_value is None or self.max_value < self._state
342+
if self.max_value is None or (
343+
self.max_value <= self._state
344+
if self._equal_updates
345+
else self.max_value < self._state
340346
):
341347
self.max_value = self._state
342348
self._state_had_real_change = True

custom_components/periodic_min_max/services.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
from __future__ import annotations
44

5+
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
56
from homeassistant.core import HomeAssistant, callback
67
from homeassistant.helpers import service
7-
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
88

99
from .const import DOMAIN
1010

custom_components/periodic_min_max/translations/de.json

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@
66
"description": "Create a sensor that is the minimum or maximum of another sensor, resetttable via an action.",
77
"data": {
88
"entity_id": "Input entity",
9+
"equal_updates": "Update on equal values",
910
"name": "Name",
10-
"type": "Statistikmerkmal"
11+
"type": "Statistic characteristic"
12+
},
13+
"data_description": {
14+
"entity_id": "The entity that the sensor will track. The sensor will calculate the minimum or maximum value of this entity until reset via the `reset` action.",
15+
"equal_updates": "If enabled, the sensor will update the `last_modified` attribute even if the input entity value is the same as the current min/max.",
16+
"type": "Whether the sensor should track the minimum or maximum value of the input entity"
1117
}
1218
}
1319
}
@@ -17,7 +23,13 @@
1723
"init": {
1824
"data": {
1925
"entity_id": "Input entity",
20-
"type": "Statistikmerkmal"
26+
"equal_updates": "Update on equal values",
27+
"type": "Statistic characteristic"
28+
},
29+
"data_description": {
30+
"entity_id": "The entity that the sensor will track. The sensor will calculate the minimum or maximum value of this entity until reset via the `reset` action.",
31+
"equal_updates": "If enabled, the sensor will update the `last_modified` attribute even if the input entity value is the same as the current min/max.",
32+
"type": "Whether the sensor should track the minimum or maximum value of the input entity"
2133
}
2234
}
2335
}
@@ -32,11 +44,11 @@
3244
},
3345
"services": {
3446
"reset": {
35-
"name": "Zurücksetzen",
47+
"name": "Reset",
3648
"description": "Reset a Periodic Min/Max sensor to the current input entity value.",
3749
"fields": {
3850
"entity_id": {
39-
"name": "Entität",
51+
"name": "Entity",
4052
"description": "Select the Periodic Min/Max sensor."
4153
}
4254
}

custom_components/periodic_min_max/translations/en.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@
66
"description": "Create a sensor that is the minimum or maximum of another sensor, resetttable via an action.",
77
"data": {
88
"entity_id": "Input entity",
9+
"equal_updates": "Update on equal values",
910
"name": "Name",
1011
"type": "Statistic characteristic"
12+
},
13+
"data_description": {
14+
"entity_id": "The entity that the sensor will track. The sensor will calculate the minimum or maximum value of this entity until reset via the `reset` action.",
15+
"equal_updates": "If enabled, the sensor will update the `last_modified` attribute even if the input entity value is the same as the current min/max.",
16+
"type": "Whether the sensor should track the minimum or maximum value of the input entity"
1117
}
1218
}
1319
}
@@ -17,7 +23,13 @@
1723
"init": {
1824
"data": {
1925
"entity_id": "Input entity",
26+
"equal_updates": "Update on equal values",
2027
"type": "Statistic characteristic"
28+
},
29+
"data_description": {
30+
"entity_id": "The entity that the sensor will track. The sensor will calculate the minimum or maximum value of this entity until reset via the `reset` action.",
31+
"equal_updates": "If enabled, the sensor will update the `last_modified` attribute even if the input entity value is the same as the current min/max.",
32+
"type": "Whether the sensor should track the minimum or maximum value of the input entity"
2133
}
2234
}
2335
}

custom_components/periodic_min_max/translations/fr.json

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@
66
"description": "Create a sensor that is the minimum or maximum of another sensor, resetttable via an action.",
77
"data": {
88
"entity_id": "Input entity",
9-
"name": "Nom",
10-
"type": "Indicateur statistique"
9+
"equal_updates": "Update on equal values",
10+
"name": "Name",
11+
"type": "Statistic characteristic"
12+
},
13+
"data_description": {
14+
"entity_id": "The entity that the sensor will track. The sensor will calculate the minimum or maximum value of this entity until reset via the `reset` action.",
15+
"equal_updates": "If enabled, the sensor will update the `last_modified` attribute even if the input entity value is the same as the current min/max.",
16+
"type": "Whether the sensor should track the minimum or maximum value of the input entity"
1117
}
1218
}
1319
}
@@ -17,7 +23,13 @@
1723
"init": {
1824
"data": {
1925
"entity_id": "Input entity",
20-
"type": "Indicateur statistique"
26+
"equal_updates": "Update on equal values",
27+
"type": "Statistic characteristic"
28+
},
29+
"data_description": {
30+
"entity_id": "The entity that the sensor will track. The sensor will calculate the minimum or maximum value of this entity until reset via the `reset` action.",
31+
"equal_updates": "If enabled, the sensor will update the `last_modified` attribute even if the input entity value is the same as the current min/max.",
32+
"type": "Whether the sensor should track the minimum or maximum value of the input entity"
2133
}
2234
}
2335
}
@@ -32,11 +44,11 @@
3244
},
3345
"services": {
3446
"reset": {
35-
"name": "Réinitialiser",
47+
"name": "Reset",
3648
"description": "Reset a Periodic Min/Max sensor to the current input entity value.",
3749
"fields": {
3850
"entity_id": {
39-
"name": "Entité",
51+
"name": "Entity",
4052
"description": "Select the Periodic Min/Max sensor."
4153
}
4254
}

0 commit comments

Comments
 (0)