Skip to content

Commit f039ed7

Browse files
committed
feat: Added the ability to update data source data updates via raised events (2 hours dev time)
1 parent 18c891a commit f039ed7

6 files changed

Lines changed: 580 additions & 8 deletions

File tree

_docs/events.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
11
# Events
22

3-
The following events are raised by the integration. These events power various entities and can also be used within automations.
3+
The following events are either raised or received by the integration. These events power various entities and can also be used within automations.
4+
5+
## Update Data Source
6+
7+
`target_timeframe_update_data_source`
8+
9+
Data sources listen for this event and then update the data based on the provided data if the `data_source_id` matches the data source's id.
10+
11+
| Attribute | Type | Description |
12+
|-----------|------|-------------|
13+
| `data_source_id` | `string` | The id of the data source the data belongs to |
14+
| `data` | `array` | The data to update the data source with |
15+
16+
For each item in `data`, the following attributes should be present
17+
18+
| Attribute | Type | Description |
19+
|-----------|------|-------------|
20+
| `start` | `datetime` | The start timestamp the value is effective from |
21+
| `end` | `datetime` | The end timestamp the value is effective to |
22+
| `value` | `float` | The value that is applicable for the timeframe. This could be something like an electricity rate |
23+
| `metadata` | `object` | Additional metadata that might describe how the value was created |

_docs/setup/data_source.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@ The name of the data source. This is for informative purposes.
1010

1111
### Id
1212

13-
The unique identifier of the data source. This is used by internal events to ensure sensors use the correct data as well as part of the entity name of all related entities. For example, if you were using data provided by Octopus Energy, then this might be `octopus_energy`.
13+
The unique identifier of the data source. This is used by internal events to ensure sensors use the correct data as well as part of the entity name of all related entities.
1414

15-
Once the data source has been created, you'll have the following entities created. You'll then need to use the [available service](../services.md#target_timeframesupdate_target_timeframe_data_source) to configure the underlying data. There are also a collection of [blueprints](../blueprints.md#data-sources) available for loading popular data sources.
15+
The data source will listen for the [update data source event](../events.md#update-data-source) where the `data source id` matches this id. This event might be raised by other integrations. If this data source is being used for this purpose, then the id will need to be set to a certain value which should be highlighted in that integrations guide.
16+
17+
Alternatively, you can use the [available service](../services.md#target_timeframesupdate_target_timeframe_data_source) to configure the underlying data. There is a collection of [blueprints](../blueprints.md#data-sources) available for loading data from popular data sources.
1618

1719
## Entities
1820

21+
Once the data source has been created, you'll have the following entities created.
22+
1923
### Data Source Last Updated
2024

2125
`sensor.target_timeframes_{{DATA_SOURCE_ID}}_data_source_last_updated`

custom_components/target_timeframes/const.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,5 @@
185185
),
186186
})
187187

188-
EVENT_DATA_SOURCE = "target_time_period_data_source_updated"
188+
EVENT_DATA_SOURCE = "target_time_period_data_source_updated"
189+
EVENT_UPDATE_DATA_SOURCE = "target_timeframe_update_data_source"

custom_components/target_timeframes/entities/data_source.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from homeassistant.helpers.entity import generate_entity_id
1818

1919
from ..utils.attributes import dict_to_typed_dict
20-
from ..const import DOMAIN, EVENT_DATA_SOURCE
20+
from ..const import DOMAIN, EVENT_DATA_SOURCE, EVENT_UPDATE_DATA_SOURCE
2121
from ..storage.data_source_data import async_save_cached_data_source_data
2222
from ..utils.data_source_data import DataSourceItem, merge_data_source_data, validate_data_source_data
2323

@@ -67,6 +67,11 @@ def extra_state_attributes(self):
6767
@property
6868
def native_value(self):
6969
return self._state
70+
71+
@callback
72+
async def _async_handle_event(self, event) -> None:
73+
if event.data.get("data_source_id", '').lower() == self._source_id.lower():
74+
await self.async_update_target_timeframe_data_source(event.data.get("data", []))
7075

7176
async def async_added_to_hass(self):
7277
"""Call when entity about to be added to hass."""
@@ -81,6 +86,10 @@ async def async_added_to_hass(self):
8186

8287
_LOGGER.debug(f'Restored state: {self._state}')
8388

89+
self.async_on_remove(
90+
self._hass.bus.async_listen(EVENT_UPDATE_DATA_SOURCE, self._async_handle_event)
91+
)
92+
8493
@callback
8594
async def async_update_target_timeframe_data_source(self, data, replace_all_existing_data = False):
8695
"""Update target timeframe data source"""

custom_components/target_timeframes/utils/data_source_data.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from copy import Error
12
from datetime import datetime, timedelta
23
from typing import Any
34

@@ -19,7 +20,7 @@ def __init__(self, success: bool, data_source_id: str, data: list[DataSourceItem
1920

2021
def validate_data_source_data(items: list[dict], data_source_id: str):
2122
if items is None or len(items) < 1:
22-
return ValidateDataSourceDataResult(True, [])
23+
return ValidateDataSourceDataResult(True, data_source_id, [])
2324

2425
processed_data_source = []
2526
for index in range(len(items)):
@@ -28,7 +29,14 @@ def validate_data_source_data(items: list[dict], data_source_id: str):
2829

2930
start = None
3031
try:
31-
start = datetime.fromisoformat(item["start"])
32+
if "start" not in item:
33+
error = f"start is missing at index {index}"
34+
break
35+
36+
if isinstance(item["start"], datetime):
37+
start = item["start"]
38+
else:
39+
start = datetime.fromisoformat(item["start"])
3240
except:
3341
error = f"start was not a valid ISO datetime in string format at index {index}"
3442
break
@@ -39,7 +47,14 @@ def validate_data_source_data(items: list[dict], data_source_id: str):
3947

4048
end = None
4149
try:
42-
end = datetime.fromisoformat(item["end"])
50+
if "end" not in item:
51+
error = f"end is missing at index {index}"
52+
break
53+
54+
if isinstance(item["end"], datetime):
55+
end = item["end"]
56+
else:
57+
end = datetime.fromisoformat(item["end"])
4358
except:
4459
error = f"end was not a valid ISO datetime in string format at index {index}"
4560
break

0 commit comments

Comments
 (0)