diff --git a/CHANGELOG.md b/CHANGELOG.md index d66b69c4..770b6d52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ETS forecasts. A median fallback is used when the available history is too short for ETS. ### Changed +- Seed genetic optimization runs with ten exact warm-start copies, twenty locally mutated + warm-start neighbours, and diverse domain-informed battery, direct-marketing, EV, and flexible + appliance schedules to improve early convergence without discarding the previous solution. - `max_home_appliances` is now purely an upper bound. No demo appliance is created when no `home_appliances` are configured, and the number is no longer used as an on/off switch. @@ -73,6 +76,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). are deprecated in favour of `appliance_starts` and `result.home_appliance_energy_wh`. ### Fixed +- Re-simulate genetic candidates after removing EV charging genes from slots that begin at full + SoC, keeping the repaired genome and its assigned fitness consistent. - FeedInTariffEnergyCharts no longer aborts the whole prediction/optimization when the Energy-Charts API is briefly unreachable: transient timeouts/connection errors are retried (with a (connect, read) timeout of (5, 60) s), and if a fetch still fails while diff --git a/src/akkudoktoreos/optimization/genetic/genetic.py b/src/akkudoktoreos/optimization/genetic/genetic.py index 41c08210..426691f3 100644 --- a/src/akkudoktoreos/optimization/genetic/genetic.py +++ b/src/akkudoktoreos/optimization/genetic/genetic.py @@ -536,6 +536,10 @@ class GeneticSimulation(PydanticBaseModel): class GeneticOptimization(OptimizationBase): """GENETIC algorithm to solve energy optimization.""" + WARM_START_COPIES = 10 + WARM_START_MUTATIONS = 20 + EDUCATED_GUESS_EXPORT_QUANTILES = (0.60, 0.75, 0.90) + # Slot-math helpers — single source of truth for the optimization grid. # At the default optimization interval of 3600 s, slot_duration_h is 1.0 and # total_slots equals prediction.hours, so the established hourly behaviour is @@ -1110,6 +1114,250 @@ class GeneticOptimization(OptimizationBase): return discharge_hours_bin, eautocharge_hours_index, appliance_gene_values + def _repair_ev_charge_at_full_soc( + self, + individual: list[int], + simulation_result: dict[str, Any], + ) -> bool: + """Remove EV charging genes in slots that begin at full SoC. + + The repair is deliberately separated from fitness calculation. Callers + must re-simulate after a change so the individual's genome, simulation + state and assigned fitness always describe the same schedule. + """ + if not self.optimize_ev or not self.ev_possible_charge_values: + return False + + zero_charge_index = min( + range(len(self.ev_possible_charge_values)), + key=lambda index: abs(self.ev_possible_charge_values[index]), + ) + if abs(self.ev_possible_charge_values[zero_charge_index]) > 1e-12: + return False + + _, ev_charge_indices, _ = self.split_individual(individual) + if ev_charge_indices is None: + return False + + ev_soc = np.asarray(simulation_result.get("EAuto_SoC_pro_Stunde", []), dtype=float) + start_slot = self._start_day_slot() + result_slots = min(ev_soc.size, self.total_slots - start_slot) + if result_slots <= 0: + return False + + changed = False + for offset in range(result_slots): + slot = start_slot + offset + charge_index = int(ev_charge_indices[slot]) + if ( + ev_soc[offset] >= 100.0 - 1e-9 + and self.ev_possible_charge_values[charge_index] > 0.0 + ): + ev_charge_indices[slot] = zero_charge_index + changed = True + + if changed: + battery_genes, _, appliance_genes = self.split_individual(individual) + individual[:] = self.merge_individual( + battery_genes, + ev_charge_indices, + appliance_genes, + ) + return changed + + def _heuristic_ev_schedule(self, *, prefer_pv: bool) -> list[int]: + """Build a low-cost EV schedule that reaches the configured minimum SoC.""" + if not self.optimize_ev or not self.ev_possible_charge_values: + return [] + + zero_index = min( + range(len(self.ev_possible_charge_values)), + key=lambda index: abs(self.ev_possible_charge_values[index]), + ) + schedule = [zero_index] * self.total_slots + ev = self.simulation.ev + if ev is None: + return schedule + + required_stored_wh = max( + ev.min_soc_wh + - ev.capacity_wh * ev.initial_soc_percentage / 100.0, + 0.0, + ) + if required_stored_wh <= 0.0: + return schedule + + start_slot = self._start_day_slot() + end_slot = max(start_slot, self.total_slots - self.fixed_eauto_hours) + prices = np.asarray(self.simulation.elect_price_hourly, dtype=float) + feed_in = np.asarray(self.simulation.elect_revenue_per_hour_arr, dtype=float) + pv = np.asarray(self.simulation.pv_prediction_wh, dtype=float) + load = np.asarray(self.simulation.load_energy_array, dtype=float) + + def marginal_cost(slot: int) -> tuple[float, float]: + surplus = pv[slot] - load[slot] + if prefer_pv and surplus > 0.0: + return (float(feed_in[slot]), -float(surplus)) + return (float(prices[slot]), -float(surplus)) + + candidates = sorted(range(start_slot, end_slot), key=marginal_cost) + positive_rates = sorted( + ( + (rate, index) + for index, rate in enumerate(self.ev_possible_charge_values) + if rate > 0.0 + ), + key=lambda item: item[0], + ) + if not positive_rates: + return schedule + + max_stored_wh = ( + ev.max_charge_power_w + * self.slot_duration_h + * ev.charging_efficiency + ) + remaining_wh = required_stored_wh + for slot in candidates: + required_rate = remaining_wh / max(max_stored_wh, 1e-9) + rate, rate_index = next( + (item for item in positive_rates if item[0] >= required_rate), + positive_rates[-1], + ) + schedule[slot] = rate_index + remaining_wh -= max_stored_wh * rate + if remaining_wh <= 1e-9: + break + return schedule + + def _heuristic_appliance_genes(self) -> list[int]: + """Choose low-opportunity-cost starts for flexible appliances.""" + if self.appliance_layout.n_genes == 0: + return [] + prices = np.asarray(self.simulation.elect_price_hourly, dtype=float) + feed_in = np.asarray(self.simulation.elect_revenue_per_hour_arr, dtype=float) + pv = np.asarray(self.simulation.pv_prediction_wh, dtype=float) + load = np.asarray(self.simulation.load_energy_array, dtype=float) + genes: list[int] = [] + for gene in self.appliance_layout.genes: + def opportunity_cost(position: int) -> float: + slot = gene.allowed_start_slots[position] + return float(feed_in[slot] if pv[slot] > load[slot] else prices[slot]) + + genes.append(min(range(len(gene.allowed_start_slots)), key=opportunity_cost)) + return genes + + def _educated_guess_individuals(self) -> list[list[int]]: + """Create diverse domain-informed candidates for the initial population.""" + slots = self.total_slots + start_slot = self._start_day_slot() + len_bat = len(self.bat_possible_charge_values) + idle_state = 0 + discharge_state = len_bat + ac_charge_state = 3 * len_bat - 1 + dc_allowed_state = 3 * len_bat + 1 + export_state = 3 * len_bat + (2 if self.optimize_dc_charge else 0) + + prices = np.asarray(self.simulation.elect_price_hourly, dtype=float) + feed_in = np.asarray(self.simulation.elect_revenue_per_hour_arr, dtype=float) + pv = np.asarray(self.simulation.pv_prediction_wh, dtype=float) + load = np.asarray(self.simulation.load_energy_array, dtype=float) + future = slice(start_slot, slots) + future_prices = prices[future] + future_feed_in = feed_in[future] + high_import_price = float(np.quantile(future_prices, 0.70)) + low_import_price = float(np.quantile(future_prices, 0.25)) + + ev_price = self._heuristic_ev_schedule(prefer_pv=False) + ev_pv = self._heuristic_ev_schedule(prefer_pv=True) + appliance_genes = self._heuristic_appliance_genes() + + def compose(battery_genes: list[int], ev_genes: list[int]) -> list[int]: + individual = list(battery_genes) + if self.optimize_ev: + individual.extend(ev_genes) + individual.extend(appliance_genes) + return individual + + guesses: list[list[int]] = [] + + # Baseline and self-consumption candidates are useful even without + # direct marketing and anchor the population with feasible schedules. + guesses.append(compose([idle_state] * slots, ev_price)) + self_consumption = [idle_state] * slots + for slot in range(start_slot, slots): + if self.optimize_dc_charge and pv[slot] > load[slot]: + self_consumption[slot] = dc_allowed_state + elif prices[slot] >= high_import_price and load[slot] > pv[slot]: + self_consumption[slot] = discharge_state + guesses.append(compose(self_consumption, ev_pv)) + + # Direct marketing candidates export only in the relatively expensive + # feed-in slots. At low tariffs PV is preferentially stored instead. + if self.optimize_battery_grid_export and future_feed_in.size: + feed_spread = float(np.ptp(future_feed_in)) + for quantile in self.EDUCATED_GUESS_EXPORT_QUANTILES: + export_threshold = float(np.quantile(future_feed_in, quantile)) + direct_marketing = [idle_state] * slots + for slot in range(start_slot, slots): + high_feed_in = ( + feed_spread > 1e-12 + and feed_in[slot] > 0.0 + and feed_in[slot] >= export_threshold + ) + if high_feed_in: + direct_marketing[slot] = export_state + elif self.optimize_dc_charge and pv[slot] > load[slot]: + direct_marketing[slot] = dc_allowed_state + elif prices[slot] >= high_import_price and load[slot] > pv[slot]: + direct_marketing[slot] = discharge_state + guesses.append(compose(direct_marketing, ev_pv)) + + inverter = self.simulation.inverter + if inverter is not None and ( + inverter.max_ac_charge_power_w is None or inverter.max_ac_charge_power_w > 0 + ): + price_arbitrage = [idle_state] * slots + for slot in range(start_slot, slots): + if prices[slot] <= low_import_price: + price_arbitrage[slot] = ac_charge_state + elif prices[slot] >= high_import_price: + price_arbitrage[slot] = discharge_state + guesses.append(compose(price_arbitrage, ev_price)) + + unique: dict[tuple[int, ...], list[int]] = {} + for guess in guesses: + unique.setdefault(tuple(guess), guess) + return list(unique.values()) + + def _mutated_warm_start_neighbors( + self, + start_solution: list[float], + count: int, + ) -> list[list[int]]: + """Create unique local variants while preserving already elapsed slots.""" + original = [int(value) for value in start_solution] + start_slot = self._start_day_slot() + seen = {tuple(original)} + neighbors: list[list[int]] = [] + for _ in range(max(count * 10, 1)): + neighbor = creator.Individual(original) + self.mutate(neighbor) + neighbor[:start_slot] = original[:start_slot] + if self.optimize_ev: + ev_start = self.total_slots + neighbor[ev_start : ev_start + start_slot] = original[ + ev_start : ev_start + start_slot + ] + key = tuple(int(value) for value in neighbor) + if key in seen: + continue + seen.add(key) + neighbors.append(list(key)) + if len(neighbors) >= count: + break + return neighbors + def setup_deap_environment(self, opti_param: dict[str, Any], start_hour: int) -> None: """Set up the DEAP environment with fitness and individual creation rules.""" self.opti_param = opti_param @@ -1267,46 +1515,14 @@ class GeneticOptimization(OptimizationBase): """ try: simulation_result = self.evaluate_inner(individual) - except Exception as e: + if self._repair_ev_charge_at_full_soc(individual, simulation_result): + simulation_result = self.evaluate_inner(individual) + except Exception: # Return bad fitness score ("FitnessMin") in case of an exception return (100000.0,) gesamtbilanz = simulation_result["Gesamtbilanz_Euro"] * (-1.0 if worst_case else 1.0) - # EV 100% & charge not allowed - if self.optimize_ev: - discharge_hours_bin, eautocharge_hours_index, appliance_gene_values = ( - self.split_individual(individual) - ) - - eauto_soc_per_hour = np.array( - simulation_result.get("EAuto_SoC_pro_Stunde", []) - ) # Beispielkey - - if eauto_soc_per_hour is None or eautocharge_hours_index is None: - raise ValueError("eauto_soc_per_hour or eautocharge_hours_index is None") - min_length = min(eauto_soc_per_hour.size, eautocharge_hours_index.size) - eauto_soc_per_hour_tail = eauto_soc_per_hour[-min_length:] - eautocharge_hours_index_tail = eautocharge_hours_index[-min_length:] - - # Mask - invalid_charge_mask = (eauto_soc_per_hour_tail == 100) & ( - eautocharge_hours_index_tail > 0 - ) - - if np.any(invalid_charge_mask): - invalid_indices = np.where(invalid_charge_mask)[0] - if len(invalid_indices) > 1: - eautocharge_hours_index_tail[invalid_indices] = 0 - - eautocharge_hours_index[-min_length:] = eautocharge_hours_index_tail.tolist() - - adjusted_individual = self.merge_individual( - discharge_hours_bin, eautocharge_hours_index, appliance_gene_values - ) - - individual[:] = adjusted_individual - # New check: Activate discharge when battery SoC is 0 # battery_soc_per_hour = np.array( # o.get("akku_soc_pro_stunde", []) @@ -1531,8 +1747,25 @@ class GeneticOptimization(OptimizationBase): "appliance layout." ) else: - for _ in range(10): + for _ in range(self.WARM_START_COPIES): population.insert(0, creator.Individual(start_solution)) + warm_neighbors = self._mutated_warm_start_neighbors( + start_solution, + self.WARM_START_MUTATIONS, + ) + population.extend(creator.Individual(neighbor) for neighbor in warm_neighbors) + logger.info( + "Seeded population with {} exact and {} mutated warm-start solutions.", + self.WARM_START_COPIES, + len(warm_neighbors), + ) + + educated_guesses = self._educated_guess_individuals() + population.extend(creator.Individual(guess) for guess in educated_guesses) + logger.info( + "Seeded population with {} educated-guess solutions.", + len(educated_guesses), + ) # Run the evolutionary algorithm pop, log = algorithms.eaMuPlusLambda( diff --git a/tests/test_genetic_seeding.py b/tests/test_genetic_seeding.py new file mode 100644 index 00000000..172e29c7 --- /dev/null +++ b/tests/test_genetic_seeding.py @@ -0,0 +1,113 @@ +from types import SimpleNamespace +from unittest.mock import patch + +import numpy as np +import pytest +from deap import creator + +from akkudoktoreos.config.config import ConfigEOS +from akkudoktoreos.core.coreabc import get_ems +from akkudoktoreos.optimization.genetic.genetic import GeneticOptimization +from akkudoktoreos.utils.datetimeutil import to_datetime + + +def _configure_hourly_grid(config_eos: ConfigEOS, *, start_hour: int = 0) -> None: + config_eos.merge_settings_from_dict( + { + "prediction": {"hours": 48}, + "optimization": {"horizon_hours": 48, "interval": 3600}, + } + ) + get_ems(init=True).set_start_datetime(to_datetime().set(hour=start_hour, minute=0)) + + +def test_ev_repair_is_resimulated_before_fitness_assignment(config_eos: ConfigEOS): + _configure_hourly_grid(config_eos) + opt = GeneticOptimization(fixed_seed=42) + opt.optimize_ev = True + opt.ev_possible_charge_values = [0.0, 1.0] + opt.setup_deap_environment({"home_appliance": 0}, start_hour=0) + individual = creator.Individual([0] * opt.total_slots + [1] * opt.total_slots) + + first_result = { + "Gesamtbilanz_Euro": 10.0, + "Gesamt_Verluste": 0.0, + "EAuto_SoC_pro_Stunde": np.full(opt.total_slots, 100.0), + } + repaired_result = { + "Gesamtbilanz_Euro": 1.0, + "Gesamt_Verluste": 0.0, + "EAuto_SoC_pro_Stunde": np.full(opt.total_slots, 100.0), + } + parameters = SimpleNamespace( + ems=SimpleNamespace(preis_euro_pro_wh_akku=0.0), + eauto=None, + ) + + with patch.object(opt, "evaluate_inner", side_effect=[first_result, repaired_result]) as evaluate: + fitness = opt.evaluate(individual, parameters, start_hour=0, worst_case=False) # type: ignore[arg-type] + + assert evaluate.call_count == 2 + assert fitness == pytest.approx((1.0,)) + assert individual[opt.total_slots :] == [0] * opt.total_slots + + +def test_mutated_warm_start_neighbors_keep_elapsed_slots(config_eos: ConfigEOS): + _configure_hourly_grid(config_eos, start_hour=10) + opt = GeneticOptimization(fixed_seed=42) + opt.optimize_ev = False + opt.setup_deap_environment({"home_appliance": 0}, start_hour=10) + start_solution = [0] * opt.total_slots + + neighbors = opt._mutated_warm_start_neighbors(start_solution, count=5) + + assert len(neighbors) == 5 + assert len({tuple(neighbor) for neighbor in neighbors}) == 5 + assert all(neighbor[:10] == start_solution[:10] for neighbor in neighbors) + assert all(neighbor != start_solution for neighbor in neighbors) + + +def test_educated_guesses_encode_high_price_direct_marketing(config_eos: ConfigEOS): + _configure_hourly_grid(config_eos) + opt = GeneticOptimization(fixed_seed=42) + opt.optimize_ev = False + opt.optimize_dc_charge = True + opt.optimize_battery_grid_export = True + opt.bat_possible_charge_values = [1.0] + opt.setup_deap_environment({"home_appliance": 0}, start_hour=0) + + slots = opt.total_slots + opt.simulation.elect_price_hourly = np.linspace(0.0001, 0.0004, slots) + opt.simulation.elect_revenue_per_hour_arr = np.linspace(0.00001, 0.0003, slots) + opt.simulation.pv_prediction_wh = np.full(slots, 1000.0) + opt.simulation.load_energy_array = np.full(slots, 500.0) + + guesses = opt._educated_guess_individuals() + + dc_allowed_state = 4 + export_state = 5 + assert len(guesses) >= 4 + assert all(len(guess) == slots for guess in guesses) + assert any(guess[0] == dc_allowed_state for guess in guesses) + assert any(guess[-1] == export_state for guess in guesses) + + +def test_flat_feed_in_tariff_does_not_seed_direct_marketing(config_eos: ConfigEOS): + _configure_hourly_grid(config_eos) + opt = GeneticOptimization(fixed_seed=42) + opt.optimize_ev = False + opt.optimize_dc_charge = True + opt.optimize_battery_grid_export = True + opt.bat_possible_charge_values = [1.0] + opt.setup_deap_environment({"home_appliance": 0}, start_hour=0) + + slots = opt.total_slots + opt.simulation.elect_price_hourly = np.linspace(0.0001, 0.0004, slots) + opt.simulation.elect_revenue_per_hour_arr = np.full(slots, 0.00005) + opt.simulation.pv_prediction_wh = np.full(slots, 1000.0) + opt.simulation.load_energy_array = np.full(slots, 500.0) + + guesses = opt._educated_guess_individuals() + + export_state = 5 + assert all(export_state not in guess for guess in guesses) diff --git a/tests/test_geneticoptimize.py b/tests/test_geneticoptimize.py index 7686c727..19139702 100644 --- a/tests/test_geneticoptimize.py +++ b/tests/test_geneticoptimize.py @@ -1,4 +1,5 @@ import json +from datetime import datetime from pathlib import Path from typing import Any from unittest.mock import patch @@ -32,7 +33,10 @@ def compare_dict(actual: dict[str, Any], expected: dict[str, Any]): compare_dict(actual[key], value) elif isinstance(value, list): assert isinstance(actual[key], list) - assert actual[key] == pytest.approx(value) + if value and isinstance(value[0], datetime): + assert actual[key] == value + else: + assert actual[key] == pytest.approx(value) else: assert actual[key] == pytest.approx(value) @@ -149,7 +153,7 @@ def test_optimize( pass # Fake energy management run start datetime - ems_eos.set_start_datetime(to_datetime().set(hour=fixed_start_hour)) + ems_eos.set_start_datetime(to_datetime("2025-01-15T10:00:00+01:00")) # Throw away any cached results of the last energy management run. CacheEnergyManagementStore().clear() diff --git a/tests/testdata/optimize_result_1.json b/tests/testdata/optimize_result_1.json index 7110b93d..98e2c3ee 100644 --- a/tests/testdata/optimize_result_1.json +++ b/tests/testdata/optimize_result_1.json @@ -145,7 +145,7 @@ 1, 0, 0, - 1, + 0, 1, 0 ], @@ -272,10 +272,10 @@ 0.0, 0.0 ], - "Gesamt_Verluste": 3425.4668727209255, - "Gesamtbilanz_Euro": 0.9585224311392879, + "Gesamt_Verluste": 3290.8745999936527, + "Gesamtbilanz_Euro": 1.251565700139288, "Gesamteinnahmen_Euro": 1.1316277804018695, - "Gesamtkosten_Euro": 2.0901502115411574, + "Gesamtkosten_Euro": 2.3831934805411574, "Home_appliance_wh_per_hour": [ 0.0, 0.0, @@ -316,6 +316,7 @@ 0.0, 0.0 ], + "home_appliance_energy_wh": {}, "Kosten_Euro_pro_Stunde": [ 0.0, 0.0, @@ -352,7 +353,7 @@ 0.0, 0.17784012884918773, 0.19011028252189552, - 0.0, + 0.293043269, 0.0, 0.16484566 ], @@ -392,7 +393,7 @@ 0.0, 556.6201215937018, 617.0408390843736, - 0.0, + 987.01, 0.0, 592.97 ], @@ -472,7 +473,7 @@ 81.2380484620021, 0.0, 0.0, - 134.59227272727276, + 0.0, 100.08954545454549, 0.0 ], @@ -513,8 +514,8 @@ 100.0, 100.0, 100.0, - 95.75150654269973, - 92.59211432506888 + 100.0, + 96.84060778236915 ], "Electricity_price": [ 0.000228, @@ -753,9 +754,10 @@ 1.0, 2.0, 2.0, - 1.0, + 0.0, 1.0, 0.0 ], - "washingstart": null + "washingstart": null, + "appliance_starts": {} } \ No newline at end of file diff --git a/tests/testdata/optimize_result_1_be.json b/tests/testdata/optimize_result_1_be.json index bdead719..ada69726 100644 --- a/tests/testdata/optimize_result_1_be.json +++ b/tests/testdata/optimize_result_1_be.json @@ -14,13 +14,6 @@ 0.0, 0.0, 0.0, - 1.0, - 1.0, - 0.0, - 1.0, - 1.0, - 0.0, - 1.0, 0.0, 0.0, 0.0, @@ -41,7 +34,14 @@ 0.0, 0.0, 0.0, - 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0, 0.0, 0.0, @@ -110,9 +110,7 @@ 0, 0, 0, - 1, - 1, - 1, + 0, 0, 0, 0, @@ -122,17 +120,25 @@ 0, 0, 1, + 1, + 0, 0, 0, 1, 1, 1, 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, 0, 0, - 1, - 1, - 1, 0, 0, 0, @@ -140,14 +146,8 @@ 1, 1, 0, - 1, 0, - 0, - 0, - 0, - 0, - 1, - 1 + 0 ], "battery_grid_export_allowed": [], "eautocharge_hours_float": null, @@ -157,7 +157,7 @@ 1063.91, 1320.56, 1132.03, - 1308.5200000000004, + 1163.67, 1176.82, 1216.22, 1103.78, @@ -237,13 +237,11 @@ 0.0, 0.0, 0.0, - 0.0, - 0.21077535122459587, + 0.022582049506752234, + 0.3039575, 0.19320652266312205, 0.1358062627100041, 0.0692592282596561, - 0.023370695807696434, - 0.0019327051509204403, 0.0, 0.0, 0.0, @@ -262,20 +260,22 @@ 0.0, 0.0, 0.0, - 0.24478962017661132, - 0.15146384621553569, + 0.0, + 0.0013652045768039896, + 0.2577971476677123, + 0.15236390731688437, 0.10316291465819699, 0.05435777788576338, - 0.020928608511559126, - 0.003524558735906156, + 0.0, + 0.0, 0.0, 0.0, 0.0 ], - "Gesamt_Verluste": 3110.842855499046, - "Gesamtbilanz_Euro": 1.1850381627731374, - "Gesamteinnahmen_Euro": 1.2125780919995675, - "Gesamtkosten_Euro": 2.397616254772705, + "Gesamt_Verluste": 2758.4157389677953, + "Gesamtbilanz_Euro": 1.2690402398027016, + "Gesamteinnahmen_Euro": 1.2938585152448954, + "Gesamtkosten_Euro": 2.562898755047597, "Home_appliance_wh_per_hour": [ 0.0, 0.0, @@ -316,98 +316,97 @@ 0.0, 0.0 ], + "home_appliance_energy_wh": {}, "Kosten_Euro_pro_Stunde": [ - 0.0, - 0.0, - 0.0, + 0.10013413727316416, + 0.09007999454232955, + 0.11436917344552285, 0.07557452231671152, - 0.026623430000000066, + 0.0, 4.55656845588237e-17, 0.001414013162203277, 0.005881449073870462, 0.05258762370598476, - 0.1614775630079859, - 0.2338232746714084, 0.0, + 0.0, + 0.29116746986009023, 0.26650619799999997, 0.19588158, 0.0, 0.0, 0.0, 0.0, - 0.182970359, - 0.162995926, 0.0, 0.0, 0.0, + 0.0, + 0.25364873699864443, 0.1306329312971816, 0.07362195915902499, 0.060401289430882174, 0.009619897970888898, - 0.0, - 0.0, + 0.07029121023060134, + 4.179128154646605e-17, 2.3325608707865465e-05, - 0.0, + 0.0021886029750169123, 0.013012984677295973, 0.08357424731947552, - 0.17784012884918773, - 0.19011028252189552, - 0.293043269, 0.0, - 0.0 + 0.0, + 0.293043269, + 0.214398479, + 0.16484566 ], "Netzbezug_Wh_pro_Stunde": [ - 0.0, - 0.0, - 0.0, + 439.1848126015972, + 407.23324838304495, + 546.436566868241, 402.20607938643707, - 144.85000000000036, + 0.0, 2.2737367544323206e-13, 6.433180901743754, 25.909467285772962, 175.4675465665157, - 505.40708296709204, - 758.9200735845777, 0.0, + 0.0, + 980.6920507244535, 912.38, 704.61, 0.0, 0.0, 0.0, 0.0, - 556.31, - 488.89, 0.0, 0.0, 0.0, + 0.0, + 833.8222781020527, 537.58407941227, 322.9033296448464, 273.0618871197205, 45.96224544141853, - 0.0, - 0.0, + 374.088399311343, + 2.2737367544323206e-13, 0.11639525303326081, - 0.0, + 9.957247384062384, 57.32592368852852, 278.85968408233407, - 556.6201215937018, - 617.0408390843736, - 987.01, 0.0, - 0.0 + 0.0, + 987.01, + 733.99, + 592.97 ], "Netzeinspeisung_Wh_pro_Stunde": [ 0.0, 0.0, 0.0, 0.0, - 0.0, - 3011.0764460656555, + 322.60070723931767, + 4342.25, 2760.093180901744, 1940.089467285773, 989.4175465665157, - 333.86708296709196, - 27.61007358457772, 0.0, 0.0, 0.0, @@ -426,95 +425,97 @@ 0.0, 0.0, 0.0, - 3496.9945739515906, - 2163.76923165051, + 0.0, + 19.502922525771282, + 3682.816395253033, + 2176.6272473840627, 1473.7559236885286, 776.5396840823341, - 298.9801215937018, - 50.35083908437366, + 0.0, + 0.0, 0.0, 0.0, 0.0 ], "Verluste_Pro_Stunde": [ - 97.85621559422765, - 101.92059640365329, - 114.42806532440363, + 37.96737751219166, + 46.38878980596536, + 39.91398802418894, 51.82392952637247, - 599.9999999999995, - 159.7408264721214, + 543.9059151312817, 0.0, 0.0, 0.0, 0.0, - 0.0, - 133.7321802766326, + 108.98319763338179, + 106.80230977350088, + 0.0014460869344160802, 0.0, 0.0, 70.41409090909087, 118.37045454545455, 94.68272727272722, 83.01681818181817, - 0.0, - 0.0, + 75.86045454545456, + 66.66681818181814, 69.12409090909085, 109.07302361034766, - 116.99491129525349, + 3.2918733722463145, 22.312089529472388, 54.18759955738153, 86.6234264543665, 165.15986945297027, - 116.9350623689079, - 538.2984000000001, - 22.298618556173096, - 2.900768349489402, + 65.92300791736113, + 535.9580492969076, 0.0, 0.0, 0.0, 0.0, + 111.78035844493081, + 90.18403329253945, 0.0, - 100.08954545454549, - 80.85954545454547 + 0.0, + 0.0 ], "akku_soc_pro_stunde": [ 80.0, - 79.16421888032488, - 78.69989843940196, - 77.45653455559739, - 78.89608815355218, - 95.56275482021886, + 81.05464937533866, + 82.3432268699488, + 83.45194875950959, + 84.8915023574644, 100.0, 100.0, 100.0, 100.0, 100.0, - 100.0, - 95.77874174137638, - 95.77874174137638, - 95.77874174137638, - 93.5560747303571, - 89.81963361465462, - 86.83091116286398, - 84.21043079096314, - 84.21043079096314, - 84.21043079096314, - 82.02848347691355, - 78.58559323596526, - 75.08792311742263, - 75.7077033821302, - 77.21291448094635, - 79.61912077134542, - 84.20689492281682, - 84.42786059566187, - 99.38059392899518, + 98.93741213017658, + 95.76274429012544, + 95.76278445920696, + 95.76278445920696, + 95.76278445920696, + 93.54011744818767, + 89.80367633248518, + 86.81495388069455, + 84.19447350879372, + 81.79988845369729, + 79.69550656664495, + 77.51355925259536, + 74.07066901164707, + 74.16210993865391, + 74.78189020336148, + 76.28710130217763, + 78.6933075925767, + 83.2810817440481, + 85.11227640841923, 100.0, 100.0, 100.0, 100.0, 100.0, - 100.0, - 100.0, - 96.84060778236915 + 98.60068046043587, + 96.11252124341868, + 96.11252124341868, + 96.11252124341868 ], "Electricity_price": [ 0.000228, @@ -708,39 +709,21 @@ "initial_soc_percentage": 54 }, "start_solution": [ - 1.0, - 1.0, - 0.0, - 1.0, - 1.0, - 2.0, - 2.0, - 1.0, - 1.0, - 0.0, - 1.0, - 1.0, - 1.0, - 0.0, - 2.0, - 2.0, - 0.0, - 2.0, - 2.0, - 0.0, - 2.0, - 1.0, 0.0, 0.0, - 1.0, - 1.0, - 1.0, - 1.0, 0.0, 0.0, - 1.0, - 1.0, - 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0, 0.0, 0.0, @@ -748,14 +731,33 @@ 1.0, 1.0, 0.0, + 0.0, + 0.0, 1.0, - 2.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, - 1.0 + 1.0, + 0.0, + 0.0, + 0.0 ], - "washingstart": null + "washingstart": null, + "appliance_starts": {} } \ No newline at end of file diff --git a/tests/testdata/optimize_result_2.json b/tests/testdata/optimize_result_2.json index 35e2f930..2cf68cfe 100644 --- a/tests/testdata/optimize_result_2.json +++ b/tests/testdata/optimize_result_2.json @@ -10,17 +10,9 @@ 0.0, 0.0, 0.0, - 1.0, 0.0, 0.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, + 0.0, 0.0, 1.0, 0.0, @@ -28,16 +20,9 @@ 0.0, 0.0, 0.0, - 1.0, - 1.0, 0.0, 1.0, 0.0, - 1.0, - 0.0, - 1.0, - 1.0, - 0.0, 0.0, 0.0, 0.0, @@ -47,6 +32,21 @@ 0.0, 0.0, 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, 0.0 ], "dc_charge": [ @@ -112,19 +112,14 @@ 0, 0, 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 1, + 0, + 1, + 1, + 0, 1, 0, 0, @@ -132,17 +127,22 @@ 0, 1, 0, + 1, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 1, + 0, 1, 1, + 0, 1, 1, 0, @@ -161,15 +161,15 @@ 0.0, 0.0, 0.0, - 0.875, - 0.75, - 0.0, - 0.375, 1.0, + 0.5, + 0.625, + 0.375, 0.75, + 0.75, + 0.375, 0.875, - 0.75, - 0.0, + 0.1, 0.0, 0.0, 0.0, @@ -202,28 +202,28 @@ ], "result": { "Last_Wh_pro_Stunde": [ - 15230.07, - 8929.91, - 1320.56, - 10061.61912107894, - 13077.21553917656, + 11541.07, + 6307.91, + 7875.5599999999995, + 5065.03, + 13622.08822093064, 9042.82, - 10393.22, - 8969.78, - 1129.12, + 7649.22, + 12780.779999999999, + 2177.92, 1178.71, 1050.98, - 988.56, + 5988.547949275546, 912.38, 704.61, 516.37, 868.05, 694.34, 608.79, - 2056.31, + 556.31, 488.89, 506.91, - 1304.8889978824886, + 804.89, 1141.98, 1056.97, 992.46, @@ -231,55 +231,55 @@ 827.01, 1257.98, 1232.67, - 871.26, + 2188.443604746967, 860.88, 1158.03, 1222.72, - 3721.04, - 3449.99, - 987.01, + 1221.04, + 949.99, + 1987.01, 733.99, 592.97 ], "EAuto_SoC_pro_Stunde": [ 5.0, - 20.294999999999998, - 33.405, - 33.405, - 39.96, - 57.440000000000005, - 70.55, - 85.845, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955, - 98.955 + 22.48, + 31.22, + 42.144999999999996, + 48.699999999999996, + 61.809999999999995, + 74.92, + 81.475, + 96.77, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518, + 98.518 ], "Einnahmen_Euro_pro_Stunde": [ 0.0, @@ -288,12 +288,6 @@ 0.0, 0.0, 0.0, - 9.722458428505041e-05, - 0.0023429436853348124, - 0.0692592282596561, - 0.023370695807696434, - 0.0019327051509204403, - 8.435507117427132e-07, 0.0, 0.0, 0.0, @@ -307,52 +301,31 @@ 0.0, 0.0, 0.0, - 0.03692581803776506, - 0.09634325718089931, - 0.038455087951794004, - 0.31400739999999994, - 0.2577866264025879, - 0.15146384621553569, - 0.09798107754792196, - 0.029150936607659956, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ], - "Gesamt_Verluste": 6850.393259430652, - "Gesamtbilanz_Euro": 13.198417631718888, - "Gesamteinnahmen_Euro": 1.1191176909827683, - "Gesamtkosten_Euro": 14.317535322701657, + "Gesamt_Verluste": 9279.931765999105, + "Gesamtbilanz_Euro": 12.822538076242544, + "Gesamteinnahmen_Euro": 0.0, + "Gesamtkosten_Euro": 12.822538076242544, "Home_appliance_wh_per_hour": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, 0.0, 0.0, 0.0, @@ -363,37 +336,37 @@ 2500.0, 0.0, 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0 ], "home_appliance_energy_wh": { "dishwasher1": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, 0.0, 0.0, 0.0, @@ -404,86 +377,113 @@ 2500.0, 0.0, 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0 ] }, "Kosten_Euro_pro_Stunde": [ - 3.26035212, - 0.7712613792641736, + 2.41926012, + 0.19137741085396395, + 1.4167558060312964, + 0.7340784901492668, + 1.4723942300000001, + 0.0, + 0.8450811735885355, + 1.2197241405944232, 0.0, - 1.672937586, - 1.342948866431813, - 0.770122611209644, - 1.4257539978642364, - 1.3586609716653002, - 0.05258762370598476, 0.1614775630079859, - 0.2338232746714084, - 0.29116746986009023, + 0.0, + 1.7756638919999999, 0.26650619799999997, 0.19588158, - 0.0, + 0.174739608, 0.0, 0.22802125600000003, - 0.199865757, - 0.676320359, - 0.162995926, 0.0, - 0.42921344809282075, + 0.0, + 0.162995926, + 0.16677339, + 0.0, 0.25364873699864443, 0.1306329312971816, 0.0, 0.060401289430882174, 0.009619897970888898, - 0.07029121023060134, - 4.179128154646605e-17, 0.0, 0.0, + 0.26398692, 0.0, 0.0, + 0.08357424731947552, 0.0, 0.0, - 0.293043269, + 0.589943269, 0.0, 0.0 ], "Netzbezug_Wh_pro_Stunde": [ - 14299.789999999999, - 3486.7150961309835, + 10610.789999999999, + 865.1781684175585, + 6769.01961792306, + 3906.7508789210588, + 8010.85, + 0.0, + 3844.7733102299158, + 5373.234099534904, 0.0, - 8903.34, - 7306.577075254695, - 3842.9272016449304, - 6486.596896561585, - 5985.290624076212, - 175.4675465665157, 505.40708296709204, - 758.9200735845777, - 980.6920507244535, + 0.0, + 5980.679999999999, 912.38, 704.61, - 0.0, + 516.37, 0.0, 694.34, - 608.79, - 2056.31, - 488.89, 0.0, - 1299.8590190576037, + 0.0, + 488.89, + 506.91, + 0.0, 833.8222781020527, 537.58407941227, 0.0, 273.0618871197205, 45.96224544141853, - 374.088399311343, - 2.2737367544323206e-13, 0.0, 0.0, + 1317.3000000000002, 0.0, 0.0, + 278.85968408233407, 0.0, 0.0, - 987.01, + 1987.01, 0.0, 0.0 ], @@ -494,12 +494,6 @@ 0.0, 0.0, 0.0, - 1.3889226326435775, - 33.47062407621161, - 989.4175465665157, - 333.86708296709196, - 27.61007358457772, - 0.012050724453467332, 0.0, 0.0, 0.0, @@ -513,14 +507,20 @@ 0.0, 0.0, 0.0, - 527.5116862537866, - 1376.3322454414188, - 549.358399311343, - 4485.82, - 3682.6660914655417, - 2163.76923165051, - 1399.729679256028, - 416.4419515379994, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0, 0.0, 0.0, @@ -528,84 +528,84 @@ 0.0 ], "Verluste_Pro_Stunde": [ - 1083.0, - 1014.0066115357181, - 114.42806532440363, - 806.9999999999999, - 752.8472490305633, - 452.3012641973916, - 490.424156871473, - 414.0, + 552.0, + 876.0621802101069, + 345.0239541507672, + 207.4093054705271, + 1013.9999999999998, + 976.3367916944278, + 226.85199722758986, + 1084.2496919441885, + 190.65093859054008, + 40.06404995605101, + 106.80230977350088, + 600.0000000000001, 0.0, 0.0, 0.0, - 0.0, - 0.0, - 0.0, - 70.41409090909087, 118.37045454545455, 0.0, + 83.01681818181817, + 75.86045454545456, 0.0, - 180.0, 0.0, - 69.12409090909085, - 60.00108228691243, + 109.07302361034766, 3.2918733722463145, 22.312089529472388, 98.21987178167876, - 23.32202410391207, - 0.0, - 0.0, - 0.0, - 0.03390853445803674, - 2.900768349489402, - 16.700320743972142, - 81.2380484620021, - 377.3215838283509, - 418.18661420587983, - 0.0, + 86.6234264543665, + 165.15986945297027, + 116.9350623689079, + 538.2984000000001, + 600.0000000000002, + 262.55307614755066, + 184.66788225469543, + 93.18476208988011, + 111.78035844493081, + 90.18403329253945, + 120.0, 100.08954545454549, 80.85954545454547 ], "akku_soc_pro_stunde": [ 80.0, - 96.66666666666667, - 77.72745638104269, - 76.48409249723811, - 93.15075916390477, - 98.72984941475377, - 99.79377342023686, - 100.0, - 100.0, - 100.0, - 100.0, - 100.0, - 100.0, - 100.0, - 100.0, - 97.77733298898072, - 94.04089187327823, - 94.04089187327823, - 94.04089187327823, - 99.04089187327823, - 99.04089187327823, - 96.85894455922863, - 98.52564128942065, - 98.6170822164275, - 99.23686248113506, - 99.35216599711354, - 100.0, - 100.0, - 100.0, - 100.0, - 100.0, - 100.0, - 100.0, - 100.0, - 88.1251455158017, - 74.92485531047642, - 74.92485531047642, - 71.76546309284556 + 80.0, + 61.0623332886646, + 61.06299868174146, + 61.074368278144995, + 77.74103494481164, + 62.263433461120634, + 62.81487782855368, + 43.910197554276095, + 42.50754248385738, + 43.62043276041435, + 40.44576492036321, + 57.11243158702987, + 57.11243158702987, + 57.11243158702987, + 57.11243158702987, + 53.3759904713274, + 53.3759904713274, + 50.75551009942657, + 48.36092504433015, + 48.36092504433015, + 48.36092504433015, + 44.918034803381865, + 45.0094757303887, + 45.629255995096266, + 45.744559511074755, + 48.150765801473824, + 52.73853995294522, + 52.95950562579026, + 67.9122389591236, + 84.57890562579026, + 91.79146973129197, + 96.45723532881205, + 99.04570094241983, + 97.64638140285571, + 95.1582221858385, + 98.49155551917185, + 95.332163301541 ], "Electricity_price": [ 0.000228, @@ -702,15 +702,15 @@ 0.0, 0.0, 0.0, - 0.875, - 0.75, - 0.0, - 0.375, 1.0, + 0.5, + 0.625, + 0.375, 0.75, + 0.75, + 0.375, 0.875, - 0.75, - 0.0, + 0.1, 0.0, 0.0, 0.0, @@ -795,112 +795,112 @@ "capacity_wh": 60000, "charging_efficiency": 0.95, "max_charge_power_w": 11040, - "soc_wh": 59373.0, + "soc_wh": 59110.8, "initial_soc_percentage": 5 }, "start_solution": [ + 0.0, + 1.0, + 2.0, + 1.0, + 0.0, + 2.0, + 0.0, + 2.0, + 0.0, + 2.0, + 0.0, + 1.0, + 0.0, + 0.0, + 2.0, + 1.0, + 0.0, + 1.0, + 1.0, + 0.0, + 1.0, + 2.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 1.0, + 1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 1.0, + 1.0, 2.0, 1.0, 1.0, 0.0, 1.0, 1.0, - 0.0, - 2.0, - 2.0, - 1.0, 2.0, 1.0, 1.0, - 2.0, - 2.0, - 2.0, - 2.0, - 2.0, - 2.0, - 2.0, - 2.0, - 0.0, - 2.0, - 0.0, - 1.0, - 1.0, - 0.0, - 0.0, - 2.0, - 2.0, - 1.0, - 2.0, - 0.0, - 2.0, - 1.0, - 2.0, - 2.0, - 0.0, - 0.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 0.0, - 1.0, - 1.0, - 4.0, - 0.0, - 5.0, - 4.0, - 1.0, - 3.0, 6.0, 5.0, - 3.0, - 0.0, - 5.0, 4.0, - 0.0, - 1.0, + 3.0, 6.0, - 4.0, - 5.0, - 4.0, - 1.0, - 3.0, - 3.0, - 2.0, - 3.0, - 0.0, - 1.0, - 3.0, - 4.0, - 5.0, - 1.0, - 3.0, - 0.0, - 2.0, - 2.0, - 5.0, 5.0, 5.0, 6.0, 1.0, - 5.0, - 5.0, - 0.0, - 0.0, 0.0, + 6.0, + 2.0, + 3.0, + 1.0, + 4.0, + 4.0, + 1.0, 5.0, 3.0, - 5.0, 2.0, 0.0, - 33.0 + 6.0, + 5.0, + 6.0, + 2.0, + 5.0, + 2.0, + 5.0, + 4.0, + 4.0, + 6.0, + 5.0, + 6.0, + 2.0, + 0.0, + 4.0, + 6.0, + 1.0, + 2.0, + 1.0, + 3.0, + 1.0, + 0.0, + 4.0, + 4.0, + 5.0, + 5.0, + 1.0, + 6.0 ], - "washingstart": 43, + "washingstart": 16, "appliance_starts": { "dishwasher1": [ - "2026-07-16 19:00:00+02:00" + "2025-01-15 16:00:00+01:00" ] } } \ No newline at end of file diff --git a/tests/testdata/optimize_result_2_be.json b/tests/testdata/optimize_result_2_be.json index 8ad92233..ae3105dc 100644 --- a/tests/testdata/optimize_result_2_be.json +++ b/tests/testdata/optimize_result_2_be.json @@ -10,19 +10,23 @@ 0.0, 0.0, 0.0, - 1.0, - 1.0, - 1.0, 0.0, 0.0, 0.0, 1.0, + 1.0, + 0.0, + 1.0, + 1.0, + 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, + 1.0, 0.0, 0.0, 0.0, @@ -32,11 +36,7 @@ 0.0, 0.0, 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, + 1.0, 0.0, 0.0, 0.0, @@ -111,11 +111,7 @@ 0, 0, 0, - 0, - 0, 1, - 1, - 0, 0, 0, 0, @@ -127,12 +123,10 @@ 0, 1, 0, - 1, - 1, 0, 1, - 1, - 1, + 0, + 0, 1, 1, 0, @@ -141,6 +135,12 @@ 0, 0, 1, + 0, + 0, + 1, + 1, + 1, + 1, 1, 1, 1, @@ -161,17 +161,17 @@ 0.0, 0.0, 0.0, - 0.875, - 0.0, 1.0, - 0.0, + 0.75, + 0.625, 0.375, - 0.375, - 1.0, - 0.0, + 0.75, 0.75, 0.375, - 0.6, + 0.8, + 0.0, + 0.0, + 0.0, 0.0, 0.0, 0.0, @@ -202,22 +202,22 @@ ], "result": { "Last_Wh_pro_Stunde": [ - 15230.07, - 1525.2526751616956, - 11808.56, - 1132.03, - 7596.67, - 7609.82, - 13190.760676868524, - 1103.78, - 8995.119999999999, - 5111.71, - 7343.779999999999, + 11541.07, + 8929.91, + 7875.5599999999995, + 10061.61912107894, + 13622.08822093064, + 11542.82, + 12483.786689770084, + 11482.522793459368, + 1129.12, + 1178.71, + 1050.98, 988.56, - 5912.38, + 912.38, 704.61, 516.37, - 868.05, + 2368.05, 694.34, 608.79, 556.31, @@ -228,7 +228,7 @@ 1056.97, 992.46, 1155.99, - 827.01, + 1189.376775455858, 1257.98, 1232.67, 871.26, @@ -243,43 +243,43 @@ ], "EAuto_SoC_pro_Stunde": [ 5.0, - 20.294999999999998, - 20.294999999999998, - 37.775, - 37.775, - 44.330000000000005, - 50.885000000000005, - 68.365, - 68.365, - 81.475, - 88.03, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518, - 98.518 + 22.48, + 35.589999999999996, + 46.515, + 53.06999999999999, + 66.18, + 79.29, + 85.845, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001, + 99.82900000000001 ], "Einnahmen_Euro_pro_Stunde": [ 0.0, @@ -289,8 +289,10 @@ 0.0, 0.0, 0.0, - 0.10263928607047809, - 0.0002638810165675977, + 0.0, + 0.05814763393192599, + 0.023370695807696434, + 0.0019327051509204403, 0.0, 0.0, 0.0, @@ -308,10 +310,8 @@ 0.0, 0.0, 0.0, - 0.0, - 0.0, - 0.035969913516850464, - 0.2577971476677123, + 0.300304461863129, + 0.2577866264025879, 0.15146384621553569, 0.09798107754792196, 0.029150936607659956, @@ -321,18 +321,18 @@ 0.0, 0.0 ], - "Gesamt_Verluste": 7723.761220821238, - "Gesamtbilanz_Euro": 14.859522880677414, - "Gesamteinnahmen_Euro": 0.6752660886427261, - "Gesamtkosten_Euro": 15.53478896932014, + "Gesamt_Verluste": 8027.369144275042, + "Gesamtbilanz_Euro": 13.979945090881573, + "Gesamteinnahmen_Euro": 0.9201379835273773, + "Gesamtkosten_Euro": 14.90008307440895, "Home_appliance_wh_per_hour": [ 0.0, 0.0, 0.0, 0.0, - 2500.0, - 2500.0, 0.0, + 2500.0, + 2500.0, 0.0, 0.0, 0.0, @@ -371,9 +371,9 @@ 0.0, 0.0, 0.0, - 2500.0, - 2500.0, 0.0, + 2500.0, + 2500.0, 0.0, 0.0, 0.0, @@ -408,36 +408,36 @@ ] }, "Kosten_Euro_pro_Stunde": [ - 3.26035212, - 0.1921289942880966, - 2.2398909259999997, + 2.41926012, + 0.7712613792641736, + 1.4167558060312964, + 1.672937586, + 1.4723942300000001, + 0.36290611910050846, + 1.907718932, + 1.9280712188270857, + 0.05258762370598476, + 0.1614775630079859, + 0.2338232746714084, 0.0, - 0.0, - 0.5064650351737862, - 2.0366107701900296, - 0.005881449073870462, - 2.11462917272379, - 0.0, - 2.1641282909999995, - 0.29116746986009023, - 1.727006198, + 0.26650619799999997, 0.19588158, - 0.174739608, 0.0, + 0.78571899, 0.22802125600000003, 0.0, 0.0, 0.162995926, + 0.16677339, 0.0, - 0.0, - 0.0, - 0.0, + 0.25364873699864443, + 0.1306329312971816, 0.0, 0.060401289430882174, - 0.009619897970888898, + 0.0854632640738, + 0.0, + 0.0, 0.0, - 4.179128154646605e-17, - 2.3325608707865465e-05, 0.0, 0.0, 0.0, @@ -448,36 +448,36 @@ 0.16484566 ], "Netzbezug_Wh_pro_Stunde": [ - 14299.789999999999, - 868.5759235447405, - 10701.82, + 10610.789999999999, + 3486.7150961309835, + 6769.01961792306, + 8903.34, + 8010.85, + 1810.908777946649, + 8679.34, + 8493.70580981095, + 175.4675465665157, + 505.40708296709204, + 758.9200735845777, 0.0, - 0.0, - 2527.2706345997312, - 9265.745087306777, - 25.909467285772962, - 7055.819728808107, - 0.0, - 7024.109999999999, - 980.6920507244535, - 5912.38, + 912.38, 704.61, - 516.37, 0.0, + 2368.05, 694.34, 0.0, 0.0, 488.89, + 506.91, 0.0, - 0.0, - 0.0, - 0.0, + 833.8222781020527, + 537.58407941227, 0.0, 273.0618871197205, - 45.96224544141853, + 408.3290208972767, + 0.0, + 0.0, 0.0, - 2.2737367544323206e-13, - 0.11639525303326081, 0.0, 0.0, 0.0, @@ -495,8 +495,10 @@ 0.0, 0.0, 0.0, - 1466.2755152925442, - 3.769728808108539, + 0.0, + 830.6804847418, + 333.86708296709196, + 27.61007358457772, 0.0, 0.0, 0.0, @@ -514,10 +516,8 @@ 0.0, 0.0, 0.0, - 0.0, - 0.0, - 513.8559073835781, - 3682.816395253033, + 4290.063740901843, + 3682.6660914655417, 2163.76923165051, 1399.729679256028, 416.4419515379994, @@ -528,36 +528,36 @@ 0.0 ], "Verluste_Pro_Stunde": [ - 1083.0, - 101.74991082536883, 552.0, - 106.67021307906845, - 567.0367126720731, - 259.38247615196775, - 735.7686104768134, - 56.857674239187475, - 414.0, - 766.976146106431, - 331.2000000000007, - 0.0014460869344160802, - 600.0, + 1014.0066115357181, + 345.0239541507672, + 806.9999999999999, + 1013.9999999999998, + 1036.459053353598, + 807.0, + 683.6982971773144, + 19.04844741896588, 0.0, 0.0, - 118.37045454545455, + 133.7321802766326, + 0.0, + 0.0, + 70.41409090909087, + 180.0, 0.0, 83.01681818181817, 75.86045454545456, 0.0, - 69.12409090909085, + 0.0, 109.07302361034766, - 116.99491129525349, - 95.61900944932736, + 3.2918733722463145, + 22.312089529472388, 98.21987178167876, 86.6234264543665, - 165.15986945297027, + 208.64388250767325, 116.9350623689079, - 476.63569111397055, - 0.0, + 23.490751091778808, + 0.03390853445803674, 2.900768349489402, 16.700320743972142, 81.2380484620021, @@ -569,34 +569,34 @@ ], "akku_soc_pro_stunde": [ 80.0, - 96.66666666666667, - 99.49305307848245, - 99.49305307848245, - 99.20134772591024, - 91.86086775366753, - 93.31593653566664, - 98.42062016002258, + 80.0, + 61.06078971437601, + 61.06145510745288, + 77.72812177411956, + 94.39478844078621, + 76.07925709454777, + 92.74592376121446, + 99.47087646058428, 100.0, 100.0, - 82.33137823444534, - 82.33137823444534, - 82.33141840352684, - 98.99808507019351, - 98.99808507019351, - 98.99808507019351, - 95.26164395449102, - 95.26164395449102, - 92.6411635825902, - 90.24657852749377, - 90.24657852749377, - 88.06463121344417, - 84.6217409724959, - 81.12407085395327, - 79.4298700605846, - 79.54517357656309, - 81.95137986696216, - 86.53915401843355, - 86.76011969127859, + 100.0, + 95.77874174137638, + 95.77874174137638, + 95.77874174137638, + 93.5560747303571, + 98.5560747303571, + 98.5560747303571, + 95.93559435845627, + 93.54100930335983, + 93.54100930335983, + 93.54100930335983, + 90.09811906241156, + 90.1895599894184, + 90.80934025412597, + 90.92464377010445, + 93.33085006050352, + 99.12651346349443, + 99.34747913633947, 100.0, 100.0, 100.0, @@ -702,17 +702,17 @@ 0.0, 0.0, 0.0, - 0.875, - 0.0, 1.0, - 0.0, + 0.75, + 0.625, 0.375, - 0.375, - 1.0, - 0.0, + 0.75, 0.75, 0.375, - 0.6, + 0.8, + 0.0, + 0.0, + 0.0, 0.0, 0.0, 0.0, @@ -795,112 +795,112 @@ "capacity_wh": 60000, "charging_efficiency": 0.95, "max_charge_power_w": 11040, - "soc_wh": 59110.8, + "soc_wh": 59897.4, "initial_soc_percentage": 5 }, "start_solution": [ 2.0, + 2.0, + 1.0, + 1.0, 0.0, 1.0, 2.0, + 2.0, + 2.0, + 0.0, + 0.0, 1.0, - 2.0, - 2.0, + 0.0, 2.0, 2.0, 1.0, 2.0, 2.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 1.0, + 2.0, 2.0, 1.0, 1.0, 0.0, - 2.0, - 0.0, 0.0, 1.0, 0.0, 0.0, + 1.0, + 0.0, 2.0, - 0.0, - 0.0, - 1.0, - 0.0, - 1.0, - 1.0, - 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 1.0, - 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, - 3.0, 0.0, 5.0, 4.0, - 0.0, - 2.0, - 1.0, - 5.0, - 0.0, - 6.0, - 5.0, - 0.0, - 6.0, - 0.0, - 1.0, - 1.0, - 6.0, - 0.0, - 4.0, - 1.0, - 5.0, - 2.0, - 1.0, - 4.0, - 6.0, - 6.0, - 6.0, - 6.0, 3.0, 6.0, - 1.0, 5.0, 5.0, - 5.0, - 5.0, - 2.0, - 6.0, - 4.0, - 4.0, - 5.0, - 4.0, - 1.0, - 6.0, - 5.0, - 1.0, - 2.0, 3.0, 1.0, - 4.0 + 0.0, + 6.0, + 4.0, + 3.0, + 1.0, + 4.0, + 4.0, + 1.0, + 5.0, + 3.0, + 2.0, + 5.0, + 6.0, + 5.0, + 1.0, + 1.0, + 1.0, + 2.0, + 5.0, + 4.0, + 2.0, + 6.0, + 5.0, + 6.0, + 2.0, + 0.0, + 4.0, + 4.0, + 1.0, + 2.0, + 1.0, + 3.0, + 2.0, + 1.0, + 0.0, + 0.0, + 0.0, + 4.0, + 5.0, + 5.0 ], - "washingstart": 14, + "washingstart": 15, "appliance_starts": { "dishwasher1": [ - "2026-07-15 14:00:00+02:00" + "2025-01-15 15:00:00+01:00" ] } } \ No newline at end of file