Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File reader as NP sensor (for development and debugging) #74

Merged
merged 3 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.coverage
.HA_VERSION
__pycache__
config_entry-nordpool_planner.json
config_entry-nordpool_planner*.json
home-assistant*
custom_components/.gitignore
/*.yaml
Expand Down
11 changes: 9 additions & 2 deletions custom_components/nordpool_planner/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@
CONF_TYPE_STATIC,
CONF_USED_HOURS_LOW_ENTITY,
DOMAIN,
NAME_FILE_READER,
PATH_FILE_READER,
PlannerStates,
)
from .helpers import get_np_from_file

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -617,7 +620,7 @@ def set_done_for_now(self) -> None:
"""Set output state to off."""
now_hour = dt_util.now().replace(minute=0, second=0, microsecond=0)
start_hour = now_hour.replace(hour=self._start_time)
if start_hour < now_hour():
if start_hour < now_hour:
start_hour += dt.timedelta(days=1)
self.low_cost_state.starts_at = start_hour
self.low_cost_state.cost_at = STATE_UNAVAILABLE
Expand Down Expand Up @@ -720,7 +723,11 @@ def current_price_attr(self):

def update(self, hass: HomeAssistant) -> bool:
"""Update price in storage."""
np = hass.states.get(self._unique_id)
if self._unique_id == NAME_FILE_READER:
np = get_np_from_file(PATH_FILE_READER)
else:
np = hass.states.get(self._unique_id)

if np is None:
_LOGGER.warning("Got empty data from Nordpool entity %s ", self._unique_id)
elif "today" not in np.attributes and "prices_today" not in np.attributes:
Expand Down
15 changes: 12 additions & 3 deletions custom_components/nordpool_planner/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@
CONF_TYPE_STATIC,
CONF_USED_HOURS_LOW_ENTITY,
DOMAIN,
NAME_FILE_READER,
PATH_FILE_READER,
)
from .helpers import get_np_from_file

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -63,7 +66,11 @@ async def async_step_user(
self.data[CONF_USED_HOURS_LOW_ENTITY] = True

self.options = {}
np_entity = self.hass.states.get(self.data[CONF_PRICES_ENTITY])
if self.data[CONF_PRICES_ENTITY] == NAME_FILE_READER:
np_entity = get_np_from_file(PATH_FILE_READER)
else:
np_entity = self.hass.states.get(self.data[CONF_PRICES_ENTITY])

try:
self.options[ATTR_UNIT_OF_MEASUREMENT] = np_entity.attributes.get(
ATTR_UNIT_OF_MEASUREMENT
Expand Down Expand Up @@ -96,8 +103,10 @@ async def async_step_user(
if "nordpool" in s or "average_electricity_price" in s
]

if len(selected_entities) == 0:
errors["base"] = "No Nordpool entity found"
# if len(selected_entities) == 0:
# errors["base"] = "No Nordpool entity found"

selected_entities.append(NAME_FILE_READER)

schema = vol.Schema(
{
Expand Down
4 changes: 4 additions & 0 deletions custom_components/nordpool_planner/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,7 @@ class PlannerStates(Enum):
CONF_USED_TIME_RESET_ENTITY = "used_time_reset_entity"
CONF_START_TIME_ENTITY = "start_time_entity"
CONF_USED_HOURS_LOW_ENTITY = "used_hours_low_entity"

NAME_FILE_READER = "file_reader"

PATH_FILE_READER = "config/config_entry-nordpool_planner.json"
82 changes: 82 additions & 0 deletions custom_components/nordpool_planner/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""Helper functions package."""

import contextlib
import datetime as dt
import json
import pathlib

from homeassistant.core import State
from homeassistant.util import dt as dt_util


def get_np_from_file(data_file: str, set_today: bool = True) -> State | None:
"""Fake NP entity from file."""
diag_data = {}
file_path = pathlib.Path(data_file)
if file_path.is_file():
with contextlib.suppress(ValueError):
diag_data = json.loads(file_path.read_text(encoding="utf-8"))

if data := diag_data.get("data"):
if planner := data.get("planner"):
if prices_entity := planner.get("_prices_entity"):
if np := prices_entity.get("_np"):
attr = np.get("attributes")
now = dt_util.now()
if "raw_today" in attr:
for item in attr["raw_today"]:
for key, value in item.items():
if key in ["start", "end"] and isinstance(value, str):
item[key] = dt_util.parse_datetime(value)
if set_today:
item[key] = item[key].replace(
year=now.year, month=now.month, day=now.day
)
if "raw_tomorrow" in attr:
for item in attr["raw_tomorrow"]:
for key, value in item.items():
if key in ["start", "end"] and isinstance(value, str):
item[key] = dt_util.parse_datetime(value)
if set_today:
item[key] = item[key].replace(
year=now.year, month=now.month, day=now.day
)
item[key] += dt.timedelta(days=1)
if "prices" in attr and set_today:
first_time = None
original_tz = None
for item in attr["prices"]:
for key, value in item.items():
if key in ["time"] and isinstance(value, str):
fixed_time = dt_util.parse_datetime(value)
if not original_tz:
original_tz = fixed_time.tzinfo
fixed_time = fixed_time.astimezone(now.tzinfo)
if not first_time:
first_time = fixed_time
if fixed_time.day == first_time.day:
fixed_time = fixed_time.replace(
year=now.year, month=now.month, day=now.day
)
else:
fixed_time = fixed_time.replace(
year=now.year, month=now.month, day=now.day
)
fixed_time += dt.timedelta(days=1)
item[key] = fixed_time.astimezone(
original_tz
).strftime("%Y-%m-%d %H:%M:%S%z")
return State(
entity_id=np.get("entity_id"),
state=np.get("state"),
attributes=attr,
# last_changed: datetime.datetime | None = None,
# last_reported: datetime.datetime | None = None,
# last_updated: datetime.datetime | None = None,
# context: Context | None = None,
# validate_entity_id: bool | None = True,
# state_info: StateInfo | None = None,
# last_updated_timestamp: float | None = None,
)

return None
Loading