Skip to content

Commit

Permalink
Values from lambda function are recorded as sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
Big-Tree committed Nov 10, 2023
1 parent 3ffc70c commit 9690452
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 60 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ coverage.xml

# Home Assistant configuration
config/*
!config/configuration.yaml
!config/configuration.yaml

homeassistant
6 changes: 4 additions & 2 deletions custom_components/integration_blueprint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
Platform.SENSOR,
Platform.BINARY_SENSOR,
Platform.SWITCH,
Platform.NUMBER,
]


Expand All @@ -28,8 +29,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN][entry.entry_id] = coordinator = BlueprintDataUpdateCoordinator(
hass=hass,
client=IntegrationBlueprintApiClient(
username=entry.data[CONF_USERNAME],
password=entry.data[CONF_PASSWORD],
postcode=entry.data['postcode'],
#username=entry.data[CONF_USERNAME],
#password=entry.data[CONF_PASSWORD],
session=async_get_clientsession(hass),
),
)
Expand Down
34 changes: 28 additions & 6 deletions custom_components/integration_blueprint/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,39 @@ class IntegrationBlueprintApiClient:

def __init__(
self,
username: str,
password: str,
postcode: str,
#username: str,
#password: str,
session: aiohttp.ClientSession,
) -> None:
"""Sample API Client."""
self._username = username
self._password = password
#self._username = username
#self._password = password
self._session = session

async def async_get_data(self) -> any:
"""Get data from the API."""
args = {}
args['house_type'] = 2
args['set_point'] = 20.0
args['temp_range'] = 3.0
args['postcode'] = 'SW118DD'

lambda_url = 'https://pkgy5zrwinj2mcxerishahglvi0hfoqh.lambda-url.eu-west-2.on.aws/0.00001666670.0000166667'
#results, errors = json.loads(response.text)

results = await self._api_wrapper(
method="post",
url=lambda_url,
data=args,
headers={"Content-type": "application/json; charset=UTF-8"},
)
print('----------Lambda request----------')
return results[0]




return await self._api_wrapper(
method="get", url="https://jsonplaceholder.typicode.com/posts/1"
)
Expand All @@ -62,11 +84,11 @@ async def _api_wrapper(
) -> any:
"""Get information from the API."""
try:
async with async_timeout.timeout(10):
async with async_timeout.timeout(40):
response = await self._session.request(
method=method,
url=url,
headers=headers,
#headers=headers,
json=data,
)
if response.status in (401, 403):
Expand Down
11 changes: 11 additions & 0 deletions custom_components/integration_blueprint/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,14 @@ def __init__(
def is_on(self) -> bool:
"""Return true if the binary_sensor is on."""
return self.coordinator.data.get("title", "") == "foo"

@property
def unique_id(self):
return 'sensor_id_binary'

#@property
#def device_info(self):
# """Return device information."""
# return {
# "identifiers": {("optispark_integration", "optispark_device_id")},
# }
62 changes: 29 additions & 33 deletions custom_components/integration_blueprint/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,49 +28,45 @@ async def async_step_user(
"""Handle a flow initialized by the user."""
_errors = {}
if user_input is not None:
try:
await self._test_credentials(
username=user_input[CONF_USERNAME],
password=user_input[CONF_PASSWORD],
)
except IntegrationBlueprintApiClientAuthenticationError as exception:
LOGGER.warning(exception)
_errors["base"] = "auth"
except IntegrationBlueprintApiClientCommunicationError as exception:
LOGGER.error(exception)
_errors["base"] = "connection"
except IntegrationBlueprintApiClientError as exception:
LOGGER.exception(exception)
_errors["base"] = "unknown"
else:
return self.async_create_entry(
title=user_input[CONF_USERNAME],
data=user_input,
)
# Process the data
pass
await self._test_credentials(
postcode=user_input['postcode'],
)
return self.async_create_entry(
title=user_input['postcode'],
data=user_input,
)
#except IntegrationBlueprintApiClientAuthenticationError as exception:
# LOGGER.warning(exception)
# _errors["base"] = "auth"
#except IntegrationBlueprintApiClientCommunicationError as exception:
# LOGGER.error(exception)
# _errors["base"] = "connection"
#except IntegrationBlueprintApiClientError as exception:
# LOGGER.exception(exception)
# _errors["base"] = "unknown"
#else:
# return self.async_create_entry(
# title=user_input[CONF_USERNAME],
# data=user_input,
# )

return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(
CONF_USERNAME,
default=(user_input or {}).get(CONF_USERNAME),
): selector.TextSelector(
selector.TextSelectorConfig(
type=selector.TextSelectorType.TEXT
),
),
vol.Required(CONF_PASSWORD): selector.TextSelector(
selector.TextSelectorConfig(
type=selector.TextSelectorType.PASSWORD
),
),
vol.Required('postcode'): str,
}
),
errors=_errors,
)

async def _test_credentials(self, username: str, password: str) -> None:
async def _test_credentials(self, postcode: str) -> None:
"""Validate credentials."""
pass

async def _test_credentials_old(self, username: str, password: str) -> None:
"""Validate credentials."""
client = IntegrationBlueprintApiClient(
username=username,
Expand Down
44 changes: 41 additions & 3 deletions custom_components/integration_blueprint/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""DataUpdateCoordinator for integration_blueprint."""
from __future__ import annotations

from datetime import timedelta
from datetime import timedelta, datetime
import time

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
Expand All @@ -19,6 +20,23 @@
from .const import DOMAIN, LOGGER


def get_closest_time(my_data):
# Convert time to dattime format
times_str: list[str] = list(my_data['base_demand'].keys())
times = [datetime.strptime(d, '%Y-%m-%d %H:%M') for d in times_str]
now = datetime.now()
absolute_difference = [abs(getattr(t-now, 'total_seconds')()) for t in times]
min_idx = absolute_difference.index(min(absolute_difference))
closest_time = times_str[min_idx]

out = {}
for key in ['base_demand', 'prices', 'temps', 'optimised_demand']:
out[key] = my_data[key][closest_time]
for key in ['optimised_cost', 'base_cost']:
out[key] = my_data[key]
return out


# https://developers.home-assistant.io/docs/integration_fetching_data#coordinated-single-api-poll-for-data-for-all-entities
class BlueprintDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the API."""
Expand All @@ -36,13 +54,33 @@ def __init__(
hass=hass,
logger=LOGGER,
name=DOMAIN,
update_interval=timedelta(minutes=5),
update_interval=timedelta(seconds=10),
)
self.results = {}
self.last_update_time = 0
self.update_lambda_interval = 300

async def _async_update_data(self):
"""Update data via library."""
try:
return await self.client.async_get_data()
if time.time() - self.last_update_time > self.update_lambda_interval:
lambda_results = await self.client.async_get_data()

# Convert to dictionary where time is the key
self.my_data = {}
for key in ['base_demand', 'prices', 'temps', 'optimised_demand']:
self.my_data[key] = {i['x']: i['y'] for i in lambda_results[key]}
for key in ['optimised_cost', 'base_cost']:
self.my_data[key] = lambda_results[key]

out = get_closest_time(self.my_data)

self.last_update_time = time.time()
return out
else:
out = get_closest_time(self.my_data)
return out
#return await self.client.async_get_data()
except IntegrationBlueprintApiClientAuthenticationError as exception:
raise ConfigEntryAuthFailed(exception) from exception
except IntegrationBlueprintApiClientError as exception:
Expand Down
2 changes: 1 addition & 1 deletion custom_components/integration_blueprint/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(self, coordinator: BlueprintDataUpdateCoordinator) -> None:
super().__init__(coordinator)
self._attr_unique_id = coordinator.config_entry.entry_id
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self.unique_id)},
identifiers={(DOMAIN, 'OptiSpark_device')},
name=NAME,
model=VERSION,
manufacturer=NAME,
Expand Down
82 changes: 82 additions & 0 deletions custom_components/integration_blueprint/number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""Sensor platform for integration_blueprint."""
from __future__ import annotations

from homeassistant.components.sensor import SensorEntity, SensorEntityDescription

from .const import DOMAIN
from .coordinator import BlueprintDataUpdateCoordinator
from .entity import IntegrationBlueprintEntity

from datetime import datetime

ENTITY_DESCRIPTIONS = (
SensorEntityDescription(
key="integration_blueprint",
name="Optimised Demand",
icon="mdi:format-quote-close",
),
)


def get_closest_time(times_str: list[str]):
# Convert time to dattime format
times = [datetime.strptime(d, '%Y-%m-%d %H:%M') for d in times_str]
now = datetime.now()
absolute_difference = [abs(getattr(t-now, 'total_seconds')()) for t in times]
min_idx = absolute_difference.index(min(absolute_difference))
#print(f'The closest time: {times[min_idx]}')
return times_str[min_idx]

async def async_setup_entry(hass, entry, async_add_devices):
pass
#"""Set up the sensor platform."""
#coordinator = hass.data[DOMAIN][entry.entry_id]
#async_add_devices(
# IntegrationBlueprintSensor(
# coordinator=coordinator,
# entity_description=entity_description,
# )
# for entity_description in ENTITY_DESCRIPTIONS
#)


class IntegrationBlueprintSensor(IntegrationBlueprintEntity, SensorEntity):
"""integration_blueprint Sensor class."""

def __init__(
self,
coordinator: BlueprintDataUpdateCoordinator,
entity_description: SensorEntityDescription,
) -> None:
"""Initialize the sensor class."""
super().__init__(coordinator)
self.entity_description = entity_description

@property
def native_value(self) -> str:
"""Return the native value of the sensor."""
#out = self.coordinator.data
## Convert to dictionary where time is the key
#data = {}
#for key in ['base_demand', 'prices', 'temps', 'optimised_demand']:
# data[key] = {i['x']: i['y'] for i in out[key]}
#
#time_str: list[str] = [i['x'] for i in out['base_demand']]
#closest_time = get_closest_time(time_str)
#base_demand_now = data['base_demand'][closest_time]
#return base_demand_now

import time
out = time.clock_gettime(0)
return 5

@property
def unique_id(self):
return 'sensor_id_number'

#@property
#def device_info(self):
# """Return device information."""
# return {
# "identifiers": {(DOMAIN, "optispark_device_id_number")},
# }
Loading

0 comments on commit 9690452

Please sign in to comment.