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

Automatic unit detected for Watts vs Kwh when reading historical data #682

Merged
merged 2 commits into from
Feb 1, 2024
Merged
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
61 changes: 51 additions & 10 deletions apps/predbat/predbat.py
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,7 @@ def find_charge_curve(self):
smoothing=False,
divide_by=1.0,
scale=self.base.battery_scaling,
required_unit="kWh",
)
charge_rate = self.base.minute_data(
charge_rate_data[0],
Expand All @@ -1024,6 +1025,7 @@ def find_charge_curve(self):
smoothing=False,
divide_by=1.0,
scale=1.0,
required_unit="W",
)
predbat_status = self.base.minute_data_state(predbat_status_data[0], self.base.max_days_previous, self.base.now_utc, "state", "last_updated")
battery_power = self.base.minute_data(
Expand All @@ -1037,6 +1039,7 @@ def find_charge_curve(self):
smoothing=False,
divide_by=1.0,
scale=1.0,
required_unit="W",
)
min_len = min(len(soc_kwh), len(charge_rate), len(predbat_status), len(battery_power))
self.log("Find charge curve has {} days of data, max days {}".format(min_len / 60 / 24.0, self.base.max_days_previous))
Expand Down Expand Up @@ -3063,7 +3066,7 @@ def load_car_energy(self, now_utc):
"""
self.car_charging_energy = {}
if "car_charging_energy" in self.args:
self.car_charging_energy = self.minute_data_import_export(now_utc, "car_charging_energy", scale=self.car_charging_energy_scale)
self.car_charging_energy = self.minute_data_import_export(now_utc, "car_charging_energy", scale=self.car_charging_energy_scale, required_unit="kWh")
else:
self.log("Car charging hold {} threshold {}".format(self.car_charging_hold, self.car_charging_threshold * 60.0))
return self.car_charging_energy
Expand Down Expand Up @@ -3094,7 +3097,7 @@ def get_history_async(self, entity_id, days=None):
self.log("Failure to fetch history for {}".format(entity_id))
raise ValueError

def minute_data_import_export(self, now_utc, key, scale=1.0):
def minute_data_import_export(self, now_utc, key, scale=1.0, required_unit=None):
"""
Download one or more entities for import/export data
"""
Expand All @@ -3111,7 +3114,17 @@ def minute_data_import_export(self, now_utc, key, scale=1.0):

if history:
import_today = self.minute_data(
history[0], self.max_days_previous, now_utc, "state", "last_updated", backwards=True, smoothing=True, scale=scale, clean_increment=True, accumulate=import_today
history[0],
self.max_days_previous,
now_utc,
"state",
"last_updated",
backwards=True,
smoothing=True,
scale=scale,
clean_increment=True,
accumulate=import_today,
required_unit=required_unit,
)
else:
self.log("Error: Unable to fetch history for {}".format(entity_id))
Expand All @@ -3120,7 +3133,7 @@ def minute_data_import_export(self, now_utc, key, scale=1.0):

return import_today

def minute_data_load(self, now_utc, entity_name, max_days_previous):
def minute_data_load(self, now_utc, entity_name, max_days_previous, required_unit=None):
"""
Download one or more entities for load data
"""
Expand Down Expand Up @@ -3154,6 +3167,7 @@ def minute_data_load(self, now_utc, entity_name, max_days_previous):
scale=self.load_scaling,
clean_increment=True,
accumulate=load_minutes,
required_unit=required_unit,
)
else:
self.log("ERROR: Unable to fetch history for {}".format(entity_id))
Expand Down Expand Up @@ -3243,6 +3257,7 @@ def minute_data(
accumulate=[],
adjust_key=None,
spreading=None,
required_unit=None,
):
"""
Turns data from HA into a hash of data indexed by minute with the data being the value
Expand All @@ -3261,6 +3276,9 @@ def minute_data(
self.log("Warning, empty history passed to minute_data, ignoring (check your settings)...")
return mdata

if self.debug_enable:
self.log("Loading data from {}".format(history[0]))

# Process history
for item in history:
# Ignore data without correct keys
Expand All @@ -3280,6 +3298,19 @@ def minute_data(
except (ValueError, TypeError):
continue

# Find and converter units
if required_unit and ("attributes" in item):
if "unit_of_measurement" in item["attributes"]:
unit = item["attributes"]["unit_of_measurement"]
if unit != required_unit:
if required_unit in ["kW", "kWh"] and unit in ["W", "Wh"]:
state = state / 1000.0
elif required_unit in ["W", "Wh"] and unit in ["kW", "kWh"]:
state = state * 1000.0
else:
# Ignore data in wrong units if we can't converter
continue

# Divide down the state if required
if divide_by:
state /= divide_by
Expand Down Expand Up @@ -8627,7 +8658,17 @@ def fetch_extra_load_forecast(self, now_utc):
data = None

load_forecast = self.minute_data(
data, self.forecast_days, self.midnight_utc, "energy", "last_updated", backwards=False, clean_increment=False, smoothing=True, divide_by=1.0, scale=1.0
data,
self.forecast_days,
self.midnight_utc,
"energy",
"last_updated",
backwards=False,
clean_increment=False,
smoothing=True,
divide_by=1.0,
scale=1.0,
required_unit="kWh",
)

return load_forecast
Expand Down Expand Up @@ -9663,7 +9704,7 @@ def fetch_sensor_data(self):
# Iboost load data
if self.iboost_enable:
if "iboost_energy_today" in self.args:
self.iboost_energy_today, iboost_energy_age = self.minute_data_load(self.now_utc, "iboost_energy_today", 1)
self.iboost_energy_today, iboost_energy_age = self.minute_data_load(self.now_utc, "iboost_energy_today", 1, required_unit="kWh")
if iboost_energy_age >= 1:
self.iboost_today = self.dp2(abs(self.iboost_energy_today[0] - self.iboost_energy_today[self.minutes_now]))
self.log("IBoost energy today from sensor reads {} kWh".format(self.iboost_today))
Expand All @@ -9674,7 +9715,7 @@ def fetch_sensor_data(self):
else:
# Load data
if "load_today" in self.args:
self.load_minutes, self.load_minutes_age = self.minute_data_load(self.now_utc, "load_today", self.max_days_previous)
self.load_minutes, self.load_minutes_age = self.minute_data_load(self.now_utc, "load_today", self.max_days_previous, required_unit="kWh")
self.log("Found {} load_today datapoints going back {} days".format(len(self.load_minutes), self.load_minutes_age))
self.load_minutes_now = max(self.load_minutes.get(0, 0) - self.load_minutes.get(self.minutes_now, 0), 0)
else:
Expand All @@ -9684,21 +9725,21 @@ def fetch_sensor_data(self):

# Load import today data
if "import_today" in self.args:
self.import_today = self.minute_data_import_export(self.now_utc, "import_today", scale=self.import_export_scaling)
self.import_today = self.minute_data_import_export(self.now_utc, "import_today", scale=self.import_export_scaling, required_unit="kWh")
self.import_today_now = max(self.import_today.get(0, 0) - self.import_today.get(self.minutes_now, 0), 0)
else:
self.log("WARN: You have not set import_today in apps.yaml, you will have no previous import data")

# Load export today data
if "export_today" in self.args:
self.export_today = self.minute_data_import_export(self.now_utc, "export_today", scale=self.import_export_scaling)
self.export_today = self.minute_data_import_export(self.now_utc, "export_today", scale=self.import_export_scaling, required_unit="kWh")
self.export_today_now = max(self.export_today.get(0, 0) - self.export_today.get(self.minutes_now, 0), 0)
else:
self.log("WARN: You have not set export_today in apps.yaml, you will have no previous export data")

# PV today data
if "pv_today" in self.args:
self.pv_today = self.minute_data_import_export(self.now_utc, "pv_today")
self.pv_today = self.minute_data_import_export(self.now_utc, "pv_today", required_unit="kWh")
self.pv_today_now = max(self.pv_today.get(0, 0) - self.pv_today.get(self.minutes_now, 0), 0)
else:
self.log("WARN: You have not set pv_today in apps.yaml, you will have no previous pv data")
Expand Down
Loading