diff --git a/.flake8 b/.flake8 index 05ec680..c7e5c32 100755 --- a/.flake8 +++ b/.flake8 @@ -3,5 +3,5 @@ exclude = .git,__pycache__,documentation max-line-length = 160 max-complexity = 13 select = B,C,E,F,W,B9 -ignore = E501, W503, E203 +ignore = E501, W503, E203, E231 diff --git a/.gitignore b/.gitignore index 2819977..ffd2eea 100644 --- a/.gitignore +++ b/.gitignore @@ -176,3 +176,10 @@ cython_debug/ .vscode *.pickle flexmeasures.log +*.png + +#MacOS +.DS_Store +flexmeasures_s2/profile_steering/examples/example_schedule_itho_flask.py +flexmeasures_s2/profile_steering/examples/run_itho_with_debug.sh +flexmeasures_s2/profile_steering/examples/instructions/ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/flexmeasures-s2.iml b/.idea/flexmeasures-s2.iml new file mode 100644 index 0000000..e8fd289 --- /dev/null +++ b/.idea/flexmeasures-s2.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f8f2fd7 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..b88603f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 1f9652d..d13909c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,14 @@ using the FLEXMEASURES_PLUGINS setting (a list). Alternatively, if you installed this plugin as a package (e.g. via `python setup.py install`, `pip install -e` or `pip install flexmeasures_s2` should this project be on Pypi), then "flexmeasures_s2" suffices. -2. +2. Config settings (during development) + +In your `flexmeasures.cfg`, you can set the following config settings for this plugin: + +- `FLEXMEASURES_S2_TARGET_MODE`: "energy" or "costs" +- `FLEXMEASURES_S2_PRICE_SENSOR`: sensor ID of the price sensor + +To do: move these settings to the db asset (preferred scheduler and flex-context). ## Development @@ -29,3 +36,7 @@ or: Try it: pre-commit run --all-files --show-diff-on-failure + +For profiling, use: + + pyinstrument -o profiling_results.html test_frbc_device.py diff --git a/flexmeasures_s2/api/somedata.py b/flexmeasures_s2/api/somedata.py index 17608d9..80a88e4 100755 --- a/flexmeasures_s2/api/somedata.py +++ b/flexmeasures_s2/api/somedata.py @@ -1,5 +1,5 @@ -from flask_security import auth_token_required from flask_json import as_json +from flask_security import auth_token_required from .. import flexmeasures_s2_api_bp diff --git a/flexmeasures_s2/api/tests/test_api.py b/flexmeasures_s2/api/tests/test_api.py index d2048ad..3f4eb6f 100644 --- a/flexmeasures_s2/api/tests/test_api.py +++ b/flexmeasures_s2/api/tests/test_api.py @@ -1,16 +1,52 @@ from flask import url_for +from flask_security import decorators as fs_decorators +from rq.job import Job +from flexmeasures.api.tests.test_auth_token import patched_check_token +from flexmeasures.api.tests.utils import UserContext +from flexmeasures.data.services.scheduling import ( + handle_scheduling_exception, + get_data_source_for_job, +) +from flexmeasures.data.tests.utils import work_on_rq -def test_get_somedata_needs_authtoken(client): - response = client.get( - url_for("flexmeasures-s2 API.somedata"), - headers={"content-type": "application/json"}, - follow_redirects=True, - ) - assert response.status_code == 401 # HTTP error code 401 Unauthorized. - assert "application/json" in response.content_type - assert "not be properly authenticated" in response.json["message"] +def test_s2_frbc_api(monkeypatch, app, setup_frbc_asset): + sensor = setup_frbc_asset.sensors[0] -# TODO: The somedata endpoint requires authentication to be testes successfully. -# We'll need to add a user in conftest, which also requires us to add a db to testing + with UserContext("test_admin_user@seita.nl") as admin: + auth_token = admin.get_auth_token() + + monkeypatch.setattr(fs_decorators, "_check_token", patched_check_token) + with app.test_client() as client: + trigger_schedule_response = client.post( + url_for("SensorAPI:trigger_schedule", id=sensor.id), + json={ + "flex-context": { + "target-profile": {}, # add target profile + } + }, + headers={"Authorization": auth_token}, + ) + print("Server responded with:\n%s" % trigger_schedule_response.json) + assert trigger_schedule_response.status_code == 200 + job_id = trigger_schedule_response.json["schedule"] + + # Now that our scheduling job was accepted, we process the scheduling queue + work_on_rq(app.queues["scheduling"], exc_handler=handle_scheduling_exception) + job = Job.fetch(job_id, connection=app.queues["scheduling"].connection).is_finished + assert job.is_finished is True + + # First, make sure the expected scheduler data source is now there + job.refresh() # catch meta info that was added on this very instance + scheduler_source = get_data_source_for_job(job) + assert scheduler_source.model == "S2Scheduler" + + # try to retrieve the schedule through the /sensors//schedules/ [GET] api endpoint + # todo: to be discussed: the response from the S2Scheduler might get a different format than the FM default + # get_schedule_response = client.get( + # url_for("SensorAPI:get_schedule", id=sensor.id, uuid=job_id), + # query_string={"duration": "PT48H"}, + # ) + # print("Server responded with:\n%s" % get_schedule_response.json) + # assert get_schedule_response.status_code == 200 diff --git a/flexmeasures_s2/conftest.py b/flexmeasures_s2/conftest.py index 186ee1a..a97ad46 100644 --- a/flexmeasures_s2/conftest.py +++ b/flexmeasures_s2/conftest.py @@ -1,12 +1,18 @@ import pytest +from flask_sqlalchemy import SQLAlchemy + +from flexmeasures import Asset, AssetType, Sensor, Account from flexmeasures.app import create as create_flexmeasures_app +from flexmeasures.auth.policy import ADMIN_ROLE from flexmeasures.conftest import ( # noqa F401 db, fresh_db, -) # Use these fixtures to rely on the FlexMeasures database. +) # Use these fixtures to rely on the FlexMeasures database. There might be others in flexmeasures/conftest you want to also re-use +from flexmeasures.data.services.users import create_user -# There might be others in flexmeasures/conftest you want to also re-use +from flexmeasures_s2 import S2_SCHEDULER_SPECS +from flexmeasures_s2.models.const import FRBC_TYPE @pytest.fixture(scope="session") @@ -25,3 +31,43 @@ def app(): ctx.pop() print("DONE WITH APP FIXTURE") + + +@pytest.fixture(scope="module") +def setup_admin(db: SQLAlchemy): # noqa: F811 + account = Account(name="Some FlexMeasures host") + db.session.add(account) + create_user( + username="Test Admin User", + email="test_admin_user@seita.nl", + account_name=account.name, + password="testtest", + user_roles=dict(name=ADMIN_ROLE, description="A user who can do everything."), + ) + yield account + + +@pytest.fixture(scope="module") +def setup_frbc_asset(db: SQLAlchemy, setup_admin): # noqa: F811 + asset_type = AssetType(name=FRBC_TYPE) + asset = Asset( + name="Test FRBC asset", + generic_asset_type=asset_type, + owner=setup_admin, + ) + asset.attributes = { + "custom-scheduler": S2_SCHEDULER_SPECS, + "flex-model": { + "S2-FRBC-device-state": None, # ?todo: add serialized state + }, + } + db.session.add(asset) + sensor = Sensor( + name="power", + unit="kW", + event_resolution="PT5M", + generic_asset=asset, + ) + db.session.add(sensor) + db.session.flush() # assign (asset and sensor) IDs + yield asset diff --git a/flexmeasures_s2/models/__init__.py b/flexmeasures_s2/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flexmeasures_s2/models/const.py b/flexmeasures_s2/models/const.py new file mode 100644 index 0000000..6ff6a35 --- /dev/null +++ b/flexmeasures_s2/models/const.py @@ -0,0 +1,2 @@ +NAMESPACE = "fm-s2" +FRBC_TYPE = f"{NAMESPACE}.FRBC" diff --git a/flexmeasures_s2/profile_steering/__init__.py b/flexmeasures_s2/profile_steering/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flexmeasures_s2/profile_steering/cluster_plan.py b/flexmeasures_s2/profile_steering/cluster_plan.py new file mode 100644 index 0000000..d031f89 --- /dev/null +++ b/flexmeasures_s2/profile_steering/cluster_plan.py @@ -0,0 +1,679 @@ +from datetime import datetime +from typing import List, Dict, Any, Optional +import uuid + +# Common data types +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile + +# Import from common data structures to avoid circular imports +from flexmeasures_s2.profile_steering.common_data_structures import ( + ClusterState, +) +from flexmeasures_s2.profile_steering.common.device_plan import DevicePlan + +# Import cluster target +from flexmeasures_s2.profile_steering.cluster_target import ClusterTarget + + +class ClusterPlanData: + """Class representing planning data for a cluster.""" + + class CpData: + """Class representing data for a congestion point.""" + + def __init__( + self, + cp_id: str, + cp_plan: List[float], + der_plans: Dict[str, List[float]], + cp_consumption: List[float], + cp_production: List[float], + cp_consumption_max: float, + cp_production_max: float, + ): + self._cp_id = cp_id + self._cp_plan = cp_plan + self._der_plans = der_plans + self._cp_consumption = cp_consumption + self._cp_production = cp_production + self._cp_consumption_max = cp_consumption_max + self._cp_production_max = cp_production_max + + def get_cp_id(self) -> str: + return self._cp_id + + def get_cp_plan(self) -> List[float]: + return self._cp_plan + + def get_der_plans(self) -> Dict[str, List[float]]: + return self._der_plans + + def get_cp_consumption(self) -> List[float]: + return self._cp_consumption + + def get_cp_production(self) -> List[float]: + return self._cp_production + + def get_cp_consumption_max(self) -> float: + return self._cp_consumption_max + + def get_cp_production_max(self) -> float: + return self._cp_production_max + + def add_der_plan( + self, der_name: str, value: JouleProfile + ) -> "ClusterPlanData.CpData": + """Add a device energy resource plan to this congestion point. + + Args: + der_name: The name of the device energy resource + value: The profile of the device energy resource + + Returns: + A new CpData instance with the added device energy resource plan + """ + der_plan = to_float_array(value) + new_cp_plan = [0.0] * len(self._cp_plan) + cp_consumption = [0.0] * len(self._cp_plan) + cp_production = [0.0] * len(self._cp_plan) + consumption_max = self._cp_consumption_max + production_max = self._cp_production_max + + for i in range(len(self._cp_plan)): + new_cp_plan[i] = der_plan[i] + self._cp_plan[i] + cp_consumption[i] = self._cp_consumption[i] + cp_production[i] = self._cp_production[i] + + if der_plan[i] >= 0: + cp_consumption[i] += der_plan[i] + consumption_max = max(cp_consumption[i], consumption_max) + else: + cp_production[i] += der_plan[i] + production_max = min(cp_production[i], production_max) + + new_der_plans = self._der_plans.copy() + new_der_plans[der_name] = der_plan + + return ClusterPlanData.CpData( + self._cp_id, + new_cp_plan, + new_der_plans, + cp_consumption, + cp_production, + consumption_max, + production_max, + ) + + @classmethod + def empty(cls, cp_id: str, profile_metadata: Any) -> "ClusterPlanData.CpData": + """Create an empty CpData instance. + + Args: + cp_id: The congestion point ID + profile_metadata: Metadata about the profile + + Returns: + An empty CpData instance + """ + timesteps = profile_metadata.nr_of_timesteps + return cls( + cp_id, + [0.0] * timesteps, + {}, + [0.0] * timesteps, + [0.0] * timesteps, + 0.0, + 0.0, + ) + + def __init__( + self, + device_plans: Optional[List[DevicePlan]] = None, + profile_metadata: Any = None, + _id: Optional[str] = None, + reason: Optional[str] = None, + target: Any = None, + active_target: Any = None, + current_plan: Optional[List[float]] = None, + start: Optional[int] = None, + step: Optional[int] = None, + global_deviation_score: float = 1.0, + constraint_violation_score: float = 1.0, + cp_datas: Optional[Dict[str, CpData]] = None, + ): + self._device_plans = device_plans or [] + self._profile_metadata = profile_metadata + self._id = _id + self._reason = reason + self._target = target + self._active_target = active_target + self._current_plan = current_plan + self._start = start + self._step = step + self._global_deviation_score = global_deviation_score + self._constraint_violation_score = constraint_violation_score + self._cp_datas = cp_datas or {} + + def get_device_plans(self) -> List[DevicePlan]: + return self._device_plans + + @property + def metadata(self): + return self._profile_metadata + + def get_id(self) -> str: + return self._id or "" + + def get_reason(self) -> str: + return self._reason or "" + + def get_target(self) -> Any: + return self._target + + def get_active_target(self) -> Any: + return self._active_target + + def get_current_plan(self) -> List[float]: + return self._current_plan or [] + + def get_start(self) -> int: + return self._start or 0 + + def get_step(self) -> int: + return self._step or 0 + + def get_global_deviation_score(self) -> float: + return self._global_deviation_score + + def get_constraint_violation_score(self) -> float: + return self._constraint_violation_score + + def get_cp_datas(self) -> Dict[str, CpData]: + return self._cp_datas + + def is_compatible(self, other: Any) -> bool: + """Check if this cluster plan data is compatible with another profile. + + Args: + other: The other profile to check compatibility with + + Returns: + True if compatible, False otherwise + """ + if self._profile_metadata is None: + return False + + return self._profile_metadata.is_compatible(other.metadata) + + def subprofile(self, new_start_date: datetime) -> "ClusterPlanData": + """Create a subprofile starting at the specified date. + + Args: + new_start_date: The new start date for the profile + + Returns: + A new ClusterPlanData instance with adjusted start date + """ + # Create a copy of this instance with adjusted device plans + new_device_plans = [] + for device_plan in self._device_plans: + new_profile = device_plan.get_profile().subprofile(new_start_date) + new_device_plans.append(DevicePlan(device_plan.device_id, new_profile)) + + # Create new profile metadata with adjusted start date + new_profile_metadata = self._profile_metadata.subprofile(new_start_date) + + return ClusterPlanData( + device_plans=new_device_plans, + profile_metadata=new_profile_metadata, + _id=self._id, + reason=self._reason, + target=self._target, + active_target=self._active_target, + current_plan=self._current_plan, + start=int(new_start_date.timestamp() * 1000), + # Convert to milliseconds + step=self._step, + global_deviation_score=self._global_deviation_score, + constraint_violation_score=self._constraint_violation_score, + cp_datas=self._cp_datas, + ) + + def adjust_nr_of_elements(self, nr_of_elements: int) -> "ClusterPlanData": + """Adjust the number of elements in the profile. + + Args: + nr_of_elements: The new number of elements + + Returns: + A new ClusterPlanData instance with adjusted number of elements + """ + # Create a copy of this instance with adjusted device plans + new_device_plans = [] + for device_plan in self._device_plans: + new_profile = device_plan.get_profile().adjust_nr_of_elements( + nr_of_elements + ) + new_device_plans.append(DevicePlan(device_plan.device_id, new_profile)) + + # Create new profile metadata with adjusted number of elements + new_profile_metadata = self._profile_metadata.adjust_nr_of_elements( + nr_of_elements + ) + + return ClusterPlanData( + device_plans=new_device_plans, + profile_metadata=new_profile_metadata, + _id=self._id, + reason=self._reason, + target=self._target, + active_target=self._active_target, + current_plan=( + self._current_plan[:nr_of_elements] if self._current_plan else None + ), + start=self._start, + step=self._step, + global_deviation_score=self._global_deviation_score, + constraint_violation_score=self._constraint_violation_score, + cp_datas=self._cp_datas, + ) + + @classmethod + def from_cluster_plan( + cls, + cluster_plan: "ClusterPlan", + active_target: Optional[ClusterTarget] = None, + active_plan: Optional[JouleProfile] = None, + ) -> "ClusterPlanData": + """Create a ClusterPlanData instance from a ClusterPlan. + + Args: + cluster_plan: The cluster plan to create the data from + active_target: The active target for the cluster + active_plan: The active plan for the cluster + + Returns: + A ClusterPlanData instance + """ + congestion_points = {} + + # Get the device plans from the cluster plan + cluster_plan_data = cluster_plan.get_plan_data() + if cluster_plan_data is None: + return None # type: ignore + + # Process each device plan + for device_plan in cluster_plan_data.get_device_plans(): + cp_id = cluster_plan.get_state().get_congestion_point( + device_plan.connection_id + ) + if cp_id is None: + # The interface needs all devices to function properly. So for devices without congestion point, set a + # dummy congestion point so that those device plans go through. + cp_id = "No congestion point" + + if cp_id not in congestion_points: + congestion_points[cp_id] = ClusterPlanData.CpData.empty( + cp_id, cluster_plan.get_plan_data().metadata + ) + + congestion_points[cp_id] = congestion_points[cp_id].add_der_plan( + device_plan.device_id, device_plan.get_profile() + ) + + # Create the current plan + if active_plan is None: + # Extract the plan from the cluster plan's JouleProfile + joule_profile = cluster_plan.get_joule_profile() + current_plan = [ + element if element is not None else 0.0 + for element in joule_profile.elements + ] + else: + # Use the active plan, adjusting it to the profile metadata + profile_start = cluster_plan.get_plan_data().metadata.profile_start + nr_of_timesteps = cluster_plan.get_plan_data().metadata.nr_of_timesteps + + subprofile = active_plan.subprofile(profile_start) + adjusted_profile = subprofile.adjust_nr_of_elements(nr_of_timesteps) + current_plan = [ + element if element is not None else 0.0 + for element in adjusted_profile.elements + ] + + # Get the profile metadata + profile_metadata = cluster_plan.get_plan_data().metadata + + # Set up the active target + actual_active_target = ( + active_target if active_target is not None else cluster_plan.get_target() + ) + + # Calculate timestamps + start_time = ( + profile_metadata.profile_start.timestamp() * 1000 + ) # Convert to milliseconds + timestep_duration = ( + profile_metadata.timestep_duration.total_seconds() * 1000 + ) # Convert to milliseconds + + # Get scores, defaulting to 1.0 if they're NaN + global_deviation_score = cluster_plan.get_global_deviation_score() + global_deviation_score = ( + 1.0 if global_deviation_score is None else global_deviation_score + ) + + constraint_violation_score = cluster_plan.get_constraint_violation_score() + constraint_violation_score = ( + 1.0 if constraint_violation_score is None else constraint_violation_score + ) + + return cls( + device_plans=cluster_plan_data.get_device_plans(), + profile_metadata=profile_metadata, + _id=str(cluster_plan.get_id()), + reason=cluster_plan.get_reason(), + target=cluster_plan.get_target(), + active_target=actual_active_target, + current_plan=current_plan, # type: ignore[arg-type] + start=int(start_time), + step=int(timestep_duration), + global_deviation_score=global_deviation_score, + constraint_violation_score=constraint_violation_score, + cp_datas=congestion_points, + ) + + +def to_float_array(profile: JouleProfile) -> List[float]: + """Convert a JouleProfile to a list of floats. + + Args: + profile: The profile to convert + + Returns: + A list of floats + """ + result = [0.0] * profile.metadata.nr_of_timesteps + for i, element in enumerate(profile.elements): + result[i] = 0.0 if element is None else float(element) + return result + + +class ClusterPlan: + """Class representing a plan for a cluster.""" + + def __init__( + self, + state: ClusterState, + target: ClusterTarget, + plan_data: ClusterPlanData, + reason: str, + plan_due_by_date: datetime, + parent_plan: Optional["ClusterPlan"] = None, + _id: Optional[str] = None, + global_deviation_score: Optional[float] = None, + constraint_violation_score: Optional[float] = None, + activated_at: Optional[datetime] = None, + planned_energy: Optional[float] = None, + ): + self._state = state + self._target = target + self._plan_data = plan_data + self._reason = reason + self._plan_due_by_date = plan_due_by_date + self._parent_plan = parent_plan + self._id = _id or str(uuid.uuid4()) + self._global_deviation_score = global_deviation_score + self._constraint_violation_score = constraint_violation_score + self._joule_profile = None # Will be initialized when needed + self._activated_at = activated_at + self._planned_energy = planned_energy # Lazy evaluation field + + def get_state(self) -> ClusterState: + return self._state + + def get_target(self) -> ClusterTarget: + return self._target + + def get_plan_data(self) -> ClusterPlanData: + return self._plan_data + + def get_reason(self) -> str: + return self._reason + + def get_plan_due_by_date(self) -> datetime: + return self._plan_due_by_date + + def get_parent_plan(self) -> Optional["ClusterPlan"]: + return self._parent_plan + + def get_id(self) -> str: + return self._id + + def get_activated_at(self) -> Optional[datetime]: + return self._activated_at + + def get_target_energy(self) -> float: + """Get the target energy for this plan. + + Returns: + The target energy + """ + return self._target.get_target_energy() + + def get_planned_energy(self) -> float: + """Get the planned energy for this plan. + + Returns: + The planned energy + """ + if self._planned_energy is None: + # Calculate the planned energy as the sum of all device plans + sum_energy = 0.0 + for device_plan in self._plan_data.get_device_plans(): + sum_energy += device_plan.get_profile().get_total_energy + self._planned_energy = sum_energy + + return self._planned_energy + + def get_global_deviation_score(self) -> Optional[float]: + """Calculate the score for the deviation between target and plan. Lower is better. + + Returns: + The global deviation score, or None if not set + """ + if self._global_deviation_score is None: + joule_target_segment = ( + self._target.get_global_target_profile().target_elements_to_joule_profile() + ) + if not joule_target_segment.elements: + # No joule target, so that's by default a perfect score! + return 0.0 + + target = joule_target_segment.elements + plan_segment = self.get_joule_profile().subprofile( + joule_target_segment.metadata.profile_start + ) + plan = plan_segment.elements + + sum_squared_distance = 0.0 + for i in range(len(target)): + if target[i] is not None: + sum_squared_distance += abs(target[i] - plan[i]) + + if plan_segment.get_total_energy == 0.0: + self._global_deviation_score = 0.0 + else: + self._global_deviation_score = ( + sum_squared_distance / plan_segment.get_total_energy + ) + + return self._global_deviation_score + + def get_constraint_violation_score(self) -> Optional[float]: + """Calculate the score for violation of constraint targets. Lower is better. + + Returns: + The constraint violation score, or None if not set + """ + if self._constraint_violation_score is None: + violation_sum = 0.0 + + for cp_id, cp_profile in self.get_profile_per_congestion_point().items(): + plan = cp_profile.elements + congestion_point_target = self._target.get_congestion_point_target( + cp_id + ) + + if congestion_point_target is not None: + # If there is no target, we don't need to calculate it for the violation sum + target_elements = congestion_point_target.elements + + for i in range(len(target_elements)): + element = target_elements[i] + max_joule = element.max_joule + min_joule = element.min_joule + + if max_joule is not None and plan[i] > max_joule: + violation_sum += abs(plan[i] - max_joule) + + if min_joule is not None and plan[i] < min_joule: + violation_sum += abs(min_joule - plan[i]) + + planned_energy = self.get_planned_energy() + if planned_energy == 0.0: + self._constraint_violation_score = 0.0 + else: + self._constraint_violation_score = violation_sum / planned_energy + + return self._constraint_violation_score + + def has_constraint_violation(self) -> bool: + """Check if this plan has any constraint violations. + + Returns: + True if there are constraint violations, False otherwise + """ + for cp_id, cp_profile in self.get_profile_per_congestion_point().items(): + plan = cp_profile.elements + congestion_point_target = self._target.get_congestion_point_target(cp_id) + + if congestion_point_target is not None: + # If there is no target, we don't need to check for violations + target_elements = congestion_point_target.elements + + for i in range(len(target_elements)): + element = target_elements[i] + max_joule = element.max_joule + min_joule = element.min_joule + plan_value = plan[i] + + if max_joule is not None and plan_value > max_joule: + return True + + if min_joule is not None and plan_value < min_joule: + return True + + return False + + def is_compatible(self, other: Any) -> bool: + """Check if this cluster plan is compatible with another profile. + + Args: + other: The other profile to check compatibility with + + Returns: + True if compatible, False otherwise + """ + return self._plan_data.is_compatible(other) + + def subprofile(self, new_start_date: datetime) -> "ClusterPlan": + """Create a subprofile starting at the specified date. + + Args: + new_start_date: The new start date for the profile + + Returns: + A new ClusterPlan instance with adjusted start date + """ + return ClusterPlan( + state=self._state, + target=self._target.subprofile(new_start_date), + plan_data=self._plan_data.subprofile(new_start_date), + reason=self._reason, + plan_due_by_date=self._plan_due_by_date, + parent_plan=None, + _id=self._id, + activated_at=None, + ) + + def adjust_nr_of_elements(self, nr_of_elements: int) -> "ClusterPlan": + """Adjust the number of elements in the profile. + + Args: + nr_of_elements: The new number of elements + + Returns: + A new ClusterPlan instance with adjusted number of elements + """ + return ClusterPlan( + state=self._state, + target=self._target.adjust_nr_of_elements(nr_of_elements), + plan_data=self._plan_data.adjust_nr_of_elements(nr_of_elements), + reason=self._reason, + plan_due_by_date=self._plan_due_by_date, + parent_plan=None, + _id=self._id, + activated_at=None, + ) + + @property + def metadata(self) -> Any: + """Get the profile metadata for this plan. + + Returns: + The profile metadata + """ + return self._target.metadata + + def get_profile_per_congestion_point(self) -> Dict[str, JouleProfile]: + """Get the profile for each congestion point. + + Returns: + A dictionary mapping congestion point IDs to profiles + """ + result: Dict[str, JouleProfile] = {} + + for device_plan in self._plan_data.get_device_plans(): + cp_id = self._state.get_congestion_point(device_plan.connection_id) + profile = device_plan.get_profile() + + if cp_id in result: + result[cp_id] = result[cp_id].add(profile) + elif cp_id is not None: + result[cp_id] = profile + else: + raise ValueError( + f"No congestion point found for device plan {device_plan.device_id}" + ) + + return result + + def get_joule_profile(self) -> JouleProfile: + """Get the JouleProfile for this plan. + + Returns: + The JouleProfile for this plan + """ + + # Add all device plans to the profile + sum_profile = JouleProfile( + profile_start=self.metadata.profile_start, + timestep_duration=self.metadata.timestep_duration, + profile_length=self.metadata.nr_of_timesteps, + value=0, + ) + for device_plan in self._plan_data.get_device_plans(): + sum_profile = sum_profile.add(device_plan.energy_profile) + + return sum_profile diff --git a/flexmeasures_s2/profile_steering/cluster_target.py b/flexmeasures_s2/profile_steering/cluster_target.py new file mode 100644 index 0000000..0db49c3 --- /dev/null +++ b/flexmeasures_s2/profile_steering/cluster_target.py @@ -0,0 +1,241 @@ +from datetime import datetime +from typing import Dict, Optional, Any, List +import uuid + +# Common data types +from flexmeasures_s2.profile_steering.common.joule_range_profile import ( + JouleRangeProfile, +) +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile + + +class ClusterTarget: + """ + ClusterTarget instances are used by traders to express how a plan should look like. + + There are two levels at which a target can be set: + 1. Global level (i.e., a target for the cluster as a whole) + 2. Congestion point level + + The global target is a TargetProfile (i.e., a line) and the congestion point targets + are JouleRangeProfile instances, allowing congestion targets to be set with + minimum and maximum constraints. + """ + + def __init__( + self, + generated_at: datetime, + parent_id: Any, + generated_by: Any, + global_target_profile: TargetProfile, + congestion_point_targets: Optional[Dict[str, JouleRangeProfile]] = None, + ): + """ + Initialize a ClusterTarget instance. + + Args: + generated_at: When the target was generated + parent_id: The ID of the parent target + generated_by: The entity that generated the target + global_target_profile: The global target profile for the cluster + congestion_point_targets: Targets for specific congestion points + """ + self._id = str(uuid.uuid4()) + self._generated_at = generated_at + self._parent_id = parent_id + self._generated_by = generated_by + self._global_target_profile = global_target_profile + self._congestion_point_targets = congestion_point_targets or {} + + # Validate + if global_target_profile is None: + raise ValueError("global_target_profile cannot be None") + + if congestion_point_targets is not None: + for cp_id, cp_target in congestion_point_targets.items(): + if not cp_target.is_compatible(global_target_profile): + raise ValueError( + f"Congestion point target {cp_id} is not compatible with the global target profile. " + f"Expected global metadata: {global_target_profile.metadata}, " + f"but congestion profile had {cp_target.metadata}" + ) + + def get_id(self) -> str: + """ + Get the ID of this target. + + Returns: + The target ID + """ + return self._id + + def get_generated_at(self) -> datetime: + """ + Get when this target was generated. + Returns: + The generation timestamp + """ + return self._generated_at + + def get_parent_id(self) -> Any: + """ + Get the parent ID of this target. + + Returns: + The parent ID + """ + return self._parent_id + + def get_generated_by(self) -> Any: + """ + Get the entity that generated this target. + + Returns: + The generator entity + """ + return self._generated_by + + def get_global_target_profile(self) -> TargetProfile: + """ + Get the global target profile. + + Returns: + The global target profile + """ + return self._global_target_profile + + def get_congestion_point_targets(self) -> Dict[str, JouleRangeProfile]: + """ + Get all congestion point targets. + + Returns: + A dictionary mapping congestion point IDs to their targets + """ + return self._congestion_point_targets + + def get_congestion_point_target( + self, congestion_point_id: str + ) -> Optional[JouleRangeProfile]: + """ + Get the target for a specific congestion point. + + Args: + congestion_point_id: The ID of the congestion point + + Returns: + The target for the congestion point, or None if not found + """ + return self._congestion_point_targets.get(congestion_point_id) + + @property + def metadata(self) -> Any: + """ + Get the profile metadata. + + Returns: + The profile metadata + """ + return self._global_target_profile.metadata + + def get_target_energy(self) -> float: + """ + Get the total target energy. + + Returns: + The total energy + """ + return self._global_target_profile.get_total_energy() + + def is_compatible(self, other: Any) -> bool: + """ + Check if this target is compatible with another profile. + + Args: + other: The other profile to check compatibility with + + Returns: + True if compatible, False otherwise + """ + return self._global_target_profile.is_compatible(other) + + def subprofile(self, new_start_date: datetime) -> "ClusterTarget": + """ + Create a subprofile starting at the specified date. + + Args: + new_start_date: The new start date for the profile + + Returns: + A new ClusterTarget instance with adjusted start date + """ + plans = {} + for cp_id, cp_target in self._congestion_point_targets.items(): + plans[cp_id] = cp_target.subprofile(new_start_date) + + return ClusterTarget( + self._generated_at, + self._parent_id, + self._generated_by, + self._global_target_profile.subprofile(new_start_date), + plans, + ) + + def adjust_nr_of_elements(self, nr_of_elements: int) -> "ClusterTarget": + """ + Adjust the number of elements in the profile. + + Args: + nr_of_elements: The new number of elements + + Returns: + A new ClusterTarget instance with adjusted number of elements + """ + plans = {} + for cp_id, cp_target in self._congestion_point_targets.items(): + plans[cp_id] = cp_target.adjust_nr_of_elements(nr_of_elements) + + return ClusterTarget( + self._generated_at, + self._parent_id, + self._generated_by, + self._global_target_profile.adjust_nr_of_elements(nr_of_elements), + plans, + ) + + def set_congestion_point_target( + self, + congestion_point_id: str, + congestion_point_target: JouleRangeProfile, + elements: Optional[List[Any]] = None, + ): + """ + Set a target for a specific congestion point. + + Args: + congestion_point_id: The ID of the congestion point + congestion_point_target: The target for the congestion point + elements: Optional elements to set in the target profile + """ + if not congestion_point_target.is_compatible(self._global_target_profile): + raise ValueError( + f"Congestion point target {congestion_point_id} is not compatible with the global target profile" + ) + + self._congestion_point_targets[congestion_point_id] = congestion_point_target + + if elements is not None: + self._congestion_point_targets[congestion_point_id].elements = elements + + def contains_energy_target(self) -> bool: + """ + Check if this cluster target contains any energy targets (JouleElement instances). + + Returns: + True if there are any JouleElement instances in the global target profile, False otherwise + """ + from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile + + for element in self._global_target_profile.elements: + if isinstance(element, TargetProfile.JouleElement): + return True + return False diff --git a/flexmeasures_s2/profile_steering/common/__init__.py b/flexmeasures_s2/profile_steering/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flexmeasures_s2/profile_steering/common/abstract_profile.py b/flexmeasures_s2/profile_steering/common/abstract_profile.py new file mode 100644 index 0000000..2eb1f28 --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/abstract_profile.py @@ -0,0 +1,157 @@ +from abc import ABC, abstractmethod +from typing import List, TypeVar, Generic, Optional +from datetime import datetime, timedelta +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata + +E = TypeVar("E") +PT = TypeVar("PT", bound="AbstractProfile") + + +class AbstractProfile(ABC, Generic[E, PT]): + def __init__( + self, + profile_metadata: Optional[ProfileMetadata] = None, + elements: Optional[List[E]] = None, + profile_start: Optional[datetime] = None, + timestep_duration: Optional[timedelta] = None, + value: Optional[E] = None, + nr_of_elements: Optional[int] = None, + ): + """ + Initialize an AbstractProfile with various parameter combinations. + + Args: + profile_metadata: ProfileMetadata object containing start time and duration + elements: List of profile elements + profile_start: Start time of the profile + timestep_duration: Duration of each timestep + value: Single value to fill the entire profile + nr_of_elements: Number of elements when using a single value + """ + # Case 1: Initialize with metadata and elements + if profile_metadata is not None and elements is not None: + self.metadata = profile_metadata + self.elements = elements + self.validate(profile_metadata, elements) + return + + # Case 2: Initialize with start time, duration and elements + if ( + profile_start is not None + and timestep_duration is not None + and elements is not None + ): + self.metadata = ProfileMetadata( + profile_start, timestep_duration, len(elements) + ) + self.elements = elements + self.validate(self.metadata, elements) + return + + # Case 3: Initialize with start time, duration, single value and number of elements + if ( + profile_start is not None + and timestep_duration is not None + and value is not None + and nr_of_elements is not None + ): + self.elements = [value] * nr_of_elements + self.metadata = ProfileMetadata( + profile_start, timestep_duration, nr_of_elements + ) + self.validate(self.metadata, self.elements) + return + + # Case 4: Empty initialization (for serialization) + self.metadata = ProfileMetadata(datetime.now(), timedelta(hours=1), 0) + self.elements = [] + + @abstractmethod + def validate(self, profile_metadata: ProfileMetadata, elements: List[E]): + if elements is None: + raise ValueError("elements cannot be null") + if ( + 24 * 60 * 60 * 1000 + ) % profile_metadata.timestep_duration.total_seconds() * 1000 != 0: + raise ValueError("A day should be dividable by the timeStepDuration") + if ( + not self.start_of_current_aligned_date( + profile_metadata.profile_start, + profile_metadata.timestep_duration, + ) + == profile_metadata.profile_start + ): + raise ValueError( + "The startTimeDuration should be aligned with the timeStepDuration" + ) + + @property + def get_elements(self) -> List[E]: + return self.elements + + def get_element_end_date_at(self, index: int) -> datetime: + return self.metadata.get_profile_start_at_timestep(index + 1) + + def index_at(self, date: datetime) -> int: + return self.metadata.get_starting_step_nr(date) + + def element_at(self, date: datetime) -> E: + index = self.index_at(date) + if index >= 0: + return self.elements[index] + raise ValueError(f"No element found at date - index {index} is invalid") + + @staticmethod + def next_aligned_date(date: datetime, time_step_duration: timedelta) -> datetime: + time_step_duration_ms = time_step_duration.total_seconds() * 1000 + ms_since_last_aligned_date = (date.timestamp() * 1000) % time_step_duration_ms + + if ms_since_last_aligned_date == 0: + return date + else: + return date + timedelta( + milliseconds=(time_step_duration_ms - ms_since_last_aligned_date) + ) + + @staticmethod + def start_of_current_aligned_date( + date: datetime, time_step_duration: timedelta + ) -> datetime: + ms_since_last_aligned_date = ( + (date.timestamp() * 1000) % time_step_duration.total_seconds() * 1000 + ) + if ms_since_last_aligned_date == 0: + return date + else: + return datetime.fromtimestamp( + date.timestamp() - ms_since_last_aligned_date / 1000 + ) + + @staticmethod + def end_of_current_aligned_date( + date: datetime, time_step_duration: timedelta + ) -> datetime: + return ( + AbstractProfile.start_of_current_aligned_date(date, time_step_duration) + + time_step_duration + ) + + @staticmethod + def get_start_of_day(date: datetime) -> datetime: + return datetime.combine(date.date(), datetime.min.time()) + + @abstractmethod + def subprofile(self, new_start_date: datetime) -> PT: + pass + + @abstractmethod + def adjust_nr_of_elements(self, nr_of_elements: int) -> PT: + pass + + @abstractmethod + def is_compatible(self, other: PT) -> bool: + return self.metadata == other.metadata + + @abstractmethod + def default_value(self) -> E: + pass diff --git a/flexmeasures_s2/profile_steering/common/device_plan.py b/flexmeasures_s2/profile_steering/common/device_plan.py new file mode 100644 index 0000000..6082845 --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/device_plan.py @@ -0,0 +1,23 @@ +from typing import Optional, Union +from flexmeasures_s2.profile_steering.common.pydantic_base import FlexMeasuresBaseModel + +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.soc_profile import SoCProfile +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_instruction_profile import ( + S2FrbcInstructionProfile, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_instruction_profile import ( + S2DdbcInstructionProfile, +) + + +class DevicePlan(FlexMeasuresBaseModel): + + device_id: str + device_name: str + connection_id: str + energy_profile: JouleProfile + fill_level_profile: Optional[SoCProfile] = None + instruction_profile: Optional[ + Union[S2FrbcInstructionProfile, S2DdbcInstructionProfile] + ] = None diff --git a/flexmeasures_s2/profile_steering/common/joule_profile.py b/flexmeasures_s2/profile_steering/common/joule_profile.py new file mode 100644 index 0000000..b51d501 --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/joule_profile.py @@ -0,0 +1,220 @@ +from datetime import datetime, timedelta +from typing import List, Optional +from flexmeasures_s2.profile_steering.common.abstract_profile import AbstractProfile +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata + +# Developer Note: Type ignores in this module +# ============================================= +# JouleProfile uses type ignores in super().__init__() and other calls because it accepts +# List[Optional[int]] for flexible initialization (allowing None values), while +# AbstractProfile expects List[int]. This design choice allows for more flexible +# profile creation where missing values can be specified as None and handled +# appropriately during processing. + + +class JouleProfile(AbstractProfile[int, "JouleProfile"]): + def __init__( + self, + profile_start: Optional[datetime] = None, + timestep_duration: Optional[timedelta] = None, + elements: Optional[List[Optional[int]]] = None, + metadata: Optional[ProfileMetadata] = None, + value: Optional[int] = None, + profile_length: Optional[int] = None, + other_profile: Optional["JouleProfile"] = None, + ): + """ + Initialize a JouleProfile with various parameter combinations. + + Args: + profile_start: Start time of the profile + timestep_duration: Duration of each timestep + elements: List of energy values + metadata: ProfileMetadata object containing start time and duration + value: Single value to fill the entire profile + profile_length: Length of the profile when using a single value + other_profile: Another JouleProfile to copy from + """ + # Case 1: Copy from another profile + if other_profile is not None: + super().__init__( + profile_metadata=other_profile.metadata, + elements=other_profile.elements, + ) + return + + # Case 2: Initialize from metadata + if metadata is not None: + if elements is not None: + super().__init__(profile_metadata=metadata, elements=elements) # type: ignore[arg-type] + elif value is not None: + elements = [value] * metadata.nr_of_timesteps + super().__init__(profile_metadata=metadata, elements=elements) # type: ignore[arg-type] + else: + super().__init__(profile_metadata=metadata, elements=[]) # type: ignore[arg-type] + return + + # Case 3: Initialize with single value and profile length + if value is not None and profile_length is not None: + elements = [value] * profile_length + super().__init__( + profile_start=profile_start, + timestep_duration=timestep_duration, + elements=elements, # type: ignore[arg-type] + ) + return + + # Case 4: Basic initialization + if profile_start is not None and timestep_duration is not None: + super().__init__( + profile_start=profile_start, + timestep_duration=timestep_duration, + elements=elements if elements is not None else [], # type: ignore[arg-type] + ) + return + + # Case 5: Empty initialization (for serialization) + super().__init__() + + def validate(self, profile_metadata: ProfileMetadata, elements: List[int]): + super().validate(profile_metadata, elements) + # Add any JouleProfile-specific validation here if needed + + def default_value(self) -> None: # type: ignore + return None + + def subprofile(self, new_start_date: datetime) -> "JouleProfile": + index = self.index_at(new_start_date) + if index < 0: + raise ValueError("New start date is outside profile range") + new_elements = self.elements[index:] + return JouleProfile( + new_start_date, + self.metadata.timestep_duration, + new_elements, # type: ignore[arg-type] + ) + + def adjust_nr_of_elements(self, nr_of_elements: int) -> "JouleProfile": + if nr_of_elements < len(self.elements): + new_elements = self.elements[:nr_of_elements] + else: + new_elements = self.elements + [0] * (nr_of_elements - len(self.elements)) + return JouleProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + new_elements, # type: ignore[arg-type] + ) + + def is_compatible(self, other: AbstractProfile) -> bool: + return self.metadata == other.metadata + + def avg_power_at(self, date: datetime) -> Optional[float]: + element = self.element_at(date) + return element / self.metadata.timestep_duration.total_seconds() + + def add(self, other: "JouleProfile") -> "JouleProfile": + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + summed_elements = [0] * len(self.elements) + for i in range(len(self.elements)): + if self.elements[i] is None or other.elements[i] is None: + # mypy complains that the return is None + summed_elements[i] = self.default_value() # type: ignore + else: + summed_elements[i] = self.elements[i] + other.elements[i] + return JouleProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + summed_elements, # type: ignore[arg-type] + ) + + def subtract(self, other: "JouleProfile") -> "JouleProfile": + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + diff_elements = [0] * len(self.elements) + for i in range(len(self.elements)): + if self.elements[i] is None or other.elements[i] is None: + # mypy complains that the return is None + diff_elements[i] = self.default_value() # type: ignore + else: + diff_elements[i] = self.elements[i] - other.elements[i] + return JouleProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + diff_elements, # type: ignore[arg-type] + ) + + def absolute_values(self) -> "JouleProfile": + abs_elements = [abs(e) for e in self.elements] + return JouleProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + abs_elements, # type: ignore[arg-type] + ) + + def sum_quadratic_distance(self) -> float: + return sum(e**2 for e in self.elements if e is not None) + + def is_below_or_equal(self, other: "JouleProfile") -> bool: + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + return all( + a <= b for a, b in zip(self.elements, other.elements) if b is not None + ) + + def is_above_or_equal(self, other: "JouleProfile") -> bool: + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + return all( + a >= b for a, b in zip(self.elements, other.elements) if b is not None + ) + + def minimum(self, other: "JouleProfile") -> "JouleProfile": + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + # skip None values + min_elements = [ + min(a, b) + for a, b in zip(self.elements, other.elements) + if a is not None and b is not None + ] + return JouleProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + min_elements, # type: ignore[arg-type] + ) + + def maximum(self, other: "JouleProfile") -> "JouleProfile": + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + # skip None values + max_elements = [ + max(a, b) + for a, b in zip(self.elements, other.elements) + if a is not None and b is not None + ] + return JouleProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + max_elements, # type: ignore[arg-type] + ) + + @property + def get_total_energy(self) -> int: + return sum(self.elements) + + @property + def get_total_energy_production(self) -> int: + return sum(min(0, e) for e in self.elements) + + @property + def get_total_energy_consumption(self) -> int: + return sum(max(0, e) for e in self.elements) + + def get_energy_for_timestep(self, index: int) -> Optional[int]: + if 0 <= index < len(self.elements): + return self.elements[index] + return None + + def __str__(self) -> str: + return f"JouleProfile(elements={self.elements}, profile_start={self.metadata.profile_start}, timestep_duration={self.metadata.timestep_duration})" diff --git a/flexmeasures_s2/profile_steering/common/joule_range_profile.py b/flexmeasures_s2/profile_steering/common/joule_range_profile.py new file mode 100644 index 0000000..fe39323 --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/joule_range_profile.py @@ -0,0 +1,259 @@ +from dataclasses import dataclass +from datetime import datetime, timedelta +from typing import ClassVar, List, Optional, Union + +from flexmeasures_s2.profile_steering.common.abstract_profile import AbstractProfile +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile + + +@dataclass +class Element: + """ + Represents an element in a JouleRangeProfile with min and max joule values. + Both values can be None, representing unbounded values. + """ + + min_joule: Optional[int] = None + max_joule: Optional[int] = None + + # Class constant for NULL element + NULL: ClassVar[Optional["Element"]] = None # Will be set after class definition + + def __eq__(self, other): + if not isinstance(other, Element): + return False + return self.min_joule == other.min_joule and self.max_joule == other.max_joule + + def __str__(self): + return f"Element(min_joule={self.min_joule}, max_joule={self.max_joule})" + + +# Set the NULL element after class definition +Element.NULL = Element(None, None) + + +class JouleRangeProfile(AbstractProfile[Element, "JouleRangeProfile"]): + """ + A profile containing elements with minimum and maximum joule values. + This is the Python implementation of the Java JouleRangeProfile class. + """ + + def __init__( + self, + profile_start: Union[datetime, ProfileMetadata], + timestep_duration: Optional[timedelta] = None, + elements: Optional[List[Element]] = None, + min_value: Optional[int] = None, + max_value: Optional[int] = None, + nr_of_timesteps: Optional[int] = None, + ): + """ + Initialize a JouleRangeProfile with various constructor options. + + Args: + profile_start: Either a datetime representing profile start or a ProfileMetadata + timestep_duration: Duration of each timestep (if profile_start is datetime) + elements: List of Element objects with min/max joule values + min_value: Optional default min value for all elements + max_value: Optional default max value for all elements + nr_of_timesteps: Number of timesteps for the profile + """ + if isinstance(profile_start, ProfileMetadata): + metadata = profile_start + if nr_of_timesteps is None: + nr_of_timesteps = metadata.nr_of_timesteps + + elements = self._create_element_array(nr_of_timesteps, min_value, max_value) + + else: + if elements is not None: + if timestep_duration is None: + raise ValueError( + "Timestep duration is required when elements are provided" + ) + metadata = ProfileMetadata( + profile_start, timestep_duration, len(elements) + ) + elif nr_of_timesteps is not None: + if timestep_duration is None: + raise ValueError( + "Timestep duration is required when nr_of_timesteps is provided" + ) + metadata = ProfileMetadata( + profile_start, timestep_duration, nr_of_timesteps + ) + elements = self._create_element_array( + nr_of_timesteps, min_value, max_value + ) + else: + if timestep_duration is None: + raise ValueError( + "Timestep duration is required when no elements or nr_of_timesteps are provided" + ) + metadata = ProfileMetadata(profile_start, timestep_duration, 0) + elements = [] + + super().__init__(metadata, elements) + + @staticmethod + def _create_element_array( + nr_of_elements: int, min_value: Optional[int], max_value: Optional[int] + ) -> List[Element]: + """Create an array of elements with the given min and max values.""" + return [Element(min_value, max_value) for _ in range(nr_of_elements)] + + def default_value(self) -> Element: + return Element(None, None) + + def validate(self, profile_metadata: ProfileMetadata, elements: List[Element]): + """Validate the elements and metadata for this profile.""" + super().validate(profile_metadata, elements) + # Add any JouleRangeProfile-specific validation here if needed + + def is_within_range(self, other: JouleProfile) -> bool: + """ + Check if the given JouleProfile is within the range defined by this profile. + + Args: + other: JouleProfile to check + + Returns: + True if other is within the range, False otherwise + """ + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + + for i in range(self.metadata.nr_of_timesteps): + element = self.elements[i] + other_value = other.get_energy_for_timestep(i) + + if ( + element.min_joule is not None + and other_value is not None + and other_value < element.min_joule + ): + return False + + if ( + element.max_joule is not None + and other_value is not None + and other_value > element.max_joule + ): + return False + + return True + + def difference_with_max_value(self, other: JouleProfile) -> JouleProfile: + """ + Calculate the difference between this profile's max values and the other profile. + + Args: + other: JouleProfile to compare against + + Returns: + JouleProfile containing the differences + """ + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + + return_values: List[Optional[int]] = [] + + for i in range(self.metadata.nr_of_timesteps): + other_energy = other.get_energy_for_timestep(i) + element_max_joule = self.elements[i].max_joule + if element_max_joule is None or other_energy is None: + return_values.append(None) + else: + return_values.append(element_max_joule - other_energy) + + return JouleProfile(metadata=self.metadata, elements=return_values) + + def difference_with_min_value(self, other: JouleProfile) -> JouleProfile: + """ + Calculate the difference between this profile's min values and the other profile. + + Args: + other: JouleProfile to compare against + + Returns: + JouleProfile containing the differences + """ + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + + return_values: List[Optional[int]] = [] + + for i in range(self.metadata.nr_of_timesteps): + element_min_joule = self.elements[i].min_joule + other_energy = other.get_energy_for_timestep(i) + if element_min_joule is None or other_energy is None: + return_values.append(None) + else: + return_values.append(element_min_joule - other_energy) + + return JouleProfile(metadata=self.metadata, elements=return_values) + + def subprofile(self, new_start_date: datetime) -> "JouleRangeProfile": + """ + Create a subprofile starting from the given date. + + Args: + new_start_date: Start date for the new profile + + Returns: + New JouleRangeProfile starting from the given date + """ + index = self.index_at(new_start_date) + if index < 0: + raise ValueError("New start date is outside profile range") + + new_elements = self.elements[index:] + return JouleRangeProfile( + new_start_date, self.metadata.timestep_duration, new_elements + ) + + def adjust_nr_of_elements(self, nr_of_elements: int) -> "JouleRangeProfile": + """ + Adjust the number of elements in this profile. + + Args: + nr_of_elements: New number of elements + + Returns: + New JouleRangeProfile with adjusted number of elements + """ + if nr_of_elements < len(self.elements): + new_elements = self.elements[:nr_of_elements] + else: + # Ignore type error because Element.NULL is not None + new_elements = self.elements + [Element.NULL] * ( # type: ignore[list-item] + nr_of_elements - len(self.elements) + ) + + return JouleRangeProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + new_elements, + ) + + def is_compatible(self, other: AbstractProfile) -> bool: + """ + Check if this profile is compatible with another profile. + + Args: + other: Another profile to check compatibility with + + Returns: + True if compatible, False otherwise + + """ + return self.metadata == other.metadata + + def __str__(self) -> str: + """Return a string representation of this profile.""" + return ( + f"JouleRangeProfile(elements={self.elements}, " + f"profile_start={self.metadata.profile_start}, " + f"timestep_duration={self.metadata.timestep_duration})" + ) diff --git a/flexmeasures_s2/profile_steering/common/power_range_wrapper.py b/flexmeasures_s2/profile_steering/common/power_range_wrapper.py new file mode 100644 index 0000000..97b7cfe --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/power_range_wrapper.py @@ -0,0 +1,46 @@ +import math +from typing import Any + + +class PowerRangeWrapper: + def __init__(self, unwrapped_range: Any): + self.start_of_range: float = float(unwrapped_range.start_of_range) + self.end_of_range: float = float(unwrapped_range.end_of_range) + self.commodity_quantity: Any = unwrapped_range.commodity_quantity + + def get_start_of_range(self) -> float: + return self.start_of_range + + def get_end_of_range(self) -> float: + return self.end_of_range + + def get_commodity_quantity(self) -> Any: + return self.commodity_quantity + + def get_power(self, factor: float) -> float: + return ( + (self.end_of_range - self.start_of_range) * factor + ) + self.start_of_range + + def __eq__(self, o: object) -> bool: + if self is o: + return True + if not isinstance(o, PowerRangeWrapper): + return False + that = o + return ( + math.isclose(that.start_of_range, self.start_of_range) + and math.isclose(that.end_of_range, self.end_of_range) + and self.commodity_quantity == that.commodity_quantity + ) + + def __hash__(self) -> int: + return hash((self.start_of_range, self.end_of_range, self.commodity_quantity)) + + def __str__(self) -> str: + return ( + f"PowerRangeWrapper(" + f"startOfRange={self.start_of_range}, " + f"endOfRange={self.end_of_range}, " + f"commodityQuantity={self.commodity_quantity})" + ) diff --git a/flexmeasures_s2/profile_steering/common/profile_metadata.py b/flexmeasures_s2/profile_steering/common/profile_metadata.py new file mode 100644 index 0000000..f0e7d54 --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/profile_metadata.py @@ -0,0 +1,106 @@ +from datetime import datetime, timedelta + + +class ProfileMetadata: + NR_OF_TIMESTEPS_KEY = "nrOfTimesteps" + TIMESTEP_DURATION_KEY = "timestepDurationMs" + PROFILE_START_KEY = "profileStart" + + def __init__( + self, + profile_start: datetime, + timestep_duration: timedelta, + nr_of_timesteps: int, + ): + self.profile_start = profile_start + self.timestep_duration = timestep_duration + self.nr_of_timesteps = nr_of_timesteps + self.profile_end = profile_start + timestep_duration * nr_of_timesteps + self.profile_duration = self.profile_end - self.profile_start + + def get_profile_start_at_timestep(self, i: int) -> datetime: + if i >= self.nr_of_timesteps or i < 0: + raise ValueError( + f"Expected i to be between 0 <= i < {self.nr_of_timesteps} but was {i}" + ) + return self.profile_start + self.timestep_duration * i + + def get_starting_step_nr(self, instant: datetime) -> int: + if instant < self.profile_start: + return -1 + elif instant >= self.profile_end: + return self.nr_of_timesteps + else: + duration_between_secs = (instant - self.profile_start).total_seconds() + timestep_duration_secs = self.timestep_duration.total_seconds() + return int(duration_between_secs // timestep_duration_secs) + + def is_aligned_with(self, other: "ProfileMetadata") -> bool: + return ( + self.timestep_duration == other.timestep_duration + and ( + abs((self.profile_start - other.profile_start).total_seconds()) + % self.timestep_duration.total_seconds() + ) + == 0 + ) + + def to_dict(self) -> dict: + return { + self.PROFILE_START_KEY: int(self.profile_start.timestamp() * 1000), + self.TIMESTEP_DURATION_KEY: int( + self.timestep_duration.total_seconds() * 1000 + ), + self.NR_OF_TIMESTEPS_KEY: self.nr_of_timesteps, + } + + @staticmethod + def from_dict(data: dict) -> "ProfileMetadata": + profile_start = datetime.fromtimestamp( + data[ProfileMetadata.PROFILE_START_KEY] / 1000 + ) + timestep_duration = timedelta( + milliseconds=data[ProfileMetadata.TIMESTEP_DURATION_KEY] + ) + nr_of_timesteps = data[ProfileMetadata.NR_OF_TIMESTEPS_KEY] + return ProfileMetadata(profile_start, timestep_duration, nr_of_timesteps) + + def subprofile(self, new_start_date: datetime) -> "ProfileMetadata": + if new_start_date < self.profile_start: + raise ValueError( + "The new start date should be after the current start date" + ) + new_start_date = self.next_aligned_date(new_start_date, self.timestep_duration) + skipped_steps = int( + (new_start_date - self.profile_start).total_seconds() + // self.timestep_duration.total_seconds() + ) + nr_of_elements = max(0, self.nr_of_timesteps - skipped_steps) + return ProfileMetadata(new_start_date, self.timestep_duration, nr_of_elements) + + def adjust_nr_of_elements(self, nr_of_elements: int) -> "ProfileMetadata": + return ProfileMetadata( + self.profile_start, self.timestep_duration, nr_of_elements + ) + + @staticmethod + def next_aligned_date(date: datetime, timestep_duration: timedelta) -> datetime: + # Align the date to the next timestep + remainder = ( + date - datetime.min + ).total_seconds() % timestep_duration.total_seconds() + if remainder == 0: + return date + return date + timedelta(seconds=(timestep_duration.total_seconds() - remainder)) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ProfileMetadata): + return False + return ( + self.nr_of_timesteps == other.nr_of_timesteps + and self.profile_start == other.profile_start + and self.timestep_duration == other.timestep_duration + ) + + def __hash__(self) -> int: + return hash((self.nr_of_timesteps, self.profile_start, self.timestep_duration)) diff --git a/flexmeasures_s2/profile_steering/common/proposal.py b/flexmeasures_s2/profile_steering/common/proposal.py new file mode 100644 index 0000000..066d20c --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/proposal.py @@ -0,0 +1,130 @@ +from typing import Optional +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from flexmeasures_s2.profile_steering.device_planner.device_planner_abstract import ( + DevicePlanner, +) + + +class Proposal: + def __init__( + self, + global_diff_target: TargetProfile, + diff_to_congestion_max: JouleProfile, + diff_to_congestion_min: JouleProfile, + proposed_plan: JouleProfile, + old_plan: JouleProfile, + origin: DevicePlanner, + ): + self.global_diff_target = global_diff_target + self.diff_to_congestion_max = diff_to_congestion_max + self.diff_to_congestion_min = diff_to_congestion_min + self.proposed_plan = proposed_plan + self.old_plan = old_plan + self.global_improvement_value: Optional[float] = None + self.congestion_improvement_value: Optional[float] = None + self.cost_improvement_value: Optional[float] = None + self.origin = origin + + def get_global_improvement_value(self) -> float: + if self.global_improvement_value is None: + # print(f"self.old_plan: {self.old_plan}") + # print(f"self.proposed_plan: {self.proposed_plan}") + # print the quadratic distance of the global diff target + # print(f"self.global_diff_target.sum_quadratic_distance(): {self.global_diff_target.sum_quadratic_distance()}") + self.global_improvement_value = ( + self.global_diff_target.sum_quadratic_distance() + - self.global_diff_target.add(self.old_plan) + .subtract(self.proposed_plan) + .sum_quadratic_distance() + ) + return self.global_improvement_value + + def get_cost_improvement_value(self) -> float: + if self.cost_improvement_value is None: + self.cost_improvement_value = self.get_cost( + self.old_plan, self.global_diff_target + ) - self.get_cost(self.proposed_plan, self.global_diff_target) + return self.cost_improvement_value + + @staticmethod + def get_cost(plan: JouleProfile, target_profile: TargetProfile) -> float: + cost = 0.0 + tariff_count = 0 + null_count = 0 + for i in range(target_profile.metadata.nr_of_timesteps): + joule_usage = plan.elements[i] + target_element = target_profile.elements[i] + if isinstance(target_element, TargetProfile.TariffElement): + tariff_count += 1 + if joule_usage is not None: + cost += (joule_usage / 3_600_000) * target_element.get_tariff() + elif isinstance(target_element, TargetProfile.NullElement): + null_count += 1 + if tariff_count == 0 and null_count > 0: + # print( + # f" WARNING: get_cost called with {null_count} NullElements, {tariff_count} TariffElements - cost will be 0!" + # ) + pass + return cost + + def get_congestion_improvement_value(self) -> float: + if self.congestion_improvement_value is None: + zero_profile = JouleProfile( + self.old_plan.metadata.profile_start, + self.old_plan.metadata.timestep_duration, + [0] * len(self.old_plan.elements), + ) + exceed_max_target_old = self.diff_to_congestion_max.minimum( + zero_profile + ).sum_quadratic_distance() + # print(f"exceed_max_target_old: {exceed_max_target_old}") + # print(f"self.diff_to_congestion_max: {self.diff_to_congestion_max}") + exceed_max_target_proposal = ( + self.diff_to_congestion_max.add(self.old_plan) + .subtract(self.proposed_plan) + .minimum(zero_profile) + .sum_quadratic_distance() + ) + # print(f"exceed_max_target_proposal: {exceed_max_target_proposal}") + exceed_min_target_old = self.diff_to_congestion_min.maximum( + zero_profile + ).sum_quadratic_distance() + # print(f"exceed_min_target_old: {exceed_min_target_old}") + exceed_min_target_proposal = ( + self.diff_to_congestion_min.add(self.old_plan) + .subtract(self.proposed_plan) + .maximum(zero_profile) + .sum_quadratic_distance() + ) + # print(f"exceed_min_target_proposal: {exceed_min_target_proposal}") + if ( + exceed_max_target_old == exceed_max_target_proposal + and exceed_min_target_old == exceed_min_target_proposal + ): + self.congestion_improvement_value = 0.0 + else: + self.congestion_improvement_value = ( + exceed_max_target_old + + exceed_min_target_old + - exceed_max_target_proposal + - exceed_min_target_proposal + ) + # print(f"congestion_improvement_value: {self.congestion_improvement_value}") + return self.congestion_improvement_value + + def is_preferred_to(self, other: "Proposal") -> bool: + if self.get_congestion_improvement_value() >= 0: + if ( + self.get_global_improvement_value() + > other.get_global_improvement_value() + ): + return True + elif ( + self.get_global_improvement_value() + == other.get_global_improvement_value() + and self.get_cost_improvement_value() + > other.get_cost_improvement_value() + ): + return True + return False diff --git a/flexmeasures_s2/profile_steering/common/pydantic_base.py b/flexmeasures_s2/profile_steering/common/pydantic_base.py new file mode 100644 index 0000000..2d083f5 --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/pydantic_base.py @@ -0,0 +1,8 @@ +from pydantic import BaseModel + + +class FlexMeasuresBaseModel(BaseModel): + """Base model for FlexMeasures S2 with arbitrary types allowed.""" + + class Config: + arbitrary_types_allowed = True diff --git a/flexmeasures_s2/profile_steering/common/s2_actuator_configuration.py b/flexmeasures_s2/profile_steering/common/s2_actuator_configuration.py new file mode 100644 index 0000000..b70b0c9 --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/s2_actuator_configuration.py @@ -0,0 +1,20 @@ +class S2ActuatorConfiguration: + def __init__(self, operation_mode_id, factor): + self.operation_mode_id = operation_mode_id + self.factor = factor + + def get_operation_mode_id(self): + return self.operation_mode_id + + def get_factor(self): + return self.factor + + def to_dict(self): + return {"operationModeId": self.operation_mode_id, "factor": self.factor} + + @staticmethod + def from_dict(data): + return S2ActuatorConfiguration(data["operationModeId"], data["factor"]) + + def __str__(self): + return f"S2ActuatorConfiguration [operationModeId={self.operation_mode_id}, factor={self.factor}]" diff --git a/flexmeasures_s2/profile_steering/common/soc_profile.py b/flexmeasures_s2/profile_steering/common/soc_profile.py new file mode 100644 index 0000000..e4b8fd2 --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/soc_profile.py @@ -0,0 +1,50 @@ +from typing import List, Optional +from flexmeasures_s2.profile_steering.common.abstract_profile import AbstractProfile +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from datetime import datetime + + +class SoCProfile(AbstractProfile[float, "SoCProfile"]): + def __init__( + self, profile_metadata: ProfileMetadata, elements: Optional[List[float]] = None + ): + self.profile_metadata = profile_metadata + self.timestep_duration = self.profile_metadata.timestep_duration + self.profile_start = self.profile_metadata.profile_start + self.profile_end = self.profile_metadata.profile_end + super().__init__( + self.profile_metadata, elements if elements is not None else [] + ) + + # mypy complains that the return is None + def default_value(self) -> None: # type: ignore + return None + + def __str__(self) -> str: + return f"SoCProfile(elements={self.elements}, profile_start={self.profile_start}, timestep_duration={self.timestep_duration})" + + def is_compatible(self, other: AbstractProfile) -> bool: + return ( + self.metadata.timestep_duration == other.metadata.timestep_duration + and len(self.elements) == len(other.elements) + ) + + def validate(self, profile_metadata: ProfileMetadata, elements: List[float]): + super().validate(profile_metadata, elements) + + def subprofile(self, new_start_date: datetime) -> "SoCProfile": + index = self.index_at(new_start_date) + if index < 0: + raise ValueError("New start date is outside profile range") + new_elements = self.elements[index:] + return SoCProfile(self.metadata, new_elements) + + def adjust_nr_of_elements(self, nr_of_elements: int) -> "SoCProfile": + if nr_of_elements < len(self.elements): + new_elements = self.elements[:nr_of_elements] + else: + new_elements = self.elements + [0.0] * (nr_of_elements - len(self.elements)) + return SoCProfile( + self.metadata, + new_elements, + ) diff --git a/flexmeasures_s2/profile_steering/common/target_profile.py b/flexmeasures_s2/profile_steering/common/target_profile.py new file mode 100644 index 0000000..6b4f6ec --- /dev/null +++ b/flexmeasures_s2/profile_steering/common/target_profile.py @@ -0,0 +1,205 @@ +from typing import List, Union, Optional +from datetime import datetime, timedelta +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.abstract_profile import AbstractProfile +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata + + +class TargetProfile( + AbstractProfile[Union["TargetProfile.Element", None], "TargetProfile"] +): + class Element: + pass + + class JouleElement(Element): + def __init__(self, joules: int): + self.joules = joules + + class TariffElement(Element): + def __init__(self, tariff: float): + self.tariff = tariff + + def get_tariff(self) -> float: + return self.tariff + + class NullElement(Element): + pass + + NULL_ELEMENT: "TargetProfile.Element" = NullElement() + + def __init__( + self, + profile_start: datetime, + timestep_duration: timedelta, + elements: List["TargetProfile.Element | None"], + ): + metadata = ProfileMetadata(profile_start, timestep_duration, len(elements)) + super().__init__(metadata, elements) + # if elements is a list of ints, convert it to a list of JouleElement + if isinstance(elements, list) and all(isinstance(e, int) for e in elements): + # Ignore type error because e is int + self.elements = [TargetProfile.JouleElement(e) for e in elements] # type: ignore[arg-type] + else: + self.elements = elements + + def validate( + self, + profile_metadata: ProfileMetadata, + elements: List["TargetProfile.Element | None"], + ): + super().validate(profile_metadata, elements) + # Add any TargetProfile-specific validation if needed + + def get_energy_for_timestep(self, index: int) -> Optional[int]: + if 0 <= index < len(self.elements) and isinstance( + self.elements[index], TargetProfile.JouleElement + ): + return self.elements[index].joules # type: ignore + return None + + def default_value(self) -> "TargetProfile.Element": + return TargetProfile.NULL_ELEMENT + + def subprofile(self, new_start_date: datetime) -> "TargetProfile": + index = self.index_at(new_start_date) + if index < 0: + raise ValueError("New start date is outside profile range") + new_elements = self.elements[index:] + return TargetProfile( + new_start_date, self.metadata.timestep_duration, new_elements + ) + + def adjust_nr_of_elements(self, nr_of_elements: int) -> "TargetProfile": + if nr_of_elements < len(self.elements): + new_elements = self.elements[:nr_of_elements] + else: + new_elements = self.elements + [self.NULL_ELEMENT] * ( + nr_of_elements - len(self.elements) + ) + return TargetProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + new_elements, + ) + + def is_compatible(self, other: AbstractProfile) -> bool: + return ( + self.metadata.timestep_duration == other.metadata.timestep_duration + and len(self.elements) == len(other.elements) + ) + + def get_total_energy(self) -> int: + return sum( + e.joules for e in self.elements if isinstance(e, TargetProfile.JouleElement) + ) + + def target_elements_to_joule_profile(self) -> JouleProfile: + joules = [ + e.joules for e in self.elements if isinstance(e, TargetProfile.JouleElement) + ] + # Ignore type error because joules is a list of ints + return JouleProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + joules, # type: ignore[arg-type] + ) + + def nr_of_joule_target_elements(self) -> int: + return len( + [e for e in self.elements if isinstance(e, TargetProfile.JouleElement)] + ) + + def subtract(self, other: JouleProfile) -> "TargetProfile": + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + diff_elements: List["TargetProfile.Element | None"] = [] + for i, element in enumerate(self.elements): + if isinstance(element, TargetProfile.JouleElement): + other_energy = other.get_energy_for_timestep(i) + if other_energy is not None: + diff_elements.append( + TargetProfile.JouleElement(element.joules - other_energy) + ) + else: + diff_elements.append(self.NULL_ELEMENT) + else: + diff_elements.append(self.NULL_ELEMENT) + return TargetProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + diff_elements, + ) + + def add(self, other: JouleProfile) -> "TargetProfile": + if not self.is_compatible(other): + raise ValueError("Profiles are not compatible") + sum_elements: List["TargetProfile.Element | None"] = [] + for i, element in enumerate(self.elements): + if isinstance(element, TargetProfile.JouleElement): + other_energy = other.get_energy_for_timestep(i) + if other_energy is not None: + sum_elements.append( + TargetProfile.JouleElement(element.joules + other_energy) + ) + else: + sum_elements.append(self.NULL_ELEMENT) + else: + sum_elements.append(self.NULL_ELEMENT) + return TargetProfile( + self.metadata.profile_start, + self.metadata.timestep_duration, + sum_elements, + ) + + def sum_quadratic_distance(self) -> float: + return sum( + e.joules**2 + for e in self.elements + if isinstance(e, TargetProfile.JouleElement) + ) + + def __str__(self) -> str: + return f"TargetProfile(elements={self.elements}, profile_start={self.metadata.profile_start}, timestep_duration={self.metadata.timestep_duration})" + + @staticmethod + def null_profile(metadata: ProfileMetadata) -> "TargetProfile": + return TargetProfile( + metadata.profile_start, + metadata.timestep_duration, + [TargetProfile.NULL_ELEMENT] * metadata.nr_of_timesteps, + ) + + @staticmethod + def from_joule_profile(joule_profile: JouleProfile) -> "TargetProfile": + return TargetProfile( + joule_profile.metadata.profile_start, + joule_profile.metadata.timestep_duration, + [TargetProfile.JouleElement(e) for e in joule_profile.elements], + ) + + @staticmethod + def from_tariff_values( + metadata: ProfileMetadata, tariff_values: List[float] + ) -> "TargetProfile": + """Create a TargetProfile with TariffElement instances from tariff values. + + Args: + metadata: ProfileMetadata for the target profile + tariff_values: List of tariff values (cost per kWh) + + Returns: + TargetProfile with TariffElement instances + """ + if len(tariff_values) != metadata.nr_of_timesteps: + raise ValueError( + f"Number of tariff values ({len(tariff_values)}) must match nr_of_timesteps ({metadata.nr_of_timesteps})" + ) + + elements: List[Union["TargetProfile.Element", None]] = [ + TargetProfile.TariffElement(tariff) for tariff in tariff_values + ] + return TargetProfile( + metadata.profile_start, + metadata.timestep_duration, + elements, + ) diff --git a/flexmeasures_s2/profile_steering/common_data_structures.py b/flexmeasures_s2/profile_steering/common_data_structures.py new file mode 100644 index 0000000..b6e9a53 --- /dev/null +++ b/flexmeasures_s2/profile_steering/common_data_structures.py @@ -0,0 +1,33 @@ +from datetime import datetime +from typing import List, Dict, Any, Optional + + +class ClusterState: + """Class representing the state of a cluster of devices.""" + + def __init__( + self, + timestamp: datetime, + device_states: Dict[str, Any] = {}, + congestion_points_by_connection_id: Dict[str, str] = {}, + ): + self._timestamp = timestamp + self._device_states = device_states or {} + self._congestion_points_by_connection_id = ( + congestion_points_by_connection_id or {} + ) + + def set_device_states(self, device_states: Dict[str, Any]): + self._device_states = device_states or {} + + def get_device_states(self) -> Dict[str, Any]: + return self._device_states + + def get_congestion_point(self, connection_id: str) -> Optional[str]: + return self._congestion_points_by_connection_id.get(connection_id) + + def set_congestion_point(self, connection_id: str, congestion_point_id: str): + self._congestion_points_by_connection_id[connection_id] = congestion_point_id + + def get_congestion_points(self) -> List[str]: + return list(set(self._congestion_points_by_connection_id.values())) diff --git a/flexmeasures_s2/profile_steering/congestion_point_planner.py b/flexmeasures_s2/profile_steering/congestion_point_planner.py new file mode 100644 index 0000000..e64449d --- /dev/null +++ b/flexmeasures_s2/profile_steering/congestion_point_planner.py @@ -0,0 +1,340 @@ +from datetime import datetime +from typing import Any, Optional, List +import concurrent.futures +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.joule_range_profile import ( + JouleRangeProfile, +) +from flexmeasures_s2.profile_steering.common.proposal import Proposal +from flexmeasures_s2.profile_steering.device_planner.device_planner_abstract import ( + DevicePlanner, +) +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile + + +def _get_device_proposal( + device: DevicePlanner, + difference_profile: TargetProfile, + diff_to_max_value: JouleProfile, + diff_to_min_value: JouleProfile, + plan_due_by_date: datetime, +) -> Optional[Proposal]: + """Helper function to be called by the process pool executor for pickling.""" + try: + return device.create_improved_planning( + difference_profile, + diff_to_max_value, + diff_to_min_value, + plan_due_by_date, + ) + except Exception: + # print(f"Error getting proposal from device {device.device_id} in worker: {e}") + return None + + +def _get_initial_device_plan( + device: DevicePlanner, plan_due_by_date: datetime +) -> tuple[str, Any]: + """Helper function to be called by the process pool executor for initial planning.""" + try: + plan = device.create_initial_planning(plan_due_by_date) + return (device.device_id, plan) + except Exception as e: + print( + f"Error getting initial plan from device {device.device_id} in worker: {e}" + ) + print(f"Exception type: {type(e).__name__}") + import traceback + + print("Full traceback:") + traceback.print_exc() + return (device.device_id, None) + + +class CongestionPointPlanner: + def __init__( + self, + congestion_point_id: str, + congestion_target: JouleRangeProfile, + multithreaded: bool = False, + ): + """Initialize a congestion point planner. + + Args: + + congestion_point_id: Unique identifier for this congestion point + congestion_target: Target profile with range constraints for this congestion point + multithreaded: Whether to use multiprocessing for device planning + """ + self.MAX_ITERATIONS = 1000 + self.congestion_point_id = congestion_point_id + self.congestion_target = congestion_target + self.profile_metadata = congestion_target.metadata + self.multithreaded = multithreaded + + # Create an empty profile (using all zeros) + self.empty_profile = JouleProfile( + profile_start=self.profile_metadata.profile_start, + timestep_duration=self.profile_metadata.timestep_duration, + elements=[0] * self.profile_metadata.nr_of_timesteps, # type: ignore[list-item] + ) + + # List of device controllers that can be used for planning + self.devices: List[DevicePlanner] = [] + + # Keep track of accepted and latest plans + self.accepted_plan = self.empty_profile + self.latest_plan = self.empty_profile + + def add_device(self, device): + """Add a device controller to this congestion point.""" + self.devices.append(device) + + @staticmethod + def is_storage_available(self) -> bool: + """Check if storage is available at this congestion point.""" + # For now, always assume storage is available + return True + + def create_initial_planning( + self, plan_due_by_date: datetime + ) -> JouleProfile: # noqa: C901 + """Create an initial plan for this congestion point. + + Args: + plan_due_by_date: The date by which the plan must be ready + + Returns: + A JouleProfile representing the initial plan + """ + current_planning = self.empty_profile + + # Aggregate initial plans from all devices (parallel or sequential based on multithreaded setting) + device_plans: dict[str, Any] = {} + if self.multithreaded: + # Use multiprocessing for parallel execution + with concurrent.futures.ProcessPoolExecutor() as executor: + futures = { + executor.submit(_get_initial_device_plan, device, plan_due_by_date) + for device in self.devices + } + for future in concurrent.futures.as_completed(futures): + device_id, plan = future.result() + if plan is not None: + device_plans[device_id] = plan + else: + # Use sequential execution to avoid pickling issues + for device in self.devices: + device_id, plan = _get_initial_device_plan(device, plan_due_by_date) + if plan is not None: + device_plans[device_id] = plan + + # Update the state of the original device objects and aggregate energy profiles + for device in self.devices: + if device.device_id in device_plans: + plan = device_plans[device.device_id] + device.set_accepted_plan(plan) + current_planning = current_planning.add(plan.energy) + + # Check if the current planning is within the congestion target range + if self.congestion_target.is_within_range(current_planning): + # print( + # "Current planning is within the congestion target range. Returning it." + # ) + return current_planning + + # If the current planning is not within the congestion target range, optimize it + # print( + # "Current planning is not within the congestion target range. Optimizing it." + # ) + + # print(f"Congestion target: {self.congestion_target}") + # This is an old implementation that does not use the root planner + # It is kept here for reference + i = 0 + best_proposal = None + + max_priority_class = self.max_priority_class() + min_priority_class = self.min_priority_class() + + # Iterate over priority classes + for priority_class in range(min_priority_class, max_priority_class + 1): + # print(f"Optimizing priority class: {priority_class}") + pass + while True: + best_proposal = None + diff_to_max = self.congestion_target.difference_with_max_value( + current_planning + ) + diff_to_min = self.congestion_target.difference_with_min_value( + current_planning + ) + + # Try to get improved plans from each device controller + for device in self.devices: + if device.priority_class <= priority_class: + try: + proposal = device.create_improved_planning( + self.empty_profile, # type: ignore[arg-type] + diff_to_max, + diff_to_min, + plan_due_by_date, + ) + if proposal is None: + raise ValueError( + f"No proposal found for device {device.device_id}" + ) + # print( + # f"congestion point improvement for '{device.device_id}': {proposal.get_congestion_improvement_value()}" + # ) + if ( + best_proposal is None + or proposal.get_congestion_improvement_value() + > best_proposal.get_congestion_improvement_value() + ): + best_proposal = proposal + except Exception: + # print( + # f"Error getting proposal from device {device.device_id}: {e}" + # ) + continue + + if ( + best_proposal is None + or best_proposal.get_congestion_improvement_value() <= 0 + ): + break + + # Update the current planning based on the best proposal + current_planning = current_planning.subtract( + best_proposal.old_plan + ).add(best_proposal.proposed_plan) + best_proposal.origin.accept_proposal(best_proposal) + i += 1 + + # print( + # f"Initial planning '{self.congestion_point_id}': best controller '{best_proposal.origin.device_id}' with congestion improvement of {best_proposal.get_congestion_improvement_value()}. Iteration {i}." + # ) + + if i >= self.MAX_ITERATIONS: + break + + return current_planning + + def create_improved_planning( + self, + difference_profile: TargetProfile, + priority_class: int, + plan_due_by_date: datetime, + ) -> Optional[Proposal]: + """Create an improved plan based on the difference profile. + + Args: + difference_profile: The difference between target and current planning + priority_class: Priority class for this planning iteration + plan_due_by_date: The date by which the plan must be ready + + Returns: + A Proposal object if an improvement was found, None otherwise + """ + best_proposal = None + + current_planning = self.get_current_planning() + + diff_to_max_value = self.congestion_target.difference_with_max_value( + current_planning + ) + diff_to_min_value = self.congestion_target.difference_with_min_value( + current_planning + ) + # print(f"diff_to_max_value: {diff_to_max_value}") + # print(f"diff_to_min_value: {diff_to_min_value}") + # Try to get improved plans from each device controller + devices_to_plan = [ + d for d in self.devices if d.priority_class <= priority_class + ] + + proposals = [] + if devices_to_plan: + if self.multithreaded: + # Use multiprocessing for parallel execution + with concurrent.futures.ProcessPoolExecutor() as executor: + futures = { + executor.submit( + _get_device_proposal, + device, + difference_profile, + diff_to_max_value, + diff_to_min_value, + plan_due_by_date, + ) + for device in devices_to_plan + } + for future in concurrent.futures.as_completed(futures): + proposal = future.result() + if proposal: + proposals.append(proposal) + else: + # Use sequential execution to avoid pickling issues + for device in devices_to_plan: + proposal = _get_device_proposal( + device, + difference_profile, + diff_to_max_value, + diff_to_min_value, + plan_due_by_date, + ) + if proposal: + proposals.append(proposal) + + for proposal in proposals: + if proposal.get_congestion_improvement_value() < 0: + # print( + # f"{proposal.origin.device_name}, congestion improvement: {proposal.get_congestion_improvement_value()}" + # ) + pass + + if best_proposal is None or proposal.is_preferred_to(best_proposal): + best_proposal = proposal + + if best_proposal is None: + # print( + # f"CP '{self.congestion_point_id}': No proposal available at current priority level ({priority_class})" + # ) + pass + else: + if best_proposal.get_congestion_improvement_value() == float("-inf"): + raise ValueError( + "Invalid proposal with negative infinity improvement value" + ) + + # print( + # f"CP '{self.congestion_point_id}': Selected best controller '{best_proposal.origin.device_name}' with improvement of {best_proposal.get_global_improvement_value()}." + # ) + + return best_proposal + + def get_current_planning(self) -> JouleProfile: + """Get the current planning profile.""" + # Return the latest accepted plan as the current planning + current_planning = self.empty_profile + for device in self.devices: + # Ignore type error because current_profile is a JouleProfile but its considered a callable JouleProfile + current_planning = current_planning.add(device.current_profile()) # type: ignore[arg-type] + return current_planning + + def add_device_controller(self, device): + """Add a device controller to this congestion point.""" + self.devices.append(device) + + def max_priority_class(self) -> int: + """Get the maximum priority class among all devices.""" + if not self.devices: + return 1 + return max(device.priority_class for device in self.devices) + + def min_priority_class(self) -> int: + """Get the minimum priority class among all devices.""" + if not self.devices: + return 1 + return min(device.priority_class for device in self.devices) diff --git a/flexmeasures_s2/profile_steering/device_planner/__init__.py b/flexmeasures_s2/profile_steering/device_planner/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/__init__.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/__init__.py new file mode 100644 index 0000000..a214524 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/__init__.py @@ -0,0 +1 @@ +# DDBC (Demand-Driven Based Control) device planner package diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/avg_demand_forecast_util.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/avg_demand_forecast_util.py new file mode 100644 index 0000000..b36b3ef --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/avg_demand_forecast_util.py @@ -0,0 +1,127 @@ +from datetime import datetime, timedelta +from typing import List, Any, Optional + + +class AvgDemandForecastElement: + """Element representing average demand forecast for a time period.""" + + def __init__(self, start: datetime, end: datetime, avg_demand: float): + self.start = start + self.end = end + self.avg_demand = avg_demand + + def get_start(self) -> datetime: + return self.start + + def get_end(self) -> datetime: + return self.end + + def get_avg_demand(self) -> float: + return self.avg_demand + + def get_duration(self) -> timedelta: + return self.end - self.start + + def __str__(self) -> str: + return f"AvgDemandForecastElement(avgDemand={self.avg_demand}, start={self.start}, end={self.end})" + + +class AvgDemandForecastProfile: + """Profile of average demand forecast elements.""" + + def __init__(self, elements: List[AvgDemandForecastElement]): + self.elements = elements + + def get_elements(self) -> List[AvgDemandForecastElement]: + return self.elements + + def get_start(self) -> Optional[datetime]: + if not self.elements: + return None + return self.elements[0].get_start() + + def get_end(self) -> Optional[datetime]: + if not self.elements: + return None + return self.elements[-1].get_end() + + def sub_profile(self, start: datetime, end: datetime) -> "AvgDemandForecastProfile": + """Get a sub-profile between start and end times.""" + sub_elements = [] + + for element in self.elements: + element_start = max(element.get_start(), start) + element_end = min(element.get_end(), end) + + if element_start < element_end: + sub_elements.append( + AvgDemandForecastElement( + element_start, element_end, element.get_avg_demand() + ) + ) + + return AvgDemandForecastProfile(sub_elements) + + +class AvgDemandForecastUtil: + """Utility class for converting DDBC average demand forecasts.""" + + @staticmethod + def from_avg_demand_rate_forecast(demand_forecast: Any) -> AvgDemandForecastProfile: + """Convert a DDBC average demand rate forecast to a profile.""" + elements: List[AvgDemandForecastElement] = [] + + start = demand_forecast.start_time + + for element in demand_forecast.elements: + if isinstance(element.duration, (int, float)): + duration_seconds = element.duration + elif hasattr(element.duration, "root"): + duration_seconds = element.duration.root + else: + duration_seconds = int(element.duration) + end = start + timedelta(seconds=duration_seconds) + elements.append( + AvgDemandForecastElement( + start, end, float(element.demand_rate_expected) + ) + ) + start = end + timedelta(milliseconds=1) + + return AvgDemandForecastProfile(elements) + + @staticmethod + def get_avg_demand_forecast_for_timestep( + avg_demand_forecast: AvgDemandForecastProfile, + timestep_start: datetime, + timestep_end: datetime, + ) -> Optional[float]: + """Get weighted average demand forecast for a timestep.""" + if avg_demand_forecast is None: + return None + + timestep_end_adjusted = timestep_end - timedelta(milliseconds=1) + + sub_profile = avg_demand_forecast.sub_profile( + timestep_start, timestep_end_adjusted + ) + + if not sub_profile.get_elements(): + return None + + demand = 0.0 + for element in sub_profile.get_elements(): + duration_ms = element.get_duration().total_seconds() * 1000 + demand += element.get_avg_demand() * duration_ms + + start = sub_profile.get_start() + end = sub_profile.get_end() + if start is None or end is None: + return None + + total_duration_ms = (end - start).total_seconds() * 1000 + + if total_duration_ms == 0: + return None + + return demand / total_duration_ms diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_operation_mode_wrapper.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_operation_mode_wrapper.py new file mode 100644 index 0000000..3ca24b7 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_operation_mode_wrapper.py @@ -0,0 +1,148 @@ +from typing import List, Any, Dict, Optional +from flexmeasures_s2.profile_steering.common.power_range_wrapper import ( + PowerRangeWrapper, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.number_range_wrapper import ( + NumberRangeWrapper, +) +from s2python.common import CommodityQuantity + + +class DdbcOperationModeWrapper: + """Wrapper for DDBC operation mode to provide utility methods.""" + + EPSILON = 1e-4 + + def __init__(self, ddbc_operation_mode: Any): + """Initialize from a DDBC operation mode.""" + self.id = ( + ddbc_operation_mode.Id + if hasattr(ddbc_operation_mode, "Id") + else ddbc_operation_mode.id + ) + self.diagnostic_label = getattr(ddbc_operation_mode, "diagnostic_label", None) + self.abnormal_condition_only = getattr( + ddbc_operation_mode, "abnormal_condition_only", False + ) + + self.power_ranges: List[PowerRangeWrapper] = [] + for unwrapped_power_range in ddbc_operation_mode.power_ranges: + self.power_ranges.append(PowerRangeWrapper(unwrapped_power_range)) + + if isinstance(ddbc_operation_mode.supply_range, list): + self.supply_range = NumberRangeWrapper(ddbc_operation_mode.supply_range[0]) + else: + self.supply_range = NumberRangeWrapper(ddbc_operation_mode.supply_range) + + self.running_costs: Optional[NumberRangeWrapper] + if ( + hasattr(ddbc_operation_mode, "running_costs") + and ddbc_operation_mode.running_costs is not None + ): + self.running_costs = NumberRangeWrapper(ddbc_operation_mode.running_costs) + else: + self.running_costs = None + + # Determine if this operation mode uses a factor + uses_factor = False + + if ( + abs( + self.supply_range.get_start_of_range() + - self.supply_range.get_end_of_range() + ) + > self.EPSILON + ): + uses_factor = True + + for power_range in self.power_ranges: + if ( + abs(power_range.get_start_of_range() - power_range.get_end_of_range()) + > self.EPSILON + ): + uses_factor = True + + self.uses_factor = uses_factor + + def get_id(self) -> str: + # Handle UUID objects with root attribute + if hasattr(self.id, "root"): + return str(self.id.root) + else: + return str(self.id) + + def get_diagnostic_label(self) -> Optional[str]: + return self.diagnostic_label + + def get_power_ranges(self) -> List[PowerRangeWrapper]: + return self.power_ranges + + def get_supply_range(self) -> NumberRangeWrapper: + return self.supply_range + + def get_running_costs(self) -> Optional[NumberRangeWrapper]: + return self.running_costs + + def uses_factor_method(self) -> bool: + return self.uses_factor + + def get_operation_mode_electrical_power(self, factor: float) -> float: + """Calculate electrical power consumption for a given factor.""" + power_watt = 0.0 + + electric_commodities = [ + CommodityQuantity.ELECTRIC_POWER_L1, + CommodityQuantity.ELECTRIC_POWER_L2, + CommodityQuantity.ELECTRIC_POWER_L3, + CommodityQuantity.ELECTRIC_POWER_3_PHASE_SYMMETRIC, + ] + + for power_range in self.get_power_ranges(): + if power_range.get_commodity_quantity() in electric_commodities: + start = power_range.get_start_of_range() + end = power_range.get_end_of_range() + power_watt += (end - start) * factor + start + + return power_watt + + def get_operation_mode_gas_consumption(self, factor: float) -> float: + """Calculate natural gas consumption (liters per second) for a given factor.""" + liters_gas_per_second = 0.0 + + for power_range in self.get_power_ranges(): + if ( + power_range.get_commodity_quantity() + == CommodityQuantity.NATURAL_GAS_FLOW_RATE + ): + start = power_range.get_start_of_range() + end = power_range.get_end_of_range() + liters_gas_per_second += (end - start) * factor + start + + return liters_gas_per_second + + def get_operation_mode_supply_rate(self, factor: float) -> float: + """Calculate supply rate for a given factor.""" + start = self.get_supply_range().get_start_of_range() + end = self.get_supply_range().get_end_of_range() + return (end - start) * factor + start + + def convert_to_actuator_config(self, factor: float): + """Convert to S2DdbcActuatorConfiguration.""" + from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_actuator_configuration import ( + S2DdbcActuatorConfiguration, + ) + + power_per_commodity_quantity: Dict[str, float] = {} + + for power_range in self.power_ranges: + commodity_quantity_value = power_range.get_commodity_quantity().value + power_per_commodity_quantity[ + commodity_quantity_value + ] = power_range.get_power(factor) + + return S2DdbcActuatorConfiguration( + operation_mode_id=self.get_id(), + factor=factor, + supply_rate=self.get_operation_mode_supply_rate(factor), + power_per_commodity_quantity=power_per_commodity_quantity, + ) diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_planning_window.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_planning_window.py new file mode 100644 index 0000000..780d569 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_planning_window.py @@ -0,0 +1,222 @@ +from datetime import datetime +from typing import List, Optional, Callable, TypeVar, Any, Dict, TYPE_CHECKING, cast +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state import ( + S2DdbcDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state_wrapper import ( + S2DdbcDeviceStateWrapper, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.ddbc_timestep import ( + DdbcTimestep, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.ddbc_state import DdbcState +from flexmeasures_s2.profile_steering.device_planner.ddbc.avg_demand_forecast_util import ( + AvgDemandForecastUtil, + AvgDemandForecastProfile, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_insights_profile import ( + S2DdbcInsightsProfile, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_plan import S2DdbcPlan + +if TYPE_CHECKING: + pass + +T = TypeVar("T") + + +class DdbcPlanningWindow: + """Planning window for DDBC device planning.""" + + def __init__( + self, + device_state: S2DdbcDeviceState, + profile_metadata: ProfileMetadata, + plan_due_by_date: datetime, + ): + self.device_state = S2DdbcDeviceStateWrapper(device_state) + self.profile_metadata = profile_metadata + self.plan_due_by_date = plan_due_by_date + self.timestep_duration_seconds = int( + profile_metadata.timestep_duration.total_seconds() + ) + + self.timesteps: List[DdbcTimestep] = [] + self._generate_timesteps() + + def _generate_timesteps(self): + """Generate timesteps for the planning window.""" + timestep_start = self.profile_metadata.profile_start + + for i in range(self.profile_metadata.nr_of_timesteps): + timestep_end = timestep_start + self.profile_metadata.timestep_duration + + if i == 0 and timestep_start < self.plan_due_by_date < timestep_end: + timestep_start = self.plan_due_by_date + + current_system_description = self.get_latest_before( + timestep_start, + self.device_state.get_system_descriptions(), + lambda sd: sd.valid_from, + ) + + current_avg_demand_forecast_obj = self.get_latest_before( + timestep_start, + self.device_state.get_demand_forecasts(), + lambda df: df.start_time, + ) + + current_demand_profile: Optional[AvgDemandForecastProfile] = None + if current_avg_demand_forecast_obj is not None: + current_demand_profile = ( + AvgDemandForecastUtil.from_avg_demand_rate_forecast( + current_avg_demand_forecast_obj + ) + ) + + avg_demand_rate_forecast = self.get_avg_demand_forecast_for_timestep( + current_demand_profile, timestep_start, timestep_end + ) + + self.timesteps.append( + DdbcTimestep( + timestep_start, + timestep_end, + current_system_description, + avg_demand_rate_forecast, + ) + ) + + timestep_start = timestep_end + + @staticmethod + def get_latest_before( + before: datetime, select_from: List[T], get_datetime: Callable[[T], datetime] + ) -> Optional[T]: + """Get the latest item from a list that occurs before a given datetime.""" + latest_before: Optional[T] = None + latest_before_datetime: Optional[datetime] = None + + if select_from is not None: + for current in select_from: + if current is not None: + current_datetime = get_datetime(current) + + if current_datetime <= before: + if latest_before is None or ( + latest_before_datetime is not None + and current_datetime > latest_before_datetime + ): + latest_before = current + latest_before_datetime = current_datetime + + return latest_before + + @staticmethod + def get_avg_demand_forecast_for_timestep( + avg_demand_forecast: Optional[AvgDemandForecastProfile], + timestep_start: datetime, + timestep_end: datetime, + ) -> Optional[float]: + """Get the average demand forecast for a timestep.""" + if avg_demand_forecast is None: + return None + + return AvgDemandForecastUtil.get_avg_demand_forecast_for_timestep( + avg_demand_forecast, timestep_start, timestep_end + ) + + def find_best_plan( + self, + target_profile: TargetProfile, + diff_to_min_profile: JouleProfile, + diff_to_max_profile: JouleProfile, + ) -> "S2DdbcPlan": + """Find the best plan for the device.""" + for i in range(len(self.timesteps)): + ts = self.timesteps[i] + ts.clear() + target_element = target_profile.elements[i] + if target_element is not None: + ts.set_targets( + target_element, + diff_to_min_profile.elements[i], + diff_to_max_profile.elements[i], + ) + + first_timestep_index = -1 + for i in range(len(self.timesteps)): + if self.timesteps[i].get_system_description() is not None: + first_timestep_index = i + break + + if first_timestep_index == -1: + first_timestep_index = self.profile_metadata.nr_of_timesteps + else: + first_timestep = self.timesteps[first_timestep_index] + + state_zero = DdbcState(self.device_state, first_timestep) + state_zero.generate_next_timestep_states(first_timestep) + + for i in range(first_timestep_index, len(self.timesteps) - 1): + current_timestep = self.timesteps[i] + next_timestep = self.timesteps[i + 1] + + best_state = current_timestep.get_best_state() + if best_state is not None: + best_state.generate_next_timestep_states(next_timestep) + + return self._convert_to_plan(first_timestep_index) + + def _convert_to_plan(self, first_timestep_index_with_state: int) -> "S2DdbcPlan": + """Convert the planning window to a plan.""" + energy: List[int] = [] + actuators: List[Dict[str, Any]] = [] + insight_elements: List[Any] = [] + + for i in range(self.profile_metadata.nr_of_timesteps): + if i >= first_timestep_index_with_state: + timestep = self.timesteps[i] + state = timestep.get_best_state() + + if state is not None: + energy.append(int(state.get_timestep_energy())) + actuators.append(state.get_actuator_configurations()) + insight_elements.append( + S2DdbcInsightsProfile.Element( + timestep.get_avg_demand_rate_forecast(), + state.get_supply_rate(), + state.get_actuator_configurations(), + ) + ) + else: + energy.append(0) + actuators.append({}) + insight_elements.append(None) + else: + energy.append(0) + actuators.append({}) + insight_elements.append(None) + + energy[0] = energy[0] + int(self.device_state.get_energy_in_current_timestep()) + + energy_profile = JouleProfile( + self.profile_metadata.profile_start, + self.profile_metadata.timestep_duration, + cast(List[Optional[int]], energy), + ) + + return S2DdbcPlan( + idle=False, + energy=energy_profile, + operation_mode_id=actuators, + s2_ddbc_insights_profile=S2DdbcInsightsProfile( + self.profile_metadata, insight_elements + ), + ) + + def get_timestep_duration_seconds(self) -> int: + return self.timestep_duration_seconds diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_state.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_state.py new file mode 100644 index 0000000..7c6b72c --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_state.py @@ -0,0 +1,415 @@ +from datetime import datetime +from typing import Optional, Dict, TYPE_CHECKING +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_actuator_configuration import ( + S2DdbcActuatorConfiguration, +) + +if TYPE_CHECKING: + from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state_wrapper import ( + S2DdbcDeviceStateWrapper, + ) + from flexmeasures_s2.profile_steering.device_planner.ddbc.ddbc_timestep import ( + DdbcTimestep, + ) + + +class DdbcState: + """Represents a state in the DDBC planning algorithm.""" + + CONSTRAINT_EPSILON = 1e-4 + + def __init__( + self, + device_state_wrapper: "S2DdbcDeviceStateWrapper", + timestep: "DdbcTimestep", + previous_state: Optional["DdbcState"] = None, + actuator_configurations: Optional[ + Dict[str, S2DdbcActuatorConfiguration] + ] = None, + ): + """Initialize state. If previous_state is None, this is state zero.""" + self.device_state_wrapper = device_state_wrapper + self.timestep = timestep + self.previous_state = previous_state + + if previous_state is None: + self._init_state_zero() + else: + assert ( + actuator_configurations is not None + ), "actuator_configurations must not be None when previous_state is provided" + self._init_from_previous_state(actuator_configurations) + + def _init_state_zero(self): + """Initialize as state zero (initial state).""" + self.supply_rate = 0.0 + self.timestep_energy = 0.0 + self.sum_squared_distance = 0.0 + self.sum_squared_constraint_violation = 0.0 + self.sum_energy_cost = 0.0 + self.sum_natural_gas_cost = 0.0 + self.sum_squared_energy = 0.0 + + self.actuator_configurations: Dict[str, S2DdbcActuatorConfiguration] = {} + + actuator_statuses = self.device_state_wrapper.get_actuator_statuses() + + for actuator in self.timestep.get_system_description().actuators: + actuator_id_str = str(actuator.id) + actuator_status = actuator_statuses.get(actuator_id_str) + + if actuator_status is None: + continue + + # Convert active_operation_mode_id to string to handle UUID objects + active_om_id = actuator_status.active_operation_mode_id + if hasattr(active_om_id, "root"): + active_om_id_str = str(active_om_id.root) + else: + active_om_id_str = str(active_om_id) + + om = self.device_state_wrapper.get_operation_mode( + self.timestep, actuator_id_str, active_om_id_str + ) + + factor = float(actuator_status.operation_mode_factor) + actuator_config = om.convert_to_actuator_config(factor) + self.actuator_configurations[actuator_id_str] = actuator_config + + self.timer_elapse_map = ( + self._get_initial_timer_elapse_map_for_system_description( + self.timestep.get_system_description() + ) + ) + self.gas_price_per_liter = ( + self.device_state_wrapper.get_gas_price_per_m3() / 1000.0 + ) + + def _init_from_previous_state( + self, actuator_configurations: Dict[str, S2DdbcActuatorConfiguration] + ): + """Initialize from a previous state.""" + assert self.previous_state is not None, "previous_state must not be None" + self.gas_price_per_liter = self.previous_state.gas_price_per_liter + + self.actuator_configurations = self._calculate_missing_factor( + actuator_configurations, self.timestep.get_avg_demand_rate_forecast() + ) + + timestep_energy = 0.0 + timestep_natural_gas_liters = 0.0 + timestep_supply_rate = 0.0 + seconds = self.timestep.get_duration_seconds() + + for actuator_id, actuator_configuration in self.actuator_configurations.items(): + om = self.device_state_wrapper.get_operation_mode( + self.timestep, + actuator_id, + actuator_configuration.get_operation_mode_id(), + ) + timestep_supply_rate += om.get_operation_mode_supply_rate( + actuator_configuration.get_factor() + ) + timestep_energy += ( + om.get_operation_mode_electrical_power( + actuator_configuration.get_factor() + ) + * seconds + ) + timestep_natural_gas_liters += ( + om.get_operation_mode_gas_consumption( + actuator_configuration.get_factor() + ) + * seconds + ) + + self.timestep_energy = timestep_energy + self.supply_rate = timestep_supply_rate + + self._update_timer_elapse_map() + self._calculate_scores(timestep_natural_gas_liters) + + self.timestep.add_state(self) + + def _update_timer_elapse_map(self): + """Update timers based on transitions.""" + if ( + self.previous_state.get_system_description().valid_from + == self.get_system_description().valid_from + ): + self.timer_elapse_map = dict(self.previous_state.timer_elapse_map) + + for actuator_id, actuator_config in self.actuator_configurations.items(): + previous_operation_mode_id = ( + self.previous_state.actuator_configurations[ + actuator_id + ].get_operation_mode_id() + ) + new_operation_mode_id = actuator_config.get_operation_mode_id() + + if previous_operation_mode_id != new_operation_mode_id: + from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state_wrapper import ( + S2DdbcDeviceStateWrapper, + ) + + transition = S2DdbcDeviceStateWrapper.get_transition( + self.timestep, + actuator_id, + previous_operation_mode_id, + new_operation_mode_id, + ) + + for timer_id in transition.start_timers: + duration = S2DdbcDeviceStateWrapper.get_timer_duration( + self.timestep, actuator_id, timer_id + ) + new_finished_at = self.timestep.get_start_date() + duration + self.timer_elapse_map[ + self._timer_key(actuator_id, timer_id) + ] = new_finished_at + else: + self.timer_elapse_map = ( + self._get_initial_timer_elapse_map_for_system_description( + self.get_system_description() + ) + ) + + def _calculate_scores(self, timestep_natural_gas_liters: float): + """Calculate scoring metrics for this state.""" + assert self.previous_state is not None, "previous_state must not be None" + target = self.timestep.get_target() + + if isinstance(target, TargetProfile.JouleElement): + self.sum_squared_distance = ( + self.previous_state.sum_squared_distance + + (target.joules - self.timestep_energy) ** 2 + ) + self.sum_energy_cost = self.previous_state.sum_energy_cost + elif isinstance(target, TargetProfile.TariffElement): + self.sum_squared_distance = self.previous_state.sum_squared_distance + self.sum_energy_cost = ( + self.previous_state.sum_energy_cost + + target.tariff * (self.timestep_energy / 3_600_000.0) + ) + else: + self.sum_squared_distance = self.previous_state.sum_squared_distance + self.sum_energy_cost = self.previous_state.sum_energy_cost + + squared_constraint_violation = ( + self.previous_state.sum_squared_constraint_violation + ) + + if self.timestep.get_max_constraint() is not None: + if self.timestep_energy > self.timestep.get_max_constraint(): + squared_constraint_violation += ( + self.timestep_energy - self.timestep.get_max_constraint() + ) ** 2 + + if self.timestep.get_min_constraint() is not None: + if self.timestep_energy < self.timestep.get_min_constraint(): + squared_constraint_violation += ( + self.timestep.get_min_constraint() - self.timestep_energy + ) ** 2 + + self.sum_natural_gas_cost = self.previous_state.sum_natural_gas_cost + ( + timestep_natural_gas_liters * self.gas_price_per_liter + ) + self.sum_squared_constraint_violation = squared_constraint_violation + self.sum_squared_energy = ( + self.previous_state.sum_squared_energy + self.timestep_energy**2 + ) + + def _calculate_missing_factor( + self, + actuator_configurations: Dict[str, S2DdbcActuatorConfiguration], + desired_supply_rate: Optional[float], + ) -> Dict[str, S2DdbcActuatorConfiguration]: + """Calculate the missing factor (if any) and return a new map with the factor filled in.""" + if desired_supply_rate is None: + return actuator_configurations + + missing_factor_actuator_id = None + + for actuator_id, config in actuator_configurations.items(): + if ( + config.get_factor() is None + and self.device_state_wrapper.operation_mode_uses_factor( + self.timestep, actuator_id, config.get_operation_mode_id() + ) + ): + missing_factor_actuator_id = actuator_id + break + + if missing_factor_actuator_id is None: + return actuator_configurations + + supply_rate = 0.0 + for actuator_id, actuator_configuration in actuator_configurations.items(): + if actuator_id != missing_factor_actuator_id: + om = self.device_state_wrapper.get_operation_mode( + self.timestep, + actuator_id, + actuator_configuration.get_operation_mode_id(), + ) + supply_rate += om.get_operation_mode_supply_rate( + actuator_configuration.get_factor() + ) + + missing_supply_rate = desired_supply_rate - supply_rate + om = self.device_state_wrapper.get_operation_mode( + self.timestep, + missing_factor_actuator_id, + actuator_configurations[missing_factor_actuator_id].get_operation_mode_id(), + ) + supply_range = om.get_supply_range() + calculated_factor = ( + missing_supply_rate - supply_range.get_start_of_range() + ) / (supply_range.get_end_of_range() - supply_range.get_start_of_range()) + + calculated_factor = min(1.0, max(0.0, calculated_factor)) + + result = dict(actuator_configurations) + result[missing_factor_actuator_id] = om.convert_to_actuator_config( + calculated_factor + ) + return result + + @staticmethod + def _timer_key(actuator_id: str, timer_id: str) -> str: + """Generate a key for timer elapse map.""" + return f"{actuator_id}-{timer_id}" + + @staticmethod + def _get_initial_timer_elapse_map_for_system_description( + system_description, + ) -> Dict[str, datetime]: + """Get initial timer elapse map for a system description.""" + timer_elapse_map = {} + + for actuator in system_description.actuators: + for timer in actuator.timers: + timer_elapse_map[ + DdbcState._timer_key(actuator.id, timer.id) + ] = timer.finished_at + + return timer_elapse_map + + @staticmethod + def try_create_next_state( + previous_state: "DdbcState", + target_timestep: "DdbcTimestep", + actuator_configs_for_target_timestep: Dict[str, S2DdbcActuatorConfiguration], + ) -> bool: + """Try to create a next state. Returns True if successful, False if constraints are violated.""" + from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state_wrapper import ( + S2DdbcDeviceStateWrapper, + ) + + if ( + previous_state.get_system_description().valid_from + == target_timestep.get_system_description().valid_from + ): + for actuator_id, config in actuator_configs_for_target_timestep.items(): + previous_operation_mode_id = previous_state.actuator_configurations[ + actuator_id + ].get_operation_mode_id() + new_operation_mode_id = config.get_operation_mode_id() + + if previous_operation_mode_id != new_operation_mode_id: + transition = S2DdbcDeviceStateWrapper.get_transition( + target_timestep, + actuator_id, + previous_operation_mode_id, + new_operation_mode_id, + ) + + if transition is None: + return False + + for timer_id in transition.blocking_timers: + timer_is_finished_at = previous_state.timer_elapse_map.get( + DdbcState._timer_key(actuator_id, timer_id) + ) + if ( + timer_is_finished_at is not None + and target_timestep.get_start_date() < timer_is_finished_at + ): + return False + + DdbcState( + previous_state.device_state_wrapper, + target_timestep, + previous_state, + actuator_configs_for_target_timestep, + ) + return True + + def generate_next_timestep_states(self, target_timestep: "DdbcTimestep"): + """Generate all possible states for the next timestep.""" + all_actions = ( + self.device_state_wrapper.get_all_possible_actuator_configurations( + target_timestep + ) + ) + for action_map in all_actions: + self.try_create_next_state(self, target_timestep, action_map) + + def is_preferable_than(self, other: "DdbcState") -> bool: + """Determine if this state is better than another state.""" + if ( + abs( + self.sum_squared_constraint_violation + - other.sum_squared_constraint_violation + ) + >= self.CONSTRAINT_EPSILON + ): + return ( + self.sum_squared_constraint_violation + < other.sum_squared_constraint_violation + ) + else: + if self.sum_squared_distance != 0: + raise RuntimeError("Expect distance 0 as only tariff elements") + + if ( + abs(self.sum_squared_distance - other.sum_squared_distance) + >= self.CONSTRAINT_EPSILON + ): + return self.sum_squared_distance < other.sum_squared_distance + else: + total_cost = self.sum_energy_cost + self.sum_natural_gas_cost + other_total_cost = other.sum_energy_cost + other.sum_natural_gas_cost + + if abs(total_cost - other_total_cost) >= self.CONSTRAINT_EPSILON: + return total_cost < other_total_cost + else: + return self.sum_squared_energy > other.sum_squared_energy + + def supply_demand_distance(self) -> float: + """Calculate distance between supply and demand.""" + return abs(self.supply_rate - self.timestep.get_avg_demand_rate_forecast()) + + def get_timestep(self) -> "DdbcTimestep": + return self.timestep + + def get_system_description(self): + return self.timestep.get_system_description() + + def get_device_state_wrapper(self) -> "S2DdbcDeviceStateWrapper": + return self.device_state_wrapper + + def get_previous_state(self) -> Optional["DdbcState"]: + return self.previous_state + + def get_actuator_configurations(self) -> Dict[str, S2DdbcActuatorConfiguration]: + return self.actuator_configurations + + def get_supply_rate(self) -> float: + return self.supply_rate + + def get_timestep_energy(self) -> float: + return self.timestep_energy + + def get_timer_elapse_map(self) -> Dict[str, datetime]: + return self.timer_elapse_map diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_timestep.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_timestep.py new file mode 100644 index 0000000..76cb259 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/ddbc_timestep.py @@ -0,0 +1,104 @@ +from datetime import datetime, timedelta +from typing import Optional, Any, List, TYPE_CHECKING +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile + +if TYPE_CHECKING: + from flexmeasures_s2.profile_steering.device_planner.ddbc.ddbc_state import ( + DdbcState, + ) + + +class DdbcTimestep: + """Represents a single timestep in DDBC planning.""" + + DISTANCE_EPSILON = 500.0 # 500 W tolerance (5% of 10kW typical system) + + def __init__( + self, + start_date: datetime, + end_date: datetime, + system_description: Any, + avg_demand_rate_forecast: Optional[float], + ): + self.start_date = start_date + self.end_date = end_date + self.system_description = system_description + self.avg_demand_rate_forecast = avg_demand_rate_forecast + + self.target: Optional[TargetProfile.Element] = None + self.min_constraint: Optional[int] = None + self.max_constraint: Optional[int] = None + + self.best_state: Optional["DdbcState"] = None + self.emergency_state: Optional["DdbcState"] = None + + def set_targets( + self, + target: TargetProfile.Element, + min_constraint: Optional[int], + max_constraint: Optional[int], + ): + """Set the target and constraints for this timestep.""" + self.target = target + self.min_constraint = min_constraint + self.max_constraint = max_constraint + + def add_state(self, state: "DdbcState"): + """Add a state to this timestep and track the best state.""" + distance = state.supply_demand_distance() + + if distance < self.DISTANCE_EPSILON: + if self.best_state is None: + self.best_state = state + elif state.is_preferable_than(self.best_state): + self.best_state = state + else: + if ( + self.emergency_state is None + or distance < self.emergency_state.supply_demand_distance() + ): + self.emergency_state = state + + def add_all_states(self, states: List["DdbcState"]): + """Add multiple states to this timestep.""" + for state in states: + self.add_state(state) + + def get_best_state(self) -> Optional["DdbcState"]: + """Get the best state for this timestep, or emergency state if no best state exists.""" + if self.best_state is None: + return self.emergency_state + else: + return self.best_state + + def get_start_date(self) -> datetime: + return self.start_date + + def get_end_date(self) -> datetime: + return self.end_date + + def get_system_description(self) -> Any: + return self.system_description + + def get_duration(self) -> timedelta: + return self.end_date - self.start_date + + def get_duration_seconds(self) -> int: + return int(self.get_duration().total_seconds()) + + def get_target(self) -> Optional[TargetProfile.Element]: + return self.target + + def get_min_constraint(self) -> Optional[int]: + return self.min_constraint + + def get_max_constraint(self) -> Optional[int]: + return self.max_constraint + + def get_avg_demand_rate_forecast(self) -> Optional[float]: + return self.avg_demand_rate_forecast + + def clear(self): + """Clear the states for this timestep.""" + self.best_state = None + self.emergency_state = None diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/number_range_wrapper.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/number_range_wrapper.py new file mode 100644 index 0000000..7c32c79 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/number_range_wrapper.py @@ -0,0 +1,49 @@ +import math +from typing import Any, Optional + + +class NumberRangeWrapper: + """Wrapper for CommonNumberRange to provide utility methods.""" + + def __init__( + self, + unwrapped_range: Any = None, + start_of_range: Optional[float] = None, + end_of_range: Optional[float] = None, + ): + """Initialize from either an unwrapped range object or explicit values.""" + if unwrapped_range is not None: + self.start_of_range: float = float(unwrapped_range.start_of_range) + self.end_of_range: float = float(unwrapped_range.end_of_range) + else: + assert ( + start_of_range is not None and end_of_range is not None + ), "start_of_range and end_of_range must be provided if unwrapped_range is None" + self.start_of_range = start_of_range + self.end_of_range = end_of_range + + def get_start_of_range(self) -> float: + return self.start_of_range + + def get_end_of_range(self) -> float: + return self.end_of_range + + def __eq__(self, o: object) -> bool: + if self is o: + return True + if not isinstance(o, NumberRangeWrapper): + return False + that = o + return math.isclose(that.start_of_range, self.start_of_range) and math.isclose( + that.end_of_range, self.end_of_range + ) + + def __hash__(self) -> int: + return hash((self.start_of_range, self.end_of_range)) + + def __str__(self) -> str: + return ( + f"NumberRangeWrapper(" + f"startOfRange={self.start_of_range}, " + f"endOfRange={self.end_of_range})" + ) diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_actuator_configuration.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_actuator_configuration.py new file mode 100644 index 0000000..1c406c4 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_actuator_configuration.py @@ -0,0 +1,51 @@ +from typing import Dict, Optional +from flexmeasures_s2.profile_steering.common.s2_actuator_configuration import ( + S2ActuatorConfiguration, +) + + +class S2DdbcActuatorConfiguration(S2ActuatorConfiguration): + """Configuration for a DDBC actuator including power per commodity and supply rate.""" + + def __init__( + self, + operation_mode_id: str, + factor: Optional[float], + supply_rate: Optional[float], + power_per_commodity_quantity: Dict[str, float], + ): + super().__init__(operation_mode_id, factor) + self.supply_rate = supply_rate + self.power_per_commodity_quantity = power_per_commodity_quantity + + def get_supply_rate(self) -> Optional[float]: + return self.supply_rate + + def get_power_per_commodity_quantity(self) -> Dict[str, float]: + return self.power_per_commodity_quantity + + def to_dict(self) -> Dict: + return { + "operationModeId": self.operation_mode_id, + "factor": self.factor, + "supplyRate": self.supply_rate, + "powerPerCommodityQuantity": self.power_per_commodity_quantity, + } + + @staticmethod + def from_dict(data: Dict): + return S2DdbcActuatorConfiguration( + data["operationModeId"], + data.get("factor"), + data.get("supplyRate"), + data.get("powerPerCommodityQuantity", {}), + ) + + def __str__(self): + return ( + f"S2DdbcActuatorConfiguration[" + f"operationModeId={self.operation_mode_id}, " + f"factor={self.factor}, " + f"supplyRate={self.supply_rate}, " + f"powerPerCommodityQuantity={self.power_per_commodity_quantity}]" + ) diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_device_planner.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_device_planner.py new file mode 100644 index 0000000..9120d83 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_device_planner.py @@ -0,0 +1,230 @@ +from datetime import datetime +from typing import Optional +import logging + +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.proposal import Proposal +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_plan import S2DdbcPlan +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_instruction_profile import ( + S2DdbcInstructionProfile, +) +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from flexmeasures_s2.profile_steering.common.device_plan import DevicePlan +from flexmeasures_s2.profile_steering.device_planner.ddbc.ddbc_planning_window import ( + DdbcPlanningWindow, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state import ( + S2DdbcDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.device_planner_abstract import ( + DevicePlanner, +) + + +class S2DdbcDevicePlanner(DevicePlanner): + """Device planner for Demand-Driven Based Control (DDBC) devices.""" + + STRATIFICATION_LAYERS = 30 # Number of stratification layers (matching FRBC) + + def __init__( + self, + s2_ddbc_state: S2DdbcDeviceState, + profile_metadata: ProfileMetadata, + plan_due_by_date: datetime, + congestion_point_id: str, + ): + self._congestion_point_id = congestion_point_id + self.s2_ddbc_state = s2_ddbc_state + self.profile_metadata = profile_metadata + self.zero_profile = JouleProfile( + profile_metadata.profile_start, + profile_metadata.timestep_duration, + [0] * profile_metadata.nr_of_timesteps, + ) + self.null_profile = JouleProfile( + profile_metadata.profile_start, + profile_metadata.timestep_duration, + elements=[None] * profile_metadata.nr_of_timesteps, + ) + + self.state_tree: Optional[DdbcPlanningWindow] + if self._is_device_available(self.s2_ddbc_state): + self.state_tree = DdbcPlanningWindow( + self.s2_ddbc_state, + profile_metadata, + plan_due_by_date, + ) + else: + self.state_tree = None + + self._priority_class = s2_ddbc_state.get_priority_class() + self.latest_plan: Optional[S2DdbcPlan] = None + self.accepted_plan: Optional[S2DdbcPlan] = None + + def _is_device_available(self, ddbc_state: S2DdbcDeviceState) -> bool: + """Check if the device is available for planning.""" + return ddbc_state.is_device_online() + + @property + def priority_class(self) -> int: + return self._priority_class + + @property + def device_id(self) -> str: + return self.s2_ddbc_state.get_device_id() + + @property + def connection_id(self) -> str: + return self.s2_ddbc_state.get_connection_id() + + @property + def congestion_point_id(self) -> str: + return self._congestion_point_id + + @property + def device_name(self) -> str: + return self.s2_ddbc_state.get_device_name() + + def create_improved_planning( + self, + diff_to_global_target: TargetProfile, + diff_to_max: JouleProfile, + diff_to_min: JouleProfile, + plan_due_by_date: datetime, + ) -> Proposal: + """Create an improved planning based on the difference to global target.""" + if self.accepted_plan is None: + raise ValueError("No accepted plan found") + + target = diff_to_global_target.add(self.accepted_plan.get_energy()) + max_profile = diff_to_max.add(self.accepted_plan.get_energy()) + min_profile = diff_to_min.add(self.accepted_plan.get_energy()) + + if ( + self._is_device_available(self.s2_ddbc_state) + and self.state_tree is not None + ): + self.latest_plan = self.state_tree.find_best_plan( + target, min_profile, max_profile + ) + else: + self.latest_plan = S2DdbcPlan( + idle=True, + energy=self.zero_profile, + operation_mode_id=None, + s2_ddbc_insights_profile=None, + ) + + if self.latest_plan is None: + raise ValueError("No latest plan found") + + proposal = Proposal( + global_diff_target=diff_to_global_target, + diff_to_congestion_max=diff_to_max, + diff_to_congestion_min=diff_to_min, + proposed_plan=self.latest_plan.get_energy(), + old_plan=self.accepted_plan.get_energy(), + origin=self, + ) + return proposal + + def create_initial_planning(self, plan_due_by_date: datetime) -> S2DdbcPlan: + """Create an initial planning.""" + if ( + self._is_device_available(self.s2_ddbc_state) + and self.state_tree is not None + ): + self.latest_plan = self.state_tree.find_best_plan( + TargetProfile.null_profile(self.profile_metadata), + self.null_profile, + self.null_profile, + ) + else: + self.latest_plan = S2DdbcPlan( + idle=True, + energy=self.zero_profile, + operation_mode_id=None, + s2_ddbc_insights_profile=None, + ) + self.accepted_plan = self.latest_plan + return self.latest_plan + + def accept_proposal(self, accepted_proposal: Proposal) -> None: + """Accept a proposal.""" + if self.latest_plan is None: + raise ValueError("No latest plan found") + if accepted_proposal.origin != self: + raise ValueError( + f"Device controller '{self.device_id}' received a proposal that it did not send." + ) + if not accepted_proposal.proposed_plan == self.latest_plan.get_energy(): + raise ValueError( + f"Device controller '{self.device_id}' received a proposal that it did not send." + ) + if accepted_proposal.get_congestion_improvement_value() < 0: + raise ValueError( + f"Device controller '{self.device_id}' received a proposal with negative improvement" + ) + self.accepted_plan = self.latest_plan + + def get_latest_plan(self) -> Optional[S2DdbcPlan]: + """Get the latest plan.""" + return self.latest_plan + + def set_accepted_plan(self, plan: S2DdbcPlan) -> None: + """Set the accepted plan.""" + if not isinstance(plan, S2DdbcPlan): + raise TypeError(f"Expected S2DdbcPlan, but got {type(plan)}") + self.accepted_plan = plan + + def current_profile(self) -> JouleProfile: + """Get the current profile.""" + if self.accepted_plan is None: + raise ValueError("No accepted plan found") + return self.accepted_plan.get_energy() + + def get_device_plan(self) -> Optional[DevicePlan]: + """Get the device plan.""" + if self.accepted_plan is None: + return None + + logging.debug( + dict( + device_id=self.device_id, + device_name=self.device_name, + connection_id=self.connection_id, + energy_profile=self.accepted_plan.get_energy(), + instruction_profile=self.convert_plan_to_instructions( + self.profile_metadata, self.accepted_plan + ), + ) + ) + return DevicePlan( + device_id=self.device_id, + device_name=self.device_name, + connection_id=self.connection_id, + energy_profile=self.accepted_plan.get_energy(), + fill_level_profile=None, + instruction_profile=self.convert_plan_to_instructions( + self.profile_metadata, self.accepted_plan + ), + insights_profile=self.accepted_plan.get_s2_ddbc_insights_profile(), + ) + + @staticmethod + def convert_plan_to_instructions( + profile_metadata: ProfileMetadata, device_plan: S2DdbcPlan + ) -> S2DdbcInstructionProfile: + """Convert a plan to instruction profile.""" + elements = [] + actuator_configurations_per_timestep = device_plan.get_operation_mode_id() + + if actuator_configurations_per_timestep is not None: + for actuator_configurations in actuator_configurations_per_timestep: + new_element = S2DdbcInstructionProfile.Element( + not actuator_configurations, actuator_configurations + ) + elements.append(new_element) + + return S2DdbcInstructionProfile(profile_metadata, elements) diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_device_state.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_device_state.py new file mode 100644 index 0000000..ca7d9d8 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_device_state.py @@ -0,0 +1,76 @@ +from datetime import datetime +from typing import List, Optional, Any, Dict + + +class S2DdbcDeviceState: + """Device state for Demand-Driven Based Control (DDBC).""" + + DEFAULT_GAS_PRICE_PER_M3 = 2.0 + + def __init__( + self, + device_id: str, + device_name: str, + connection_id: str, + priority_class: int, + timestamp: datetime, + energy_in_current_timestep: float, + is_online: bool, + power_forecast: Optional[Any], + system_descriptions: List[Any], + demand_forecasts: List[Any], + actuator_statuses: Optional[Dict[str, Any]] = None, + gas_price_per_m3: Optional[float] = None, + ): + self.device_id = device_id + self.device_name = device_name + self.connection_id = connection_id + self.priority_class = priority_class + self.timestamp = timestamp + self.energy_in_current_timestep = energy_in_current_timestep + self.is_online = is_online + self.power_forecast = power_forecast + self.system_descriptions = system_descriptions + self.demand_forecasts = demand_forecasts + self.actuator_statuses = actuator_statuses or {} + self.gas_price_per_m3 = ( + gas_price_per_m3 + if gas_price_per_m3 is not None + else self.DEFAULT_GAS_PRICE_PER_M3 + ) + + def get_device_id(self) -> str: + return self.device_id + + def get_device_name(self) -> str: + return self.device_name + + def get_connection_id(self) -> str: + return self.connection_id + + def get_priority_class(self) -> int: + return self.priority_class + + def get_timestamp(self) -> datetime: + return self.timestamp + + def get_energy_in_current_timestep(self) -> float: + return self.energy_in_current_timestep + + def is_device_online(self) -> bool: + return self.is_online + + def get_power_forecast(self) -> Optional[Any]: + return self.power_forecast + + def get_system_descriptions(self) -> List[Any]: + return self.system_descriptions + + def get_demand_forecasts(self) -> List[Any]: + return self.demand_forecasts + + def get_gas_price_per_m3(self) -> float: + return self.gas_price_per_m3 + + def get_actuator_statuses(self) -> Dict[str, Any]: + return self.actuator_statuses diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_device_state_wrapper.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_device_state_wrapper.py new file mode 100644 index 0000000..72d7506 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_device_state_wrapper.py @@ -0,0 +1,412 @@ +from datetime import datetime, timedelta +from typing import List, Dict, Set, Optional, Any, TYPE_CHECKING +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state import ( + S2DdbcDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_actuator_configuration import ( + S2DdbcActuatorConfiguration, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.ddbc_operation_mode_wrapper import ( + DdbcOperationModeWrapper, +) + +if TYPE_CHECKING: + from flexmeasures_s2.profile_steering.device_planner.ddbc.ddbc_timestep import ( + DdbcTimestep, + ) + + +class S2DdbcDeviceStateWrapper: + """ + Wrapper for S2DdbcDeviceState that adds utility functions and caching. + """ + + EPSILON = 1e-4 + STRATIFICATION_LAYERS = 30 # Number of stratification layers (matching FRBC) + + def __init__(self, device_state: S2DdbcDeviceState): + self.device_state = device_state + + self.actuator_operation_mode_map_per_timestep: Dict[ + datetime, Dict[str, List[str]] + ] = {} + self.all_actions: Dict[ + datetime, List[Dict[str, S2DdbcActuatorConfiguration]] + ] = {} + self.operation_mode_uses_factor_map: Dict[str, bool] = {} + self.operation_modes: Dict[str, DdbcOperationModeWrapper] = {} + + def is_online(self) -> bool: + return self.device_state.is_device_online() + + def get_power_forecast(self) -> Any: + return self.device_state.get_power_forecast() + + def get_system_descriptions(self) -> List[Any]: + return self.device_state.get_system_descriptions() + + def get_demand_forecasts(self) -> List[Any]: + return self.device_state.get_demand_forecasts() + + def get_energy_in_current_timestep(self) -> float: + return self.device_state.get_energy_in_current_timestep() + + def get_gas_price_per_m3(self) -> float: + return self.device_state.get_gas_price_per_m3() + + def get_actuator_statuses(self): + return self.device_state.get_actuator_statuses() + + def get_actuators(self, target_timestep: "DdbcTimestep") -> Set[str]: + """Get all actuator IDs for a timestep.""" + actuator_operation_mode_map = self.actuator_operation_mode_map_per_timestep.get( + target_timestep.get_start_date() + ) + if actuator_operation_mode_map is None: + actuator_operation_mode_map = self._create_actuator_operation_mode_map( + target_timestep + ) + return set(actuator_operation_mode_map.keys()) + + def get_normal_operation_modes_for_actuator( + self, target_timestep: "DdbcTimestep", actuator_id: str + ) -> List[str]: + """Get all normal operation mode IDs for an actuator.""" + actuator_operation_mode_map = self.actuator_operation_mode_map_per_timestep.get( + target_timestep.get_start_date() + ) + if actuator_operation_mode_map is None: + actuator_operation_mode_map = self._create_actuator_operation_mode_map( + target_timestep + ) + return actuator_operation_mode_map[actuator_id] + + def _create_actuator_operation_mode_map( + self, target_timestep: "DdbcTimestep" + ) -> Dict[str, List[str]]: + """Create a map from actuator ID to list of normal operation mode IDs.""" + actuator_operation_mode_map: Dict[str, List[str]] = {} + + for actuator in target_timestep.get_system_description().actuators: + # Convert both actuator ID and operation mode IDs to strings + operation_mode_ids = [ + str(om.id) + for om in actuator.operation_modes + if not om.abnormal_condition_only + ] + actuator_operation_mode_map[str(actuator.id)] = operation_mode_ids + + self.actuator_operation_mode_map_per_timestep[ + target_timestep.get_start_date() + ] = actuator_operation_mode_map + return actuator_operation_mode_map + + def get_operation_mode( + self, target_timestep: "DdbcTimestep", actuator_id: str, operation_mode_id: str + ) -> DdbcOperationModeWrapper: + """Get an operation mode wrapper.""" + + # Handle UUID objects with root attribute - extract the actual UUID value + if hasattr(operation_mode_id, "root"): + # Extract the root attribute and convert to string + operation_mode_id = str(operation_mode_id.root) + elif not isinstance(operation_mode_id, str): + operation_mode_id = str(operation_mode_id) + # If it's already a string, use it as is + + om_key = f"{actuator_id}-{operation_mode_id}" + + if om_key in self.operation_modes: + return self.operation_modes[om_key] + + found_actuator_description = None + system_actuators = target_timestep.get_system_description().actuators + + for actuator_description in system_actuators: + actuator_desc_id_str = str(actuator_description.id) + if ( + actuator_desc_id_str == actuator_id + or actuator_description.id == actuator_id + ): + found_actuator_description = actuator_description + break + + if found_actuator_description is None: + raise ValueError(f"Actuator {actuator_id} not found") + + found_om_ids = [] + for idx, operation_mode in enumerate( + found_actuator_description.operation_modes + ): + # Try to get the operation mode ID from multiple sources + operation_mode_id_obj = None + if hasattr(operation_mode, "Id"): + operation_mode_id_obj = operation_mode.Id + elif hasattr(operation_mode, "id"): + operation_mode_id_obj = operation_mode.id + else: + operation_mode_id_obj = None + + # Convert to string for comparison + if operation_mode_id_obj is not None and hasattr( + operation_mode_id_obj, "root" + ): + operation_mode_id_str = str(operation_mode_id_obj.root) + elif operation_mode_id_obj is not None and hasattr( + operation_mode_id_obj, "hex" + ): + operation_mode_id_str = str(operation_mode_id_obj) + else: + operation_mode_id_str = str(operation_mode_id_obj) + + found_om_ids.append(operation_mode_id_str) + + if operation_mode_id_str == operation_mode_id: + found_operation_mode = DdbcOperationModeWrapper(operation_mode) + self.operation_modes[om_key] = found_operation_mode + return found_operation_mode + + raise ValueError( + f"Operation mode '{operation_mode_id}' (type: {type(operation_mode_id)}) not found for actuator {actuator_id}. " + f"Available operation modes: {found_om_ids}. " + f"Comparison details: searching='{operation_mode_id}' vs found={found_om_ids}" + ) + + def operation_mode_uses_factor( + self, target_timestep: "DdbcTimestep", actuator_id: str, operation_mode_id: str + ) -> bool: + """Check if an operation mode uses a factor.""" + # Handle UUID objects with root attribute + if hasattr(operation_mode_id, "root"): + operation_mode_id = str(operation_mode_id.root) + else: + operation_mode_id = str(operation_mode_id) + + key = f"{actuator_id}-{operation_mode_id}" + result_from_map = self.operation_mode_uses_factor_map.get(key) + + if result_from_map is None: + result = self.get_operation_mode( + target_timestep, actuator_id, operation_mode_id + ).uses_factor_method() + self.operation_mode_uses_factor_map[key] = result + return result + else: + return result_from_map + + def get_all_possible_actuator_configurations( + self, target_timestep: "DdbcTimestep" + ) -> List[Dict[str, S2DdbcActuatorConfiguration]]: + """Get all possible actuator configurations for a timestep.""" + timestep_date = target_timestep.get_start_date() + + if timestep_date in self.all_actions: + return self.all_actions[timestep_date] + + possible_actuator_configs: Dict[str, List[S2DdbcActuatorConfiguration]] = {} + + for actuator_id in self.get_actuators(target_timestep): + actuator_list: List[S2DdbcActuatorConfiguration] = [] + + for operation_mode_id in self.get_normal_operation_modes_for_actuator( + target_timestep, actuator_id + ): + if self.operation_mode_uses_factor( + target_timestep, actuator_id, operation_mode_id + ): + actuator_list.append( + S2DdbcActuatorConfiguration(operation_mode_id, None, None, {}) + ) + else: + om = self.get_operation_mode( + target_timestep, actuator_id, operation_mode_id + ) + actuator_list.append(om.convert_to_actuator_config(0.0)) + + possible_actuator_configs[actuator_id] = actuator_list + + keys = list(possible_actuator_configs.keys()) + operation_mode_configurations: List[Dict[str, S2DdbcActuatorConfiguration]] = [] + + combination = [0] * len(keys) + operation_mode_configurations.append( + self._combination_to_map(combination, keys, possible_actuator_configs) + ) + + while self._increase(combination, keys, possible_actuator_configs): + operation_mode_configurations.append( + self._combination_to_map(combination, keys, possible_actuator_configs) + ) + + finished = False + strat_iter_count = 0 + # Safety limit to prevent infinite loops in stratification + MAX_STRATIFICATION_ITERATIONS = 1000 + + while not finished and strat_iter_count < MAX_STRATIFICATION_ITERATIONS: + found_multiple = False + for i in range(len(operation_mode_configurations)): + c = operation_mode_configurations[i] + if self._contains_multiple_oms_with_factor(c, target_timestep): + operation_mode_configurations.pop(i) + new_configs = self._apply_stratification_layers(c, target_timestep) + operation_mode_configurations.extend(new_configs) + found_multiple = True + break + finished = not found_multiple + strat_iter_count += 1 + + self.all_actions[timestep_date] = operation_mode_configurations + return operation_mode_configurations + + def _apply_stratification_layers( + self, + configurations: Dict[str, S2DdbcActuatorConfiguration], + target_timestep: "DdbcTimestep", + ) -> List[Dict[str, S2DdbcActuatorConfiguration]]: + """Apply stratification layers to configurations with factors.""" + actuator_id = None + operation_mode_id = None + copy = dict(configurations) + + for config_actuator_id, config in list(copy.items()): + if self.operation_mode_uses_factor( + target_timestep, config_actuator_id, config.get_operation_mode_id() + ): + actuator_id = config_actuator_id + operation_mode_id = config.get_operation_mode_id() + del copy[config_actuator_id] + break + + if actuator_id is None or operation_mode_id is None: + raise ValueError("No actuator with factor found") + + configs: List[Dict[str, S2DdbcActuatorConfiguration]] = [] + om = self.get_operation_mode(target_timestep, actuator_id, operation_mode_id) + + # If stratification is disabled, just use factor 0.0 + if self.STRATIFICATION_LAYERS == 0: + config_actuator_map = dict(copy) + config_actuator_map[actuator_id] = om.convert_to_actuator_config(0.0) + configs.append(config_actuator_map) + else: + for i in range(self.STRATIFICATION_LAYERS + 1): + config_actuator_map = dict(copy) + factor_for_actuator = i * (1.0 / self.STRATIFICATION_LAYERS) + config_actuator_map[actuator_id] = om.convert_to_actuator_config( + factor_for_actuator + ) + configs.append(config_actuator_map) + + return configs + + def _contains_multiple_oms_with_factor( + self, + configurations: Dict[str, S2DdbcActuatorConfiguration], + target_timestep: "DdbcTimestep", + ) -> bool: + """Check if configurations contain multiple operation modes with factors.""" + found_one = False + for actuator_id, config in configurations.items(): + if self.operation_mode_uses_factor( + target_timestep, actuator_id, config.get_operation_mode_id() + ): + if found_one: + return True + else: + found_one = True + return False + + def _combination_to_map( + self, + cur: List[int], + keys: List[str], + possible_actuator_configs: Dict[str, List[S2DdbcActuatorConfiguration]], + ) -> Dict[str, S2DdbcActuatorConfiguration]: + """Convert combination indices to a configuration map.""" + combination: Dict[str, S2DdbcActuatorConfiguration] = {} + for i in range(len(keys)): + key = keys[i] + combination[key] = possible_actuator_configs[key][cur[i]] + return combination + + def _increase( + self, + cur: List[int], + keys: List[str], + possible_actuator_configs: Dict[str, List[S2DdbcActuatorConfiguration]], + ) -> bool: + """Increase combination indices.""" + cur[0] += 1 + for i in range(len(keys)): + key = keys[i] + if cur[i] >= len(possible_actuator_configs[key]): + if i + 1 >= len(keys): + return False + cur[i] = 0 + cur[i + 1] += 1 + return True + + @staticmethod + def get_transition( + target_timestep: "DdbcTimestep", + actuator_id: str, + from_operation_mode_id: str, + to_operation_mode_id: str, + ) -> Optional[Any]: + """Get a transition between operation modes.""" + actuator_description = S2DdbcDeviceStateWrapper.get_actuator_description( + target_timestep, actuator_id + ) + + found_transition = None + for transition in actuator_description.transitions: + if ( + getattr(transition, "from", None) == from_operation_mode_id + and transition.to == to_operation_mode_id + ): + found_transition = transition + break + + return found_transition + + @staticmethod + def get_timer_duration_milliseconds( + target_timestep: "DdbcTimestep", actuator_id: str, timer_id: str + ) -> int: + """Get timer duration in milliseconds.""" + actuator_description = S2DdbcDeviceStateWrapper.get_actuator_description( + target_timestep, actuator_id + ) + timer = next(t for t in actuator_description.timers if t.id == timer_id) + return timer.duration + + @staticmethod + def get_timer_duration( + target_timestep: "DdbcTimestep", actuator_id: str, timer_id: str + ) -> timedelta: + """Get timer duration as timedelta.""" + return timedelta( + milliseconds=S2DdbcDeviceStateWrapper.get_timer_duration_milliseconds( + target_timestep, actuator_id, timer_id + ) + ) + + @staticmethod + def get_actuator_description( + target_timestep: "DdbcTimestep", actuator_id: str + ) -> Any: + """Get actuator description by ID.""" + found_actuator_description = None + for actuator_description in target_timestep.get_system_description().actuators: + if ( + str(actuator_description.id) == actuator_id + or actuator_description.id == actuator_id + ): + found_actuator_description = actuator_description + break + + if found_actuator_description is None: + raise ValueError(f"Actuator {actuator_id} not found") + + return found_actuator_description diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_insights_profile.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_insights_profile.py new file mode 100644 index 0000000..1f40881 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_insights_profile.py @@ -0,0 +1,40 @@ +from typing import List, Dict, Optional, Any +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata + + +class S2DdbcInsightsProfile: + """Insights profile for DDBC device providing additional information about the plan.""" + + class Element: + """Single element in the insights profile.""" + + def __init__( + self, + demand_rate_forecast: Optional[float], + supply_rate: float, + actuator_configurations: Dict[str, Any], + ): + self.demand_rate_forecast = demand_rate_forecast + self.supply_rate = supply_rate + self.actuator_configurations = actuator_configurations + + def get_demand_rate_forecast(self) -> Optional[float]: + return self.demand_rate_forecast + + def get_supply_rate(self) -> float: + return self.supply_rate + + def get_actuator_configurations(self) -> Dict[str, Any]: + return self.actuator_configurations + + def __init__( + self, profile_metadata: ProfileMetadata, elements: List[Optional[Element]] + ): + self.profile_metadata = profile_metadata + self.elements = elements + + def get_profile_metadata(self) -> ProfileMetadata: + return self.profile_metadata + + def get_elements(self) -> List[Optional[Element]]: + return self.elements diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_instruction_profile.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_instruction_profile.py new file mode 100644 index 0000000..d188d27 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_instruction_profile.py @@ -0,0 +1,29 @@ +from typing import List, Dict, Any +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata + + +class S2DdbcInstructionProfile: + """Instruction profile for DDBC device.""" + + class Element: + """Single instruction element.""" + + def __init__(self, is_empty: bool, actuator_configurations: Dict[str, Any]): + self.is_empty = is_empty + self.actuator_configurations = actuator_configurations + + def is_element_empty(self) -> bool: + return self.is_empty + + def get_actuator_configurations(self) -> Dict[str, Any]: + return self.actuator_configurations + + def __init__(self, profile_metadata: ProfileMetadata, elements: List[Element]): + self.profile_metadata = profile_metadata + self.elements = elements + + def get_profile_metadata(self) -> ProfileMetadata: + return self.profile_metadata + + def get_elements(self) -> List[Element]: + return self.elements diff --git a/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_plan.py b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_plan.py new file mode 100644 index 0000000..8f270ff --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/ddbc/s2_ddbc_plan.py @@ -0,0 +1,35 @@ +from typing import List, Dict, Optional, Any, TYPE_CHECKING +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile + +if TYPE_CHECKING: + from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_insights_profile import ( + S2DdbcInsightsProfile, + ) + + +class S2DdbcPlan: + """Plan for a DDBC device.""" + + def __init__( + self, + idle: bool, + energy: JouleProfile, + operation_mode_id: Optional[List[Dict[str, Any]]], + s2_ddbc_insights_profile: Optional["S2DdbcInsightsProfile"], + ): + self.idle = idle + self.energy = energy + self.operation_mode_id = operation_mode_id + self.s2_ddbc_insights_profile = s2_ddbc_insights_profile + + def is_idle(self) -> bool: + return self.idle + + def get_energy(self) -> JouleProfile: + return self.energy + + def get_operation_mode_id(self) -> Optional[List[Dict[str, Any]]]: + return self.operation_mode_id + + def get_s2_ddbc_insights_profile(self) -> Optional["S2DdbcInsightsProfile"]: + return self.s2_ddbc_insights_profile diff --git a/flexmeasures_s2/profile_steering/device_planner/device_planner_abstract.py b/flexmeasures_s2/profile_steering/device_planner/device_planner_abstract.py new file mode 100644 index 0000000..f9df657 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/device_planner_abstract.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from datetime import datetime +from typing import Any, Optional, TYPE_CHECKING + +if TYPE_CHECKING: + from flexmeasures_s2.profile_steering.common.proposal import Proposal +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.device_plan import ( + DevicePlan, +) +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile + + +class DevicePlanner(ABC): + """Abstract base class for all device planners.""" + + @property + @abstractmethod + def priority_class(self) -> int: + """The priority class of the device.""" + raise NotImplementedError + + @property + @abstractmethod + def device_id(self) -> str: + """The device ID.""" + raise NotImplementedError + + @property + @abstractmethod + def device_name(self) -> str: + """The device name.""" + raise NotImplementedError + + @property + @abstractmethod + def connection_id(self) -> str: + """The connection ID.""" + raise NotImplementedError + + @property + @abstractmethod + def congestion_point_id(self) -> str: + """The congestion point ID this device belongs to.""" + raise NotImplementedError + + @abstractmethod + def create_improved_planning( + self, + difference_profile: TargetProfile, + diff_to_max_value: JouleProfile, + diff_to_min_value: JouleProfile, + plan_due_by_date: datetime, + ) -> Optional["Proposal"]: + """Create an improved planning profile based on the difference profile. + + Args: + difference_profile: The difference profile for the cluster + diff_to_max_value: The difference to the maximum profile + diff_to_min_value: The difference to the minimum profile + plan_due_by_date: The date by which the plan must be ready + + Returns: + A Proposal object if an improvement was found, None otherwise + """ + pass + + @abstractmethod + def create_initial_planning(self, plan_due_by_date: datetime) -> "Any": + """Create an initial planning profile. + + Args: + plan_due_by_date: The date by which the plan must be ready + + Returns: + A plan object for the device. + """ + pass + + @abstractmethod + def accept_proposal(self, proposal: "Proposal") -> None: + """This method is called when a proposal from this device is accepted by a higher-level controller. + + Args: + proposal: The proposal that was accepted + """ + pass + + @abstractmethod + def current_profile(self) -> JouleProfile: + """Get the current profile of the device.""" + pass + + @abstractmethod + def get_device_plan(self) -> Optional[DevicePlan]: + """Get the device plan.""" + pass + + @abstractmethod + def get_latest_plan(self) -> Any: + """Get the latest calculated plan, which may not have been accepted yet.""" + pass + + @abstractmethod + def set_accepted_plan(self, plan: Any): + """Forcefully set the accepted plan for the device.""" + pass diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/fill_level_target_util.py b/flexmeasures_s2/profile_steering/device_planner/frbc/fill_level_target_util.py new file mode 100644 index 0000000..1a453d8 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/fill_level_target_util.py @@ -0,0 +1,69 @@ +from datetime import timedelta, timezone + + +class FillLevelTargetElement: + def __init__(self, start, end, lower_limit, upper_limit): + self.start = start + self.end = end + self.lower_limit = lower_limit + self.upper_limit = upper_limit + + def split(self, date): + if self.date_in_element(date): + return [ + FillLevelTargetElement( + self.start, date, self.lower_limit, self.upper_limit + ), + FillLevelTargetElement( + date, self.end, self.lower_limit, self.upper_limit + ), + ] + return [] + + def date_in_element(self, date): + return self.start <= date <= self.end + + +class FillLevelTargetUtil: + @staticmethod + def from_fill_level_target_profile(fill_level_target_profile): + elements = [] + start = fill_level_target_profile.start_time.astimezone(timezone.utc) + for element in fill_level_target_profile.elements: + # Extract duration value - handle both int and Duration object + duration = element.duration + if isinstance(duration, (int, float)): + duration_ms = int(duration) + elif hasattr(duration, "root"): + duration_ms = int(duration.root) + elif hasattr(duration, "__root__"): + duration_ms = int(duration.__root__) + else: + try: + duration_ms = int(duration) + except (TypeError, ValueError): + duration_ms = int(str(duration)) + + end = start + timedelta(milliseconds=duration_ms) + elements.append( + FillLevelTargetElement( + start, + end, + element.fill_level_range.start_of_range, + element.fill_level_range.end_of_range, + ) + ) + start = end + timedelta(milliseconds=1) + return elements + + @staticmethod + def get_elements_in_range(target_profile, start, end): + elements_in_range = [] + start = start.replace(tzinfo=None) + end = end.replace(tzinfo=None) + for element in target_profile: + element_start = element.start.replace(tzinfo=None) + element_end = element.end.replace(tzinfo=None) + if element_start <= end and element_end >= start: + elements_in_range.append(element) + return elements_in_range diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/frbc_operation_mode_wrapper.py b/flexmeasures_s2/profile_steering/device_planner/frbc/frbc_operation_mode_wrapper.py new file mode 100644 index 0000000..ecdcbbc --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/frbc_operation_mode_wrapper.py @@ -0,0 +1,98 @@ +import numpy as np +from typing import List, Optional + +from flexmeasures_s2.profile_steering.common.power_range_wrapper import ( + PowerRangeWrapper, +) +from flexmeasures_s2.profile_steering.s2_utils.number_range_wrapper import ( + NumberRangeWrapper, +) +from s2python.frbc import FRBCOperationMode, FRBCOperationModeElement + + +class FrbcOperationModeElementWrapper: + def __init__(self, element: FRBCOperationModeElement): + self.fill_level_range = NumberRangeWrapper( + element.fill_level_range.start_of_range, + element.fill_level_range.end_of_range, + ) + self.fill_rate = NumberRangeWrapper( + element.fill_rate.start_of_range, element.fill_rate.end_of_range + ) + self.power_ranges: List[PowerRangeWrapper] = [ + PowerRangeWrapper(pr) for pr in element.power_ranges + ] + + if element.running_costs is None: + self.running_costs: Optional[NumberRangeWrapper] = None + else: + self.running_costs = NumberRangeWrapper( + element.running_costs.start_of_range, + element.running_costs.end_of_range, + ) + + def __eq__(self, o: object) -> bool: + if not isinstance(o, FrbcOperationModeElementWrapper): + return False + return ( + self.fill_level_range == o.fill_level_range + and self.fill_rate == o.fill_rate + and self.power_ranges == o.power_ranges + and self.running_costs == o.running_costs + ) + + def __hash__(self) -> int: + return hash( + ( + self.fill_level_range, + self.fill_rate, + tuple(self.power_ranges), + self.running_costs, + ) + ) + + +class FrbcOperationModeWrapper: + def __init__(self, frbc_operation_mode: FRBCOperationMode): + self.id = frbc_operation_mode.id + self.diagnostic_label = frbc_operation_mode.diagnostic_label + self.abnormal_condition_only = frbc_operation_mode.abnormal_condition_only + self.elements = [ + FrbcOperationModeElementWrapper(element) + for element in frbc_operation_mode.elements + ] + self.uses_factor = self.calculate_uses_factor() + + # Pre-process elements into NumPy arrays for vectorization + if self.elements: + self.fill_level_starts = np.array( + [e.fill_level_range.start_of_range for e in self.elements] + ) + self.fill_level_ends = np.array( + [e.fill_level_range.end_of_range for e in self.elements] + ) + else: + self.fill_level_starts = np.array([]) + self.fill_level_ends = np.array([]) + + def calculate_uses_factor(self) -> bool: + from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state_wrapper import ( + S2FrbcDeviceStateWrapper, + ) + + for element in self.elements: + if ( + abs(element.fill_rate.start_of_range - element.fill_rate.end_of_range) + > S2FrbcDeviceStateWrapper.epsilon + ): + return True + for power_range in element.power_ranges: + if ( + abs(power_range.start_of_range - power_range.end_of_range) + > S2FrbcDeviceStateWrapper.epsilon + ): + return True + return False + + def is_uses_factor(self) -> bool: + return self.uses_factor diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/frbc_state.py b/flexmeasures_s2/profile_steering/device_planner/frbc/frbc_state.py new file mode 100644 index 0000000..bbe2c4a --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/frbc_state.py @@ -0,0 +1,494 @@ +from datetime import datetime +from typing import Dict, Optional, Any, Tuple +import logging + +# from flask import current_app as app +from s2python.frbc import ( + FRBCSystemDescription, +) + +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +import flexmeasures_s2.profile_steering.device_planner.frbc.frbc_timestep as frbc_timestep +import flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state_wrapper as s2_frbc_device_state_wrapper + +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_actuator_configuration import ( + S2ActuatorConfiguration, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.selection_reason_result import ( + SelectionResult, + SelectionReason, +) + +logger = logging.getLogger(__name__) + + +class FrbcState: + constraint_epsilon = 1e-4 + tariff_epsilon = 0.5 + transition_cache: Dict[Any, Any] = {} + + def __init__( # noqa: C901 + self, + timestep: frbc_timestep.FrbcTimestep, + device_state: Optional[S2FrbcDeviceState] = None, + previous_state: Optional["FrbcState"] = None, + actuator_configurations: Optional[Dict[str, S2ActuatorConfiguration]] = None, + initial_fill_level: float = 0.0, + ): + self.fill_level = initial_fill_level + self.timer_elapse_map: Dict[tuple, datetime] + self.actuator_configurations: Dict[str, S2ActuatorConfiguration] + self.sum_squared_distance: float + self.sum_energy_cost: float + self.sum_squared_constraint_violation: float + self.sum_squared_energy: float + if previous_state: + if device_state: + self.device_state = ( + s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper(device_state) + ) + else: + self.device_state = previous_state.device_state + self.timestep = timestep + self.previous_state = previous_state + self.system_description = timestep.system_description + self.bucket = 0 + self.timestep_energy = 0.0 + seconds = self.timestep.get_duration_seconds() + for actuator_id, actuator_configuration in ( + actuator_configurations or {} + ).items(): + power, fill_rate = self._calculate_and_cache_op_mode_values( + previous_state, + actuator_id, + actuator_configuration, + ) + + self.timestep_energy += power * seconds + self.fill_level += fill_rate * seconds + + leakage_rate = ( + s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper.get_leakage_rate( + self.timestep, self.fill_level + ) + ) + leakage = leakage_rate * seconds + self.fill_level -= leakage + self.fill_level += self.timestep.forecasted_fill_level_usage + + self.bucket = ( + s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper.calculate_bucket( + self.timestep, self.fill_level + ) + ) + if ( + previous_state.system_description.valid_from + == self.system_description.valid_from + ): + self.timer_elapse_map = previous_state.timer_elapse_map.copy() + for ( + actuator_id, + actuator_configuration, + ) in (actuator_configurations or {}).items(): + previous_operation_mode_id = previous_state.actuator_configurations[ + actuator_id + ].operation_mode_id + new_operation_mode_id = actuator_configuration.operation_mode_id + if previous_operation_mode_id != new_operation_mode_id: + transition = s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper.get_transition( + self.timestep, + actuator_id, + previous_operation_mode_id, + new_operation_mode_id, + ) + last_timer_id = None + new_finished_at: datetime = datetime.min + if transition is not None: + for timer_id in transition.start_timers: + duration = s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper.get_timer_duration( + self.timestep, actuator_id, str(timer_id) + ) + new_finished_at = self.timestep.start_date + duration + last_timer_id = timer_id + if last_timer_id is not None: + key = FrbcState.timer_key( + actuator_id, str(last_timer_id) + ) + self.timer_elapse_map[key] = new_finished_at + else: + self.timer_elapse_map = ( + self.get_initial_timer_elapse_map_for_system_description( + self.system_description + ) + ) + # calculate scores + target = self.timestep.get_target() + if isinstance(target, TargetProfile.JouleElement): + self.sum_squared_distance = ( + previous_state.sum_squared_distance + + (target.joules - self.timestep_energy) ** 2 + ) + self.sum_energy_cost = previous_state.sum_energy_cost + elif isinstance(target, TargetProfile.TariffElement): + self.sum_squared_distance = previous_state.sum_squared_distance + # Convert Joules to kWh before multiplying by tariff + # 1 kWh = 3,600,000 Joules + energy_kwh = self.timestep_energy / 3_600_000 + cost_increment = target.tariff * energy_kwh + self.sum_energy_cost = previous_state.sum_energy_cost + cost_increment + else: + self.sum_squared_distance = previous_state.sum_squared_distance + self.sum_energy_cost = previous_state.sum_energy_cost + + squared_constraint_violation = ( + previous_state.sum_squared_constraint_violation + ) + if self.timestep.max_constraint is not None: + if self.timestep_energy > self.timestep.max_constraint: + squared_constraint_violation += ( + self.timestep_energy - self.timestep.max_constraint + ) ** 2 + if self.timestep.min_constraint is not None: + if self.timestep_energy < self.timestep.min_constraint: + squared_constraint_violation += ( + self.timestep.min_constraint - self.timestep_energy + ) ** 2 + self.sum_squared_constraint_violation = ( + previous_state.sum_squared_constraint_violation + + squared_constraint_violation + ) + self.sum_squared_energy = ( + previous_state.sum_squared_energy + self.timestep_energy**2 + ) + + self.selection_reason: Optional[SelectionReason] = None + self.actuator_configurations = { + **previous_state.actuator_configurations, + **(actuator_configurations or {}), + } + + self.timestep.add_state(self) + + else: + FrbcState.transition_cache.clear() + if device_state is not None: + self.device_state = ( + s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper(device_state) + ) + else: + self.device_state = None # type: ignore[assignment] + self.timestep = timestep + self.previous_state = None # type: ignore[assignment] + self.system_description = timestep.system_description + self.fill_level = initial_fill_level + self.bucket = 0 + self.timestep_energy = 0.0 + self.sum_squared_distance = 0.0 + self.sum_squared_constraint_violation = 0.0 + self.sum_energy_cost = 0.0 + self.sum_squared_energy = 0.0 + self.selection_reason: Optional[SelectionReason] = None # type: ignore[no-redef] + self.actuator_configurations = {} + self.timer_elapse_map = ( + self.get_initial_timer_elapse_map_for_system_description( + self.system_description + ) + ) + for a in self.device_state.actuator_statuses: + actuator_status = a + actuators = self.system_description.actuators + for actuator in actuators: + if actuator.id == a.actuator_id: + self.actuator_configurations[ + str(a.actuator_id) + ] = S2ActuatorConfiguration( + str(actuator_status.active_operation_mode_id), + actuator_status.operation_mode_factor, + ) + + @staticmethod + def get_initial_timer_elapse_map_for_system_description( + system_description: FRBCSystemDescription, + ) -> Dict[tuple, datetime]: + timer_elapse_map = {} + for actuator in system_description.actuators: + for timer in actuator.timers: + key = FrbcState.timer_key(str(actuator.id), str(timer.id)) + timer_elapse_map[key] = datetime.min # arbitrary day in the past + return timer_elapse_map + + def calculate_state_values( + self, + previous_state: "FrbcState", + actuator_configurations: Dict[str, S2ActuatorConfiguration], + ): + self.timestep_energy = 0.0 + self.fill_level = previous_state.fill_level + seconds = self.timestep.get_duration_seconds() + for actuator_id, actuator_configuration in actuator_configurations.items(): + om = self.device_state.get_operation_mode( + self.timestep, + actuator_id, + actuator_configuration.operation_mode_id, + ) + self.timestep_energy += ( + self.device_state.get_operation_mode_power( + om, + previous_state.fill_level, + actuator_configuration.factor, + ) + * seconds + ) + self.fill_level += ( + self.device_state.get_operation_mode_fill_rate( + om, + previous_state.fill_level, + actuator_configuration.factor, + ) + * seconds + ) + self.fill_level -= ( + s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper.get_leakage_rate( + self.timestep, self.fill_level + ) + * seconds + ) + self.fill_level += self.timestep.forecasted_fill_level_usage + self.bucket = ( + s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper.calculate_bucket( + self.timestep, self.fill_level + ) + ) + self.update_timers(previous_state, actuator_configurations) + self.calculate_scores(previous_state) + self.timestep.add_state(self) + + def update_timers( + self, + previous_state: "FrbcState", + actuator_configurations: Dict[str, S2ActuatorConfiguration], + ): + if ( + previous_state.system_description.valid_from + == self.system_description.valid_from + ): + self.timer_elapse_map = previous_state.timer_elapse_map.copy() + for actuator_id, actuator_configuration in actuator_configurations.items(): + previous_operation_mode_id = previous_state.actuator_configurations[ + actuator_id + ].operation_mode_id + new_operation_mode_id = actuator_configuration.operation_mode_id + if previous_operation_mode_id != new_operation_mode_id: + transition = s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper.get_transition( + self.timestep, + actuator_id, + previous_operation_mode_id, + new_operation_mode_id, + ) + if transition is None: + continue + for timer_id in transition.start_timers: + duration = s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper.get_timer_duration( + self.timestep, actuator_id, str(timer_id) + ) + new_finished_at = self.timestep.start_date + duration + key = FrbcState.timer_key(actuator_id, str(timer_id)) + self.timer_elapse_map[key] = new_finished_at + else: + self.timer_elapse_map = ( + self.get_initial_timer_elapse_map_for_system_description( + self.system_description + ) + ) + + def calculate_scores(self, previous_state: "FrbcState"): + target = self.timestep.get_target() + if isinstance(target, TargetProfile.JouleElement): + self.sum_squared_distance = ( + previous_state.sum_squared_distance + + (target.joules - self.timestep_energy) ** 2 + ) + self.sum_energy_cost = previous_state.sum_energy_cost + + else: + self.sum_squared_distance = previous_state.sum_squared_distance + self.sum_energy_cost = previous_state.sum_energy_cost + squared_constraint_violation = previous_state.sum_squared_constraint_violation + if ( + self.timestep.max_constraint is not None + and self.timestep_energy > self.timestep.max_constraint + ): + squared_constraint_violation += ( + self.timestep_energy - self.timestep.max_constraint + ) ** 2 + if ( + self.timestep.min_constraint is not None + and self.timestep_energy < self.timestep.min_constraint + ): + squared_constraint_violation += ( + self.timestep.min_constraint - self.timestep_energy + ) ** 2 + self.sum_squared_constraint_violation = ( + previous_state.sum_squared_constraint_violation + + squared_constraint_violation + ) + self.sum_squared_energy = ( + previous_state.sum_squared_energy + self.timestep_energy**2 + ) + + @staticmethod + def timer_key(actuator_id: str, timer_id: str) -> tuple: + return (actuator_id, timer_id) + + def generate_next_timestep_states(self, target_timestep): + all_actions = self.device_state.get_all_possible_actuator_configurations( + target_timestep + ) + # todo: try vectorizing this + for action in all_actions: + self.try_create_next_state(self, target_timestep, action) + + def _calculate_and_cache_op_mode_values( + self, + previous_state: "FrbcState", + actuator_id: str, + actuator_configuration: S2ActuatorConfiguration, + ) -> Tuple[float, float]: + discretized_fill_level = round(previous_state.fill_level, 4) + cache_key = ( + actuator_id, + actuator_configuration.operation_mode_id, + actuator_configuration.factor, + discretized_fill_level, + ) + if cache_key in FrbcState.transition_cache: + return FrbcState.transition_cache[cache_key] + + om = self.device_state.get_operation_mode( + self.timestep, + actuator_id, + actuator_configuration.operation_mode_id, + ) + power = self.device_state.get_operation_mode_power( + om, + previous_state.fill_level, + actuator_configuration.factor, + ) + fill_rate = self.device_state.get_operation_mode_fill_rate( + om, + previous_state.fill_level, + actuator_configuration.factor, + ) + + FrbcState.transition_cache[cache_key] = (power, fill_rate) + return power, fill_rate + + @staticmethod + def try_create_next_state( + previous_state: "FrbcState", + target_timestep, + actuator_configs_for_target_timestep: Dict[str, S2ActuatorConfiguration], + ): + if ( + previous_state.system_description.valid_from + == target_timestep.system_description.valid_from + ): + for ( + actuator_id, + actuator_configuration, + ) in actuator_configs_for_target_timestep.items(): + + # print all the keys in the previous_state.actuator_configurations + # print(previous_state.actuator_configurations.keys()) + try: + previous_operation_mode_id = previous_state.actuator_configurations[ + actuator_id + ].operation_mode_id + except KeyError: + # app.logger.debug( + # f"previous_state.actuator_configurations = {previous_state.actuator_configurations}" + # ) + raise KeyError( + f"UUID {actuator_id} not in actuator configurations" + ) from None + + new_operation_mode_id = actuator_configuration.operation_mode_id + if previous_operation_mode_id != new_operation_mode_id: + transition = s2_frbc_device_state_wrapper.S2FrbcDeviceStateWrapper.get_transition( + target_timestep, + actuator_id, + previous_operation_mode_id, + new_operation_mode_id, + ) + if transition is None: + return False + for timer_id in transition.blocking_timers: + timer_is_finished_at = previous_state.timer_elapse_map.get( + FrbcState.timer_key(actuator_id, str(timer_id)) + ) + if ( + timer_is_finished_at + and timer_is_finished_at.year != 1 + and target_timestep.start_date + < timer_is_finished_at.astimezone( + target_timestep.start_date.tzinfo + ) + ): + return False + FrbcState( + timestep=target_timestep, + previous_state=previous_state, + actuator_configurations=actuator_configs_for_target_timestep, + initial_fill_level=previous_state.fill_level, + ) + return True + + def is_preferable_than(self, other_state: "FrbcState") -> SelectionResult: + other_violation = other_state.sum_squared_constraint_violation + other_distance = other_state.sum_squared_distance + other_cost = other_state.sum_energy_cost + other_energy = other_state.sum_squared_energy + + if ( + abs(self.sum_squared_constraint_violation - other_violation) + >= self.constraint_epsilon + ): + return SelectionResult( + result=self.sum_squared_constraint_violation < other_violation, + reason=SelectionReason.CONGESTION_CONSTRAINT, + ) + elif abs(self.sum_squared_distance - other_distance) >= self.constraint_epsilon: + return SelectionResult( + result=self.sum_squared_distance < other_distance, + reason=SelectionReason.ENERGY_TARGET, + ) + elif abs(self.sum_energy_cost - other_cost) >= self.tariff_epsilon: + return SelectionResult( + result=self.sum_energy_cost < other_cost, + reason=SelectionReason.TARIFF_TARGET, + ) + else: + return SelectionResult( + result=self.sum_squared_energy < other_energy, + reason=SelectionReason.MIN_ENERGY, + ) + + def is_within_fill_level_range(self): + fill_level_range = self.system_description.storage.fill_level_range + return ( + self.fill_level >= fill_level_range.start_of_range + and self.fill_level <= fill_level_range.end_of_range + ) + + def get_fill_level_distance(self): + fill_level_range = self.system_description.storage.fill_level_range + if self.fill_level < fill_level_range.start_of_range: + return fill_level_range.start_of_range - self.fill_level + else: + return self.fill_level - fill_level_range.end_of_range + + def set_selection_reason(self, selection_reason): + self.selection_reason = selection_reason diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/frbc_timestep.py b/flexmeasures_s2/profile_steering/device_planner/frbc/frbc_timestep.py new file mode 100644 index 0000000..3950276 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/frbc_timestep.py @@ -0,0 +1,198 @@ +from datetime import datetime, timedelta +from typing import List, Optional, Dict, Tuple, TYPE_CHECKING +import logging + +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from flexmeasures_s2.profile_steering.s2_utils.number_range_wrapper import ( + NumberRangeWrapper, +) +from s2python.frbc import FRBCSystemDescription, FRBCLeakageBehaviour + +if TYPE_CHECKING: + from flexmeasures_s2.profile_steering.device_planner.frbc.frbc_state import ( + FrbcState, + ) + +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) +from enum import Enum + +logger = logging.getLogger(__name__) + + +class SelectionReason(Enum): + NO_ALTERNATIVE = "NA" + EMERGENCY_STATE = "ES" + CONGESTION_CONSTRAINT = "CC" + ENERGY_TARGET = "ET" + TARIFF_TARGET = "TT" + MIN_ENERGY = "ME" + + @property + def abbr(self) -> str: + return self.value + + +class FrbcTimestep: + def __init__( + self, + start_date: datetime, + end_date: datetime, + system_description: FRBCSystemDescription, + leakage_behaviour: FRBCLeakageBehaviour, + fill_level_target: Optional[NumberRangeWrapper], + forecasted_fill_level_usage: float, + computational_parameters: "S2FrbcDeviceState.ComputationalParameters", + **kwargs, + ): + self.system_description = system_description + self.computational_parameters = computational_parameters + self.leakage_behaviour = leakage_behaviour + self.forecasted_fill_level_usage = forecasted_fill_level_usage + self.fill_level_target = fill_level_target + self.previous_actuator_statuses: Dict[str, str] = kwargs.get( + "previous_actuator_statuses", {} + ) + self.timers: Dict[str, timedelta] = kwargs.get("timers", {}) + self._states_by_bucket: Dict[int, FrbcState] = {} + self.start_date = start_date + self.end_date = end_date + self.best_plan: Optional[FrbcState] = None + self.emergency_state: Optional[FrbcState] = None + self.target: Optional[TargetProfile.Element] = None + self.min_constraint: float = 0.0 + self.max_constraint: float = 0.0 + + # Cache for bucket calculation + self._bucket_calc_params: Optional[Tuple[float, float, int]] = None + + def get_bucket_calculation_params(self) -> Tuple[float, float, int]: + if self._bucket_calc_params is None: + fill_level_range = self.system_description.storage.fill_level_range + self._bucket_calc_params = ( + fill_level_range.start_of_range, + fill_level_range.end_of_range, + self.get_nr_of_buckets(), + ) + return self._bucket_calc_params + + def get_nr_of_buckets(self) -> int: + if self.computational_parameters is None: + raise ValueError("Computational parameters are not set") + return self.computational_parameters.get_nr_of_buckets() + + def set_targets( + self, + target: TargetProfile.Element, + min_constraint: float, + max_constraint: float, + ) -> None: + self.target = target + self.min_constraint = min_constraint + self.max_constraint = max_constraint + + def add_state(self, state: Optional["FrbcState"]) -> None: + if state is None: + return + + if state.is_within_fill_level_range(): + bucket = state.bucket + stored_state = self._states_by_bucket.get(bucket) + if stored_state is None: + self._states_by_bucket[bucket] = state + state.set_selection_reason(SelectionReason.NO_ALTERNATIVE) + # logger.debug( + # f" New state in bucket {bucket}: fill_level={state.fill_level:.2f}, energy={state.timestep_energy:.0f}" + # ) + else: + selection_result = state.is_preferable_than(stored_state) + if selection_result.result: + # logger.debug( + # f" Bucket {bucket}: Replacing state (fill_level={stored_state.fill_level:.2f}) with better state (fill_level={state.fill_level:.2f})" + # ) + # logger.debug( + # f" Reason: {selection_result.reason.value if hasattr(selection_result.reason, 'value') else selection_result.reason}" + # ) + self._states_by_bucket[bucket] = state + else: + # logger.debug( + # f" Bucket {bucket}: Keeping existing state (fill_level={stored_state.fill_level:.2f}) over new state (fill_level={state.fill_level:.2f})" + # ) + pass + self._states_by_bucket[bucket].set_selection_reason( + selection_result.reason + ) + else: + # logger.debug( + # f" State outside fill level range: fill_level={state.fill_level:.2f} (emergency state)" + # ) + pass + if ( + self.emergency_state is None + or state.get_fill_level_distance() + < self.emergency_state.get_fill_level_distance() + ): + self.emergency_state = state + state.set_selection_reason(SelectionReason.EMERGENCY_STATE) + + def add_all_states(self, states: List[Optional["FrbcState"]]) -> None: + for state in states: + self.add_state(state) + + @property + def duration(self) -> timedelta: + return self.end_date - self.start_date + + def get_duration_seconds(self) -> int: + return int(self.duration.total_seconds()) + + def get_target(self) -> Optional[TargetProfile.Element]: + return self.target + + def get_final_states(self) -> List["FrbcState"]: + final_states = list(self._states_by_bucket.values()) + + if not final_states and self.emergency_state is not None: + return [self.emergency_state] + return final_states + + def get_final_states_within_fill_level_target(self) -> List["FrbcState"]: + final_states = self.get_final_states() + if self.fill_level_target is None: + return final_states + final_states = [ + s for s in final_states if self.state_is_within_fill_level_target_range(s) + ] + if final_states: + return final_states + best_state = min( + self.get_final_states(), key=self.get_fill_level_target_distance + ) + return [best_state] + + def state_is_within_fill_level_target_range(self, state: "FrbcState") -> bool: + if self.fill_level_target is None: + return True + return ( + self.fill_level_target.start_of_range is None + or state.fill_level >= self.fill_level_target.start_of_range + ) and ( + self.fill_level_target.end_of_range is None + or state.fill_level <= self.fill_level_target.end_of_range + ) + + def get_fill_level_target_distance(self, state: "FrbcState") -> float: + if self.fill_level_target is None: + return 0 + if ( + self.fill_level_target.end_of_range is None + or state.fill_level < self.fill_level_target.start_of_range + ): + return self.fill_level_target.start_of_range - state.fill_level + else: + return state.fill_level - self.fill_level_target.end_of_range + + def clear(self) -> None: + self._states_by_bucket.clear() + self.emergency_state = None diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/operation_mode_profile_tree.py b/flexmeasures_s2/profile_steering/device_planner/frbc/operation_mode_profile_tree.py new file mode 100644 index 0000000..777aeb3 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/operation_mode_profile_tree.py @@ -0,0 +1,540 @@ +from datetime import datetime, timedelta +from typing import List, Optional, Any +import matplotlib.pyplot as plt +import matplotlib.dates as mdates +import logging + +from flexmeasures_s2.profile_steering.device_planner.frbc.frbc_timestep import ( + FrbcTimestep, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state_wrapper import ( + S2FrbcDeviceStateWrapper, +) + +from flexmeasures_s2.profile_steering.device_planner.frbc.frbc_state import FrbcState +from flexmeasures_s2.profile_steering.device_planner.frbc.fill_level_target_util import ( + FillLevelTargetUtil, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.usage_forecast_util import ( + UsageForecastUtil, +) +from flexmeasures_s2.profile_steering.s2_utils.number_range_wrapper import ( + NumberRangeWrapper, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_plan import S2FrbcPlan +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.soc_profile import SoCProfile +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from pint import UnitRegistry + +SI = UnitRegistry() +logger = logging.getLogger(__name__) + + +# TODO: Add S2FrbcInsightsProfile?->Update 08-02-2025: Not needed for now + + +def plot_planning_results( + timestep_start_times, energy_elements, fill_level_elements, operation_mode_ids, ids +): + """ + Plots the energy, fill level, actuator usage, and operation mode ID lists using matplotlib. + + :param timestep_start_times: List of datetime objects representing the start time of each timestep. + :param energy_elements: List of energy values. + :param fill_level_elements: List of fill level values. + :param operation_mode_ids: List of dictionaries with actuator configurations. + :param ids: List of tuples (id, name) for debugging. + """ + # Create a figure and a set of subplots + fig, axs = plt.subplots(4, 1, figsize=(12, 16), sharex=True) + + # Plot energy elements + axs[0].plot(timestep_start_times, energy_elements, label="Energy", color="blue") + axs[0].set_ylabel("Energy (Joules)") + axs[0].legend(loc="upper right") + axs[0].grid(True) + + # Plot fill level elements + axs[1].plot( + timestep_start_times, fill_level_elements, label="Fill Level", color="green" + ) + axs[1].set_ylabel("Fill Level (%)") + axs[1].legend(loc="upper right") + axs[1].grid(True) + + # Create a dictionary from the list of tuples for easier lookup + id_to_name = {id_val: name for id_val, name in ids} + + # Create a color mapping for names + unique_names = set(name for _, name in ids) + actuator_colors = {name: f"C{i}" for i, name in enumerate(unique_names)} + + # Plot actuator usage + for i, (time, config) in enumerate(zip(timestep_start_times, operation_mode_ids)): + for actuator_id, config in config.items(): + actuator_name = id_to_name.get(str(actuator_id), str(actuator_id)) + axs[2].scatter( + time, + actuator_name, + color=actuator_colors.get(actuator_name, "black"), + label=actuator_name if i == 0 else "", + ) + axs[2].set_ylabel("Actuator Name") + handles, labels = axs[2].get_legend_handles_labels() + by_label = dict(zip(labels, handles)) + axs[2].legend(by_label.values(), by_label.keys(), loc="upper right") + axs[2].grid(True) + + # Plot operation modes + for i, (time, config) in enumerate(zip(timestep_start_times, operation_mode_ids)): + for actuator_id, config in config.items(): + operation_mode_id = getattr(config, "operation_mode_id", None) + if operation_mode_id: + operation_mode_name = id_to_name.get( + str(operation_mode_id), str(operation_mode_id) + ) + axs[3].scatter( + time, + operation_mode_name, + color=actuator_colors.get(operation_mode_name, "black"), + label=operation_mode_name if i == 0 else "", + ) + axs[3].set_ylabel("Operation Mode Name") + handles, labels = axs[3].get_legend_handles_labels() + by_label = dict(zip(labels, handles)) + axs[3].legend(by_label.values(), by_label.keys(), loc="upper right") + axs[3].grid(True) + + # Format the x-axis to show time and set ticks every 30 minutes + axs[3].xaxis.set_major_locator(mdates.MinuteLocator(interval=30)) + axs[3].xaxis.set_major_formatter(mdates.DateFormatter("%H:%M:%S")) + fig.autofmt_xdate() + + # Adjust layout + plt.tight_layout() + plt.show() + + +class OperationModeProfileTree: + def __init__( + self, + device_state: S2FrbcDeviceState, + profile_metadata: ProfileMetadata, + plan_due_by_date: datetime, + ): + self.device_state = S2FrbcDeviceStateWrapper(device_state) + self.profile_metadata = profile_metadata + self.plan_due_by_date = plan_due_by_date + self.timestep_duration_seconds = int( + profile_metadata.timestep_duration.total_seconds() + ) + self.timesteps: List[FrbcTimestep] = [] + self.generate_timesteps() + + def generate_timesteps(self) -> None: + # logger.info("=" * 80) + # logger.info("GENERATING TIMESTEPS") + # logger.info("=" * 80) + # logger.info(f"Profile start: {self.profile_metadata.profile_start}") + # logger.info(f"Number of timesteps: {self.profile_metadata.nr_of_timesteps}") + # logger.info(f"Timestep duration: {self.profile_metadata.timestep_duration}") + # logger.info(f"Plan due by date: {self.plan_due_by_date}") + + time_step_start = self.profile_metadata.profile_start + for i in range(self.profile_metadata.nr_of_timesteps): + time_step_end = time_step_start + self.profile_metadata.timestep_duration + + if i == 0: + time_step_start = self.plan_due_by_date + # logger.debug( + # f"Timestep {i}: Adjusted start to plan_due_by_date: {time_step_start}" + # ) + + system_default_timezone = time_step_start.astimezone().tzinfo + time_step_start_dt = time_step_start.astimezone(system_default_timezone) + current_system_description = self.get_latest_before( + time_step_start_dt, + self.device_state.get_system_descriptions(), + lambda sd: sd.valid_from, + ) + current_leakage_behaviour = self.get_latest_before( + time_step_start_dt, + self.device_state.get_leakage_behaviours(), + lambda lb: lb.valid_from, + ) + current_fill_level = self.get_latest_before( + time_step_start_dt, + self.device_state.fill_level_target_profiles, + lambda fl: fl.start_time, + ) + current_fill_level_target = None + if current_fill_level: + current_fill_level_target = ( + FillLevelTargetUtil.from_fill_level_target_profile( + current_fill_level + ) + ) + fill_level_target = self.get_fill_level_target_for_timestep( + current_fill_level_target, time_step_start, time_step_end + ) + current_usage_forecast = self.get_latest_before( + time_step_start_dt, + self.device_state.usage_forecasts, + lambda uf: uf.start_time, + ) + current_usage_forecast_profile = None + if current_usage_forecast: + current_usage_forecast_profile = ( + UsageForecastUtil.from_storage_usage_profile(current_usage_forecast) + ) + + usage_forecast = self.get_usage_forecast_for_timestep( + current_usage_forecast_profile, time_step_start, time_step_end + ) + + # Log timestep details every 10 timesteps and first/last + if i % 10 == 0 or i == 0 or i == self.profile_metadata.nr_of_timesteps - 1: + # logger.info( + # f"Timestep {i}: {time_step_start.strftime('%H:%M:%S')} -> {time_step_end.strftime('%H:%M:%S')}" + # ) + # if fill_level_target: + # logger.info( + # f" Fill level target: [{fill_level_target.start_of_range}, {fill_level_target.end_of_range}]" + # ) + # else: + # logger.info(" Fill level target: None") + # logger.info(f" Usage forecast: {usage_forecast}") + # if current_leakage_behaviour: + # logger.info(" Leakage behaviour: present") + # else: + # logger.info(" Leakage behaviour: None") + pass + + self.timesteps.append( + FrbcTimestep( + time_step_start.astimezone(system_default_timezone), + time_step_end.astimezone(system_default_timezone), + current_system_description, + current_leakage_behaviour, + fill_level_target, + usage_forecast, + self.device_state.get_computational_parameters(), + ) + ) + time_step_start = time_step_end + + # logger.info(f"Generated {len(self.timesteps)} timesteps") + # logger.info("=" * 80) + + @staticmethod + def get_latest_before(before, select_from, get_date_time): + latest_before = None + latest_before_date_time = None + if select_from: + for current in select_from: + if current: + current_date_time = get_date_time(current).replace(tzinfo=None) + before = before.replace(tzinfo=None) + if current_date_time <= before and ( + latest_before is None + or current_date_time > latest_before_date_time + ): + latest_before = current + latest_before_date_time = current_date_time + return latest_before + + @staticmethod + def get_fill_level_target_for_timestep( + fill_level_target_profile: Optional[Any], + time_step_start: datetime, + time_step_end: datetime, + ) -> Optional[NumberRangeWrapper]: + if not fill_level_target_profile: + return None + time_step_end -= timedelta(milliseconds=1) + lower, upper = None, None + for e in FillLevelTargetUtil.get_elements_in_range( + fill_level_target_profile, time_step_start, time_step_end + ): + if e.lower_limit is not None and (lower is None or e.lower_limit > lower): + lower = e.lower_limit + if e.upper_limit is not None and (upper is None or e.upper_limit < upper): + upper = e.upper_limit + if lower is None and upper is None: + return None + return NumberRangeWrapper(lower, upper) + + @staticmethod + def get_usage_forecast_for_timestep( + usage_forecast: Optional[Any], + time_step_start: datetime, + time_step_end: datetime, + ) -> float: + if not usage_forecast: + return 0 + time_step_end -= timedelta(milliseconds=1) + usage = 0 + usage = UsageForecastUtil.sub_profile( + usage_forecast=usage_forecast, + time_step_start=time_step_start, + time_step_end=time_step_end, + ) + + return usage + + def find_best_plan( + self, + target_profile: TargetProfile, + diff_to_min_profile: Any, + diff_to_max_profile: Any, + ids: Optional[dict] = None, + ) -> S2FrbcPlan: + # logger.info("=" * 80) + # logger.info("FINDING BEST PLAN") + # logger.info("=" * 80) + + # Set targets for each timestep + for i, ts in enumerate(self.timesteps): + ts.clear() + target_element = target_profile.elements[i] + if target_element is not None: + ts.set_targets( + target_element, + diff_to_min_profile.elements[i], + diff_to_max_profile.elements[i], + ) + if i % 10 == 0 or i == 0 or i == len(self.timesteps) - 1: + # logger.debug( + # f"Timestep {i} target: {target_element}, diff_min: {diff_to_min_profile.elements[i]}, diff_max: {diff_to_max_profile.elements[i]}" + # ) + pass + + first_timestep_index = next( + (i for i, ts in enumerate(self.timesteps) if ts.system_description), + -1, + ) + # logger.info(f"First timestep with system description: {first_timestep_index}") + + first_timestep = self.timesteps[first_timestep_index] + last_timestep = self.timesteps[-1] + + initial_fill_level = ( + self.device_state.device_state.storage_status.present_fill_level + ) + # logger.info(f"Initial fill level: {initial_fill_level}") + + state_zero = FrbcState( + device_state=self.device_state.device_state, + timestep=first_timestep, + initial_fill_level=initial_fill_level, + ) + + # logger.info(f"Generating states for initial timestep {first_timestep_index}...") + state_zero.generate_next_timestep_states(first_timestep) + initial_states = first_timestep.get_final_states_within_fill_level_target() + # logger.info(f"Generated {len(initial_states)} initial states") + + # Sample some initial states to log + if initial_states: + for idx, state in enumerate(initial_states[:3]): # Log first 3 states + # logger.debug( + # f" Initial state {idx}: fill_level={state.fill_level:.2f}, energy={state.timestep_energy}, cost={getattr(state, 'cost', 'N/A')}" + # ) + pass + + # Generate states for each timestep + for i in range(first_timestep_index, len(self.timesteps) - 1): + current_timestep = self.timesteps[i] + next_timestep = self.timesteps[i + 1] + final_states = current_timestep.get_final_states_within_fill_level_target() + + # Log progress every 10 timesteps + if i % 10 == 0 or i == first_timestep_index: + # logger.info( + # f"Timestep {i}: Processing {len(final_states)} states -> generating states for timestep {i+1}" + # ) + # if final_states: + # # Log sample states + # for idx, state in enumerate(final_states[:2]): # Log first 2 states + # logger.debug( + # f" State {idx}: fill_level={state.fill_level:.2f}, energy={state.timestep_energy}, bucket={getattr(state, 'bucket_index', 'N/A')}" + # ) + pass + + for frbc_state in final_states: + frbc_state.generate_next_timestep_states(next_timestep) + + # Find best end state + final_states = last_timestep.get_final_states_within_fill_level_target() + # logger.info(f"Final timestep has {len(final_states)} states") + + if final_states: + for idx, state in enumerate(final_states[:5]): # Log first 5 final states + # cost = getattr(state, "sum_energy_cost", "N/A") + # constraint_violation = getattr( + # state, "sum_squared_constraint_violation", "N/A" + # ) + # logger.info( + # f" Final state {idx}: fill_level={state.fill_level:.2f}, energy={state.timestep_energy:.0f}, cost={cost}, constraint_violation={constraint_violation}" + # ) + pass + + end_state = self.find_best_end_state(final_states) + # logger.info( + # f"Best end state selected: fill_level={end_state.fill_level:.2f}, energy={end_state.timestep_energy:.0f}" + # ) + # logger.info( + # f" Selection reason: {getattr(end_state, 'selection_reason', 'N/A')}" + # ) + # logger.info( + # f" Best state cost: {getattr(end_state, 'sum_energy_cost', 'N/A')}" + # ) + # logger.info( + # f" Best state constraint_violation: {getattr(end_state, 'sum_squared_constraint_violation', 'N/A')}" + # ) + + plan = self.convert_to_plan(first_timestep_index, end_state) + + # logger.info("=" * 80) + # logger.info("PLAN GENERATION COMPLETE") + # logger.info("=" * 80) + + return plan + + @staticmethod + def find_best_end_state(states: List[FrbcState]) -> FrbcState: + # logger.info(f"Comparing {len(states)} end states to find best...") + best_state = states[0] + comparisons = 0 + + # best_cost = getattr(best_state, "sum_energy_cost", 0) + # best_violation = getattr(best_state, "sum_squared_constraint_violation", 0) + # logger.info( + # f" Initial best state: fill_level={best_state.fill_level:.2f}, energy={best_state.timestep_energy:.0f}, cost={best_cost:.4f}, violation={best_violation:.4f}" + # ) + + for idx, state in enumerate(states[1:], 1): + # state_cost = getattr(state, "sum_energy_cost", 0) + # state_violation = getattr(state, "sum_squared_constraint_violation", 0) + comparison_result = state.is_preferable_than(best_state) + + if idx <= 5: # Log first 5 comparisons + # logger.info( + # f" Comparing state {idx}: fill_level={state.fill_level:.2f}, energy={state.timestep_energy:.0f}, cost={state_cost:.4f}, violation={state_violation:.4f}" + # ) + # logger.info( + # f" Comparison result: {comparison_result.result}, reason: {comparison_result.reason if hasattr(comparison_result, 'reason') else 'N/A'}" + # ) + # logger.info( + # f" Cost difference: {abs(state_cost - best_cost):.4f}, tariff_epsilon: {FrbcState.tariff_epsilon}" + # ) + pass + + if comparison_result.result: + # logger.info( + # f" State {idx} is BETTER: fill_level={state.fill_level:.2f} vs {best_state.fill_level:.2f}" + # ) + # logger.info( + # f" Reason: {comparison_result.reason if hasattr(comparison_result, 'reason') else 'N/A'}" + # ) + best_state = state + # best_cost = state_cost + # best_violation = state_violation + comparisons += 1 + + # logger.info(f"Best state found after {comparisons} preference changes") + # logger.info( + # f" Final best: fill_level={best_state.fill_level:.2f}, energy={best_state.timestep_energy:.0f}, cost={best_cost:.4f}" + # ) + return best_state + + def convert_to_plan( + self, first_timestep_index_with_state: int, end_state: FrbcState + ) -> S2FrbcPlan: + # logger.info("Converting end state to plan...") + # logger.info(f" First timestep index: {first_timestep_index_with_state}") + + energy: List[int] = [0] * self.profile_metadata.nr_of_timesteps + fill_level: List[float] = [0.0] * self.profile_metadata.nr_of_timesteps + actuators: List[dict] = [{}] * self.profile_metadata.nr_of_timesteps + insight_elements = [None] * self.profile_metadata.nr_of_timesteps + state_selection_reasons: List[str] = [ + "" + ] * self.profile_metadata.nr_of_timesteps + + state = end_state + states_traced = 0 + + # Trace back through states + for i in range(self.profile_metadata.nr_of_timesteps - 1, -1, -1): + if i >= first_timestep_index_with_state: + energy[i] = int(state.timestep_energy) + fill_level[i] = state.fill_level + actuators[i] = state.actuator_configurations + state_selection_reasons[i] = state.selection_reason # type: ignore + + # Log every 10 states + if i % 10 == 0 or i == first_timestep_index_with_state: + # logger.debug( + # f" Timestep {i}: energy={energy[i]}, fill_level={fill_level[i]:.2f}, actuator_configs={len(actuators[i])} actuator(s)" + # ) + # if actuators[i]: + # for actuator_id, config in actuators[i].items(): + # mode_id = getattr(config, "operation_mode_id", "N/A") + # logger.debug( + # f" Actuator {str(actuator_id)[:8]}...: mode {str(mode_id)[:8]}..." + # ) + pass + + state = state.previous_state + states_traced += 1 + else: + energy[i] = 0 + fill_level[i] = 0.0 + actuators[i] = {} + insight_elements[i] = None + + # logger.info(f"Traced back through {states_traced} states") + + # Add current energy + current_energy = self.device_state.get_energy_in_current_timestep().value + # logger.info(f"Adding current timestep energy: {current_energy}") + energy[0] += current_energy + + # Calculate plan statistics + # total_energy = sum(energy) + # avg_fill_level = sum(fill_level) / len(fill_level) if fill_level else 0 + # mode_changes = 0 + # prev_mode = None + # for actuator_config in actuators: + # for actuator_id, config in actuator_config.items(): + # mode_id = getattr(config, "operation_mode_id", None) + # if mode_id and mode_id != prev_mode: + # mode_changes += 1 + # prev_mode = mode_id + + # logger.info("Plan statistics:") + # logger.info( + # f" Total energy: {total_energy} J ({total_energy/3600000:.2f} kWh)" + # ) + # logger.info(f" Average fill level: {avg_fill_level:.2f}") + # logger.info(f" Operation mode changes: {mode_changes}") + + return S2FrbcPlan( + False, + JouleProfile( + profile_start=self.profile_metadata.profile_start, + timestep_duration=self.profile_metadata.timestep_duration, + elements=energy, # type: ignore[arg-type] + ), + SoCProfile( + self.profile_metadata, + fill_level, + ), + actuators, + ) diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_actuator_configuration.py b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_actuator_configuration.py new file mode 100644 index 0000000..3a10f36 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_actuator_configuration.py @@ -0,0 +1,19 @@ +from typing import Dict, Any + +# TODO: Should this just be an actuator description + + +class S2ActuatorConfiguration: + def __init__(self, operation_mode_id: str, factor): + self.operation_mode_id = operation_mode_id + self.factor = factor + + def to_dict(self): + return {"operationModeId": self.operation_mode_id, "factor": self.factor} + + @staticmethod + def from_dict(data: Dict[str, Any]) -> "S2ActuatorConfiguration": + return S2ActuatorConfiguration(str(data["operationModeId"]), data["factor"]) + + def __str__(self): + return f"S2ActuatorConfiguration [operationModeId={self.operation_mode_id}, factor={self.factor}]" diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_device_planner.py b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_device_planner.py new file mode 100644 index 0000000..4315ab0 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_device_planner.py @@ -0,0 +1,342 @@ +from datetime import datetime +from typing import Optional + +# import logging + +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.proposal import Proposal +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_plan import S2FrbcPlan +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_instruction_profile import ( + S2FrbcInstructionProfile, +) +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from flexmeasures_s2.profile_steering.common.device_plan import ( + DevicePlan, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.operation_mode_profile_tree import ( + OperationModeProfileTree, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.device_planner_abstract import ( + DevicePlanner, +) +from s2python.frbc import FRBCInstruction + + +class S2FrbcDevicePlanner(DevicePlanner): + def __init__( + self, + s2_frbc_state: S2FrbcDeviceState, + profile_metadata: ProfileMetadata, + plan_due_by_date: datetime, + congestion_point_id: str, + ): + self._congestion_point_id = congestion_point_id + self.s2_frbc_state = s2_frbc_state + self.profile_metadata = profile_metadata + self.zero_profile = JouleProfile( + profile_metadata.profile_start, + profile_metadata.timestep_duration, + [0] * profile_metadata.nr_of_timesteps, + ) + self.null_profile = JouleProfile( + profile_metadata.profile_start, + profile_metadata.timestep_duration, + elements=[None] * profile_metadata.nr_of_timesteps, + ) + if self.is_storage_available(self.s2_frbc_state): + self.state_tree = OperationModeProfileTree( + self.s2_frbc_state, + profile_metadata, + plan_due_by_date, + ) + self._priority_class = 1 + self.latest_plan: Optional[S2FrbcPlan] = None + self.accepted_plan: Optional[S2FrbcPlan] = None + + def is_storage_available(self, storage_state: S2FrbcDeviceState) -> bool: + latest_before_first_ptu = OperationModeProfileTree.get_latest_before( + self.profile_metadata.profile_start.replace(tzinfo=None), + storage_state.get_system_descriptions(), + lambda sd: sd.valid_from.replace(tzinfo=None), + ) + if not storage_state.get_system_descriptions(): + return False + if latest_before_first_ptu is None: + active_and_upcoming_system_descriptions_has_active_storage = any( + # TODO: ask if TypeError: can't compare offset-naive and offset-aware datetimes could be solved differently + self.profile_metadata.profile_end.replace(tzinfo=None) + >= sd.valid_from.replace(tzinfo=None) + >= self.profile_metadata.profile_start.replace(tzinfo=None) + for sd in storage_state.get_system_descriptions() + ) + else: + active_and_upcoming_system_descriptions_has_active_storage = any( + self.profile_metadata.profile_end.replace(tzinfo=None) + >= sd.valid_from.replace(tzinfo=None) + >= latest_before_first_ptu.valid_from.replace(tzinfo=None) + for sd in storage_state.get_system_descriptions() + ) + return ( + storage_state.is_online + and active_and_upcoming_system_descriptions_has_active_storage + ) + + @property + def priority_class(self) -> int: + return self.s2_frbc_state.priority_class + + @property + def device_id(self) -> str: + return self.s2_frbc_state.device_id + + @property + def connection_id(self) -> str: + return self.s2_frbc_state.connection_id + + @property + def congestion_point_id(self) -> str: + return self._congestion_point_id + + @property + def device_name(self) -> str: + return self.s2_frbc_state.device_name + + def create_improved_planning( + self, + diff_to_global_target: TargetProfile, + diff_to_max: JouleProfile, + diff_to_min: JouleProfile, + plan_due_by_date: datetime, + ) -> Proposal: + if self.accepted_plan is None: + raise ValueError("No accepted plan found") + + # print(f"\n{'='*80}") + # print(f"DEVICE PLANNER: create_improved_planning for {self.device_name}") + # print( + # f" Accepted plan energy: {sum(self.accepted_plan.energy.elements) if self.accepted_plan.energy else 0} J" + # ) + # print( + # f" diff_to_global_target has Joule elements: {diff_to_global_target.nr_of_joule_target_elements()}" + # ) + # print( + # f" diff_to_global_target nr_of_timesteps: {diff_to_global_target.metadata.nr_of_timesteps}" + # ) + + # Count tariff elements + # tariff_count = sum( + # 1 + # for e in diff_to_global_target.elements + # if isinstance(e, TargetProfile.TariffElement) + # ) + # null_count = sum( + # 1 + # for e in diff_to_global_target.elements + # if isinstance(e, TargetProfile.NullElement) + # ) + # print( + # f" Target elements: {tariff_count} TariffElement, {null_count} NullElement, {len(diff_to_global_target.elements)} total" + # ) + + # Show sample tariff values + # if tariff_count > 0: + # sample_tariffs = [ + # e.get_tariff() + # for e in diff_to_global_target.elements[:10] + # if isinstance(e, TargetProfile.TariffElement) + # ] + # print(f" Sample tariff values (first 10): {sample_tariffs}") + pass + + # TODO: check if diff_to_global_target has tarrif elements + # TODO: check for NULL elements in target + if diff_to_global_target.nr_of_joule_target_elements() != 0: + target = diff_to_global_target.add(self.accepted_plan.energy) + else: + target = diff_to_global_target + # print( + # "diff_to_global_target has no Joule elements, using the target directly" + # ) + pass + + # print(" Final target for find_best_plan:") + # tariff_count_final = sum( + # 1 for e in target.elements if isinstance(e, TargetProfile.TariffElement) + # ) + # null_count_final = sum( + # 1 for e in target.elements if isinstance(e, TargetProfile.NullElement) + # ) + # print(f" {tariff_count_final} TariffElement, {null_count_final} NullElement") + # print(f"{'='*80}\n") + + max_profile = diff_to_max.add(self.accepted_plan.energy) + min_profile = diff_to_min.add(self.accepted_plan.energy) + + if self.is_storage_available(self.s2_frbc_state): + self.latest_plan = self.state_tree.find_best_plan( + target, min_profile, max_profile + ) + + # Log the new plan + # new_energy = ( + # sum(self.latest_plan.energy.elements) + # if self.latest_plan and self.latest_plan.energy + # else 0 + # ) + # print(f" New plan energy: {new_energy} J") + # print( + # f" Energy difference: {new_energy - sum(self.accepted_plan.energy.elements)} J" + # ) + else: + self.latest_plan = S2FrbcPlan( + idle=True, + energy=self.zero_profile, + fill_level=None, + operation_mode_id=[], + ) + if self.latest_plan is None: + raise ValueError("No latest plan found") + proposal = Proposal( + global_diff_target=diff_to_global_target, + diff_to_congestion_max=diff_to_max, + diff_to_congestion_min=diff_to_min, + proposed_plan=self.latest_plan.energy, + old_plan=self.accepted_plan.energy, + origin=self, + ) + return proposal + + def create_initial_planning( + self, plan_due_by_date: datetime, ids: Optional[dict] = None + ) -> S2FrbcPlan: + if self.is_storage_available(self.s2_frbc_state): + if ids is None: + self.latest_plan = self.state_tree.find_best_plan( + TargetProfile.null_profile(self.profile_metadata), + self.null_profile, + self.null_profile, + ) + else: + self.latest_plan = self.state_tree.find_best_plan( + TargetProfile.null_profile(self.profile_metadata), + self.null_profile, + self.null_profile, + ids, + ) + else: + self.latest_plan = S2FrbcPlan( + idle=True, + energy=self.zero_profile, + fill_level=None, + operation_mode_id=[], + ) + self.accepted_plan = self.latest_plan + return self.latest_plan + + def accept_proposal(self, accepted_proposal: Proposal) -> None: + if self.latest_plan is None: + raise ValueError("No latest plan found") + if accepted_proposal.origin != self: + raise ValueError( + f"Storage controller '{self.device_id}' received a proposal that he did not send." + ) + if not accepted_proposal.proposed_plan == self.latest_plan.energy: + raise ValueError( + f"Storage controller '{self.device_id}' received a proposal that he did not send." + ) + if accepted_proposal.get_congestion_improvement_value() < 0: + raise ValueError( + f"Storage controller '{self.device_id}' received a proposal with negative improvement" + ) + self.accepted_plan = self.latest_plan + + def get_latest_plan(self) -> Optional[S2FrbcPlan]: + return self.latest_plan + + def set_accepted_plan(self, plan: S2FrbcPlan) -> None: + if not isinstance(plan, S2FrbcPlan): + raise TypeError(f"Expected S2FrbcPlan, but got {type(plan)}") + self.accepted_plan = plan + + def current_profile(self) -> JouleProfile: + if self.accepted_plan is None: + raise ValueError("No accepted plan found") + return self.accepted_plan.energy + + def get_device_plan(self) -> Optional[DevicePlan]: + if self.accepted_plan is None: + return None + # logging.debug( + # dict( + # device_id=self.device_id, + # device_name=self.device_name, + # connection_id=self.connection_id, + # energy_profile=self.accepted_plan.energy, + # fill_level_profile=self.accepted_plan.fill_level, + # instruction_profile=self.convert_plan_to_instructions( + # self.profile_metadata, self.accepted_plan + # ), + # ) + # ) + return DevicePlan( + device_id=self.device_id, + device_name=self.device_name, + connection_id=self.connection_id, + energy_profile=self.accepted_plan.energy, + fill_level_profile=self.accepted_plan.fill_level, + instruction_profile=self.convert_plan_to_instructions( + self.profile_metadata, self.accepted_plan + ), + ) + + @staticmethod + def convert_plan_to_instructions( + profile_metadata: ProfileMetadata, device_plan: S2FrbcPlan + ) -> S2FrbcInstructionProfile: + import uuid + from datetime import timedelta + + elements = [] + actuator_configurations_per_timestep = device_plan.get_operation_mode_id() + + if actuator_configurations_per_timestep is not None: + for timestep_index, actuator_configurations_dict in enumerate( + actuator_configurations_per_timestep + ): + # Calculate execution time for this timestep + execution_time = profile_metadata.profile_start + timedelta( + seconds=timestep_index + * profile_metadata.timestep_duration.total_seconds() + ) + # Ensure timezone-aware datetime + if execution_time.tzinfo is None: + from datetime import timezone + + execution_time = execution_time.replace(tzinfo=timezone.utc) + + # Create instructions for each actuator at this timestep + for ( + actuator_id, + actuator_config, + ) in actuator_configurations_dict.items(): + if actuator_config is not None: + instruction = FRBCInstruction( + message_id=str(uuid.uuid4()), + id=str(uuid.uuid4()), + actuator_id=str(actuator_id), + operation_mode=str(actuator_config.operation_mode_id), + operation_mode_factor=float(actuator_config.factor), + execution_time=execution_time, + abnormal_condition=False, + ) + elements.append(instruction) + + return S2FrbcInstructionProfile( + profile_start=profile_metadata.profile_start, + timestep_duration=profile_metadata.timestep_duration, + elements=elements, + ) diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_device_state.py b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_device_state.py new file mode 100644 index 0000000..8a27c99 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_device_state.py @@ -0,0 +1,76 @@ +from datetime import datetime +from typing import List, Optional +from s2python.common import PowerForecast +from s2python.frbc import ( + FRBCSystemDescription, + FRBCLeakageBehaviour, + FRBCUsageForecast, + FRBCFillLevelTargetProfile, +) +from s2python.frbc.frbc_actuator_status import FRBCActuatorStatus +from s2python.generated.gen_s2 import FRBCStorageStatus, PowerValue + + +class S2FrbcDeviceState: + class ComputationalParameters: + def __init__(self, nr_of_buckets: int, stratification_layers: int): + self.nr_of_buckets = nr_of_buckets + self.stratification_layers = stratification_layers + + def get_nr_of_buckets(self) -> int: + return self.nr_of_buckets + + def get_stratification_layers(self) -> int: + return self.stratification_layers + + def __init__( + self, + device_id: str, + device_name: str, + connection_id: str, + priority_class: int, + timestamp: datetime, + energy_in_current_timestep: PowerValue, + is_online: bool, + power_forecast: Optional[PowerForecast], + system_descriptions: List[FRBCSystemDescription], + leakage_behaviours: List[FRBCLeakageBehaviour], + usage_forecasts: List[FRBCUsageForecast], + fill_level_target_profiles: List[FRBCFillLevelTargetProfile], + computational_parameters: ComputationalParameters, + storage_status: FRBCStorageStatus = None, + actuator_statuses: Optional[List[FRBCActuatorStatus]] = None, + ): + self.device_id = device_id + self.device_name = device_name + self.connection_id = connection_id + self.priority_class = priority_class + self.timestamp = timestamp + self.energy_in_current_timestep = energy_in_current_timestep + self.is_online = is_online + self.power_forecast = power_forecast + self.system_descriptions = system_descriptions + self.leakage_behaviours = leakage_behaviours + self.usage_forecasts = usage_forecasts + self.fill_level_target_profiles = fill_level_target_profiles + self.computational_parameters = computational_parameters + self.storage_status = storage_status + self.actuator_statuses = actuator_statuses + + def get_system_descriptions(self) -> List[FRBCSystemDescription]: + return self.system_descriptions + + def get_leakage_behaviours(self) -> List[FRBCLeakageBehaviour]: + return self.leakage_behaviours + + def get_device_name(self) -> str: + return self.device_name + + def get_computational_parameters(self) -> ComputationalParameters: + return self.computational_parameters + + def get_power_forecast(self) -> Optional[PowerForecast]: + return self.power_forecast + + def get_energy_in_current_timestep(self) -> PowerValue: + return self.energy_in_current_timestep diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_device_state_wrapper.py b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_device_state_wrapper.py new file mode 100644 index 0000000..a4ec7de --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_device_state_wrapper.py @@ -0,0 +1,340 @@ +from datetime import datetime, timedelta +from typing import Dict, List, Optional, Any, TYPE_CHECKING +from functools import lru_cache +import numpy as np + +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_actuator_configuration import ( + S2ActuatorConfiguration, +) +from s2python.common import CommodityQuantity +from flexmeasures_s2.profile_steering.device_planner.frbc.frbc_operation_mode_wrapper import ( + FrbcOperationModeWrapper, +) + +if TYPE_CHECKING: + from flexmeasures_s2.profile_steering.device_planner.frbc.frbc_timestep import ( + FrbcTimestep, + ) + +from s2python.common.transition import Transition +from s2python.frbc import ( + FRBCLeakageBehaviour, + FRBCLeakageBehaviourElement, + FRBCActuatorDescription, + FRBCActuatorStatus, + FRBCStorageStatus, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) + + +class S2FrbcDeviceStateWrapper: + epsilon = 1e-4 + + def __init__(self, device_state: S2FrbcDeviceState): + self.device_state: S2FrbcDeviceState = device_state + computational_params = self.device_state.get_computational_parameters() + self.nr_of_buckets: int = computational_params.get_nr_of_buckets() + self.nr_of_stratification_layers: int = ( + computational_params.get_stratification_layers() + ) + self.actuator_operation_mode_map_per_timestep: Dict[ + datetime, Dict[str, List[str]] + ] = {} + self.all_actions: Dict[datetime, List[Dict[str, S2ActuatorConfiguration]]] = {} + self.operation_mode_uses_factor_map: Dict[str, bool] = {} + self.operation_modes: Dict[str, FrbcOperationModeWrapper] = {} + + @property + def is_online(self) -> bool: + return self.device_state.is_online + + def get_power_forecast(self) -> Any: + return self.device_state.get_power_forecast() + + def get_system_descriptions(self) -> Any: + return self.device_state.get_system_descriptions() + + def get_leakage_behaviours(self) -> Any: + return self.device_state.get_leakage_behaviours() + + @property + def usage_forecasts(self) -> Any: + return self.device_state.usage_forecasts + + @property + def fill_level_target_profiles(self) -> Any: + return self.device_state.fill_level_target_profiles + + def get_computational_parameters(self) -> Any: + return self.device_state.get_computational_parameters() + + @lru_cache(maxsize=None) + def get_actuators(self, target_timestep: "FrbcTimestep") -> List[str]: + return list(self.create_actuator_operation_mode_map(target_timestep).keys()) + + @lru_cache(maxsize=None) + def get_normal_operation_modes_for_actuator( + self, target_timestep: "FrbcTimestep", actuator_id: str + ) -> List[str]: + actuator_operation_mode_map = self.create_actuator_operation_mode_map( + target_timestep + ) + return actuator_operation_mode_map.get(actuator_id, []) + + @lru_cache(maxsize=None) + def create_actuator_operation_mode_map( + self, target_timestep: "FrbcTimestep" + ) -> Dict[str, List[str]]: + actuator_operation_mode_map = {} + for a in target_timestep.system_description.actuators: + actuator_operation_mode_map[str(a.id)] = [ + str(om.id) for om in a.operation_modes if not om.abnormal_condition_only + ] + return actuator_operation_mode_map + + @lru_cache(maxsize=None) + def get_operation_mode( + self, target_timestep, actuator_id: str, operation_mode_id: str + ): + om_key = f"{actuator_id}-{operation_mode_id}" + if om_key in self.operation_modes: + return self.operation_modes[om_key] + + actuator_description = self.get_actuator_description( + target_timestep, actuator_id + ) + if actuator_description: + for operation_mode in actuator_description.operation_modes: + if str(operation_mode.id) == operation_mode_id: + found_operation_mode = FrbcOperationModeWrapper(operation_mode) + self.operation_modes[om_key] = found_operation_mode + return found_operation_mode + return None + + @lru_cache(maxsize=None) + def operation_mode_uses_factor( + self, + target_timestep: "FrbcTimestep", + actuator_id: str, + operation_mode_id: str, + ) -> bool: + return self.get_operation_mode( + target_timestep, actuator_id, operation_mode_id + ).is_uses_factor() + + @lru_cache(maxsize=None) + def get_all_possible_actuator_configurations( + self, target_timestep: "FrbcTimestep" + ) -> List[Dict[Any, S2ActuatorConfiguration]]: + possible_actuator_configs = {} + for actuator_id in self.get_actuators(target_timestep): + actuator_list = [] + for op_mode_id in self.get_normal_operation_modes_for_actuator( + target_timestep, actuator_id + ): + if self.operation_mode_uses_factor( + target_timestep, actuator_id, op_mode_id + ): + factors = np.linspace( + 0.0, 1.0, self.nr_of_stratification_layers + 1 + ) + actuator_list.extend( + [ + S2ActuatorConfiguration(op_mode_id, factor) + for factor in factors + ] + ) + else: + actuator_list.append(S2ActuatorConfiguration(op_mode_id, 0.0)) + possible_actuator_configs[actuator_id] = actuator_list + + keys = list(possible_actuator_configs.keys()) + import itertools + + combinations = itertools.product( + *(possible_actuator_configs[key] for key in keys) + ) + + return [dict(zip(keys, combo)) for combo in combinations] + + @staticmethod + @lru_cache(maxsize=None) + def get_transition( + target_timestep, + actuator_id: str, + from_operation_mode_id: str, + to_operation_mode_id: str, + ) -> Optional[Transition]: + actuator_description = S2FrbcDeviceStateWrapper.get_actuator_description( + target_timestep, actuator_id + ) + if actuator_description is None: + return None + + for transition in actuator_description.transitions: + if ( + str(transition.from_) == from_operation_mode_id + and str(transition.to) == to_operation_mode_id + ): + return transition + return None + + def get_operation_mode_power( + self, om_wrapper: FrbcOperationModeWrapper, fill_level: float, factor: float + ) -> float: + element = self.find_operation_mode_element(om_wrapper, fill_level) + power_watt = 0 + for power_range in element.power_ranges: + if power_range.commodity_quantity in [ + CommodityQuantity.ELECTRIC_POWER_L1, + CommodityQuantity.ELECTRIC_POWER_L2, + CommodityQuantity.ELECTRIC_POWER_L3, + CommodityQuantity.ELECTRIC_POWER_3_PHASE_SYMMETRIC, + ]: + start = power_range.start_of_range + end = power_range.end_of_range + power_watt += (end - start) * factor + start + return power_watt + + @staticmethod + def find_operation_mode_element( + om_wrapper: FrbcOperationModeWrapper, fill_level: float + ): + starts = om_wrapper.fill_level_starts + ends = om_wrapper.fill_level_ends + + # Assumes that starts is sorted, which is a reasonable assumption for S2 data. + # Find the index of the interval start that is just less than or equal to fill_level. + idx = np.searchsorted(starts, fill_level, side="right") - 1 + + # Check if fill_level is within the found range. + if idx >= 0 and fill_level <= ends[idx]: + return om_wrapper.elements[idx] + + # Handle edge cases and gaps, consistent with the original logic. + return ( + om_wrapper.elements[0] + if fill_level < starts[0] + else om_wrapper.elements[-1] + ) + + def get_operation_mode_fill_rate( + self, om_wrapper: FrbcOperationModeWrapper, fill_level: float, factor: float + ) -> float: + element = self.find_operation_mode_element(om_wrapper, fill_level) + fill_rate = element.fill_rate + start = fill_rate.end_of_range + end = fill_rate.start_of_range + return (start - end) * factor + end + + @staticmethod + def get_leakage_rate(target_timestep: "FrbcTimestep", fill_level: float) -> float: + if target_timestep.leakage_behaviour is None: + return 0.0 + + element = S2FrbcDeviceStateWrapper.find_leakage_element( + target_timestep.leakage_behaviour, fill_level + ) + return element.leakage_rate if element else 0.0 + + @staticmethod + def find_leakage_element( + leakage_behaviour: FRBCLeakageBehaviour, fill_level: float + ) -> Optional[FRBCLeakageBehaviourElement]: + if not leakage_behaviour.elements: + return None + + # Calculate starts and ends arrays directly to avoid monkey-patching issues + starts = np.array( + [e.fill_level_range.start_of_range for e in leakage_behaviour.elements] + ) + ends = np.array( + [e.fill_level_range.end_of_range for e in leakage_behaviour.elements] + ) + + # Use binary search for efficient lookup + idx = np.searchsorted(starts, fill_level, side="right") - 1 + + if idx >= 0 and fill_level <= ends[idx]: + return leakage_behaviour.elements[idx] + + return ( + leakage_behaviour.elements[0] + if fill_level < starts[0] + else leakage_behaviour.elements[-1] + ) + + @staticmethod + def calculate_bucket(target_timestep: "FrbcTimestep", fill_level: float) -> int: + ( + fill_level_lower_limit, + fill_level_upper_limit, + nr_of_buckets, + ) = target_timestep.get_bucket_calculation_params() + + if fill_level_upper_limit == fill_level_lower_limit: + return 0 + + bucket = int( + (fill_level - fill_level_lower_limit) + / (fill_level_upper_limit - fill_level_lower_limit) + * nr_of_buckets + ) + return min(max(bucket, 0), nr_of_buckets - 1) + + @staticmethod + @lru_cache(maxsize=None) + def get_timer_duration( + target_timestep: "FrbcTimestep", actuator_id: str, timer_id: str + ) -> timedelta: + return timedelta( + milliseconds=S2FrbcDeviceStateWrapper.get_timer_duration_milliseconds( + target_timestep, actuator_id, timer_id + ) + ) + + @staticmethod + @lru_cache(maxsize=None) + def get_timer_duration_milliseconds( + target_timestep: "FrbcTimestep", actuator_id: str, timer_id: str + ) -> int: + actuator_description = S2FrbcDeviceStateWrapper.get_actuator_description( + target_timestep, actuator_id + ) + if actuator_description is None: + raise ValueError( + f"Actuator description not found for actuator {actuator_id}" + ) + + timer = next( + (t for t in actuator_description.timers if str(t.id) == timer_id), None + ) + return timer.duration.root if timer else 0 + + @staticmethod + @lru_cache(maxsize=None) + def get_actuator_description( + target_timestep: "FrbcTimestep", actuator_id: str + ) -> Optional[FRBCActuatorDescription]: + return next( + ( + ad + for ad in target_timestep.system_description.actuators + if str(ad.id) == actuator_id + ), + None, + ) + + def get_energy_in_current_timestep(self) -> CommodityQuantity: + return self.device_state.get_energy_in_current_timestep() + + @property + def actuator_statuses(self) -> List[FRBCActuatorStatus]: + return self.device_state.actuator_statuses or [] + + @property + def storage_status(self) -> List[FRBCStorageStatus]: + # The return type is correct but mypy does not understand the structure of s2python correctly + return self.device_state.storage_status # type: ignore[return-value] diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_instruction_profile.py b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_instruction_profile.py new file mode 100644 index 0000000..c3fe6d8 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_instruction_profile.py @@ -0,0 +1,20 @@ +from typing import List +from datetime import datetime, timedelta +from s2python.frbc import FRBCInstruction + + +class S2FrbcInstructionProfile: + # This class represents a profile generated by the Reflex as a list of + # S2 FRBCInstruction s + def __init__( + self, + profile_start: datetime, + timestep_duration: timedelta, + elements: List[FRBCInstruction], + ): + self.profile_start = profile_start + self.timestep_duration = timestep_duration + self.elements = elements + + def __str__(self) -> str: + return f"S2FrbcInstructionProfile(elements={self.elements})" diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_plan.py b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_plan.py new file mode 100644 index 0000000..0e147ba --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/s2_frbc_plan.py @@ -0,0 +1,28 @@ +from typing import List, Dict +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_actuator_configuration import ( + S2ActuatorConfiguration, +) +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile + + +class S2FrbcPlan: + def __init__( + self, + idle: bool, + energy: JouleProfile, + fill_level, + operation_mode_id: List[Dict[str, S2ActuatorConfiguration]], + ): + self.idle = idle + self.energy = energy + self.fill_level = fill_level + self.operation_mode_id = operation_mode_id + + def is_idle(self) -> bool: + return self.idle + + def get_energy(self): + return self.energy + + def get_operation_mode_id(self) -> List[Dict[str, S2ActuatorConfiguration]]: + return self.operation_mode_id diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/selection_reason_result.py b/flexmeasures_s2/profile_steering/device_planner/frbc/selection_reason_result.py new file mode 100644 index 0000000..757b859 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/selection_reason_result.py @@ -0,0 +1,20 @@ +from enum import Enum + + +class SelectionReason(Enum): + CONGESTION_CONSTRAINT = "C" + ENERGY_TARGET = "E" + TARIFF_TARGET = "T" + MIN_ENERGY = "M" + NO_ALTERNATIVE = "_" + EMERGENCY_STATE = "!" + + +class SelectionResult: + def __init__( + self, + result: bool, + reason: SelectionReason, + ): + self.result = result + self.reason = reason diff --git a/flexmeasures_s2/profile_steering/device_planner/frbc/usage_forecast_util.py b/flexmeasures_s2/profile_steering/device_planner/frbc/usage_forecast_util.py new file mode 100644 index 0000000..9f9cbd6 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/frbc/usage_forecast_util.py @@ -0,0 +1,116 @@ +# TODO: Is this the same as FRBCUsageForecast? + + +from datetime import timedelta, timezone +from typing import List + + +class UsageForecastElement: + def __init__(self, start, end, usage_rate): + self.start = start.replace(tzinfo=None) + self.end = end.replace(tzinfo=None) + self.usage_rate = usage_rate + + def get_usage(self): + seconds = ( + self.end - self.start + ).total_seconds() + 0.001 # one milisecond added for the offeset from total_Seconds() + return seconds * self.usage_rate + + def split(self, date): + if self.date_in_element(date): + return [ + UsageForecastElement(self.start, date, self.usage_rate), + UsageForecastElement(date, self.end, self.usage_rate), + ] + # If the date is not within the range, return the element itself twice to avoid index errors + return [self, self] + + def date_in_element(self, date): + # Ensure both self.start and self.end are offset-naive or offset-aware + if self.start.tzinfo is None and self.end.tzinfo is None: + # Make date offset-naive + date = date.replace(tzinfo=None) + elif self.start.tzinfo is not None and self.end.tzinfo is not None: + # Make date offset-aware with the same timezone as self.start + date = date.astimezone(self.start.tzinfo) + else: + # If there's a mismatch, raise an error or handle it appropriately + raise ValueError("Mismatch between offset-naive and offset-aware datetimes") + + return self.start <= date <= self.end + + +class UsageForecastUtil: + @staticmethod + def from_storage_usage_profile(usage_forecast): + elements = [] + start = usage_forecast.start_time + start = start.astimezone(timezone.utc) + for element in usage_forecast.elements: + end = start + timedelta(seconds=element.duration.root) + elements.append( + UsageForecastElement(start, end, element.usage_rate_expected) + ) + start = end + timedelta(milliseconds=1) + return elements + + @staticmethod + def sub_profile( + usage_forecast: List[UsageForecastElement], time_step_start, time_step_end + ): + if usage_forecast is None: + return 0 + + usage = 0 + time_step_start = time_step_start.replace(tzinfo=None) + time_step_end = time_step_end.replace(tzinfo=None) + + for element in usage_forecast: + element_start = element.start.replace(tzinfo=None) + element_end = element.end.replace(tzinfo=None) + + if element_start < time_step_start < element_end < time_step_end: + # case 1: ....s.....e + # case 1: |-------|.. + split = element.split(time_step_start) + usage += split[1].get_usage() + elif element_start > time_step_start and element_end < time_step_end: + # case 2: s...........e + # case 2: ..|-------|.. + usage += element.get_usage() + elif time_step_start < element_start < time_step_end < element_end: + # case 3: s.....e.... + # case 3: ..|-------| + split = element.split(time_step_end) + usage += split[0].get_usage() + elif element_start < time_step_start and element_end > time_step_end: + # case 4: ....s...e.... + # case 4: |-----------| + split1 = element.split(time_step_start) + split2 = split1[1].split(time_step_end) + usage += split2[0].get_usage() + elif element_start == time_step_start and element_end == time_step_end: + # case 5: s...........e + # case 5: |-----------| + usage += element.get_usage() + elif element_start == time_step_start and element_end > time_step_end: + # case 6: s.....e...... + # case 6: |-----------| + split = element.split(time_step_end) + usage += split[0].get_usage() + elif element_start == time_step_start and element_end < time_step_end: + # case 7: s...............e + # case 7: |-----------|.... + usage += element.get_usage() + elif element_start < time_step_start and element_end == time_step_end: + # case 8: ......s.....e + # case 8: |-----------| + split = element.split(time_step_start) + usage += split[1].get_usage() + elif element_start > time_step_start and element_end == time_step_end: + # case 9: s...........e + # case 9: ...|--------| + usage += element.get_usage() + + return usage diff --git a/flexmeasures_s2/profile_steering/device_planner/nocontrol/__init__.py b/flexmeasures_s2/profile_steering/device_planner/nocontrol/__init__.py new file mode 100644 index 0000000..42bd487 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/nocontrol/__init__.py @@ -0,0 +1,19 @@ +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_state import ( + S2NoControlDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_planner import ( + S2NoControlDevicePlanner, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_plan import ( + S2NoControlPlan, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.proposal_without_improvement import ( + ProposalWithoutImprovement, +) + +__all__ = [ + "S2NoControlDeviceState", + "S2NoControlDevicePlanner", + "S2NoControlPlan", + "ProposalWithoutImprovement", +] diff --git a/flexmeasures_s2/profile_steering/device_planner/nocontrol/conversion_utils.py b/flexmeasures_s2/profile_steering/device_planner/nocontrol/conversion_utils.py new file mode 100644 index 0000000..7da1c11 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/nocontrol/conversion_utils.py @@ -0,0 +1,115 @@ +from typing import Optional +from s2python.common import PowerForecast, CommodityQuantity +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata + + +def convert_power_forecast_to_joule_profile( + power_forecast: Optional[PowerForecast], profile_metadata: ProfileMetadata +) -> JouleProfile: + """ + Convert a PowerForecast to a JouleProfile. + This is a Python port of the Java ConversionTools.convertPowerForecast method. + + Args: + power_forecast: The power forecast to convert (can be None) + profile_metadata: The metadata for the output profile + + Returns: + A JouleProfile with energy values aligned to the profile metadata + """ + if power_forecast is None: + return JouleProfile( + metadata=profile_metadata, + value=0, + ) + + forecast_start = power_forecast.start_time + profile_start = profile_metadata.profile_start + + if forecast_start > profile_start: + current_forecast_element_index = 0 + time_diff = forecast_start - profile_start + current_profile_step_index = int( + time_diff.total_seconds() + / profile_metadata.timestep_duration.total_seconds() + ) + else: + current_profile_step_index = 0 + time_diff = profile_start - forecast_start + seconds_into_forecast = time_diff.total_seconds() + current_forecast_element_index = 0 + accumulated_seconds = 0 + + for i, element in enumerate(power_forecast.elements): + # element.duration is a Duration object with .root in milliseconds + # We need to convert to seconds + element_duration_seconds = element.duration.root / 1000.0 + if accumulated_seconds + element_duration_seconds > seconds_into_forecast: + current_forecast_element_index = i + break + accumulated_seconds += element_duration_seconds + else: + current_forecast_element_index = len(power_forecast.elements) + + joule_profile_elements = [0] * profile_metadata.nr_of_timesteps + forecast_elements = power_forecast.elements + + if ( + 0 <= current_profile_step_index < profile_metadata.nr_of_timesteps + and 0 <= current_forecast_element_index < len(forecast_elements) + ): + profile_timestep_duration_seconds = ( + profile_metadata.timestep_duration.total_seconds() + ) + while ( + current_profile_step_index < profile_metadata.nr_of_timesteps + and current_forecast_element_index < len(forecast_elements) + ): + forecast_element = forecast_elements[current_forecast_element_index] + power_watts = get_expected_electrical_power(forecast_element) + # forecast_element.duration is a Duration object with .root in milliseconds + # We need to convert to seconds + forecast_element_duration_seconds = forecast_element.duration.root / 1000.0 + energy_joules = int(power_watts * forecast_element_duration_seconds) + number_of_profile_steps = int( + forecast_element_duration_seconds / profile_timestep_duration_seconds + ) + + for _ in range(number_of_profile_steps): + if current_profile_step_index >= profile_metadata.nr_of_timesteps: + break + joule_profile_elements[current_profile_step_index] = int( + energy_joules / number_of_profile_steps + ) + current_profile_step_index += 1 + + current_forecast_element_index += 1 + + return JouleProfile( + metadata=profile_metadata, + elements=joule_profile_elements, # type: ignore[arg-type] + ) + + +def get_expected_electrical_power(forecast_element) -> float: + """ + Get the expected electrical power from a forecast element. + Sums up all electrical power values from different phases. + + Args: + forecast_element: The forecast element containing power values + + Returns: + The total expected electrical power in watts + """ + expected_power = 0.0 + for power_value in forecast_element.power_values: + if power_value.commodity_quantity in [ + CommodityQuantity.ELECTRIC_POWER_L1, + CommodityQuantity.ELECTRIC_POWER_L2, + CommodityQuantity.ELECTRIC_POWER_L3, + CommodityQuantity.ELECTRIC_POWER_3_PHASE_SYMMETRIC, + ]: + expected_power += power_value.value_expected + return expected_power diff --git a/flexmeasures_s2/profile_steering/device_planner/nocontrol/proposal_without_improvement.py b/flexmeasures_s2/profile_steering/device_planner/nocontrol/proposal_without_improvement.py new file mode 100644 index 0000000..ace296c --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/nocontrol/proposal_without_improvement.py @@ -0,0 +1,36 @@ +from flexmeasures_s2.profile_steering.common.proposal import Proposal +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.device_planner.device_planner_abstract import ( + DevicePlanner, +) + + +class ProposalWithoutImprovement(Proposal): + """ + A special proposal for devices that cannot be improved. + This is used for nocontrol devices that have fixed power forecasts. + """ + + def __init__(self, plan: JouleProfile, origin: DevicePlanner): + # Call parent constructor with None for diff profiles since + # nocontrol devices don't respond to target profiles + super().__init__( + global_diff_target=None, # type: ignore[arg-type] + diff_to_congestion_max=None, # type: ignore[arg-type] + diff_to_congestion_min=None, # type: ignore[arg-type] + proposed_plan=plan, + old_plan=plan, + origin=origin, + ) + + def get_global_improvement_value(self) -> float: + """No improvement possible for nocontrol devices.""" + return 0.0 + + def get_congestion_improvement_value(self) -> float: + """No improvement possible for nocontrol devices.""" + return 0.0 + + def get_cost_improvement_value(self) -> float: + """No improvement possible for nocontrol devices.""" + return 0.0 diff --git a/flexmeasures_s2/profile_steering/device_planner/nocontrol/s2_nocontrol_device_planner.py b/flexmeasures_s2/profile_steering/device_planner/nocontrol/s2_nocontrol_device_planner.py new file mode 100644 index 0000000..3dfee0f --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/nocontrol/s2_nocontrol_device_planner.py @@ -0,0 +1,172 @@ +from datetime import datetime +from flexmeasures_s2.profile_steering.device_planner.device_planner_abstract import ( + DevicePlanner, +) +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from flexmeasures_s2.profile_steering.common.device_plan import DevicePlan +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_state import ( + S2NoControlDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.proposal_without_improvement import ( + ProposalWithoutImprovement, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.conversion_utils import ( + convert_power_forecast_to_joule_profile, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_plan import ( + S2NoControlPlan, +) + + +class S2NoControlDevicePlanner(DevicePlanner): + """ + Device planner for devices with no control capabilities. + These devices have a fixed power forecast and cannot be optimized. + This is a Python port of the Java S2NoControlDevicePlanner class. + """ + + def __init__( + self, + device_state: S2NoControlDeviceState, + profile_metadata: ProfileMetadata, + congestion_point_id: str, + ): + self.device_state = device_state + self.profile_metadata = profile_metadata + self._congestion_point_id = congestion_point_id + + if device_state.get_power_forecast() is None: + self.profile = JouleProfile(metadata=profile_metadata, value=0) + else: + self.profile = convert_power_forecast_to_joule_profile( + device_state.get_power_forecast(), profile_metadata + ) + + @property + def device_id(self) -> str: + return self.device_state.device_id + + @property + def device_name(self) -> str: + return self.device_state.device_name + + @property + def connection_id(self) -> str: + return self.device_state.connection_id + + @property + def congestion_point_id(self) -> str: + return self._congestion_point_id + + @property + def priority_class(self) -> int: + return self.device_state.priority_class + + def create_initial_planning(self, plan_due_by_date: datetime) -> S2NoControlPlan: + """ + Create initial planning for a nocontrol device. + Since the device cannot be controlled, this just returns the fixed profile. + + Args: + plan_due_by_date: The date by which the plan must be ready (not used) + + Returns: + A plan with the fixed power forecast profile + """ + return S2NoControlPlan(self.profile) + + def create_improved_planning( + self, + difference_profile: TargetProfile, + diff_to_max_value: JouleProfile, + diff_to_min_value: JouleProfile, + plan_due_by_date: datetime, + ) -> ProposalWithoutImprovement: + """ + Attempt to create an improved planning for a nocontrol device. + Since the device cannot be controlled, this returns a proposal with no improvement. + + Args: + difference_profile: The difference profile for the cluster (not used) + diff_to_max_value: The difference to the maximum profile (not used) + diff_to_min_value: The difference to the minimum profile (not used) + plan_due_by_date: The date by which the plan must be ready (not used) + + Returns: + A ProposalWithoutImprovement indicating no changes can be made + """ + return ProposalWithoutImprovement(self.profile, self) + + def accept_proposal(self, proposal: ProposalWithoutImprovement) -> None: # type: ignore[override] + """ + Accept a proposal for this device. + Validates that the proposal is from this planner and hasn't changed. + + Args: + proposal: The proposal to accept + + Raises: + ValueError: If the proposal is not valid + """ + if proposal.origin != self: + raise ValueError( + f"Planner for '{self.device_id}' received a proposal that it did not send." + ) + + if proposal.proposed_plan != self.profile or proposal.old_plan != self.profile: + raise ValueError( + f"Planner for '{self.device_id}' received a proposal that it did not send." + ) + + def current_profile(self) -> JouleProfile: + """ + Get the current profile of the device. + + Returns: + The fixed power forecast profile + """ + return self.profile + + def get_device_plan(self) -> DevicePlan: + """ + Get the device plan for this nocontrol device. + + Returns: + A DevicePlan with the fixed energy profile + """ + return DevicePlan( + device_id=self.device_id, + device_name=self.device_name, + connection_id=self.connection_id, + energy_profile=self.profile, + fill_level_profile=None, + instruction_profile=None, + ) + + def get_latest_plan(self) -> S2NoControlPlan: + """ + Get the latest calculated plan. + For nocontrol devices, this is always the fixed profile. + + Returns: + A plan with the fixed power forecast profile + """ + return S2NoControlPlan(self.profile) + + def set_accepted_plan(self, plan: S2NoControlPlan) -> None: + """ + Forcefully set the accepted plan for the device. + For nocontrol devices, this validates but doesn't change the profile. + + Args: + plan: The plan to set + + Raises: + ValueError: If the plan doesn't match the fixed profile + """ + if not isinstance(plan, S2NoControlPlan) or plan.energy != self.profile: + raise ValueError( + f"Cannot set a different plan for nocontrol device '{self.device_id}'" + ) diff --git a/flexmeasures_s2/profile_steering/device_planner/nocontrol/s2_nocontrol_device_state.py b/flexmeasures_s2/profile_steering/device_planner/nocontrol/s2_nocontrol_device_state.py new file mode 100644 index 0000000..42f9d68 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/nocontrol/s2_nocontrol_device_state.py @@ -0,0 +1,33 @@ +from datetime import datetime +from typing import Optional +from s2python.common import PowerForecast, PowerValue + + +class S2NoControlDeviceState: + """ + Device state for devices with no control capabilities. + These devices only provide a power forecast and cannot be controlled. + """ + + def __init__( + self, + device_id: str, + device_name: str, + connection_id: str, + priority_class: int, + timestamp: datetime, + energy_in_current_timestep: PowerValue, + is_online: bool, + power_forecast: Optional[PowerForecast], + ): + self.device_id = device_id + self.device_name = device_name + self.connection_id = connection_id + self.priority_class = priority_class + self.timestamp = timestamp + self.energy_in_current_timestep = energy_in_current_timestep + self.is_online = is_online + self.power_forecast = power_forecast + + def get_power_forecast(self) -> Optional[PowerForecast]: + return self.power_forecast diff --git a/flexmeasures_s2/profile_steering/device_planner/nocontrol/s2_nocontrol_plan.py b/flexmeasures_s2/profile_steering/device_planner/nocontrol/s2_nocontrol_plan.py new file mode 100644 index 0000000..66366c2 --- /dev/null +++ b/flexmeasures_s2/profile_steering/device_planner/nocontrol/s2_nocontrol_plan.py @@ -0,0 +1,14 @@ +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile + + +class S2NoControlPlan: + """ + Simple plan wrapper for nocontrol devices. + Since these devices cannot be controlled, the plan only contains an energy profile. + """ + + def __init__(self, energy: JouleProfile): + self.energy = energy + + def get_energy(self) -> JouleProfile: + return self.energy diff --git a/flexmeasures_s2/profile_steering/examples/example_schedule_ddbc.py b/flexmeasures_s2/profile_steering/examples/example_schedule_ddbc.py new file mode 100644 index 0000000..2636694 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/example_schedule_ddbc.py @@ -0,0 +1,560 @@ +""" +Example script demonstrating DDBC (Demand-Driven Based Control) planning using Flask scheduler. + +This script tests the S2FlaskScheduler with DDBC devices, following the pattern from +example_schedule_itho_flask.py and using test data from S2DdbcTests.java. + +The test creates a hybrid heating system with: +- A gas boiler actuator (natural gas commodity) +- A heat pump actuator (electricity commodity) +- Average demand rate forecasts +- Tariff-based targets to optimize cost + +To run: + python flexmeasures_s2/profile_steering/examples/example_schedule_ddbc.py +""" + +from datetime import datetime, timedelta, timezone +from typing import Optional +import logging +import time +import pandas as pd +import os +import uuid +from decimal import Decimal + +# Import Flask app creation +from flexmeasures.app import create as create_flexmeasures_app + +from flexmeasures_s2.scheduler.scheduler_flask import S2FlaskScheduler +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state import ( + S2DdbcDeviceState, +) +from s2python.ddbc import ( + DDBCSystemDescription, + DDBCAverageDemandRateForecast, + DDBCAverageDemandRateForecastElement, + DDBCActuatorDescription, + DDBCActuatorStatus, + DDBCOperationMode, +) +from s2python.common import NumberRange, PowerRange, CommodityQuantity, Commodity +import matplotlib.pyplot as plt + +# Configuration parameters +PLANNING_WINDOW = pd.Timedelta("PT24H") +PLANNING_RESOLUTION = pd.Timedelta("PT1H") +# S = 30 # Number of stratification layers (matching FRBC) [NOT CURRENTLY USED] + +T = PLANNING_WINDOW // PLANNING_RESOLUTION # number of time steps +TIMESTEP_DURATION = PLANNING_RESOLUTION / pd.Timedelta("PT1S") + + +class MockDDBCDeviceData: + """Mock DDBCDeviceData class to mimic the structure from WebSocket integration.""" + + def __init__(self): + self.system_description = None + self.demand_forecasts = [] + self.actuator_statuses = {} + self.resource_id = None + + +def create_hybrid_heating_device_state( + device_id: str, + start_time: datetime, + profile_length: int = T, +) -> S2DdbcDeviceState: + """ + Create a DDBC device state for a hybrid heating system. + + Based on S2DdbcTests.java testByPlotting() method. + System has: + - Gas boiler: 0-20kW (using natural gas) + - Heat pump: 0-2kW (using electricity) + - Both provide 0-10kW heating supply rate + - Average demand rate forecast of 10kW + + Args: + device_id: Unique device identifier + start_time: Start time for planning + profile_length: Number of timesteps + + Returns: + S2DdbcDeviceState configured for hybrid heating + """ + # Create UUIDs for actuators and operation modes + # Use strings - s2python validates and expects string UUIDs + gas_id = str(uuid.uuid4()) + gas_work_mode_id = str(uuid.uuid4()) + hp_id = str(uuid.uuid4()) + hp_work_mode_id = str(uuid.uuid4()) + + # Gas boiler actuator + # 1 m3 gas ~= 10 kWh energy, so 20kW boiler uses ~2000/3600 liters/second + gas_actuator = DDBCActuatorDescription( + id=gas_id, + diagnostic_label="gas", + supported_commodites=[Commodity.GAS], + operation_modes=[ + DDBCOperationMode( + Id=gas_work_mode_id, + id=gas_work_mode_id, + diagnostic_label="gas_on", + power_ranges=[ + PowerRange( + start_of_range=Decimal("0"), + end_of_range=Decimal(str(2000 / 3600)), # liters/second + commodity_quantity=CommodityQuantity.NATURAL_GAS_FLOW_RATE, + ) + ], + supply_range=[ + NumberRange( + start_of_range=Decimal("0"), + end_of_range=Decimal("10000"), # 10kW in Watts + ) + ], + abnormal_condition_only=False, + ) + ], + transitions=[], + timers=[], + ) + + # Heat pump actuator + hp_actuator = DDBCActuatorDescription( + id=hp_id, + diagnostic_label="hp", + supported_commodites=[Commodity.ELECTRICITY], + operation_modes=[ + DDBCOperationMode( + Id=hp_work_mode_id, + id=hp_work_mode_id, + diagnostic_label="hp_on", + power_ranges=[ + PowerRange( + start_of_range=Decimal("0"), + end_of_range=Decimal("2000"), # 2kW in Watts + commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1, + ) + ], + supply_range=[ + NumberRange( + start_of_range=Decimal("0"), + end_of_range=Decimal("10000"), # 10kW in Watts + ) + ], + abnormal_condition_only=False, + ) + ], + transitions=[], + timers=[], + ) + + # Actuator statuses - both starting in their "on" mode at factor 1.0 + # Dictionary keys must be strings to match device state wrapper expectations + actuator_statuses = { + gas_id: DDBCActuatorStatus( + message_id=str(uuid.uuid4()), + actuator_id=gas_id, + active_operation_mode_id=gas_work_mode_id, + operation_mode_factor=Decimal("1.0"), + ), + hp_id: DDBCActuatorStatus( + message_id=str(uuid.uuid4()), + actuator_id=hp_id, + active_operation_mode_id=hp_work_mode_id, + operation_mode_factor=Decimal("1.0"), + ), + } + + # System description + system_description = DDBCSystemDescription( + message_id=str(uuid.uuid4()), + valid_from=start_time, + actuators=[gas_actuator, hp_actuator], + present_demand_rate=NumberRange( + start_of_range=Decimal("10000"), + end_of_range=Decimal("10000"), + ), + provides_average_demand_rate_forecast=True, + ) + + # Average demand rate forecast - constant 10kW demand + demand_rate_elements = [] + for _ in range(profile_length): + demand_rate_elements.append( + DDBCAverageDemandRateForecastElement( + duration=int(TIMESTEP_DURATION), + demand_rate_expected=Decimal("10000"), # 10kW constant demand + ) + ) + + demand_rate_forecast = DDBCAverageDemandRateForecast( + message_id=str(uuid.uuid4()), + start_time=start_time, + elements=demand_rate_elements, + ) + + # Create device state + device_state = S2DdbcDeviceState( + device_id=device_id, + device_name=f"DDBC Hybrid Heating {device_id}", + connection_id=f"{device_id}_connection", + priority_class=0, + timestamp=start_time, + energy_in_current_timestep=0.0, + is_online=True, + power_forecast=None, + system_descriptions=[system_description], + demand_forecasts=[demand_rate_forecast], + actuator_statuses=actuator_statuses, + gas_price_per_m3=2.0, # €2 per m3 of gas + ) + + return device_state + + +def create_ddbc_device_data_from_device_state( + device_state: S2DdbcDeviceState, resource_id: str +) -> MockDDBCDeviceData: + """Convert S2DdbcDeviceState to DDBCDeviceData structure for scheduler.""" + ddbc_data = MockDDBCDeviceData() + ddbc_data.resource_id = resource_id + + if device_state.system_descriptions: + ddbc_data.system_description = device_state.system_descriptions[0] + + ddbc_data.demand_forecasts = device_state.demand_forecasts + + if hasattr(device_state, "actuator_statuses"): + # Convert dict to dict (already in correct format) + ddbc_data.actuator_statuses = device_state.actuator_statuses + + return ddbc_data + + +def get_cost_target_profile_elements(num_elements: int) -> list: + """ + Create cost target profile with time-of-use pricing. + + Simulates variable electricity pricing to test cost optimization: + - Night hours (00:00-06:00): 0.10 EUR/kWh (cheap - favor heat pump) + - Morning (06:00-09:00): 0.15 EUR/kWh + - Peak hours (09:00-17:00): 0.30 EUR/kWh (expensive - favor gas boiler) + - Evening (17:00-21:00): 0.25 EUR/kWh + - Late evening (21:00-24:00): 0.15 EUR/kWh + """ + cost_elements = [] + + for timestep in range(num_elements): + # Calculate hour of day based on timestep + hour = (timestep * int(PLANNING_RESOLUTION.total_seconds() / 60)) // 60 + + if 0 <= hour < 6: + tariff = 0.10 # Cheap night rate + elif 6 <= hour < 9: + tariff = 0.15 + elif 9 <= hour < 17: + tariff = 0.30 # Expensive peak rate + elif 17 <= hour < 21: + tariff = 0.25 + else: + tariff = 0.15 + + cost_elements.append(tariff) + + return cost_elements + + +def test_ddbc_with_flask_scheduler( + profile_length: int = T, + use_tariff_target: bool = True, + suffix="_ddbc_flask", +): + """ + Test S2FlaskScheduler with DDBC hybrid heating device. + + Args: + profile_length: Number of timesteps to plan + use_tariff_target: If True, use tariff-based targets; else use joule targets + suffix: Suffix for output files + """ + print("=" * 80) + print("Test: DDBC Hybrid Heating with S2FlaskScheduler") + print(f" Profile length: {profile_length} timesteps") + print(f" Target type: {'Tariff' if use_tariff_target else 'Joule'}") + print("=" * 80) + + # Create Flask app for scheduler context + app = create_flexmeasures_app(env="development") + + with app.app_context(): + # Configure app settings for scheduler + app.config.setdefault( + "FLEXMEASURES_S2_TARGET_MODE", "costs" if use_tariff_target else "energy" + ) + app.config.setdefault("FLEXMEASURES_S2_PRICE_SENSOR", 2) + + # Start time aligned to the planning resolution + resolution_minutes = PLANNING_RESOLUTION // pd.Timedelta(minutes=1) + now = datetime.now(timezone.utc) + minutes = (now.minute // resolution_minutes) * resolution_minutes + start_time = now.replace(minute=minutes, second=0, microsecond=0) + print(f"Planning start time: {start_time}") + + # Create device state + device_id = f"ddbc_hybrid_heating_{suffix}" + device_state = create_hybrid_heating_device_state( + device_id, + start_time, + profile_length, + ) + + # Convert device state to DDBCDeviceData format + ddbc_device_data = create_ddbc_device_data_from_device_state( + device_state, device_id + ) + + # Create S2FlaskScheduler instance + scheduler = S2FlaskScheduler.__new__(S2FlaskScheduler) + + # Set basic time parameters + scheduler.sensor = None + scheduler.asset = None + scheduler.start = start_time + scheduler.end = start_time + timedelta( + seconds=TIMESTEP_DURATION * profile_length + ) + scheduler.resolution = PLANNING_RESOLUTION + scheduler.belief_time = start_time + scheduler.round_to_decimals = 6 + scheduler.flex_model = {} + scheduler.flex_context = {} + scheduler.fallback_scheduler_class = None + + # Initialize scheduler attributes + scheduler.planning_service = None + scheduler.config_deserialized = False + scheduler.ddbc_device_data = ddbc_device_data # Note: using ddbc_device_data + + # Set data source if available + try: + from flexmeasures.data.services.users import get_or_create_source + from flexmeasures import User + + user = User.query.first() + if user: + data_source = get_or_create_source(user) + scheduler.data_source = data_source + except Exception as e: + app.logger.debug(f"Could not set data source: {e}") + scheduler.data_source = None + + print( + f"Scheduler window: {scheduler.start.strftime('%Y-%m-%d %H:%M:%S')} → " + f"{scheduler.end.strftime('%Y-%m-%d %H:%M:%S')}" + ) + print("Generating plan using S2FlaskScheduler...") + + # Generate plan using scheduler + start_planning_time = time.time() + + # Note: The scheduler's compute() method will call PlanningServiceImpl + # which should handle DDBC devices if properly integrated + schedule_results = scheduler.compute() + + end_planning_time = time.time() + execution_time = end_planning_time - start_planning_time + + print(f"Plan generated in {execution_time:.2f} seconds") + + # Extract results + energy_data = [ + result + for result in schedule_results + if isinstance(result, dict) and "device" in result and "data" in result + ] + + print(f"Generated energy data for {len(energy_data)} device(s)") + + # Process energy profile + total_energy_kwh = 0.0 + if energy_data: + energy_series = energy_data[0]["data"] + # Convert Joules to kWh - trim to profile_length + energy_values_joules = [ + energy if pd.notna(energy) else 0 + for energy in energy_series.values[:profile_length] + ] + total_energy_joules = sum(energy_values_joules) + total_energy_kwh = total_energy_joules / 3_600_000 + print(f"Total energy consumption: {total_energy_kwh:.2f} kWh") + + # Convert to Watts for plotting + power_profile_watts = [ + energy / TIMESTEP_DURATION if energy > 0 else 0 + for energy in energy_values_joules + ] + else: + power_profile_watts = [0] * profile_length + print("Warning: No energy data generated") + + # Create cost profile if using tariff targets + cost_elements = None + cost_target_elements = None + if use_tariff_target: + cost_target_elements = get_cost_target_profile_elements(profile_length) + if energy_data: + # Calculate actual costs + cost_elements = [] + for energy_joules, tariff in zip( + energy_values_joules, cost_target_elements + ): + kwh = energy_joules / 3_600_000 + cost = kwh * tariff + cost_elements.append(cost) + total_cost = sum(cost_elements) + print(f"Total cost: ${total_cost:.4f}") + + # Plot results + plot_ddbc_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=profile_length, + energy_profile=power_profile_watts, + cost_elements=cost_elements, + cost_target_elements=cost_target_elements, + start_time=start_time, + suffix=suffix, + ) + + print("DDBC Flask scheduler test completed!") + + return { + "energy_profile": power_profile_watts, + "total_energy_kwh": total_energy_kwh if energy_data else 0, + "total_cost": sum(cost_elements) if cost_elements else 0, + } + + +def plot_ddbc_results( + timestep_duration: timedelta, + nr_of_timesteps: int, + energy_profile: list, + cost_elements: Optional[list] = None, + cost_target_elements: Optional[list] = None, + start_time: Optional[datetime] = None, + suffix: str = "", +): + """Plot DDBC planning results.""" + # Create output directory + os.makedirs("plots", exist_ok=True) + + if cost_elements is not None or cost_target_elements is not None: + # Create dual-axis plot for energy and cost + fig, ax1 = plt.subplots(1, 1, figsize=(14, 8)) + + timesteps = list(range(nr_of_timesteps)) + + # Energy plot on left y-axis + ax1.plot( + timesteps, + energy_profile, + label="Energy (Watts)", + color="green", + linewidth=2, + marker="o", + ) + ax1.set_ylabel("Power (Watts)", color="green") + ax1.tick_params(axis="y", labelcolor="green") + ax1.set_xlabel("Timestep") + ax1.grid(True, alpha=0.3) + + # Cost plot on right y-axis + ax2 = ax1.twinx() + if cost_target_elements is not None: + ax2.plot( + timesteps, + cost_target_elements, + label="Tariff (EUR/kWh)", + color="orange", + linestyle="dashed", + linewidth=2, + marker="s", + ) + if cost_elements is not None: + ax2.plot( + timesteps, + cost_elements, + label="Cost (EUR)", + color="blue", + linewidth=2, + marker="^", + ) + ax2.set_ylabel("Cost / Tariff", color="blue") + ax2.tick_params(axis="y", labelcolor="blue") + + # Combined legend + lines1, labels1 = ax1.get_legend_handles_labels() + lines2, labels2 = ax2.get_legend_handles_labels() + ax1.legend(lines1 + lines2, labels1 + labels2, loc="upper left") + + ax1.set_title("DDBC Hybrid Heating - Energy and Cost Planning") + else: + # Simple energy plot + fig, ax1 = plt.subplots(1, 1, figsize=(12, 6)) + + timesteps = list(range(nr_of_timesteps)) + ax1.plot( + timesteps, + energy_profile, + label="Energy (Watts)", + color="green", + linewidth=2, + marker="o", + ) + ax1.set_xlabel("Timestep") + ax1.set_ylabel("Power (Watts)") + ax1.set_title("DDBC Hybrid Heating - Energy Profile") + ax1.legend() + ax1.grid(True) + + plt.tight_layout() + plot_filename = f"plots/ddbc_planning_results{suffix}.png" + plt.savefig(plot_filename) + print(f"Plot saved to {plot_filename}") + plt.close() + + +if __name__ == "__main__": + # Configure logging + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + datefmt="%H:%M:%S", + ) + + print("=" * 80) + print("DDBC Hybrid Heating Planning with S2FlaskScheduler") + print("=" * 80) + print() + + try: + # Test with tariff-based optimization + results = test_ddbc_with_flask_scheduler( + profile_length=T, + use_tariff_target=True, + suffix="_tariff", + ) + + print("\n" + "=" * 80) + print("Test Summary:") + print(f" Total energy: {results['total_energy_kwh']:.2f} kWh") + print(f" Total cost: ${results['total_cost']:.4f}") + print("=" * 80) + except Exception as e: + print(f"\n❌ Test failed with error: {e}") + import traceback + + traceback.print_exc() + raise diff --git a/flexmeasures_s2/profile_steering/examples/example_schedule_ddbc_simple.py b/flexmeasures_s2/profile_steering/examples/example_schedule_ddbc_simple.py new file mode 100644 index 0000000..94d7243 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/example_schedule_ddbc_simple.py @@ -0,0 +1,237 @@ +""" +Simplified DDBC test that uses the simplified device state. +This test demonstrates DDBC device integration without complex S2 objects. +""" + +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from datetime import datetime, timedelta, timezone + +# import time +import pandas as pd +import os +from s2python.common import PowerValue, CommodityQuantity +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state import ( + S2DdbcDeviceState, +) +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata + +from flexmeasures_s2.scheduler.schedulers import ( + PlanningServiceImpl, + PlanningServiceConfig, + ClusterState, + ClusterTarget, +) +import matplotlib.dates as mdates +import matplotlib.pyplot as plt + +D = 2 # Number of DDBC devices +PLANNING_WINDOW = pd.Timedelta("PT2H") # Shorter window for testing +PLANNING_RESOLUTION = pd.Timedelta("PT5M") + +T = PLANNING_WINDOW // PLANNING_RESOLUTION +TIMESTEP_DURATION = PLANNING_RESOLUTION / pd.Timedelta("PT1S") + + +def create_ddbc_device_state_simple( + device_id: str, start_time: datetime +) -> S2DdbcDeviceState: + """ + Create a simplified DDBC device state for testing. + Uses empty lists for system descriptions and demand forecasts. + """ + device_state = S2DdbcDeviceState( + device_id=device_id, + device_name=device_id, + connection_id=device_id + "_connection", + priority_class=1, + timestamp=start_time, + energy_in_current_timestep=PowerValue( + value=0, commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1 + ), + is_online=True, + power_forecast=None, # DDBC devices don't need power forecast + system_descriptions=[], # Simplified: empty list + demand_forecasts=[], # Simplified: empty list + gas_price_per_m3=2.0, # €2 per m3 of gas + ) + return device_state + + +def plot_planning_results( + timestep_duration, + nr_of_timesteps, + predicted_energy_elements, + target_energy_elements, +): + """ + Plots the energy comparison for DDBC devices. + """ + timestep_start_times = [ + datetime(1970, 1, 1, tzinfo=timezone.utc) + + timedelta(seconds=i * timestep_duration.total_seconds()) + for i in range(nr_of_timesteps) + ] + + fig, ax1 = plt.subplots(1, 1, figsize=(12, 8)) + + ax1.plot( + timestep_start_times, + predicted_energy_elements, + label="Predicted Energy (DDBC Devices)", + color="blue", + ) + ax1.plot( + timestep_start_times, + target_energy_elements, + label="Target Energy", + color="red", + linestyle="dotted", + linewidth=2, + ) + + ax1.set_ylabel("Energy (Joules)") + ax1.set_title("Predicted vs Target Energy - DDBC Devices (Simplified)") + ax1.legend(loc="best") + ax1.grid(True) + + ax1.xaxis.set_major_locator(mdates.MinuteLocator(interval=15)) + ax1.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M")) + fig.autofmt_xdate() + + plt.tight_layout() + os.makedirs("plots", exist_ok=True) + plt.savefig(f"plots/ddbc_simple_plot_D={D}_T={T}.png") + # print(f"Plot saved to plots/ddbc_simple_plot_D={D}_T={T}.png") + + +def get_target_profile_elements(number_of_elements: int): + """Create target profile elements for testing.""" + target_elements = [] + # Simple varying target for testing + for i in range(number_of_elements): + if i < number_of_elements // 4: + target_elements.append(5000000) # 5 MJ + elif i < number_of_elements // 2: + target_elements.append(3000000) # 3 MJ + elif i < 3 * number_of_elements // 4: + target_elements.append(2000000) # 2 MJ + else: + target_elements.append(4000000) # 4 MJ + return target_elements + + +def test_planning_service_impl_with_ddbc_devices_simple(): + """Test the PlanningServiceImpl with simplified DDBC devices.""" + # print("Testing PlanningServiceImpl with simplified DDBC devices") + # print(f"Number of devices: {D}") + # print(f"Number of timesteps: {T}") + + target_metadata = ProfileMetadata( + profile_start=datetime(1970, 1, 1, tzinfo=timezone.utc), + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + ) + plan_due_by_date = target_metadata.profile_start + timedelta(seconds=10) + target_profile_elements = get_target_profile_elements(T) + + global_target_profile = TargetProfile( + profile_start=target_metadata.profile_start, + timestep_duration=target_metadata.timestep_duration, + elements=target_profile_elements, + ) + + device_states = [ + create_ddbc_device_state_simple( + f"ddbc_device_{i + 1}", + target_metadata.profile_start, + ) + for i in range(D) + ] + + device_states_dict = { + device_state.device_id: device_state for device_state in device_states + } + + congestion_points_by_connection_id = { + device_state.connection_id: "" for device_state in device_states + } + + cluster_state = ClusterState( + datetime.now(), device_states_dict, congestion_points_by_connection_id + ) + + congestion_point_targets = {} + cluster_target = ClusterTarget( + datetime.now(), + None, + None, + global_target_profile=global_target_profile, + congestion_point_targets=congestion_point_targets, + ) + + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + + # print("Generating plan!") + + service = PlanningServiceImpl(config) + + # start_time = time.time() + cluster_plan = service.plan( + state=cluster_state, + target=cluster_target, + planning_window=TIMESTEP_DURATION * T, + reason="Testing DDBC planning (simplified)", + plan_due_by_date=plan_due_by_date, + optimize_for_target=True, + max_priority_class=1, + ) + # end_time = time.time() + # execution_time = end_time - start_time + + # print(f"Plan generated in {execution_time:.2f} seconds") + + assert cluster_plan is not None + # print("Got cluster plan") + + if cluster_plan is None: + # print("Cluster plan is None") + return + + device_plans = cluster_plan.get_plan_data().get_device_plans() + energy_profile = cluster_plan.get_joule_profile() + + plot_planning_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + predicted_energy_elements=energy_profile.elements, + target_energy_elements=target_profile_elements, + ) + + device_plans = [plan for plan in device_plans if plan is not None] + + assert len(device_plans) > 0 + # print(f"Got {len(device_plans)} device plans") + + for device_plan in device_plans: + if device_plan: + # print(f"Device {device_plan.device_id}:") + # total_energy = sum( + # e for e in device_plan.energy_profile.elements if e is not None + # ) + # print(f" Total energy: {total_energy} Joules (zero for simplified test)") + # print(f" Instruction profile: {device_plan.instruction_profile}") + pass + + assert len(energy_profile.elements) == target_metadata.nr_of_timesteps + # print("Test completed successfully!") + # print("\nNote: This is a simplified test. Full DDBC planning with state trees") + # print(" and optimization would be implemented in ddbc_planning_window.py") + + +if __name__ == "__main__": + test_planning_service_impl_with_ddbc_devices_simple() diff --git a/flexmeasures_s2/profile_steering/examples/example_schedule_frbc.py b/flexmeasures_s2/profile_steering/examples/example_schedule_frbc.py new file mode 100644 index 0000000..43c5529 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/example_schedule_frbc.py @@ -0,0 +1,1027 @@ +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from datetime import datetime, timedelta, timezone +import uuid + +# import logging +# import time +import pandas as pd +import os +from s2python.frbc.frbc_actuator_description import FRBCActuatorDescription +from s2python.frbc.frbc_fill_level_target_profile_element import ( + FRBCFillLevelTargetProfileElement, +) +from s2python.frbc.frbc_leakage_behaviour_element import FRBCLeakageBehaviourElement +from s2python.frbc.frbc_operation_mode import FRBCOperationMode +from s2python.frbc.frbc_usage_forecast_element import FRBCUsageForecastElement +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from s2python.frbc import FRBCSystemDescription +from s2python.frbc import FRBCUsageForecast +from s2python.frbc import FRBCFillLevelTargetProfile +from s2python.frbc import FRBCLeakageBehaviour +from s2python.frbc import FRBCOperationModeElement +from s2python.frbc import FRBCActuatorStatus, FRBCStorageStatus, FRBCStorageDescription +from s2python.common import PowerRange, Duration +from s2python.common import NumberRange +from s2python.common import CommodityQuantity +from s2python.common import Transition +from s2python.common import Timer +from s2python.common import PowerValue +from s2python.common import Commodity + +from flexmeasures_s2.scheduler.schedulers import ( + PlanningServiceImpl, + PlanningServiceConfig, + ClusterState, + ClusterTarget, +) +import matplotlib.dates as mdates +import matplotlib.pyplot as plt +import json + +# Global variables to store IDs for debugging +# make a list of tuples with the ids and the names +ids = [] + +# -> todo: plot of run time vs D, vs B, vs S and vs T +D = 1 # number of devices -> todo: multiprocessing on create_improved_planning +B = 200 # number of buckets -> todo: vectorize computation of next state from current state +S = 30 # number of stratification layers +PLANNING_WINDOW = pd.Timedelta("PT24H") +PLANNING_RESOLUTION = pd.Timedelta("PT5M") + +T = PLANNING_WINDOW // PLANNING_RESOLUTION # number of time steps +TIMESTEP_DURATION = PLANNING_RESOLUTION / pd.Timedelta( + "PT1S" +) # duration of a time step in seconds + + +def create_ev_device_state( + device_id: str, + omloop_starts_at: datetime, + cet: timezone, + charge_power_soc_percentage_per_second_night: float, + charging_power_kw_night: float, + charge_power_soc_percentage_per_second_day: float, + charging_power_kw_day: float, + soc_percentage_before_charging1: float, + final_fill_level_target1: float, + recharge_duration1: timedelta, + start_of_recharge1: datetime, + drive_duration1: timedelta, + start_of_drive1: datetime, + drive_consume_soc_per_second1: float, + soc_percentage_before_driving1: float, + soc_percentage_before_charging2: float, + final_fill_level_target2: float, + recharge_duration2: timedelta, + start_of_recharge2: datetime, +) -> S2FrbcDeviceState: + # Create system description + ( + recharge_system_description1, + charge_actuator_status1, + storage_status1, + ) = create_recharge_system_description( + start_of_recharge=start_of_recharge1, + charge_power_soc_percentage_per_second=charge_power_soc_percentage_per_second_night, + charging_power_kw=charging_power_kw_night, + soc_percentage_before_charging=soc_percentage_before_charging1, + ) + + # Create leakage behaviour + recharge_leakage1 = create_recharge_leakage_behaviour(start_of_recharge1) + + # Create usage forecast + recharge_usage_forecast1 = create_recharge_usage_forecast( + start_of_recharge1, recharge_duration1 + ) + + # Create fill level target profile + recharge_fill_level_target1 = create_recharge_fill_level_target_profile( + start_of_recharge1, + recharge_duration1, + final_fill_level_target1, + soc_percentage_before_charging1, + ) + + ( + drive_system_description1, + off_actuator_status1, + storage_status1, + ) = create_driving_system_description( + start_of_drive1, soc_percentage_before_driving1 + ) + drive_usage_forecast1 = create_driving_usage_forecast( + start_of_drive1, drive_duration1, drive_consume_soc_per_second1 + ) + + ( + recharge_system_description2, + charge_actuator_status2, + storage_status2, + ) = create_recharge_system_description( + start_of_recharge2, + charge_power_soc_percentage_per_second_day, + charging_power_kw_day, + soc_percentage_before_charging2, + ) + recharge_leakage2 = create_recharge_leakage_behaviour(start_of_recharge2) + recharge_usage_forecast2 = create_recharge_usage_forecast( + start_of_recharge2, recharge_duration2 + ) + recharge_fill_level_target2 = create_recharge_fill_level_target_profile( + start_of_recharge2, + recharge_duration2, + final_fill_level_target2, + soc_percentage_before_charging2, + ) + + # Create done state + done_start = start_of_recharge2 + recharge_duration2 + done_duration = timedelta(hours=4, minutes=10) # 4 hours & 10 minutes + done_leakage = create_recharge_leakage_behaviour(done_start) + ( + done_system_description, + done_actuator_status, + done_storage_status, + ) = create_driving_system_description(done_start, final_fill_level_target2) + done_usage_forecast = create_recharge_usage_forecast(done_start, done_duration) + + device_state = S2FrbcDeviceState( + device_id=device_id, + device_name=device_id, + connection_id=device_id + "_cid1", + priority_class=1, + timestamp=omloop_starts_at, + energy_in_current_timestep=PowerValue( + value=0, commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1 + ), + is_online=True, + power_forecast=None, + system_descriptions=[ + recharge_system_description1, + drive_system_description1, + recharge_system_description2, + done_system_description, + ], + leakage_behaviours=[recharge_leakage1, recharge_leakage2, done_leakage], + usage_forecasts=[ + recharge_usage_forecast1, + drive_usage_forecast1, + recharge_usage_forecast2, + done_usage_forecast, + ], + fill_level_target_profiles=[ + recharge_fill_level_target1, + recharge_fill_level_target2, + ], + computational_parameters=S2FrbcDeviceState.ComputationalParameters(B, S), + actuator_statuses=[ + off_actuator_status1, + charge_actuator_status1, + charge_actuator_status2, + done_actuator_status, + ], + storage_status=storage_status2, # Use first storage status (matches first system description) + ) + return device_state + + +def create_recharge_system_description( + start_of_recharge, + charge_power_soc_percentage_per_second, + charging_power_kw, + soc_percentage_before_charging, +) -> FRBCSystemDescription: + # Create and return a mock system description for recharging + on_operation_element = FRBCOperationModeElement( + fill_level_range=NumberRange(start_of_range=0, end_of_range=100), + fill_rate=NumberRange( + start_of_range=0, + end_of_range=charge_power_soc_percentage_per_second, + ), + power_ranges=[ + PowerRange( + start_of_range=charging_power_kw * 0, + end_of_range=charging_power_kw * 1000, + commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1, + ) + ], + ) + id_on_operation_mode = str(uuid.uuid4()) + # logging.debug(f"id_on_operation_mode: {id_on_operation_mode}") + ids.append((id_on_operation_mode, "charge_on_operation_mode")) + on_operation_mode = FRBCOperationMode( + id=id_on_operation_mode, + diagnostic_label="charge.on", + elements=[on_operation_element], + abnormal_condition_only=False, + ) + off_operation_element = FRBCOperationModeElement( + fill_level_range=NumberRange(start_of_range=0, end_of_range=100), + fill_rate=NumberRange(start_of_range=0, end_of_range=0), + power_ranges=[ + PowerRange( + start_of_range=0, + end_of_range=0, + commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1, + ) + ], + ) + id_off_operation_mode = str(uuid.uuid4()) + # logging.debug(f"id_off_operation_mode: {id_off_operation_mode}") + ids.append((id_off_operation_mode, "charge_off_operation_mode")) + off_operation_mode = FRBCOperationMode( + id=id_off_operation_mode, + diagnostic_label="charge.off", + elements=[off_operation_element], + abnormal_condition_only=False, + ) + + id_on_to_off_timer = str(uuid.uuid4()) + # logging.debug(f"id_on_to_off_timer: {id_on_to_off_timer}") + ids.append((id_on_to_off_timer, "charge_on_to_off_timer")) + on_to_off_timer = Timer( + id=id_on_to_off_timer, + diagnostic_label="charge_on.to.off.timer", + duration=Duration(root=30), + ) + id_off_to_on_timer = str(uuid.uuid4()) + # logging.debug(f"id_off_to_on_timer: {id_off_to_on_timer}") + ids.append((id_off_to_on_timer, "charge_off_to_on_timer")) + off_to_on_timer = Timer( + id=id_off_to_on_timer, + diagnostic_label="charge_off.to.on.timer", + duration=Duration(root=30), + ) + transition_id_from_on_to_off = str(uuid.uuid4()) + # logging.debug(f"transition_id_from_on_to_off: {transition_id_from_on_to_off}") + ids.append( + (transition_id_from_on_to_off, "transition_from_charge_on_to_charge_off") + ) + transition_from_on_to_off = Transition( + id=transition_id_from_on_to_off, + **{"from": id_on_operation_mode}, + to=id_off_operation_mode, + start_timers=[id_off_to_on_timer], + blocking_timers=[id_on_to_off_timer], + transition_duration=None, + abnormal_condition_only=False, + ) + transition_id_from_off_to_on = str(uuid.uuid4()) + # logging.debug(f"transition_id_from_off_to_on: {transition_id_from_off_to_on}") + ids.append( + (transition_id_from_off_to_on, "transition_from_charge_off_to_charge_on") + ) + transition_from_off_to_on = Transition( + id=transition_id_from_off_to_on, # type: ignore[arg-type] + **{"from": id_off_operation_mode}, # type: ignore[arg-type] + to=id_on_operation_mode, # type: ignore[arg-type] + start_timers=[id_on_to_off_timer], # type: ignore[arg-type] + blocking_timers=[id_off_to_on_timer], # type: ignore[arg-type] + transition_duration=None, + abnormal_condition_only=False, + ) + charge_actuator_id = str(uuid.uuid4()) + # logging.debug(f"charge_actuator_id: {charge_actuator_id}") + ids.append((charge_actuator_id, "charge_actuator")) + charge_actuator_status = FRBCActuatorStatus( + message_id=charge_actuator_id, # type: ignore[arg-type] + actuator_id=charge_actuator_id, # type: ignore[arg-type] + active_operation_mode_id=id_on_operation_mode, # type: ignore[arg-type] + operation_mode_factor=0, + ) + + charge_actuator_description = FRBCActuatorDescription( + id=charge_actuator_id, # type: ignore[arg-type] + diagnostic_label="charge.actuator", + operation_modes=[on_operation_mode, off_operation_mode], + transitions=[transition_from_on_to_off, transition_from_off_to_on], + timers=[on_to_off_timer, off_to_on_timer], + supported_commodities=[Commodity.ELECTRICITY], + ) + storage_status_id = str(uuid.uuid4()) + # logging.debug(f"storage_status_id: {storage_status_id}") + ids.append((storage_status_id, "storage_status")) + storage_status = FRBCStorageStatus( + message_id=storage_status_id, # type: ignore[arg-type] + present_fill_level=soc_percentage_before_charging, + ) + + frbc_storage_description = FRBCStorageDescription( + diagnostic_label="battery", + fill_level_label="SoC %", + provides_leakage_behaviour=False, + provides_fill_level_target_profile=True, + provides_usage_forecast=False, + fill_level_range=NumberRange(start_of_range=0, end_of_range=100), + ) + system_description_id = str(uuid.uuid4()) + # logging.debug(f"system_description_id: {system_description_id}") + ids.append((system_description_id, "system_description")) + frbc_system_description = FRBCSystemDescription( + message_id=system_description_id, # type: ignore[arg-type] + valid_from=start_of_recharge, + actuators=[charge_actuator_description], + storage=frbc_storage_description, + ) + + return frbc_system_description, charge_actuator_status, storage_status + + +def create_recharge_leakage_behaviour(start_of_recharge): + leakage_id = str(uuid.uuid4()) + # logging.debug(f"leakage_id: {leakage_id}") + ids.append((leakage_id, "leakage")) + return FRBCLeakageBehaviour( + message_id=leakage_id, + valid_from=start_of_recharge, + elements=[ + FRBCLeakageBehaviourElement( + fill_level_range=NumberRange(start_of_range=0, end_of_range=100), + leakage_rate=0, + ) + ], + ) + + +def create_recharge_usage_forecast(start_of_recharge, recharge_duration): + no_usage = FRBCUsageForecastElement( + duration=int(recharge_duration.total_seconds()), usage_rate_expected=0 + ) + usage_id = str(uuid.uuid4()) + # logging.debug(f"usage_id: {usage_id}") + ids.append((usage_id, "usage")) + return FRBCUsageForecast( + message_id=usage_id, start_time=start_of_recharge, elements=[no_usage] + ) + + +def create_recharge_fill_level_target_profile( + start_of_recharge, + recharge_duration, + final_fill_level_target, + soc_percentage_before_charging, +): + during_charge = FRBCFillLevelTargetProfileElement( + duration=max(recharge_duration.total_seconds() - 10, 0), + fill_level_range=NumberRange( + start_of_range=soc_percentage_before_charging, end_of_range=100 + ), + ) + end_of_charge = FRBCFillLevelTargetProfileElement( + duration=min(recharge_duration.total_seconds(), 10), + fill_level_range=NumberRange( + start_of_range=final_fill_level_target, end_of_range=100 + ), + ) + fill_level_id = str(uuid.uuid4()) + # logging.debug(f"fill_level_id: {fill_level_id}") + ids.append((fill_level_id, "fill_level")) + return FRBCFillLevelTargetProfile( + message_id=fill_level_id, + start_time=start_of_recharge, + elements=[during_charge, end_of_charge], + ) + + +def create_driving_system_description(start_of_drive, soc_percentage_before_driving): + global off_actuator_id, id_off_operation_mode + off_operation_element = FRBCOperationModeElement( + fill_level_range=NumberRange(start_of_range=0, end_of_range=100), + fill_rate=NumberRange(start_of_range=0, end_of_range=0), + power_ranges=[ + PowerRange( + start_of_range=0, + end_of_range=0, + commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1, + ) + ], + ) + id_off_operation_mode = str(uuid.uuid4()) + # logging.debug(f"operation_mode_driving: {id_off_operation_mode}") + ids.append((id_off_operation_mode, "operation_mode_driving")) + off_operation_mode = FRBCOperationMode( + id=id_off_operation_mode, + diagnostic_label="off", + elements=[off_operation_element], + abnormal_condition_only=False, + ) + off_actuator_id = str(uuid.uuid4()) + # logging.debug(f"actuator_driving: {off_actuator_id}") + ids.append((off_actuator_id, "actuator_driving")) + off_actuator_status = FRBCActuatorStatus( + message_id=str(uuid.uuid4()), + actuator_id=off_actuator_id, + active_operation_mode_id=id_off_operation_mode, + operation_mode_factor=0, + ) + off_actuator = FRBCActuatorDescription( + id=off_actuator_id, + diagnostic_label="off", + operation_modes=[off_operation_mode], + transitions=[], + timers=[], + supported_commodities=[Commodity.ELECTRICITY], + ) + storage_status = FRBCStorageStatus( + message_id=str(uuid.uuid4()), present_fill_level=soc_percentage_before_driving + ) + storage_description = FRBCStorageDescription( + diagnostic_label="battery", + fill_level_label="SoC %", + provides_leakage_behaviour=False, + provides_fill_level_target_profile=True, + provides_usage_forecast=False, + fill_level_range=NumberRange(start_of_range=0, end_of_range=100), + ) + return ( + FRBCSystemDescription( + message_id=str(uuid.uuid4()), + valid_from=start_of_drive, + actuators=[off_actuator], + storage=storage_description, + ), + off_actuator_status, + storage_status, + ) + + +def create_driving_usage_forecast( + start_of_driving, next_drive_duration, soc_usage_per_second +): + no_usage = FRBCUsageForecastElement( + duration=int(next_drive_duration.total_seconds()), + usage_rate_expected=(-1 * soc_usage_per_second), + ) + return FRBCUsageForecast( + message_id=str(uuid.uuid4()), start_time=start_of_driving, elements=[no_usage] + ) + + +def plot_planning_results( + timestep_duration, + nr_of_timesteps, + predicted_energy_elements, + target_energy_elements, + cost_elements=None, + target_cost_elements=None, +): + """ + Plots the energy, fill level, actuator usage, and operation mode ID lists using matplotlib. + + :param timestep_duration: Duration of each timestep. + :param nr_of_timesteps: Number of timesteps. + :param predicted_energy_elements: List of predicted energy values. + :param target_energy_elements: List of target energy values. + :param cost_elements: Optional list of cost values. + :param target_cost_elements: Optional list of target cost values (tariffs). + """ + # Generate timestep_start_times + timestep_start_times = [ + datetime(1970, 1, 1, tzinfo=timezone.utc) + + timedelta(seconds=i * timestep_duration.total_seconds()) + for i in range(nr_of_timesteps) + ] + + if cost_elements is not None or target_cost_elements is not None: + # Create a figure with dual y-axes for energy and cost + fig, ax1 = plt.subplots(1, 1, figsize=(14, 8)) + + # Energy plot on left y-axis + ax1.plot( + timestep_start_times, + predicted_energy_elements, + label="Predicted Energy", + color="green", + linewidth=2, + ) + ax1.plot( + timestep_start_times, + target_energy_elements, + label="Target Energy", + color="red", + linestyle="dotted", + linewidth=2, + ) + ax1.set_ylabel("Energy (Joules)", color="green") + ax1.tick_params(axis="y", labelcolor="green") + ax1.grid(True, alpha=0.3) + + # Cost plot on right y-axis + ax2 = ax1.twinx() + if cost_elements is not None: + ax2.plot( + timestep_start_times, + cost_elements, + label="Predicted Cost", + color="blue", + linewidth=2, + ) + if target_cost_elements is not None: + ax2.plot( + timestep_start_times, + target_cost_elements, + label="Target Cost (Tariffs)", + color="orange", + linestyle="dashed", + linewidth=2, + ) + ax2.set_ylabel("Cost ($/kWh)", color="blue") + ax2.tick_params(axis="y", labelcolor="blue") + + # Combined legend + lines1, labels1 = ax1.get_legend_handles_labels() + lines2, labels2 = ax2.get_legend_handles_labels() + ax1.legend(lines1 + lines2, labels1 + labels2, loc="upper left") + + ax1.set_title("Energy and Cost Planning Results") + else: + # Create a figure with a single subplot for energy only + fig, ax1 = plt.subplots(1, 1, figsize=(12, 8)) + + # Plot both lines on the same subplot + ax1.plot( + timestep_start_times, + predicted_energy_elements, + label="Predicted Energy", + color="green", + ) + ax1.plot( + timestep_start_times, + target_energy_elements, + label="Target Energy", + color="red", + linestyle="dotted", + linewidth=2, + ) + + # Set labels and grid + ax1.set_ylabel("Energy (Joules)") + ax1.set_title("Predicted vs Target Energy") + ax1.legend(loc="best") + ax1.grid(True) + + # Format the x-axis to show time and set ticks every 30 minutes + ax1.xaxis.set_major_locator(mdates.MinuteLocator(interval=30)) + ax1.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M:%S")) + fig.autofmt_xdate() + + # Adjust layout + plt.tight_layout() + # Save it in a directory called plots + os.makedirs("plots", exist_ok=True) + suffix = ( + "_cost" if cost_elements is not None or target_cost_elements is not None else "" + ) + plt.savefig(f"plots/my plot - D = {D} - B = {B} - S = {S} - T = {T}{suffix}") + + +def create_device_state( + device_id: str, omloop_starts_at: datetime, cet: timezone +) -> S2FrbcDeviceState: + # Device charging parameters + charge_power_soc_percentage_per_second_night = 0.01099537114 + charging_power_kw_night = 57 + charge_power_soc_percentage_per_second_day = 0.01099537114 + charging_power_kw_day = 57 + + # First recharge period + start_of_recharge1 = omloop_starts_at.astimezone(cet) + recharge_duration1 = timedelta(hours=7, minutes=15) + soc_percentage_before_charging1 = 0 + final_fill_level_target1 = 100 + + # Driving period + start_of_drive1 = start_of_recharge1 + recharge_duration1 + drive_duration1 = timedelta(hours=4, minutes=35) + drive_consume_soc_per_second1 = 0.00375927565821256038647342995169 + soc_percentage_before_driving1 = 100 + + # Second recharge period + start_of_recharge2 = start_of_drive1 + drive_duration1 + recharge_duration2 = timedelta(hours=7) + soc_percentage_before_charging2 = 37.0 + final_fill_level_target2 = 94.4825134 + + # Create the device state + device_state = create_ev_device_state( + device_id, + omloop_starts_at, + cet, + charge_power_soc_percentage_per_second_night, + charging_power_kw_night, + charge_power_soc_percentage_per_second_day, + charging_power_kw_day, + soc_percentage_before_charging1, + final_fill_level_target1, + recharge_duration1, + start_of_recharge1, + drive_duration1, + start_of_drive1, + drive_consume_soc_per_second1, + soc_percentage_before_driving1, + soc_percentage_before_charging2, + final_fill_level_target2, + recharge_duration2, + start_of_recharge2, + ) + return device_state + + +def get_target_profile_elements(number_of_elements: int): + """Create target profile elements with the same pattern as the Java code.""" + target_elements = [] + # First 38 elements of 0 + target_elements.extend([0] * 38) + # Next 62 elements of 8400000 + target_elements.extend([8400000] * 62) + # Next 55 elements of 0 + target_elements.extend([0] * 45) + # Next 18 elements of 8400000 + target_elements.extend([8400000] * 28) + # Last 115 elements of 176000000 + target_elements.extend([176000000] * 115) + return target_elements[:number_of_elements] + + +def get_cost_target_profile_elements(number_of_elements: int): + """Create cost target profile elements with dynamic pricing pattern.""" + cost_elements = [] + # Simulate time-of-use pricing for a 24-hour period (288 = 5-minute intervals) + intervals_per_hour = number_of_elements // 24 + + for hour in range(24): + if 0 <= hour < 6: # Night hours (00:00-06:00) - lowest cost + tariff = 0.10 # 10 cents per kWh + elif 6 <= hour < 9: # Morning ramp-up (06:00-09:00) + tariff = 0.15 # 15 cents per kWh + elif 9 <= hour < 17: # Peak hours (09:00-17:00) - highest cost + tariff = 0.30 # 30 cents per kWh + elif 17 <= hour < 21: # Evening peak (17:00-21:00) + tariff = 0.25 # 25 cents per kWh + else: # Late evening (21:00-24:00) + tariff = 0.15 # 15 cents per kWh + + # Add the tariff for all intervals in this hour + cost_elements.extend([tariff] * intervals_per_hour) + + return cost_elements[:number_of_elements] + + +def calculate_cost_from_energy_and_tariffs(energy_elements, tariff_elements): + """Calculate cost from energy usage and tariff rates.""" + cost_elements = [] + for energy, tariff in zip(energy_elements, tariff_elements): + if energy is not None and tariff is not None: + # Convert Joules to kWh and multiply by tariff + kwh = energy / 3_600_000 # 1 kWh = 3,600,000 Joules + cost = kwh * tariff + cost_elements.append(cost) + else: + cost_elements.append(0.0) + return cost_elements + + +def test_planning_service_impl_with_ev_device(): + """Test the PlanningServiceImpl with an EV device.""" + # print("Test the PlanningServiceImpl with an EV device.") + # Create 10 device states + numberOfDevices = D + + # Create profile metadata and target profile + target_metadata = ProfileMetadata( + profile_start=datetime(1970, 1, 1, tzinfo=timezone.utc), + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + ) + plan_due_by_date = target_metadata.profile_start + timedelta(seconds=10) + target_profile_elements = get_target_profile_elements(T) + + # Create a target profile + global_target_profile = TargetProfile( + profile_start=target_metadata.profile_start, + timestep_duration=target_metadata.timestep_duration, + elements=target_profile_elements, + ) + + device_states = [ + create_device_state( + f"battery{i + 1}", + datetime.fromtimestamp(3600), + timezone(timedelta(hours=1)), + ) + for i in range(numberOfDevices) + ] + + # Create Dictionary of device states + device_states_dict = { + device_state.device_id: device_state for device_state in device_states + } + + # Create congestion points mapping - follow pattern from example_schedule_itho.py + # Note: Uses device_id as key, not connection_id (system will fallback to DEFAULT_CONGESTION_POINT if not found) + congestion_points_by_connection_id = { + device_id: "" for device_id in device_states_dict.keys() + } + # Create a cluster state using the list of device states + start_time = target_metadata.profile_start + cluster_state = ClusterState( + start_time, device_states_dict, congestion_points_by_connection_id + ) + # Create an empty map for congestion point targets + congestion_point_targets = {} + # Create a cluster target + cluster_target = ClusterTarget( + start_time, + None, + None, + global_target_profile=global_target_profile, + congestion_point_targets=congestion_point_targets, + ) + + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + + # print("Generating plan!") + + # Create planning service implementation + service = PlanningServiceImpl(config) + + # Set due by date for planning + plan_due_by_date = target_metadata.profile_start + timedelta(seconds=10) + # Act - Generate a plan + # start_time = time.time() + cluster_plan = service.plan( + state=cluster_state, + target=cluster_target, + planning_window=TIMESTEP_DURATION * T, # Full planning window in seconds + reason="Testing EV planning", + plan_due_by_date=plan_due_by_date, + optimize_for_target=True, + max_priority_class=1, + ) + # end_time = time.time() + # execution_time = end_time - start_time + + # Log information + # print(f"Plan generated in {execution_time: .2f} seconds") + + # Assert + assert cluster_plan is not None + # print("Got cluster plan") + if cluster_plan is None: + # print("Cluster plan is None") + return + # Get the plan for our device + device_plans = cluster_plan.get_plan_data().get_device_plans() + + # Manually compute energy profile, filtering out None device plans + # This is necessary because get_joule_profile() doesn't handle None device plans + energy_profile = JouleProfile( + profile_start=cluster_plan.metadata.profile_start, + timestep_duration=cluster_plan.metadata.timestep_duration, + profile_length=cluster_plan.metadata.nr_of_timesteps, + value=0, + ) + for device_plan in device_plans: + if device_plan is not None and device_plan.energy_profile is not None: + energy_profile = energy_profile.add(device_plan.energy_profile) + + # Save the energy profile to a file, + # with open(f"energy_profile-D={D}_B={B}_S={S}_T={T}.json", "w") as f: + # json.dump(energy_profile.elements, f) + + # Plot the planning results + plot_planning_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + predicted_energy_elements=energy_profile.elements, + target_energy_elements=target_profile_elements, + ) + + if D == 3 or D == 10 or D == 5: + expected_file = f"energy_profile-D={D}_B={B}_S={S}_T={T}.json" + if os.path.exists(expected_file): + with open(expected_file, "r") as f: + assert energy_profile.elements == json.load(f) + print("Energy profile matches expected values") + else: + print(f"Skipping validation: {expected_file} does not exist") + # Get only the non-None plans + device_plans_filtered = [plan for plan in device_plans if plan is not None] + + # Debug: Print information about device plans + if len(device_plans_filtered) == 0: + print( + f"Warning: No device plans were generated. Total device plans: {len(device_plans)}, None plans: {sum(1 for p in device_plans if p is None)}" + ) + # If no plans were generated, we still have an energy profile (all zeros), so continue + else: + print( + f"Successfully generated {len(device_plans_filtered)} device plan(s) out of {len(device_plans)} total" + ) + + # Note: We don't assert here because the energy profile computation above handles None plans gracefully + # The planning might fail for some devices, but we can still proceed with the energy profile + # print("Got device plan") + + # Print instructions and analyze operation mode changes + all_instructions = [] + for device_plan in device_plans_filtered: + if device_plan and device_plan.instruction_profile: + instructions = device_plan.instruction_profile.elements + all_instructions.extend(instructions) + # print( + # f"Device {device_plan.device_id} has {len(instructions)} instructions" + # ) + + # print(f"Total number of instructions: {len(all_instructions)}") + + # Find instructions with different operation modes than previous instruction + mode_changes = [] + previous_mode = None + + for i, instruction in enumerate(all_instructions): + if hasattr(instruction, "operation_mode"): + current_mode = instruction.operation_mode + if previous_mode is not None and current_mode != previous_mode: + mode_changes.append( + { + "index": i, + "instruction": instruction, + "previous_mode": previous_mode, + "current_mode": current_mode, + "execution_time": getattr(instruction, "execution_time", "N/A"), + "operation_mode_factor": getattr( + instruction, "operation_mode_factor", "N/A" + ), + } + ) + previous_mode = current_mode + + print(f"Found {len(mode_changes)} operation mode changes:") + # for change in mode_changes: + # print( + # f" Instruction {change['index']}: {change['previous_mode']} -> {change['current_mode']}" + # ) + # print(f" Execution time: {change['execution_time']}") + # print(f" Operation mode factor: {change['operation_mode_factor']}") + # print(f" Instruction ID: {getattr(change['instruction'], 'id', 'N/A')}") + # print() + + # Basic assertion - the energy profile should have the expected number of elements + assert len(energy_profile.elements) == target_metadata.nr_of_timesteps + # pass + + +def test_planning_service_impl_with_cost_target(): + """Test the PlanningServiceImpl with cost targeting.""" + # print("Test the PlanningServiceImpl with cost targeting.") + + # Create profile metadata + target_metadata = ProfileMetadata( + profile_start=datetime(1970, 1, 1, tzinfo=timezone.utc), + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + ) + plan_due_by_date = target_metadata.profile_start + timedelta(seconds=10) + + # Create cost target profile instead of energy target + cost_target_elements = get_cost_target_profile_elements(T) + + # Create a cost-based target profile + cost_target_profile = TargetProfile.from_tariff_values( + target_metadata, cost_target_elements + ) + + device_states = [ + create_device_state( + f"battery{i + 1}", + datetime.fromtimestamp(3600), + timezone(timedelta(hours=1)), + ) + for i in range(D) + ] + + # Create Dictionary of device states + device_states_dict = { + device_state.device_id: device_state for device_state in device_states + } + + # Create congestion points mapping - follow pattern from example_schedule_itho.py + # Note: Uses device_id as key, not connection_id (system will fallback to DEFAULT_CONGESTION_POINT if not found) + congestion_points_by_connection_id = { + device_id: "" for device_id in device_states_dict.keys() + } + + # Create a cluster state using the list of device states + start_time = target_metadata.profile_start + cluster_state = ClusterState( + start_time, device_states_dict, congestion_points_by_connection_id + ) + + # Create a cluster target with cost target + cluster_target = ClusterTarget( + start_time, + None, + None, + global_target_profile=cost_target_profile, + congestion_point_targets={}, + ) + + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + + # print("Generating cost-optimized plan!") + + # Create planning service implementation + service = PlanningServiceImpl(config) + + # Act - Generate a plan + # start_time = time.time() + cluster_plan = service.plan( + state=cluster_state, + target=cluster_target, + planning_window=TIMESTEP_DURATION * T, # Full planning window in seconds + reason="Testing Cost planning", + plan_due_by_date=plan_due_by_date, + optimize_for_target=True, + max_priority_class=1, + ) + # end_time = time.time() + # execution_time = end_time - start_time + + # Log information + # print(f"Cost-optimized plan generated in {execution_time: .2f} seconds") + + # Assert + assert cluster_plan is not None + # print("Got cost-optimized cluster plan") + + if cluster_plan is None: + # print("Cluster plan is None") + return + + # Get the plan for our device + device_plans = cluster_plan.get_plan_data().get_device_plans() + + # Manually compute energy profile, filtering out None device plans + # This is necessary because get_joule_profile() doesn't handle None device plans + energy_profile = JouleProfile( + profile_start=cluster_plan.metadata.profile_start, + timestep_duration=cluster_plan.metadata.timestep_duration, + profile_length=cluster_plan.metadata.nr_of_timesteps, + value=0, + ) + for device_plan in device_plans: + if device_plan is not None and device_plan.energy_profile is not None: + energy_profile = energy_profile.add(device_plan.energy_profile) + + # Calculate the actual costs from the energy profile and tariffs + cost_elements = calculate_cost_from_energy_and_tariffs( + energy_profile.elements, cost_target_elements + ) + + # print( + # f"Total energy consumption: {sum(energy_profile.elements) / 3_600_000:.2f} kWh" # + # ) + # print(f"Total cost: ${sum(cost_elements):.2f}") + + # Plot the cost-optimized planning results with dual axes + plot_planning_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + predicted_energy_elements=energy_profile.elements, + target_energy_elements=[0] * T, # use the energy target just for plotting + cost_elements=cost_elements, + target_cost_elements=cost_target_elements, + ) + + # Basic assertion - the energy profile should have the expected number of elements + assert len(energy_profile.elements) == target_metadata.nr_of_timesteps + + # print("Cost targeting test completed successfully!") + + +# Main function +if __name__ == "__main__": + # Test energy targeting (original functionality) + test_planning_service_impl_with_ev_device() + + # print("\n" + "=" * 60 + "\n") + + # Test cost targeting (new functionality) + test_planning_service_impl_with_cost_target() diff --git a/flexmeasures_s2/profile_steering/examples/example_schedule_itho.py b/flexmeasures_s2/profile_steering/examples/example_schedule_itho.py new file mode 100644 index 0000000..d32c980 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/example_schedule_itho.py @@ -0,0 +1,1910 @@ +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from datetime import datetime, timedelta, timezone +import uuid +import logging +import time +import pandas as pd +import os +from s2python.frbc.frbc_actuator_description import FRBCActuatorDescription +from s2python.frbc.frbc_fill_level_target_profile_element import ( + FRBCFillLevelTargetProfileElement, +) +from s2python.frbc.frbc_leakage_behaviour_element import FRBCLeakageBehaviourElement +from s2python.frbc.frbc_operation_mode import FRBCOperationMode +from s2python.frbc.frbc_usage_forecast_element import FRBCUsageForecastElement +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from s2python.frbc import FRBCSystemDescription +from s2python.frbc import FRBCUsageForecast +from s2python.frbc import FRBCFillLevelTargetProfile +from s2python.frbc import FRBCLeakageBehaviour +from s2python.frbc import FRBCOperationModeElement +from s2python.frbc import FRBCActuatorStatus, FRBCStorageStatus, FRBCStorageDescription +from s2python.common import PowerRange, Duration +from s2python.common import NumberRange +from s2python.common import CommodityQuantity +from s2python.common import Transition +from s2python.common import Timer +from s2python.common import PowerValue +from s2python.common import Commodity + +from flexmeasures_s2.scheduler.schedulers import ( + PlanningServiceImpl, + PlanningServiceConfig, + ClusterState, + ClusterTarget, +) +import matplotlib.dates as mdates +import matplotlib.pyplot as plt + +# Configuration parameters +D = 1 # number of devices +B = 200 # number of buckets +S = 30 # number of stratification layers +PLANNING_WINDOW = pd.Timedelta("PT24H") +PLANNING_RESOLUTION = pd.Timedelta("PT5M") + +T = PLANNING_WINDOW // PLANNING_RESOLUTION +TIMESTEP_DURATION = PLANNING_RESOLUTION / pd.Timedelta("PT1S") + + +def adjust_fill_level_target_profile_for_current_time( + fill_level_target_profile: FRBCFillLevelTargetProfile, + current_time: datetime, +) -> FRBCFillLevelTargetProfile: + """ + Adjust fill level target profile when current time is ahead of profile start_time. + + Removes elements that have already passed and adjusts the start_time to current_time. + This keeps fill_level_ranges at fixed positions in time regardless of when scheduling happens. + + Args: + fill_level_target_profile: The original fill level target profile + current_time: The current scheduling time (when planning actually happens) + + Returns: + Adjusted fill level target profile with start_time set to current_time + """ + if fill_level_target_profile is None: + return None + + profile_start = fill_level_target_profile.start_time + if isinstance(profile_start, datetime): + profile_start = ( + profile_start.replace(tzinfo=timezone.utc) + if profile_start.tzinfo is None + else profile_start + ) + else: + profile_start = profile_start.astimezone(timezone.utc) + + current_time = ( + current_time.replace(tzinfo=timezone.utc) + if current_time.tzinfo is None + else current_time + ) + + # If current time is not ahead of profile start, just update start_time + if current_time <= profile_start: + return fill_level_target_profile.model_copy(update={"start_time": current_time}) + + # Calculate elapsed time since profile start + elapsed_time_ms = int((current_time - profile_start).total_seconds() * 1000) + + # Helper function to extract duration in milliseconds + def get_duration_ms(elem): + duration = elem.duration + if isinstance(duration, (int, float)): + return int(duration) + elif hasattr(duration, "root"): + return int(duration.root) + else: + return int(duration) + + # Find which elements have passed and which we're currently in + remaining_elements = [] + cumulative_duration_ms = 0 + + for element in fill_level_target_profile.elements: + element_duration_ms = get_duration_ms(element) + element_end_ms = cumulative_duration_ms + element_duration_ms + + if element_end_ms <= elapsed_time_ms: + # This element has completely passed, skip it + cumulative_duration_ms = element_end_ms + continue + elif cumulative_duration_ms < elapsed_time_ms: + # We're in the middle of this element, truncate it + remaining_duration_ms = element_end_ms - elapsed_time_ms + if remaining_duration_ms > 0: + remaining_elements.append( + FRBCFillLevelTargetProfileElement( + duration=Duration(root=remaining_duration_ms), + fill_level_range=element.fill_level_range, + ) + ) + cumulative_duration_ms = element_end_ms + else: + # This element is in the future, keep it as-is + remaining_elements.append(element) + cumulative_duration_ms = element_end_ms + + # Create adjusted profile with current_time as start_time + adjusted_profile = FRBCFillLevelTargetProfile( + message_id=str(uuid.uuid4()), + start_time=current_time, + elements=remaining_elements, + ) + + return adjusted_profile + + +def create_itho_device_state( + device_id: str, + start_time: datetime, + planning_window_duration: timedelta | None = None, + include_fill_level_target: bool = True, + include_usage_forecast: bool = True, +) -> S2FrbcDeviceState: + """ + Create device state from FRBC messages extracted from itho.yaml + """ + + # FRBC.SystemDescription from line 2 of itho.yaml + # DHW_OFF operation mode + dhw_off_mode_id = "959eb2c3-3d92-4ca1-8005-1d9caab972a5" + dhw_off_element = FRBCOperationModeElement( + fill_level_range=NumberRange(start_of_range=0.0, end_of_range=100.0), + fill_rate=NumberRange(start_of_range=0.0, end_of_range=0.0), + power_ranges=[ + PowerRange( + start_of_range=0.0, + end_of_range=0.0, + commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1, + ) + ], + running_costs=NumberRange(start_of_range=0.0, end_of_range=0.0), + ) + dhw_off_mode = FRBCOperationMode( + id=dhw_off_mode_id, + diagnostic_label="DHW_OFF", + elements=[dhw_off_element], + abnormal_condition_only=False, + ) + + # DHW_ON operation mode + dhw_on_mode_id = "31314092-4456-43f8-89dd-0421194bc821" + dhw_on_element = FRBCOperationModeElement( + fill_level_range=NumberRange(start_of_range=10.0, end_of_range=61.5), + fill_rate=NumberRange( + start_of_range=0.002031807896078361, end_of_range=0.002031807896078361 + ), + power_ranges=[ + PowerRange( + start_of_range=1100.0, + end_of_range=1100.0, + commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1, + ) + ], + ) + dhw_on_mode = FRBCOperationMode( + id=dhw_on_mode_id, + diagnostic_label="DHW_ON", + elements=[dhw_on_element], + abnormal_condition_only=False, + ) + + # Timers + min_on_timer_id = "702cd17f-ac40-429e-93d4-ce69c8eb8040" + min_on_timer = Timer( + id=min_on_timer_id, + diagnostic_label="DHW Minimum On Time", + duration=Duration(root=1800000), # 30 minutes in milliseconds + ) + + min_off_timer_id = "b27ef8c9-c440-44cb-8deb-f7f85f491a92" + min_off_timer = Timer( + id=min_off_timer_id, + diagnostic_label="DHW Minimum Off Time", + duration=Duration(root=600000), # 10 minutes in milliseconds + ) + + # Transitions + off_to_on_transition_id = "4359a2e3-8782-4192-9775-2a29b828c45e" + off_to_on_transition = Transition( + id=off_to_on_transition_id, + **{"from": dhw_off_mode_id}, + to=dhw_on_mode_id, + start_timers=[min_on_timer_id], + blocking_timers=[min_off_timer_id], + transition_duration=300000, # 5 minutes in milliseconds + abnormal_condition_only=False, + ) + + on_to_off_transition_id = "8d3bdeae-5052-4579-a62b-a36b427df63a" + on_to_off_transition = Transition( + id=on_to_off_transition_id, + **{"from": dhw_on_mode_id}, + to=dhw_off_mode_id, + start_timers=[min_off_timer_id], + blocking_timers=[min_on_timer_id], + transition_duration=180000, # 3 minutes in milliseconds + abnormal_condition_only=False, + ) + + # Actuator + actuator_id = "189f6a58-e78a-4c3f-bcda-6cd151342285" + actuator_description = FRBCActuatorDescription( + id=actuator_id, + diagnostic_label="Heat Pump (DHW)", + supported_commodities=[Commodity.ELECTRICITY], + operation_modes=[dhw_off_mode, dhw_on_mode], + transitions=[off_to_on_transition, on_to_off_transition], + timers=[min_on_timer, min_off_timer], + ) + + # Storage description + storage_description = FRBCStorageDescription( + diagnostic_label="DHW Buffer", + fill_level_label="Temperature in degrees Celcius", + provides_leakage_behaviour=True, + provides_fill_level_target_profile=True, + provides_usage_forecast=True, + fill_level_range=NumberRange(start_of_range=10.0, end_of_range=61.5), + ) + + # System description + system_description = FRBCSystemDescription( + message_id=str(uuid.uuid4()), + valid_from=start_time, + actuators=[actuator_description], + storage=storage_description, + ) + + # FRBC.ActuatorStatus from line 123 (present_fill_level=16.182) + actuator_status = FRBCActuatorStatus( + message_id=str(uuid.uuid4()), + actuator_id=actuator_id, + active_operation_mode_id=dhw_off_mode_id, + operation_mode_factor=0.0, + ) + + # FRBC.StorageStatus from line 94 + present_fill_level = 16.182 # Current fill level from device + storage_status = FRBCStorageStatus( + message_id=str(uuid.uuid4()), + present_fill_level=present_fill_level, + ) + + # FRBC.LeakageBehaviour from line 71 + leakage_behaviour = FRBCLeakageBehaviour( + message_id=str(uuid.uuid4()), + valid_from=start_time, + elements=[ + FRBCLeakageBehaviourElement( + fill_level_range=NumberRange(start_of_range=10.0, end_of_range=61.5), + leakage_rate=0.00004464134898917508, + ) + ], + ) + + # Calculate total planning window in milliseconds + if planning_window_duration is None: + planning_window_duration = PLANNING_WINDOW + + # Create fill level target profile (only if requested) + fill_level_target_profile = None + if include_fill_level_target: + # FRBC.FillLevelTargetProfile - create with fixed reference time (start of day) + # This keeps fill_level_ranges at fixed positions in time regardless of when scheduling happens + # The profile will be adjusted for the actual scheduling time later + fixed_reference_time = start_time.replace( + hour=0, minute=0, second=0, microsecond=0 + ) + + # Get heating parameters from SystemDescription + # From DHW_ON operation mode: fill_rate = 0.002031807896078361 per second + # This means: 0.002031807896078361 °C per second when heating at full power (1100W) + fill_rate_per_second = 0.002031807896078361 + timestep_duration_seconds = TIMESTEP_DURATION + fill_level_min = ( + 10.0 # From fill level target profile in itho.yaml (maintenance periods) + ) + fill_level_max = ( + 55.0 # From fill level target profile in itho.yaml (maintenance periods) + ) + peak_target_min = 51.5 # Peak period minimum target + peak_target_max = 55.0 # Peak period maximum target + + # Calculate how long it takes to heat from current level to peak target + # Time needed = (target_temp - current_temp) / fill_rate + temp_rise_needed = peak_target_min - present_fill_level + heating_time_seconds = temp_rise_needed / fill_rate_per_second + heating_time_timesteps = ( + int(heating_time_seconds / timestep_duration_seconds) + 1 + ) # Add 1 for safety margin + + print("=" * 80) + print("FILL LEVEL TARGET CONFIGURATION") + print("=" * 80) + print(f"Current fill level:{present_fill_level}°C") + print(f"Peak target: [{peak_target_min}, {peak_target_max}]°C") + print(f"Fill rate: {fill_rate_per_second} °C/second (when heating at 1100W)") + print(f"Temperature rise needed: {temp_rise_needed:.2f}°C") + print( + f"Heating time required: {heating_time_seconds / 3600:.2f} hours ({heating_time_timesteps} timesteps)" + ) + print("") + print("STRATEGY:") + print(" - Peak periods require 51.5-55.0°C (constraint: fill_level >= 51.5°C)") + print(" - Optimizer sees constraint violation at peak times if not heated") + print(" - Optimizer MUST heat to 51.5°C before/during peak periods") + print(" - Optimizer will minimize cost by heating during CHEAP hours") + print("=" * 80) + + # Create fill level target profile elements + # Use the EXACT pattern from itho.yaml line 116 + # Pattern: 10 elements with alternating maintenance and peak periods + # Maintenance: [10.0, 55.0]°C, Peak: [51.5, 55.0]°C + + elements = [] + + # Original pattern from itho.yaml (durations in milliseconds): + # Element 1: 23400000 ms (6.5 hours) - maintenance [10.0, 55.0] + # Element 2: 5400000 ms (1.5 hours) - peak [51.5, 55.0] + # Element 3: 32400000 ms (9 hours) - maintenance [10.0, 55.0] + # Element 4: 10800000 ms (3 hours) - peak [51.5, 55.0] + # Element 5: 14400000 ms (4 hours) - maintenance [10.0, 55.0] + # Element 6: 23400000 ms (6.5 hours) - maintenance [10.0, 55.0] + # Element 7: 5400000 ms (1.5 hours) - peak [51.5, 55.0] + # Element 8: 32400000 ms (9 hours) - maintenance [10.0, 55.0] + # Element 9: 10800000 ms (3 hours) - peak [51.5, 55.0] + # Element 10: 14400000 ms (4 hours) - maintenance [10.0, 55.0] + + # Total duration: + # Define the pattern exactly as in itho.yaml + fill_level_target_elements = [ + (23400000, fill_level_min, fill_level_max), # Maintenance + (5400000, peak_target_min, peak_target_max), # Peak + (32400000, fill_level_min, fill_level_max), # Maintenance + (10800000, peak_target_min, peak_target_max), # Peak + (14400000, fill_level_min, fill_level_max), # Maintenance + (23400000, fill_level_min, fill_level_max), # Maintenance + (5400000, peak_target_min, peak_target_max), # Peak + (32400000, fill_level_min, fill_level_max), # Maintenance + (10800000, peak_target_min, peak_target_max), # Peak + (14400000, fill_level_min, fill_level_max), # Maintenance + ] + + for duration_ms, range_min, range_max in fill_level_target_elements: + elements.append( + FRBCFillLevelTargetProfileElement( + duration=Duration(root=duration_ms), + fill_level_range=NumberRange( + start_of_range=range_min, end_of_range=range_max + ), + ) + ) + + # Verify total duration matches planning window + # Extract duration value (Duration objects store milliseconds in .root) + def get_duration_ms(elem): + duration = elem.duration + if isinstance(duration, (int, float)): + return int(duration) # Assume milliseconds if numeric + elif hasattr(duration, "root"): + return int(duration.root) # Duration.root is in milliseconds + else: + return int(duration) + + total_duration_ms = sum(get_duration_ms(elem) for elem in elements) + total_duration_seconds = total_duration_ms / 1000.0 + print( + f"\nTarget profile duration: {total_duration_seconds / 3600:.2f} hours ({total_duration_ms / 1000:.0f} seconds)" + ) + print( + f"Planning window duration: {planning_window_duration.total_seconds() / 3600:.2f} hours ({planning_window_duration.total_seconds():.0f} seconds)" + ) + print(f"Number of elements: {len(elements)}") + + # Create profile with fixed reference time (start of day) + fill_level_target_profile = FRBCFillLevelTargetProfile( + message_id=str(uuid.uuid4()), + start_time=fixed_reference_time, + elements=elements, + ) + + # Adjust profile for actual scheduling time + # This removes elements that have already passed and sets start_time to current scheduling time + fill_level_target_profile = adjust_fill_level_target_profile_for_current_time( + fill_level_target_profile, + start_time, + ) + + if fill_level_target_profile: + print("\nAdjusted fill level target profile:") + print(f" Original reference time: {fixed_reference_time}") + print(f" Adjusted start_time: {fill_level_target_profile.start_time}") + print(f" Remaining elements: {len(fill_level_target_profile.elements)}") + else: + print( + "\nFill level target profile: NOT CREATED (include_fill_level_target=False)" + ) + + # Create simulated usage forecast (only if requested) + usage_forecast = None + if include_usage_forecast: + # Usage represents hot water being drawn, which reduces fill level (temperature) + # Positive usage_rate_expected means fill level decreases per second + # Match the pattern from fill level target profile (10 elements with same durations) + # Higher usage during peak periods to force heating + + usage_elements = [] + + # Usage rates (fill level decrease per second) + # Higher usage during peak periods to force heating + base_usage_rate = 0.00001 # Low base usage (0.00001 °C/second = 0.036 °C/hour) + peak_usage_rate = ( + 0.0001 # High usage during peaks (0.0001 °C/second = 0.36 °C/hour) + ) + + # Match the fill level target profile pattern exactly + # Use same durations and pattern: maintenance periods have low usage, peak periods have high usage + usage_forecast_elements = [ + (23400000, base_usage_rate), # Maintenance period 1 + (5400000, peak_usage_rate), # Peak period 1 + (32400000, base_usage_rate), # Maintenance period 2 + (10800000, peak_usage_rate), # Peak period 2 + (14400000, base_usage_rate), # Maintenance period 3 + (23400000, base_usage_rate), # Maintenance period 4 + (5400000, peak_usage_rate), # Peak period 3 + (32400000, base_usage_rate), # Maintenance period 5 + (10800000, peak_usage_rate), # Peak period 4 + (14400000, base_usage_rate), # Maintenance period 6 + ] + + for duration_ms, usage_rate in usage_forecast_elements: + usage_elements.append( + FRBCUsageForecastElement( + duration=duration_ms, + usage_rate_expected=usage_rate, + ) + ) + + # Verify total duration (extract duration value, handling both int/float and Duration objects) + def get_duration_ms_usage(elem): + duration = elem.duration + if isinstance(duration, (int, float)): + return int(duration) # Assume milliseconds if numeric + elif hasattr(duration, "root"): + return int(duration.root) # Duration.root is in milliseconds + else: + return int(duration) + + total_usage_duration_ms = sum( + get_duration_ms_usage(elem) for elem in usage_elements + ) + total_usage_duration_seconds = total_usage_duration_ms / 1000.0 + + print("\nUsage forecast created:") + print( + f" Total duration: {total_usage_duration_seconds / 3600:.2f} hours ({total_usage_duration_ms / 1000:.0f} seconds)" + ) + print(f" Number of elements: {len(usage_elements)}") + print( + f" Base usage rate: {base_usage_rate} °C/second ({base_usage_rate * 3600:.4f} °C/hour)" + ) + print( + f" Peak usage rate: {peak_usage_rate} °C/second ({peak_usage_rate * 3600:.4f} °C/hour)" + ) + print(" Usage during peaks will reduce fill level, forcing optimizer to heat") + + usage_forecast = FRBCUsageForecast( + message_id=str(uuid.uuid4()), + start_time=start_time, + elements=usage_elements, + ) + else: + print("\nUsage forecast: NOT CREATED (include_usage_forecast=False)") + + # Create device state with optional fill level target and usage forecast + device_state = S2FrbcDeviceState( + device_id=device_id, + device_name="ITHO DHW Heat Pump", + connection_id=device_id + "_connection", + priority_class=1, + timestamp=start_time, + energy_in_current_timestep=PowerValue( + value=0, commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1 + ), + is_online=True, + power_forecast=None, + system_descriptions=[system_description], + leakage_behaviours=[leakage_behaviour], + usage_forecasts=[usage_forecast] + if (include_usage_forecast and usage_forecast) + else [], + fill_level_target_profiles=( + [fill_level_target_profile] + if (include_fill_level_target and fill_level_target_profile) + else [] + ), + computational_parameters=S2FrbcDeviceState.ComputationalParameters(B, S), + actuator_statuses=[actuator_status], + storage_status=storage_status, + ) + + return device_state + + +def convert_fill_level_target_to_timeseries( + fill_level_target_profile, + start_time, + timestep_duration, + nr_of_timesteps, +): + """ + Convert FRBCFillLevelTargetProfile to time series arrays for plotting. + + Returns: + tuple: (target_min_values, target_max_values) as lists + """ + target_min = [] + target_max = [] + + if fill_level_target_profile is None or not fill_level_target_profile.elements: + return [None] * nr_of_timesteps, [None] * nr_of_timesteps + + current_timestep = 0 + timestep_seconds = timestep_duration.total_seconds() + + for element in fill_level_target_profile.elements: + # Duration is in milliseconds - extract the actual value + duration_ms = ( + element.duration + if isinstance(element.duration, (int, float)) + else getattr(element.duration, "root", element.duration) + ) + duration_seconds = duration_ms / 1000 + num_timesteps = int(duration_seconds / timestep_seconds) + + # Get the fill level range for this element + min_level = element.fill_level_range.start_of_range + max_level = element.fill_level_range.end_of_range + + # Add values for all timesteps in this element's duration + for _ in range(min(num_timesteps, nr_of_timesteps - current_timestep)): + target_min.append(min_level) + target_max.append(max_level) + current_timestep += 1 + + if current_timestep >= nr_of_timesteps: + break + + # Fill remaining timesteps if needed + while len(target_min) < nr_of_timesteps: + target_min.append(target_min[-1] if target_min else None) + target_max.append(target_max[-1] if target_max else None) + + return target_min[:nr_of_timesteps], target_max[:nr_of_timesteps] + + +def plot_planning_results( + timestep_duration, + nr_of_timesteps, + predicted_energy_elements, + fill_level_profile=None, + fill_level_target_min=None, + fill_level_target_max=None, + start_time=None, + suffix="", + tariff_elements=None, +): + """ + Plots the energy and optionally fill level profiles using matplotlib. + + Args: + suffix: Optional suffix for the filename (e.g., "_cost" or "_energy") + tariff_elements: Optional list of tariff values to display (for cost optimization) + """ + # Generate timestep_start_times + if start_time is None: + start_time = datetime(1970, 1, 1, tzinfo=timezone.utc) + + timestep_start_times = [ + start_time + timedelta(seconds=i * timestep_duration.total_seconds()) + for i in range(nr_of_timesteps) + ] + + if fill_level_profile is not None: + # Create a figure with dual y-axes + fig, ax1 = plt.subplots(1, 1, figsize=(14, 8)) + + # If tariffs are provided, add them as background shading + if tariff_elements is not None: + # Normalize tariffs to 0-1 range for color intensity + min_tariff = min(tariff_elements) + max_tariff = max(tariff_elements) + tariff_range = max_tariff - min_tariff + + # Color background based on tariff (red = expensive, green = cheap) + for i in range(len(timestep_start_times) - 1): + if tariff_range > 0: + intensity = (tariff_elements[i] - min_tariff) / tariff_range + else: + intensity = 0 + # Red for high prices, yellow for medium, green for low + color = (intensity, 1 - intensity * 0.5, 0) # RGB + ax1.axvspan( + timestep_start_times[i], + timestep_start_times[i + 1], + alpha=0.15, + color=color, + ) + + # Add a text annotation explaining the background colors + ax1.text( + 0.02, + 0.98, + f"Background: Red=High price (${max_tariff:.2f}/kWh), Green=Low price (${min_tariff:.2f}/kWh)", + transform=ax1.transAxes, + verticalalignment="top", + bbox=dict(boxstyle="round", facecolor="white", alpha=0.8), + fontsize=9, + ) + + # Energy plot on left y-axis + ax1.plot( + timestep_start_times, + predicted_energy_elements, + label="Power Consumption (W)", + color="darkblue", + linewidth=2.5, + zorder=10, + ) + ax1.set_ylabel("Power (W)", color="darkblue") + ax1.tick_params(axis="y", labelcolor="darkblue") + ax1.grid(True, alpha=0.3, zorder=0) + + # Fill level plot on right y-axis + ax2 = ax1.twinx() + ax2.plot( + timestep_start_times, + fill_level_profile, + label="Actual Temperature (°C)", + color="red", + linewidth=2, + ) + + # Plot fill level targets if provided + if fill_level_target_min is not None and fill_level_target_max is not None: + # Filter out None values and convert to numeric arrays + target_min_numeric = [] + target_max_numeric = [] + times_numeric = [] + + for i, (t, min_val, max_val) in enumerate( + zip(timestep_start_times, fill_level_target_min, fill_level_target_max) + ): + if min_val is not None and max_val is not None: + try: + min_float = float(min_val) + max_float = float(max_val) + target_min_numeric.append(min_float) + target_max_numeric.append(max_float) + times_numeric.append(t) + except (ValueError, TypeError): + continue + + if target_min_numeric and target_max_numeric: + ax2.fill_between( + times_numeric, + target_min_numeric, + target_max_numeric, + alpha=0.2, + color="blue", + label="Target Range (°C)", + ) + ax2.plot( + times_numeric, + target_min_numeric, + color="blue", + linestyle="--", + linewidth=1, + alpha=0.5, + ) + ax2.plot( + times_numeric, + target_max_numeric, + color="blue", + linestyle="--", + linewidth=1, + alpha=0.5, + ) + + ax2.set_ylabel("Temperature (°C)", color="red") + ax2.tick_params(axis="y", labelcolor="red") + + # Combined legend + lines1, labels1 = ax1.get_legend_handles_labels() + lines2, labels2 = ax2.get_legend_handles_labels() + ax1.legend(lines1 + lines2, labels1 + labels2, loc="upper left") + + ax1.set_title("ITHO DHW Heat Pump Schedule") + else: + # Create a figure with a single subplot for energy only + fig, ax1 = plt.subplots(1, 1, figsize=(14, 8)) + + ax1.plot( + timestep_start_times, + predicted_energy_elements, + label="Power Consumption (W)", + color="green", + linewidth=2, + ) + ax1.set_ylabel("Power (W)") + ax1.set_title("ITHO DHW Heat Pump Schedule - Power Consumption") + ax1.legend(loc="best") + ax1.grid(True) + + # Format the x-axis to show time with hourly ticks + ax1.xaxis.set_major_locator(mdates.HourLocator(interval=1)) + ax1.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M")) + fig.autofmt_xdate() + + # Adjust layout + plt.tight_layout() + + # Save plot + os.makedirs("plots", exist_ok=True) + filename = f"plots/itho_schedule{suffix}_D={D}_B={B}_S={S}_T={T}.png" + plt.savefig(filename) + # print(f"Plot saved to {filename}") + + plt.show() + + +def get_energy_target_profile_elements(number_of_elements: int, start_time: datetime): + """ + Create energy target profile elements based on time of day. + Encourage heating during off-peak hours, discourage during peak hours. + """ + target_elements = [] + + for i in range(number_of_elements): + current_time = start_time + timedelta(seconds=i * TIMESTEP_DURATION) + hour = current_time.hour + + # Energy targets in Joules per timestep + # Heat pump consumes 1100W, so per 5-minute timestep: 1100W * 300s = 330,000 J + if 0 <= hour < 6: # Night hours (00:00-06:00) - encourage heating + target_elements.append(330000) # Full power + elif 6 <= hour < 9: # Morning (06:00-09:00) - moderate + target_elements.append(165000) # Half power + elif 9 <= hour < 17: # Peak hours (09:00-17:00) - discourage + target_elements.append(0) # Minimize + elif 17 <= hour < 21: # Evening (17:00-21:00) - moderate + target_elements.append(165000) # Half power + else: # Late evening (21:00-24:00) - encourage + target_elements.append(330000) # Full power + + return target_elements + + +def get_cost_target_profile_elements(number_of_elements: int): + """ + Create cost target profile elements with dynamic pricing pattern. + Similar to the EV example. + """ + cost_elements = [] + intervals_per_hour = number_of_elements // 24 + + for hour in range(24): + if 0 <= hour < 6: # Night hours (00:00-06:00) - lowest cost + tariff = 0.10 # 10 cents per kWh + elif 6 <= hour < 9: # Morning ramp-up (06:00-09:00) + tariff = 0.15 # 15 cents per kWh + elif 9 <= hour < 17: # Peak hours (09:00-17:00) - highest cost + tariff = 0.30 # 30 cents per kWh + elif 17 <= hour < 21: # Evening peak (17:00-21:00) + tariff = 0.25 # 25 cents per kWh + else: # Late evening (21:00-24:00) + tariff = 0.15 # 15 cents per kWh + + # Add the tariff for all intervals in this hour + cost_elements.extend([tariff] * intervals_per_hour) + + return cost_elements[:number_of_elements] + + +def calculate_cost_from_energy_and_tariffs(energy_elements, tariff_elements): + """Calculate cost from energy usage and tariff rates.""" + cost_elements = [] + for energy, tariff in zip(energy_elements, tariff_elements): + if energy is not None and tariff is not None: + # Convert Joules to kWh and multiply by tariff + kwh = energy / 3_600_000 # 1 kWh = 3,600,000 Joules + cost = kwh * tariff + cost_elements.append(cost) + else: + cost_elements.append(0.0) + return cost_elements + + +def save_instructions_to_file( + device_plans_list, filename_suffix, start_time, device_state=None +): + """ + Save instruction profiles to a text file. + + Args: + device_plans_list: List of device plans containing instruction profiles + filename_suffix: Suffix for the output filename + start_time: Start time of the planning window + device_state: Device state containing operation mode mappings (optional) + """ + if not device_plans_list: + # print(f"No device plans to save for {filename_suffix}") + return + + # Create operation mode ID to name mapping + operation_mode_names = {} + if device_state and device_state.system_descriptions: + for system_desc in device_state.system_descriptions: + if hasattr(system_desc, "actuators"): + for actuator in system_desc.actuators: + if hasattr(actuator, "operation_modes"): + for mode in actuator.operation_modes: + operation_mode_names[mode.id] = mode.diagnostic_label + + os.makedirs("instructions", exist_ok=True) + filename = ( + f"instructions/itho_instructions{filename_suffix}_D={D}_B={B}_S={S}_T={T}.txt" + ) + + with open(filename, "w") as f: + f.write("=" * 80 + "\n") + f.write( + f"ITHO DHW Heat Pump Instructions{filename_suffix.replace('_', ' ').title()}\n" + ) + f.write("=" * 80 + "\n") + f.write(f"Planning start time: {start_time}\n") + f.write(f"Planning window: {PLANNING_WINDOW}\n") + f.write(f"Resolution: {PLANNING_RESOLUTION}\n") + f.write(f"Total timesteps: {T}\n") + f.write("=" * 80 + "\n\n") + + for device_plan in device_plans_list: + if device_plan and device_plan.instruction_profile: + f.write(f"Device: {device_plan.device_id}\n") + f.write( + f"Number of instructions: {len(device_plan.instruction_profile.elements)}\n" + ) + f.write("-" * 80 + "\n\n") + + instructions = device_plan.instruction_profile.elements + + # Group consecutive instructions with same operation mode + if instructions: + current_mode = None + current_mode_start = None + current_mode_start_idx = 0 + mode_count = 0 + + f.write("Instruction Timeline:\n") + f.write("-" * 80 + "\n") + + for i, instruction in enumerate(instructions): + if hasattr(instruction, "operation_mode"): + if instruction.operation_mode != current_mode: + # Print previous mode summary if exists + if current_mode is not None: + duration = i - current_mode_start_idx + duration_minutes = duration * TIMESTEP_DURATION / 60 + mode_name = operation_mode_names.get( + current_mode, current_mode + ) + f.write(f" Mode: {mode_name}\n") + f.write( + f" Start: {current_mode_start} (timestep {current_mode_start_idx})\n" + ) + f.write( + f" Duration: {duration} timesteps ({duration_minutes:.1f} minutes)\n" + ) + f.write( + f" Operation mode factor: {getattr(instruction, 'operation_mode_factor', 'N/A')}\n" + ) + f.write("-" * 40 + "\n") + mode_count += 1 + + # Start new mode + current_mode = instruction.operation_mode + current_mode_start = getattr( + instruction, "execution_time", f"Timestep {i}" + ) + current_mode_start_idx = i + + # Print final mode + if current_mode is not None: + duration = len(instructions) - current_mode_start_idx + duration_minutes = duration * TIMESTEP_DURATION / 60 + mode_name = operation_mode_names.get(current_mode, current_mode) + f.write(f" Mode: {mode_name}\n") + f.write( + f" Start: {current_mode_start} (timestep {current_mode_start_idx})\n" + ) + f.write( + f" Duration: {duration} timesteps ({duration_minutes:.1f} minutes)\n" + ) + f.write("-" * 40 + "\n") + mode_count += 1 + + f.write(f"\nTotal operation mode changes: {mode_count - 1}\n") + f.write("=" * 80 + "\n\n") + + # Detailed instruction list + f.write("Detailed Instruction List:\n") + f.write("=" * 80 + "\n") + for i, instruction in enumerate(instructions): + f.write(f"\nInstruction #{i + 1}:\n") + f.write(f" Timestep: {i}\n") + f.write( + f" Time: {start_time + timedelta(seconds=i * TIMESTEP_DURATION)}\n" + ) + + if hasattr(instruction, "id"): + f.write(f" ID: {instruction.id}\n") + if hasattr(instruction, "actuator_id"): + f.write(f" Actuator ID: {instruction.actuator_id}\n") + if hasattr(instruction, "operation_mode"): + mode_name = operation_mode_names.get( + instruction.operation_mode, instruction.operation_mode + ) + f.write(f" Operation Mode: {mode_name}\n") + if operation_mode_names.get(instruction.operation_mode): + f.write( + f" Operation Mode ID: {instruction.operation_mode}\n" + ) + if hasattr(instruction, "operation_mode_factor"): + f.write( + f" Operation Mode Factor: {instruction.operation_mode_factor}\n" + ) + if hasattr(instruction, "execution_time"): + f.write(f" Execution Time: {instruction.execution_time}\n") + + f.write("-" * 40 + "\n") + + # print(f"Instructions saved to: {filename}") + + +def test_itho_planning_with_energy_target(): + """Test the PlanningServiceImpl with ITHO DHW device using energy targets.""" + # print("=" * 80) + # print("Test 1: ITHO DHW Heat Pump with Energy Target Profile") + # print("=" * 80) + + # Start time is 15 minutes from now, aligned to 5-minute intervals + now = datetime.now(timezone.utc) + # Round to nearest 5-minute interval + minutes = (now.minute // 5) * 5 + start_time = now.replace(minute=minutes, second=0, microsecond=0) + timedelta( + minutes=15 + ) + # print(f"Planning start time: {start_time}") + + # Create profile metadata + target_metadata = ProfileMetadata( + profile_start=start_time, + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + ) + + # Create device state + device_id = "itho_dhw_device_001" + device_state = create_itho_device_state(device_id, start_time) + + # Create Dictionary of device states + device_states_dict = {device_id: device_state} + + # Create congestion points mapping + congestion_points_by_connection_id = {device_id: ""} + + # Create a cluster state + cluster_state = ClusterState( + start_time, device_states_dict, congestion_points_by_connection_id + ) + + # Create energy target profile based on time of day + target_profile_elements = get_energy_target_profile_elements(T, start_time) + global_target_profile = TargetProfile( + profile_start=target_metadata.profile_start, + timestep_duration=target_metadata.timestep_duration, + elements=target_profile_elements, + ) + + # Create a cluster target + cluster_target = ClusterTarget( + start_time, + None, + None, + global_target_profile=global_target_profile, + congestion_point_targets={}, + ) + + # Configuration similar to example_schedule_frbc.py + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + + # print("Generating plan...") + + # Create planning service implementation + service = PlanningServiceImpl(config) + + # Generate a plan + plan_due_by_date = start_time + timedelta(seconds=10) + start_planning_time = time.time() + + cluster_plan = service.plan( + state=cluster_state, + target=cluster_target, + planning_window=TIMESTEP_DURATION * T, + reason="ITHO DHW Heat Pump scheduling", + plan_due_by_date=plan_due_by_date, + optimize_for_target=True, + max_priority_class=1, + ) + + end_planning_time = time.time() + execution_time = end_planning_time - start_planning_time + + print(f"Plan generated in {execution_time:.2f} seconds") + + # Assert and process results + assert cluster_plan is not None, "Cluster plan is None" + print("Successfully generated cluster plan") + + # Get the plan data + device_plans = cluster_plan.get_plan_data().get_device_plans() + energy_profile = cluster_plan.get_joule_profile() + + # Convert Joules to Watts (W = J / timestep_in_seconds) + power_profile_watts = [ + energy / TIMESTEP_DURATION if energy is not None else 0 + for energy in energy_profile.elements + ] + + # Get fill level profile if available + fill_level_profile = None + device_plans_list = [plan for plan in device_plans if plan is not None] + + if device_plans_list: + device_plan = device_plans_list[0] + if ( + hasattr(device_plan, "fill_level_profile") + and device_plan.fill_level_profile + ): + fill_level_profile = device_plan.fill_level_profile.elements + print( + f"Fill level profile available with {len(fill_level_profile)} elements" + ) + + if device_plan.instruction_profile: + instructions = device_plan.instruction_profile.elements + print(f"Device has {len(instructions)} instructions") + + # Analyze operation mode changes + mode_changes = 0 + previous_mode = None + for instruction in instructions: + if hasattr(instruction, "operation_mode"): + if previous_mode and instruction.operation_mode != previous_mode: + mode_changes += 1 + previous_mode = instruction.operation_mode + # print(f"Number of operation mode changes: {mode_changes}") + + # Calculate total energy consumption + total_energy_kwh = sum(energy_profile.elements) / 3_600_000 + print(f"Total energy consumption: {total_energy_kwh:.2f} kWh") + + # Extract fill level targets from device state + fill_level_target_min = None + fill_level_target_max = None + if device_state.fill_level_target_profiles: + target_profile = device_state.fill_level_target_profiles[0] + ( + fill_level_target_min, + fill_level_target_max, + ) = convert_fill_level_target_to_timeseries( + target_profile, + start_time, + timedelta(seconds=TIMESTEP_DURATION), + T, + ) + # print("Fill level targets extracted from device state") + + # Save instructions to file + save_instructions_to_file(device_plans_list, "_energy", start_time, device_state) + + # Plot the results + plot_planning_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + predicted_energy_elements=power_profile_watts, + fill_level_profile=fill_level_profile, + fill_level_target_min=fill_level_target_min, + fill_level_target_max=fill_level_target_max, + start_time=start_time, + suffix="_energy", + ) + + # print("ITHO energy target test completed successfully!") + + return cluster_plan + + +def test_itho_planning_with_constant_cost(): + """Test the PlanningServiceImpl with ITHO DHW device using constant cost.""" + # print("\n" + "=" * 80) + # print("Test 2: ITHO DHW Heat Pump with Constant Cost (1 EUR/kWh)") + # print("=" * 80) + + # Start time is 15 minutes from now, aligned to 5-minute intervals + now = datetime.now(timezone.utc) + # Round to nearest 5-minute interval + minutes = (now.minute // 5) * 5 + start_time = now.replace(minute=minutes, second=0, microsecond=0) + timedelta( + minutes=15 + ) + # print(f"Planning start time: {start_time}") + + # Create profile metadata + target_metadata = ProfileMetadata( + profile_start=start_time, + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + ) + + # Create device state + device_id = "itho_dhw_device_002" + device_state = create_itho_device_state(device_id, start_time) + + # Create Dictionary of device states + device_states_dict = {device_id: device_state} + + # Create congestion points mapping + congestion_points_by_connection_id = {device_id: ""} + + # Create a cluster state + cluster_state = ClusterState( + start_time, device_states_dict, congestion_points_by_connection_id + ) + + # Create constant cost target profile (1 EUR/kWh for all timesteps) + constant_cost_elements = [1.0] * T + + # Create a cost-based target profile + cost_target_profile = TargetProfile.from_tariff_values( + target_metadata, constant_cost_elements + ) + + # Create a cluster target with cost target + cluster_target = ClusterTarget( + start_time, + None, + None, + global_target_profile=cost_target_profile, + congestion_point_targets={}, + ) + + # Configuration similar to example_schedule_frbc.py + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + + # print("Generating constant-cost plan...") + + # Create planning service implementation + service = PlanningServiceImpl(config) + + # Generate a plan + plan_due_by_date = start_time + timedelta(seconds=10) + # start_planning_time = time.time() + + cluster_plan = service.plan( + state=cluster_state, + target=cluster_target, + planning_window=TIMESTEP_DURATION * T, + reason="ITHO DHW Heat Pump constant cost optimization", + plan_due_by_date=plan_due_by_date, + optimize_for_target=True, + max_priority_class=1, + ) + + # end_planning_time = time.time() + # execution_time = end_planning_time - start_planning_time + + # print(f"Constant-cost plan generated in {execution_time:.2f} seconds") + + # Assert and process results + assert cluster_plan is not None, "Cluster plan is None" + # print("Successfully generated constant-cost cluster plan") + + # Get the plan data + device_plans = cluster_plan.get_plan_data().get_device_plans() + energy_profile = cluster_plan.get_joule_profile() + + # Convert Joules to Watts (W = J / timestep_in_seconds) + power_profile_watts = [ + energy / TIMESTEP_DURATION if energy is not None else 0 + for energy in energy_profile.elements + ] + + # Get fill level profile if available + fill_level_profile = None + device_plans_list = [plan for plan in device_plans if plan is not None] + + if device_plans_list: + device_plan = device_plans_list[0] + if ( + hasattr(device_plan, "fill_level_profile") + and device_plan.fill_level_profile + ): + fill_level_profile = device_plan.fill_level_profile.elements + print( + f"Fill level profile available with {len(fill_level_profile)} elements" + ) + + if device_plan.instruction_profile: + instructions = device_plan.instruction_profile.elements + # print(f"Device has {len(instructions)} instructions") + + # Analyze operation mode changes + mode_changes = 0 + previous_mode = None + for instruction in instructions: + if hasattr(instruction, "operation_mode"): + if previous_mode and instruction.operation_mode != previous_mode: + mode_changes += 1 + previous_mode = instruction.operation_mode + # print(f"Number of operation mode changes: {mode_changes}") + + # Calculate total energy consumption + # total_energy_kwh = sum(energy_profile.elements) / 3_600_000 + # print(f"Total energy consumption: {total_energy_kwh:.2f} kWh") + + # Calculate the actual costs from the energy profile and tariffs + # cost_elements = calculate_cost_from_energy_and_tariffs( + # energy_profile.elements, constant_cost_elements + # ) + # total_cost = sum(cost_elements) + # print(f"Total cost: €{total_cost:.2f}") + + # Extract fill level targets from device state + fill_level_target_min = None + fill_level_target_max = None + if device_state.fill_level_target_profiles: + target_profile = device_state.fill_level_target_profiles[0] + ( + fill_level_target_min, + fill_level_target_max, + ) = convert_fill_level_target_to_timeseries( + target_profile, + start_time, + timedelta(seconds=TIMESTEP_DURATION), + T, + ) + # print("Fill level targets extracted from device state") + + # Save instructions to file + save_instructions_to_file( + device_plans_list, "_constant_cost", start_time, device_state + ) + + # Plot the results with constant tariff information + plot_planning_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + predicted_energy_elements=power_profile_watts, + fill_level_profile=fill_level_profile, + fill_level_target_min=fill_level_target_min, + fill_level_target_max=fill_level_target_max, + start_time=start_time, + suffix="_constant_cost", + tariff_elements=constant_cost_elements, + ) + + # print("ITHO constant cost test completed successfully!") + + return cluster_plan + + +def test_itho_planning_with_cost_target(): + """Test the PlanningServiceImpl with ITHO DHW device using variable cost targets.""" + # print("\n" + "=" * 80) + # print("Test 3: ITHO DHW Heat Pump with Variable Cost Target Profile") + # print("=" * 80) + + # Start time is 15 minutes from now, aligned to 5-minute intervals + now = datetime.now(timezone.utc) + # Round to nearest 5-minute interval + minutes = (now.minute // 5) * 5 + start_time = now.replace(minute=minutes, second=0, microsecond=0) + timedelta( + minutes=15 + ) + # print(f"Planning start time: {start_time}") + + # Create profile metadata + target_metadata = ProfileMetadata( + profile_start=start_time, + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + ) + + # Create device state + device_id = "itho_dhw_device_003" + device_state = create_itho_device_state(device_id, start_time) + + # Create Dictionary of device states + device_states_dict = {device_id: device_state} + + # Create congestion points mapping + congestion_points_by_connection_id = {device_id: ""} + + # Create a cluster state + cluster_state = ClusterState( + start_time, device_states_dict, congestion_points_by_connection_id + ) + + # Create variable cost target profile + cost_target_elements = get_cost_target_profile_elements(T) + + # Create a cost-based target profile + cost_target_profile = TargetProfile.from_tariff_values( + target_metadata, cost_target_elements + ) + + # Create a cluster target with cost target + cluster_target = ClusterTarget( + start_time, + None, + None, + global_target_profile=cost_target_profile, + congestion_point_targets={}, + ) + + # Configuration similar to example_schedule_frbc.py + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + + # print("Generating cost-optimized plan...") + + # Create planning service implementation + service = PlanningServiceImpl(config) + + # Generate a plan + plan_due_by_date = start_time + timedelta(seconds=10) + start_planning_time = time.time() + + cluster_plan = service.plan( + state=cluster_state, + target=cluster_target, + planning_window=TIMESTEP_DURATION * T, + reason="ITHO DHW Heat Pump cost optimization", + plan_due_by_date=plan_due_by_date, + optimize_for_target=True, + max_priority_class=1, + ) + + end_planning_time = time.time() + execution_time = end_planning_time - start_planning_time + + print(f"Cost-optimized plan generated in {execution_time:.2f} seconds") + + # Assert and process results + assert cluster_plan is not None, "Cluster plan is None" + print("Successfully generated cost-optimized cluster plan") + + # Get the plan data + device_plans = cluster_plan.get_plan_data().get_device_plans() + energy_profile = cluster_plan.get_joule_profile() + + # Convert Joules to Watts (W = J / timestep_in_seconds) + power_profile_watts = [ + energy / TIMESTEP_DURATION if energy is not None else 0 + for energy in energy_profile.elements + ] + + # Get fill level profile if available + fill_level_profile = None + device_plans_list = [plan for plan in device_plans if plan is not None] + + if device_plans_list: + device_plan = device_plans_list[0] + if ( + hasattr(device_plan, "fill_level_profile") + and device_plan.fill_level_profile + ): + fill_level_profile = device_plan.fill_level_profile.elements + print( + f"Fill level profile available with {len(fill_level_profile)} elements" + ) + + if device_plan.instruction_profile: + instructions = device_plan.instruction_profile.elements + # print(f"Device has {len(instructions)} instructions") + + # Analyze operation mode changes + mode_changes = 0 + previous_mode = None + for instruction in instructions: + if hasattr(instruction, "operation_mode"): + if previous_mode and instruction.operation_mode != previous_mode: + mode_changes += 1 + previous_mode = instruction.operation_mode + # print(f"Number of operation mode changes: {mode_changes}") + + # Calculate total energy consumption + total_energy_kwh = sum(energy_profile.elements) / 3_600_000 + print(f"Total energy consumption: {total_energy_kwh:.2f} kWh") + + # Calculate the actual costs from the energy profile and tariffs + cost_elements = calculate_cost_from_energy_and_tariffs( + energy_profile.elements, cost_target_elements + ) + total_cost = sum(cost_elements) + print(f"Total cost: ${total_cost:.2f}") + + # Extract fill level targets from device state + fill_level_target_min = None + fill_level_target_max = None + if device_state.fill_level_target_profiles: + target_profile = device_state.fill_level_target_profiles[0] + ( + fill_level_target_min, + fill_level_target_max, + ) = convert_fill_level_target_to_timeseries( + target_profile, + start_time, + timedelta(seconds=TIMESTEP_DURATION), + T, + ) + # print("Fill level targets extracted from device state") + + # Save instructions to file + save_instructions_to_file(device_plans_list, "_cost", start_time, device_state) + + # Plot the results with tariff information + plot_planning_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + predicted_energy_elements=power_profile_watts, + fill_level_profile=fill_level_profile, + fill_level_target_min=fill_level_target_min, + fill_level_target_max=fill_level_target_max, + start_time=start_time, + suffix="_cost", + tariff_elements=cost_target_elements, + ) + + # print("ITHO cost target test completed successfully!") + + return cluster_plan + + +def test_itho_planning_with_usage_forecast_only(): + """Test the PlanningServiceImpl with ITHO DHW device using ONLY usage forecast (no fill level target).""" + # print("\n" + "=" * 80) + # print( + # "Test 4: ITHO DHW Heat Pump with Usage Forecast ONLY (no FillLevelTargetProfile)" + # ) + # print("=" * 80) + + # Start time is 15 minutes from now, aligned to 5-minute intervals + now = datetime.now(timezone.utc) + # Round to nearest 5-minute interval + minutes = (now.minute // 5) * 5 + start_time = now.replace(minute=minutes, second=0, microsecond=0) + timedelta( + minutes=15 + ) + # print(f"Planning start time: {start_time}") + + # Create profile metadata + target_metadata = ProfileMetadata( + profile_start=start_time, + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + ) + + # Create device state WITH usage forecast but WITHOUT fill level target + device_id = "itho_dhw_device_004" + device_state = create_itho_device_state( + device_id, + start_time, + include_fill_level_target=False, # NO fill level target + include_usage_forecast=True, # YES usage forecast + ) + + # Create Dictionary of device states + device_states_dict = {device_id: device_state} + + # Create congestion points mapping + congestion_points_by_connection_id = {device_id: ""} + + # Create a cluster state + cluster_state = ClusterState( + start_time, device_states_dict, congestion_points_by_connection_id + ) + + # Create variable cost target profile + cost_target_elements = get_cost_target_profile_elements(T) + + # Create a cost-based target profile + cost_target_profile = TargetProfile.from_tariff_values( + target_metadata, cost_target_elements + ) + + # Create a cluster target with cost target + cluster_target = ClusterTarget( + start_time, + None, + None, + global_target_profile=cost_target_profile, + congestion_point_targets={}, + ) + + # Configuration similar to example_schedule_frbc.py + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + + # print("Generating plan with usage forecast only (no fill level target)...") + + # Create planning service implementation + service = PlanningServiceImpl(config) + + # Generate a plan + plan_due_by_date = start_time + timedelta(seconds=10) + # start_planning_time = time.time() + + cluster_plan = service.plan( + state=cluster_state, + target=cluster_target, + planning_window=TIMESTEP_DURATION * T, + reason="ITHO DHW Heat Pump with usage forecast only", + plan_due_by_date=plan_due_by_date, + optimize_for_target=True, + max_priority_class=1, + ) + + # end_planning_time = time.time() + # execution_time = end_planning_time - start_planning_time + + # print(f"Plan generated in {execution_time:.2f} seconds") + + # Assert and process results + assert cluster_plan is not None, "Cluster plan is None" + # print("Successfully generated cluster plan with usage forecast only") + + # Get the plan data + device_plans = cluster_plan.get_plan_data().get_device_plans() + energy_profile = cluster_plan.get_joule_profile() + + # Convert Joules to Watts (W = J / timestep_in_seconds) + power_profile_watts = [ + energy / TIMESTEP_DURATION if energy is not None else 0 + for energy in energy_profile.elements + ] + + # Get fill level profile if available + fill_level_profile = None + device_plans_list = [plan for plan in device_plans if plan is not None] + + if device_plans_list: + device_plan = device_plans_list[0] + if ( + hasattr(device_plan, "fill_level_profile") + and device_plan.fill_level_profile + ): + fill_level_profile = device_plan.fill_level_profile.elements + print( + f"Fill level profile available with {len(fill_level_profile)} elements" + ) + + if device_plan.instruction_profile: + instructions = device_plan.instruction_profile.elements + # print(f"Device has {len(instructions)} instructions") + + # Analyze operation mode changes + mode_changes = 0 + previous_mode = None + for instruction in instructions: + if hasattr(instruction, "operation_mode"): + if previous_mode and instruction.operation_mode != previous_mode: + mode_changes += 1 + previous_mode = instruction.operation_mode + # print(f"Number of operation mode changes: {mode_changes}") + + # Calculate total energy consumption + # total_energy_kwh = sum(energy_profile.elements) / 3_600_000 + # print(f"Total energy consumption: {total_energy_kwh:.2f} kWh") + + # Calculate the actual costs from the energy profile and tariffs + # cost_elements = calculate_cost_from_energy_and_tariffs( + # energy_profile.elements, cost_target_elements + # ) + # total_cost = sum(cost_elements) + # print(f"Total cost: ${total_cost:.2f}") + + # No fill level targets to extract (they were not included) + fill_level_target_min = None + fill_level_target_max = None + # print("No fill level targets (test uses usage forecast only)") + + # Save instructions to file + save_instructions_to_file( + device_plans_list, "_usage_only", start_time, device_state + ) + + # Plot the results with tariff information + plot_planning_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + predicted_energy_elements=power_profile_watts, + fill_level_profile=fill_level_profile, + fill_level_target_min=fill_level_target_min, + fill_level_target_max=fill_level_target_max, + start_time=start_time, + suffix="_usage_only", + tariff_elements=cost_target_elements, + ) + + # print("ITHO usage forecast only test completed successfully!") + + return cluster_plan + + +def test_itho_planning_with_fill_level_target_only(): + """Test the PlanningServiceImpl with ITHO DHW device using ONLY fill level target (no usage forecast).""" + # print("\n" + "=" * 80) + # print( + # "Test 5: ITHO DHW Heat Pump with FillLevelTargetProfile ONLY (no UsageForecast)" + # ) + # print("=" * 80) + + # Start time is 15 minutes from now, aligned to 5-minute intervals + now = datetime.now(timezone.utc) + # Round to nearest 5-minute interval + minutes = (now.minute // 5) * 5 + start_time = now.replace(minute=minutes, second=0, microsecond=0) + timedelta( + minutes=15 + ) + # print(f"Planning start time: {start_time}") + + # Create profile metadata + target_metadata = ProfileMetadata( + profile_start=start_time, + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + ) + + # Create device state WITH fill level target but WITHOUT usage forecast + device_id = "itho_dhw_device_005" + device_state = create_itho_device_state( + device_id, + start_time, + include_fill_level_target=True, # YES fill level target + include_usage_forecast=False, # NO usage forecast + ) + + # Create Dictionary of device states + device_states_dict = {device_id: device_state} + + # Create congestion points mapping + congestion_points_by_connection_id = {device_id: ""} + + # Create a cluster state + cluster_state = ClusterState( + start_time, device_states_dict, congestion_points_by_connection_id + ) + + # Create variable cost target profile + cost_target_elements = get_cost_target_profile_elements(T) + + # Create a cost-based target profile + cost_target_profile = TargetProfile.from_tariff_values( + target_metadata, cost_target_elements + ) + + # Create a cluster target with cost target + cluster_target = ClusterTarget( + start_time, + None, + None, + global_target_profile=cost_target_profile, + congestion_point_targets={}, + ) + + # Configuration similar to example_schedule_frbc.py + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + + # print("Generating plan with fill level target only (no usage forecast)...") + + # Create planning service implementation + service = PlanningServiceImpl(config) + + # Generate a plan + plan_due_by_date = start_time + timedelta(seconds=10) + # start_planning_time = time.time() + + cluster_plan = service.plan( + state=cluster_state, + target=cluster_target, + planning_window=TIMESTEP_DURATION * T, + reason="ITHO DHW Heat Pump with fill level target only", + plan_due_by_date=plan_due_by_date, + optimize_for_target=True, + max_priority_class=1, + ) + + # end_planning_time = time.time() + # execution_time = end_planning_time - start_planning_time + + # print(f"Plan generated in {execution_time:.2f} seconds") + + # Assert and process results + assert cluster_plan is not None, "Cluster plan is None" + # print("Successfully generated cluster plan with fill level target only") + + # Get the plan data + device_plans = cluster_plan.get_plan_data().get_device_plans() + energy_profile = cluster_plan.get_joule_profile() + + # Convert Joules to Watts (W = J / timestep_in_seconds) + power_profile_watts = [ + energy / TIMESTEP_DURATION if energy is not None else 0 + for energy in energy_profile.elements + ] + + # Get fill level profile if available + fill_level_profile = None + device_plans_list = [plan for plan in device_plans if plan is not None] + + if device_plans_list: + device_plan = device_plans_list[0] + if ( + hasattr(device_plan, "fill_level_profile") + and device_plan.fill_level_profile + ): + fill_level_profile = device_plan.fill_level_profile.elements + print( + f"Fill level profile available with {len(fill_level_profile)} elements" + ) + + if device_plan.instruction_profile: + instructions = device_plan.instruction_profile.elements + # print(f"Device has {len(instructions)} instructions") + + # Analyze operation mode changes + mode_changes = 0 + previous_mode = None + for instruction in instructions: + if hasattr(instruction, "operation_mode"): + if previous_mode and instruction.operation_mode != previous_mode: + mode_changes += 1 + previous_mode = instruction.operation_mode + # print(f"Number of operation mode changes: {mode_changes}") + + # Calculate total energy consumption + total_energy_kwh = sum(energy_profile.elements) / 3_600_000 + print(f"Total energy consumption: {total_energy_kwh:.2f} kWh") + + # Calculate the actual costs from the energy profile and tariffs + cost_elements = calculate_cost_from_energy_and_tariffs( + energy_profile.elements, cost_target_elements + ) + total_cost = sum(cost_elements) + print(f"Total cost: ${total_cost:.2f}") + + # Extract fill level targets from device state + fill_level_target_min = None + fill_level_target_max = None + if device_state.fill_level_target_profiles: + target_profile = device_state.fill_level_target_profiles[0] + ( + fill_level_target_min, + fill_level_target_max, + ) = convert_fill_level_target_to_timeseries( + target_profile, + start_time, + timedelta(seconds=TIMESTEP_DURATION), + T, + ) + # print("Fill level targets extracted from device state") + else: + print("No fill level targets found in device state") + + # Save instructions to file + save_instructions_to_file( + device_plans_list, "_filltarget_only", start_time, device_state + ) + + # Plot the results with tariff information + plot_planning_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + predicted_energy_elements=power_profile_watts, + fill_level_profile=fill_level_profile, + fill_level_target_min=fill_level_target_min, + fill_level_target_max=fill_level_target_max, + start_time=start_time, + suffix="_filltarget_only", + tariff_elements=cost_target_elements, + ) + + # print("ITHO fill level target only test completed successfully!") + + return cluster_plan + + +if __name__ == "__main__": + # Configure logging to show DEBUG messages + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + datefmt="%H:%M:%S", + ) + + # Optionally, set specific loggers to different levels + # logging.getLogger('matplotlib').setLevel(logging.WARNING) + + # print("=" * 80) + # print("ITHO DHW Heat Pump Planning Examples with DEBUG Logging") + # print("=" * 80) + # print() + + # Test 1: Energy targeting + # test_itho_planning_with_energy_target() + + # print("\n" + "=" * 80 + "\n") + + # Test 2: Constant cost (1 EUR/kWh) + # test_itho_planning_with_constant_cost() + + # print("\n" + "=" * 80 + "\n") + + # Test 3: Variable cost targeting (with both fill level target and usage forecast) + # test_itho_planning_with_cost_target() + + # print("\n" + "=" * 80 + "\n") + + # Test 4: Usage forecast ONLY (no fill level target) + # test_itho_planning_with_usage_forecast_only() + + # print("\n" + "=" * 80 + "\n") + + # Test 5: Fill level target ONLY (no usage forecast) + test_itho_planning_with_fill_level_target_only() + + # Default: run Test 3 (variable cost with both profiles) + # test_itho_planning_with_cost_target() diff --git a/flexmeasures_s2/profile_steering/examples/example_schedule_nocontrol.py b/flexmeasures_s2/profile_steering/examples/example_schedule_nocontrol.py new file mode 100644 index 0000000..c1f5f8c --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/example_schedule_nocontrol.py @@ -0,0 +1,284 @@ +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from datetime import datetime, timedelta, timezone + +# import time +import pandas as pd +import os +import uuid +from s2python.common import PowerForecast, PowerValue, CommodityQuantity +from s2python.common import PowerForecastElement, PowerForecastValue +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_state import ( + S2NoControlDeviceState, +) +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata + +from flexmeasures_s2.scheduler.schedulers import ( + PlanningServiceImpl, + PlanningServiceConfig, + ClusterState, + ClusterTarget, +) +import matplotlib.dates as mdates +import matplotlib.pyplot as plt + +D = 3 +PLANNING_WINDOW = pd.Timedelta("PT24H") +PLANNING_RESOLUTION = pd.Timedelta("PT5M") + +T = PLANNING_WINDOW // PLANNING_RESOLUTION +TIMESTEP_DURATION = PLANNING_RESOLUTION / pd.Timedelta("PT1S") + + +def create_simple_power_forecast( + start_time: datetime, nr_of_timesteps: int, timestep_duration: float +) -> PowerForecast: + """ + Create a simple power forecast with varying consumption. + This simulates a device with fixed consumption pattern (e.g., a fridge). + + Args: + start_time: When the forecast starts + nr_of_timesteps: Number of timesteps + timestep_duration: Duration of each timestep in seconds + + Returns: + A PowerForecast with a realistic consumption pattern + """ + elements = [] + + for i in range(nr_of_timesteps): + if i % 12 == 0: + power_watts = 150.0 + elif i % 12 < 3: + power_watts = 150.0 + else: + power_watts = 0.0 + + power_value = PowerForecastValue( + value_expected=power_watts, + commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1, + ) + + element = PowerForecastElement( + duration=int(timestep_duration), power_values=[power_value] + ) + elements.append(element) + + return PowerForecast( + message_id=str(uuid.uuid4()), + start_time=start_time, + elements=elements, + ) + + +def create_nocontrol_device_state( + device_id: str, start_time: datetime, nr_of_timesteps: int, timestep_duration: float +) -> S2NoControlDeviceState: + """ + Create a nocontrol device state (e.g., for a non-controllable load like a fridge). + + Args: + device_id: ID of the device + start_time: When the planning starts + nr_of_timesteps: Number of timesteps + timestep_duration: Duration of each timestep in seconds + + Returns: + An S2NoControlDeviceState with a power forecast + """ + power_forecast = create_simple_power_forecast( + start_time, nr_of_timesteps, timestep_duration + ) + + device_state = S2NoControlDeviceState( + device_id=device_id, + device_name=device_id, + connection_id=device_id + "_connection", + priority_class=1, + timestamp=start_time, + energy_in_current_timestep=PowerValue( + value=0, commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1 + ), + is_online=True, + power_forecast=power_forecast, + ) + return device_state + + +def plot_planning_results( + timestep_duration, + nr_of_timesteps, + predicted_energy_elements, + target_energy_elements, +): + """ + Plots the energy comparison. + + :param timestep_duration: Duration of each timestep. + :param nr_of_timesteps: Number of timesteps. + :param predicted_energy_elements: List of predicted energy values. + :param target_energy_elements: List of target energy values. + """ + timestep_start_times = [ + datetime(1970, 1, 1, tzinfo=timezone.utc) + + timedelta(seconds=i * timestep_duration.total_seconds()) + for i in range(nr_of_timesteps) + ] + + fig, ax1 = plt.subplots(1, 1, figsize=(12, 8)) + + ax1.plot( + timestep_start_times, + predicted_energy_elements, + label="Predicted Energy (NoControl Devices)", + color="green", + ) + ax1.plot( + timestep_start_times, + target_energy_elements, + label="Target Energy", + color="red", + linestyle="dotted", + linewidth=2, + ) + + ax1.set_ylabel("Energy (Joules)") + ax1.set_title("Predicted vs Target Energy - NoControl Devices") + ax1.legend(loc="best") + ax1.grid(True) + + ax1.xaxis.set_major_locator(mdates.MinuteLocator(interval=30)) + ax1.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M:%S")) + fig.autofmt_xdate() + + plt.tight_layout() + os.makedirs("plots", exist_ok=True) + plt.savefig(f"plots/nocontrol_plot_D={D}_T={T}.png") + # print(f"Plot saved to plots/nocontrol_plot_D={D}_T={T}.png") + + +def get_target_profile_elements(number_of_elements: int): + """Create target profile elements.""" + target_elements = [] + target_elements.extend([0] * 38) + target_elements.extend([8400000] * 62) + target_elements.extend([0] * 45) + target_elements.extend([8400000] * 28) + target_elements.extend([176000000] * 115) + return target_elements[:number_of_elements] + + +def test_planning_service_impl_with_nocontrol_devices(): + """Test the PlanningServiceImpl with nocontrol devices.""" + # print("Testing PlanningServiceImpl with nocontrol devices") + # print(f"Number of devices: {D}") + # print(f"Number of timesteps: {T}") + + target_metadata = ProfileMetadata( + profile_start=datetime(1970, 1, 1, tzinfo=timezone.utc), + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + ) + plan_due_by_date = target_metadata.profile_start + timedelta(seconds=10) + target_profile_elements = get_target_profile_elements(T) + + global_target_profile = TargetProfile( + profile_start=target_metadata.profile_start, + timestep_duration=target_metadata.timestep_duration, + elements=target_profile_elements, + ) + + device_states = [ + create_nocontrol_device_state( + f"nocontrol_device_{i + 1}", + target_metadata.profile_start, + T, + TIMESTEP_DURATION, + ) + for i in range(D) + ] + + device_states_dict = { + device_state.device_id: device_state for device_state in device_states + } + + congestion_points_by_connection_id = { + device_state.connection_id: "" for device_state in device_states + } + + cluster_state = ClusterState( + datetime.now(), device_states_dict, congestion_points_by_connection_id + ) + + congestion_point_targets = {} + cluster_target = ClusterTarget( + datetime.now(), + None, + None, + global_target_profile=global_target_profile, + congestion_point_targets=congestion_point_targets, + ) + + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + + # print("Generating plan!") + + service = PlanningServiceImpl(config) + + # start_time = time.time() + cluster_plan = service.plan( + state=cluster_state, + target=cluster_target, + planning_window=TIMESTEP_DURATION * T, + reason="Testing NoControl planning", + plan_due_by_date=plan_due_by_date, + optimize_for_target=True, + max_priority_class=1, + ) + # end_time = time.time() + # execution_time = end_time - start_time + + # print(f"Plan generated in {execution_time:.2f} seconds") + + assert cluster_plan is not None + # print("Got cluster plan") + + if cluster_plan is None: + # print("Cluster plan is None") + return + + device_plans = cluster_plan.get_plan_data().get_device_plans() + energy_profile = cluster_plan.get_joule_profile() + + plot_planning_results( + timestep_duration=timedelta(seconds=TIMESTEP_DURATION), + nr_of_timesteps=T, + predicted_energy_elements=energy_profile.elements, + target_energy_elements=target_profile_elements, + ) + + device_plans = [plan for plan in device_plans if plan is not None] + + assert len(device_plans) > 0 + # print(f"Got {len(device_plans)} device plans") + + for device_plan in device_plans: + if device_plan: + # print(f"Device {device_plan.device_id}:") + # print( + # f" Total energy: {sum(e for e in device_plan.energy_profile.elements if e is not None)} Joules" + # ) + # print(f" Instruction profile: {device_plan.instruction_profile}") + pass + + assert len(energy_profile.elements) == target_metadata.nr_of_timesteps + # print("Test completed successfully!") + + +if __name__ == "__main__": + test_planning_service_impl_with_nocontrol_devices() diff --git a/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_constant_cost_D=1_B=200_S=30_T=288.txt b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_constant_cost_D=1_B=200_S=30_T=288.txt new file mode 100644 index 0000000..dc24305 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_constant_cost_D=1_B=200_S=30_T=288.txt @@ -0,0 +1,3208 @@ +================================================================================ +ITHO DHW Heat Pump Instructions Constant Cost +================================================================================ +Planning start time: 2025-11-03 10:30:00+00:00 +Planning window: 1 days 00:00:00 +Resolution: 0 days 00:05:00 +Total timesteps: 288 +================================================================================ + +Device: itho_dhw_device_002 +Number of instructions: 288 +-------------------------------------------------------------------------------- + +Instruction Timeline: +-------------------------------------------------------------------------------- + Mode: DHW_ON + Start: 2025-11-03 10:30:00+00:00 (timestep 0) + Duration: 17 timesteps (85.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-03 11:55:00+00:00 (timestep 17) + Duration: 8 timesteps (40.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-03 12:35:00+00:00 (timestep 25) + Duration: 6 timesteps (30.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-03 13:05:00+00:00 (timestep 31) + Duration: 257 timesteps (1285.0 minutes) +---------------------------------------- + +Total operation mode changes: 3 +================================================================================ + +Detailed Instruction List: +================================================================================ + +Instruction #1: + Timestep: 0 + Time: 2025-11-03 10:30:00+00:00 + ID: 83c7f07d-5297-45e6-ac4f-89ef120dc6f0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:30:00+00:00 +---------------------------------------- + +Instruction #2: + Timestep: 1 + Time: 2025-11-03 10:35:00+00:00 + ID: 7bf4e491-4b12-4832-9ca1-f7d891eb1740 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:35:00+00:00 +---------------------------------------- + +Instruction #3: + Timestep: 2 + Time: 2025-11-03 10:40:00+00:00 + ID: b14bd3e5-3b10-45e2-a82c-b116d1e8e3fd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:40:00+00:00 +---------------------------------------- + +Instruction #4: + Timestep: 3 + Time: 2025-11-03 10:45:00+00:00 + ID: 3af14ed7-54c7-4c44-9f7d-97d48890f7b7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:45:00+00:00 +---------------------------------------- + +Instruction #5: + Timestep: 4 + Time: 2025-11-03 10:50:00+00:00 + ID: f3eb8014-5053-4e4f-826f-ddd8fa10f84d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:50:00+00:00 +---------------------------------------- + +Instruction #6: + Timestep: 5 + Time: 2025-11-03 10:55:00+00:00 + ID: 1722d79e-5182-4313-8127-090dc2f70dcb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:55:00+00:00 +---------------------------------------- + +Instruction #7: + Timestep: 6 + Time: 2025-11-03 11:00:00+00:00 + ID: 6cbc4461-c952-4a46-9a97-13c3eaa7ea34 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:00:00+00:00 +---------------------------------------- + +Instruction #8: + Timestep: 7 + Time: 2025-11-03 11:05:00+00:00 + ID: 137dbfb8-c8cc-492c-ab90-697eebc4a38d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:05:00+00:00 +---------------------------------------- + +Instruction #9: + Timestep: 8 + Time: 2025-11-03 11:10:00+00:00 + ID: 37231f02-26be-41b0-82ec-34f598c99a5b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:10:00+00:00 +---------------------------------------- + +Instruction #10: + Timestep: 9 + Time: 2025-11-03 11:15:00+00:00 + ID: 74f23dc3-a418-435d-94fc-3a7f3201f43f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:15:00+00:00 +---------------------------------------- + +Instruction #11: + Timestep: 10 + Time: 2025-11-03 11:20:00+00:00 + ID: bdae9b40-e19c-459c-8082-e125267772a8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:20:00+00:00 +---------------------------------------- + +Instruction #12: + Timestep: 11 + Time: 2025-11-03 11:25:00+00:00 + ID: 864f7e87-98cf-4010-a75c-aef9a20f7cab + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:25:00+00:00 +---------------------------------------- + +Instruction #13: + Timestep: 12 + Time: 2025-11-03 11:30:00+00:00 + ID: a1381b07-3039-43a2-bc2f-83e5d31b8b06 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:30:00+00:00 +---------------------------------------- + +Instruction #14: + Timestep: 13 + Time: 2025-11-03 11:35:00+00:00 + ID: 87ed4010-8bbe-4bfa-81fc-e65e06a4f0ab + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:35:00+00:00 +---------------------------------------- + +Instruction #15: + Timestep: 14 + Time: 2025-11-03 11:40:00+00:00 + ID: d369e94e-9b3a-4039-bc6c-9d52c31eb16b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:40:00+00:00 +---------------------------------------- + +Instruction #16: + Timestep: 15 + Time: 2025-11-03 11:45:00+00:00 + ID: 4fd54730-4822-461b-a497-ad38c3dcac11 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:45:00+00:00 +---------------------------------------- + +Instruction #17: + Timestep: 16 + Time: 2025-11-03 11:50:00+00:00 + ID: cbbbaeb3-8263-44ea-aea9-b2087c59ac30 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:50:00+00:00 +---------------------------------------- + +Instruction #18: + Timestep: 17 + Time: 2025-11-03 11:55:00+00:00 + ID: f15d55f8-6ab6-48d4-b47b-c33e5d608a7a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:55:00+00:00 +---------------------------------------- + +Instruction #19: + Timestep: 18 + Time: 2025-11-03 12:00:00+00:00 + ID: 7af9d1f5-69cf-471a-82e5-ac154b55d917 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:00:00+00:00 +---------------------------------------- + +Instruction #20: + Timestep: 19 + Time: 2025-11-03 12:05:00+00:00 + ID: 3a346742-be03-4b61-8574-ab8f27f611ef + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:05:00+00:00 +---------------------------------------- + +Instruction #21: + Timestep: 20 + Time: 2025-11-03 12:10:00+00:00 + ID: c8f5a56f-311c-487a-b999-9da111e0c397 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:10:00+00:00 +---------------------------------------- + +Instruction #22: + Timestep: 21 + Time: 2025-11-03 12:15:00+00:00 + ID: a85db965-9c0a-4ecf-9213-5e3961d536f6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:15:00+00:00 +---------------------------------------- + +Instruction #23: + Timestep: 22 + Time: 2025-11-03 12:20:00+00:00 + ID: f2de2882-53f3-4e60-9e23-4d3808dc70b8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:20:00+00:00 +---------------------------------------- + +Instruction #24: + Timestep: 23 + Time: 2025-11-03 12:25:00+00:00 + ID: 34cc7850-c214-4fa3-92db-79cb6ce38e5e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:25:00+00:00 +---------------------------------------- + +Instruction #25: + Timestep: 24 + Time: 2025-11-03 12:30:00+00:00 + ID: 7cfd98d6-853f-4791-ae13-cbb850392345 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:30:00+00:00 +---------------------------------------- + +Instruction #26: + Timestep: 25 + Time: 2025-11-03 12:35:00+00:00 + ID: fcee59fb-a64a-415e-b6a0-1585d00cdcfc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:35:00+00:00 +---------------------------------------- + +Instruction #27: + Timestep: 26 + Time: 2025-11-03 12:40:00+00:00 + ID: f5e2d55a-cad8-4f95-8b32-9606086dbfb4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:40:00+00:00 +---------------------------------------- + +Instruction #28: + Timestep: 27 + Time: 2025-11-03 12:45:00+00:00 + ID: 1332ec39-5191-44d8-a035-89a89bc98516 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:45:00+00:00 +---------------------------------------- + +Instruction #29: + Timestep: 28 + Time: 2025-11-03 12:50:00+00:00 + ID: 74d40833-83b1-4feb-9562-7f46d6ee1854 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:50:00+00:00 +---------------------------------------- + +Instruction #30: + Timestep: 29 + Time: 2025-11-03 12:55:00+00:00 + ID: fd7e611a-d136-455b-8621-4c63e5334d17 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:55:00+00:00 +---------------------------------------- + +Instruction #31: + Timestep: 30 + Time: 2025-11-03 13:00:00+00:00 + ID: d7f67bc0-c776-450a-a65b-d642cd1ab4ec + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:00:00+00:00 +---------------------------------------- + +Instruction #32: + Timestep: 31 + Time: 2025-11-03 13:05:00+00:00 + ID: eae05c52-4cbe-4d2f-a79a-6885cd311440 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:05:00+00:00 +---------------------------------------- + +Instruction #33: + Timestep: 32 + Time: 2025-11-03 13:10:00+00:00 + ID: 442e99d1-f90c-4113-9332-fd9b2c0b2cbd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:10:00+00:00 +---------------------------------------- + +Instruction #34: + Timestep: 33 + Time: 2025-11-03 13:15:00+00:00 + ID: 0822174c-329d-427a-b412-dc56084f316a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:15:00+00:00 +---------------------------------------- + +Instruction #35: + Timestep: 34 + Time: 2025-11-03 13:20:00+00:00 + ID: 8f30079a-9d23-4ebe-93fa-dec91e10ef92 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:20:00+00:00 +---------------------------------------- + +Instruction #36: + Timestep: 35 + Time: 2025-11-03 13:25:00+00:00 + ID: 1e7d53ff-88a1-4a23-9d30-1baa60daab35 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:25:00+00:00 +---------------------------------------- + +Instruction #37: + Timestep: 36 + Time: 2025-11-03 13:30:00+00:00 + ID: b8b2f438-9b2f-4fd4-b92e-00f246d8cfc6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:30:00+00:00 +---------------------------------------- + +Instruction #38: + Timestep: 37 + Time: 2025-11-03 13:35:00+00:00 + ID: a95e5d7b-7b6b-49ca-950e-9b2778e2cf15 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:35:00+00:00 +---------------------------------------- + +Instruction #39: + Timestep: 38 + Time: 2025-11-03 13:40:00+00:00 + ID: 11f6b222-e637-4b23-a713-9f967ddcb340 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:40:00+00:00 +---------------------------------------- + +Instruction #40: + Timestep: 39 + Time: 2025-11-03 13:45:00+00:00 + ID: 4b8c562e-83cd-42b3-9207-d50dc0f0b1d5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:45:00+00:00 +---------------------------------------- + +Instruction #41: + Timestep: 40 + Time: 2025-11-03 13:50:00+00:00 + ID: 970a0edc-ca34-4249-bdca-85c652dd44bd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:50:00+00:00 +---------------------------------------- + +Instruction #42: + Timestep: 41 + Time: 2025-11-03 13:55:00+00:00 + ID: 9a87dced-fd9b-42d3-84ad-0f35549ae2de + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:55:00+00:00 +---------------------------------------- + +Instruction #43: + Timestep: 42 + Time: 2025-11-03 14:00:00+00:00 + ID: a17b1089-3400-475f-aef3-b34b8dbc0c3d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:00:00+00:00 +---------------------------------------- + +Instruction #44: + Timestep: 43 + Time: 2025-11-03 14:05:00+00:00 + ID: d07fff16-5255-4ae1-afe2-790898ed484e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:05:00+00:00 +---------------------------------------- + +Instruction #45: + Timestep: 44 + Time: 2025-11-03 14:10:00+00:00 + ID: 4dbb7124-6e64-469c-9675-7881af252e2e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:10:00+00:00 +---------------------------------------- + +Instruction #46: + Timestep: 45 + Time: 2025-11-03 14:15:00+00:00 + ID: a983c6d7-fd56-43bc-958d-dd24594d18ec + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:15:00+00:00 +---------------------------------------- + +Instruction #47: + Timestep: 46 + Time: 2025-11-03 14:20:00+00:00 + ID: 474ce289-8d05-495c-baeb-02dafc665fe5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:20:00+00:00 +---------------------------------------- + +Instruction #48: + Timestep: 47 + Time: 2025-11-03 14:25:00+00:00 + ID: cdf451da-e33d-4096-8775-143ce9f2d094 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:25:00+00:00 +---------------------------------------- + +Instruction #49: + Timestep: 48 + Time: 2025-11-03 14:30:00+00:00 + ID: e5c04030-10bf-45dc-a0c3-4432e85838a5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:30:00+00:00 +---------------------------------------- + +Instruction #50: + Timestep: 49 + Time: 2025-11-03 14:35:00+00:00 + ID: 60b65d4f-c258-4551-b76a-fc6958c3fd95 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:35:00+00:00 +---------------------------------------- + +Instruction #51: + Timestep: 50 + Time: 2025-11-03 14:40:00+00:00 + ID: 4e3a04a0-4970-4a8a-9797-2495bfd6a2be + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:40:00+00:00 +---------------------------------------- + +Instruction #52: + Timestep: 51 + Time: 2025-11-03 14:45:00+00:00 + ID: 7fc23408-b358-435d-b9f8-699a0cc35753 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:45:00+00:00 +---------------------------------------- + +Instruction #53: + Timestep: 52 + Time: 2025-11-03 14:50:00+00:00 + ID: 3a16c689-4737-464d-9a00-18d8eb52164a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:50:00+00:00 +---------------------------------------- + +Instruction #54: + Timestep: 53 + Time: 2025-11-03 14:55:00+00:00 + ID: ddadc349-8180-473f-b96a-49a2a7541588 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:55:00+00:00 +---------------------------------------- + +Instruction #55: + Timestep: 54 + Time: 2025-11-03 15:00:00+00:00 + ID: e813ab6d-f0e1-4c1b-90fe-006857acd3bb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:00:00+00:00 +---------------------------------------- + +Instruction #56: + Timestep: 55 + Time: 2025-11-03 15:05:00+00:00 + ID: add4e16b-869a-40e1-ad6b-4ba21a683753 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:05:00+00:00 +---------------------------------------- + +Instruction #57: + Timestep: 56 + Time: 2025-11-03 15:10:00+00:00 + ID: a1fc6722-afed-4894-9dda-15f45a724a16 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:10:00+00:00 +---------------------------------------- + +Instruction #58: + Timestep: 57 + Time: 2025-11-03 15:15:00+00:00 + ID: 6ce9dba6-e9f6-4b02-b6e7-81f8261ad751 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:15:00+00:00 +---------------------------------------- + +Instruction #59: + Timestep: 58 + Time: 2025-11-03 15:20:00+00:00 + ID: c8c68d5c-4699-4573-99c9-4a45f3af424d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:20:00+00:00 +---------------------------------------- + +Instruction #60: + Timestep: 59 + Time: 2025-11-03 15:25:00+00:00 + ID: ab1e2a90-c26b-4fd6-bc66-d50ca954a24c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:25:00+00:00 +---------------------------------------- + +Instruction #61: + Timestep: 60 + Time: 2025-11-03 15:30:00+00:00 + ID: 0c53fc4c-449e-4262-bd79-82bb5c1c030c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:30:00+00:00 +---------------------------------------- + +Instruction #62: + Timestep: 61 + Time: 2025-11-03 15:35:00+00:00 + ID: abe1f899-f6e7-4f15-88ad-65bd79cca7a3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:35:00+00:00 +---------------------------------------- + +Instruction #63: + Timestep: 62 + Time: 2025-11-03 15:40:00+00:00 + ID: bd166c11-0fa6-4927-b40c-f6931d03761f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:40:00+00:00 +---------------------------------------- + +Instruction #64: + Timestep: 63 + Time: 2025-11-03 15:45:00+00:00 + ID: a0a885b6-e8fa-4880-b289-e13ac8d4889c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:45:00+00:00 +---------------------------------------- + +Instruction #65: + Timestep: 64 + Time: 2025-11-03 15:50:00+00:00 + ID: ebf4f2b6-6373-4e43-ae12-c9f27aca4249 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:50:00+00:00 +---------------------------------------- + +Instruction #66: + Timestep: 65 + Time: 2025-11-03 15:55:00+00:00 + ID: 2169d220-1202-4401-b39e-405b2514ad48 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:55:00+00:00 +---------------------------------------- + +Instruction #67: + Timestep: 66 + Time: 2025-11-03 16:00:00+00:00 + ID: 7f6ec097-050a-4214-9b8d-a91aabbc8ba7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:00:00+00:00 +---------------------------------------- + +Instruction #68: + Timestep: 67 + Time: 2025-11-03 16:05:00+00:00 + ID: e3b54f38-34b7-479a-a74b-8ac79c1a5479 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:05:00+00:00 +---------------------------------------- + +Instruction #69: + Timestep: 68 + Time: 2025-11-03 16:10:00+00:00 + ID: 9b4dcb89-5549-4770-889e-fe6c06f659d9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:10:00+00:00 +---------------------------------------- + +Instruction #70: + Timestep: 69 + Time: 2025-11-03 16:15:00+00:00 + ID: e07ceae7-d7d8-4bec-b04a-2f9ac879eace + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:15:00+00:00 +---------------------------------------- + +Instruction #71: + Timestep: 70 + Time: 2025-11-03 16:20:00+00:00 + ID: 540477f4-bcd1-4810-baa3-7129af7873a0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:20:00+00:00 +---------------------------------------- + +Instruction #72: + Timestep: 71 + Time: 2025-11-03 16:25:00+00:00 + ID: 189cab4d-66dc-4c3e-a966-b2981d524df6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:25:00+00:00 +---------------------------------------- + +Instruction #73: + Timestep: 72 + Time: 2025-11-03 16:30:00+00:00 + ID: 386b81fb-7158-496c-b4c0-e47f2658eb61 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:30:00+00:00 +---------------------------------------- + +Instruction #74: + Timestep: 73 + Time: 2025-11-03 16:35:00+00:00 + ID: 613fa089-9130-433e-9ccc-d3d7f6de36b4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:35:00+00:00 +---------------------------------------- + +Instruction #75: + Timestep: 74 + Time: 2025-11-03 16:40:00+00:00 + ID: 26ef0fbf-6115-4988-9905-7e1fefbc12f0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:40:00+00:00 +---------------------------------------- + +Instruction #76: + Timestep: 75 + Time: 2025-11-03 16:45:00+00:00 + ID: e337fcb0-8396-4591-a78a-e6241bafeb94 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:45:00+00:00 +---------------------------------------- + +Instruction #77: + Timestep: 76 + Time: 2025-11-03 16:50:00+00:00 + ID: 45813c8c-8f5a-4392-8cb0-f81c1f3021ef + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:50:00+00:00 +---------------------------------------- + +Instruction #78: + Timestep: 77 + Time: 2025-11-03 16:55:00+00:00 + ID: 4feb4a15-1bab-4733-bfb9-00283bc82f05 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:55:00+00:00 +---------------------------------------- + +Instruction #79: + Timestep: 78 + Time: 2025-11-03 17:00:00+00:00 + ID: 9dffc33e-3657-44db-a207-6206de2f2bd2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:00:00+00:00 +---------------------------------------- + +Instruction #80: + Timestep: 79 + Time: 2025-11-03 17:05:00+00:00 + ID: e7ecfe61-2db3-43b5-8129-232d17fa3db6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:05:00+00:00 +---------------------------------------- + +Instruction #81: + Timestep: 80 + Time: 2025-11-03 17:10:00+00:00 + ID: fd4798db-d529-4807-b91b-b8661d3d19d8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:10:00+00:00 +---------------------------------------- + +Instruction #82: + Timestep: 81 + Time: 2025-11-03 17:15:00+00:00 + ID: d8736cfe-ac5f-4fa2-a9fc-1b3b1afbcb20 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:15:00+00:00 +---------------------------------------- + +Instruction #83: + Timestep: 82 + Time: 2025-11-03 17:20:00+00:00 + ID: 9950db1b-6606-48e9-a50f-bcd53e44aae7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:20:00+00:00 +---------------------------------------- + +Instruction #84: + Timestep: 83 + Time: 2025-11-03 17:25:00+00:00 + ID: 6e89d142-9bad-4757-bb19-a0de195a7613 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:25:00+00:00 +---------------------------------------- + +Instruction #85: + Timestep: 84 + Time: 2025-11-03 17:30:00+00:00 + ID: cd88ea58-f189-46ba-98f6-1a39e1cbb857 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:30:00+00:00 +---------------------------------------- + +Instruction #86: + Timestep: 85 + Time: 2025-11-03 17:35:00+00:00 + ID: 7391d156-4de9-417f-904d-30cdb549a6e7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:35:00+00:00 +---------------------------------------- + +Instruction #87: + Timestep: 86 + Time: 2025-11-03 17:40:00+00:00 + ID: c7e1ce27-63d3-4c4d-b2fb-a56a904c1ca2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:40:00+00:00 +---------------------------------------- + +Instruction #88: + Timestep: 87 + Time: 2025-11-03 17:45:00+00:00 + ID: 317c2336-c10a-48dc-8a37-af91641cf73a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:45:00+00:00 +---------------------------------------- + +Instruction #89: + Timestep: 88 + Time: 2025-11-03 17:50:00+00:00 + ID: 8d521331-c83c-444d-af40-16d0266d13e3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:50:00+00:00 +---------------------------------------- + +Instruction #90: + Timestep: 89 + Time: 2025-11-03 17:55:00+00:00 + ID: 5a798515-c141-4275-88e2-90bc05f78628 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:55:00+00:00 +---------------------------------------- + +Instruction #91: + Timestep: 90 + Time: 2025-11-03 18:00:00+00:00 + ID: b2050394-22d9-442e-bbe6-e804d7922fe1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:00:00+00:00 +---------------------------------------- + +Instruction #92: + Timestep: 91 + Time: 2025-11-03 18:05:00+00:00 + ID: 7aaa12e9-b4c2-4f5e-a7b6-926dd960d343 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:05:00+00:00 +---------------------------------------- + +Instruction #93: + Timestep: 92 + Time: 2025-11-03 18:10:00+00:00 + ID: 525a69e6-d3bd-465a-8431-0f733e7f6358 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:10:00+00:00 +---------------------------------------- + +Instruction #94: + Timestep: 93 + Time: 2025-11-03 18:15:00+00:00 + ID: 9f54ef57-26dc-4cce-9255-7e9264cf7ab0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:15:00+00:00 +---------------------------------------- + +Instruction #95: + Timestep: 94 + Time: 2025-11-03 18:20:00+00:00 + ID: 5bc2a76b-145c-4ce7-bf0e-e87cfdfddf9d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:20:00+00:00 +---------------------------------------- + +Instruction #96: + Timestep: 95 + Time: 2025-11-03 18:25:00+00:00 + ID: d1089c9d-f1bd-489d-a2c0-87ea26b9c718 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:25:00+00:00 +---------------------------------------- + +Instruction #97: + Timestep: 96 + Time: 2025-11-03 18:30:00+00:00 + ID: c6a82451-7f0b-49dd-8437-d0f2dc998ba1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:30:00+00:00 +---------------------------------------- + +Instruction #98: + Timestep: 97 + Time: 2025-11-03 18:35:00+00:00 + ID: 5cc09405-1c93-4d9e-a3f3-7491ae737907 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:35:00+00:00 +---------------------------------------- + +Instruction #99: + Timestep: 98 + Time: 2025-11-03 18:40:00+00:00 + ID: bf1e77c6-e766-4db0-bd92-fab00a9d2446 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:40:00+00:00 +---------------------------------------- + +Instruction #100: + Timestep: 99 + Time: 2025-11-03 18:45:00+00:00 + ID: 212f5bd4-d9eb-4753-b6ca-544942ea7d15 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:45:00+00:00 +---------------------------------------- + +Instruction #101: + Timestep: 100 + Time: 2025-11-03 18:50:00+00:00 + ID: a0259ce6-3721-4c18-89a6-4a56e2111a09 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:50:00+00:00 +---------------------------------------- + +Instruction #102: + Timestep: 101 + Time: 2025-11-03 18:55:00+00:00 + ID: 9e7bcacb-3cae-4939-86fa-34ff677d2acc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:55:00+00:00 +---------------------------------------- + +Instruction #103: + Timestep: 102 + Time: 2025-11-03 19:00:00+00:00 + ID: bc561828-249a-4b8d-8a90-e6ecfcb37f15 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:00:00+00:00 +---------------------------------------- + +Instruction #104: + Timestep: 103 + Time: 2025-11-03 19:05:00+00:00 + ID: 353b4419-9a94-404e-854e-87fecfc36792 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:05:00+00:00 +---------------------------------------- + +Instruction #105: + Timestep: 104 + Time: 2025-11-03 19:10:00+00:00 + ID: 5a22cd01-d115-48d6-b04a-11925c86efd0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:10:00+00:00 +---------------------------------------- + +Instruction #106: + Timestep: 105 + Time: 2025-11-03 19:15:00+00:00 + ID: 3eaed500-60ac-476a-bc52-71ba1e8373e5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:15:00+00:00 +---------------------------------------- + +Instruction #107: + Timestep: 106 + Time: 2025-11-03 19:20:00+00:00 + ID: 30ad03f0-d9cb-46bc-be03-f9f8b7283fe0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:20:00+00:00 +---------------------------------------- + +Instruction #108: + Timestep: 107 + Time: 2025-11-03 19:25:00+00:00 + ID: a35bd162-8519-4272-9f33-9969c81434c4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:25:00+00:00 +---------------------------------------- + +Instruction #109: + Timestep: 108 + Time: 2025-11-03 19:30:00+00:00 + ID: e4488d8c-5fc4-409e-918a-e482aac9da55 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:30:00+00:00 +---------------------------------------- + +Instruction #110: + Timestep: 109 + Time: 2025-11-03 19:35:00+00:00 + ID: 576d658d-7312-46d5-bdc0-98cf2f639d63 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:35:00+00:00 +---------------------------------------- + +Instruction #111: + Timestep: 110 + Time: 2025-11-03 19:40:00+00:00 + ID: 790f4410-6360-4abd-b42c-918f985d11ae + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:40:00+00:00 +---------------------------------------- + +Instruction #112: + Timestep: 111 + Time: 2025-11-03 19:45:00+00:00 + ID: b6cecd12-30c1-43f0-81ad-2a6d57b63d1c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:45:00+00:00 +---------------------------------------- + +Instruction #113: + Timestep: 112 + Time: 2025-11-03 19:50:00+00:00 + ID: 97da666e-1696-4e1c-855a-a36ec69bc2e9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:50:00+00:00 +---------------------------------------- + +Instruction #114: + Timestep: 113 + Time: 2025-11-03 19:55:00+00:00 + ID: fc49dfd8-59a0-4444-8620-c0ab93a60d5c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:55:00+00:00 +---------------------------------------- + +Instruction #115: + Timestep: 114 + Time: 2025-11-03 20:00:00+00:00 + ID: 8b744c8c-2d94-4c8e-ae26-aba4bbeb71e3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:00:00+00:00 +---------------------------------------- + +Instruction #116: + Timestep: 115 + Time: 2025-11-03 20:05:00+00:00 + ID: cc208e13-d557-451a-a926-1bd73456b693 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:05:00+00:00 +---------------------------------------- + +Instruction #117: + Timestep: 116 + Time: 2025-11-03 20:10:00+00:00 + ID: f46633b2-9f8d-43a5-85a1-f5e09f39a924 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:10:00+00:00 +---------------------------------------- + +Instruction #118: + Timestep: 117 + Time: 2025-11-03 20:15:00+00:00 + ID: 4d6abbd0-205f-4427-bf69-42942752575c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:15:00+00:00 +---------------------------------------- + +Instruction #119: + Timestep: 118 + Time: 2025-11-03 20:20:00+00:00 + ID: 842f6ed7-3bc3-46ed-afcc-9b6d7e6d0236 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:20:00+00:00 +---------------------------------------- + +Instruction #120: + Timestep: 119 + Time: 2025-11-03 20:25:00+00:00 + ID: e6ad36a7-292a-4a5a-adda-45ca072e7996 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:25:00+00:00 +---------------------------------------- + +Instruction #121: + Timestep: 120 + Time: 2025-11-03 20:30:00+00:00 + ID: cbe9e800-862d-432e-8ed7-f275426b3233 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:30:00+00:00 +---------------------------------------- + +Instruction #122: + Timestep: 121 + Time: 2025-11-03 20:35:00+00:00 + ID: 96aab91d-2300-4ad3-b1ea-e7c312015ca7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:35:00+00:00 +---------------------------------------- + +Instruction #123: + Timestep: 122 + Time: 2025-11-03 20:40:00+00:00 + ID: c95bb76f-c2ca-4f70-88b8-a29170f7fbb6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:40:00+00:00 +---------------------------------------- + +Instruction #124: + Timestep: 123 + Time: 2025-11-03 20:45:00+00:00 + ID: 47a66504-c08e-4d2b-9a43-8f5eceeea4bc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:45:00+00:00 +---------------------------------------- + +Instruction #125: + Timestep: 124 + Time: 2025-11-03 20:50:00+00:00 + ID: cccbf585-47e3-4559-9e96-bf192eb1479f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:50:00+00:00 +---------------------------------------- + +Instruction #126: + Timestep: 125 + Time: 2025-11-03 20:55:00+00:00 + ID: 4b15c41a-088c-440a-bdf6-d088e0f0eb54 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:55:00+00:00 +---------------------------------------- + +Instruction #127: + Timestep: 126 + Time: 2025-11-03 21:00:00+00:00 + ID: 95c148cf-ab46-4589-a196-60f64f54c0b1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:00:00+00:00 +---------------------------------------- + +Instruction #128: + Timestep: 127 + Time: 2025-11-03 21:05:00+00:00 + ID: c32f5101-0e46-4e3b-bb0d-818d07ce6e1b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:05:00+00:00 +---------------------------------------- + +Instruction #129: + Timestep: 128 + Time: 2025-11-03 21:10:00+00:00 + ID: ea2c3149-5a60-4a30-b07a-161f0aceaf45 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:10:00+00:00 +---------------------------------------- + +Instruction #130: + Timestep: 129 + Time: 2025-11-03 21:15:00+00:00 + ID: 95785c76-c8fe-4a57-bb1d-7427a02a056f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:15:00+00:00 +---------------------------------------- + +Instruction #131: + Timestep: 130 + Time: 2025-11-03 21:20:00+00:00 + ID: 43157851-da51-4c01-9e85-61223aae14c1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:20:00+00:00 +---------------------------------------- + +Instruction #132: + Timestep: 131 + Time: 2025-11-03 21:25:00+00:00 + ID: 137a7ac5-e9c8-4e33-a761-2a3a82804348 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:25:00+00:00 +---------------------------------------- + +Instruction #133: + Timestep: 132 + Time: 2025-11-03 21:30:00+00:00 + ID: 59b9a783-4a16-4324-b077-bf9a5cecb5a1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:30:00+00:00 +---------------------------------------- + +Instruction #134: + Timestep: 133 + Time: 2025-11-03 21:35:00+00:00 + ID: 25aed623-4e39-4118-b7a4-751a60966992 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:35:00+00:00 +---------------------------------------- + +Instruction #135: + Timestep: 134 + Time: 2025-11-03 21:40:00+00:00 + ID: e00adfe8-52d5-48ce-9a4f-f8f944f4d322 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:40:00+00:00 +---------------------------------------- + +Instruction #136: + Timestep: 135 + Time: 2025-11-03 21:45:00+00:00 + ID: e1e030f2-7734-4aa8-b4af-135926048031 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:45:00+00:00 +---------------------------------------- + +Instruction #137: + Timestep: 136 + Time: 2025-11-03 21:50:00+00:00 + ID: a7fd38f3-1c44-47ab-adba-a2b2cee2e9b9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:50:00+00:00 +---------------------------------------- + +Instruction #138: + Timestep: 137 + Time: 2025-11-03 21:55:00+00:00 + ID: 1cd985a3-3621-409e-8134-8c5ea5204920 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:55:00+00:00 +---------------------------------------- + +Instruction #139: + Timestep: 138 + Time: 2025-11-03 22:00:00+00:00 + ID: e2f86b59-953f-4cde-98c8-913ef963d654 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:00:00+00:00 +---------------------------------------- + +Instruction #140: + Timestep: 139 + Time: 2025-11-03 22:05:00+00:00 + ID: f4cd9864-3b6a-4380-95db-a7f90162a117 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:05:00+00:00 +---------------------------------------- + +Instruction #141: + Timestep: 140 + Time: 2025-11-03 22:10:00+00:00 + ID: c0ab79ff-7420-4244-879d-d3167bf9b093 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:10:00+00:00 +---------------------------------------- + +Instruction #142: + Timestep: 141 + Time: 2025-11-03 22:15:00+00:00 + ID: cd22ea01-4d31-4f22-b451-01afc28305cc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:15:00+00:00 +---------------------------------------- + +Instruction #143: + Timestep: 142 + Time: 2025-11-03 22:20:00+00:00 + ID: 15374a18-11df-484a-b048-09bf148ebe68 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:20:00+00:00 +---------------------------------------- + +Instruction #144: + Timestep: 143 + Time: 2025-11-03 22:25:00+00:00 + ID: 1bb9f63f-0612-48cc-9a52-b82911a2caa5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:25:00+00:00 +---------------------------------------- + +Instruction #145: + Timestep: 144 + Time: 2025-11-03 22:30:00+00:00 + ID: e43b4c2b-70f6-45e5-8c7e-8ceb92a4d980 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:30:00+00:00 +---------------------------------------- + +Instruction #146: + Timestep: 145 + Time: 2025-11-03 22:35:00+00:00 + ID: 208fc523-3792-4ef3-88b5-8f8d4fdc84b2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:35:00+00:00 +---------------------------------------- + +Instruction #147: + Timestep: 146 + Time: 2025-11-03 22:40:00+00:00 + ID: f4cc05e7-00ee-436c-aa3f-026f7de08c5e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:40:00+00:00 +---------------------------------------- + +Instruction #148: + Timestep: 147 + Time: 2025-11-03 22:45:00+00:00 + ID: ec341e07-190c-4bf8-9025-0d452e0199f5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:45:00+00:00 +---------------------------------------- + +Instruction #149: + Timestep: 148 + Time: 2025-11-03 22:50:00+00:00 + ID: 3a43c9f7-17f3-4eeb-adbe-5b0baf314e22 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:50:00+00:00 +---------------------------------------- + +Instruction #150: + Timestep: 149 + Time: 2025-11-03 22:55:00+00:00 + ID: d92bcbd6-c5df-42c6-82c3-5177ae94c09f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:55:00+00:00 +---------------------------------------- + +Instruction #151: + Timestep: 150 + Time: 2025-11-03 23:00:00+00:00 + ID: 377af6f9-8e71-4bb6-8a87-9d227210eef2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:00:00+00:00 +---------------------------------------- + +Instruction #152: + Timestep: 151 + Time: 2025-11-03 23:05:00+00:00 + ID: 39d9ba66-2333-442a-bc24-1a06c409333c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:05:00+00:00 +---------------------------------------- + +Instruction #153: + Timestep: 152 + Time: 2025-11-03 23:10:00+00:00 + ID: cb265400-5a21-4a3c-8d1e-e4eab195e50f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:10:00+00:00 +---------------------------------------- + +Instruction #154: + Timestep: 153 + Time: 2025-11-03 23:15:00+00:00 + ID: 250b1a4b-800f-46f5-850c-24f8667ad447 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:15:00+00:00 +---------------------------------------- + +Instruction #155: + Timestep: 154 + Time: 2025-11-03 23:20:00+00:00 + ID: 2f7f98e2-e8cc-43a4-b54b-c256ed1d42b7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:20:00+00:00 +---------------------------------------- + +Instruction #156: + Timestep: 155 + Time: 2025-11-03 23:25:00+00:00 + ID: 564f4a10-a8ae-4f24-985c-326abae623f8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:25:00+00:00 +---------------------------------------- + +Instruction #157: + Timestep: 156 + Time: 2025-11-03 23:30:00+00:00 + ID: 9705fa5a-f987-42a2-b77b-97aa84610e87 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:30:00+00:00 +---------------------------------------- + +Instruction #158: + Timestep: 157 + Time: 2025-11-03 23:35:00+00:00 + ID: 6aa496b5-8583-4e71-b7a2-2732de17de6a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:35:00+00:00 +---------------------------------------- + +Instruction #159: + Timestep: 158 + Time: 2025-11-03 23:40:00+00:00 + ID: 8d0d2440-c6bc-4fdf-82ff-97e7186d9387 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:40:00+00:00 +---------------------------------------- + +Instruction #160: + Timestep: 159 + Time: 2025-11-03 23:45:00+00:00 + ID: 1683cbe6-babb-4a24-9b3e-67c96960295d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:45:00+00:00 +---------------------------------------- + +Instruction #161: + Timestep: 160 + Time: 2025-11-03 23:50:00+00:00 + ID: 79a330f9-ca78-4770-b966-55b74c498763 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:50:00+00:00 +---------------------------------------- + +Instruction #162: + Timestep: 161 + Time: 2025-11-03 23:55:00+00:00 + ID: a3ad8ea0-e244-4343-a01d-3b9ffd9b8e32 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:55:00+00:00 +---------------------------------------- + +Instruction #163: + Timestep: 162 + Time: 2025-11-04 00:00:00+00:00 + ID: c3cf4d5d-cd89-4346-afb5-a5f8586c9a54 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:00:00+00:00 +---------------------------------------- + +Instruction #164: + Timestep: 163 + Time: 2025-11-04 00:05:00+00:00 + ID: 53cdf3f7-3ea4-4865-92a7-cb8f601ab308 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:05:00+00:00 +---------------------------------------- + +Instruction #165: + Timestep: 164 + Time: 2025-11-04 00:10:00+00:00 + ID: c6177f25-23f5-4ae7-b5b8-bb3079984a54 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:10:00+00:00 +---------------------------------------- + +Instruction #166: + Timestep: 165 + Time: 2025-11-04 00:15:00+00:00 + ID: fd60dd3d-fc63-41b4-a63f-2d20f4268716 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:15:00+00:00 +---------------------------------------- + +Instruction #167: + Timestep: 166 + Time: 2025-11-04 00:20:00+00:00 + ID: d5fcc44d-07e8-4b70-9603-8965ea111a9c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:20:00+00:00 +---------------------------------------- + +Instruction #168: + Timestep: 167 + Time: 2025-11-04 00:25:00+00:00 + ID: d87b3b05-1b78-40ee-9f75-1f3e26a76817 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:25:00+00:00 +---------------------------------------- + +Instruction #169: + Timestep: 168 + Time: 2025-11-04 00:30:00+00:00 + ID: c51d9d83-d8de-4b4c-8801-391dd4003d22 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:30:00+00:00 +---------------------------------------- + +Instruction #170: + Timestep: 169 + Time: 2025-11-04 00:35:00+00:00 + ID: 2b7a41e5-ca34-4af7-afd9-315292c5094d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:35:00+00:00 +---------------------------------------- + +Instruction #171: + Timestep: 170 + Time: 2025-11-04 00:40:00+00:00 + ID: dedf9772-3570-468f-ae29-2fdcb8f35c37 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:40:00+00:00 +---------------------------------------- + +Instruction #172: + Timestep: 171 + Time: 2025-11-04 00:45:00+00:00 + ID: 0a06a09a-19d5-445a-8e9f-36c620478891 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:45:00+00:00 +---------------------------------------- + +Instruction #173: + Timestep: 172 + Time: 2025-11-04 00:50:00+00:00 + ID: d1915a49-0332-4650-9fbd-e22051882cad + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:50:00+00:00 +---------------------------------------- + +Instruction #174: + Timestep: 173 + Time: 2025-11-04 00:55:00+00:00 + ID: 6261425e-597d-417e-97f7-66517ea23ae9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:55:00+00:00 +---------------------------------------- + +Instruction #175: + Timestep: 174 + Time: 2025-11-04 01:00:00+00:00 + ID: 44fc8270-1654-4d9f-863c-cb4a10a59a75 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:00:00+00:00 +---------------------------------------- + +Instruction #176: + Timestep: 175 + Time: 2025-11-04 01:05:00+00:00 + ID: d9184538-df54-4157-bbf3-5e97adb3d2cf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:05:00+00:00 +---------------------------------------- + +Instruction #177: + Timestep: 176 + Time: 2025-11-04 01:10:00+00:00 + ID: e793e154-1103-4f92-a5e6-688ce22ab5fe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:10:00+00:00 +---------------------------------------- + +Instruction #178: + Timestep: 177 + Time: 2025-11-04 01:15:00+00:00 + ID: bb728ace-6194-4399-b4d7-8f1cbec7b2be + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:15:00+00:00 +---------------------------------------- + +Instruction #179: + Timestep: 178 + Time: 2025-11-04 01:20:00+00:00 + ID: 6fc04066-cccf-488b-bdae-e38f39d13a70 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:20:00+00:00 +---------------------------------------- + +Instruction #180: + Timestep: 179 + Time: 2025-11-04 01:25:00+00:00 + ID: 456af611-d69e-4af5-a125-e839ec203274 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:25:00+00:00 +---------------------------------------- + +Instruction #181: + Timestep: 180 + Time: 2025-11-04 01:30:00+00:00 + ID: 142beb9f-0a19-472a-aad9-02e39c656bba + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:30:00+00:00 +---------------------------------------- + +Instruction #182: + Timestep: 181 + Time: 2025-11-04 01:35:00+00:00 + ID: 61411de8-084d-4e8d-9f4e-1f8c49623d2d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:35:00+00:00 +---------------------------------------- + +Instruction #183: + Timestep: 182 + Time: 2025-11-04 01:40:00+00:00 + ID: 4c7ff65f-6d5d-4d8e-95dd-e18696d142a1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:40:00+00:00 +---------------------------------------- + +Instruction #184: + Timestep: 183 + Time: 2025-11-04 01:45:00+00:00 + ID: 91d7d4dd-1e04-4e27-b0a3-4c9f130d4c35 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:45:00+00:00 +---------------------------------------- + +Instruction #185: + Timestep: 184 + Time: 2025-11-04 01:50:00+00:00 + ID: 3968c6bf-d5e9-47a8-9d8c-2a618942c8e5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:50:00+00:00 +---------------------------------------- + +Instruction #186: + Timestep: 185 + Time: 2025-11-04 01:55:00+00:00 + ID: c34b837c-7bd4-4859-a7c1-083952a36b1e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:55:00+00:00 +---------------------------------------- + +Instruction #187: + Timestep: 186 + Time: 2025-11-04 02:00:00+00:00 + ID: f779a9a8-45ae-4e04-baa9-51d3a385995a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:00:00+00:00 +---------------------------------------- + +Instruction #188: + Timestep: 187 + Time: 2025-11-04 02:05:00+00:00 + ID: d0297b34-047a-47f6-8382-339e717e94b2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:05:00+00:00 +---------------------------------------- + +Instruction #189: + Timestep: 188 + Time: 2025-11-04 02:10:00+00:00 + ID: d55f7750-6113-44ec-9a0f-08bad7e0510b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:10:00+00:00 +---------------------------------------- + +Instruction #190: + Timestep: 189 + Time: 2025-11-04 02:15:00+00:00 + ID: d32425cc-2319-41e1-9996-1e7af9e100b0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:15:00+00:00 +---------------------------------------- + +Instruction #191: + Timestep: 190 + Time: 2025-11-04 02:20:00+00:00 + ID: f6f8e538-123b-4e05-a68c-5e8bf605205a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:20:00+00:00 +---------------------------------------- + +Instruction #192: + Timestep: 191 + Time: 2025-11-04 02:25:00+00:00 + ID: 6d44f4e2-b471-4920-805d-d964b804137a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:25:00+00:00 +---------------------------------------- + +Instruction #193: + Timestep: 192 + Time: 2025-11-04 02:30:00+00:00 + ID: 7e5fb3e9-e9cf-464e-b3af-951228a55234 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:30:00+00:00 +---------------------------------------- + +Instruction #194: + Timestep: 193 + Time: 2025-11-04 02:35:00+00:00 + ID: f720f57f-b2bb-49c0-920a-4d60247c2598 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:35:00+00:00 +---------------------------------------- + +Instruction #195: + Timestep: 194 + Time: 2025-11-04 02:40:00+00:00 + ID: 769410ff-e1f7-4336-8c27-50d5deb036f7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:40:00+00:00 +---------------------------------------- + +Instruction #196: + Timestep: 195 + Time: 2025-11-04 02:45:00+00:00 + ID: 68e5462e-49fe-415a-a56b-5511519d4922 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:45:00+00:00 +---------------------------------------- + +Instruction #197: + Timestep: 196 + Time: 2025-11-04 02:50:00+00:00 + ID: a17d0e70-52a7-4a1a-96e1-de40d4882028 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:50:00+00:00 +---------------------------------------- + +Instruction #198: + Timestep: 197 + Time: 2025-11-04 02:55:00+00:00 + ID: 1af448fa-36da-4986-b0a9-8bcbca2072c0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:55:00+00:00 +---------------------------------------- + +Instruction #199: + Timestep: 198 + Time: 2025-11-04 03:00:00+00:00 + ID: 6ea92b62-4031-4ede-9659-ece46ce1b773 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:00:00+00:00 +---------------------------------------- + +Instruction #200: + Timestep: 199 + Time: 2025-11-04 03:05:00+00:00 + ID: ca5fded9-5781-46c9-884f-c9638e4a1b74 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:05:00+00:00 +---------------------------------------- + +Instruction #201: + Timestep: 200 + Time: 2025-11-04 03:10:00+00:00 + ID: fd32c708-8a57-46db-8fc8-53197be2d66f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:10:00+00:00 +---------------------------------------- + +Instruction #202: + Timestep: 201 + Time: 2025-11-04 03:15:00+00:00 + ID: 31f5d943-4128-40dc-87ea-3df1aba84b02 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:15:00+00:00 +---------------------------------------- + +Instruction #203: + Timestep: 202 + Time: 2025-11-04 03:20:00+00:00 + ID: d2c4f0e4-2941-425a-a2aa-2b28c49ae013 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:20:00+00:00 +---------------------------------------- + +Instruction #204: + Timestep: 203 + Time: 2025-11-04 03:25:00+00:00 + ID: 0a23e8cc-1ffb-4fc8-a79c-d68689ccebba + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:25:00+00:00 +---------------------------------------- + +Instruction #205: + Timestep: 204 + Time: 2025-11-04 03:30:00+00:00 + ID: 5e260393-7568-494a-8d88-156abcf7441a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:30:00+00:00 +---------------------------------------- + +Instruction #206: + Timestep: 205 + Time: 2025-11-04 03:35:00+00:00 + ID: ed6616d8-8692-48bc-9fcc-55fab9821642 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:35:00+00:00 +---------------------------------------- + +Instruction #207: + Timestep: 206 + Time: 2025-11-04 03:40:00+00:00 + ID: 0208578e-75b4-4b53-8406-a7da717c62f0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:40:00+00:00 +---------------------------------------- + +Instruction #208: + Timestep: 207 + Time: 2025-11-04 03:45:00+00:00 + ID: 09d68eb0-3a5a-4df0-863b-a7ae6bc19cc7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:45:00+00:00 +---------------------------------------- + +Instruction #209: + Timestep: 208 + Time: 2025-11-04 03:50:00+00:00 + ID: 3897f5a8-01e1-4c39-828e-6e82c0df8124 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:50:00+00:00 +---------------------------------------- + +Instruction #210: + Timestep: 209 + Time: 2025-11-04 03:55:00+00:00 + ID: 842609b3-29de-4553-82a3-170eb563b736 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:55:00+00:00 +---------------------------------------- + +Instruction #211: + Timestep: 210 + Time: 2025-11-04 04:00:00+00:00 + ID: 83150631-b0c4-4b86-9b6f-60d1307600fa + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:00:00+00:00 +---------------------------------------- + +Instruction #212: + Timestep: 211 + Time: 2025-11-04 04:05:00+00:00 + ID: 3fb5bcb1-7f76-414e-99d4-1e5a98a9c30c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:05:00+00:00 +---------------------------------------- + +Instruction #213: + Timestep: 212 + Time: 2025-11-04 04:10:00+00:00 + ID: cc8aee00-c992-4e36-9477-02e3c6b77055 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:10:00+00:00 +---------------------------------------- + +Instruction #214: + Timestep: 213 + Time: 2025-11-04 04:15:00+00:00 + ID: beda227b-207a-4e24-95b3-968d68c5ad51 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:15:00+00:00 +---------------------------------------- + +Instruction #215: + Timestep: 214 + Time: 2025-11-04 04:20:00+00:00 + ID: 3f830f7b-e187-4481-af3d-4f64d026a0c9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:20:00+00:00 +---------------------------------------- + +Instruction #216: + Timestep: 215 + Time: 2025-11-04 04:25:00+00:00 + ID: 46df39e1-df12-437c-9fe5-546f3b638622 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:25:00+00:00 +---------------------------------------- + +Instruction #217: + Timestep: 216 + Time: 2025-11-04 04:30:00+00:00 + ID: 6e803b87-b7ca-4bc1-b81c-860d545a0585 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:30:00+00:00 +---------------------------------------- + +Instruction #218: + Timestep: 217 + Time: 2025-11-04 04:35:00+00:00 + ID: 442cfef0-e871-4946-8ad8-9866a15f12a5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:35:00+00:00 +---------------------------------------- + +Instruction #219: + Timestep: 218 + Time: 2025-11-04 04:40:00+00:00 + ID: 4f409b27-0636-4644-939a-6bd1b9be433c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:40:00+00:00 +---------------------------------------- + +Instruction #220: + Timestep: 219 + Time: 2025-11-04 04:45:00+00:00 + ID: 5ec7a5f4-46e8-405b-abd8-b37fb90fa48a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:45:00+00:00 +---------------------------------------- + +Instruction #221: + Timestep: 220 + Time: 2025-11-04 04:50:00+00:00 + ID: 0a06ddf9-9c02-4756-9d60-63ddd41a7301 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:50:00+00:00 +---------------------------------------- + +Instruction #222: + Timestep: 221 + Time: 2025-11-04 04:55:00+00:00 + ID: e2cdb543-020c-428b-9919-0f976108f012 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:55:00+00:00 +---------------------------------------- + +Instruction #223: + Timestep: 222 + Time: 2025-11-04 05:00:00+00:00 + ID: a824603b-a5ed-486a-8ca5-671b97bb0f63 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:00:00+00:00 +---------------------------------------- + +Instruction #224: + Timestep: 223 + Time: 2025-11-04 05:05:00+00:00 + ID: ee57d585-0c8d-459a-b613-15914720e51b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:05:00+00:00 +---------------------------------------- + +Instruction #225: + Timestep: 224 + Time: 2025-11-04 05:10:00+00:00 + ID: 80654488-5783-467e-8e8a-da34e5707ff9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:10:00+00:00 +---------------------------------------- + +Instruction #226: + Timestep: 225 + Time: 2025-11-04 05:15:00+00:00 + ID: b955e2f3-fc0d-4195-b634-b95b9ea595dc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:15:00+00:00 +---------------------------------------- + +Instruction #227: + Timestep: 226 + Time: 2025-11-04 05:20:00+00:00 + ID: 965c1ed1-bea0-42e9-96c1-2dc7baf0ec81 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:20:00+00:00 +---------------------------------------- + +Instruction #228: + Timestep: 227 + Time: 2025-11-04 05:25:00+00:00 + ID: 5e97c253-0144-44f4-a773-45fa90bb9771 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:25:00+00:00 +---------------------------------------- + +Instruction #229: + Timestep: 228 + Time: 2025-11-04 05:30:00+00:00 + ID: 4949890c-5404-473c-a081-f3de4462dcb1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:30:00+00:00 +---------------------------------------- + +Instruction #230: + Timestep: 229 + Time: 2025-11-04 05:35:00+00:00 + ID: 0ee3579c-eb33-48ef-a4cd-565f6510cc8e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:35:00+00:00 +---------------------------------------- + +Instruction #231: + Timestep: 230 + Time: 2025-11-04 05:40:00+00:00 + ID: 3e6bfb86-b5dc-49e6-8605-14fc994266fd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:40:00+00:00 +---------------------------------------- + +Instruction #232: + Timestep: 231 + Time: 2025-11-04 05:45:00+00:00 + ID: 2e858eb3-c863-4a7a-b785-657436d62c85 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:45:00+00:00 +---------------------------------------- + +Instruction #233: + Timestep: 232 + Time: 2025-11-04 05:50:00+00:00 + ID: f1069a63-5a96-4bd7-83ed-ed2a01197cf3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:50:00+00:00 +---------------------------------------- + +Instruction #234: + Timestep: 233 + Time: 2025-11-04 05:55:00+00:00 + ID: b6845a7a-d99c-4008-a2ea-d9999cfc01d8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:55:00+00:00 +---------------------------------------- + +Instruction #235: + Timestep: 234 + Time: 2025-11-04 06:00:00+00:00 + ID: af94fb5d-0be3-4c38-b18c-97f04e1449ac + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:00:00+00:00 +---------------------------------------- + +Instruction #236: + Timestep: 235 + Time: 2025-11-04 06:05:00+00:00 + ID: a5cd576e-e63b-45fa-8724-d266b3a6498a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:05:00+00:00 +---------------------------------------- + +Instruction #237: + Timestep: 236 + Time: 2025-11-04 06:10:00+00:00 + ID: cb3d6545-3028-49d8-a8ef-536075fc883f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:10:00+00:00 +---------------------------------------- + +Instruction #238: + Timestep: 237 + Time: 2025-11-04 06:15:00+00:00 + ID: 3f5ea738-9c2b-46ae-bf17-50e015549192 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:15:00+00:00 +---------------------------------------- + +Instruction #239: + Timestep: 238 + Time: 2025-11-04 06:20:00+00:00 + ID: 422e9c32-64bc-4b8e-9bfb-0f033ee0b57e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:20:00+00:00 +---------------------------------------- + +Instruction #240: + Timestep: 239 + Time: 2025-11-04 06:25:00+00:00 + ID: 9b3135af-ae18-4339-befe-51b17fb29756 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:25:00+00:00 +---------------------------------------- + +Instruction #241: + Timestep: 240 + Time: 2025-11-04 06:30:00+00:00 + ID: 8d45702c-f005-4c57-aecc-2872b306c68e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:30:00+00:00 +---------------------------------------- + +Instruction #242: + Timestep: 241 + Time: 2025-11-04 06:35:00+00:00 + ID: dd180ef8-93aa-4375-b8e1-809acf5a6294 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:35:00+00:00 +---------------------------------------- + +Instruction #243: + Timestep: 242 + Time: 2025-11-04 06:40:00+00:00 + ID: c9248f10-f702-411e-ac85-608b854c446a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:40:00+00:00 +---------------------------------------- + +Instruction #244: + Timestep: 243 + Time: 2025-11-04 06:45:00+00:00 + ID: a12f0774-10c8-4e59-ba23-a95511f1b137 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:45:00+00:00 +---------------------------------------- + +Instruction #245: + Timestep: 244 + Time: 2025-11-04 06:50:00+00:00 + ID: d3209d1e-f10e-4698-b44c-cd83af0d8cc7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:50:00+00:00 +---------------------------------------- + +Instruction #246: + Timestep: 245 + Time: 2025-11-04 06:55:00+00:00 + ID: c4cda9ee-2721-402a-95aa-1b804fbe17ff + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:55:00+00:00 +---------------------------------------- + +Instruction #247: + Timestep: 246 + Time: 2025-11-04 07:00:00+00:00 + ID: f0351c3b-52ab-427e-a1b6-2464d9592b9f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:00:00+00:00 +---------------------------------------- + +Instruction #248: + Timestep: 247 + Time: 2025-11-04 07:05:00+00:00 + ID: 150fa754-dda4-4e0f-be5f-6707225a26cb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:05:00+00:00 +---------------------------------------- + +Instruction #249: + Timestep: 248 + Time: 2025-11-04 07:10:00+00:00 + ID: b338b427-c48d-40c8-9b2c-201999d0f72f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:10:00+00:00 +---------------------------------------- + +Instruction #250: + Timestep: 249 + Time: 2025-11-04 07:15:00+00:00 + ID: 17b8f14c-de9b-471c-a365-b90f2625963c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:15:00+00:00 +---------------------------------------- + +Instruction #251: + Timestep: 250 + Time: 2025-11-04 07:20:00+00:00 + ID: a177f48e-2181-4e08-8b7e-3a08c3007a84 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:20:00+00:00 +---------------------------------------- + +Instruction #252: + Timestep: 251 + Time: 2025-11-04 07:25:00+00:00 + ID: 52b2f9c8-4d34-4dfd-8f04-ffb4e3d3bbac + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:25:00+00:00 +---------------------------------------- + +Instruction #253: + Timestep: 252 + Time: 2025-11-04 07:30:00+00:00 + ID: 5a5c9cd2-76f1-4fde-84f2-fb43f9891948 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:30:00+00:00 +---------------------------------------- + +Instruction #254: + Timestep: 253 + Time: 2025-11-04 07:35:00+00:00 + ID: 1e7a0332-36c1-48f0-813f-0b33ada638c9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:35:00+00:00 +---------------------------------------- + +Instruction #255: + Timestep: 254 + Time: 2025-11-04 07:40:00+00:00 + ID: b4ed6c87-9747-4545-81d1-5185654187c9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:40:00+00:00 +---------------------------------------- + +Instruction #256: + Timestep: 255 + Time: 2025-11-04 07:45:00+00:00 + ID: e7f1b1b8-ba74-4c6b-8dc8-4eb451f66a87 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:45:00+00:00 +---------------------------------------- + +Instruction #257: + Timestep: 256 + Time: 2025-11-04 07:50:00+00:00 + ID: e898e67b-fab7-4992-a571-b1feeeddcbb6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:50:00+00:00 +---------------------------------------- + +Instruction #258: + Timestep: 257 + Time: 2025-11-04 07:55:00+00:00 + ID: ab770a9d-6ce4-41ea-9a9d-d3f5f98e1453 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:55:00+00:00 +---------------------------------------- + +Instruction #259: + Timestep: 258 + Time: 2025-11-04 08:00:00+00:00 + ID: 851feb94-37e6-4df9-88a3-d14331dc8165 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:00:00+00:00 +---------------------------------------- + +Instruction #260: + Timestep: 259 + Time: 2025-11-04 08:05:00+00:00 + ID: 3faeb273-8559-44b3-8be5-35a6defbc028 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:05:00+00:00 +---------------------------------------- + +Instruction #261: + Timestep: 260 + Time: 2025-11-04 08:10:00+00:00 + ID: 52acfa9e-33f5-4770-a2e4-4dbd05f87a02 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:10:00+00:00 +---------------------------------------- + +Instruction #262: + Timestep: 261 + Time: 2025-11-04 08:15:00+00:00 + ID: 681112f5-a7d4-4be7-a8aa-37d62fb6fe13 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:15:00+00:00 +---------------------------------------- + +Instruction #263: + Timestep: 262 + Time: 2025-11-04 08:20:00+00:00 + ID: 0a5b1201-b92c-4fa3-b4e9-d3e35db1f9d3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:20:00+00:00 +---------------------------------------- + +Instruction #264: + Timestep: 263 + Time: 2025-11-04 08:25:00+00:00 + ID: af7c8343-5c11-40ec-b594-2ee9450aeea7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:25:00+00:00 +---------------------------------------- + +Instruction #265: + Timestep: 264 + Time: 2025-11-04 08:30:00+00:00 + ID: 7b18d5e5-463a-488a-9b13-1a1c5c3a2ad7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:30:00+00:00 +---------------------------------------- + +Instruction #266: + Timestep: 265 + Time: 2025-11-04 08:35:00+00:00 + ID: 3b49bea5-3734-4cb4-902a-627d372690c6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:35:00+00:00 +---------------------------------------- + +Instruction #267: + Timestep: 266 + Time: 2025-11-04 08:40:00+00:00 + ID: 48c60b29-fa94-4368-a2d0-8a5e2ff99e0c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:40:00+00:00 +---------------------------------------- + +Instruction #268: + Timestep: 267 + Time: 2025-11-04 08:45:00+00:00 + ID: 13528d8d-1ca8-43c5-8751-38603a768f7e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:45:00+00:00 +---------------------------------------- + +Instruction #269: + Timestep: 268 + Time: 2025-11-04 08:50:00+00:00 + ID: d17f3930-e3c8-45a3-85ac-44fa38157d92 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:50:00+00:00 +---------------------------------------- + +Instruction #270: + Timestep: 269 + Time: 2025-11-04 08:55:00+00:00 + ID: 0ed320fb-039e-429d-ba6b-e11c341af7cb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:55:00+00:00 +---------------------------------------- + +Instruction #271: + Timestep: 270 + Time: 2025-11-04 09:00:00+00:00 + ID: 4f77207d-0bed-493c-b404-d46b89105c04 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:00:00+00:00 +---------------------------------------- + +Instruction #272: + Timestep: 271 + Time: 2025-11-04 09:05:00+00:00 + ID: e0abf01e-ade7-421f-bed6-2058996e217e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:05:00+00:00 +---------------------------------------- + +Instruction #273: + Timestep: 272 + Time: 2025-11-04 09:10:00+00:00 + ID: 190a56bb-0957-4e32-ab88-2866db996661 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:10:00+00:00 +---------------------------------------- + +Instruction #274: + Timestep: 273 + Time: 2025-11-04 09:15:00+00:00 + ID: 5246135a-9984-4ac1-aa8e-0fd2000bc609 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:15:00+00:00 +---------------------------------------- + +Instruction #275: + Timestep: 274 + Time: 2025-11-04 09:20:00+00:00 + ID: 7c028112-2f51-4727-9087-8980a0562237 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:20:00+00:00 +---------------------------------------- + +Instruction #276: + Timestep: 275 + Time: 2025-11-04 09:25:00+00:00 + ID: 7c0d1427-c4df-4a58-9ab2-3c0f107edaa2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:25:00+00:00 +---------------------------------------- + +Instruction #277: + Timestep: 276 + Time: 2025-11-04 09:30:00+00:00 + ID: b220990e-2179-405a-830d-d37848d019ab + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:30:00+00:00 +---------------------------------------- + +Instruction #278: + Timestep: 277 + Time: 2025-11-04 09:35:00+00:00 + ID: 9ac60ea5-d406-4749-9103-fbb60275649a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:35:00+00:00 +---------------------------------------- + +Instruction #279: + Timestep: 278 + Time: 2025-11-04 09:40:00+00:00 + ID: c851842d-bc83-491c-a21e-bb0bd12d3d25 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:40:00+00:00 +---------------------------------------- + +Instruction #280: + Timestep: 279 + Time: 2025-11-04 09:45:00+00:00 + ID: 5e64be1e-050d-48ed-bf3b-ce8ad07462a2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:45:00+00:00 +---------------------------------------- + +Instruction #281: + Timestep: 280 + Time: 2025-11-04 09:50:00+00:00 + ID: 2d3a12b7-bc43-4889-831f-c32b7b63fe5d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:50:00+00:00 +---------------------------------------- + +Instruction #282: + Timestep: 281 + Time: 2025-11-04 09:55:00+00:00 + ID: 4988dced-b972-4fa2-85f6-55912b60e30e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:55:00+00:00 +---------------------------------------- + +Instruction #283: + Timestep: 282 + Time: 2025-11-04 10:00:00+00:00 + ID: 59f3fd55-d896-4278-aa98-1ed5a15a0775 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:00:00+00:00 +---------------------------------------- + +Instruction #284: + Timestep: 283 + Time: 2025-11-04 10:05:00+00:00 + ID: 3af01b7f-e1c4-434e-9099-ebbc384c32fd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:05:00+00:00 +---------------------------------------- + +Instruction #285: + Timestep: 284 + Time: 2025-11-04 10:10:00+00:00 + ID: bc3d9487-2df9-4046-925e-ece009f3d438 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:10:00+00:00 +---------------------------------------- + +Instruction #286: + Timestep: 285 + Time: 2025-11-04 10:15:00+00:00 + ID: 34de4a2a-18ba-4fc1-b587-10e769dfd96a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:15:00+00:00 +---------------------------------------- + +Instruction #287: + Timestep: 286 + Time: 2025-11-04 10:20:00+00:00 + ID: 6b816706-c164-4255-9431-421326c351a9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:20:00+00:00 +---------------------------------------- + +Instruction #288: + Timestep: 287 + Time: 2025-11-04 10:25:00+00:00 + ID: 9c876bc7-075d-408f-9de9-135ba63cb640 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:25:00+00:00 +---------------------------------------- diff --git a/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_cost_D=1_B=200_S=30_T=288.txt b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_cost_D=1_B=200_S=30_T=288.txt new file mode 100644 index 0000000..ec30e29 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_cost_D=1_B=200_S=30_T=288.txt @@ -0,0 +1,3218 @@ +================================================================================ +ITHO DHW Heat Pump Instructions Cost +================================================================================ +Planning start time: 2025-11-05 14:10:00+00:00 +Planning window: 1 days 00:00:00 +Resolution: 0 days 00:05:00 +Total timesteps: 288 +================================================================================ + +Device: itho_dhw_device_003 +Number of instructions: 288 +-------------------------------------------------------------------------------- + +Instruction Timeline: +-------------------------------------------------------------------------------- + Mode: DHW_ON + Start: 2025-11-05 14:10:00+00:00 (timestep 0) + Duration: 7 timesteps (35.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-05 14:45:00+00:00 (timestep 7) + Duration: 19 timesteps (95.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-05 16:20:00+00:00 (timestep 26) + Duration: 53 timesteps (265.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-05 20:45:00+00:00 (timestep 79) + Duration: 124 timesteps (620.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-06 07:05:00+00:00 (timestep 203) + Duration: 6 timesteps (30.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-06 07:35:00+00:00 (timestep 209) + Duration: 79 timesteps (395.0 minutes) +---------------------------------------- + +Total operation mode changes: 5 +================================================================================ + +Detailed Instruction List: +================================================================================ + +Instruction #1: + Timestep: 0 + Time: 2025-11-05 14:10:00+00:00 + ID: a607df3d-4615-45e7-8e8d-fd32762b910a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:10:00+00:00 +---------------------------------------- + +Instruction #2: + Timestep: 1 + Time: 2025-11-05 14:15:00+00:00 + ID: 8d7a0849-ad6c-4446-962c-991612c1e243 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:15:00+00:00 +---------------------------------------- + +Instruction #3: + Timestep: 2 + Time: 2025-11-05 14:20:00+00:00 + ID: 1a74f25c-dac4-41b0-b8ab-0fb51ae8cd95 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:20:00+00:00 +---------------------------------------- + +Instruction #4: + Timestep: 3 + Time: 2025-11-05 14:25:00+00:00 + ID: d66956c2-e904-4e69-9bfc-175a96926377 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:25:00+00:00 +---------------------------------------- + +Instruction #5: + Timestep: 4 + Time: 2025-11-05 14:30:00+00:00 + ID: 87a39cec-19ed-4c70-93b0-6d6d2bfe842d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:30:00+00:00 +---------------------------------------- + +Instruction #6: + Timestep: 5 + Time: 2025-11-05 14:35:00+00:00 + ID: f05b6540-7c25-4c8c-b2c9-b93cfbfc8299 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:35:00+00:00 +---------------------------------------- + +Instruction #7: + Timestep: 6 + Time: 2025-11-05 14:40:00+00:00 + ID: 1aeabc8f-a212-43b4-86e0-beb6f4c04a2f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:40:00+00:00 +---------------------------------------- + +Instruction #8: + Timestep: 7 + Time: 2025-11-05 14:45:00+00:00 + ID: ffb3d047-d2b7-44e0-ac0c-b84750230f84 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:45:00+00:00 +---------------------------------------- + +Instruction #9: + Timestep: 8 + Time: 2025-11-05 14:50:00+00:00 + ID: aabb95e6-3f9c-4f59-a628-a955e8210d2b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:50:00+00:00 +---------------------------------------- + +Instruction #10: + Timestep: 9 + Time: 2025-11-05 14:55:00+00:00 + ID: a2f01523-8833-41db-98c0-f7905439481f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 14:55:00+00:00 +---------------------------------------- + +Instruction #11: + Timestep: 10 + Time: 2025-11-05 15:00:00+00:00 + ID: a4b0d48f-0645-44d1-8d2e-8878223de140 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:00:00+00:00 +---------------------------------------- + +Instruction #12: + Timestep: 11 + Time: 2025-11-05 15:05:00+00:00 + ID: a114f19f-9393-4ea1-a401-041dae2c0aad + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:05:00+00:00 +---------------------------------------- + +Instruction #13: + Timestep: 12 + Time: 2025-11-05 15:10:00+00:00 + ID: 68f6fa97-e658-4f0d-a2c0-6198d971d319 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:10:00+00:00 +---------------------------------------- + +Instruction #14: + Timestep: 13 + Time: 2025-11-05 15:15:00+00:00 + ID: f9cab0d2-d477-4457-a950-da1f5c254019 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:15:00+00:00 +---------------------------------------- + +Instruction #15: + Timestep: 14 + Time: 2025-11-05 15:20:00+00:00 + ID: d85fb2e6-dc4c-4e95-a66c-8f9d743432a7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:20:00+00:00 +---------------------------------------- + +Instruction #16: + Timestep: 15 + Time: 2025-11-05 15:25:00+00:00 + ID: 93c3d453-3880-4a55-8d74-726800f42a29 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:25:00+00:00 +---------------------------------------- + +Instruction #17: + Timestep: 16 + Time: 2025-11-05 15:30:00+00:00 + ID: 98fd64df-5d60-4102-b0d6-efa54e9bba00 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:30:00+00:00 +---------------------------------------- + +Instruction #18: + Timestep: 17 + Time: 2025-11-05 15:35:00+00:00 + ID: e1cfb574-5a8a-422c-b4bf-6da482e6746c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:35:00+00:00 +---------------------------------------- + +Instruction #19: + Timestep: 18 + Time: 2025-11-05 15:40:00+00:00 + ID: bd35c9ae-2532-4489-9407-18f9a965db92 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:40:00+00:00 +---------------------------------------- + +Instruction #20: + Timestep: 19 + Time: 2025-11-05 15:45:00+00:00 + ID: 1413cfb4-8273-493b-82ec-de7f780d555d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:45:00+00:00 +---------------------------------------- + +Instruction #21: + Timestep: 20 + Time: 2025-11-05 15:50:00+00:00 + ID: c50639a8-4c74-445b-a024-acce1f58a77d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:50:00+00:00 +---------------------------------------- + +Instruction #22: + Timestep: 21 + Time: 2025-11-05 15:55:00+00:00 + ID: b774d7fe-3287-4f0b-b561-a6b4228c84f5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 15:55:00+00:00 +---------------------------------------- + +Instruction #23: + Timestep: 22 + Time: 2025-11-05 16:00:00+00:00 + ID: 04e8c6dc-010c-475e-9a33-fd0b5caa01fc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:00:00+00:00 +---------------------------------------- + +Instruction #24: + Timestep: 23 + Time: 2025-11-05 16:05:00+00:00 + ID: e3a46199-901e-4a71-b156-d86b45744a8e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:05:00+00:00 +---------------------------------------- + +Instruction #25: + Timestep: 24 + Time: 2025-11-05 16:10:00+00:00 + ID: 77baa0ec-667f-49a2-a420-cb97163bf5a9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:10:00+00:00 +---------------------------------------- + +Instruction #26: + Timestep: 25 + Time: 2025-11-05 16:15:00+00:00 + ID: 31e9dfe5-5c4a-4865-9d79-f89ea6fe1df4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:15:00+00:00 +---------------------------------------- + +Instruction #27: + Timestep: 26 + Time: 2025-11-05 16:20:00+00:00 + ID: 29b12ab2-5929-4508-84de-5f5f45dc4caa + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:20:00+00:00 +---------------------------------------- + +Instruction #28: + Timestep: 27 + Time: 2025-11-05 16:25:00+00:00 + ID: 55e6d25c-78f6-41b0-8f8b-045ba2da76d1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:25:00+00:00 +---------------------------------------- + +Instruction #29: + Timestep: 28 + Time: 2025-11-05 16:30:00+00:00 + ID: 7c2ccebb-b399-4c75-ab2b-93a8a1c8ef7e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:30:00+00:00 +---------------------------------------- + +Instruction #30: + Timestep: 29 + Time: 2025-11-05 16:35:00+00:00 + ID: 42546ee8-7230-49bb-b0b1-88f6dfa3a66f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:35:00+00:00 +---------------------------------------- + +Instruction #31: + Timestep: 30 + Time: 2025-11-05 16:40:00+00:00 + ID: ceb16ed4-9d74-4aa6-92a1-f909190ce40c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:40:00+00:00 +---------------------------------------- + +Instruction #32: + Timestep: 31 + Time: 2025-11-05 16:45:00+00:00 + ID: c459bcbb-4484-4cad-b1a8-7c3afdb294c9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:45:00+00:00 +---------------------------------------- + +Instruction #33: + Timestep: 32 + Time: 2025-11-05 16:50:00+00:00 + ID: 98e8dda3-8752-4261-a704-f324c0b02b09 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:50:00+00:00 +---------------------------------------- + +Instruction #34: + Timestep: 33 + Time: 2025-11-05 16:55:00+00:00 + ID: 9826e3c7-da68-4b01-991b-3281dfae9fec + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 16:55:00+00:00 +---------------------------------------- + +Instruction #35: + Timestep: 34 + Time: 2025-11-05 17:00:00+00:00 + ID: 44100e91-704a-490f-86da-a670f317528c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:00:00+00:00 +---------------------------------------- + +Instruction #36: + Timestep: 35 + Time: 2025-11-05 17:05:00+00:00 + ID: 103d8a13-f64b-4304-9faf-f72b77482b66 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:05:00+00:00 +---------------------------------------- + +Instruction #37: + Timestep: 36 + Time: 2025-11-05 17:10:00+00:00 + ID: ee27e3de-5781-4517-9e94-2d2c700fb033 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:10:00+00:00 +---------------------------------------- + +Instruction #38: + Timestep: 37 + Time: 2025-11-05 17:15:00+00:00 + ID: 6fc365ba-e1fb-4671-bc1a-18f9a9edf469 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:15:00+00:00 +---------------------------------------- + +Instruction #39: + Timestep: 38 + Time: 2025-11-05 17:20:00+00:00 + ID: de2e293c-eb79-43de-bec2-46e25efd06ae + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:20:00+00:00 +---------------------------------------- + +Instruction #40: + Timestep: 39 + Time: 2025-11-05 17:25:00+00:00 + ID: 6fab1d8b-07b1-4cc5-8741-f55dfe923cd8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:25:00+00:00 +---------------------------------------- + +Instruction #41: + Timestep: 40 + Time: 2025-11-05 17:30:00+00:00 + ID: efc50d22-16a8-4d1d-95e7-47eff66a0794 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:30:00+00:00 +---------------------------------------- + +Instruction #42: + Timestep: 41 + Time: 2025-11-05 17:35:00+00:00 + ID: 328750e3-6a3c-4fc9-b8eb-f47b82bdb849 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:35:00+00:00 +---------------------------------------- + +Instruction #43: + Timestep: 42 + Time: 2025-11-05 17:40:00+00:00 + ID: 848342f2-7742-43cc-ad1f-5d11ce7f9fb3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:40:00+00:00 +---------------------------------------- + +Instruction #44: + Timestep: 43 + Time: 2025-11-05 17:45:00+00:00 + ID: 85d7e3ef-00c8-4a7e-96ec-ddfa7fe4d03b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:45:00+00:00 +---------------------------------------- + +Instruction #45: + Timestep: 44 + Time: 2025-11-05 17:50:00+00:00 + ID: d2b9ed5b-98e9-48a9-8cc7-d7a6ac95200a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:50:00+00:00 +---------------------------------------- + +Instruction #46: + Timestep: 45 + Time: 2025-11-05 17:55:00+00:00 + ID: 427613c8-d9d1-4355-85c0-e28eca4f356a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 17:55:00+00:00 +---------------------------------------- + +Instruction #47: + Timestep: 46 + Time: 2025-11-05 18:00:00+00:00 + ID: 821468c6-5583-44ea-8dd9-8c7c86240918 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:00:00+00:00 +---------------------------------------- + +Instruction #48: + Timestep: 47 + Time: 2025-11-05 18:05:00+00:00 + ID: c79a1cf7-ddd1-441d-b3af-93f92cd61b02 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:05:00+00:00 +---------------------------------------- + +Instruction #49: + Timestep: 48 + Time: 2025-11-05 18:10:00+00:00 + ID: abb26b86-7bf1-4c69-a553-dbf7455eed6c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:10:00+00:00 +---------------------------------------- + +Instruction #50: + Timestep: 49 + Time: 2025-11-05 18:15:00+00:00 + ID: bbb9b27b-bc08-4ad1-be95-96fd80878c85 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:15:00+00:00 +---------------------------------------- + +Instruction #51: + Timestep: 50 + Time: 2025-11-05 18:20:00+00:00 + ID: 3905d6f9-11f4-42fd-ab7c-d080a248f586 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:20:00+00:00 +---------------------------------------- + +Instruction #52: + Timestep: 51 + Time: 2025-11-05 18:25:00+00:00 + ID: a5f6e140-8210-46f0-855b-abf4efbd0dd9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:25:00+00:00 +---------------------------------------- + +Instruction #53: + Timestep: 52 + Time: 2025-11-05 18:30:00+00:00 + ID: 3bfeddc3-dbe6-4b5b-8953-8f9d10799834 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:30:00+00:00 +---------------------------------------- + +Instruction #54: + Timestep: 53 + Time: 2025-11-05 18:35:00+00:00 + ID: 4112b2e0-56f2-432d-9f83-eea36da54984 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:35:00+00:00 +---------------------------------------- + +Instruction #55: + Timestep: 54 + Time: 2025-11-05 18:40:00+00:00 + ID: d0588239-a3f7-48b8-83c8-86206a3753e6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:40:00+00:00 +---------------------------------------- + +Instruction #56: + Timestep: 55 + Time: 2025-11-05 18:45:00+00:00 + ID: 99cf5e5a-8a2a-4b67-b9bd-338763441770 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:45:00+00:00 +---------------------------------------- + +Instruction #57: + Timestep: 56 + Time: 2025-11-05 18:50:00+00:00 + ID: 7f1b451d-f747-4694-992c-e078808b6aa6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:50:00+00:00 +---------------------------------------- + +Instruction #58: + Timestep: 57 + Time: 2025-11-05 18:55:00+00:00 + ID: dd1852e7-77e9-4aa0-b31c-1f53d885c8e9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 18:55:00+00:00 +---------------------------------------- + +Instruction #59: + Timestep: 58 + Time: 2025-11-05 19:00:00+00:00 + ID: 5530162a-0f46-4a2e-a6c5-d8bb0d823345 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:00:00+00:00 +---------------------------------------- + +Instruction #60: + Timestep: 59 + Time: 2025-11-05 19:05:00+00:00 + ID: 1ca5a31e-1999-48a3-a278-d5723b408524 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:05:00+00:00 +---------------------------------------- + +Instruction #61: + Timestep: 60 + Time: 2025-11-05 19:10:00+00:00 + ID: 32fa55ec-e355-418c-967a-7a591f09739c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:10:00+00:00 +---------------------------------------- + +Instruction #62: + Timestep: 61 + Time: 2025-11-05 19:15:00+00:00 + ID: d9b2aa76-d3b5-4e75-a637-0b260adf830c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:15:00+00:00 +---------------------------------------- + +Instruction #63: + Timestep: 62 + Time: 2025-11-05 19:20:00+00:00 + ID: 1d97a5c4-a9e0-45af-a9d6-4e4cf26c8761 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:20:00+00:00 +---------------------------------------- + +Instruction #64: + Timestep: 63 + Time: 2025-11-05 19:25:00+00:00 + ID: 3829d685-6937-49e3-b4a6-ad07d3e746b8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:25:00+00:00 +---------------------------------------- + +Instruction #65: + Timestep: 64 + Time: 2025-11-05 19:30:00+00:00 + ID: d72cc742-9c90-4396-86fd-38ccd8c415ca + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:30:00+00:00 +---------------------------------------- + +Instruction #66: + Timestep: 65 + Time: 2025-11-05 19:35:00+00:00 + ID: 069e1529-4ed2-4b0d-b387-eaabe3b4780e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:35:00+00:00 +---------------------------------------- + +Instruction #67: + Timestep: 66 + Time: 2025-11-05 19:40:00+00:00 + ID: 895dbab8-03a4-40b3-b025-bb7de65acff5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:40:00+00:00 +---------------------------------------- + +Instruction #68: + Timestep: 67 + Time: 2025-11-05 19:45:00+00:00 + ID: 542af801-45ca-45c9-9251-e17c5af1ec72 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:45:00+00:00 +---------------------------------------- + +Instruction #69: + Timestep: 68 + Time: 2025-11-05 19:50:00+00:00 + ID: a1848f10-077d-45d8-939d-89eaadb6806e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:50:00+00:00 +---------------------------------------- + +Instruction #70: + Timestep: 69 + Time: 2025-11-05 19:55:00+00:00 + ID: 4d3ead0b-2a8f-4828-81d8-0cfb2dbd3975 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 19:55:00+00:00 +---------------------------------------- + +Instruction #71: + Timestep: 70 + Time: 2025-11-05 20:00:00+00:00 + ID: adad14b2-e3d1-44b2-8f8b-0050819e6234 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:00:00+00:00 +---------------------------------------- + +Instruction #72: + Timestep: 71 + Time: 2025-11-05 20:05:00+00:00 + ID: 19e61a9d-043d-4199-87b3-c5d914eb5f47 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:05:00+00:00 +---------------------------------------- + +Instruction #73: + Timestep: 72 + Time: 2025-11-05 20:10:00+00:00 + ID: e6021c41-4103-426a-8765-721389c36454 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:10:00+00:00 +---------------------------------------- + +Instruction #74: + Timestep: 73 + Time: 2025-11-05 20:15:00+00:00 + ID: 2f6d3baf-7096-4f1e-84ff-4c49058121f4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:15:00+00:00 +---------------------------------------- + +Instruction #75: + Timestep: 74 + Time: 2025-11-05 20:20:00+00:00 + ID: 20ca2a82-c841-4405-bafd-bf001fd8a526 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:20:00+00:00 +---------------------------------------- + +Instruction #76: + Timestep: 75 + Time: 2025-11-05 20:25:00+00:00 + ID: 0e181ea6-6ef3-4876-8702-f1624d0a50dc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:25:00+00:00 +---------------------------------------- + +Instruction #77: + Timestep: 76 + Time: 2025-11-05 20:30:00+00:00 + ID: 3e805c7f-7dfe-4f4e-b31c-2b7c96693681 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:30:00+00:00 +---------------------------------------- + +Instruction #78: + Timestep: 77 + Time: 2025-11-05 20:35:00+00:00 + ID: 2d1711f5-58c3-425d-abd0-ed8bb8e4f309 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:35:00+00:00 +---------------------------------------- + +Instruction #79: + Timestep: 78 + Time: 2025-11-05 20:40:00+00:00 + ID: 656988d8-7d13-4919-9782-b77939ffcaca + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:40:00+00:00 +---------------------------------------- + +Instruction #80: + Timestep: 79 + Time: 2025-11-05 20:45:00+00:00 + ID: e586713e-9992-4d94-a28b-06177dcc0da1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:45:00+00:00 +---------------------------------------- + +Instruction #81: + Timestep: 80 + Time: 2025-11-05 20:50:00+00:00 + ID: dda8203c-caad-49da-bafc-558c16825a1d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:50:00+00:00 +---------------------------------------- + +Instruction #82: + Timestep: 81 + Time: 2025-11-05 20:55:00+00:00 + ID: 7339772a-f20f-4ff1-8397-3ca260a2c152 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 20:55:00+00:00 +---------------------------------------- + +Instruction #83: + Timestep: 82 + Time: 2025-11-05 21:00:00+00:00 + ID: 98e5fe7d-07f7-40d3-bae6-c993a9eaaa0b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:00:00+00:00 +---------------------------------------- + +Instruction #84: + Timestep: 83 + Time: 2025-11-05 21:05:00+00:00 + ID: f516bdc8-77b6-4732-9b63-fb6533c471e9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:05:00+00:00 +---------------------------------------- + +Instruction #85: + Timestep: 84 + Time: 2025-11-05 21:10:00+00:00 + ID: 0404a191-f425-4977-87f3-210f74d2a49a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:10:00+00:00 +---------------------------------------- + +Instruction #86: + Timestep: 85 + Time: 2025-11-05 21:15:00+00:00 + ID: d6c0ec61-7ee5-4382-a700-1f033365bb83 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:15:00+00:00 +---------------------------------------- + +Instruction #87: + Timestep: 86 + Time: 2025-11-05 21:20:00+00:00 + ID: cbb03cc2-1d4f-4e35-a385-3501d8f2aa26 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:20:00+00:00 +---------------------------------------- + +Instruction #88: + Timestep: 87 + Time: 2025-11-05 21:25:00+00:00 + ID: 10b0ecb2-715b-476e-85e5-395731d782f4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:25:00+00:00 +---------------------------------------- + +Instruction #89: + Timestep: 88 + Time: 2025-11-05 21:30:00+00:00 + ID: 48c73627-8ddf-44ac-9e04-1536a94d6923 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:30:00+00:00 +---------------------------------------- + +Instruction #90: + Timestep: 89 + Time: 2025-11-05 21:35:00+00:00 + ID: c23e2d55-ff8c-4257-89b3-a52f83f049b3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:35:00+00:00 +---------------------------------------- + +Instruction #91: + Timestep: 90 + Time: 2025-11-05 21:40:00+00:00 + ID: 92179365-fc76-44b1-b02c-4903552930c0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:40:00+00:00 +---------------------------------------- + +Instruction #92: + Timestep: 91 + Time: 2025-11-05 21:45:00+00:00 + ID: fda08542-2b94-4b14-9b7a-8818d7d8742d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:45:00+00:00 +---------------------------------------- + +Instruction #93: + Timestep: 92 + Time: 2025-11-05 21:50:00+00:00 + ID: c25151aa-20bb-42c8-81ef-fdd90bcc76d6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:50:00+00:00 +---------------------------------------- + +Instruction #94: + Timestep: 93 + Time: 2025-11-05 21:55:00+00:00 + ID: 6302cc46-6e5d-4b9d-96b5-ec83bd4ba19e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 21:55:00+00:00 +---------------------------------------- + +Instruction #95: + Timestep: 94 + Time: 2025-11-05 22:00:00+00:00 + ID: 812b8c68-35f6-4b10-91da-84d60863b015 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:00:00+00:00 +---------------------------------------- + +Instruction #96: + Timestep: 95 + Time: 2025-11-05 22:05:00+00:00 + ID: fa8f903c-ae41-4b84-bae4-89d5312968c7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:05:00+00:00 +---------------------------------------- + +Instruction #97: + Timestep: 96 + Time: 2025-11-05 22:10:00+00:00 + ID: 52da8785-a1ed-4d5f-bf65-a2ec5a3101ec + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:10:00+00:00 +---------------------------------------- + +Instruction #98: + Timestep: 97 + Time: 2025-11-05 22:15:00+00:00 + ID: 116c6cc1-c5fc-4481-b3bb-f6abfc2d549f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:15:00+00:00 +---------------------------------------- + +Instruction #99: + Timestep: 98 + Time: 2025-11-05 22:20:00+00:00 + ID: 6c78a1b8-94dc-4391-ada3-5f54c11c39d5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:20:00+00:00 +---------------------------------------- + +Instruction #100: + Timestep: 99 + Time: 2025-11-05 22:25:00+00:00 + ID: 5ffba73d-299a-4a9e-bd8c-cc6fe816cbe1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:25:00+00:00 +---------------------------------------- + +Instruction #101: + Timestep: 100 + Time: 2025-11-05 22:30:00+00:00 + ID: 545f7466-5dae-4d75-a694-057bae68edf6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:30:00+00:00 +---------------------------------------- + +Instruction #102: + Timestep: 101 + Time: 2025-11-05 22:35:00+00:00 + ID: bea09ea9-ad25-430b-a978-94a85c49a2ed + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:35:00+00:00 +---------------------------------------- + +Instruction #103: + Timestep: 102 + Time: 2025-11-05 22:40:00+00:00 + ID: 97fafde2-7237-4398-921a-faebb10d443b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:40:00+00:00 +---------------------------------------- + +Instruction #104: + Timestep: 103 + Time: 2025-11-05 22:45:00+00:00 + ID: e1458564-27e5-4184-b9b7-fa61da8446a0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:45:00+00:00 +---------------------------------------- + +Instruction #105: + Timestep: 104 + Time: 2025-11-05 22:50:00+00:00 + ID: 9f802d9e-a74b-4b8d-80ce-e991c8b788f8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:50:00+00:00 +---------------------------------------- + +Instruction #106: + Timestep: 105 + Time: 2025-11-05 22:55:00+00:00 + ID: a3f86417-33ae-4e6f-bcab-a7563d755632 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 22:55:00+00:00 +---------------------------------------- + +Instruction #107: + Timestep: 106 + Time: 2025-11-05 23:00:00+00:00 + ID: 40f35609-75a0-407f-ac08-cd8e28f95c67 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:00:00+00:00 +---------------------------------------- + +Instruction #108: + Timestep: 107 + Time: 2025-11-05 23:05:00+00:00 + ID: 029862fa-4b41-47df-9008-149ffcb640c1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:05:00+00:00 +---------------------------------------- + +Instruction #109: + Timestep: 108 + Time: 2025-11-05 23:10:00+00:00 + ID: 4875bff6-ea9d-47a3-a0ee-51ec0d282060 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:10:00+00:00 +---------------------------------------- + +Instruction #110: + Timestep: 109 + Time: 2025-11-05 23:15:00+00:00 + ID: bdcd95f1-4cb0-404d-aa97-9871ab571095 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:15:00+00:00 +---------------------------------------- + +Instruction #111: + Timestep: 110 + Time: 2025-11-05 23:20:00+00:00 + ID: 26474c0c-7a0d-48e9-8d93-458281a59bc8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:20:00+00:00 +---------------------------------------- + +Instruction #112: + Timestep: 111 + Time: 2025-11-05 23:25:00+00:00 + ID: aa63520d-2310-4008-914a-a78e41b84b34 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:25:00+00:00 +---------------------------------------- + +Instruction #113: + Timestep: 112 + Time: 2025-11-05 23:30:00+00:00 + ID: 1e73c7ca-352d-4e4b-9616-d3672c8d7458 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:30:00+00:00 +---------------------------------------- + +Instruction #114: + Timestep: 113 + Time: 2025-11-05 23:35:00+00:00 + ID: 61336d94-29ec-4cc9-807e-60f81e127af0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:35:00+00:00 +---------------------------------------- + +Instruction #115: + Timestep: 114 + Time: 2025-11-05 23:40:00+00:00 + ID: d2163c19-b873-463d-8967-7b4782e3d69d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:40:00+00:00 +---------------------------------------- + +Instruction #116: + Timestep: 115 + Time: 2025-11-05 23:45:00+00:00 + ID: 60c4558a-7d7a-46c2-93c6-2cb4b7ed92fc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:45:00+00:00 +---------------------------------------- + +Instruction #117: + Timestep: 116 + Time: 2025-11-05 23:50:00+00:00 + ID: e56926b3-b030-4a5a-8c5a-d9803fa7dbf4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:50:00+00:00 +---------------------------------------- + +Instruction #118: + Timestep: 117 + Time: 2025-11-05 23:55:00+00:00 + ID: 0ff229c9-e308-42b5-a0ee-2ad0710f03c6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-05 23:55:00+00:00 +---------------------------------------- + +Instruction #119: + Timestep: 118 + Time: 2025-11-06 00:00:00+00:00 + ID: 3d50027c-0020-47f3-a94e-3c1672c8d5bd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:00:00+00:00 +---------------------------------------- + +Instruction #120: + Timestep: 119 + Time: 2025-11-06 00:05:00+00:00 + ID: da8eef38-2dba-48c8-8982-c44cc4823d5f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:05:00+00:00 +---------------------------------------- + +Instruction #121: + Timestep: 120 + Time: 2025-11-06 00:10:00+00:00 + ID: 6e3c77ab-6745-46a5-83f7-74e676ffa5b0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:10:00+00:00 +---------------------------------------- + +Instruction #122: + Timestep: 121 + Time: 2025-11-06 00:15:00+00:00 + ID: 498ba0a9-43f5-47fc-96b4-6e0e92b49846 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:15:00+00:00 +---------------------------------------- + +Instruction #123: + Timestep: 122 + Time: 2025-11-06 00:20:00+00:00 + ID: e6feea40-81b8-4aba-aa9a-43f36ac8cab1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:20:00+00:00 +---------------------------------------- + +Instruction #124: + Timestep: 123 + Time: 2025-11-06 00:25:00+00:00 + ID: 7aed39a9-fda9-4214-b7d3-d38843c33389 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:25:00+00:00 +---------------------------------------- + +Instruction #125: + Timestep: 124 + Time: 2025-11-06 00:30:00+00:00 + ID: 7e426f16-8f44-469a-90f8-96da1cbd68e2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:30:00+00:00 +---------------------------------------- + +Instruction #126: + Timestep: 125 + Time: 2025-11-06 00:35:00+00:00 + ID: eaf5897b-75ae-404e-af7d-79802e817de2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:35:00+00:00 +---------------------------------------- + +Instruction #127: + Timestep: 126 + Time: 2025-11-06 00:40:00+00:00 + ID: b3ee2c82-4adb-4ea5-9338-9c5c4bf7bc40 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:40:00+00:00 +---------------------------------------- + +Instruction #128: + Timestep: 127 + Time: 2025-11-06 00:45:00+00:00 + ID: eb88cee9-ff83-4339-aa4f-9b76bcb5c6af + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:45:00+00:00 +---------------------------------------- + +Instruction #129: + Timestep: 128 + Time: 2025-11-06 00:50:00+00:00 + ID: 9333baf2-2ff2-4853-aed3-1dd07baf1281 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:50:00+00:00 +---------------------------------------- + +Instruction #130: + Timestep: 129 + Time: 2025-11-06 00:55:00+00:00 + ID: cc48ea9c-2b4f-46e9-8365-2aae75deacaf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 00:55:00+00:00 +---------------------------------------- + +Instruction #131: + Timestep: 130 + Time: 2025-11-06 01:00:00+00:00 + ID: 69229eaf-f42e-4b3f-b2d6-0126cbf7fcc5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:00:00+00:00 +---------------------------------------- + +Instruction #132: + Timestep: 131 + Time: 2025-11-06 01:05:00+00:00 + ID: 73938aac-f889-4f8f-8188-597bde222bc7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:05:00+00:00 +---------------------------------------- + +Instruction #133: + Timestep: 132 + Time: 2025-11-06 01:10:00+00:00 + ID: daa6590c-079f-4b3e-92e6-1282a2481043 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:10:00+00:00 +---------------------------------------- + +Instruction #134: + Timestep: 133 + Time: 2025-11-06 01:15:00+00:00 + ID: 157ba8bb-85fd-42bb-b71a-57941953847e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:15:00+00:00 +---------------------------------------- + +Instruction #135: + Timestep: 134 + Time: 2025-11-06 01:20:00+00:00 + ID: 4a53341a-59f8-485a-920e-15203a38ce0e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:20:00+00:00 +---------------------------------------- + +Instruction #136: + Timestep: 135 + Time: 2025-11-06 01:25:00+00:00 + ID: f7fbd8ff-4a1c-430c-bf56-347c1ee83150 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:25:00+00:00 +---------------------------------------- + +Instruction #137: + Timestep: 136 + Time: 2025-11-06 01:30:00+00:00 + ID: 4cf7c322-899d-4432-a55c-99e0244e5dac + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:30:00+00:00 +---------------------------------------- + +Instruction #138: + Timestep: 137 + Time: 2025-11-06 01:35:00+00:00 + ID: 5c6b12d8-36fb-432a-b5a9-95ef1b9b3bc2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:35:00+00:00 +---------------------------------------- + +Instruction #139: + Timestep: 138 + Time: 2025-11-06 01:40:00+00:00 + ID: 11c691cd-58a0-420e-8d65-e811629085a0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:40:00+00:00 +---------------------------------------- + +Instruction #140: + Timestep: 139 + Time: 2025-11-06 01:45:00+00:00 + ID: 9d43b5b9-e303-48ea-a56c-1cb090ade2d5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:45:00+00:00 +---------------------------------------- + +Instruction #141: + Timestep: 140 + Time: 2025-11-06 01:50:00+00:00 + ID: 64d5f716-145b-4efd-a6bb-7d607b94af8e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:50:00+00:00 +---------------------------------------- + +Instruction #142: + Timestep: 141 + Time: 2025-11-06 01:55:00+00:00 + ID: c66e358a-efdb-486a-a800-ffd8bf7eca81 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 01:55:00+00:00 +---------------------------------------- + +Instruction #143: + Timestep: 142 + Time: 2025-11-06 02:00:00+00:00 + ID: 8a6bedad-74c7-461b-a865-b47e3081f47f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:00:00+00:00 +---------------------------------------- + +Instruction #144: + Timestep: 143 + Time: 2025-11-06 02:05:00+00:00 + ID: 52192718-7125-4531-82a0-58c4101f8372 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:05:00+00:00 +---------------------------------------- + +Instruction #145: + Timestep: 144 + Time: 2025-11-06 02:10:00+00:00 + ID: 76cccdf4-81f8-4ed4-b29d-51d844357724 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:10:00+00:00 +---------------------------------------- + +Instruction #146: + Timestep: 145 + Time: 2025-11-06 02:15:00+00:00 + ID: 68781f1f-73ae-4a8e-8a2f-d07ce7972187 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:15:00+00:00 +---------------------------------------- + +Instruction #147: + Timestep: 146 + Time: 2025-11-06 02:20:00+00:00 + ID: 324c6036-69de-4e32-9b44-35f214251b32 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:20:00+00:00 +---------------------------------------- + +Instruction #148: + Timestep: 147 + Time: 2025-11-06 02:25:00+00:00 + ID: 564dbf95-7d57-4674-959b-6df6c98bd6d2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:25:00+00:00 +---------------------------------------- + +Instruction #149: + Timestep: 148 + Time: 2025-11-06 02:30:00+00:00 + ID: 3c87fe4c-4810-4659-adb0-e436e72f98a0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:30:00+00:00 +---------------------------------------- + +Instruction #150: + Timestep: 149 + Time: 2025-11-06 02:35:00+00:00 + ID: d7505a1a-60d3-450a-b2a3-be598ce3ddbc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:35:00+00:00 +---------------------------------------- + +Instruction #151: + Timestep: 150 + Time: 2025-11-06 02:40:00+00:00 + ID: ecc38d26-5904-41bf-bd73-53547d66d84a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:40:00+00:00 +---------------------------------------- + +Instruction #152: + Timestep: 151 + Time: 2025-11-06 02:45:00+00:00 + ID: 99f1cb77-2654-4f5d-aa51-16ef38a8f893 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:45:00+00:00 +---------------------------------------- + +Instruction #153: + Timestep: 152 + Time: 2025-11-06 02:50:00+00:00 + ID: 1c6e279f-d6ca-4a29-9483-bbf9e346ae4f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:50:00+00:00 +---------------------------------------- + +Instruction #154: + Timestep: 153 + Time: 2025-11-06 02:55:00+00:00 + ID: 01265509-b920-4a4a-b047-a1208e968535 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 02:55:00+00:00 +---------------------------------------- + +Instruction #155: + Timestep: 154 + Time: 2025-11-06 03:00:00+00:00 + ID: eb8d9bc8-b3ec-48c6-a69d-d7a2288b978f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:00:00+00:00 +---------------------------------------- + +Instruction #156: + Timestep: 155 + Time: 2025-11-06 03:05:00+00:00 + ID: 4aa8c290-77bf-4540-b462-ee59e69bf0ed + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:05:00+00:00 +---------------------------------------- + +Instruction #157: + Timestep: 156 + Time: 2025-11-06 03:10:00+00:00 + ID: 4c4bf144-ca55-48ef-b719-03f7d04e94a9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:10:00+00:00 +---------------------------------------- + +Instruction #158: + Timestep: 157 + Time: 2025-11-06 03:15:00+00:00 + ID: 1ecca388-821c-4a70-af43-d3b3ed546ad7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:15:00+00:00 +---------------------------------------- + +Instruction #159: + Timestep: 158 + Time: 2025-11-06 03:20:00+00:00 + ID: 51230534-a7ed-4fae-b294-4a45aece98aa + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:20:00+00:00 +---------------------------------------- + +Instruction #160: + Timestep: 159 + Time: 2025-11-06 03:25:00+00:00 + ID: f1c82e0f-fcd1-4446-8e7c-8f6464f2d2f5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:25:00+00:00 +---------------------------------------- + +Instruction #161: + Timestep: 160 + Time: 2025-11-06 03:30:00+00:00 + ID: 1fa099c9-0124-4109-9e36-7321d7eda90c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:30:00+00:00 +---------------------------------------- + +Instruction #162: + Timestep: 161 + Time: 2025-11-06 03:35:00+00:00 + ID: 5e9f46ed-cdfa-4ef1-afa4-fe147bb7bb37 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:35:00+00:00 +---------------------------------------- + +Instruction #163: + Timestep: 162 + Time: 2025-11-06 03:40:00+00:00 + ID: 867348d0-e0b8-4d12-8c24-4d4447b308c1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:40:00+00:00 +---------------------------------------- + +Instruction #164: + Timestep: 163 + Time: 2025-11-06 03:45:00+00:00 + ID: c8e9e326-ad5b-4238-867a-ef6011a881be + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:45:00+00:00 +---------------------------------------- + +Instruction #165: + Timestep: 164 + Time: 2025-11-06 03:50:00+00:00 + ID: 0b6eb68d-1335-4e49-827f-d65f977e44f1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:50:00+00:00 +---------------------------------------- + +Instruction #166: + Timestep: 165 + Time: 2025-11-06 03:55:00+00:00 + ID: fc602029-b588-4f6b-a566-581f5d7850e2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 03:55:00+00:00 +---------------------------------------- + +Instruction #167: + Timestep: 166 + Time: 2025-11-06 04:00:00+00:00 + ID: 5348a8bd-4dd2-4d9f-8b27-575ad014b32e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:00:00+00:00 +---------------------------------------- + +Instruction #168: + Timestep: 167 + Time: 2025-11-06 04:05:00+00:00 + ID: 257a3cc5-ffd9-4138-bf13-4870ea134c75 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:05:00+00:00 +---------------------------------------- + +Instruction #169: + Timestep: 168 + Time: 2025-11-06 04:10:00+00:00 + ID: 8418ecec-46f9-49ab-98b1-91570ba32ebf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:10:00+00:00 +---------------------------------------- + +Instruction #170: + Timestep: 169 + Time: 2025-11-06 04:15:00+00:00 + ID: 5c1a055f-1767-455b-bbf0-88ebfb2dc659 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:15:00+00:00 +---------------------------------------- + +Instruction #171: + Timestep: 170 + Time: 2025-11-06 04:20:00+00:00 + ID: 7d9af51f-37b6-449c-8700-8516710604b9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:20:00+00:00 +---------------------------------------- + +Instruction #172: + Timestep: 171 + Time: 2025-11-06 04:25:00+00:00 + ID: c580bd49-3414-46b0-97bc-a5e3811a45af + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:25:00+00:00 +---------------------------------------- + +Instruction #173: + Timestep: 172 + Time: 2025-11-06 04:30:00+00:00 + ID: 5d6c99aa-c324-45fc-9dab-fafd50194509 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:30:00+00:00 +---------------------------------------- + +Instruction #174: + Timestep: 173 + Time: 2025-11-06 04:35:00+00:00 + ID: 369d8428-4c4b-4709-a89e-bf6e7161877c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:35:00+00:00 +---------------------------------------- + +Instruction #175: + Timestep: 174 + Time: 2025-11-06 04:40:00+00:00 + ID: dbac193a-6653-4996-bb2e-89acd5aee35a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:40:00+00:00 +---------------------------------------- + +Instruction #176: + Timestep: 175 + Time: 2025-11-06 04:45:00+00:00 + ID: f677e734-c2b1-47f9-afb5-11c116897b7f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:45:00+00:00 +---------------------------------------- + +Instruction #177: + Timestep: 176 + Time: 2025-11-06 04:50:00+00:00 + ID: c0239d1f-6520-486f-9928-82bcc6034b42 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:50:00+00:00 +---------------------------------------- + +Instruction #178: + Timestep: 177 + Time: 2025-11-06 04:55:00+00:00 + ID: 07b9b89f-d30a-48f2-813e-f0eb5dd2a99b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 04:55:00+00:00 +---------------------------------------- + +Instruction #179: + Timestep: 178 + Time: 2025-11-06 05:00:00+00:00 + ID: 16a0e7de-62df-473e-818e-71552ab206bd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:00:00+00:00 +---------------------------------------- + +Instruction #180: + Timestep: 179 + Time: 2025-11-06 05:05:00+00:00 + ID: d531138a-7a2c-4807-8504-dd07a9705a72 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:05:00+00:00 +---------------------------------------- + +Instruction #181: + Timestep: 180 + Time: 2025-11-06 05:10:00+00:00 + ID: ac0ca978-23dc-4f70-b3d4-9a503c94166a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:10:00+00:00 +---------------------------------------- + +Instruction #182: + Timestep: 181 + Time: 2025-11-06 05:15:00+00:00 + ID: f6bbb161-98ab-4717-83ad-d8546d245ba4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:15:00+00:00 +---------------------------------------- + +Instruction #183: + Timestep: 182 + Time: 2025-11-06 05:20:00+00:00 + ID: a48373b7-168b-413b-82f8-5d94c765d10f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:20:00+00:00 +---------------------------------------- + +Instruction #184: + Timestep: 183 + Time: 2025-11-06 05:25:00+00:00 + ID: 617de272-3555-4534-b3c6-acef2c47bb26 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:25:00+00:00 +---------------------------------------- + +Instruction #185: + Timestep: 184 + Time: 2025-11-06 05:30:00+00:00 + ID: fb5f57a2-00ea-4ffb-8028-f0f4bd5b2aee + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:30:00+00:00 +---------------------------------------- + +Instruction #186: + Timestep: 185 + Time: 2025-11-06 05:35:00+00:00 + ID: df12081f-e373-44e1-a172-55d4e136b2e7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:35:00+00:00 +---------------------------------------- + +Instruction #187: + Timestep: 186 + Time: 2025-11-06 05:40:00+00:00 + ID: 1f652783-fa41-4b42-965f-2674d8eef106 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:40:00+00:00 +---------------------------------------- + +Instruction #188: + Timestep: 187 + Time: 2025-11-06 05:45:00+00:00 + ID: ab7391df-3d94-44d1-b518-14048a742351 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:45:00+00:00 +---------------------------------------- + +Instruction #189: + Timestep: 188 + Time: 2025-11-06 05:50:00+00:00 + ID: c9bacd21-278d-45dc-ac54-78a462333f80 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:50:00+00:00 +---------------------------------------- + +Instruction #190: + Timestep: 189 + Time: 2025-11-06 05:55:00+00:00 + ID: 76ad44e5-2686-4778-b615-712d2fb29670 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 05:55:00+00:00 +---------------------------------------- + +Instruction #191: + Timestep: 190 + Time: 2025-11-06 06:00:00+00:00 + ID: 91a05fd2-37cd-4f2d-81c8-65e04e2943a1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:00:00+00:00 +---------------------------------------- + +Instruction #192: + Timestep: 191 + Time: 2025-11-06 06:05:00+00:00 + ID: ccfae7c9-e73b-49cd-addf-e18e53293036 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:05:00+00:00 +---------------------------------------- + +Instruction #193: + Timestep: 192 + Time: 2025-11-06 06:10:00+00:00 + ID: 7b57d126-70ac-4088-bc18-3ff32dc9e5ac + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:10:00+00:00 +---------------------------------------- + +Instruction #194: + Timestep: 193 + Time: 2025-11-06 06:15:00+00:00 + ID: 16cbf763-18cf-402a-a844-628e14b027ca + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:15:00+00:00 +---------------------------------------- + +Instruction #195: + Timestep: 194 + Time: 2025-11-06 06:20:00+00:00 + ID: 33f8fe77-202e-49cd-b0d9-bf05f4e5a93d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:20:00+00:00 +---------------------------------------- + +Instruction #196: + Timestep: 195 + Time: 2025-11-06 06:25:00+00:00 + ID: bdfb055e-6a1e-45f1-8a0a-c1c41fc8d8c8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:25:00+00:00 +---------------------------------------- + +Instruction #197: + Timestep: 196 + Time: 2025-11-06 06:30:00+00:00 + ID: 36308266-a5e4-4fa4-8e1d-af917f8296c8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:30:00+00:00 +---------------------------------------- + +Instruction #198: + Timestep: 197 + Time: 2025-11-06 06:35:00+00:00 + ID: d94f7c4c-572e-4183-8329-a1a638ba3854 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:35:00+00:00 +---------------------------------------- + +Instruction #199: + Timestep: 198 + Time: 2025-11-06 06:40:00+00:00 + ID: 1378be99-5233-48fc-ba95-b90aa03db619 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:40:00+00:00 +---------------------------------------- + +Instruction #200: + Timestep: 199 + Time: 2025-11-06 06:45:00+00:00 + ID: 8a5bf51c-450e-4c49-ade3-421443f8f865 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:45:00+00:00 +---------------------------------------- + +Instruction #201: + Timestep: 200 + Time: 2025-11-06 06:50:00+00:00 + ID: b9d3665d-593f-4da9-be5e-c1ee86cf9713 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:50:00+00:00 +---------------------------------------- + +Instruction #202: + Timestep: 201 + Time: 2025-11-06 06:55:00+00:00 + ID: 7d2e0d74-70fc-4bf1-8a69-84c68eb41809 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 06:55:00+00:00 +---------------------------------------- + +Instruction #203: + Timestep: 202 + Time: 2025-11-06 07:00:00+00:00 + ID: 984bf498-c8e8-4631-a743-a22dc9679616 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:00:00+00:00 +---------------------------------------- + +Instruction #204: + Timestep: 203 + Time: 2025-11-06 07:05:00+00:00 + ID: 9095b838-1bf5-43b2-9ce1-7365142e9935 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:05:00+00:00 +---------------------------------------- + +Instruction #205: + Timestep: 204 + Time: 2025-11-06 07:10:00+00:00 + ID: 39357caf-91cb-471c-b776-c80a44e47a89 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:10:00+00:00 +---------------------------------------- + +Instruction #206: + Timestep: 205 + Time: 2025-11-06 07:15:00+00:00 + ID: c6deecbd-ee86-484b-afe9-8a38a6e72c10 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:15:00+00:00 +---------------------------------------- + +Instruction #207: + Timestep: 206 + Time: 2025-11-06 07:20:00+00:00 + ID: 58c8bfa8-cb4c-40dc-88fb-9dfaec98f7eb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:20:00+00:00 +---------------------------------------- + +Instruction #208: + Timestep: 207 + Time: 2025-11-06 07:25:00+00:00 + ID: e0d10bf7-7035-4abe-a729-ac4dd38ad031 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:25:00+00:00 +---------------------------------------- + +Instruction #209: + Timestep: 208 + Time: 2025-11-06 07:30:00+00:00 + ID: 3818fbf4-ba0b-4927-a07d-89a62eac2fbb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:30:00+00:00 +---------------------------------------- + +Instruction #210: + Timestep: 209 + Time: 2025-11-06 07:35:00+00:00 + ID: 649f00fa-8583-4631-be3d-2316780c9311 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:35:00+00:00 +---------------------------------------- + +Instruction #211: + Timestep: 210 + Time: 2025-11-06 07:40:00+00:00 + ID: 52b3a9e2-c96a-4e01-8030-dea7cbca29bd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:40:00+00:00 +---------------------------------------- + +Instruction #212: + Timestep: 211 + Time: 2025-11-06 07:45:00+00:00 + ID: c0849362-503e-4b01-9ad8-a02c9f336599 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:45:00+00:00 +---------------------------------------- + +Instruction #213: + Timestep: 212 + Time: 2025-11-06 07:50:00+00:00 + ID: b38fca6b-7460-46a7-b8f8-f9f241c9bafd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:50:00+00:00 +---------------------------------------- + +Instruction #214: + Timestep: 213 + Time: 2025-11-06 07:55:00+00:00 + ID: e3afcc3d-5e02-4a0d-8158-fb77c0ca509f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 07:55:00+00:00 +---------------------------------------- + +Instruction #215: + Timestep: 214 + Time: 2025-11-06 08:00:00+00:00 + ID: bfea6500-1470-41ef-9044-5e41a762b7fb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:00:00+00:00 +---------------------------------------- + +Instruction #216: + Timestep: 215 + Time: 2025-11-06 08:05:00+00:00 + ID: 05d7cccb-d4a6-4113-bd71-fb7943a467b7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:05:00+00:00 +---------------------------------------- + +Instruction #217: + Timestep: 216 + Time: 2025-11-06 08:10:00+00:00 + ID: d9bd37c8-94e5-46da-97a5-f521e0801aae + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:10:00+00:00 +---------------------------------------- + +Instruction #218: + Timestep: 217 + Time: 2025-11-06 08:15:00+00:00 + ID: a29900fd-740b-46bb-87a7-8ae1b05e5057 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:15:00+00:00 +---------------------------------------- + +Instruction #219: + Timestep: 218 + Time: 2025-11-06 08:20:00+00:00 + ID: 9341fa89-4798-490c-be37-31846f9e149b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:20:00+00:00 +---------------------------------------- + +Instruction #220: + Timestep: 219 + Time: 2025-11-06 08:25:00+00:00 + ID: 40ad3695-2aad-4947-8369-eab0c933f1b5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:25:00+00:00 +---------------------------------------- + +Instruction #221: + Timestep: 220 + Time: 2025-11-06 08:30:00+00:00 + ID: dd57595d-d860-44ef-adc6-b10a0aff7fe6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:30:00+00:00 +---------------------------------------- + +Instruction #222: + Timestep: 221 + Time: 2025-11-06 08:35:00+00:00 + ID: 7dee7c2f-6fc0-4098-b24b-cf6367b2be53 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:35:00+00:00 +---------------------------------------- + +Instruction #223: + Timestep: 222 + Time: 2025-11-06 08:40:00+00:00 + ID: d0db5447-7585-43da-9a7a-b6bcc6307960 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:40:00+00:00 +---------------------------------------- + +Instruction #224: + Timestep: 223 + Time: 2025-11-06 08:45:00+00:00 + ID: 5c832413-0dfa-4ef9-934b-eea951b7fe93 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:45:00+00:00 +---------------------------------------- + +Instruction #225: + Timestep: 224 + Time: 2025-11-06 08:50:00+00:00 + ID: 3a4cdf54-5584-47b3-b2af-4179167a5596 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:50:00+00:00 +---------------------------------------- + +Instruction #226: + Timestep: 225 + Time: 2025-11-06 08:55:00+00:00 + ID: 67c8f614-c930-4c31-a59e-fc488a0afb93 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 08:55:00+00:00 +---------------------------------------- + +Instruction #227: + Timestep: 226 + Time: 2025-11-06 09:00:00+00:00 + ID: 5004bad1-8a64-49a2-8b8e-51a1199fcb82 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:00:00+00:00 +---------------------------------------- + +Instruction #228: + Timestep: 227 + Time: 2025-11-06 09:05:00+00:00 + ID: bf584a0d-6d86-43b3-9302-50ab5f558d57 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:05:00+00:00 +---------------------------------------- + +Instruction #229: + Timestep: 228 + Time: 2025-11-06 09:10:00+00:00 + ID: 943a3e62-e1e5-4a06-9b3c-da7b533fc7b2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:10:00+00:00 +---------------------------------------- + +Instruction #230: + Timestep: 229 + Time: 2025-11-06 09:15:00+00:00 + ID: 1a8b6ed6-bb39-4e3c-9266-b645a3b608ba + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:15:00+00:00 +---------------------------------------- + +Instruction #231: + Timestep: 230 + Time: 2025-11-06 09:20:00+00:00 + ID: 1a6256da-3344-434c-bdb8-2364f0c4bfd1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:20:00+00:00 +---------------------------------------- + +Instruction #232: + Timestep: 231 + Time: 2025-11-06 09:25:00+00:00 + ID: 75ca5c13-4f8f-41b7-b0d1-671ab2c14045 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:25:00+00:00 +---------------------------------------- + +Instruction #233: + Timestep: 232 + Time: 2025-11-06 09:30:00+00:00 + ID: 7bd3f610-7aeb-4a81-b1d3-098f68cc94e3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:30:00+00:00 +---------------------------------------- + +Instruction #234: + Timestep: 233 + Time: 2025-11-06 09:35:00+00:00 + ID: 3886258a-3e9c-405f-98ca-b464faf02482 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:35:00+00:00 +---------------------------------------- + +Instruction #235: + Timestep: 234 + Time: 2025-11-06 09:40:00+00:00 + ID: fb48ab2e-748d-4a03-acf5-b045845a0b93 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:40:00+00:00 +---------------------------------------- + +Instruction #236: + Timestep: 235 + Time: 2025-11-06 09:45:00+00:00 + ID: 61b9a444-2c4c-4422-99b6-843768eb4673 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:45:00+00:00 +---------------------------------------- + +Instruction #237: + Timestep: 236 + Time: 2025-11-06 09:50:00+00:00 + ID: fffc1575-9c67-4e7b-810a-15d0b0239b63 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:50:00+00:00 +---------------------------------------- + +Instruction #238: + Timestep: 237 + Time: 2025-11-06 09:55:00+00:00 + ID: 71ef5036-08de-4283-80d8-446a2770f82b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 09:55:00+00:00 +---------------------------------------- + +Instruction #239: + Timestep: 238 + Time: 2025-11-06 10:00:00+00:00 + ID: c8ff4eca-7337-49fe-bbdf-2ff36cce9021 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:00:00+00:00 +---------------------------------------- + +Instruction #240: + Timestep: 239 + Time: 2025-11-06 10:05:00+00:00 + ID: 6537b669-7c97-43a2-b721-fb5d35c6928c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:05:00+00:00 +---------------------------------------- + +Instruction #241: + Timestep: 240 + Time: 2025-11-06 10:10:00+00:00 + ID: ce4fafa5-ecdb-4d9a-b790-c9374635b62e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:10:00+00:00 +---------------------------------------- + +Instruction #242: + Timestep: 241 + Time: 2025-11-06 10:15:00+00:00 + ID: 5517ce79-66de-4dc8-a99a-a29ddd0951e9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:15:00+00:00 +---------------------------------------- + +Instruction #243: + Timestep: 242 + Time: 2025-11-06 10:20:00+00:00 + ID: adc1e21e-d73d-480a-a0cc-2b63ba467c4e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:20:00+00:00 +---------------------------------------- + +Instruction #244: + Timestep: 243 + Time: 2025-11-06 10:25:00+00:00 + ID: 2076d7a3-5a00-4fbc-909d-eabba7335530 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:25:00+00:00 +---------------------------------------- + +Instruction #245: + Timestep: 244 + Time: 2025-11-06 10:30:00+00:00 + ID: a6417141-3e92-46c6-8aa3-fc3d7f83c1a1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:30:00+00:00 +---------------------------------------- + +Instruction #246: + Timestep: 245 + Time: 2025-11-06 10:35:00+00:00 + ID: d23b12f2-9600-40d6-ba24-698dfe0c4507 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:35:00+00:00 +---------------------------------------- + +Instruction #247: + Timestep: 246 + Time: 2025-11-06 10:40:00+00:00 + ID: 8787d207-75a3-4808-a5c5-1ab6f64156ef + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:40:00+00:00 +---------------------------------------- + +Instruction #248: + Timestep: 247 + Time: 2025-11-06 10:45:00+00:00 + ID: ff0d7a4d-b44a-44d7-b826-87d10b6ee8f5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:45:00+00:00 +---------------------------------------- + +Instruction #249: + Timestep: 248 + Time: 2025-11-06 10:50:00+00:00 + ID: 723e1ab3-72b1-45d2-a209-7dc58b3957b3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:50:00+00:00 +---------------------------------------- + +Instruction #250: + Timestep: 249 + Time: 2025-11-06 10:55:00+00:00 + ID: 67d70eb2-e77b-40ce-9136-975545373dae + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 10:55:00+00:00 +---------------------------------------- + +Instruction #251: + Timestep: 250 + Time: 2025-11-06 11:00:00+00:00 + ID: 0a67383a-9d7f-4007-869f-3128873dc484 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:00:00+00:00 +---------------------------------------- + +Instruction #252: + Timestep: 251 + Time: 2025-11-06 11:05:00+00:00 + ID: 9a3beea4-43a2-4d6d-ac97-d8c42cac73d1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:05:00+00:00 +---------------------------------------- + +Instruction #253: + Timestep: 252 + Time: 2025-11-06 11:10:00+00:00 + ID: 40859fc5-07e9-4ac3-80f0-513f35bc1b8d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:10:00+00:00 +---------------------------------------- + +Instruction #254: + Timestep: 253 + Time: 2025-11-06 11:15:00+00:00 + ID: f31a5ba0-8601-443c-8abe-17b113d055bc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:15:00+00:00 +---------------------------------------- + +Instruction #255: + Timestep: 254 + Time: 2025-11-06 11:20:00+00:00 + ID: f479043d-1a0b-4769-9c67-8a585e4445d6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:20:00+00:00 +---------------------------------------- + +Instruction #256: + Timestep: 255 + Time: 2025-11-06 11:25:00+00:00 + ID: 96d996df-fb76-4e78-a211-6871a7520530 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:25:00+00:00 +---------------------------------------- + +Instruction #257: + Timestep: 256 + Time: 2025-11-06 11:30:00+00:00 + ID: 71c5cf45-5b9c-4d27-aaf0-914b3e4c66cd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:30:00+00:00 +---------------------------------------- + +Instruction #258: + Timestep: 257 + Time: 2025-11-06 11:35:00+00:00 + ID: e36688b2-94f3-41f0-a213-199dfb0d3014 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:35:00+00:00 +---------------------------------------- + +Instruction #259: + Timestep: 258 + Time: 2025-11-06 11:40:00+00:00 + ID: 8bfab8d2-32d6-4724-be46-57e7cef0ddb6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:40:00+00:00 +---------------------------------------- + +Instruction #260: + Timestep: 259 + Time: 2025-11-06 11:45:00+00:00 + ID: 88de47e9-aa5c-4d2f-af95-8b266bd7578c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:45:00+00:00 +---------------------------------------- + +Instruction #261: + Timestep: 260 + Time: 2025-11-06 11:50:00+00:00 + ID: fba6b767-8f80-4f14-ba52-9e64affa96b7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:50:00+00:00 +---------------------------------------- + +Instruction #262: + Timestep: 261 + Time: 2025-11-06 11:55:00+00:00 + ID: 5eac828e-9d59-410f-bc42-cf7601fffb67 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 11:55:00+00:00 +---------------------------------------- + +Instruction #263: + Timestep: 262 + Time: 2025-11-06 12:00:00+00:00 + ID: 87270fb2-7a59-4089-bc03-6f3f7e649d15 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:00:00+00:00 +---------------------------------------- + +Instruction #264: + Timestep: 263 + Time: 2025-11-06 12:05:00+00:00 + ID: ed3f690a-39ce-4d8b-a203-14a242c0d54d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:05:00+00:00 +---------------------------------------- + +Instruction #265: + Timestep: 264 + Time: 2025-11-06 12:10:00+00:00 + ID: 775b15cf-e945-4c3d-9664-75cedc515825 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:10:00+00:00 +---------------------------------------- + +Instruction #266: + Timestep: 265 + Time: 2025-11-06 12:15:00+00:00 + ID: 1ba0db26-b5ac-4233-9892-0a183c07ed60 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:15:00+00:00 +---------------------------------------- + +Instruction #267: + Timestep: 266 + Time: 2025-11-06 12:20:00+00:00 + ID: 5150a558-1d0b-4eec-80e6-b01d9c96c59f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:20:00+00:00 +---------------------------------------- + +Instruction #268: + Timestep: 267 + Time: 2025-11-06 12:25:00+00:00 + ID: 00487922-a65f-4c67-9657-a69459d19eb7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:25:00+00:00 +---------------------------------------- + +Instruction #269: + Timestep: 268 + Time: 2025-11-06 12:30:00+00:00 + ID: 53b11f96-f09d-4304-903d-67de39e6d260 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:30:00+00:00 +---------------------------------------- + +Instruction #270: + Timestep: 269 + Time: 2025-11-06 12:35:00+00:00 + ID: a9f5dcc8-1c19-46bf-8a84-9b050e07b560 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:35:00+00:00 +---------------------------------------- + +Instruction #271: + Timestep: 270 + Time: 2025-11-06 12:40:00+00:00 + ID: 7c7cc8d4-7534-423f-b06f-9e4cd7d78fdb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:40:00+00:00 +---------------------------------------- + +Instruction #272: + Timestep: 271 + Time: 2025-11-06 12:45:00+00:00 + ID: 580b8807-2df6-4ebd-9335-f84b61c0f1da + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:45:00+00:00 +---------------------------------------- + +Instruction #273: + Timestep: 272 + Time: 2025-11-06 12:50:00+00:00 + ID: b54b3759-d6a6-43cc-942a-e44a277d74f4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:50:00+00:00 +---------------------------------------- + +Instruction #274: + Timestep: 273 + Time: 2025-11-06 12:55:00+00:00 + ID: d9150ee8-9d33-47ab-9a6d-42066263c1da + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 12:55:00+00:00 +---------------------------------------- + +Instruction #275: + Timestep: 274 + Time: 2025-11-06 13:00:00+00:00 + ID: 9266f5e2-537d-4f55-9eca-109e4067b6e7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:00:00+00:00 +---------------------------------------- + +Instruction #276: + Timestep: 275 + Time: 2025-11-06 13:05:00+00:00 + ID: ad93e9b7-f793-4207-8633-8ddd1225d61b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:05:00+00:00 +---------------------------------------- + +Instruction #277: + Timestep: 276 + Time: 2025-11-06 13:10:00+00:00 + ID: c10943db-17d6-4f77-b6fe-a072f7098554 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:10:00+00:00 +---------------------------------------- + +Instruction #278: + Timestep: 277 + Time: 2025-11-06 13:15:00+00:00 + ID: 2b45be86-a0d4-4a8a-ab8f-848c304d220b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:15:00+00:00 +---------------------------------------- + +Instruction #279: + Timestep: 278 + Time: 2025-11-06 13:20:00+00:00 + ID: ca4bd560-3319-4c84-b411-ee0137634b69 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:20:00+00:00 +---------------------------------------- + +Instruction #280: + Timestep: 279 + Time: 2025-11-06 13:25:00+00:00 + ID: e5d0e58e-30ba-4e71-b969-10d0e9ed84f5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:25:00+00:00 +---------------------------------------- + +Instruction #281: + Timestep: 280 + Time: 2025-11-06 13:30:00+00:00 + ID: 83e18688-a642-4d8f-8914-7f1cb2212092 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:30:00+00:00 +---------------------------------------- + +Instruction #282: + Timestep: 281 + Time: 2025-11-06 13:35:00+00:00 + ID: 36b577a5-0971-4dc2-a3be-e364b305ae86 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:35:00+00:00 +---------------------------------------- + +Instruction #283: + Timestep: 282 + Time: 2025-11-06 13:40:00+00:00 + ID: a8bdf3b8-0ba8-450f-ac9d-54c7c0bfa2ae + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:40:00+00:00 +---------------------------------------- + +Instruction #284: + Timestep: 283 + Time: 2025-11-06 13:45:00+00:00 + ID: 2cdcdf7f-4428-45ef-b021-f336768d6a76 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:45:00+00:00 +---------------------------------------- + +Instruction #285: + Timestep: 284 + Time: 2025-11-06 13:50:00+00:00 + ID: 86f52287-9782-4e2d-a86e-a4a8b501c844 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:50:00+00:00 +---------------------------------------- + +Instruction #286: + Timestep: 285 + Time: 2025-11-06 13:55:00+00:00 + ID: a725b018-5dce-4fdd-a476-53f583a5f0db + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 13:55:00+00:00 +---------------------------------------- + +Instruction #287: + Timestep: 286 + Time: 2025-11-06 14:00:00+00:00 + ID: af427759-40ae-4e32-9acc-caead28d50fc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 14:00:00+00:00 +---------------------------------------- + +Instruction #288: + Timestep: 287 + Time: 2025-11-06 14:05:00+00:00 + ID: 0f5d6517-b80f-4616-89f1-4b54086c1dab + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-06 14:05:00+00:00 +---------------------------------------- diff --git a/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_energy_D=1_B=200_S=30_T=288.txt b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_energy_D=1_B=200_S=30_T=288.txt new file mode 100644 index 0000000..2043c5b --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_energy_D=1_B=200_S=30_T=288.txt @@ -0,0 +1,3218 @@ +================================================================================ +ITHO DHW Heat Pump Instructions Energy +================================================================================ +Planning start time: 2025-11-03 10:30:00+00:00 +Planning window: 1 days 00:00:00 +Resolution: 0 days 00:05:00 +Total timesteps: 288 +================================================================================ + +Device: itho_dhw_device_001 +Number of instructions: 288 +-------------------------------------------------------------------------------- + +Instruction Timeline: +-------------------------------------------------------------------------------- + Mode: DHW_ON + Start: 2025-11-03 10:30:00+00:00 (timestep 0) + Duration: 17 timesteps (85.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-03 11:55:00+00:00 (timestep 17) + Duration: 8 timesteps (40.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-03 12:35:00+00:00 (timestep 25) + Duration: 6 timesteps (30.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-03 13:05:00+00:00 (timestep 31) + Duration: 131 timesteps (655.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-04 00:00:00+00:00 (timestep 162) + Duration: 72 timesteps (360.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-04 06:00:00+00:00 (timestep 234) + Duration: 54 timesteps (270.0 minutes) +---------------------------------------- + +Total operation mode changes: 5 +================================================================================ + +Detailed Instruction List: +================================================================================ + +Instruction #1: + Timestep: 0 + Time: 2025-11-03 10:30:00+00:00 + ID: 7400f900-b57a-4b2e-9b65-317490543af5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:30:00+00:00 +---------------------------------------- + +Instruction #2: + Timestep: 1 + Time: 2025-11-03 10:35:00+00:00 + ID: 952cb0f9-ceb8-4cd1-bfdd-227c889eb324 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:35:00+00:00 +---------------------------------------- + +Instruction #3: + Timestep: 2 + Time: 2025-11-03 10:40:00+00:00 + ID: e4e8d856-006e-4687-aca0-c1322950ced9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:40:00+00:00 +---------------------------------------- + +Instruction #4: + Timestep: 3 + Time: 2025-11-03 10:45:00+00:00 + ID: e2d19ae2-6029-41fd-8f6d-b43b41dd334d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:45:00+00:00 +---------------------------------------- + +Instruction #5: + Timestep: 4 + Time: 2025-11-03 10:50:00+00:00 + ID: 6b6a92b8-3b84-43a2-8cd7-8f0d06323244 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:50:00+00:00 +---------------------------------------- + +Instruction #6: + Timestep: 5 + Time: 2025-11-03 10:55:00+00:00 + ID: 7258f35d-8185-4551-b140-cef4a665b8ed + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 10:55:00+00:00 +---------------------------------------- + +Instruction #7: + Timestep: 6 + Time: 2025-11-03 11:00:00+00:00 + ID: fa8ff845-3c14-4b1f-a327-c56c15660801 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:00:00+00:00 +---------------------------------------- + +Instruction #8: + Timestep: 7 + Time: 2025-11-03 11:05:00+00:00 + ID: a14edb23-72c4-436a-bfc2-1e9f47b01fab + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:05:00+00:00 +---------------------------------------- + +Instruction #9: + Timestep: 8 + Time: 2025-11-03 11:10:00+00:00 + ID: 16d68d00-1d0a-47a4-9c3f-b218b1d1d35a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:10:00+00:00 +---------------------------------------- + +Instruction #10: + Timestep: 9 + Time: 2025-11-03 11:15:00+00:00 + ID: fe0f6882-9ea0-4b84-9e65-af34bd9336ef + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:15:00+00:00 +---------------------------------------- + +Instruction #11: + Timestep: 10 + Time: 2025-11-03 11:20:00+00:00 + ID: 2e7ece7c-41e3-4940-8946-ae80566aff0a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:20:00+00:00 +---------------------------------------- + +Instruction #12: + Timestep: 11 + Time: 2025-11-03 11:25:00+00:00 + ID: 8ea5bb8b-e826-4376-b227-358230ed3a08 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:25:00+00:00 +---------------------------------------- + +Instruction #13: + Timestep: 12 + Time: 2025-11-03 11:30:00+00:00 + ID: ededad99-009f-4a76-ae93-9e2d1c7d2bd7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:30:00+00:00 +---------------------------------------- + +Instruction #14: + Timestep: 13 + Time: 2025-11-03 11:35:00+00:00 + ID: c8afa93f-6083-4076-91d0-0c40f57eb5d5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:35:00+00:00 +---------------------------------------- + +Instruction #15: + Timestep: 14 + Time: 2025-11-03 11:40:00+00:00 + ID: 1cc470ad-5ae4-47a5-bcf3-8228b3cbd656 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:40:00+00:00 +---------------------------------------- + +Instruction #16: + Timestep: 15 + Time: 2025-11-03 11:45:00+00:00 + ID: b0afd846-3afc-41e3-80b1-7fd469c6e10d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:45:00+00:00 +---------------------------------------- + +Instruction #17: + Timestep: 16 + Time: 2025-11-03 11:50:00+00:00 + ID: df035f0c-d462-4ced-ab12-4d56f46c454e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:50:00+00:00 +---------------------------------------- + +Instruction #18: + Timestep: 17 + Time: 2025-11-03 11:55:00+00:00 + ID: 243c7c3e-0897-4183-99e8-f3fc3889f51c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 11:55:00+00:00 +---------------------------------------- + +Instruction #19: + Timestep: 18 + Time: 2025-11-03 12:00:00+00:00 + ID: 81e14785-c224-46da-b33f-7eb6b83c24e8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:00:00+00:00 +---------------------------------------- + +Instruction #20: + Timestep: 19 + Time: 2025-11-03 12:05:00+00:00 + ID: c1e45c82-8663-4d96-845a-db966663f0c5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:05:00+00:00 +---------------------------------------- + +Instruction #21: + Timestep: 20 + Time: 2025-11-03 12:10:00+00:00 + ID: 1c2d6ccc-b26c-4d7d-a31f-42ad88a829c3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:10:00+00:00 +---------------------------------------- + +Instruction #22: + Timestep: 21 + Time: 2025-11-03 12:15:00+00:00 + ID: 3b378056-13e6-4ab2-93c0-fdb9b322fd5b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:15:00+00:00 +---------------------------------------- + +Instruction #23: + Timestep: 22 + Time: 2025-11-03 12:20:00+00:00 + ID: b67b4bb2-5e0a-4801-9a83-87a4fe171deb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:20:00+00:00 +---------------------------------------- + +Instruction #24: + Timestep: 23 + Time: 2025-11-03 12:25:00+00:00 + ID: 321cc200-59bf-488a-82ff-b4e3d73ee375 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:25:00+00:00 +---------------------------------------- + +Instruction #25: + Timestep: 24 + Time: 2025-11-03 12:30:00+00:00 + ID: b77b1d38-b116-4810-aad8-da1e8d61cd89 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:30:00+00:00 +---------------------------------------- + +Instruction #26: + Timestep: 25 + Time: 2025-11-03 12:35:00+00:00 + ID: 4ee267d9-65ee-4197-bc3f-8378e3110f60 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:35:00+00:00 +---------------------------------------- + +Instruction #27: + Timestep: 26 + Time: 2025-11-03 12:40:00+00:00 + ID: 72e3a38f-5c15-491e-b7fa-972b15652a65 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:40:00+00:00 +---------------------------------------- + +Instruction #28: + Timestep: 27 + Time: 2025-11-03 12:45:00+00:00 + ID: 68da5b2e-ef90-49b0-9193-f1377da3ca3f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:45:00+00:00 +---------------------------------------- + +Instruction #29: + Timestep: 28 + Time: 2025-11-03 12:50:00+00:00 + ID: 5cc1953d-be4a-4492-a003-c47ecbf92df6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:50:00+00:00 +---------------------------------------- + +Instruction #30: + Timestep: 29 + Time: 2025-11-03 12:55:00+00:00 + ID: 79265bac-e7d9-4407-964a-3f62d36615d3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 12:55:00+00:00 +---------------------------------------- + +Instruction #31: + Timestep: 30 + Time: 2025-11-03 13:00:00+00:00 + ID: a65510a4-7ce6-480a-b55a-66c93d36b075 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:00:00+00:00 +---------------------------------------- + +Instruction #32: + Timestep: 31 + Time: 2025-11-03 13:05:00+00:00 + ID: 6b3e62b2-18df-4c4e-8b51-eade9e67e796 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:05:00+00:00 +---------------------------------------- + +Instruction #33: + Timestep: 32 + Time: 2025-11-03 13:10:00+00:00 + ID: 3684e158-ee43-4390-b3d3-213f81625eca + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:10:00+00:00 +---------------------------------------- + +Instruction #34: + Timestep: 33 + Time: 2025-11-03 13:15:00+00:00 + ID: 82f975bf-60e1-4cde-817c-4eae4fc54cd3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:15:00+00:00 +---------------------------------------- + +Instruction #35: + Timestep: 34 + Time: 2025-11-03 13:20:00+00:00 + ID: 535e3392-8ffb-4951-852e-6fd936b3c0fe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:20:00+00:00 +---------------------------------------- + +Instruction #36: + Timestep: 35 + Time: 2025-11-03 13:25:00+00:00 + ID: 304cd113-59b9-488f-9c8b-ed95481a1415 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:25:00+00:00 +---------------------------------------- + +Instruction #37: + Timestep: 36 + Time: 2025-11-03 13:30:00+00:00 + ID: b2796a84-55fa-47ab-82ab-fcde395abb01 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:30:00+00:00 +---------------------------------------- + +Instruction #38: + Timestep: 37 + Time: 2025-11-03 13:35:00+00:00 + ID: cf6ea147-47dc-40c4-b87d-c41c3ac46dae + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:35:00+00:00 +---------------------------------------- + +Instruction #39: + Timestep: 38 + Time: 2025-11-03 13:40:00+00:00 + ID: 839999f7-ee86-49f1-802f-ff09ff1559ee + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:40:00+00:00 +---------------------------------------- + +Instruction #40: + Timestep: 39 + Time: 2025-11-03 13:45:00+00:00 + ID: 2d16fe32-f0a3-426f-8484-e5449b05a3f6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:45:00+00:00 +---------------------------------------- + +Instruction #41: + Timestep: 40 + Time: 2025-11-03 13:50:00+00:00 + ID: 98385695-1ba6-46d5-9dc5-98181c15a3e3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:50:00+00:00 +---------------------------------------- + +Instruction #42: + Timestep: 41 + Time: 2025-11-03 13:55:00+00:00 + ID: dea4710e-854a-4ca8-b7d7-3bd9d643cbce + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 13:55:00+00:00 +---------------------------------------- + +Instruction #43: + Timestep: 42 + Time: 2025-11-03 14:00:00+00:00 + ID: 9faf4b3a-3721-46da-98b6-903beb61f2da + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:00:00+00:00 +---------------------------------------- + +Instruction #44: + Timestep: 43 + Time: 2025-11-03 14:05:00+00:00 + ID: 5da54143-e84f-4b54-ac9b-fb199d6e28fc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:05:00+00:00 +---------------------------------------- + +Instruction #45: + Timestep: 44 + Time: 2025-11-03 14:10:00+00:00 + ID: 5034652f-4188-4fae-b296-d470fb4a9d2a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:10:00+00:00 +---------------------------------------- + +Instruction #46: + Timestep: 45 + Time: 2025-11-03 14:15:00+00:00 + ID: 779fe68e-af66-4224-883c-d30be4169d72 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:15:00+00:00 +---------------------------------------- + +Instruction #47: + Timestep: 46 + Time: 2025-11-03 14:20:00+00:00 + ID: a26977e6-c088-406e-b2d2-be7879e854ed + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:20:00+00:00 +---------------------------------------- + +Instruction #48: + Timestep: 47 + Time: 2025-11-03 14:25:00+00:00 + ID: 56d79c4c-9e79-459b-bd5e-4ca9c577ea9a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:25:00+00:00 +---------------------------------------- + +Instruction #49: + Timestep: 48 + Time: 2025-11-03 14:30:00+00:00 + ID: 7c4bf6f5-f4b1-4174-9f74-77373121c5c6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:30:00+00:00 +---------------------------------------- + +Instruction #50: + Timestep: 49 + Time: 2025-11-03 14:35:00+00:00 + ID: 681911da-ae32-4318-a16d-2a802946a44a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:35:00+00:00 +---------------------------------------- + +Instruction #51: + Timestep: 50 + Time: 2025-11-03 14:40:00+00:00 + ID: f178340a-a540-4b4a-9c4d-7f709f6a837a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:40:00+00:00 +---------------------------------------- + +Instruction #52: + Timestep: 51 + Time: 2025-11-03 14:45:00+00:00 + ID: 59664dd5-792c-4876-9262-9dd9f03a1edf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:45:00+00:00 +---------------------------------------- + +Instruction #53: + Timestep: 52 + Time: 2025-11-03 14:50:00+00:00 + ID: 42e58335-384a-41de-8fba-995569a7ea0c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:50:00+00:00 +---------------------------------------- + +Instruction #54: + Timestep: 53 + Time: 2025-11-03 14:55:00+00:00 + ID: 819c34c4-df42-4888-867a-2c6f76367943 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 14:55:00+00:00 +---------------------------------------- + +Instruction #55: + Timestep: 54 + Time: 2025-11-03 15:00:00+00:00 + ID: 629dca3f-d7b3-4024-8aeb-95dec8b3e359 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:00:00+00:00 +---------------------------------------- + +Instruction #56: + Timestep: 55 + Time: 2025-11-03 15:05:00+00:00 + ID: 87c47d29-3c88-433d-93fb-de16715defc3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:05:00+00:00 +---------------------------------------- + +Instruction #57: + Timestep: 56 + Time: 2025-11-03 15:10:00+00:00 + ID: 49826e33-969b-4d86-ba20-848c5e7e486c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:10:00+00:00 +---------------------------------------- + +Instruction #58: + Timestep: 57 + Time: 2025-11-03 15:15:00+00:00 + ID: ddff1350-f8ea-4322-89fc-4a06f5dcc5b3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:15:00+00:00 +---------------------------------------- + +Instruction #59: + Timestep: 58 + Time: 2025-11-03 15:20:00+00:00 + ID: f9aecb24-08f6-4354-afa5-5955b0cad052 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:20:00+00:00 +---------------------------------------- + +Instruction #60: + Timestep: 59 + Time: 2025-11-03 15:25:00+00:00 + ID: f198c285-b014-4cc9-a005-2ec0b20f855d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:25:00+00:00 +---------------------------------------- + +Instruction #61: + Timestep: 60 + Time: 2025-11-03 15:30:00+00:00 + ID: 06398626-ee5c-43fe-b53d-2b144b58f395 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:30:00+00:00 +---------------------------------------- + +Instruction #62: + Timestep: 61 + Time: 2025-11-03 15:35:00+00:00 + ID: 920abba6-48f5-42d8-b75f-7f1569ea2424 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:35:00+00:00 +---------------------------------------- + +Instruction #63: + Timestep: 62 + Time: 2025-11-03 15:40:00+00:00 + ID: 88c2227b-dfc1-411c-b9ea-1e3e72c61471 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:40:00+00:00 +---------------------------------------- + +Instruction #64: + Timestep: 63 + Time: 2025-11-03 15:45:00+00:00 + ID: 0e83acb9-75ff-4683-9c9e-8bf98dbf9d6e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:45:00+00:00 +---------------------------------------- + +Instruction #65: + Timestep: 64 + Time: 2025-11-03 15:50:00+00:00 + ID: 9003d4dc-b9da-4a47-b426-fb58f5f12dc4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:50:00+00:00 +---------------------------------------- + +Instruction #66: + Timestep: 65 + Time: 2025-11-03 15:55:00+00:00 + ID: d7ffcb24-73b0-4324-8a64-15104cf19f7a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 15:55:00+00:00 +---------------------------------------- + +Instruction #67: + Timestep: 66 + Time: 2025-11-03 16:00:00+00:00 + ID: dfe73b88-68dd-4614-9971-b41ac055f172 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:00:00+00:00 +---------------------------------------- + +Instruction #68: + Timestep: 67 + Time: 2025-11-03 16:05:00+00:00 + ID: e170163b-6931-4be7-a176-dcbca70ad1cf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:05:00+00:00 +---------------------------------------- + +Instruction #69: + Timestep: 68 + Time: 2025-11-03 16:10:00+00:00 + ID: 074ce0d1-dd61-48ce-9239-a81aaef88000 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:10:00+00:00 +---------------------------------------- + +Instruction #70: + Timestep: 69 + Time: 2025-11-03 16:15:00+00:00 + ID: fa1834a5-ba7c-4ffa-82fd-d99769d98787 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:15:00+00:00 +---------------------------------------- + +Instruction #71: + Timestep: 70 + Time: 2025-11-03 16:20:00+00:00 + ID: 5017cc8e-9b53-4b4a-a940-5598f676fc85 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:20:00+00:00 +---------------------------------------- + +Instruction #72: + Timestep: 71 + Time: 2025-11-03 16:25:00+00:00 + ID: 1f313835-83d0-4729-922a-381f285ab3fa + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:25:00+00:00 +---------------------------------------- + +Instruction #73: + Timestep: 72 + Time: 2025-11-03 16:30:00+00:00 + ID: 97a0014e-badb-41d3-9f99-84890d578e35 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:30:00+00:00 +---------------------------------------- + +Instruction #74: + Timestep: 73 + Time: 2025-11-03 16:35:00+00:00 + ID: 98e69c11-b876-4619-b417-ff97bbb11973 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:35:00+00:00 +---------------------------------------- + +Instruction #75: + Timestep: 74 + Time: 2025-11-03 16:40:00+00:00 + ID: 89647b11-a5f7-4574-b560-a18832d657bd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:40:00+00:00 +---------------------------------------- + +Instruction #76: + Timestep: 75 + Time: 2025-11-03 16:45:00+00:00 + ID: c7a6a8e5-abe8-47f1-8283-2e7b50551507 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:45:00+00:00 +---------------------------------------- + +Instruction #77: + Timestep: 76 + Time: 2025-11-03 16:50:00+00:00 + ID: e079a978-0deb-4d69-879a-af66b086224f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:50:00+00:00 +---------------------------------------- + +Instruction #78: + Timestep: 77 + Time: 2025-11-03 16:55:00+00:00 + ID: 8855f96c-39d4-4e12-9435-263e77a7c607 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 16:55:00+00:00 +---------------------------------------- + +Instruction #79: + Timestep: 78 + Time: 2025-11-03 17:00:00+00:00 + ID: a5638577-f052-4f75-ae97-dc4216f9a5bb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:00:00+00:00 +---------------------------------------- + +Instruction #80: + Timestep: 79 + Time: 2025-11-03 17:05:00+00:00 + ID: 572df723-5956-4585-8ac8-255b8de86b59 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:05:00+00:00 +---------------------------------------- + +Instruction #81: + Timestep: 80 + Time: 2025-11-03 17:10:00+00:00 + ID: 12c5b6a3-4eb9-4411-8900-bc93171b8198 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:10:00+00:00 +---------------------------------------- + +Instruction #82: + Timestep: 81 + Time: 2025-11-03 17:15:00+00:00 + ID: d240ac15-40d3-46b3-9f35-cc46e98e0be5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:15:00+00:00 +---------------------------------------- + +Instruction #83: + Timestep: 82 + Time: 2025-11-03 17:20:00+00:00 + ID: ecf75dd7-9646-4391-a7f7-375221185b3b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:20:00+00:00 +---------------------------------------- + +Instruction #84: + Timestep: 83 + Time: 2025-11-03 17:25:00+00:00 + ID: 52d4551b-721b-4d69-90d2-3b9ce068b6e5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:25:00+00:00 +---------------------------------------- + +Instruction #85: + Timestep: 84 + Time: 2025-11-03 17:30:00+00:00 + ID: 72bae77b-a316-43d7-a698-34a1d494faa2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:30:00+00:00 +---------------------------------------- + +Instruction #86: + Timestep: 85 + Time: 2025-11-03 17:35:00+00:00 + ID: 2c6c1f60-43d1-4e29-a020-c83dbaf62f89 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:35:00+00:00 +---------------------------------------- + +Instruction #87: + Timestep: 86 + Time: 2025-11-03 17:40:00+00:00 + ID: e0e8f020-f10b-4d6b-9fd4-151f1ea65002 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:40:00+00:00 +---------------------------------------- + +Instruction #88: + Timestep: 87 + Time: 2025-11-03 17:45:00+00:00 + ID: 86871f59-a99a-45d0-a026-6439e04562bf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:45:00+00:00 +---------------------------------------- + +Instruction #89: + Timestep: 88 + Time: 2025-11-03 17:50:00+00:00 + ID: 33b67b16-1802-48da-aa2e-569231b4d414 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:50:00+00:00 +---------------------------------------- + +Instruction #90: + Timestep: 89 + Time: 2025-11-03 17:55:00+00:00 + ID: 154c9045-63a0-46a8-8d6c-e12df36dde77 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 17:55:00+00:00 +---------------------------------------- + +Instruction #91: + Timestep: 90 + Time: 2025-11-03 18:00:00+00:00 + ID: 5b76b5ea-4b80-4903-9412-b78d2fefef49 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:00:00+00:00 +---------------------------------------- + +Instruction #92: + Timestep: 91 + Time: 2025-11-03 18:05:00+00:00 + ID: 9faba6b5-7b8f-4354-9e81-eaadd9324ac1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:05:00+00:00 +---------------------------------------- + +Instruction #93: + Timestep: 92 + Time: 2025-11-03 18:10:00+00:00 + ID: bd26fea2-045e-41c3-9f82-72e868714fc9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:10:00+00:00 +---------------------------------------- + +Instruction #94: + Timestep: 93 + Time: 2025-11-03 18:15:00+00:00 + ID: 7ef2b4d6-7f4c-4c3b-b673-a08d968a1699 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:15:00+00:00 +---------------------------------------- + +Instruction #95: + Timestep: 94 + Time: 2025-11-03 18:20:00+00:00 + ID: a772bbcb-4389-47d2-b3a0-a1b754706c9a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:20:00+00:00 +---------------------------------------- + +Instruction #96: + Timestep: 95 + Time: 2025-11-03 18:25:00+00:00 + ID: f47e70a0-c429-4b57-b310-04d574308aab + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:25:00+00:00 +---------------------------------------- + +Instruction #97: + Timestep: 96 + Time: 2025-11-03 18:30:00+00:00 + ID: 6eacdedf-d376-4829-9b47-0f637b0d86fe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:30:00+00:00 +---------------------------------------- + +Instruction #98: + Timestep: 97 + Time: 2025-11-03 18:35:00+00:00 + ID: 96add9b2-f3e6-4689-9bb7-e72038191c91 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:35:00+00:00 +---------------------------------------- + +Instruction #99: + Timestep: 98 + Time: 2025-11-03 18:40:00+00:00 + ID: 79a5e4fd-2868-4200-a949-449b08b7f7de + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:40:00+00:00 +---------------------------------------- + +Instruction #100: + Timestep: 99 + Time: 2025-11-03 18:45:00+00:00 + ID: 01cea868-18eb-4752-8032-6e6c1a1c7405 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:45:00+00:00 +---------------------------------------- + +Instruction #101: + Timestep: 100 + Time: 2025-11-03 18:50:00+00:00 + ID: c2dbde31-fda9-4a71-ab41-4b5754944932 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:50:00+00:00 +---------------------------------------- + +Instruction #102: + Timestep: 101 + Time: 2025-11-03 18:55:00+00:00 + ID: c189165c-d37d-4bff-8136-976927bdc1ea + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 18:55:00+00:00 +---------------------------------------- + +Instruction #103: + Timestep: 102 + Time: 2025-11-03 19:00:00+00:00 + ID: a9ac2cbe-31a3-4947-ad84-2eba74d991bb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:00:00+00:00 +---------------------------------------- + +Instruction #104: + Timestep: 103 + Time: 2025-11-03 19:05:00+00:00 + ID: a39dba22-b038-463a-a6dd-ef53859f7ee3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:05:00+00:00 +---------------------------------------- + +Instruction #105: + Timestep: 104 + Time: 2025-11-03 19:10:00+00:00 + ID: 7ec502b4-45a2-4536-8c3d-246d4fc46b75 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:10:00+00:00 +---------------------------------------- + +Instruction #106: + Timestep: 105 + Time: 2025-11-03 19:15:00+00:00 + ID: 7f7135c8-a13e-4fb2-8f8e-e736a5be08a2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:15:00+00:00 +---------------------------------------- + +Instruction #107: + Timestep: 106 + Time: 2025-11-03 19:20:00+00:00 + ID: 27a4d75d-2472-4c2a-b187-119716a8bc83 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:20:00+00:00 +---------------------------------------- + +Instruction #108: + Timestep: 107 + Time: 2025-11-03 19:25:00+00:00 + ID: f483b2d0-d346-4e7a-9693-97ae6541d04d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:25:00+00:00 +---------------------------------------- + +Instruction #109: + Timestep: 108 + Time: 2025-11-03 19:30:00+00:00 + ID: ffb97ad5-ead7-4234-b13e-b314385ff486 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:30:00+00:00 +---------------------------------------- + +Instruction #110: + Timestep: 109 + Time: 2025-11-03 19:35:00+00:00 + ID: ed8dacf6-471d-43fb-8eae-97f8ee6a95a2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:35:00+00:00 +---------------------------------------- + +Instruction #111: + Timestep: 110 + Time: 2025-11-03 19:40:00+00:00 + ID: 8938544f-055b-41cc-ad9b-9d3acf6db0c5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:40:00+00:00 +---------------------------------------- + +Instruction #112: + Timestep: 111 + Time: 2025-11-03 19:45:00+00:00 + ID: dd162d17-b751-400e-8de0-23a0f7a6e9cb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:45:00+00:00 +---------------------------------------- + +Instruction #113: + Timestep: 112 + Time: 2025-11-03 19:50:00+00:00 + ID: 1430c106-477c-45c9-8594-07e79f3f11b5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:50:00+00:00 +---------------------------------------- + +Instruction #114: + Timestep: 113 + Time: 2025-11-03 19:55:00+00:00 + ID: 7234d025-d782-46cb-9d66-3522c630db53 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 19:55:00+00:00 +---------------------------------------- + +Instruction #115: + Timestep: 114 + Time: 2025-11-03 20:00:00+00:00 + ID: 1b192a6b-bb22-4d1c-915d-fae4357fa9ad + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:00:00+00:00 +---------------------------------------- + +Instruction #116: + Timestep: 115 + Time: 2025-11-03 20:05:00+00:00 + ID: aed2c21d-ddc2-45f7-8a27-da0cd246ee72 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:05:00+00:00 +---------------------------------------- + +Instruction #117: + Timestep: 116 + Time: 2025-11-03 20:10:00+00:00 + ID: df5aad69-bc80-4443-8b3c-83bbb58b057e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:10:00+00:00 +---------------------------------------- + +Instruction #118: + Timestep: 117 + Time: 2025-11-03 20:15:00+00:00 + ID: 8975a0ed-d27e-4da0-a9ca-17b97fc1f2f0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:15:00+00:00 +---------------------------------------- + +Instruction #119: + Timestep: 118 + Time: 2025-11-03 20:20:00+00:00 + ID: fd2b2611-9645-450c-9e6a-46311829ab18 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:20:00+00:00 +---------------------------------------- + +Instruction #120: + Timestep: 119 + Time: 2025-11-03 20:25:00+00:00 + ID: ac0c2c3d-2cab-45cf-be6c-debfac711c69 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:25:00+00:00 +---------------------------------------- + +Instruction #121: + Timestep: 120 + Time: 2025-11-03 20:30:00+00:00 + ID: d920e3d2-9997-4d64-a061-321b5bfae462 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:30:00+00:00 +---------------------------------------- + +Instruction #122: + Timestep: 121 + Time: 2025-11-03 20:35:00+00:00 + ID: c816236d-cb2f-4ce4-bd76-3908637b93d8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:35:00+00:00 +---------------------------------------- + +Instruction #123: + Timestep: 122 + Time: 2025-11-03 20:40:00+00:00 + ID: d7e27a2d-ff5c-4a55-9fd4-f590466a5e13 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:40:00+00:00 +---------------------------------------- + +Instruction #124: + Timestep: 123 + Time: 2025-11-03 20:45:00+00:00 + ID: f98b4c43-3d5f-4aeb-af82-58e6363fa07a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:45:00+00:00 +---------------------------------------- + +Instruction #125: + Timestep: 124 + Time: 2025-11-03 20:50:00+00:00 + ID: 6eaada6a-6159-4cc3-8356-733c571f4c71 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:50:00+00:00 +---------------------------------------- + +Instruction #126: + Timestep: 125 + Time: 2025-11-03 20:55:00+00:00 + ID: d599219a-5adc-4bd2-a0f3-ea83b70f9100 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 20:55:00+00:00 +---------------------------------------- + +Instruction #127: + Timestep: 126 + Time: 2025-11-03 21:00:00+00:00 + ID: 46526216-0680-4700-a02e-f921becda746 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:00:00+00:00 +---------------------------------------- + +Instruction #128: + Timestep: 127 + Time: 2025-11-03 21:05:00+00:00 + ID: b15e0c87-a7e0-49f6-905c-ce8bf3eb0c63 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:05:00+00:00 +---------------------------------------- + +Instruction #129: + Timestep: 128 + Time: 2025-11-03 21:10:00+00:00 + ID: 695792d3-201a-418f-af31-31aaa6f103ea + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:10:00+00:00 +---------------------------------------- + +Instruction #130: + Timestep: 129 + Time: 2025-11-03 21:15:00+00:00 + ID: 8be1e41c-cfa1-4094-b5f9-e2b6ce33f2d8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:15:00+00:00 +---------------------------------------- + +Instruction #131: + Timestep: 130 + Time: 2025-11-03 21:20:00+00:00 + ID: f1d2f789-5ca4-41f5-9d5f-e9ad9cfc0223 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:20:00+00:00 +---------------------------------------- + +Instruction #132: + Timestep: 131 + Time: 2025-11-03 21:25:00+00:00 + ID: b03653a1-039d-4897-8dbe-c5e3f7782161 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:25:00+00:00 +---------------------------------------- + +Instruction #133: + Timestep: 132 + Time: 2025-11-03 21:30:00+00:00 + ID: d0d3199f-a299-4fc8-916c-c2bef51cdf46 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:30:00+00:00 +---------------------------------------- + +Instruction #134: + Timestep: 133 + Time: 2025-11-03 21:35:00+00:00 + ID: 2605ccfb-516c-463d-a9cd-ec6510138ddd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:35:00+00:00 +---------------------------------------- + +Instruction #135: + Timestep: 134 + Time: 2025-11-03 21:40:00+00:00 + ID: 72b784e3-8657-4360-8d05-e1a30d373633 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:40:00+00:00 +---------------------------------------- + +Instruction #136: + Timestep: 135 + Time: 2025-11-03 21:45:00+00:00 + ID: 4418900d-bb8f-430f-941c-217a34ab905c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:45:00+00:00 +---------------------------------------- + +Instruction #137: + Timestep: 136 + Time: 2025-11-03 21:50:00+00:00 + ID: a441b19e-9a95-463b-ad50-ad50f49e39d4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:50:00+00:00 +---------------------------------------- + +Instruction #138: + Timestep: 137 + Time: 2025-11-03 21:55:00+00:00 + ID: 56f6d6dd-309b-4a09-a774-741e3acd35fa + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 21:55:00+00:00 +---------------------------------------- + +Instruction #139: + Timestep: 138 + Time: 2025-11-03 22:00:00+00:00 + ID: 5a5b27e7-a038-4073-bf7a-eb0ec57c1bac + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:00:00+00:00 +---------------------------------------- + +Instruction #140: + Timestep: 139 + Time: 2025-11-03 22:05:00+00:00 + ID: e7333faf-7371-4261-a21c-9fa5c40779f8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:05:00+00:00 +---------------------------------------- + +Instruction #141: + Timestep: 140 + Time: 2025-11-03 22:10:00+00:00 + ID: 3e23a96c-d724-4169-a61a-05e2ecebc369 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:10:00+00:00 +---------------------------------------- + +Instruction #142: + Timestep: 141 + Time: 2025-11-03 22:15:00+00:00 + ID: 0875fa60-ae46-42ad-9229-1e8080f88879 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:15:00+00:00 +---------------------------------------- + +Instruction #143: + Timestep: 142 + Time: 2025-11-03 22:20:00+00:00 + ID: f75bde96-bef2-4a2a-84ea-50e704a68697 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:20:00+00:00 +---------------------------------------- + +Instruction #144: + Timestep: 143 + Time: 2025-11-03 22:25:00+00:00 + ID: cfce273d-7a9f-4709-8af9-13c7f81f6e8a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:25:00+00:00 +---------------------------------------- + +Instruction #145: + Timestep: 144 + Time: 2025-11-03 22:30:00+00:00 + ID: a1f4a6f6-9293-4e5d-8721-b96ee277c290 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:30:00+00:00 +---------------------------------------- + +Instruction #146: + Timestep: 145 + Time: 2025-11-03 22:35:00+00:00 + ID: aee2ed03-237c-415e-8670-e42439ef5983 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:35:00+00:00 +---------------------------------------- + +Instruction #147: + Timestep: 146 + Time: 2025-11-03 22:40:00+00:00 + ID: dea22692-edd9-4716-89ad-824df281885d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:40:00+00:00 +---------------------------------------- + +Instruction #148: + Timestep: 147 + Time: 2025-11-03 22:45:00+00:00 + ID: b89805db-621c-4d16-b616-b1ff05fc26e6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:45:00+00:00 +---------------------------------------- + +Instruction #149: + Timestep: 148 + Time: 2025-11-03 22:50:00+00:00 + ID: b88e6db6-665f-4407-803d-93e52917a97c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:50:00+00:00 +---------------------------------------- + +Instruction #150: + Timestep: 149 + Time: 2025-11-03 22:55:00+00:00 + ID: 26224527-73ef-4402-859e-4471a01f6b17 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 22:55:00+00:00 +---------------------------------------- + +Instruction #151: + Timestep: 150 + Time: 2025-11-03 23:00:00+00:00 + ID: 824525f0-d4c8-446a-9727-c83b60cdbf26 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:00:00+00:00 +---------------------------------------- + +Instruction #152: + Timestep: 151 + Time: 2025-11-03 23:05:00+00:00 + ID: cc680480-4b0f-426c-85f1-4a0de8c96609 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:05:00+00:00 +---------------------------------------- + +Instruction #153: + Timestep: 152 + Time: 2025-11-03 23:10:00+00:00 + ID: 01ec1362-39a4-43d3-a423-354b8b8300e0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:10:00+00:00 +---------------------------------------- + +Instruction #154: + Timestep: 153 + Time: 2025-11-03 23:15:00+00:00 + ID: 948245c8-9afa-43bd-9f46-7e63811743d4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:15:00+00:00 +---------------------------------------- + +Instruction #155: + Timestep: 154 + Time: 2025-11-03 23:20:00+00:00 + ID: 7c1c126b-4a66-434d-9353-85dde83ec835 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:20:00+00:00 +---------------------------------------- + +Instruction #156: + Timestep: 155 + Time: 2025-11-03 23:25:00+00:00 + ID: 2ec1d4f4-eb19-4a00-bbba-16abcd028569 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:25:00+00:00 +---------------------------------------- + +Instruction #157: + Timestep: 156 + Time: 2025-11-03 23:30:00+00:00 + ID: 53cae277-3262-420a-bbcd-f7e4dcaa1d8e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:30:00+00:00 +---------------------------------------- + +Instruction #158: + Timestep: 157 + Time: 2025-11-03 23:35:00+00:00 + ID: f77e3534-93fd-4428-9368-f8b17d9bad71 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:35:00+00:00 +---------------------------------------- + +Instruction #159: + Timestep: 158 + Time: 2025-11-03 23:40:00+00:00 + ID: d389f7ba-970d-4dbf-864d-5a52cb75412a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:40:00+00:00 +---------------------------------------- + +Instruction #160: + Timestep: 159 + Time: 2025-11-03 23:45:00+00:00 + ID: 3ef93978-45e6-4e7f-a418-99023cd726a7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:45:00+00:00 +---------------------------------------- + +Instruction #161: + Timestep: 160 + Time: 2025-11-03 23:50:00+00:00 + ID: 5afbf63f-30f0-44bf-bf7e-3d4775090884 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:50:00+00:00 +---------------------------------------- + +Instruction #162: + Timestep: 161 + Time: 2025-11-03 23:55:00+00:00 + ID: 537eae5f-eb0e-473d-9d1c-9b66eb987861 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-03 23:55:00+00:00 +---------------------------------------- + +Instruction #163: + Timestep: 162 + Time: 2025-11-04 00:00:00+00:00 + ID: 18c9c090-f440-40ad-9790-47f638477df8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:00:00+00:00 +---------------------------------------- + +Instruction #164: + Timestep: 163 + Time: 2025-11-04 00:05:00+00:00 + ID: eead63e8-3a39-4755-95aa-2c72829d5645 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:05:00+00:00 +---------------------------------------- + +Instruction #165: + Timestep: 164 + Time: 2025-11-04 00:10:00+00:00 + ID: 1466c5e2-fe29-4310-b74d-d2cca0cde2c8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:10:00+00:00 +---------------------------------------- + +Instruction #166: + Timestep: 165 + Time: 2025-11-04 00:15:00+00:00 + ID: 9fd25440-e42a-43a2-96a6-26054a76af0a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:15:00+00:00 +---------------------------------------- + +Instruction #167: + Timestep: 166 + Time: 2025-11-04 00:20:00+00:00 + ID: ac14b5d4-158a-4b1c-b4e8-946f2609d45a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:20:00+00:00 +---------------------------------------- + +Instruction #168: + Timestep: 167 + Time: 2025-11-04 00:25:00+00:00 + ID: 9f19f4be-1512-4f13-ab1c-23bf9cbaea67 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:25:00+00:00 +---------------------------------------- + +Instruction #169: + Timestep: 168 + Time: 2025-11-04 00:30:00+00:00 + ID: 81edbe7a-ca2a-48ad-8e8c-342e3f7b5878 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:30:00+00:00 +---------------------------------------- + +Instruction #170: + Timestep: 169 + Time: 2025-11-04 00:35:00+00:00 + ID: 80acf276-9eb3-4140-9139-2506898117da + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:35:00+00:00 +---------------------------------------- + +Instruction #171: + Timestep: 170 + Time: 2025-11-04 00:40:00+00:00 + ID: 813bbd0c-326e-4b0d-98ee-503cc654b2dd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:40:00+00:00 +---------------------------------------- + +Instruction #172: + Timestep: 171 + Time: 2025-11-04 00:45:00+00:00 + ID: 81074676-dd44-46b6-aaa8-bf2ab45992f4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:45:00+00:00 +---------------------------------------- + +Instruction #173: + Timestep: 172 + Time: 2025-11-04 00:50:00+00:00 + ID: 5103c1ab-9d44-4416-982f-e90aac761632 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:50:00+00:00 +---------------------------------------- + +Instruction #174: + Timestep: 173 + Time: 2025-11-04 00:55:00+00:00 + ID: b6b318ee-dd80-40fd-bb17-6c4ac18d4125 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 00:55:00+00:00 +---------------------------------------- + +Instruction #175: + Timestep: 174 + Time: 2025-11-04 01:00:00+00:00 + ID: 434b6426-8603-4e6d-802d-2830b3fbb9dc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:00:00+00:00 +---------------------------------------- + +Instruction #176: + Timestep: 175 + Time: 2025-11-04 01:05:00+00:00 + ID: bf0ae72f-251a-4653-99d5-22a1372f6afe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:05:00+00:00 +---------------------------------------- + +Instruction #177: + Timestep: 176 + Time: 2025-11-04 01:10:00+00:00 + ID: a8f5c3ce-58e1-48f8-be21-e2d6f53b2d0b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:10:00+00:00 +---------------------------------------- + +Instruction #178: + Timestep: 177 + Time: 2025-11-04 01:15:00+00:00 + ID: af6f2482-b58d-4e57-903a-01def0259f8a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:15:00+00:00 +---------------------------------------- + +Instruction #179: + Timestep: 178 + Time: 2025-11-04 01:20:00+00:00 + ID: c2374a18-4ad3-40d2-a44b-ebe4dbd25ef2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:20:00+00:00 +---------------------------------------- + +Instruction #180: + Timestep: 179 + Time: 2025-11-04 01:25:00+00:00 + ID: 8a53ae5b-692b-474e-ad56-9a088926de4d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:25:00+00:00 +---------------------------------------- + +Instruction #181: + Timestep: 180 + Time: 2025-11-04 01:30:00+00:00 + ID: a044f5f8-126d-41ea-8941-cc489c471a30 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:30:00+00:00 +---------------------------------------- + +Instruction #182: + Timestep: 181 + Time: 2025-11-04 01:35:00+00:00 + ID: 1387cbad-4016-468a-9241-8fd4908b188f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:35:00+00:00 +---------------------------------------- + +Instruction #183: + Timestep: 182 + Time: 2025-11-04 01:40:00+00:00 + ID: 1a9813e5-5d60-4e31-91c4-20d0aa5de49b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:40:00+00:00 +---------------------------------------- + +Instruction #184: + Timestep: 183 + Time: 2025-11-04 01:45:00+00:00 + ID: bfb8b504-b878-4432-bbae-adaa68cbcfa7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:45:00+00:00 +---------------------------------------- + +Instruction #185: + Timestep: 184 + Time: 2025-11-04 01:50:00+00:00 + ID: 51e36336-bf40-4916-8870-f914467cb04a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:50:00+00:00 +---------------------------------------- + +Instruction #186: + Timestep: 185 + Time: 2025-11-04 01:55:00+00:00 + ID: e55c1c10-8d4f-4265-8a25-aca73942deb7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 01:55:00+00:00 +---------------------------------------- + +Instruction #187: + Timestep: 186 + Time: 2025-11-04 02:00:00+00:00 + ID: 9c4ba964-13a9-47a5-9729-ef39853b785b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:00:00+00:00 +---------------------------------------- + +Instruction #188: + Timestep: 187 + Time: 2025-11-04 02:05:00+00:00 + ID: 572cce0e-55a9-430c-847d-dffc3178ec49 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:05:00+00:00 +---------------------------------------- + +Instruction #189: + Timestep: 188 + Time: 2025-11-04 02:10:00+00:00 + ID: 1f9cb64a-f6c1-4d63-81c0-d9651292cb35 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:10:00+00:00 +---------------------------------------- + +Instruction #190: + Timestep: 189 + Time: 2025-11-04 02:15:00+00:00 + ID: abbc9372-0ef4-4a77-8be1-4438fd20d8d0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:15:00+00:00 +---------------------------------------- + +Instruction #191: + Timestep: 190 + Time: 2025-11-04 02:20:00+00:00 + ID: 6eafe9c5-79ad-41ad-95e0-e9908c829e1b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:20:00+00:00 +---------------------------------------- + +Instruction #192: + Timestep: 191 + Time: 2025-11-04 02:25:00+00:00 + ID: 9462b4a2-b1a8-4e44-9e53-cbc99d245eb2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:25:00+00:00 +---------------------------------------- + +Instruction #193: + Timestep: 192 + Time: 2025-11-04 02:30:00+00:00 + ID: 729e06fa-6a01-44e0-b4fa-6c0c41fed841 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:30:00+00:00 +---------------------------------------- + +Instruction #194: + Timestep: 193 + Time: 2025-11-04 02:35:00+00:00 + ID: c7cf5410-a783-4dd1-a5e8-3c7d02de4240 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:35:00+00:00 +---------------------------------------- + +Instruction #195: + Timestep: 194 + Time: 2025-11-04 02:40:00+00:00 + ID: 5884609e-63c2-496e-a887-4a2278232d04 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:40:00+00:00 +---------------------------------------- + +Instruction #196: + Timestep: 195 + Time: 2025-11-04 02:45:00+00:00 + ID: a4eb26c2-af2f-4e68-8ad7-4cc90cce8900 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:45:00+00:00 +---------------------------------------- + +Instruction #197: + Timestep: 196 + Time: 2025-11-04 02:50:00+00:00 + ID: c5d22d2a-7a0d-4568-b58d-f84153cd36c0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:50:00+00:00 +---------------------------------------- + +Instruction #198: + Timestep: 197 + Time: 2025-11-04 02:55:00+00:00 + ID: 2b5f3bb1-65a0-457a-ba76-e72580c966c5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 02:55:00+00:00 +---------------------------------------- + +Instruction #199: + Timestep: 198 + Time: 2025-11-04 03:00:00+00:00 + ID: 3f8346d3-5354-45d7-a8d5-a7d6baedfb3e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:00:00+00:00 +---------------------------------------- + +Instruction #200: + Timestep: 199 + Time: 2025-11-04 03:05:00+00:00 + ID: eb54f402-19da-4883-bfd9-903adf5045bb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:05:00+00:00 +---------------------------------------- + +Instruction #201: + Timestep: 200 + Time: 2025-11-04 03:10:00+00:00 + ID: 8cf4e378-830f-489d-a9d7-e5babafd08de + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:10:00+00:00 +---------------------------------------- + +Instruction #202: + Timestep: 201 + Time: 2025-11-04 03:15:00+00:00 + ID: 33e64dbb-afcc-416d-8839-14d29a5b7beb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:15:00+00:00 +---------------------------------------- + +Instruction #203: + Timestep: 202 + Time: 2025-11-04 03:20:00+00:00 + ID: a392c38a-cb05-42bc-977b-b234c1b564a2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:20:00+00:00 +---------------------------------------- + +Instruction #204: + Timestep: 203 + Time: 2025-11-04 03:25:00+00:00 + ID: 8697b229-5882-4e59-87b4-f1d5cb364ecd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:25:00+00:00 +---------------------------------------- + +Instruction #205: + Timestep: 204 + Time: 2025-11-04 03:30:00+00:00 + ID: 6ba3b8df-8bbf-4696-80fc-18fa2c0cf29c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:30:00+00:00 +---------------------------------------- + +Instruction #206: + Timestep: 205 + Time: 2025-11-04 03:35:00+00:00 + ID: 3baa2ec9-6255-4af8-a3e0-55701ca195b6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:35:00+00:00 +---------------------------------------- + +Instruction #207: + Timestep: 206 + Time: 2025-11-04 03:40:00+00:00 + ID: 97a0ec67-f19a-4616-99b9-be037901d9bd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:40:00+00:00 +---------------------------------------- + +Instruction #208: + Timestep: 207 + Time: 2025-11-04 03:45:00+00:00 + ID: 83d06faa-3e56-41ea-add7-8a760ef74eb8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:45:00+00:00 +---------------------------------------- + +Instruction #209: + Timestep: 208 + Time: 2025-11-04 03:50:00+00:00 + ID: 03a73048-9993-4d2a-86ca-4f6c3b851807 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:50:00+00:00 +---------------------------------------- + +Instruction #210: + Timestep: 209 + Time: 2025-11-04 03:55:00+00:00 + ID: a00a0e5f-e703-4592-887b-57c4d2032244 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 03:55:00+00:00 +---------------------------------------- + +Instruction #211: + Timestep: 210 + Time: 2025-11-04 04:00:00+00:00 + ID: eef31d3b-fedf-4cd8-83ff-b3717f6bb645 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:00:00+00:00 +---------------------------------------- + +Instruction #212: + Timestep: 211 + Time: 2025-11-04 04:05:00+00:00 + ID: f2065747-e1de-4bf6-a5dd-14fb66969aa1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:05:00+00:00 +---------------------------------------- + +Instruction #213: + Timestep: 212 + Time: 2025-11-04 04:10:00+00:00 + ID: d2e52154-da53-4417-87f8-06c7b96c30ea + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:10:00+00:00 +---------------------------------------- + +Instruction #214: + Timestep: 213 + Time: 2025-11-04 04:15:00+00:00 + ID: 93c3ebc6-6b51-4971-871a-6fe6e9829102 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:15:00+00:00 +---------------------------------------- + +Instruction #215: + Timestep: 214 + Time: 2025-11-04 04:20:00+00:00 + ID: 4d29a5e1-4f84-4cac-82c8-b45d1a7af2ad + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:20:00+00:00 +---------------------------------------- + +Instruction #216: + Timestep: 215 + Time: 2025-11-04 04:25:00+00:00 + ID: d39c9f7d-88bd-4cee-b65d-3c4a81900d64 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:25:00+00:00 +---------------------------------------- + +Instruction #217: + Timestep: 216 + Time: 2025-11-04 04:30:00+00:00 + ID: 3479a9ba-5943-45b2-9d91-0ba208f2609c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:30:00+00:00 +---------------------------------------- + +Instruction #218: + Timestep: 217 + Time: 2025-11-04 04:35:00+00:00 + ID: f05cfb99-179a-4d75-9e90-1b7b5c159754 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:35:00+00:00 +---------------------------------------- + +Instruction #219: + Timestep: 218 + Time: 2025-11-04 04:40:00+00:00 + ID: e277eceb-2fca-4423-8418-57892293c929 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:40:00+00:00 +---------------------------------------- + +Instruction #220: + Timestep: 219 + Time: 2025-11-04 04:45:00+00:00 + ID: 3eee9159-d9e2-4e06-80dd-7add4cbf2fd2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:45:00+00:00 +---------------------------------------- + +Instruction #221: + Timestep: 220 + Time: 2025-11-04 04:50:00+00:00 + ID: 23f6e9e1-d962-4ed3-b55b-d27bc57f7395 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:50:00+00:00 +---------------------------------------- + +Instruction #222: + Timestep: 221 + Time: 2025-11-04 04:55:00+00:00 + ID: 6f5d53c6-8051-4284-aa8a-00bb75f6e534 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 04:55:00+00:00 +---------------------------------------- + +Instruction #223: + Timestep: 222 + Time: 2025-11-04 05:00:00+00:00 + ID: 9fbeebaf-19f8-47a0-a3d9-e26bb5d1d201 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:00:00+00:00 +---------------------------------------- + +Instruction #224: + Timestep: 223 + Time: 2025-11-04 05:05:00+00:00 + ID: d149a0f7-5a43-4491-8a98-35f4e653f11f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:05:00+00:00 +---------------------------------------- + +Instruction #225: + Timestep: 224 + Time: 2025-11-04 05:10:00+00:00 + ID: e054f7cb-ac01-42c7-94d4-8bbff1b28f59 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:10:00+00:00 +---------------------------------------- + +Instruction #226: + Timestep: 225 + Time: 2025-11-04 05:15:00+00:00 + ID: 15fbb051-3bb9-4e7d-9c5c-b8bb24659193 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:15:00+00:00 +---------------------------------------- + +Instruction #227: + Timestep: 226 + Time: 2025-11-04 05:20:00+00:00 + ID: c6b0a3eb-795d-403b-b206-a6f8f35fddbb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:20:00+00:00 +---------------------------------------- + +Instruction #228: + Timestep: 227 + Time: 2025-11-04 05:25:00+00:00 + ID: e0f56280-0553-4974-b10d-81a35f040793 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:25:00+00:00 +---------------------------------------- + +Instruction #229: + Timestep: 228 + Time: 2025-11-04 05:30:00+00:00 + ID: 6376942c-023f-4711-acf1-b792b80c3944 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:30:00+00:00 +---------------------------------------- + +Instruction #230: + Timestep: 229 + Time: 2025-11-04 05:35:00+00:00 + ID: 8ef61a4c-f597-4077-a8c7-ed57f912abc9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:35:00+00:00 +---------------------------------------- + +Instruction #231: + Timestep: 230 + Time: 2025-11-04 05:40:00+00:00 + ID: 9cc2e6e9-1ea1-4ff7-8b24-2eae63ce4012 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:40:00+00:00 +---------------------------------------- + +Instruction #232: + Timestep: 231 + Time: 2025-11-04 05:45:00+00:00 + ID: 922691d4-c9ec-4bdf-83fe-c75e7673fe16 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:45:00+00:00 +---------------------------------------- + +Instruction #233: + Timestep: 232 + Time: 2025-11-04 05:50:00+00:00 + ID: 25ad2dde-0384-4887-9a9e-26201a65fa8b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:50:00+00:00 +---------------------------------------- + +Instruction #234: + Timestep: 233 + Time: 2025-11-04 05:55:00+00:00 + ID: 307d928e-6dec-430d-b1c8-c2251496ba70 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 05:55:00+00:00 +---------------------------------------- + +Instruction #235: + Timestep: 234 + Time: 2025-11-04 06:00:00+00:00 + ID: 4172fc61-e3e3-437f-bfcc-d78f4359dbfb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:00:00+00:00 +---------------------------------------- + +Instruction #236: + Timestep: 235 + Time: 2025-11-04 06:05:00+00:00 + ID: 01fe5f02-b9e1-421c-b5be-29b975fec0be + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:05:00+00:00 +---------------------------------------- + +Instruction #237: + Timestep: 236 + Time: 2025-11-04 06:10:00+00:00 + ID: 765fb36c-ba62-4617-9816-8a0d64e06150 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:10:00+00:00 +---------------------------------------- + +Instruction #238: + Timestep: 237 + Time: 2025-11-04 06:15:00+00:00 + ID: 041c6160-ac0e-4a76-b8ce-b05ad2f48ffa + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:15:00+00:00 +---------------------------------------- + +Instruction #239: + Timestep: 238 + Time: 2025-11-04 06:20:00+00:00 + ID: d32f5531-f2d3-4331-a690-14c77341bcfe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:20:00+00:00 +---------------------------------------- + +Instruction #240: + Timestep: 239 + Time: 2025-11-04 06:25:00+00:00 + ID: ea294527-8643-491a-9a07-964227510275 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:25:00+00:00 +---------------------------------------- + +Instruction #241: + Timestep: 240 + Time: 2025-11-04 06:30:00+00:00 + ID: c713e1df-41f4-4ed8-8f12-123fe078c779 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:30:00+00:00 +---------------------------------------- + +Instruction #242: + Timestep: 241 + Time: 2025-11-04 06:35:00+00:00 + ID: 485533d8-69e3-46fa-a0ba-a9e90c7caaa3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:35:00+00:00 +---------------------------------------- + +Instruction #243: + Timestep: 242 + Time: 2025-11-04 06:40:00+00:00 + ID: 3b267d9d-3aca-4c24-a947-4341e59b53a6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:40:00+00:00 +---------------------------------------- + +Instruction #244: + Timestep: 243 + Time: 2025-11-04 06:45:00+00:00 + ID: ec243dc6-147a-48b2-8cd6-9fd1b9b8832e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:45:00+00:00 +---------------------------------------- + +Instruction #245: + Timestep: 244 + Time: 2025-11-04 06:50:00+00:00 + ID: 1e7de924-e3e1-4df5-a3c9-8a8e483f108c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:50:00+00:00 +---------------------------------------- + +Instruction #246: + Timestep: 245 + Time: 2025-11-04 06:55:00+00:00 + ID: ef035bfd-8b42-49ae-b1b3-852a7861546e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 06:55:00+00:00 +---------------------------------------- + +Instruction #247: + Timestep: 246 + Time: 2025-11-04 07:00:00+00:00 + ID: 725ad818-ff23-4342-b0ff-82391666f7c9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:00:00+00:00 +---------------------------------------- + +Instruction #248: + Timestep: 247 + Time: 2025-11-04 07:05:00+00:00 + ID: 643acfb7-2325-4543-8f05-c74c81128f9b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:05:00+00:00 +---------------------------------------- + +Instruction #249: + Timestep: 248 + Time: 2025-11-04 07:10:00+00:00 + ID: b2210f98-f4d7-4121-ab82-0fedacef81eb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:10:00+00:00 +---------------------------------------- + +Instruction #250: + Timestep: 249 + Time: 2025-11-04 07:15:00+00:00 + ID: ae9adb54-f49b-4d35-8f3f-b90e7f919a69 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:15:00+00:00 +---------------------------------------- + +Instruction #251: + Timestep: 250 + Time: 2025-11-04 07:20:00+00:00 + ID: cac19eca-04f0-4a5a-abc5-cb4b49a0d4de + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:20:00+00:00 +---------------------------------------- + +Instruction #252: + Timestep: 251 + Time: 2025-11-04 07:25:00+00:00 + ID: 7556ba0e-5d96-42f3-86fb-0f7352f8bd41 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:25:00+00:00 +---------------------------------------- + +Instruction #253: + Timestep: 252 + Time: 2025-11-04 07:30:00+00:00 + ID: f289a7f2-bd2f-4dec-8d28-a4c8e76fc614 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:30:00+00:00 +---------------------------------------- + +Instruction #254: + Timestep: 253 + Time: 2025-11-04 07:35:00+00:00 + ID: 021415e8-4ca4-478c-a262-370b6e6e7e13 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:35:00+00:00 +---------------------------------------- + +Instruction #255: + Timestep: 254 + Time: 2025-11-04 07:40:00+00:00 + ID: 3c0a8221-7c5f-43c2-bf7d-b26a6544109e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:40:00+00:00 +---------------------------------------- + +Instruction #256: + Timestep: 255 + Time: 2025-11-04 07:45:00+00:00 + ID: 5548d4d0-ba0d-401b-9e6e-05ebbdb1dd59 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:45:00+00:00 +---------------------------------------- + +Instruction #257: + Timestep: 256 + Time: 2025-11-04 07:50:00+00:00 + ID: 6cf773f2-9a6c-45e8-9d4f-ae796c72e83b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:50:00+00:00 +---------------------------------------- + +Instruction #258: + Timestep: 257 + Time: 2025-11-04 07:55:00+00:00 + ID: ec21f19c-126c-44b2-800a-1b7f778f6500 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 07:55:00+00:00 +---------------------------------------- + +Instruction #259: + Timestep: 258 + Time: 2025-11-04 08:00:00+00:00 + ID: 33b51205-4228-484f-9c97-8d616afa927c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:00:00+00:00 +---------------------------------------- + +Instruction #260: + Timestep: 259 + Time: 2025-11-04 08:05:00+00:00 + ID: b28f065d-fb8d-471f-a111-079d78e80aca + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:05:00+00:00 +---------------------------------------- + +Instruction #261: + Timestep: 260 + Time: 2025-11-04 08:10:00+00:00 + ID: 54d473db-f4ea-4cb9-add1-baff3f27e0bc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:10:00+00:00 +---------------------------------------- + +Instruction #262: + Timestep: 261 + Time: 2025-11-04 08:15:00+00:00 + ID: 839f98d2-d403-40d7-b2fa-12fbd504d1fb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:15:00+00:00 +---------------------------------------- + +Instruction #263: + Timestep: 262 + Time: 2025-11-04 08:20:00+00:00 + ID: 04c110e1-f623-4542-a00b-d6010ebeb424 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:20:00+00:00 +---------------------------------------- + +Instruction #264: + Timestep: 263 + Time: 2025-11-04 08:25:00+00:00 + ID: dce1acb1-d4f7-4108-89b7-15213acb5f2e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:25:00+00:00 +---------------------------------------- + +Instruction #265: + Timestep: 264 + Time: 2025-11-04 08:30:00+00:00 + ID: cb9b0b10-6d10-4426-8a3c-e376f11cb942 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:30:00+00:00 +---------------------------------------- + +Instruction #266: + Timestep: 265 + Time: 2025-11-04 08:35:00+00:00 + ID: e474ddc0-0572-4f4f-aa6a-abcb4a9c7188 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:35:00+00:00 +---------------------------------------- + +Instruction #267: + Timestep: 266 + Time: 2025-11-04 08:40:00+00:00 + ID: e52f66e8-1cad-4efa-8993-7fb2532eaddb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:40:00+00:00 +---------------------------------------- + +Instruction #268: + Timestep: 267 + Time: 2025-11-04 08:45:00+00:00 + ID: fab0a59e-c67c-47cd-b331-0c6682d5235e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:45:00+00:00 +---------------------------------------- + +Instruction #269: + Timestep: 268 + Time: 2025-11-04 08:50:00+00:00 + ID: f9b712c7-8b94-4ec8-8d7a-a9ca4c9f5837 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:50:00+00:00 +---------------------------------------- + +Instruction #270: + Timestep: 269 + Time: 2025-11-04 08:55:00+00:00 + ID: a41cc9e2-7a35-4b40-b42f-8af19f4a9152 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 08:55:00+00:00 +---------------------------------------- + +Instruction #271: + Timestep: 270 + Time: 2025-11-04 09:00:00+00:00 + ID: 96f2afed-af96-4cf4-8cd0-6a60ac2c2763 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:00:00+00:00 +---------------------------------------- + +Instruction #272: + Timestep: 271 + Time: 2025-11-04 09:05:00+00:00 + ID: c826efce-997f-4529-a4d1-1b06c0db10e4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:05:00+00:00 +---------------------------------------- + +Instruction #273: + Timestep: 272 + Time: 2025-11-04 09:10:00+00:00 + ID: b9ed7ad8-e786-47d0-bb76-a07af225d3b0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:10:00+00:00 +---------------------------------------- + +Instruction #274: + Timestep: 273 + Time: 2025-11-04 09:15:00+00:00 + ID: d4773698-3353-4d42-9840-1e4af3aba7db + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:15:00+00:00 +---------------------------------------- + +Instruction #275: + Timestep: 274 + Time: 2025-11-04 09:20:00+00:00 + ID: b6792925-3f3e-4095-828a-b2ff075241b1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:20:00+00:00 +---------------------------------------- + +Instruction #276: + Timestep: 275 + Time: 2025-11-04 09:25:00+00:00 + ID: 45c7eb47-37bd-465b-b50e-c31e85299ccb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:25:00+00:00 +---------------------------------------- + +Instruction #277: + Timestep: 276 + Time: 2025-11-04 09:30:00+00:00 + ID: 2e632794-7d6a-4610-bc41-b392db5f9bec + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:30:00+00:00 +---------------------------------------- + +Instruction #278: + Timestep: 277 + Time: 2025-11-04 09:35:00+00:00 + ID: 4b16fcb6-b824-4a1c-913e-eedc0ec7d61b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:35:00+00:00 +---------------------------------------- + +Instruction #279: + Timestep: 278 + Time: 2025-11-04 09:40:00+00:00 + ID: 599ef653-3516-4641-9242-5ad426238e5b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:40:00+00:00 +---------------------------------------- + +Instruction #280: + Timestep: 279 + Time: 2025-11-04 09:45:00+00:00 + ID: 59569fe4-a58d-4c88-ba2f-6a2c0a65ea7b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:45:00+00:00 +---------------------------------------- + +Instruction #281: + Timestep: 280 + Time: 2025-11-04 09:50:00+00:00 + ID: 3feeaa47-f41e-4d61-a1ca-50f0ea6a86fc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:50:00+00:00 +---------------------------------------- + +Instruction #282: + Timestep: 281 + Time: 2025-11-04 09:55:00+00:00 + ID: 762e2e57-b1f2-4cbe-ac65-794e99afa096 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 09:55:00+00:00 +---------------------------------------- + +Instruction #283: + Timestep: 282 + Time: 2025-11-04 10:00:00+00:00 + ID: e3aa8b20-3055-4546-9992-5d0d006f6995 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:00:00+00:00 +---------------------------------------- + +Instruction #284: + Timestep: 283 + Time: 2025-11-04 10:05:00+00:00 + ID: ba785dc6-e01a-435b-ad24-ebe2f7f4b583 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:05:00+00:00 +---------------------------------------- + +Instruction #285: + Timestep: 284 + Time: 2025-11-04 10:10:00+00:00 + ID: 265ca424-dd48-4ae1-b14d-c10321f8345f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:10:00+00:00 +---------------------------------------- + +Instruction #286: + Timestep: 285 + Time: 2025-11-04 10:15:00+00:00 + ID: c0c33d62-2629-4707-a41e-0599bcf070d3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:15:00+00:00 +---------------------------------------- + +Instruction #287: + Timestep: 286 + Time: 2025-11-04 10:20:00+00:00 + ID: 33892850-c152-4f8e-a469-0e0b6440cdbc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:20:00+00:00 +---------------------------------------- + +Instruction #288: + Timestep: 287 + Time: 2025-11-04 10:25:00+00:00 + ID: 610ad97b-41f4-44b5-8b85-552d050a5de8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-04 10:25:00+00:00 +---------------------------------------- diff --git a/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_filltarget_only_D=1_B=200_S=30_T=288.txt b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_filltarget_only_D=1_B=200_S=30_T=288.txt new file mode 100644 index 0000000..ab013ac --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_filltarget_only_D=1_B=200_S=30_T=288.txt @@ -0,0 +1,3218 @@ +================================================================================ +ITHO DHW Heat Pump Instructions Filltarget Only +================================================================================ +Planning start time: 2025-11-19 10:00:00+00:00 +Planning window: 1 days 00:00:00 +Resolution: 0 days 00:05:00 +Total timesteps: 288 +================================================================================ + +Device: itho_dhw_device_005 +Number of instructions: 288 +-------------------------------------------------------------------------------- + +Instruction Timeline: +-------------------------------------------------------------------------------- + Mode: DHW_ON + Start: 2025-11-19 10:00:00+00:00 (timestep 0) + Duration: 7 timesteps (35.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-19 10:35:00+00:00 (timestep 7) + Duration: 25 timesteps (125.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-19 12:40:00+00:00 (timestep 32) + Duration: 53 timesteps (265.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-19 17:05:00+00:00 (timestep 85) + Duration: 7 timesteps (35.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-19 17:40:00+00:00 (timestep 92) + Duration: 6 timesteps (30.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-19 18:10:00+00:00 (timestep 98) + Duration: 190 timesteps (950.0 minutes) +---------------------------------------- + +Total operation mode changes: 5 +================================================================================ + +Detailed Instruction List: +================================================================================ + +Instruction #1: + Timestep: 0 + Time: 2025-11-19 10:00:00+00:00 + ID: cca769e9-d53f-4e80-b3b5-acef02920bb7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:00:00+00:00 +---------------------------------------- + +Instruction #2: + Timestep: 1 + Time: 2025-11-19 10:05:00+00:00 + ID: ddeabad5-43a6-4cb9-9ed6-1cd5fe44c016 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:05:00+00:00 +---------------------------------------- + +Instruction #3: + Timestep: 2 + Time: 2025-11-19 10:10:00+00:00 + ID: 2cdb5869-b156-4c88-836a-ad6fcb5ff05e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:10:00+00:00 +---------------------------------------- + +Instruction #4: + Timestep: 3 + Time: 2025-11-19 10:15:00+00:00 + ID: 63c672fb-02ce-4372-afc6-2bc34490d9e3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:15:00+00:00 +---------------------------------------- + +Instruction #5: + Timestep: 4 + Time: 2025-11-19 10:20:00+00:00 + ID: 15cdaaae-67b6-4edb-9ab3-f14a5b6a296f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:20:00+00:00 +---------------------------------------- + +Instruction #6: + Timestep: 5 + Time: 2025-11-19 10:25:00+00:00 + ID: 01bf3db9-e78b-4bad-8302-d3bc05e4412d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:25:00+00:00 +---------------------------------------- + +Instruction #7: + Timestep: 6 + Time: 2025-11-19 10:30:00+00:00 + ID: 19b954f6-f819-45a3-8bf2-950d00e22d17 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:30:00+00:00 +---------------------------------------- + +Instruction #8: + Timestep: 7 + Time: 2025-11-19 10:35:00+00:00 + ID: 3a5c8a64-376f-4055-9864-57706504ce02 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:35:00+00:00 +---------------------------------------- + +Instruction #9: + Timestep: 8 + Time: 2025-11-19 10:40:00+00:00 + ID: f178e768-804e-455d-ba48-f192685e8fd4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:40:00+00:00 +---------------------------------------- + +Instruction #10: + Timestep: 9 + Time: 2025-11-19 10:45:00+00:00 + ID: 723b1efd-160f-47e0-ac40-3cbf327480d7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:45:00+00:00 +---------------------------------------- + +Instruction #11: + Timestep: 10 + Time: 2025-11-19 10:50:00+00:00 + ID: 6f311b75-26d2-498e-82c5-5b38a9560af4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:50:00+00:00 +---------------------------------------- + +Instruction #12: + Timestep: 11 + Time: 2025-11-19 10:55:00+00:00 + ID: 2451a8e4-fdb0-4248-8b46-b2efc7c6d98a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:55:00+00:00 +---------------------------------------- + +Instruction #13: + Timestep: 12 + Time: 2025-11-19 11:00:00+00:00 + ID: 09dae461-e56b-4dc0-a306-cc1a9a154b35 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:00:00+00:00 +---------------------------------------- + +Instruction #14: + Timestep: 13 + Time: 2025-11-19 11:05:00+00:00 + ID: e3fcc514-18a0-447f-9d9b-e5d5031fa0d2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:05:00+00:00 +---------------------------------------- + +Instruction #15: + Timestep: 14 + Time: 2025-11-19 11:10:00+00:00 + ID: 4f9d2a44-bb14-45a4-97b6-df3322c9771a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:10:00+00:00 +---------------------------------------- + +Instruction #16: + Timestep: 15 + Time: 2025-11-19 11:15:00+00:00 + ID: a6a18fba-17fb-46be-87bf-01d5bfc65365 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:15:00+00:00 +---------------------------------------- + +Instruction #17: + Timestep: 16 + Time: 2025-11-19 11:20:00+00:00 + ID: 0b166ef7-cc67-4758-a6cb-0f1c3b32047c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:20:00+00:00 +---------------------------------------- + +Instruction #18: + Timestep: 17 + Time: 2025-11-19 11:25:00+00:00 + ID: 788768f8-e972-4288-8789-e50a78861966 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:25:00+00:00 +---------------------------------------- + +Instruction #19: + Timestep: 18 + Time: 2025-11-19 11:30:00+00:00 + ID: bd1c4fea-4613-4654-9f94-b78e36ec2de3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:30:00+00:00 +---------------------------------------- + +Instruction #20: + Timestep: 19 + Time: 2025-11-19 11:35:00+00:00 + ID: 413f5f3f-d72a-47ed-ac91-098a0621f926 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:35:00+00:00 +---------------------------------------- + +Instruction #21: + Timestep: 20 + Time: 2025-11-19 11:40:00+00:00 + ID: 579d588b-42d7-4260-9505-e7c1ba9749fd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:40:00+00:00 +---------------------------------------- + +Instruction #22: + Timestep: 21 + Time: 2025-11-19 11:45:00+00:00 + ID: 173a52a4-745d-4815-b90c-a36f646db8b5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:45:00+00:00 +---------------------------------------- + +Instruction #23: + Timestep: 22 + Time: 2025-11-19 11:50:00+00:00 + ID: 28b2d057-36ce-4651-aa92-d5029355d581 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:50:00+00:00 +---------------------------------------- + +Instruction #24: + Timestep: 23 + Time: 2025-11-19 11:55:00+00:00 + ID: f2671ccc-d508-44f4-b591-778839d7759b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:55:00+00:00 +---------------------------------------- + +Instruction #25: + Timestep: 24 + Time: 2025-11-19 12:00:00+00:00 + ID: 515883e9-0dcf-42cb-910b-7d6f7f4403a6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:00:00+00:00 +---------------------------------------- + +Instruction #26: + Timestep: 25 + Time: 2025-11-19 12:05:00+00:00 + ID: a90b5ecf-ff59-4a55-8fc5-a7645bcf7bf5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:05:00+00:00 +---------------------------------------- + +Instruction #27: + Timestep: 26 + Time: 2025-11-19 12:10:00+00:00 + ID: e62b7740-ce9f-402c-876f-43afbb347110 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:10:00+00:00 +---------------------------------------- + +Instruction #28: + Timestep: 27 + Time: 2025-11-19 12:15:00+00:00 + ID: 5ddc637b-385f-44ef-ab90-57e996f46270 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:15:00+00:00 +---------------------------------------- + +Instruction #29: + Timestep: 28 + Time: 2025-11-19 12:20:00+00:00 + ID: bdb687c9-1c78-423c-9c15-e846bfa50f6f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:20:00+00:00 +---------------------------------------- + +Instruction #30: + Timestep: 29 + Time: 2025-11-19 12:25:00+00:00 + ID: 5229bf77-0d28-404c-9295-e3c87322c2a6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:25:00+00:00 +---------------------------------------- + +Instruction #31: + Timestep: 30 + Time: 2025-11-19 12:30:00+00:00 + ID: 13b6266f-54cd-41c1-8a78-63edaeb29e91 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:30:00+00:00 +---------------------------------------- + +Instruction #32: + Timestep: 31 + Time: 2025-11-19 12:35:00+00:00 + ID: c05970fb-d717-4e9d-abc5-9b639c3b7cfe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:35:00+00:00 +---------------------------------------- + +Instruction #33: + Timestep: 32 + Time: 2025-11-19 12:40:00+00:00 + ID: 774fd218-bb5a-4331-8b9b-6ff80775b11f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:40:00+00:00 +---------------------------------------- + +Instruction #34: + Timestep: 33 + Time: 2025-11-19 12:45:00+00:00 + ID: 68c2964d-6c38-43cb-a067-5bb58054a988 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:45:00+00:00 +---------------------------------------- + +Instruction #35: + Timestep: 34 + Time: 2025-11-19 12:50:00+00:00 + ID: ab0f453e-e662-4d65-b0c3-04e8d53912e2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:50:00+00:00 +---------------------------------------- + +Instruction #36: + Timestep: 35 + Time: 2025-11-19 12:55:00+00:00 + ID: eefb9164-84d3-420a-be2e-47c8bbe5d703 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:55:00+00:00 +---------------------------------------- + +Instruction #37: + Timestep: 36 + Time: 2025-11-19 13:00:00+00:00 + ID: 8f52e188-bcce-403a-86a0-3327e7121b08 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:00:00+00:00 +---------------------------------------- + +Instruction #38: + Timestep: 37 + Time: 2025-11-19 13:05:00+00:00 + ID: e41cb4b5-5c2b-4604-92ea-fd2b959f19e9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:05:00+00:00 +---------------------------------------- + +Instruction #39: + Timestep: 38 + Time: 2025-11-19 13:10:00+00:00 + ID: afa53aaf-6b71-46ff-b8dc-28f228d64d4f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:10:00+00:00 +---------------------------------------- + +Instruction #40: + Timestep: 39 + Time: 2025-11-19 13:15:00+00:00 + ID: a35a011e-8e1f-47ff-9501-7927829a8a3b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:15:00+00:00 +---------------------------------------- + +Instruction #41: + Timestep: 40 + Time: 2025-11-19 13:20:00+00:00 + ID: 5d947674-877e-4d6a-8509-65b17e954c73 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:20:00+00:00 +---------------------------------------- + +Instruction #42: + Timestep: 41 + Time: 2025-11-19 13:25:00+00:00 + ID: 12d85158-e038-41ba-96b8-d36a807162a7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:25:00+00:00 +---------------------------------------- + +Instruction #43: + Timestep: 42 + Time: 2025-11-19 13:30:00+00:00 + ID: 1dc0457d-f4c8-4c73-8d8a-9f5d2162fe2e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:30:00+00:00 +---------------------------------------- + +Instruction #44: + Timestep: 43 + Time: 2025-11-19 13:35:00+00:00 + ID: cf1f223b-458f-4b50-87f8-81f1dab76d37 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:35:00+00:00 +---------------------------------------- + +Instruction #45: + Timestep: 44 + Time: 2025-11-19 13:40:00+00:00 + ID: fe20efd4-104d-4e08-8366-25d8b3cffe40 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:40:00+00:00 +---------------------------------------- + +Instruction #46: + Timestep: 45 + Time: 2025-11-19 13:45:00+00:00 + ID: e0737971-4c35-4b74-949b-e4b48eda300d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:45:00+00:00 +---------------------------------------- + +Instruction #47: + Timestep: 46 + Time: 2025-11-19 13:50:00+00:00 + ID: 46e89ce3-ec2d-475d-909f-51393dab49a0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:50:00+00:00 +---------------------------------------- + +Instruction #48: + Timestep: 47 + Time: 2025-11-19 13:55:00+00:00 + ID: 2bb59cb8-aa61-437e-8ad2-89a213574b2b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:55:00+00:00 +---------------------------------------- + +Instruction #49: + Timestep: 48 + Time: 2025-11-19 14:00:00+00:00 + ID: fe377764-4ac2-4f79-87a5-983f2a1ad8db + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:00:00+00:00 +---------------------------------------- + +Instruction #50: + Timestep: 49 + Time: 2025-11-19 14:05:00+00:00 + ID: 3c6930f1-43b1-4fc2-ab28-18c0a97f576e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:05:00+00:00 +---------------------------------------- + +Instruction #51: + Timestep: 50 + Time: 2025-11-19 14:10:00+00:00 + ID: 8e6cb726-7305-4841-84d0-d123dfea9d7c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:10:00+00:00 +---------------------------------------- + +Instruction #52: + Timestep: 51 + Time: 2025-11-19 14:15:00+00:00 + ID: 72bf6210-844e-4e5e-83d8-fee38ef88a88 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:15:00+00:00 +---------------------------------------- + +Instruction #53: + Timestep: 52 + Time: 2025-11-19 14:20:00+00:00 + ID: b30316ba-5715-49f9-b1eb-19ed3bab448a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:20:00+00:00 +---------------------------------------- + +Instruction #54: + Timestep: 53 + Time: 2025-11-19 14:25:00+00:00 + ID: 4c1dec9e-1b66-471a-a924-cfb3213bc35a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:25:00+00:00 +---------------------------------------- + +Instruction #55: + Timestep: 54 + Time: 2025-11-19 14:30:00+00:00 + ID: fa0fa8a6-8552-4e02-bf74-191fdede17f9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:30:00+00:00 +---------------------------------------- + +Instruction #56: + Timestep: 55 + Time: 2025-11-19 14:35:00+00:00 + ID: b760fdd9-f574-490a-af1b-661b0bdff2c7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:35:00+00:00 +---------------------------------------- + +Instruction #57: + Timestep: 56 + Time: 2025-11-19 14:40:00+00:00 + ID: dd2a4c9d-5ec2-40ac-9805-2cb2207c534e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:40:00+00:00 +---------------------------------------- + +Instruction #58: + Timestep: 57 + Time: 2025-11-19 14:45:00+00:00 + ID: a9a9c3af-ff19-44ed-bb55-ced2297c0cdf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:45:00+00:00 +---------------------------------------- + +Instruction #59: + Timestep: 58 + Time: 2025-11-19 14:50:00+00:00 + ID: ecfae9e6-f25e-4872-be52-464727cf0e66 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:50:00+00:00 +---------------------------------------- + +Instruction #60: + Timestep: 59 + Time: 2025-11-19 14:55:00+00:00 + ID: 9b13794f-6728-4658-a211-cc6101cfc172 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:55:00+00:00 +---------------------------------------- + +Instruction #61: + Timestep: 60 + Time: 2025-11-19 15:00:00+00:00 + ID: 01e0e254-3200-472b-a67b-5245e57f2afd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:00:00+00:00 +---------------------------------------- + +Instruction #62: + Timestep: 61 + Time: 2025-11-19 15:05:00+00:00 + ID: cf4bf369-5685-49ec-bee4-4ba106c3b1c4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:05:00+00:00 +---------------------------------------- + +Instruction #63: + Timestep: 62 + Time: 2025-11-19 15:10:00+00:00 + ID: 5e2a706f-1d43-4418-b7d9-69c29a511412 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:10:00+00:00 +---------------------------------------- + +Instruction #64: + Timestep: 63 + Time: 2025-11-19 15:15:00+00:00 + ID: a4d21b32-e5b1-4b5f-abd0-3acc7919aaae + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:15:00+00:00 +---------------------------------------- + +Instruction #65: + Timestep: 64 + Time: 2025-11-19 15:20:00+00:00 + ID: 4980f494-e488-45a8-859f-0c8649a6ecf0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:20:00+00:00 +---------------------------------------- + +Instruction #66: + Timestep: 65 + Time: 2025-11-19 15:25:00+00:00 + ID: b0c69a30-6183-428b-85c0-294c1ddf522c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:25:00+00:00 +---------------------------------------- + +Instruction #67: + Timestep: 66 + Time: 2025-11-19 15:30:00+00:00 + ID: 79d9a30d-c087-4ae8-af6a-4c30d7c5d41e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:30:00+00:00 +---------------------------------------- + +Instruction #68: + Timestep: 67 + Time: 2025-11-19 15:35:00+00:00 + ID: 3d0789a2-0560-49aa-833b-731ab6b659d7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:35:00+00:00 +---------------------------------------- + +Instruction #69: + Timestep: 68 + Time: 2025-11-19 15:40:00+00:00 + ID: d4be47ef-ce21-42cd-a353-57431a72c54e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:40:00+00:00 +---------------------------------------- + +Instruction #70: + Timestep: 69 + Time: 2025-11-19 15:45:00+00:00 + ID: b56e0880-9225-4598-8682-bfe4fb9e9f7b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:45:00+00:00 +---------------------------------------- + +Instruction #71: + Timestep: 70 + Time: 2025-11-19 15:50:00+00:00 + ID: aa3002b0-9bbe-4cb9-ab9f-c21c6b1418fe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:50:00+00:00 +---------------------------------------- + +Instruction #72: + Timestep: 71 + Time: 2025-11-19 15:55:00+00:00 + ID: 5739b9e9-e188-406d-b33a-c788bdb20dfb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:55:00+00:00 +---------------------------------------- + +Instruction #73: + Timestep: 72 + Time: 2025-11-19 16:00:00+00:00 + ID: dafd175e-1780-41ad-9a69-035ca94d5ffb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:00:00+00:00 +---------------------------------------- + +Instruction #74: + Timestep: 73 + Time: 2025-11-19 16:05:00+00:00 + ID: c1fba3a6-a0fa-415b-953f-688cf8505ec1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:05:00+00:00 +---------------------------------------- + +Instruction #75: + Timestep: 74 + Time: 2025-11-19 16:10:00+00:00 + ID: 60f856d0-0866-43ef-80af-9c42eb3e923a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:10:00+00:00 +---------------------------------------- + +Instruction #76: + Timestep: 75 + Time: 2025-11-19 16:15:00+00:00 + ID: f34ad8e9-dfdb-45b1-b42c-f32b824ec324 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:15:00+00:00 +---------------------------------------- + +Instruction #77: + Timestep: 76 + Time: 2025-11-19 16:20:00+00:00 + ID: 8ec5c67a-6866-4b35-ada8-6e1826c0ad5f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:20:00+00:00 +---------------------------------------- + +Instruction #78: + Timestep: 77 + Time: 2025-11-19 16:25:00+00:00 + ID: feccaee2-2b3c-4ab2-9616-ad4811904fde + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:25:00+00:00 +---------------------------------------- + +Instruction #79: + Timestep: 78 + Time: 2025-11-19 16:30:00+00:00 + ID: a739b40d-3147-4bf3-bc65-b9df1c0849fc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:30:00+00:00 +---------------------------------------- + +Instruction #80: + Timestep: 79 + Time: 2025-11-19 16:35:00+00:00 + ID: 6c788ed8-7844-4c18-9f91-0f4b1feaa83f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:35:00+00:00 +---------------------------------------- + +Instruction #81: + Timestep: 80 + Time: 2025-11-19 16:40:00+00:00 + ID: ed8b6e3f-1d6b-49fb-bd52-53e51821b7e5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:40:00+00:00 +---------------------------------------- + +Instruction #82: + Timestep: 81 + Time: 2025-11-19 16:45:00+00:00 + ID: 7ec07b7d-d146-44d8-879a-63313d8cea41 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:45:00+00:00 +---------------------------------------- + +Instruction #83: + Timestep: 82 + Time: 2025-11-19 16:50:00+00:00 + ID: dcc4a1be-e021-44df-9bd4-5fd72cfbe393 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:50:00+00:00 +---------------------------------------- + +Instruction #84: + Timestep: 83 + Time: 2025-11-19 16:55:00+00:00 + ID: b3e437b1-8e65-461b-ac01-b9659ddeec13 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:55:00+00:00 +---------------------------------------- + +Instruction #85: + Timestep: 84 + Time: 2025-11-19 17:00:00+00:00 + ID: 4cc72c9c-9939-4e70-b1a2-9d9afa6e0f2e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:00:00+00:00 +---------------------------------------- + +Instruction #86: + Timestep: 85 + Time: 2025-11-19 17:05:00+00:00 + ID: f1324c66-803a-4348-ad90-fb33ccc1c10c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:05:00+00:00 +---------------------------------------- + +Instruction #87: + Timestep: 86 + Time: 2025-11-19 17:10:00+00:00 + ID: 15ae7371-ecf9-4679-89bb-38505b30b2d7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:10:00+00:00 +---------------------------------------- + +Instruction #88: + Timestep: 87 + Time: 2025-11-19 17:15:00+00:00 + ID: 6f345862-930f-4c33-8061-197f9c4fc4bc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:15:00+00:00 +---------------------------------------- + +Instruction #89: + Timestep: 88 + Time: 2025-11-19 17:20:00+00:00 + ID: 389ffb93-a214-4054-852f-107a96f113c3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:20:00+00:00 +---------------------------------------- + +Instruction #90: + Timestep: 89 + Time: 2025-11-19 17:25:00+00:00 + ID: 0443e3b9-402e-4d75-9157-d310348c358d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:25:00+00:00 +---------------------------------------- + +Instruction #91: + Timestep: 90 + Time: 2025-11-19 17:30:00+00:00 + ID: a5d2b9da-a963-4fb0-943e-171a67319700 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:30:00+00:00 +---------------------------------------- + +Instruction #92: + Timestep: 91 + Time: 2025-11-19 17:35:00+00:00 + ID: 724456d8-12b9-410f-8a4c-f1b7149f8789 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:35:00+00:00 +---------------------------------------- + +Instruction #93: + Timestep: 92 + Time: 2025-11-19 17:40:00+00:00 + ID: 00305d0a-b0bc-4e0a-b78c-29e894bbc710 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:40:00+00:00 +---------------------------------------- + +Instruction #94: + Timestep: 93 + Time: 2025-11-19 17:45:00+00:00 + ID: 7948c68a-2b56-4dd1-a160-b62bd38bbc05 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:45:00+00:00 +---------------------------------------- + +Instruction #95: + Timestep: 94 + Time: 2025-11-19 17:50:00+00:00 + ID: 42692dd6-17e4-4ff4-8bd1-135e0fc92950 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:50:00+00:00 +---------------------------------------- + +Instruction #96: + Timestep: 95 + Time: 2025-11-19 17:55:00+00:00 + ID: 095b3741-8605-4522-8d17-f09b942bde6f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:55:00+00:00 +---------------------------------------- + +Instruction #97: + Timestep: 96 + Time: 2025-11-19 18:00:00+00:00 + ID: 631b32b2-77d6-4acc-9daa-3026f5ef6f1f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:00:00+00:00 +---------------------------------------- + +Instruction #98: + Timestep: 97 + Time: 2025-11-19 18:05:00+00:00 + ID: ae63f82e-4e15-418a-b2d3-e42376a36781 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:05:00+00:00 +---------------------------------------- + +Instruction #99: + Timestep: 98 + Time: 2025-11-19 18:10:00+00:00 + ID: 407df5db-4b82-4368-b698-ecb2782caca5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:10:00+00:00 +---------------------------------------- + +Instruction #100: + Timestep: 99 + Time: 2025-11-19 18:15:00+00:00 + ID: b026012a-4238-424a-a9ae-ccbf20f135d5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:15:00+00:00 +---------------------------------------- + +Instruction #101: + Timestep: 100 + Time: 2025-11-19 18:20:00+00:00 + ID: 803b27a9-d64d-4771-a985-d3debb0e24f3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:20:00+00:00 +---------------------------------------- + +Instruction #102: + Timestep: 101 + Time: 2025-11-19 18:25:00+00:00 + ID: 901adf12-95f5-48a9-8e50-927ebf1f0da1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:25:00+00:00 +---------------------------------------- + +Instruction #103: + Timestep: 102 + Time: 2025-11-19 18:30:00+00:00 + ID: 78be0c7e-9810-4427-9d60-f36438682029 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:30:00+00:00 +---------------------------------------- + +Instruction #104: + Timestep: 103 + Time: 2025-11-19 18:35:00+00:00 + ID: 7a290227-eeb9-4816-952c-91f036f253c0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:35:00+00:00 +---------------------------------------- + +Instruction #105: + Timestep: 104 + Time: 2025-11-19 18:40:00+00:00 + ID: 927a70ef-e6a9-4875-99f6-206d03cb1dd0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:40:00+00:00 +---------------------------------------- + +Instruction #106: + Timestep: 105 + Time: 2025-11-19 18:45:00+00:00 + ID: 034c9b08-696e-4663-a03b-cc9aa441a95d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:45:00+00:00 +---------------------------------------- + +Instruction #107: + Timestep: 106 + Time: 2025-11-19 18:50:00+00:00 + ID: cac4889e-de08-45b0-8795-8f05820f22b6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:50:00+00:00 +---------------------------------------- + +Instruction #108: + Timestep: 107 + Time: 2025-11-19 18:55:00+00:00 + ID: cfbf031d-f332-487c-ad0f-5507d2a133c5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:55:00+00:00 +---------------------------------------- + +Instruction #109: + Timestep: 108 + Time: 2025-11-19 19:00:00+00:00 + ID: 9ed1e178-1108-419a-b460-131ceb640cf8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:00:00+00:00 +---------------------------------------- + +Instruction #110: + Timestep: 109 + Time: 2025-11-19 19:05:00+00:00 + ID: ab85b788-5f5f-442c-9076-866114148e4d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:05:00+00:00 +---------------------------------------- + +Instruction #111: + Timestep: 110 + Time: 2025-11-19 19:10:00+00:00 + ID: 7ec8d1d3-ff0c-469c-bf0d-4918e4d2f2e5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:10:00+00:00 +---------------------------------------- + +Instruction #112: + Timestep: 111 + Time: 2025-11-19 19:15:00+00:00 + ID: 33a18bad-1a27-4b8e-bdeb-0912f0edea6b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:15:00+00:00 +---------------------------------------- + +Instruction #113: + Timestep: 112 + Time: 2025-11-19 19:20:00+00:00 + ID: 5e461372-0662-40ba-88c8-147d6aa8f182 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:20:00+00:00 +---------------------------------------- + +Instruction #114: + Timestep: 113 + Time: 2025-11-19 19:25:00+00:00 + ID: 2e4dde51-929f-46e5-be45-42f1b2276f4b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:25:00+00:00 +---------------------------------------- + +Instruction #115: + Timestep: 114 + Time: 2025-11-19 19:30:00+00:00 + ID: 69a55912-ee12-40f2-ad5c-23740ae14b20 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:30:00+00:00 +---------------------------------------- + +Instruction #116: + Timestep: 115 + Time: 2025-11-19 19:35:00+00:00 + ID: 35bd807f-2a97-4566-ac0f-2af8f1daf3d3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:35:00+00:00 +---------------------------------------- + +Instruction #117: + Timestep: 116 + Time: 2025-11-19 19:40:00+00:00 + ID: 01ec4530-8b72-4875-97a9-7de3815eab05 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:40:00+00:00 +---------------------------------------- + +Instruction #118: + Timestep: 117 + Time: 2025-11-19 19:45:00+00:00 + ID: 36dbc46e-2ed3-4a21-a996-1408d4fbabb6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:45:00+00:00 +---------------------------------------- + +Instruction #119: + Timestep: 118 + Time: 2025-11-19 19:50:00+00:00 + ID: c058409e-bcc3-44ee-8b35-475af162a906 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:50:00+00:00 +---------------------------------------- + +Instruction #120: + Timestep: 119 + Time: 2025-11-19 19:55:00+00:00 + ID: 85d3734a-8fd3-4551-a735-e4a12f87236d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:55:00+00:00 +---------------------------------------- + +Instruction #121: + Timestep: 120 + Time: 2025-11-19 20:00:00+00:00 + ID: 92bce3ab-0c16-43ea-8f0f-2e9bee537402 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:00:00+00:00 +---------------------------------------- + +Instruction #122: + Timestep: 121 + Time: 2025-11-19 20:05:00+00:00 + ID: 6d5055a3-2bee-4dd8-a1c9-f16076a8b32e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:05:00+00:00 +---------------------------------------- + +Instruction #123: + Timestep: 122 + Time: 2025-11-19 20:10:00+00:00 + ID: a4b836a6-7767-4bc8-9c7c-473733df640d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:10:00+00:00 +---------------------------------------- + +Instruction #124: + Timestep: 123 + Time: 2025-11-19 20:15:00+00:00 + ID: 61d50ab3-bb1e-4f84-ad58-3820dd47bdf1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:15:00+00:00 +---------------------------------------- + +Instruction #125: + Timestep: 124 + Time: 2025-11-19 20:20:00+00:00 + ID: f5057804-a544-4479-a298-9ee63c58e8d8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:20:00+00:00 +---------------------------------------- + +Instruction #126: + Timestep: 125 + Time: 2025-11-19 20:25:00+00:00 + ID: 2be36061-309a-4611-9cf8-43438b39d496 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:25:00+00:00 +---------------------------------------- + +Instruction #127: + Timestep: 126 + Time: 2025-11-19 20:30:00+00:00 + ID: e812a3b3-8e26-4699-9081-8419e38e3261 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:30:00+00:00 +---------------------------------------- + +Instruction #128: + Timestep: 127 + Time: 2025-11-19 20:35:00+00:00 + ID: 0b3179dc-8d6a-4d2a-a155-a892ee6497ce + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:35:00+00:00 +---------------------------------------- + +Instruction #129: + Timestep: 128 + Time: 2025-11-19 20:40:00+00:00 + ID: b9035e27-884c-41c0-ad46-8379d49e97b6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:40:00+00:00 +---------------------------------------- + +Instruction #130: + Timestep: 129 + Time: 2025-11-19 20:45:00+00:00 + ID: cb40cb64-0ab0-422b-aa0f-621c8b681015 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:45:00+00:00 +---------------------------------------- + +Instruction #131: + Timestep: 130 + Time: 2025-11-19 20:50:00+00:00 + ID: 146a2acc-ae78-404f-90ba-8e270101ef05 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:50:00+00:00 +---------------------------------------- + +Instruction #132: + Timestep: 131 + Time: 2025-11-19 20:55:00+00:00 + ID: 26934c57-e9d0-4724-97fa-2bbe7a4beecf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:55:00+00:00 +---------------------------------------- + +Instruction #133: + Timestep: 132 + Time: 2025-11-19 21:00:00+00:00 + ID: b5d44fac-ce73-456e-864d-e27449666098 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:00:00+00:00 +---------------------------------------- + +Instruction #134: + Timestep: 133 + Time: 2025-11-19 21:05:00+00:00 + ID: 2403af44-fc07-4f97-88cb-2ceff410951e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:05:00+00:00 +---------------------------------------- + +Instruction #135: + Timestep: 134 + Time: 2025-11-19 21:10:00+00:00 + ID: f63d55bf-0bee-41c4-8e93-2c493ac9962b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:10:00+00:00 +---------------------------------------- + +Instruction #136: + Timestep: 135 + Time: 2025-11-19 21:15:00+00:00 + ID: bcd63a41-b375-4f62-b513-96839852c33d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:15:00+00:00 +---------------------------------------- + +Instruction #137: + Timestep: 136 + Time: 2025-11-19 21:20:00+00:00 + ID: 05b28cc0-b4b4-423e-aa2d-f6e976b961c4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:20:00+00:00 +---------------------------------------- + +Instruction #138: + Timestep: 137 + Time: 2025-11-19 21:25:00+00:00 + ID: 6f194b71-f80f-4bdf-b143-b9f1550b5360 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:25:00+00:00 +---------------------------------------- + +Instruction #139: + Timestep: 138 + Time: 2025-11-19 21:30:00+00:00 + ID: e3df84ce-ea85-42dd-93d4-e38a2fde2296 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:30:00+00:00 +---------------------------------------- + +Instruction #140: + Timestep: 139 + Time: 2025-11-19 21:35:00+00:00 + ID: ce5d749b-7fcf-44d0-8adb-12ed7662e72b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:35:00+00:00 +---------------------------------------- + +Instruction #141: + Timestep: 140 + Time: 2025-11-19 21:40:00+00:00 + ID: 07f86d66-2a46-46f6-a989-0482dea67064 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:40:00+00:00 +---------------------------------------- + +Instruction #142: + Timestep: 141 + Time: 2025-11-19 21:45:00+00:00 + ID: 93c4ce73-6805-41f9-850a-90c6e4501ed1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:45:00+00:00 +---------------------------------------- + +Instruction #143: + Timestep: 142 + Time: 2025-11-19 21:50:00+00:00 + ID: ff2af496-efb4-4c6f-a0bb-9e7495c456d6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:50:00+00:00 +---------------------------------------- + +Instruction #144: + Timestep: 143 + Time: 2025-11-19 21:55:00+00:00 + ID: 2eaa33ff-07e2-4940-9ea7-55a3384ca827 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:55:00+00:00 +---------------------------------------- + +Instruction #145: + Timestep: 144 + Time: 2025-11-19 22:00:00+00:00 + ID: 56f7c606-4d74-4577-adb7-3701ea38118c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:00:00+00:00 +---------------------------------------- + +Instruction #146: + Timestep: 145 + Time: 2025-11-19 22:05:00+00:00 + ID: 1c64bc95-2aec-43df-89f5-e9ee03473796 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:05:00+00:00 +---------------------------------------- + +Instruction #147: + Timestep: 146 + Time: 2025-11-19 22:10:00+00:00 + ID: c8c6433b-2820-4d9c-9879-c5563f542030 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:10:00+00:00 +---------------------------------------- + +Instruction #148: + Timestep: 147 + Time: 2025-11-19 22:15:00+00:00 + ID: 42a66fa3-2c42-454a-9724-488027355580 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:15:00+00:00 +---------------------------------------- + +Instruction #149: + Timestep: 148 + Time: 2025-11-19 22:20:00+00:00 + ID: 3748f427-6d64-4572-bb00-6b453b697df2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:20:00+00:00 +---------------------------------------- + +Instruction #150: + Timestep: 149 + Time: 2025-11-19 22:25:00+00:00 + ID: 3f5440ea-071e-4428-a880-3b07047ae281 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:25:00+00:00 +---------------------------------------- + +Instruction #151: + Timestep: 150 + Time: 2025-11-19 22:30:00+00:00 + ID: ffe9d2ba-f0ea-47f7-92e5-28e50752dff2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:30:00+00:00 +---------------------------------------- + +Instruction #152: + Timestep: 151 + Time: 2025-11-19 22:35:00+00:00 + ID: 440e157b-bae8-464f-b116-32b11b14889d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:35:00+00:00 +---------------------------------------- + +Instruction #153: + Timestep: 152 + Time: 2025-11-19 22:40:00+00:00 + ID: 723ace7e-dc13-4a4e-96cc-65f8d87bbbc5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:40:00+00:00 +---------------------------------------- + +Instruction #154: + Timestep: 153 + Time: 2025-11-19 22:45:00+00:00 + ID: d20998b4-eb9a-47d3-9fe3-f496fcaf9e8c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:45:00+00:00 +---------------------------------------- + +Instruction #155: + Timestep: 154 + Time: 2025-11-19 22:50:00+00:00 + ID: 6b00bbc8-e1fe-4100-8a41-e60bf5829883 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:50:00+00:00 +---------------------------------------- + +Instruction #156: + Timestep: 155 + Time: 2025-11-19 22:55:00+00:00 + ID: 4df02ebc-5ffa-4b39-8888-676d18e99a9b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:55:00+00:00 +---------------------------------------- + +Instruction #157: + Timestep: 156 + Time: 2025-11-19 23:00:00+00:00 + ID: d5c8b139-36a9-4721-b692-0d0a625ce42d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:00:00+00:00 +---------------------------------------- + +Instruction #158: + Timestep: 157 + Time: 2025-11-19 23:05:00+00:00 + ID: d401f481-73ab-44d0-b413-fc29acb76922 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:05:00+00:00 +---------------------------------------- + +Instruction #159: + Timestep: 158 + Time: 2025-11-19 23:10:00+00:00 + ID: aad8cd17-858b-4fe9-87fd-13af65dcaac4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:10:00+00:00 +---------------------------------------- + +Instruction #160: + Timestep: 159 + Time: 2025-11-19 23:15:00+00:00 + ID: 98a3ed11-bd56-46a5-ac5f-b32419e673ac + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:15:00+00:00 +---------------------------------------- + +Instruction #161: + Timestep: 160 + Time: 2025-11-19 23:20:00+00:00 + ID: 55d88eec-ddc7-4a77-a8ab-60743df96c4a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:20:00+00:00 +---------------------------------------- + +Instruction #162: + Timestep: 161 + Time: 2025-11-19 23:25:00+00:00 + ID: b11d4779-55de-473b-8762-50e156a6cd70 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:25:00+00:00 +---------------------------------------- + +Instruction #163: + Timestep: 162 + Time: 2025-11-19 23:30:00+00:00 + ID: 2e749bef-bbfc-42ea-abaa-8ac9757af31e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:30:00+00:00 +---------------------------------------- + +Instruction #164: + Timestep: 163 + Time: 2025-11-19 23:35:00+00:00 + ID: 1fb75821-072c-449b-8fb2-41bbc174f6a5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:35:00+00:00 +---------------------------------------- + +Instruction #165: + Timestep: 164 + Time: 2025-11-19 23:40:00+00:00 + ID: c5aa0d82-fe72-48d6-99bf-6dd2897e3e0c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:40:00+00:00 +---------------------------------------- + +Instruction #166: + Timestep: 165 + Time: 2025-11-19 23:45:00+00:00 + ID: 3e77957f-c0af-4acf-b443-238c05cf256b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:45:00+00:00 +---------------------------------------- + +Instruction #167: + Timestep: 166 + Time: 2025-11-19 23:50:00+00:00 + ID: bd239563-bd68-4498-9b51-482bf978a807 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:50:00+00:00 +---------------------------------------- + +Instruction #168: + Timestep: 167 + Time: 2025-11-19 23:55:00+00:00 + ID: 585e91f1-865f-4498-a0d8-e27e878ab820 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:55:00+00:00 +---------------------------------------- + +Instruction #169: + Timestep: 168 + Time: 2025-11-20 00:00:00+00:00 + ID: 5d18a339-cb42-4aba-aadf-50a23362f9f7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:00:00+00:00 +---------------------------------------- + +Instruction #170: + Timestep: 169 + Time: 2025-11-20 00:05:00+00:00 + ID: a0dad660-892e-441f-9950-479f40939605 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:05:00+00:00 +---------------------------------------- + +Instruction #171: + Timestep: 170 + Time: 2025-11-20 00:10:00+00:00 + ID: 77c9b34f-1dd0-4633-ab91-35d09fe6edd0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:10:00+00:00 +---------------------------------------- + +Instruction #172: + Timestep: 171 + Time: 2025-11-20 00:15:00+00:00 + ID: ba5e4a22-c565-4e76-8e9f-453ce97546a5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:15:00+00:00 +---------------------------------------- + +Instruction #173: + Timestep: 172 + Time: 2025-11-20 00:20:00+00:00 + ID: e0725995-cda6-4b94-b2ef-e65674f1e159 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:20:00+00:00 +---------------------------------------- + +Instruction #174: + Timestep: 173 + Time: 2025-11-20 00:25:00+00:00 + ID: ef0e5de9-698d-469c-aded-e4cc9c8f6495 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:25:00+00:00 +---------------------------------------- + +Instruction #175: + Timestep: 174 + Time: 2025-11-20 00:30:00+00:00 + ID: cb8db03e-0da1-45bf-abd7-2b3e0c2373e3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:30:00+00:00 +---------------------------------------- + +Instruction #176: + Timestep: 175 + Time: 2025-11-20 00:35:00+00:00 + ID: 89d1f492-82ab-4589-a14a-434a33fb730c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:35:00+00:00 +---------------------------------------- + +Instruction #177: + Timestep: 176 + Time: 2025-11-20 00:40:00+00:00 + ID: 4fd2f06b-4866-4db4-85d6-9eccee09a5b2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:40:00+00:00 +---------------------------------------- + +Instruction #178: + Timestep: 177 + Time: 2025-11-20 00:45:00+00:00 + ID: 7149a94b-42bd-4551-b120-f868a618d660 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:45:00+00:00 +---------------------------------------- + +Instruction #179: + Timestep: 178 + Time: 2025-11-20 00:50:00+00:00 + ID: feb713d3-2e40-4027-a5d3-7422f011cdb7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:50:00+00:00 +---------------------------------------- + +Instruction #180: + Timestep: 179 + Time: 2025-11-20 00:55:00+00:00 + ID: f0464679-c3fa-411e-839f-c323410fec6f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:55:00+00:00 +---------------------------------------- + +Instruction #181: + Timestep: 180 + Time: 2025-11-20 01:00:00+00:00 + ID: 203d7ffc-1808-44cc-8e85-0801f9e3efd1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:00:00+00:00 +---------------------------------------- + +Instruction #182: + Timestep: 181 + Time: 2025-11-20 01:05:00+00:00 + ID: d3ea4358-62f6-40db-95a0-216dd5adcfd4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:05:00+00:00 +---------------------------------------- + +Instruction #183: + Timestep: 182 + Time: 2025-11-20 01:10:00+00:00 + ID: edaec515-d7ad-401a-bc22-ffd305ed7695 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:10:00+00:00 +---------------------------------------- + +Instruction #184: + Timestep: 183 + Time: 2025-11-20 01:15:00+00:00 + ID: 3466819d-9770-4719-a6f8-ed0df52a7f38 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:15:00+00:00 +---------------------------------------- + +Instruction #185: + Timestep: 184 + Time: 2025-11-20 01:20:00+00:00 + ID: 808c1d0f-7e5d-4b3d-96de-f9a0811b8826 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:20:00+00:00 +---------------------------------------- + +Instruction #186: + Timestep: 185 + Time: 2025-11-20 01:25:00+00:00 + ID: 614af99a-52ba-4ab3-98a4-a571c4fd11ec + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:25:00+00:00 +---------------------------------------- + +Instruction #187: + Timestep: 186 + Time: 2025-11-20 01:30:00+00:00 + ID: 94ef6fc0-d19b-424f-b642-a78afcc32c6f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:30:00+00:00 +---------------------------------------- + +Instruction #188: + Timestep: 187 + Time: 2025-11-20 01:35:00+00:00 + ID: 07fd219f-d127-4ef1-b414-1331e23da7e5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:35:00+00:00 +---------------------------------------- + +Instruction #189: + Timestep: 188 + Time: 2025-11-20 01:40:00+00:00 + ID: 6a1c8dab-3967-4193-8aaf-ae6a5cbe0247 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:40:00+00:00 +---------------------------------------- + +Instruction #190: + Timestep: 189 + Time: 2025-11-20 01:45:00+00:00 + ID: 575dd889-1c48-416c-9dce-978a66366324 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:45:00+00:00 +---------------------------------------- + +Instruction #191: + Timestep: 190 + Time: 2025-11-20 01:50:00+00:00 + ID: 59048ff7-8c64-455b-8393-33bd65eff843 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:50:00+00:00 +---------------------------------------- + +Instruction #192: + Timestep: 191 + Time: 2025-11-20 01:55:00+00:00 + ID: f438d6c6-11a3-44c1-b83e-ef006fe0a5c7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:55:00+00:00 +---------------------------------------- + +Instruction #193: + Timestep: 192 + Time: 2025-11-20 02:00:00+00:00 + ID: 86bf1792-448c-463b-ac95-27e10e0493e9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:00:00+00:00 +---------------------------------------- + +Instruction #194: + Timestep: 193 + Time: 2025-11-20 02:05:00+00:00 + ID: 84c5f5b2-94f7-4923-9ddd-1c2151bbcfd2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:05:00+00:00 +---------------------------------------- + +Instruction #195: + Timestep: 194 + Time: 2025-11-20 02:10:00+00:00 + ID: 3c7145d4-d0a0-4329-aa1e-0a9027db1501 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:10:00+00:00 +---------------------------------------- + +Instruction #196: + Timestep: 195 + Time: 2025-11-20 02:15:00+00:00 + ID: 4ee3c2a0-e5c5-4ded-a81c-618ba6afdf65 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:15:00+00:00 +---------------------------------------- + +Instruction #197: + Timestep: 196 + Time: 2025-11-20 02:20:00+00:00 + ID: 554ca15a-9d19-4f74-b93d-524c1c4017d8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:20:00+00:00 +---------------------------------------- + +Instruction #198: + Timestep: 197 + Time: 2025-11-20 02:25:00+00:00 + ID: 3c0c7045-0bbc-4545-85e7-5b6b4a55d89b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:25:00+00:00 +---------------------------------------- + +Instruction #199: + Timestep: 198 + Time: 2025-11-20 02:30:00+00:00 + ID: 447a31ba-3aed-4439-829b-72a41205d1d7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:30:00+00:00 +---------------------------------------- + +Instruction #200: + Timestep: 199 + Time: 2025-11-20 02:35:00+00:00 + ID: b8356de4-d80b-4533-8584-248756b49f44 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:35:00+00:00 +---------------------------------------- + +Instruction #201: + Timestep: 200 + Time: 2025-11-20 02:40:00+00:00 + ID: f250c9ff-6cb6-47b3-bf7d-01bdf98b4d70 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:40:00+00:00 +---------------------------------------- + +Instruction #202: + Timestep: 201 + Time: 2025-11-20 02:45:00+00:00 + ID: b8fb013e-ec61-481c-b717-7bb8839d416d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:45:00+00:00 +---------------------------------------- + +Instruction #203: + Timestep: 202 + Time: 2025-11-20 02:50:00+00:00 + ID: 31354d50-b08c-4ae8-8c97-8fc219542103 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:50:00+00:00 +---------------------------------------- + +Instruction #204: + Timestep: 203 + Time: 2025-11-20 02:55:00+00:00 + ID: d3c8f9a9-53dc-44de-a24c-6ef8c637d818 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:55:00+00:00 +---------------------------------------- + +Instruction #205: + Timestep: 204 + Time: 2025-11-20 03:00:00+00:00 + ID: 2a951855-ae73-4fa7-a7a7-909768dd9ee1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:00:00+00:00 +---------------------------------------- + +Instruction #206: + Timestep: 205 + Time: 2025-11-20 03:05:00+00:00 + ID: e7bea64c-9610-4a7c-a4e0-5d0e5f15a041 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:05:00+00:00 +---------------------------------------- + +Instruction #207: + Timestep: 206 + Time: 2025-11-20 03:10:00+00:00 + ID: ba7ee545-8361-4409-8220-e3745593795f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:10:00+00:00 +---------------------------------------- + +Instruction #208: + Timestep: 207 + Time: 2025-11-20 03:15:00+00:00 + ID: a741032e-737f-4390-97ef-7fce241b7463 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:15:00+00:00 +---------------------------------------- + +Instruction #209: + Timestep: 208 + Time: 2025-11-20 03:20:00+00:00 + ID: 38809127-be9c-4bdb-ac74-12b80f3317aa + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:20:00+00:00 +---------------------------------------- + +Instruction #210: + Timestep: 209 + Time: 2025-11-20 03:25:00+00:00 + ID: d8f398de-9257-4d18-9415-3ed41786c845 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:25:00+00:00 +---------------------------------------- + +Instruction #211: + Timestep: 210 + Time: 2025-11-20 03:30:00+00:00 + ID: f805a453-9766-46c9-a54f-89bfb2353628 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:30:00+00:00 +---------------------------------------- + +Instruction #212: + Timestep: 211 + Time: 2025-11-20 03:35:00+00:00 + ID: c0faf3a1-899c-4b30-be0c-6de50e226b8e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:35:00+00:00 +---------------------------------------- + +Instruction #213: + Timestep: 212 + Time: 2025-11-20 03:40:00+00:00 + ID: 4939a2ff-2d56-4fcb-98dd-5c4f53d3949f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:40:00+00:00 +---------------------------------------- + +Instruction #214: + Timestep: 213 + Time: 2025-11-20 03:45:00+00:00 + ID: 9830ecc4-8e59-4652-b50f-3e4e3aaea52b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:45:00+00:00 +---------------------------------------- + +Instruction #215: + Timestep: 214 + Time: 2025-11-20 03:50:00+00:00 + ID: afc37158-3292-470e-a8b3-e76670036b04 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:50:00+00:00 +---------------------------------------- + +Instruction #216: + Timestep: 215 + Time: 2025-11-20 03:55:00+00:00 + ID: e1b5313e-489d-4873-83b5-964620b595a3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:55:00+00:00 +---------------------------------------- + +Instruction #217: + Timestep: 216 + Time: 2025-11-20 04:00:00+00:00 + ID: 9f994e57-a96b-432d-a658-06dce044f881 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:00:00+00:00 +---------------------------------------- + +Instruction #218: + Timestep: 217 + Time: 2025-11-20 04:05:00+00:00 + ID: 07f77fca-308d-497f-895e-d896dfc21f17 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:05:00+00:00 +---------------------------------------- + +Instruction #219: + Timestep: 218 + Time: 2025-11-20 04:10:00+00:00 + ID: 558d410a-fdb0-4b24-b4db-fbd3d357a277 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:10:00+00:00 +---------------------------------------- + +Instruction #220: + Timestep: 219 + Time: 2025-11-20 04:15:00+00:00 + ID: 4f8a87de-ad3b-4e0f-aee7-7de0f5ec4df0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:15:00+00:00 +---------------------------------------- + +Instruction #221: + Timestep: 220 + Time: 2025-11-20 04:20:00+00:00 + ID: 878f031b-7730-4286-94e3-0a3188fb9204 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:20:00+00:00 +---------------------------------------- + +Instruction #222: + Timestep: 221 + Time: 2025-11-20 04:25:00+00:00 + ID: ee8bcb8a-eb3f-4973-b80a-f38b48052d5e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:25:00+00:00 +---------------------------------------- + +Instruction #223: + Timestep: 222 + Time: 2025-11-20 04:30:00+00:00 + ID: f76696f7-64ab-4ad3-affc-bfad2f5c78d4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:30:00+00:00 +---------------------------------------- + +Instruction #224: + Timestep: 223 + Time: 2025-11-20 04:35:00+00:00 + ID: 9efdd12c-c92e-4270-a19f-69798d5e99e8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:35:00+00:00 +---------------------------------------- + +Instruction #225: + Timestep: 224 + Time: 2025-11-20 04:40:00+00:00 + ID: 47698f42-7367-4b48-99d5-d2b52dff217e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:40:00+00:00 +---------------------------------------- + +Instruction #226: + Timestep: 225 + Time: 2025-11-20 04:45:00+00:00 + ID: 61e2ab37-aae1-4586-81db-378d440ae1cd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:45:00+00:00 +---------------------------------------- + +Instruction #227: + Timestep: 226 + Time: 2025-11-20 04:50:00+00:00 + ID: dd4d6df6-144f-40df-a291-6713789a343a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:50:00+00:00 +---------------------------------------- + +Instruction #228: + Timestep: 227 + Time: 2025-11-20 04:55:00+00:00 + ID: 74faf011-b4d9-4bc0-b8b0-443315a9f332 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:55:00+00:00 +---------------------------------------- + +Instruction #229: + Timestep: 228 + Time: 2025-11-20 05:00:00+00:00 + ID: 820b0a7c-0782-458a-975e-8eee4d6466b4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:00:00+00:00 +---------------------------------------- + +Instruction #230: + Timestep: 229 + Time: 2025-11-20 05:05:00+00:00 + ID: 9dfd830b-59a9-4230-ac81-769afa2fb12e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:05:00+00:00 +---------------------------------------- + +Instruction #231: + Timestep: 230 + Time: 2025-11-20 05:10:00+00:00 + ID: 901ac14e-c33e-40dd-960f-ffbf5961d98d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:10:00+00:00 +---------------------------------------- + +Instruction #232: + Timestep: 231 + Time: 2025-11-20 05:15:00+00:00 + ID: 4b02a55f-d065-47d5-889f-b896a131bf7c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:15:00+00:00 +---------------------------------------- + +Instruction #233: + Timestep: 232 + Time: 2025-11-20 05:20:00+00:00 + ID: 3f828ad2-54c4-439e-9505-a1f64dba4566 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:20:00+00:00 +---------------------------------------- + +Instruction #234: + Timestep: 233 + Time: 2025-11-20 05:25:00+00:00 + ID: 82f4bfe1-56eb-44cb-94a5-a2fd867c54eb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:25:00+00:00 +---------------------------------------- + +Instruction #235: + Timestep: 234 + Time: 2025-11-20 05:30:00+00:00 + ID: b4556c81-08e2-44eb-ba5c-f023fea2a3d7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:30:00+00:00 +---------------------------------------- + +Instruction #236: + Timestep: 235 + Time: 2025-11-20 05:35:00+00:00 + ID: e23b08fc-d00d-4981-ad41-3fefc1a34312 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:35:00+00:00 +---------------------------------------- + +Instruction #237: + Timestep: 236 + Time: 2025-11-20 05:40:00+00:00 + ID: 110f51cb-269b-4456-bbe2-a4a03fbfc279 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:40:00+00:00 +---------------------------------------- + +Instruction #238: + Timestep: 237 + Time: 2025-11-20 05:45:00+00:00 + ID: d2b52303-28c2-4c29-8f78-381ac8c647ea + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:45:00+00:00 +---------------------------------------- + +Instruction #239: + Timestep: 238 + Time: 2025-11-20 05:50:00+00:00 + ID: 292f00c9-4ba3-4521-82db-43f036a41d4f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:50:00+00:00 +---------------------------------------- + +Instruction #240: + Timestep: 239 + Time: 2025-11-20 05:55:00+00:00 + ID: c0f15adc-fb4f-4b14-9151-8ac6e797aec4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:55:00+00:00 +---------------------------------------- + +Instruction #241: + Timestep: 240 + Time: 2025-11-20 06:00:00+00:00 + ID: 5e6b85b7-e7be-4f2c-95be-260b3b06fe11 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:00:00+00:00 +---------------------------------------- + +Instruction #242: + Timestep: 241 + Time: 2025-11-20 06:05:00+00:00 + ID: d49665e3-6aab-42ff-b534-29cfb259d19b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:05:00+00:00 +---------------------------------------- + +Instruction #243: + Timestep: 242 + Time: 2025-11-20 06:10:00+00:00 + ID: 09c660a3-6e7a-42b8-91c9-b7837262078d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:10:00+00:00 +---------------------------------------- + +Instruction #244: + Timestep: 243 + Time: 2025-11-20 06:15:00+00:00 + ID: 62e6fa58-05d0-4cae-bab2-f30e92925573 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:15:00+00:00 +---------------------------------------- + +Instruction #245: + Timestep: 244 + Time: 2025-11-20 06:20:00+00:00 + ID: c8f61400-58b7-4035-819a-eeaa66f11763 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:20:00+00:00 +---------------------------------------- + +Instruction #246: + Timestep: 245 + Time: 2025-11-20 06:25:00+00:00 + ID: 537c9937-8579-47a0-8c42-6d2d81957b5a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:25:00+00:00 +---------------------------------------- + +Instruction #247: + Timestep: 246 + Time: 2025-11-20 06:30:00+00:00 + ID: 91378f95-efe8-4957-9f84-0f0b67371bf7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:30:00+00:00 +---------------------------------------- + +Instruction #248: + Timestep: 247 + Time: 2025-11-20 06:35:00+00:00 + ID: 4b848139-c0d3-4046-8741-8e1ee1d05ba8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:35:00+00:00 +---------------------------------------- + +Instruction #249: + Timestep: 248 + Time: 2025-11-20 06:40:00+00:00 + ID: 8a298f67-1941-4c54-a935-b623bd2b16da + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:40:00+00:00 +---------------------------------------- + +Instruction #250: + Timestep: 249 + Time: 2025-11-20 06:45:00+00:00 + ID: a4661135-9abf-4af6-9a7d-423fdd58284c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:45:00+00:00 +---------------------------------------- + +Instruction #251: + Timestep: 250 + Time: 2025-11-20 06:50:00+00:00 + ID: 4bbfce99-12a5-44e1-8156-1565cc3f305c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:50:00+00:00 +---------------------------------------- + +Instruction #252: + Timestep: 251 + Time: 2025-11-20 06:55:00+00:00 + ID: 6c818ed5-ebda-4a18-b15c-292f8a834465 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:55:00+00:00 +---------------------------------------- + +Instruction #253: + Timestep: 252 + Time: 2025-11-20 07:00:00+00:00 + ID: 9b8ebdce-3476-4165-89d0-63b68b7c84d7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:00:00+00:00 +---------------------------------------- + +Instruction #254: + Timestep: 253 + Time: 2025-11-20 07:05:00+00:00 + ID: 5d40ef96-c222-432a-8dec-bcecf26bfbd1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:05:00+00:00 +---------------------------------------- + +Instruction #255: + Timestep: 254 + Time: 2025-11-20 07:10:00+00:00 + ID: 92bcc3b6-7872-4371-a26e-ab3a0f13a849 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:10:00+00:00 +---------------------------------------- + +Instruction #256: + Timestep: 255 + Time: 2025-11-20 07:15:00+00:00 + ID: cb262382-b866-4140-8fdf-69a4a86fd95a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:15:00+00:00 +---------------------------------------- + +Instruction #257: + Timestep: 256 + Time: 2025-11-20 07:20:00+00:00 + ID: 5ff0ac4c-c64d-473a-a2ef-3d25c8052cc8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:20:00+00:00 +---------------------------------------- + +Instruction #258: + Timestep: 257 + Time: 2025-11-20 07:25:00+00:00 + ID: 1b9c4fb6-a7a3-4778-9402-bd332a05c60c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:25:00+00:00 +---------------------------------------- + +Instruction #259: + Timestep: 258 + Time: 2025-11-20 07:30:00+00:00 + ID: 2df1d3d5-e930-4e94-bfb4-d1562ebacb40 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:30:00+00:00 +---------------------------------------- + +Instruction #260: + Timestep: 259 + Time: 2025-11-20 07:35:00+00:00 + ID: 4e1289d2-896c-470b-ade9-9c95bb5de697 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:35:00+00:00 +---------------------------------------- + +Instruction #261: + Timestep: 260 + Time: 2025-11-20 07:40:00+00:00 + ID: ef556afe-2348-482d-9545-e7bfba9c7806 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:40:00+00:00 +---------------------------------------- + +Instruction #262: + Timestep: 261 + Time: 2025-11-20 07:45:00+00:00 + ID: 8d7eaf43-d6dc-4983-b050-470f144bd2af + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:45:00+00:00 +---------------------------------------- + +Instruction #263: + Timestep: 262 + Time: 2025-11-20 07:50:00+00:00 + ID: 86ce0d05-df0e-467e-b296-c5a1b21c4045 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:50:00+00:00 +---------------------------------------- + +Instruction #264: + Timestep: 263 + Time: 2025-11-20 07:55:00+00:00 + ID: 6726097c-b7b4-4cd6-a045-50e48763d6bd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:55:00+00:00 +---------------------------------------- + +Instruction #265: + Timestep: 264 + Time: 2025-11-20 08:00:00+00:00 + ID: 4a62dc29-d054-42f2-bcfa-dc436bfd3662 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:00:00+00:00 +---------------------------------------- + +Instruction #266: + Timestep: 265 + Time: 2025-11-20 08:05:00+00:00 + ID: 995097c0-fbc8-45ec-ad96-b4d3894ccc8a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:05:00+00:00 +---------------------------------------- + +Instruction #267: + Timestep: 266 + Time: 2025-11-20 08:10:00+00:00 + ID: a711dfb0-3231-4427-bd65-19a712df01c7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:10:00+00:00 +---------------------------------------- + +Instruction #268: + Timestep: 267 + Time: 2025-11-20 08:15:00+00:00 + ID: 08ceec3e-91bd-46c0-8936-f39444da0abe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:15:00+00:00 +---------------------------------------- + +Instruction #269: + Timestep: 268 + Time: 2025-11-20 08:20:00+00:00 + ID: 7775b2e0-687e-4341-8541-44c4198f6042 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:20:00+00:00 +---------------------------------------- + +Instruction #270: + Timestep: 269 + Time: 2025-11-20 08:25:00+00:00 + ID: c521d12f-0f37-4d4e-95c5-7c46dd5b1149 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:25:00+00:00 +---------------------------------------- + +Instruction #271: + Timestep: 270 + Time: 2025-11-20 08:30:00+00:00 + ID: 02481576-83d2-42d6-afbe-f15afc1312af + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:30:00+00:00 +---------------------------------------- + +Instruction #272: + Timestep: 271 + Time: 2025-11-20 08:35:00+00:00 + ID: 21820305-3d99-4c65-9583-9bfeb9740a37 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:35:00+00:00 +---------------------------------------- + +Instruction #273: + Timestep: 272 + Time: 2025-11-20 08:40:00+00:00 + ID: fe62914b-fbfd-4a39-a20e-45cc24c51083 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:40:00+00:00 +---------------------------------------- + +Instruction #274: + Timestep: 273 + Time: 2025-11-20 08:45:00+00:00 + ID: b3f42212-a3f4-47cc-b0b7-7ecf763d60f5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:45:00+00:00 +---------------------------------------- + +Instruction #275: + Timestep: 274 + Time: 2025-11-20 08:50:00+00:00 + ID: f307e66d-d6a4-4c74-a8d7-0caed7663a8a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:50:00+00:00 +---------------------------------------- + +Instruction #276: + Timestep: 275 + Time: 2025-11-20 08:55:00+00:00 + ID: 0b666012-7341-4098-a06d-7773bd472f36 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:55:00+00:00 +---------------------------------------- + +Instruction #277: + Timestep: 276 + Time: 2025-11-20 09:00:00+00:00 + ID: e67f89e4-3d4c-4bc5-a18b-b96a45620d8e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:00:00+00:00 +---------------------------------------- + +Instruction #278: + Timestep: 277 + Time: 2025-11-20 09:05:00+00:00 + ID: 45850660-3b98-4199-9e81-08f019b24783 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:05:00+00:00 +---------------------------------------- + +Instruction #279: + Timestep: 278 + Time: 2025-11-20 09:10:00+00:00 + ID: b99bd11e-60c8-4c01-83ca-e5b948be56f0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:10:00+00:00 +---------------------------------------- + +Instruction #280: + Timestep: 279 + Time: 2025-11-20 09:15:00+00:00 + ID: f26ae8fc-c07a-4c2c-9c03-5eb023565549 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:15:00+00:00 +---------------------------------------- + +Instruction #281: + Timestep: 280 + Time: 2025-11-20 09:20:00+00:00 + ID: a035e49b-e0b4-4c18-87ec-f32bec2b6375 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:20:00+00:00 +---------------------------------------- + +Instruction #282: + Timestep: 281 + Time: 2025-11-20 09:25:00+00:00 + ID: 59940f45-119b-4be8-9cb0-f44ab32ec3fe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:25:00+00:00 +---------------------------------------- + +Instruction #283: + Timestep: 282 + Time: 2025-11-20 09:30:00+00:00 + ID: abfb88b8-8b30-4272-a49c-ff5fa43824b5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:30:00+00:00 +---------------------------------------- + +Instruction #284: + Timestep: 283 + Time: 2025-11-20 09:35:00+00:00 + ID: 345b9687-eb43-45ca-a850-ca6c2e81f1ce + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:35:00+00:00 +---------------------------------------- + +Instruction #285: + Timestep: 284 + Time: 2025-11-20 09:40:00+00:00 + ID: 8e03482c-1f6f-499f-927e-03950d45955a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:40:00+00:00 +---------------------------------------- + +Instruction #286: + Timestep: 285 + Time: 2025-11-20 09:45:00+00:00 + ID: 0246f49a-f36d-4679-b044-971c9eb91107 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:45:00+00:00 +---------------------------------------- + +Instruction #287: + Timestep: 286 + Time: 2025-11-20 09:50:00+00:00 + ID: 8b878275-ee24-46ee-97b2-b08dcee17085 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:50:00+00:00 +---------------------------------------- + +Instruction #288: + Timestep: 287 + Time: 2025-11-20 09:55:00+00:00 + ID: 71264dbe-5efa-4839-a7a3-97f2c477327d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:55:00+00:00 +---------------------------------------- diff --git a/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_flask_filltarget_only_D=1_B=200_S=30_T=288.txt b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_flask_filltarget_only_D=1_B=200_S=30_T=288.txt new file mode 100644 index 0000000..b6f5d25 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_flask_filltarget_only_D=1_B=200_S=30_T=288.txt @@ -0,0 +1,177 @@ +================================================================================ +ITHO DHW Heat Pump Instructions Flask Filltarget Only +================================================================================ +Planning start time: 2025-11-19 09:55:00+00:00 +Planning window: 1 days 00:00:00 +Resolution: 0 days 00:05:00 +Total timesteps: 288 +================================================================================ + +Device: itho_dhw_device_flask_001 +Number of instructions: 288 +-------------------------------------------------------------------------------- + +Instruction Timeline: +-------------------------------------------------------------------------------- + Mode: DHW_ON + Start: 2025-11-19 09:55:00+00:00 (timestep 0) + Duration: 85 timesteps (425.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-19 17:00:00+00:00 (timestep 85) + Duration: 198 timesteps (990.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-20 09:30:00+00:00 (timestep 283) + Duration: 5 timesteps (25.0 minutes) +---------------------------------------- + +Total operation mode changes: 2 +================================================================================ + +Detailed Instruction List: +================================================================================ + +Instruction #1: + Timestep: 0 + Time: 2025-11-19 09:55:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 09:40:00+00:00 + +Instruction #2: + Timestep: 1 + Time: 2025-11-19 10:00:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 09:45:00+00:00 + +Instruction #3: + Timestep: 2 + Time: 2025-11-19 10:05:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 09:50:00+00:00 + +Instruction #4: + Timestep: 3 + Time: 2025-11-19 10:10:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 09:55:00+00:00 + +Instruction #5: + Timestep: 4 + Time: 2025-11-19 10:15:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:00:00+00:00 + +Instruction #6: + Timestep: 5 + Time: 2025-11-19 10:20:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:05:00+00:00 + +Instruction #7: + Timestep: 6 + Time: 2025-11-19 10:25:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:10:00+00:00 + +Instruction #8: + Timestep: 7 + Time: 2025-11-19 10:30:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:15:00+00:00 + +Instruction #9: + Timestep: 8 + Time: 2025-11-19 10:35:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:20:00+00:00 + +Instruction #10: + Timestep: 9 + Time: 2025-11-19 10:40:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:25:00+00:00 + +Instruction #11: + Timestep: 10 + Time: 2025-11-19 10:45:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:30:00+00:00 + +Instruction #12: + Timestep: 11 + Time: 2025-11-19 10:50:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:35:00+00:00 + +Instruction #13: + Timestep: 12 + Time: 2025-11-19 10:55:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:40:00+00:00 + +Instruction #14: + Timestep: 13 + Time: 2025-11-19 11:00:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:45:00+00:00 + +Instruction #15: + Timestep: 14 + Time: 2025-11-19 11:05:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:50:00+00:00 + +Instruction #16: + Timestep: 15 + Time: 2025-11-19 11:10:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 10:55:00+00:00 + +Instruction #17: + Timestep: 16 + Time: 2025-11-19 11:15:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 11:00:00+00:00 + +Instruction #18: + Timestep: 17 + Time: 2025-11-19 11:20:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 11:05:00+00:00 + +Instruction #19: + Timestep: 18 + Time: 2025-11-19 11:25:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 11:10:00+00:00 + +Instruction #20: + Timestep: 19 + Time: 2025-11-19 11:30:00+00:00 + Operation mode: e7eeb83d-5155-4f05-acec-7b6db49b854c + Factor: 0.0 + Execution time: 2025-11-19 11:15:00+00:00 + +... and 268 more instructions diff --git a/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_flask_scheduler_D=1_B=200_S=30_T=288.txt b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_flask_scheduler_D=1_B=200_S=30_T=288.txt new file mode 100644 index 0000000..f67844b --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_flask_scheduler_D=1_B=200_S=30_T=288.txt @@ -0,0 +1,177 @@ +================================================================================ +ITHO DHW Heat Pump Instructions Flask Scheduler +================================================================================ +Planning start time: 2025-11-18 11:15:00+00:00 +Planning window: 1 days 00:00:00 +Resolution: 0 days 00:05:00 +Total timesteps: 288 +================================================================================ + +Device: itho_dhw_device_flask_001 +Number of instructions: 288 +-------------------------------------------------------------------------------- + +Instruction Timeline: +-------------------------------------------------------------------------------- + Mode: DHW + Start: 2025-11-18 11:15:00+00:00 (timestep 0) + Duration: 6 timesteps (30.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: OFF + Start: 2025-11-18 11:45:00+00:00 (timestep 6) + Duration: 269 timesteps (1345.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW + Start: 2025-11-19 10:10:00+00:00 (timestep 275) + Duration: 13 timesteps (65.0 minutes) +---------------------------------------- + +Total operation mode changes: 2 +================================================================================ + +Detailed Instruction List: +================================================================================ + +Instruction #1: + Timestep: 0 + Time: 2025-11-18 11:15:00+00:00 + Operation mode: f93ae9b2-820d-471a-a9db-c5d4180c5370 + Factor: 0.0 + Execution time: 2025-11-18 11:00:00+00:00 + +Instruction #2: + Timestep: 1 + Time: 2025-11-18 11:20:00+00:00 + Operation mode: f93ae9b2-820d-471a-a9db-c5d4180c5370 + Factor: 0.0 + Execution time: 2025-11-18 11:05:00+00:00 + +Instruction #3: + Timestep: 2 + Time: 2025-11-18 11:25:00+00:00 + Operation mode: f93ae9b2-820d-471a-a9db-c5d4180c5370 + Factor: 0.0 + Execution time: 2025-11-18 11:10:00+00:00 + +Instruction #4: + Timestep: 3 + Time: 2025-11-18 11:30:00+00:00 + Operation mode: f93ae9b2-820d-471a-a9db-c5d4180c5370 + Factor: 0.0 + Execution time: 2025-11-18 11:15:00+00:00 + +Instruction #5: + Timestep: 4 + Time: 2025-11-18 11:35:00+00:00 + Operation mode: f93ae9b2-820d-471a-a9db-c5d4180c5370 + Factor: 0.0 + Execution time: 2025-11-18 11:20:00+00:00 + +Instruction #6: + Timestep: 5 + Time: 2025-11-18 11:40:00+00:00 + Operation mode: f93ae9b2-820d-471a-a9db-c5d4180c5370 + Factor: 0.0 + Execution time: 2025-11-18 11:25:00+00:00 + +Instruction #7: + Timestep: 6 + Time: 2025-11-18 11:45:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 11:30:00+00:00 + +Instruction #8: + Timestep: 7 + Time: 2025-11-18 11:50:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 11:35:00+00:00 + +Instruction #9: + Timestep: 8 + Time: 2025-11-18 11:55:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 11:40:00+00:00 + +Instruction #10: + Timestep: 9 + Time: 2025-11-18 12:00:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 11:45:00+00:00 + +Instruction #11: + Timestep: 10 + Time: 2025-11-18 12:05:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 11:50:00+00:00 + +Instruction #12: + Timestep: 11 + Time: 2025-11-18 12:10:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 11:55:00+00:00 + +Instruction #13: + Timestep: 12 + Time: 2025-11-18 12:15:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 12:00:00+00:00 + +Instruction #14: + Timestep: 13 + Time: 2025-11-18 12:20:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 12:05:00+00:00 + +Instruction #15: + Timestep: 14 + Time: 2025-11-18 12:25:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 12:10:00+00:00 + +Instruction #16: + Timestep: 15 + Time: 2025-11-18 12:30:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 12:15:00+00:00 + +Instruction #17: + Timestep: 16 + Time: 2025-11-18 12:35:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 12:20:00+00:00 + +Instruction #18: + Timestep: 17 + Time: 2025-11-18 12:40:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 12:25:00+00:00 + +Instruction #19: + Timestep: 18 + Time: 2025-11-18 12:45:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 12:30:00+00:00 + +Instruction #20: + Timestep: 19 + Time: 2025-11-18 12:50:00+00:00 + Operation mode: 1cbe1d95-5313-48c5-acb5-4e208195006c + Factor: 0.0 + Execution time: 2025-11-18 12:35:00+00:00 + +... and 268 more instructions diff --git a/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_flask_usage_only_D=1_B=200_S=30_T=288.txt b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_flask_usage_only_D=1_B=200_S=30_T=288.txt new file mode 100644 index 0000000..2e18c52 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_flask_usage_only_D=1_B=200_S=30_T=288.txt @@ -0,0 +1,177 @@ +================================================================================ +ITHO DHW Heat Pump Instructions Flask Usage Only +================================================================================ +Planning start time: 2025-11-19 09:55:00+00:00 +Planning window: 1 days 00:00:00 +Resolution: 0 days 00:05:00 +Total timesteps: 288 +================================================================================ + +Device: itho_dhw_device_flask_001 +Number of instructions: 288 +-------------------------------------------------------------------------------- + +Instruction Timeline: +-------------------------------------------------------------------------------- + Mode: DHW_ON + Start: 2025-11-19 09:55:00+00:00 (timestep 0) + Duration: 17 timesteps (85.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-19 11:20:00+00:00 (timestep 17) + Duration: 188 timesteps (940.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-20 03:00:00+00:00 (timestep 205) + Duration: 83 timesteps (415.0 minutes) +---------------------------------------- + +Total operation mode changes: 2 +================================================================================ + +Detailed Instruction List: +================================================================================ + +Instruction #1: + Timestep: 0 + Time: 2025-11-19 09:55:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 09:40:00+00:00 + +Instruction #2: + Timestep: 1 + Time: 2025-11-19 10:00:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 09:45:00+00:00 + +Instruction #3: + Timestep: 2 + Time: 2025-11-19 10:05:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 09:50:00+00:00 + +Instruction #4: + Timestep: 3 + Time: 2025-11-19 10:10:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 09:55:00+00:00 + +Instruction #5: + Timestep: 4 + Time: 2025-11-19 10:15:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:00:00+00:00 + +Instruction #6: + Timestep: 5 + Time: 2025-11-19 10:20:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:05:00+00:00 + +Instruction #7: + Timestep: 6 + Time: 2025-11-19 10:25:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:10:00+00:00 + +Instruction #8: + Timestep: 7 + Time: 2025-11-19 10:30:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:15:00+00:00 + +Instruction #9: + Timestep: 8 + Time: 2025-11-19 10:35:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:20:00+00:00 + +Instruction #10: + Timestep: 9 + Time: 2025-11-19 10:40:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:25:00+00:00 + +Instruction #11: + Timestep: 10 + Time: 2025-11-19 10:45:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:30:00+00:00 + +Instruction #12: + Timestep: 11 + Time: 2025-11-19 10:50:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:35:00+00:00 + +Instruction #13: + Timestep: 12 + Time: 2025-11-19 10:55:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:40:00+00:00 + +Instruction #14: + Timestep: 13 + Time: 2025-11-19 11:00:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:45:00+00:00 + +Instruction #15: + Timestep: 14 + Time: 2025-11-19 11:05:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:50:00+00:00 + +Instruction #16: + Timestep: 15 + Time: 2025-11-19 11:10:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 10:55:00+00:00 + +Instruction #17: + Timestep: 16 + Time: 2025-11-19 11:15:00+00:00 + Operation mode: 7bfbf58c-7bd5-4bdc-b419-f0f9bdf3e560 + Factor: 0.0 + Execution time: 2025-11-19 11:00:00+00:00 + +Instruction #18: + Timestep: 17 + Time: 2025-11-19 11:20:00+00:00 + Operation mode: f397493b-be70-49ee-8d28-08e07c6395aa + Factor: 0.0 + Execution time: 2025-11-19 11:05:00+00:00 + +Instruction #19: + Timestep: 18 + Time: 2025-11-19 11:25:00+00:00 + Operation mode: f397493b-be70-49ee-8d28-08e07c6395aa + Factor: 0.0 + Execution time: 2025-11-19 11:10:00+00:00 + +Instruction #20: + Timestep: 19 + Time: 2025-11-19 11:30:00+00:00 + Operation mode: f397493b-be70-49ee-8d28-08e07c6395aa + Factor: 0.0 + Execution time: 2025-11-19 11:15:00+00:00 + +... and 268 more instructions diff --git a/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_usage_only_D=1_B=200_S=30_T=288.txt b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_usage_only_D=1_B=200_S=30_T=288.txt new file mode 100644 index 0000000..1772df4 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/instructions/itho_instructions_usage_only_D=1_B=200_S=30_T=288.txt @@ -0,0 +1,3208 @@ +================================================================================ +ITHO DHW Heat Pump Instructions Usage Only +================================================================================ +Planning start time: 2025-11-19 10:00:00+00:00 +Planning window: 1 days 00:00:00 +Resolution: 0 days 00:05:00 +Total timesteps: 288 +================================================================================ + +Device: itho_dhw_device_004 +Number of instructions: 288 +-------------------------------------------------------------------------------- + +Instruction Timeline: +-------------------------------------------------------------------------------- + Mode: DHW_ON + Start: 2025-11-19 10:00:00+00:00 (timestep 0) + Duration: 17 timesteps (85.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-19 11:25:00+00:00 (timestep 17) + Duration: 15 timesteps (75.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_ON + Start: 2025-11-19 12:40:00+00:00 (timestep 32) + Duration: 6 timesteps (30.0 minutes) + Operation mode factor: 0.0 +---------------------------------------- + Mode: DHW_OFF + Start: 2025-11-19 13:10:00+00:00 (timestep 38) + Duration: 250 timesteps (1250.0 minutes) +---------------------------------------- + +Total operation mode changes: 3 +================================================================================ + +Detailed Instruction List: +================================================================================ + +Instruction #1: + Timestep: 0 + Time: 2025-11-19 10:00:00+00:00 + ID: 9210300e-20af-4ea8-84b0-98f2b44bdbe6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:00:00+00:00 +---------------------------------------- + +Instruction #2: + Timestep: 1 + Time: 2025-11-19 10:05:00+00:00 + ID: 4059ad4c-c363-4eab-a8d3-3b3a10265ae3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:05:00+00:00 +---------------------------------------- + +Instruction #3: + Timestep: 2 + Time: 2025-11-19 10:10:00+00:00 + ID: 977921e2-c076-43e7-9c04-99f5e1ee1736 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:10:00+00:00 +---------------------------------------- + +Instruction #4: + Timestep: 3 + Time: 2025-11-19 10:15:00+00:00 + ID: 99777816-b85d-4a3b-b6ca-2c75dc33cfc2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:15:00+00:00 +---------------------------------------- + +Instruction #5: + Timestep: 4 + Time: 2025-11-19 10:20:00+00:00 + ID: 1acc320f-6389-4238-a164-fa2d055dc9df + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:20:00+00:00 +---------------------------------------- + +Instruction #6: + Timestep: 5 + Time: 2025-11-19 10:25:00+00:00 + ID: 86220aeb-e807-4cc1-bc17-3b2d073e5974 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:25:00+00:00 +---------------------------------------- + +Instruction #7: + Timestep: 6 + Time: 2025-11-19 10:30:00+00:00 + ID: 10675e35-b022-4a42-9162-943a59e1baf7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:30:00+00:00 +---------------------------------------- + +Instruction #8: + Timestep: 7 + Time: 2025-11-19 10:35:00+00:00 + ID: c8ca41dc-6ee2-4e48-8fc3-edf529e48439 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:35:00+00:00 +---------------------------------------- + +Instruction #9: + Timestep: 8 + Time: 2025-11-19 10:40:00+00:00 + ID: f0f27981-eb5b-4851-99eb-196fd48ea155 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:40:00+00:00 +---------------------------------------- + +Instruction #10: + Timestep: 9 + Time: 2025-11-19 10:45:00+00:00 + ID: 8797cb86-c7fb-4354-b651-e6f083ee3050 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:45:00+00:00 +---------------------------------------- + +Instruction #11: + Timestep: 10 + Time: 2025-11-19 10:50:00+00:00 + ID: 31e13ee8-d21e-4691-b074-abb955006140 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:50:00+00:00 +---------------------------------------- + +Instruction #12: + Timestep: 11 + Time: 2025-11-19 10:55:00+00:00 + ID: 31314468-fd14-4ce8-87b2-c6fbab18aafd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 10:55:00+00:00 +---------------------------------------- + +Instruction #13: + Timestep: 12 + Time: 2025-11-19 11:00:00+00:00 + ID: 409e29a8-3a84-4048-8db0-7a703f7b657a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:00:00+00:00 +---------------------------------------- + +Instruction #14: + Timestep: 13 + Time: 2025-11-19 11:05:00+00:00 + ID: 041ed3ed-fa45-4152-be44-a932472b1fcb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:05:00+00:00 +---------------------------------------- + +Instruction #15: + Timestep: 14 + Time: 2025-11-19 11:10:00+00:00 + ID: 707438d2-59d7-4b3e-aca1-c4359f757dc7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:10:00+00:00 +---------------------------------------- + +Instruction #16: + Timestep: 15 + Time: 2025-11-19 11:15:00+00:00 + ID: b33c7bf1-1289-4537-a89e-6f8f058a103e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:15:00+00:00 +---------------------------------------- + +Instruction #17: + Timestep: 16 + Time: 2025-11-19 11:20:00+00:00 + ID: d2aa6044-e4ea-489d-996c-80349b5e1220 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:20:00+00:00 +---------------------------------------- + +Instruction #18: + Timestep: 17 + Time: 2025-11-19 11:25:00+00:00 + ID: 45d6ca31-828f-48cf-bcb6-d1eafbd83ca8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:25:00+00:00 +---------------------------------------- + +Instruction #19: + Timestep: 18 + Time: 2025-11-19 11:30:00+00:00 + ID: 765b9ea9-7701-4831-b14e-5f8538a840ef + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:30:00+00:00 +---------------------------------------- + +Instruction #20: + Timestep: 19 + Time: 2025-11-19 11:35:00+00:00 + ID: 76cde4c5-1a20-40b4-9252-2ba2262f0cc5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:35:00+00:00 +---------------------------------------- + +Instruction #21: + Timestep: 20 + Time: 2025-11-19 11:40:00+00:00 + ID: 7640671f-5f68-46cc-811c-f712887bc019 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:40:00+00:00 +---------------------------------------- + +Instruction #22: + Timestep: 21 + Time: 2025-11-19 11:45:00+00:00 + ID: a3aeec59-5cfe-4745-bbdc-a4b6540d26af + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:45:00+00:00 +---------------------------------------- + +Instruction #23: + Timestep: 22 + Time: 2025-11-19 11:50:00+00:00 + ID: 82193bfe-a52e-4737-87c8-b51552e53a06 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:50:00+00:00 +---------------------------------------- + +Instruction #24: + Timestep: 23 + Time: 2025-11-19 11:55:00+00:00 + ID: 7edc56c7-987b-4c24-82e4-7f77d39aab80 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 11:55:00+00:00 +---------------------------------------- + +Instruction #25: + Timestep: 24 + Time: 2025-11-19 12:00:00+00:00 + ID: 95fd45d0-d7ae-4a78-a9e1-96eeeb2e9529 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:00:00+00:00 +---------------------------------------- + +Instruction #26: + Timestep: 25 + Time: 2025-11-19 12:05:00+00:00 + ID: 8945fd46-4acd-4a4d-b9c3-aacaa21121ff + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:05:00+00:00 +---------------------------------------- + +Instruction #27: + Timestep: 26 + Time: 2025-11-19 12:10:00+00:00 + ID: 77dfabb1-3d50-469a-89aa-1b2d406b799c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:10:00+00:00 +---------------------------------------- + +Instruction #28: + Timestep: 27 + Time: 2025-11-19 12:15:00+00:00 + ID: c23f1128-7526-4d1c-8dde-8a930cea194f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:15:00+00:00 +---------------------------------------- + +Instruction #29: + Timestep: 28 + Time: 2025-11-19 12:20:00+00:00 + ID: 5283dc15-1dd3-4250-adb4-6c512671076f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:20:00+00:00 +---------------------------------------- + +Instruction #30: + Timestep: 29 + Time: 2025-11-19 12:25:00+00:00 + ID: a9732ff9-06b9-4bf2-82bf-9fe651a7aaca + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:25:00+00:00 +---------------------------------------- + +Instruction #31: + Timestep: 30 + Time: 2025-11-19 12:30:00+00:00 + ID: 1c1fd4d2-ce32-4663-8b3d-4d96a9ec1cd7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:30:00+00:00 +---------------------------------------- + +Instruction #32: + Timestep: 31 + Time: 2025-11-19 12:35:00+00:00 + ID: 9e3080d9-d60a-4fd4-9c58-f36401976560 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:35:00+00:00 +---------------------------------------- + +Instruction #33: + Timestep: 32 + Time: 2025-11-19 12:40:00+00:00 + ID: e579033b-d0b1-45d3-bbfc-cab74caa5fb9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:40:00+00:00 +---------------------------------------- + +Instruction #34: + Timestep: 33 + Time: 2025-11-19 12:45:00+00:00 + ID: 6f37e2bc-b682-43f1-82c1-61827110a076 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:45:00+00:00 +---------------------------------------- + +Instruction #35: + Timestep: 34 + Time: 2025-11-19 12:50:00+00:00 + ID: 45906d97-e6e7-4a0f-8fd8-e75c224a8d54 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:50:00+00:00 +---------------------------------------- + +Instruction #36: + Timestep: 35 + Time: 2025-11-19 12:55:00+00:00 + ID: b3808754-d740-4a6f-9a04-fec1637bd2c0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 12:55:00+00:00 +---------------------------------------- + +Instruction #37: + Timestep: 36 + Time: 2025-11-19 13:00:00+00:00 + ID: 6edfcd40-efd5-44be-81e3-adc0439b48bd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:00:00+00:00 +---------------------------------------- + +Instruction #38: + Timestep: 37 + Time: 2025-11-19 13:05:00+00:00 + ID: 7dfd92cc-f2ed-4041-a691-0909ea6ea07a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_ON + Operation Mode ID: 31314092-4456-43f8-89dd-0421194bc821 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:05:00+00:00 +---------------------------------------- + +Instruction #39: + Timestep: 38 + Time: 2025-11-19 13:10:00+00:00 + ID: 75c20e15-03cd-44c1-a629-6d4417b4b712 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:10:00+00:00 +---------------------------------------- + +Instruction #40: + Timestep: 39 + Time: 2025-11-19 13:15:00+00:00 + ID: b4d57365-3e73-497e-b111-657f31257aab + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:15:00+00:00 +---------------------------------------- + +Instruction #41: + Timestep: 40 + Time: 2025-11-19 13:20:00+00:00 + ID: 39e994e7-fbff-4caa-ab87-adb7e9db69bf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:20:00+00:00 +---------------------------------------- + +Instruction #42: + Timestep: 41 + Time: 2025-11-19 13:25:00+00:00 + ID: 01e4629d-5c44-475b-9e79-2326d34d6b32 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:25:00+00:00 +---------------------------------------- + +Instruction #43: + Timestep: 42 + Time: 2025-11-19 13:30:00+00:00 + ID: 69bead87-f6b0-496f-a89a-d6bdb0cfd125 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:30:00+00:00 +---------------------------------------- + +Instruction #44: + Timestep: 43 + Time: 2025-11-19 13:35:00+00:00 + ID: 9f84e73d-fc02-472e-b66f-575343057209 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:35:00+00:00 +---------------------------------------- + +Instruction #45: + Timestep: 44 + Time: 2025-11-19 13:40:00+00:00 + ID: 076841fb-6ae3-40b6-b200-e5c67b7762fe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:40:00+00:00 +---------------------------------------- + +Instruction #46: + Timestep: 45 + Time: 2025-11-19 13:45:00+00:00 + ID: 0eda40ab-00b9-48bb-978a-8b18d9199f41 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:45:00+00:00 +---------------------------------------- + +Instruction #47: + Timestep: 46 + Time: 2025-11-19 13:50:00+00:00 + ID: 5b0b3616-5be3-4b6d-8cbe-cb133c92aef8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:50:00+00:00 +---------------------------------------- + +Instruction #48: + Timestep: 47 + Time: 2025-11-19 13:55:00+00:00 + ID: ea50f8ae-a1f4-4153-a209-0ebf7bb8deaf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 13:55:00+00:00 +---------------------------------------- + +Instruction #49: + Timestep: 48 + Time: 2025-11-19 14:00:00+00:00 + ID: 7b24fb76-f45e-416e-8858-e0cc51481e56 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:00:00+00:00 +---------------------------------------- + +Instruction #50: + Timestep: 49 + Time: 2025-11-19 14:05:00+00:00 + ID: 66eaf0ca-8500-4d05-81b5-242de971dcf2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:05:00+00:00 +---------------------------------------- + +Instruction #51: + Timestep: 50 + Time: 2025-11-19 14:10:00+00:00 + ID: c798beac-9d93-47a4-856e-a06dcbf2dc68 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:10:00+00:00 +---------------------------------------- + +Instruction #52: + Timestep: 51 + Time: 2025-11-19 14:15:00+00:00 + ID: a3cc6b89-9320-42d9-80d8-e8bb760468e3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:15:00+00:00 +---------------------------------------- + +Instruction #53: + Timestep: 52 + Time: 2025-11-19 14:20:00+00:00 + ID: 6ef6e30e-052a-405d-a71a-f5b85ab638bd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:20:00+00:00 +---------------------------------------- + +Instruction #54: + Timestep: 53 + Time: 2025-11-19 14:25:00+00:00 + ID: cc73f965-535f-4a14-98bd-04bfa0b6fa43 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:25:00+00:00 +---------------------------------------- + +Instruction #55: + Timestep: 54 + Time: 2025-11-19 14:30:00+00:00 + ID: 00630800-a52a-4c2e-b534-fe27d96e0945 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:30:00+00:00 +---------------------------------------- + +Instruction #56: + Timestep: 55 + Time: 2025-11-19 14:35:00+00:00 + ID: 67e9cd1c-c075-4758-92bc-175a9b8854e0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:35:00+00:00 +---------------------------------------- + +Instruction #57: + Timestep: 56 + Time: 2025-11-19 14:40:00+00:00 + ID: 24290fee-7282-40e7-84a5-ca3ad3a7809a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:40:00+00:00 +---------------------------------------- + +Instruction #58: + Timestep: 57 + Time: 2025-11-19 14:45:00+00:00 + ID: 1d050ac4-c369-44b5-a167-76f1c13a3b0a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:45:00+00:00 +---------------------------------------- + +Instruction #59: + Timestep: 58 + Time: 2025-11-19 14:50:00+00:00 + ID: 36be74c4-7a08-428e-8922-d3ee304e3f6a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:50:00+00:00 +---------------------------------------- + +Instruction #60: + Timestep: 59 + Time: 2025-11-19 14:55:00+00:00 + ID: 73e336d4-9443-4afe-849e-109393763de7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 14:55:00+00:00 +---------------------------------------- + +Instruction #61: + Timestep: 60 + Time: 2025-11-19 15:00:00+00:00 + ID: 755db1fc-8f4c-4872-9859-dd79b293cd1b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:00:00+00:00 +---------------------------------------- + +Instruction #62: + Timestep: 61 + Time: 2025-11-19 15:05:00+00:00 + ID: 30dbe11d-48b8-4609-a89d-b35181c7a7d1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:05:00+00:00 +---------------------------------------- + +Instruction #63: + Timestep: 62 + Time: 2025-11-19 15:10:00+00:00 + ID: a0887362-c6d4-4f21-8e46-4a2f2fb5f1a0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:10:00+00:00 +---------------------------------------- + +Instruction #64: + Timestep: 63 + Time: 2025-11-19 15:15:00+00:00 + ID: 3dcc752d-9d0a-46d9-90d8-b2d03a6b7f43 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:15:00+00:00 +---------------------------------------- + +Instruction #65: + Timestep: 64 + Time: 2025-11-19 15:20:00+00:00 + ID: 76c2751c-37d4-4db1-b031-f0f10d5a7017 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:20:00+00:00 +---------------------------------------- + +Instruction #66: + Timestep: 65 + Time: 2025-11-19 15:25:00+00:00 + ID: 77a455f3-aad8-495d-80bd-61e9feaf1ebe + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:25:00+00:00 +---------------------------------------- + +Instruction #67: + Timestep: 66 + Time: 2025-11-19 15:30:00+00:00 + ID: c4344a68-18a7-4bf1-a415-b94266f6c018 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:30:00+00:00 +---------------------------------------- + +Instruction #68: + Timestep: 67 + Time: 2025-11-19 15:35:00+00:00 + ID: 46863a9f-d87b-48a3-9cc3-5df31ba1ccc3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:35:00+00:00 +---------------------------------------- + +Instruction #69: + Timestep: 68 + Time: 2025-11-19 15:40:00+00:00 + ID: d6e7acdf-130c-4176-9163-c175550c46c0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:40:00+00:00 +---------------------------------------- + +Instruction #70: + Timestep: 69 + Time: 2025-11-19 15:45:00+00:00 + ID: 67f35824-b753-41bf-a8f1-b642328cf06b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:45:00+00:00 +---------------------------------------- + +Instruction #71: + Timestep: 70 + Time: 2025-11-19 15:50:00+00:00 + ID: c86dace6-d7c1-49f6-96ef-4ff71ceaeeb4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:50:00+00:00 +---------------------------------------- + +Instruction #72: + Timestep: 71 + Time: 2025-11-19 15:55:00+00:00 + ID: c6bfd3ac-12fe-4111-b5f1-34453a050e0f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 15:55:00+00:00 +---------------------------------------- + +Instruction #73: + Timestep: 72 + Time: 2025-11-19 16:00:00+00:00 + ID: 9c76e2ff-a5e4-4d3a-9be0-3321f37ee50d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:00:00+00:00 +---------------------------------------- + +Instruction #74: + Timestep: 73 + Time: 2025-11-19 16:05:00+00:00 + ID: d94e15ca-ad39-41b8-994b-ab4f41bd68cb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:05:00+00:00 +---------------------------------------- + +Instruction #75: + Timestep: 74 + Time: 2025-11-19 16:10:00+00:00 + ID: 91073d42-06fb-4934-b4a8-6d8e5df8a4c6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:10:00+00:00 +---------------------------------------- + +Instruction #76: + Timestep: 75 + Time: 2025-11-19 16:15:00+00:00 + ID: 62166a3b-42f8-435d-bf63-9640828e0b1c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:15:00+00:00 +---------------------------------------- + +Instruction #77: + Timestep: 76 + Time: 2025-11-19 16:20:00+00:00 + ID: 5220dc08-2673-4e8a-9f2c-3df126052997 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:20:00+00:00 +---------------------------------------- + +Instruction #78: + Timestep: 77 + Time: 2025-11-19 16:25:00+00:00 + ID: 7510a829-3b00-40af-a916-b99979eba4ff + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:25:00+00:00 +---------------------------------------- + +Instruction #79: + Timestep: 78 + Time: 2025-11-19 16:30:00+00:00 + ID: 47a52e33-bdac-47f2-963f-99fb8ea5d4f4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:30:00+00:00 +---------------------------------------- + +Instruction #80: + Timestep: 79 + Time: 2025-11-19 16:35:00+00:00 + ID: a9a34991-3b77-4d87-87f0-cdd913c91c10 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:35:00+00:00 +---------------------------------------- + +Instruction #81: + Timestep: 80 + Time: 2025-11-19 16:40:00+00:00 + ID: 0660eb10-b086-4bb6-b13d-75d3b2ca3001 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:40:00+00:00 +---------------------------------------- + +Instruction #82: + Timestep: 81 + Time: 2025-11-19 16:45:00+00:00 + ID: 91afb8c7-c439-4472-b8e2-a17ac42e703b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:45:00+00:00 +---------------------------------------- + +Instruction #83: + Timestep: 82 + Time: 2025-11-19 16:50:00+00:00 + ID: f4e1ca4e-3b33-4446-9c7e-39bf7acfea46 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:50:00+00:00 +---------------------------------------- + +Instruction #84: + Timestep: 83 + Time: 2025-11-19 16:55:00+00:00 + ID: 672b3f40-6ea4-4650-87f9-179257c2371c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 16:55:00+00:00 +---------------------------------------- + +Instruction #85: + Timestep: 84 + Time: 2025-11-19 17:00:00+00:00 + ID: 301560eb-d6da-4af0-a81c-5749b5895e9d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:00:00+00:00 +---------------------------------------- + +Instruction #86: + Timestep: 85 + Time: 2025-11-19 17:05:00+00:00 + ID: b96ffb31-e65d-4dc7-a0d5-cbc4aece1ad0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:05:00+00:00 +---------------------------------------- + +Instruction #87: + Timestep: 86 + Time: 2025-11-19 17:10:00+00:00 + ID: 263ea792-7943-4a63-ab93-ed48e9f80ae2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:10:00+00:00 +---------------------------------------- + +Instruction #88: + Timestep: 87 + Time: 2025-11-19 17:15:00+00:00 + ID: 7f5a7807-9bc5-4a8b-ba41-d980a7750a9c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:15:00+00:00 +---------------------------------------- + +Instruction #89: + Timestep: 88 + Time: 2025-11-19 17:20:00+00:00 + ID: 31510eb4-bbce-4625-9934-1c853bd16743 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:20:00+00:00 +---------------------------------------- + +Instruction #90: + Timestep: 89 + Time: 2025-11-19 17:25:00+00:00 + ID: 2e33f3aa-92df-4dbf-8472-4253192c8aff + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:25:00+00:00 +---------------------------------------- + +Instruction #91: + Timestep: 90 + Time: 2025-11-19 17:30:00+00:00 + ID: 0018eb46-db09-411f-a451-e6b940db64ed + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:30:00+00:00 +---------------------------------------- + +Instruction #92: + Timestep: 91 + Time: 2025-11-19 17:35:00+00:00 + ID: e8f7137c-3a67-4045-b781-0e38ec62205a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:35:00+00:00 +---------------------------------------- + +Instruction #93: + Timestep: 92 + Time: 2025-11-19 17:40:00+00:00 + ID: 149df643-4aa8-4d1a-8764-ec0b3e9dcc62 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:40:00+00:00 +---------------------------------------- + +Instruction #94: + Timestep: 93 + Time: 2025-11-19 17:45:00+00:00 + ID: a349f4c1-fc8b-4fb0-8892-1a7ed0dcbce6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:45:00+00:00 +---------------------------------------- + +Instruction #95: + Timestep: 94 + Time: 2025-11-19 17:50:00+00:00 + ID: faa6263e-395f-42e6-9cb3-e87686d438d8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:50:00+00:00 +---------------------------------------- + +Instruction #96: + Timestep: 95 + Time: 2025-11-19 17:55:00+00:00 + ID: 1b4218c9-08d5-43c2-b423-8f72de72feb1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 17:55:00+00:00 +---------------------------------------- + +Instruction #97: + Timestep: 96 + Time: 2025-11-19 18:00:00+00:00 + ID: 535fe40d-5f9a-4d94-8d52-8395f6b112e8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:00:00+00:00 +---------------------------------------- + +Instruction #98: + Timestep: 97 + Time: 2025-11-19 18:05:00+00:00 + ID: df370064-b0f3-4707-a23e-56a212506b88 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:05:00+00:00 +---------------------------------------- + +Instruction #99: + Timestep: 98 + Time: 2025-11-19 18:10:00+00:00 + ID: 2767d481-1ad9-4e9f-aca4-dc70ee6f3916 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:10:00+00:00 +---------------------------------------- + +Instruction #100: + Timestep: 99 + Time: 2025-11-19 18:15:00+00:00 + ID: 1e409c35-c530-487d-aafd-b3700bda192e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:15:00+00:00 +---------------------------------------- + +Instruction #101: + Timestep: 100 + Time: 2025-11-19 18:20:00+00:00 + ID: 8e0d150a-0f6f-40b1-9966-4055e16cf524 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:20:00+00:00 +---------------------------------------- + +Instruction #102: + Timestep: 101 + Time: 2025-11-19 18:25:00+00:00 + ID: 1fd45823-eb20-4fea-b26d-2e153d3aa403 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:25:00+00:00 +---------------------------------------- + +Instruction #103: + Timestep: 102 + Time: 2025-11-19 18:30:00+00:00 + ID: a69ebd32-8616-47bb-83b0-95083e7557d1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:30:00+00:00 +---------------------------------------- + +Instruction #104: + Timestep: 103 + Time: 2025-11-19 18:35:00+00:00 + ID: 8407a06e-7d17-4d86-9f80-94b49c9aab0f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:35:00+00:00 +---------------------------------------- + +Instruction #105: + Timestep: 104 + Time: 2025-11-19 18:40:00+00:00 + ID: c50bc82e-c524-4682-b6f8-a45b50c97ff3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:40:00+00:00 +---------------------------------------- + +Instruction #106: + Timestep: 105 + Time: 2025-11-19 18:45:00+00:00 + ID: 5dabc8d2-fcba-4186-b7a1-ae1d24ec34c5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:45:00+00:00 +---------------------------------------- + +Instruction #107: + Timestep: 106 + Time: 2025-11-19 18:50:00+00:00 + ID: b9f7cc75-0be2-442d-af50-abc8f738ccb4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:50:00+00:00 +---------------------------------------- + +Instruction #108: + Timestep: 107 + Time: 2025-11-19 18:55:00+00:00 + ID: cf073841-79cb-465d-a2b0-40af534114ca + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 18:55:00+00:00 +---------------------------------------- + +Instruction #109: + Timestep: 108 + Time: 2025-11-19 19:00:00+00:00 + ID: 08646e9d-e2f9-4035-b98c-c93afa534bd6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:00:00+00:00 +---------------------------------------- + +Instruction #110: + Timestep: 109 + Time: 2025-11-19 19:05:00+00:00 + ID: fdd90049-a275-4ee2-b3f9-7ac91a9e6e6a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:05:00+00:00 +---------------------------------------- + +Instruction #111: + Timestep: 110 + Time: 2025-11-19 19:10:00+00:00 + ID: 77e23c7e-7302-4e31-b902-e123eb1cc469 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:10:00+00:00 +---------------------------------------- + +Instruction #112: + Timestep: 111 + Time: 2025-11-19 19:15:00+00:00 + ID: ad376fd2-a736-4be4-b442-bb0ccacbb2da + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:15:00+00:00 +---------------------------------------- + +Instruction #113: + Timestep: 112 + Time: 2025-11-19 19:20:00+00:00 + ID: ca2aac54-4480-4779-844f-94e026d182e7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:20:00+00:00 +---------------------------------------- + +Instruction #114: + Timestep: 113 + Time: 2025-11-19 19:25:00+00:00 + ID: 0d1cd9c9-f9e1-4bbd-84ae-d53d4e29d424 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:25:00+00:00 +---------------------------------------- + +Instruction #115: + Timestep: 114 + Time: 2025-11-19 19:30:00+00:00 + ID: f4548bd0-d9c0-4ca8-b7ef-2e376f5b2b49 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:30:00+00:00 +---------------------------------------- + +Instruction #116: + Timestep: 115 + Time: 2025-11-19 19:35:00+00:00 + ID: 952c1ad8-9f75-47bf-b69e-0a1d0eb13b52 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:35:00+00:00 +---------------------------------------- + +Instruction #117: + Timestep: 116 + Time: 2025-11-19 19:40:00+00:00 + ID: 38828f83-3278-44be-bbfe-a3d03fa4c309 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:40:00+00:00 +---------------------------------------- + +Instruction #118: + Timestep: 117 + Time: 2025-11-19 19:45:00+00:00 + ID: cdb58087-e002-47f2-bef2-235a8105b659 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:45:00+00:00 +---------------------------------------- + +Instruction #119: + Timestep: 118 + Time: 2025-11-19 19:50:00+00:00 + ID: bd6e0965-b6af-46ae-aac5-c7e9718df3e6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:50:00+00:00 +---------------------------------------- + +Instruction #120: + Timestep: 119 + Time: 2025-11-19 19:55:00+00:00 + ID: e5a739e4-c85e-4f71-af4b-0031d8f8302e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 19:55:00+00:00 +---------------------------------------- + +Instruction #121: + Timestep: 120 + Time: 2025-11-19 20:00:00+00:00 + ID: 47fd802a-f4bf-44aa-9271-4ebe6c62a307 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:00:00+00:00 +---------------------------------------- + +Instruction #122: + Timestep: 121 + Time: 2025-11-19 20:05:00+00:00 + ID: 59eab968-40f7-42c9-ac7c-84c64ca805d0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:05:00+00:00 +---------------------------------------- + +Instruction #123: + Timestep: 122 + Time: 2025-11-19 20:10:00+00:00 + ID: 3904cfbf-b5c8-4538-a22e-f978222815f6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:10:00+00:00 +---------------------------------------- + +Instruction #124: + Timestep: 123 + Time: 2025-11-19 20:15:00+00:00 + ID: dcd50e9f-e72d-4796-ba6c-d2f1b0cde1a1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:15:00+00:00 +---------------------------------------- + +Instruction #125: + Timestep: 124 + Time: 2025-11-19 20:20:00+00:00 + ID: aa05aa60-97b0-4c18-abae-40bf4103548c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:20:00+00:00 +---------------------------------------- + +Instruction #126: + Timestep: 125 + Time: 2025-11-19 20:25:00+00:00 + ID: 8873b43d-4dcc-40bf-953a-b3a53c0c1ea1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:25:00+00:00 +---------------------------------------- + +Instruction #127: + Timestep: 126 + Time: 2025-11-19 20:30:00+00:00 + ID: 7f0d47e6-ddd2-4eed-a5b3-e2f8ade1aee9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:30:00+00:00 +---------------------------------------- + +Instruction #128: + Timestep: 127 + Time: 2025-11-19 20:35:00+00:00 + ID: 436ffb11-8751-4aaa-9ba4-00955c2bab01 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:35:00+00:00 +---------------------------------------- + +Instruction #129: + Timestep: 128 + Time: 2025-11-19 20:40:00+00:00 + ID: 78ecc15c-15d1-42e7-af0a-9f96af624c0e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:40:00+00:00 +---------------------------------------- + +Instruction #130: + Timestep: 129 + Time: 2025-11-19 20:45:00+00:00 + ID: 3b1ef0bb-39f1-47b0-91a1-7fc73fa00f55 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:45:00+00:00 +---------------------------------------- + +Instruction #131: + Timestep: 130 + Time: 2025-11-19 20:50:00+00:00 + ID: f31594b4-1022-4f76-a2c2-d63fbb90ab6c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:50:00+00:00 +---------------------------------------- + +Instruction #132: + Timestep: 131 + Time: 2025-11-19 20:55:00+00:00 + ID: 78123622-f64b-467a-9110-94d4b0068750 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 20:55:00+00:00 +---------------------------------------- + +Instruction #133: + Timestep: 132 + Time: 2025-11-19 21:00:00+00:00 + ID: f426f67b-c929-4405-b79f-2e1399ef203c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:00:00+00:00 +---------------------------------------- + +Instruction #134: + Timestep: 133 + Time: 2025-11-19 21:05:00+00:00 + ID: ad55692e-7261-47c0-b635-868072115939 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:05:00+00:00 +---------------------------------------- + +Instruction #135: + Timestep: 134 + Time: 2025-11-19 21:10:00+00:00 + ID: 6f63545f-4b18-4906-a532-83cadffc6a25 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:10:00+00:00 +---------------------------------------- + +Instruction #136: + Timestep: 135 + Time: 2025-11-19 21:15:00+00:00 + ID: a82b5887-6d4a-423f-ab9d-6a8786b480ad + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:15:00+00:00 +---------------------------------------- + +Instruction #137: + Timestep: 136 + Time: 2025-11-19 21:20:00+00:00 + ID: 6a341c5c-2c6a-4d54-b79d-0ad07ad96ff0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:20:00+00:00 +---------------------------------------- + +Instruction #138: + Timestep: 137 + Time: 2025-11-19 21:25:00+00:00 + ID: 7401e0ba-665e-4050-8fa6-b833502a092a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:25:00+00:00 +---------------------------------------- + +Instruction #139: + Timestep: 138 + Time: 2025-11-19 21:30:00+00:00 + ID: 6efd4c2a-fcc6-4e3d-8446-5bebec39af05 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:30:00+00:00 +---------------------------------------- + +Instruction #140: + Timestep: 139 + Time: 2025-11-19 21:35:00+00:00 + ID: 0b4691f3-2b77-49a6-9bd7-b2cfbf9708bf + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:35:00+00:00 +---------------------------------------- + +Instruction #141: + Timestep: 140 + Time: 2025-11-19 21:40:00+00:00 + ID: ae4d28fa-927b-41cc-b0fe-b804c4cf2245 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:40:00+00:00 +---------------------------------------- + +Instruction #142: + Timestep: 141 + Time: 2025-11-19 21:45:00+00:00 + ID: 03e52894-fc3c-4c4d-af27-9504171a2b6e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:45:00+00:00 +---------------------------------------- + +Instruction #143: + Timestep: 142 + Time: 2025-11-19 21:50:00+00:00 + ID: 6c21c1ca-d09f-465b-9582-e561d847c47b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:50:00+00:00 +---------------------------------------- + +Instruction #144: + Timestep: 143 + Time: 2025-11-19 21:55:00+00:00 + ID: af35755a-3dd4-4379-a2ef-83ff04162870 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 21:55:00+00:00 +---------------------------------------- + +Instruction #145: + Timestep: 144 + Time: 2025-11-19 22:00:00+00:00 + ID: cbda5384-61dd-4908-b389-5cf4a39d7b76 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:00:00+00:00 +---------------------------------------- + +Instruction #146: + Timestep: 145 + Time: 2025-11-19 22:05:00+00:00 + ID: 656f1df1-85b0-41c3-aba5-0dfd6d1ef278 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:05:00+00:00 +---------------------------------------- + +Instruction #147: + Timestep: 146 + Time: 2025-11-19 22:10:00+00:00 + ID: 7e5bbb14-f8f5-49a7-8221-238484bff64a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:10:00+00:00 +---------------------------------------- + +Instruction #148: + Timestep: 147 + Time: 2025-11-19 22:15:00+00:00 + ID: a150a5d9-74b2-40b4-8d50-b25591d4bee9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:15:00+00:00 +---------------------------------------- + +Instruction #149: + Timestep: 148 + Time: 2025-11-19 22:20:00+00:00 + ID: 324822a1-90df-4238-bacc-a6bc66c2293c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:20:00+00:00 +---------------------------------------- + +Instruction #150: + Timestep: 149 + Time: 2025-11-19 22:25:00+00:00 + ID: c4c27988-d4fa-408e-9dce-0348884b3061 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:25:00+00:00 +---------------------------------------- + +Instruction #151: + Timestep: 150 + Time: 2025-11-19 22:30:00+00:00 + ID: fed2a1d2-3446-48de-9003-beb869268bc3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:30:00+00:00 +---------------------------------------- + +Instruction #152: + Timestep: 151 + Time: 2025-11-19 22:35:00+00:00 + ID: f0eb9994-45d1-459d-9562-661af0a083fb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:35:00+00:00 +---------------------------------------- + +Instruction #153: + Timestep: 152 + Time: 2025-11-19 22:40:00+00:00 + ID: 0059c104-938f-436f-8719-b951304d9fb7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:40:00+00:00 +---------------------------------------- + +Instruction #154: + Timestep: 153 + Time: 2025-11-19 22:45:00+00:00 + ID: 9159f26b-76f8-4622-8362-71b2b54270f7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:45:00+00:00 +---------------------------------------- + +Instruction #155: + Timestep: 154 + Time: 2025-11-19 22:50:00+00:00 + ID: efebfaa1-a3bd-4a5d-a8a6-24b0f5ef06e0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:50:00+00:00 +---------------------------------------- + +Instruction #156: + Timestep: 155 + Time: 2025-11-19 22:55:00+00:00 + ID: 0ba8afc1-8abd-47d0-8dd4-98de4de0259e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 22:55:00+00:00 +---------------------------------------- + +Instruction #157: + Timestep: 156 + Time: 2025-11-19 23:00:00+00:00 + ID: 1132acdc-1205-4e80-9379-cc6c76180a90 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:00:00+00:00 +---------------------------------------- + +Instruction #158: + Timestep: 157 + Time: 2025-11-19 23:05:00+00:00 + ID: 0ac6b656-6673-4c1c-bde6-cd637a02c603 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:05:00+00:00 +---------------------------------------- + +Instruction #159: + Timestep: 158 + Time: 2025-11-19 23:10:00+00:00 + ID: 57ac78f5-13bf-4c6e-b7e8-3eeade269852 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:10:00+00:00 +---------------------------------------- + +Instruction #160: + Timestep: 159 + Time: 2025-11-19 23:15:00+00:00 + ID: 40fef557-cf77-4356-addb-9583dfe641ad + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:15:00+00:00 +---------------------------------------- + +Instruction #161: + Timestep: 160 + Time: 2025-11-19 23:20:00+00:00 + ID: d4170bf5-61d4-452e-a7bb-9bf8300db562 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:20:00+00:00 +---------------------------------------- + +Instruction #162: + Timestep: 161 + Time: 2025-11-19 23:25:00+00:00 + ID: bde32bee-6d9b-4f7f-a351-339a6f31d72a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:25:00+00:00 +---------------------------------------- + +Instruction #163: + Timestep: 162 + Time: 2025-11-19 23:30:00+00:00 + ID: 461774af-451d-46d2-90c8-afbbc1d5e99b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:30:00+00:00 +---------------------------------------- + +Instruction #164: + Timestep: 163 + Time: 2025-11-19 23:35:00+00:00 + ID: 78f6a372-cbfd-4e70-89d9-578a2fad2c85 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:35:00+00:00 +---------------------------------------- + +Instruction #165: + Timestep: 164 + Time: 2025-11-19 23:40:00+00:00 + ID: 567f815f-fca3-4cc5-b7a2-d9b9f6f4e39f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:40:00+00:00 +---------------------------------------- + +Instruction #166: + Timestep: 165 + Time: 2025-11-19 23:45:00+00:00 + ID: 83d8cf28-a468-4c34-8091-6c9f7019fc3d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:45:00+00:00 +---------------------------------------- + +Instruction #167: + Timestep: 166 + Time: 2025-11-19 23:50:00+00:00 + ID: 2d15a48c-b0a5-4ecf-b577-e75b1aedae4e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:50:00+00:00 +---------------------------------------- + +Instruction #168: + Timestep: 167 + Time: 2025-11-19 23:55:00+00:00 + ID: 49bf1b60-be50-4be9-b3f9-e7c49efd745c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-19 23:55:00+00:00 +---------------------------------------- + +Instruction #169: + Timestep: 168 + Time: 2025-11-20 00:00:00+00:00 + ID: 6b93ed99-02a7-4c81-971e-9f0d44ea6ae7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:00:00+00:00 +---------------------------------------- + +Instruction #170: + Timestep: 169 + Time: 2025-11-20 00:05:00+00:00 + ID: ac9fcc84-948b-4678-9978-57ce115e37f8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:05:00+00:00 +---------------------------------------- + +Instruction #171: + Timestep: 170 + Time: 2025-11-20 00:10:00+00:00 + ID: 58fd2ccc-aa13-4af4-adbd-c8c2a9952170 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:10:00+00:00 +---------------------------------------- + +Instruction #172: + Timestep: 171 + Time: 2025-11-20 00:15:00+00:00 + ID: 2a83ef49-7859-48c7-a444-119ad36fbe3a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:15:00+00:00 +---------------------------------------- + +Instruction #173: + Timestep: 172 + Time: 2025-11-20 00:20:00+00:00 + ID: da9aec62-6d81-4d89-b1fe-2ecccbc320d8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:20:00+00:00 +---------------------------------------- + +Instruction #174: + Timestep: 173 + Time: 2025-11-20 00:25:00+00:00 + ID: 0ca85ae0-185f-43ca-a28d-6f6f6f244e59 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:25:00+00:00 +---------------------------------------- + +Instruction #175: + Timestep: 174 + Time: 2025-11-20 00:30:00+00:00 + ID: 731f786e-7f89-4206-a388-2ef97571d66c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:30:00+00:00 +---------------------------------------- + +Instruction #176: + Timestep: 175 + Time: 2025-11-20 00:35:00+00:00 + ID: 472b0605-05b6-4268-b453-dd24feb13c75 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:35:00+00:00 +---------------------------------------- + +Instruction #177: + Timestep: 176 + Time: 2025-11-20 00:40:00+00:00 + ID: 998e3115-5f36-49b5-9f2a-70c3882a8e94 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:40:00+00:00 +---------------------------------------- + +Instruction #178: + Timestep: 177 + Time: 2025-11-20 00:45:00+00:00 + ID: c948ee13-2efd-466c-a023-9631d49af0ae + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:45:00+00:00 +---------------------------------------- + +Instruction #179: + Timestep: 178 + Time: 2025-11-20 00:50:00+00:00 + ID: e3f3b401-1eb2-40bc-90d8-024b3f98b924 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:50:00+00:00 +---------------------------------------- + +Instruction #180: + Timestep: 179 + Time: 2025-11-20 00:55:00+00:00 + ID: 2bb32d70-b88f-4f83-8171-be0b579d9579 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 00:55:00+00:00 +---------------------------------------- + +Instruction #181: + Timestep: 180 + Time: 2025-11-20 01:00:00+00:00 + ID: cfc0bc0c-60a2-4d60-a49c-b554d7f25015 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:00:00+00:00 +---------------------------------------- + +Instruction #182: + Timestep: 181 + Time: 2025-11-20 01:05:00+00:00 + ID: 6e2f7bcb-33d0-4efc-acc1-de1d6d4f80cc + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:05:00+00:00 +---------------------------------------- + +Instruction #183: + Timestep: 182 + Time: 2025-11-20 01:10:00+00:00 + ID: e1ce7efb-3b7c-4832-9478-f2c4535491d0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:10:00+00:00 +---------------------------------------- + +Instruction #184: + Timestep: 183 + Time: 2025-11-20 01:15:00+00:00 + ID: 6799e5cf-3286-4811-a91e-9a38ba24139a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:15:00+00:00 +---------------------------------------- + +Instruction #185: + Timestep: 184 + Time: 2025-11-20 01:20:00+00:00 + ID: 9cb10857-fff9-43e1-909b-0dfba950506c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:20:00+00:00 +---------------------------------------- + +Instruction #186: + Timestep: 185 + Time: 2025-11-20 01:25:00+00:00 + ID: b8e7aed7-ec6c-4247-956a-bbd7243af597 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:25:00+00:00 +---------------------------------------- + +Instruction #187: + Timestep: 186 + Time: 2025-11-20 01:30:00+00:00 + ID: 6164eec7-5b9f-418a-8f2e-c5485ade4f53 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:30:00+00:00 +---------------------------------------- + +Instruction #188: + Timestep: 187 + Time: 2025-11-20 01:35:00+00:00 + ID: f0c55cd1-4550-4ee3-850f-b9882cbd029e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:35:00+00:00 +---------------------------------------- + +Instruction #189: + Timestep: 188 + Time: 2025-11-20 01:40:00+00:00 + ID: aa52bf5a-011f-48ab-b1b5-c8e0b1079ae1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:40:00+00:00 +---------------------------------------- + +Instruction #190: + Timestep: 189 + Time: 2025-11-20 01:45:00+00:00 + ID: 8e3b67ab-823d-4cc6-8500-2acdc8bdea80 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:45:00+00:00 +---------------------------------------- + +Instruction #191: + Timestep: 190 + Time: 2025-11-20 01:50:00+00:00 + ID: 65b63db5-e6e2-44bd-a064-b149b648fb99 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:50:00+00:00 +---------------------------------------- + +Instruction #192: + Timestep: 191 + Time: 2025-11-20 01:55:00+00:00 + ID: eb479956-4a35-455c-9022-5ea7489a34ed + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 01:55:00+00:00 +---------------------------------------- + +Instruction #193: + Timestep: 192 + Time: 2025-11-20 02:00:00+00:00 + ID: 8e1f70a0-638d-4e2b-bb9d-c5e78b346be2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:00:00+00:00 +---------------------------------------- + +Instruction #194: + Timestep: 193 + Time: 2025-11-20 02:05:00+00:00 + ID: 6d2079df-551d-4c0c-bd09-dde7f8c57e99 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:05:00+00:00 +---------------------------------------- + +Instruction #195: + Timestep: 194 + Time: 2025-11-20 02:10:00+00:00 + ID: fca0b279-68d0-44fa-a7a3-41cc36072241 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:10:00+00:00 +---------------------------------------- + +Instruction #196: + Timestep: 195 + Time: 2025-11-20 02:15:00+00:00 + ID: 13942e1a-6508-48d6-b7ef-3481710d4bb5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:15:00+00:00 +---------------------------------------- + +Instruction #197: + Timestep: 196 + Time: 2025-11-20 02:20:00+00:00 + ID: 145e72f5-15ef-4343-8369-237bd75a6713 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:20:00+00:00 +---------------------------------------- + +Instruction #198: + Timestep: 197 + Time: 2025-11-20 02:25:00+00:00 + ID: 8e05bb42-7499-4be5-ba2c-f48dd907708c + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:25:00+00:00 +---------------------------------------- + +Instruction #199: + Timestep: 198 + Time: 2025-11-20 02:30:00+00:00 + ID: d34411d6-3636-4899-9dca-854f3ca7bb92 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:30:00+00:00 +---------------------------------------- + +Instruction #200: + Timestep: 199 + Time: 2025-11-20 02:35:00+00:00 + ID: 7479cda1-2bde-4fab-8ecf-f9223d06b185 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:35:00+00:00 +---------------------------------------- + +Instruction #201: + Timestep: 200 + Time: 2025-11-20 02:40:00+00:00 + ID: 0e665ea8-9c1b-4026-b7a4-85e5a68c846e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:40:00+00:00 +---------------------------------------- + +Instruction #202: + Timestep: 201 + Time: 2025-11-20 02:45:00+00:00 + ID: b0aea9bd-982c-4279-966d-17fabedc46f3 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:45:00+00:00 +---------------------------------------- + +Instruction #203: + Timestep: 202 + Time: 2025-11-20 02:50:00+00:00 + ID: c0bca062-1d88-4a02-806b-59c4ee6aa8e9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:50:00+00:00 +---------------------------------------- + +Instruction #204: + Timestep: 203 + Time: 2025-11-20 02:55:00+00:00 + ID: 683aca55-f951-47de-885d-e0da2455ff26 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 02:55:00+00:00 +---------------------------------------- + +Instruction #205: + Timestep: 204 + Time: 2025-11-20 03:00:00+00:00 + ID: 09489495-3288-484c-b43b-2c0d42464a72 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:00:00+00:00 +---------------------------------------- + +Instruction #206: + Timestep: 205 + Time: 2025-11-20 03:05:00+00:00 + ID: 6b41e4f3-b174-4842-972e-9d0ae17b3342 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:05:00+00:00 +---------------------------------------- + +Instruction #207: + Timestep: 206 + Time: 2025-11-20 03:10:00+00:00 + ID: 10f1dbb2-e2c9-4fb7-80e3-9cb9a1ff7c3b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:10:00+00:00 +---------------------------------------- + +Instruction #208: + Timestep: 207 + Time: 2025-11-20 03:15:00+00:00 + ID: a3567989-8755-4c67-bb4d-0902f1f44a17 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:15:00+00:00 +---------------------------------------- + +Instruction #209: + Timestep: 208 + Time: 2025-11-20 03:20:00+00:00 + ID: db1cf121-9ceb-4836-a77d-ca5c1203b2d5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:20:00+00:00 +---------------------------------------- + +Instruction #210: + Timestep: 209 + Time: 2025-11-20 03:25:00+00:00 + ID: 51884a8e-8ce3-49f4-b1b1-bbbf9f5d3a88 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:25:00+00:00 +---------------------------------------- + +Instruction #211: + Timestep: 210 + Time: 2025-11-20 03:30:00+00:00 + ID: e9fa88c3-6ec1-4492-9a57-7673c77b3b7a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:30:00+00:00 +---------------------------------------- + +Instruction #212: + Timestep: 211 + Time: 2025-11-20 03:35:00+00:00 + ID: 72885f58-f71a-4487-9cd5-2e35f7d4b632 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:35:00+00:00 +---------------------------------------- + +Instruction #213: + Timestep: 212 + Time: 2025-11-20 03:40:00+00:00 + ID: 4862ecf1-e8f9-42ca-b449-3f9417f757de + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:40:00+00:00 +---------------------------------------- + +Instruction #214: + Timestep: 213 + Time: 2025-11-20 03:45:00+00:00 + ID: fa294000-5676-4cf2-8226-5e2f720d7c81 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:45:00+00:00 +---------------------------------------- + +Instruction #215: + Timestep: 214 + Time: 2025-11-20 03:50:00+00:00 + ID: ac5ef310-b3fc-458c-8bc6-2c4ff9172e1b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:50:00+00:00 +---------------------------------------- + +Instruction #216: + Timestep: 215 + Time: 2025-11-20 03:55:00+00:00 + ID: d53bf796-cabc-4ae9-80b7-2ba51bbbac86 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 03:55:00+00:00 +---------------------------------------- + +Instruction #217: + Timestep: 216 + Time: 2025-11-20 04:00:00+00:00 + ID: 79f55983-11fe-416c-82e8-0699f011a285 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:00:00+00:00 +---------------------------------------- + +Instruction #218: + Timestep: 217 + Time: 2025-11-20 04:05:00+00:00 + ID: 1b7dfc58-8aa4-4099-ad4d-86df284b598f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:05:00+00:00 +---------------------------------------- + +Instruction #219: + Timestep: 218 + Time: 2025-11-20 04:10:00+00:00 + ID: 57c20d65-af40-4f33-9f84-159647791e0a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:10:00+00:00 +---------------------------------------- + +Instruction #220: + Timestep: 219 + Time: 2025-11-20 04:15:00+00:00 + ID: 55f50815-69ce-43ab-bbb7-e57b9f74a742 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:15:00+00:00 +---------------------------------------- + +Instruction #221: + Timestep: 220 + Time: 2025-11-20 04:20:00+00:00 + ID: e0e67073-6985-484f-be71-8036e55337fd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:20:00+00:00 +---------------------------------------- + +Instruction #222: + Timestep: 221 + Time: 2025-11-20 04:25:00+00:00 + ID: 7bbaf451-a2f1-4d6a-965b-86b8a75375be + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:25:00+00:00 +---------------------------------------- + +Instruction #223: + Timestep: 222 + Time: 2025-11-20 04:30:00+00:00 + ID: 9b5a87c8-4f0e-4e06-9395-c4e9454021e7 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:30:00+00:00 +---------------------------------------- + +Instruction #224: + Timestep: 223 + Time: 2025-11-20 04:35:00+00:00 + ID: 201d3b1f-0c88-4678-a037-ed1f4bf50bfb + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:35:00+00:00 +---------------------------------------- + +Instruction #225: + Timestep: 224 + Time: 2025-11-20 04:40:00+00:00 + ID: 45b1b5e3-68bf-42e2-9636-8f588ef22579 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:40:00+00:00 +---------------------------------------- + +Instruction #226: + Timestep: 225 + Time: 2025-11-20 04:45:00+00:00 + ID: 8cf83935-24d8-4f9f-af89-189716716db0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:45:00+00:00 +---------------------------------------- + +Instruction #227: + Timestep: 226 + Time: 2025-11-20 04:50:00+00:00 + ID: 17e354ca-3f49-41d0-8260-7ef841cb4834 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:50:00+00:00 +---------------------------------------- + +Instruction #228: + Timestep: 227 + Time: 2025-11-20 04:55:00+00:00 + ID: c1ab8db7-5bd2-411f-8fc8-cbc9901dd598 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 04:55:00+00:00 +---------------------------------------- + +Instruction #229: + Timestep: 228 + Time: 2025-11-20 05:00:00+00:00 + ID: 4509ab25-74a4-4bb5-8a1c-b54d657320f1 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:00:00+00:00 +---------------------------------------- + +Instruction #230: + Timestep: 229 + Time: 2025-11-20 05:05:00+00:00 + ID: 11e3b4e9-9276-4de0-a0c2-556b0356d430 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:05:00+00:00 +---------------------------------------- + +Instruction #231: + Timestep: 230 + Time: 2025-11-20 05:10:00+00:00 + ID: 122e848b-6f69-4235-91f2-4df3ad3a1016 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:10:00+00:00 +---------------------------------------- + +Instruction #232: + Timestep: 231 + Time: 2025-11-20 05:15:00+00:00 + ID: dd615fb1-7035-489a-83ee-768710b4ae6a + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:15:00+00:00 +---------------------------------------- + +Instruction #233: + Timestep: 232 + Time: 2025-11-20 05:20:00+00:00 + ID: 9b04fe07-c2ed-4fbf-afe2-6eb067fd644b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:20:00+00:00 +---------------------------------------- + +Instruction #234: + Timestep: 233 + Time: 2025-11-20 05:25:00+00:00 + ID: 4437dc96-3f8f-4ae1-bacc-f4b90886db0e + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:25:00+00:00 +---------------------------------------- + +Instruction #235: + Timestep: 234 + Time: 2025-11-20 05:30:00+00:00 + ID: 269da291-0b0d-4fac-a8df-2c0cf5a01f65 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:30:00+00:00 +---------------------------------------- + +Instruction #236: + Timestep: 235 + Time: 2025-11-20 05:35:00+00:00 + ID: 9da4ab8e-5153-49ba-ad1e-d612046a6431 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:35:00+00:00 +---------------------------------------- + +Instruction #237: + Timestep: 236 + Time: 2025-11-20 05:40:00+00:00 + ID: 0e49ba1b-a92e-4131-aa0b-c7725b15ce14 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:40:00+00:00 +---------------------------------------- + +Instruction #238: + Timestep: 237 + Time: 2025-11-20 05:45:00+00:00 + ID: afee8542-bdec-49ed-87fb-34a27669f892 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:45:00+00:00 +---------------------------------------- + +Instruction #239: + Timestep: 238 + Time: 2025-11-20 05:50:00+00:00 + ID: 1a212380-c7d7-42c0-8322-614c86831bde + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:50:00+00:00 +---------------------------------------- + +Instruction #240: + Timestep: 239 + Time: 2025-11-20 05:55:00+00:00 + ID: f0615fa9-38a6-42c3-9ce1-380e845dd617 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 05:55:00+00:00 +---------------------------------------- + +Instruction #241: + Timestep: 240 + Time: 2025-11-20 06:00:00+00:00 + ID: 6738c7c0-b49e-4574-a105-b7d2fffbece4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:00:00+00:00 +---------------------------------------- + +Instruction #242: + Timestep: 241 + Time: 2025-11-20 06:05:00+00:00 + ID: a398619d-becb-4ffd-937e-93b50bbc16af + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:05:00+00:00 +---------------------------------------- + +Instruction #243: + Timestep: 242 + Time: 2025-11-20 06:10:00+00:00 + ID: 7dee5cf4-2be2-4e02-859b-a88049faec3b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:10:00+00:00 +---------------------------------------- + +Instruction #244: + Timestep: 243 + Time: 2025-11-20 06:15:00+00:00 + ID: 9cffc18b-ef4f-4431-a875-abdd21b3dd3f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:15:00+00:00 +---------------------------------------- + +Instruction #245: + Timestep: 244 + Time: 2025-11-20 06:20:00+00:00 + ID: b11bc621-cbf8-4e60-b565-5586d719722d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:20:00+00:00 +---------------------------------------- + +Instruction #246: + Timestep: 245 + Time: 2025-11-20 06:25:00+00:00 + ID: 22e2da11-583b-4baa-8b2f-39f87e8336f4 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:25:00+00:00 +---------------------------------------- + +Instruction #247: + Timestep: 246 + Time: 2025-11-20 06:30:00+00:00 + ID: a715fb3f-135b-4647-aa8d-a4ef855ad10f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:30:00+00:00 +---------------------------------------- + +Instruction #248: + Timestep: 247 + Time: 2025-11-20 06:35:00+00:00 + ID: 6994bc73-b446-45d5-ba4c-62f7798affc5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:35:00+00:00 +---------------------------------------- + +Instruction #249: + Timestep: 248 + Time: 2025-11-20 06:40:00+00:00 + ID: 8c520588-3ee7-4f62-8c2d-c162349c0cf9 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:40:00+00:00 +---------------------------------------- + +Instruction #250: + Timestep: 249 + Time: 2025-11-20 06:45:00+00:00 + ID: 1aae9a40-cfdc-44eb-9e66-35e574eb1305 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:45:00+00:00 +---------------------------------------- + +Instruction #251: + Timestep: 250 + Time: 2025-11-20 06:50:00+00:00 + ID: fcae4b23-8ec1-4a28-8a03-77d8ede3f898 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:50:00+00:00 +---------------------------------------- + +Instruction #252: + Timestep: 251 + Time: 2025-11-20 06:55:00+00:00 + ID: d48ff10e-dcc9-4a0e-b04c-22025a67edc5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 06:55:00+00:00 +---------------------------------------- + +Instruction #253: + Timestep: 252 + Time: 2025-11-20 07:00:00+00:00 + ID: 8287ab62-0fb0-48f5-95a6-2a03a404f150 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:00:00+00:00 +---------------------------------------- + +Instruction #254: + Timestep: 253 + Time: 2025-11-20 07:05:00+00:00 + ID: a372f94b-55cc-4282-8581-3cef77459ba0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:05:00+00:00 +---------------------------------------- + +Instruction #255: + Timestep: 254 + Time: 2025-11-20 07:10:00+00:00 + ID: 6c769e05-31df-4156-8615-e32e33f21227 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:10:00+00:00 +---------------------------------------- + +Instruction #256: + Timestep: 255 + Time: 2025-11-20 07:15:00+00:00 + ID: 0eb99564-4abc-44be-a12e-5b53511caf4b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:15:00+00:00 +---------------------------------------- + +Instruction #257: + Timestep: 256 + Time: 2025-11-20 07:20:00+00:00 + ID: 0201dd39-5e1a-4478-a08c-da2cb0710bfd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:20:00+00:00 +---------------------------------------- + +Instruction #258: + Timestep: 257 + Time: 2025-11-20 07:25:00+00:00 + ID: 3eb97923-073d-48ba-a547-a3bbf48dc45d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:25:00+00:00 +---------------------------------------- + +Instruction #259: + Timestep: 258 + Time: 2025-11-20 07:30:00+00:00 + ID: 0cc18bec-fbd6-4a4d-ae99-15aebd79e8dd + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:30:00+00:00 +---------------------------------------- + +Instruction #260: + Timestep: 259 + Time: 2025-11-20 07:35:00+00:00 + ID: e3e79ea0-6d30-459e-a216-6b9c859d2826 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:35:00+00:00 +---------------------------------------- + +Instruction #261: + Timestep: 260 + Time: 2025-11-20 07:40:00+00:00 + ID: c954196f-9978-4cb5-9d92-edc1ad2e7f03 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:40:00+00:00 +---------------------------------------- + +Instruction #262: + Timestep: 261 + Time: 2025-11-20 07:45:00+00:00 + ID: 4528ec70-d0d9-4351-8c43-56179f6c5372 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:45:00+00:00 +---------------------------------------- + +Instruction #263: + Timestep: 262 + Time: 2025-11-20 07:50:00+00:00 + ID: 93d884b5-b359-47ac-91a7-3c2ca97d83a5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:50:00+00:00 +---------------------------------------- + +Instruction #264: + Timestep: 263 + Time: 2025-11-20 07:55:00+00:00 + ID: fbce642a-0e1b-4c7d-a104-771cb743479f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 07:55:00+00:00 +---------------------------------------- + +Instruction #265: + Timestep: 264 + Time: 2025-11-20 08:00:00+00:00 + ID: 0da438fc-cfcb-4ae0-860e-b42a804161b6 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:00:00+00:00 +---------------------------------------- + +Instruction #266: + Timestep: 265 + Time: 2025-11-20 08:05:00+00:00 + ID: 914ef2c2-f573-429b-95e0-57e3adedda4d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:05:00+00:00 +---------------------------------------- + +Instruction #267: + Timestep: 266 + Time: 2025-11-20 08:10:00+00:00 + ID: 4b1ee423-a543-4fe0-b46d-a9faa5748d40 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:10:00+00:00 +---------------------------------------- + +Instruction #268: + Timestep: 267 + Time: 2025-11-20 08:15:00+00:00 + ID: 70c078db-ae3d-476f-b585-f27bcd91620f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:15:00+00:00 +---------------------------------------- + +Instruction #269: + Timestep: 268 + Time: 2025-11-20 08:20:00+00:00 + ID: bbcc7c7e-4aff-4666-b51a-19fb9402fa47 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:20:00+00:00 +---------------------------------------- + +Instruction #270: + Timestep: 269 + Time: 2025-11-20 08:25:00+00:00 + ID: 3e4c5682-84d3-43e9-946f-f77a5a7bd4e8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:25:00+00:00 +---------------------------------------- + +Instruction #271: + Timestep: 270 + Time: 2025-11-20 08:30:00+00:00 + ID: 80396301-9dce-4490-b1a1-7d19182da769 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:30:00+00:00 +---------------------------------------- + +Instruction #272: + Timestep: 271 + Time: 2025-11-20 08:35:00+00:00 + ID: ff56dc47-2c2d-466e-8d10-23da0d2f2c4d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:35:00+00:00 +---------------------------------------- + +Instruction #273: + Timestep: 272 + Time: 2025-11-20 08:40:00+00:00 + ID: e9af8b18-241c-4009-8415-c2dbb66355ae + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:40:00+00:00 +---------------------------------------- + +Instruction #274: + Timestep: 273 + Time: 2025-11-20 08:45:00+00:00 + ID: 9e8d2adc-d2cf-4dc2-8795-693f1ffa1313 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:45:00+00:00 +---------------------------------------- + +Instruction #275: + Timestep: 274 + Time: 2025-11-20 08:50:00+00:00 + ID: 7c959381-7e1f-40b5-9f6f-abd6dae934c8 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:50:00+00:00 +---------------------------------------- + +Instruction #276: + Timestep: 275 + Time: 2025-11-20 08:55:00+00:00 + ID: 54e87ae1-e5ad-4023-a6f4-22bde56f2b5f + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 08:55:00+00:00 +---------------------------------------- + +Instruction #277: + Timestep: 276 + Time: 2025-11-20 09:00:00+00:00 + ID: e98b4546-35f1-402b-a580-0744eb63fbb2 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:00:00+00:00 +---------------------------------------- + +Instruction #278: + Timestep: 277 + Time: 2025-11-20 09:05:00+00:00 + ID: 6aba851a-33c0-4539-8837-6af92e866766 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:05:00+00:00 +---------------------------------------- + +Instruction #279: + Timestep: 278 + Time: 2025-11-20 09:10:00+00:00 + ID: bb7083f6-df53-4c64-8184-f6e79036ac77 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:10:00+00:00 +---------------------------------------- + +Instruction #280: + Timestep: 279 + Time: 2025-11-20 09:15:00+00:00 + ID: 3ec0fc2a-1827-4943-9a0c-35d36852150b + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:15:00+00:00 +---------------------------------------- + +Instruction #281: + Timestep: 280 + Time: 2025-11-20 09:20:00+00:00 + ID: 8889d42b-8f01-4668-a46f-8cd65cf6e3ee + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:20:00+00:00 +---------------------------------------- + +Instruction #282: + Timestep: 281 + Time: 2025-11-20 09:25:00+00:00 + ID: d313c40e-74ad-4881-95db-56bb2e175118 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:25:00+00:00 +---------------------------------------- + +Instruction #283: + Timestep: 282 + Time: 2025-11-20 09:30:00+00:00 + ID: 0812cbaa-02c0-4779-bee7-130332da7dea + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:30:00+00:00 +---------------------------------------- + +Instruction #284: + Timestep: 283 + Time: 2025-11-20 09:35:00+00:00 + ID: 1af91293-3b2a-4ac0-9082-14c62c0a560d + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:35:00+00:00 +---------------------------------------- + +Instruction #285: + Timestep: 284 + Time: 2025-11-20 09:40:00+00:00 + ID: a91a93f0-fb68-434d-9e6f-44153fd58331 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:40:00+00:00 +---------------------------------------- + +Instruction #286: + Timestep: 285 + Time: 2025-11-20 09:45:00+00:00 + ID: f5f79c47-e341-404d-9466-fc9d1eb89486 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:45:00+00:00 +---------------------------------------- + +Instruction #287: + Timestep: 286 + Time: 2025-11-20 09:50:00+00:00 + ID: e126bdba-e3b5-4e71-82ad-ab95b00ab4a5 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:50:00+00:00 +---------------------------------------- + +Instruction #288: + Timestep: 287 + Time: 2025-11-20 09:55:00+00:00 + ID: 0aff01a8-fb77-4009-99eb-99d5f47a97a0 + Actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 + Operation Mode: DHW_OFF + Operation Mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 + Operation Mode Factor: 0.0 + Execution Time: 2025-11-20 09:55:00+00:00 +---------------------------------------- diff --git a/flexmeasures_s2/profile_steering/examples/itho.yaml b/flexmeasures_s2/profile_steering/examples/itho.yaml new file mode 100644 index 0000000..15e96a0 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/itho.yaml @@ -0,0 +1,192 @@ + INFO: 📋 FRBC.SystemDescription +[FLEXMEASURES][2025-11-03 08:13:02,259] DEBUG: {"message_type":"FRBC.SystemDescription","message_id":"56b1c93f-7bf9-4f40-a0c2-8996309bad87","valid_from":"2025-11-03T08:12:42.561432Z","actuators":[{"id":"189f6a58-e78a-4c3f-bcda-6cd151342285","diagnostic_label":"Heat Pump (DHW)","supported_commodities":["ELECTRICITY"],"operation_modes":[{"id":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","diagnostic_label":"DHW_OFF","elements":[{"fill_level_range":{"start_of_range":0.0,"end_of_range":100.0},"fill_rate":{"start_of_range":0.0,"end_of_range":0.0},"power_ranges":[{"start_of_range":0.0,"end_of_range":0.0,"commodity_quantity":"ELECTRIC.POWER.L1"}],"running_costs":{"start_of_range":0.0,"end_of_range":0.0}}],"abnormal_condition_only":false},{"id":"31314092-4456-43f8-89dd-0421194bc821","diagnostic_label":"DHW_ON","elements":[{"fill_level_range":{"start_of_range":10.0,"end_of_range":61.5},"fill_rate":{"start_of_range":0.002031807896078361,"end_of_range":0.002031807896078361},"power_ranges":[{"start_of_range":1100.0,"end_of_range":1100.0,"commodity_quantity":"ELECTRIC.POWER.L1"}]}],"abnormal_condition_only":false}],"transitions":[{"id":"4359a2e3-8782-4192-9775-2a29b828c45e","from":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","to":"31314092-4456-43f8-89dd-0421194bc821","start_timers":["702cd17f-ac40-429e-93d4-ce69c8eb8040"],"blocking_timers":["b27ef8c9-c440-44cb-8deb-f7f85f491a92"],"transition_duration":300000,"abnormal_condition_only":false},{"id":"8d3bdeae-5052-4579-a62b-a36b427df63a","from":"31314092-4456-43f8-89dd-0421194bc821","to":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","start_timers":["b27ef8c9-c440-44cb-8deb-f7f85f491a92"],"blocking_timers":["702cd17f-ac40-429e-93d4-ce69c8eb8040"],"transition_duration":180000,"abnormal_condition_only":false}],"timers":[{"id":"702cd17f-ac40-429e-93d4-ce69c8eb8040","diagnostic_label":"DHW Minimum On Time","duration":1800000},{"id":"b27ef8c9-c440-44cb-8deb-f7f85f491a92","diagnostic_label":"DHW Minimum Off Time","duration":600000}]}],"storage":{"diagnostic_label":"DHW Buffer","fill_level_label":"Temperature in degrees Celcius","provides_leakage_behaviour":true,"provides_fill_level_target_profile":true,"provides_usage_forecast":true,"fill_level_range":{"start_of_range":10.0,"end_of_range":61.5}}} +[FLEXMEASURES][2025-11-03 08:13:02,264] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:13:02,302] DEBUG: ⚙️ Actuator 189f6a58...: 2 modes, 2 transitions, 2 timers +[FLEXMEASURES][2025-11-03 08:13:02,310] DEBUG: 💾 Storage: 10.0-61.5 Temperature in degrees Celcius +[FLEXMEASURES][2025-11-03 08:13:02,311] INFO: 📋 SystemDescription: 1 actuator(s) +[FLEXMEASURES][2025-11-03 08:13:02,311] DEBUG: ⏳ Missing actuator status for: 189f6a58-e78a-4c3f-bcda-6cd151342285 +[FLEXMEASURES][2025-11-03 08:13:02,312] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ❌ ActuatorStatus (0/1 received) +[FLEXMEASURES][2025-11-03 08:13:02,312] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus, ActuatorStatus +[FLEXMEASURES][2025-11-03 08:13:03,996] INFO: 📋 FRBC.SystemDescription +[FLEXMEASURES][2025-11-03 08:13:04,006] DEBUG: {"message_type":"FRBC.SystemDescription","message_id":"ae668e82-c315-48a3-80be-7d3389b3e4b4","valid_from":"2025-11-03T08:12:44.399427Z","actuators":[{"id":"189f6a58-e78a-4c3f-bcda-6cd151342285","diagnostic_label":"Heat Pump (DHW)","supported_commodities":["ELECTRICITY"],"operation_modes":[{"id":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","diagnostic_label":"DHW_OFF","elements":[{"fill_level_range":{"start_of_range":0.0,"end_of_range":100.0},"fill_rate":{"start_of_range":0.0,"end_of_range":0.0},"power_ranges":[{"start_of_range":0.0,"end_of_range":0.0,"commodity_quantity":"ELECTRIC.POWER.3_PHASE_SYMMETRIC"}],"running_costs":{"start_of_range":0.0,"end_of_range":0.0}}],"abnormal_condition_only":false},{"id":"31314092-4456-43f8-89dd-0421194bc821","diagnostic_label":"DHW_ON","elements":[{"fill_level_range":{"start_of_range":10.0,"end_of_range":61.5},"fill_rate":{"start_of_range":0.010397806827295799,"end_of_range":0.010397806827295799},"power_ranges":[{"start_of_range":2060.9,"end_of_range":2060.9,"commodity_quantity":"ELECTRIC.POWER.3_PHASE_SYMMETRIC"}]}],"abnormal_condition_only":false}],"transitions":[{"id":"4359a2e3-8782-4192-9775-2a29b828c45e","from":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","to":"31314092-4456-43f8-89dd-0421194bc821","start_timers":["702cd17f-ac40-429e-93d4-ce69c8eb8040"],"blocking_timers":["b27ef8c9-c440-44cb-8deb-f7f85f491a92"],"transition_duration":300000,"abnormal_condition_only":false},{"id":"8d3bdeae-5052-4579-a62b-a36b427df63a","from":"31314092-4456-43f8-89dd-0421194bc821","to":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","start_timers":["b27ef8c9-c440-44cb-8deb-f7f85f491a92"],"blocking_timers":["702cd17f-ac40-429e-93d4-ce69c8eb8040"],"transition_duration":180000,"abnormal_condition_only":false}],"timers":[{"id":"702cd17f-ac40-429e-93d4-ce69c8eb8040","diagnostic_label":"DHW Minimum On Time","duration":1800000},{"id":"b27ef8c9-c440-44cb-8deb-f7f85f491a92","diagnostic_label":"DHW Minimum Off Time","duration":600000}]}],"storage":{"diagnostic_label":"DHW Buffer","fill_level_label":"Temperature in degrees Celcius","provides_leakage_behaviour":true,"provides_fill_level_target_profile":true,"provides_usage_forecast":true,"fill_level_range":{"start_of_range":10.0,"end_of_range":61.5}}} +[FLEXMEASURES][2025-11-03 08:13:04,008] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:13:04,034] INFO: 📋 FRBC.SystemDescription +[FLEXMEASURES][2025-11-03 08:13:04,037] DEBUG: {"message_type":"FRBC.SystemDescription","message_id":"d8d28734-7073-4a7a-967c-6047f4f35e1f","valid_from":"2025-11-03T08:12:44.405821Z","actuators":[{"id":"189f6a58-e78a-4c3f-bcda-6cd151342285","diagnostic_label":"Heat Pump (DHW)","supported_commodities":["ELECTRICITY"],"operation_modes":[{"id":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","diagnostic_label":"DHW_OFF","elements":[{"fill_level_range":{"start_of_range":0.0,"end_of_range":100.0},"fill_rate":{"start_of_range":0.0,"end_of_range":0.0},"power_ranges":[{"start_of_range":0.0,"end_of_range":0.0,"commodity_quantity":"ELECTRIC.POWER.3_PHASE_SYMMETRIC"}],"running_costs":{"start_of_range":0.0,"end_of_range":0.0}}],"abnormal_condition_only":false},{"id":"31314092-4456-43f8-89dd-0421194bc821","diagnostic_label":"DHW_ON","elements":[{"fill_level_range":{"start_of_range":10.0,"end_of_range":45.0},"fill_rate":{"start_of_range":0.010657432945423886,"end_of_range":0.010657432945423886},"power_ranges":[{"start_of_range":1596.1,"end_of_range":1596.1,"commodity_quantity":"ELECTRIC.POWER.3_PHASE_SYMMETRIC"}]}],"abnormal_condition_only":false}],"transitions":[{"id":"4359a2e3-8782-4192-9775-2a29b828c45e","from":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","to":"31314092-4456-43f8-89dd-0421194bc821","start_timers":["702cd17f-ac40-429e-93d4-ce69c8eb8040"],"blocking_timers":["b27ef8c9-c440-44cb-8deb-f7f85f491a92"],"transition_duration":300000,"abnormal_condition_only":false},{"id":"8d3bdeae-5052-4579-a62b-a36b427df63a","from":"31314092-4456-43f8-89dd-0421194bc821","to":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","start_timers":["b27ef8c9-c440-44cb-8deb-f7f85f491a92"],"blocking_timers":["702cd17f-ac40-429e-93d4-ce69c8eb8040"],"transition_duration":180000,"abnormal_condition_only":false}],"timers":[{"id":"702cd17f-ac40-429e-93d4-ce69c8eb8040","diagnostic_label":"DHW Minimum On Time","duration":1800000},{"id":"b27ef8c9-c440-44cb-8deb-f7f85f491a92","diagnostic_label":"DHW Minimum Off Time","duration":600000}]}],"storage":{"diagnostic_label":"DHW Buffer","fill_level_label":"Temperature in degrees Celcius","provides_leakage_behaviour":true,"provides_fill_level_target_profile":true,"provides_usage_forecast":true,"fill_level_range":{"start_of_range":10.0,"end_of_range":45.0}}} +[FLEXMEASURES][2025-11-03 08:13:04,037] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:13:04,043] DEBUG: ⚙️ Actuator 189f6a58...: 2 modes, 2 transitions, 2 timers +[FLEXMEASURES][2025-11-03 08:13:04,052] DEBUG: 💾 Storage: 10.0-61.5 Temperature in degrees Celcius +[FLEXMEASURES][2025-11-03 08:13:04,053] DEBUG: ⚙️ Actuator 189f6a58...: 2 modes, 2 transitions, 2 timers +[FLEXMEASURES][2025-11-03 08:13:04,053] INFO: 📋 SystemDescription: 1 actuator(s) +[FLEXMEASURES][2025-11-03 08:13:04,054] DEBUG: ⏳ Missing actuator status for: 189f6a58-e78a-4c3f-bcda-6cd151342285 +[FLEXMEASURES][2025-11-03 08:13:04,054] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ❌ ActuatorStatus (0/1 received) +[FLEXMEASURES][2025-11-03 08:13:04,054] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus, ActuatorStatus +[FLEXMEASURES][2025-11-03 08:13:04,064] DEBUG: 💾 Storage: 10.0-45.0 Temperature in degrees Celcius +[FLEXMEASURES][2025-11-03 08:13:04,065] INFO: 📋 SystemDescription: 1 actuator(s) +[FLEXMEASURES][2025-11-03 08:13:04,065] DEBUG: ⏳ Missing actuator status for: 189f6a58-e78a-4c3f-bcda-6cd151342285 +[FLEXMEASURES][2025-11-03 08:13:04,065] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ❌ ActuatorStatus (0/1 received) +[FLEXMEASURES][2025-11-03 08:13:04,066] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus, ActuatorStatus +[FLEXMEASURES][2025-11-03 08:13:23,415] INFO: 📥 PowerMeasurement +[FLEXMEASURES][2025-11-03 08:13:26,546] DEBUG: {"message_type":"PowerMeasurement","message_id":"51a2cb16-7482-4d83-b821-4650ad7ac4e4","measurement_timestamp":"2025-11-03T08:13:03.688588Z","values":[{"commodity_quantity":"ELECTRIC.POWER.L1","value":1100.0}]} +[FLEXMEASURES][2025-11-03 08:13:27,227] INFO: 📥 PowerMeasurement +[FLEXMEASURES][2025-11-03 08:13:28,343] INFO: 📥 PowerMeasurement +[FLEXMEASURES][2025-11-03 08:13:28,484] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:13:31,850] DEBUG: {"message_type":"PowerMeasurement","message_id":"9df1cb51-2a02-467b-8491-2eed109fa8b9","measurement_timestamp":"2025-11-03T08:13:05.588639Z","values":[{"commodity_quantity":"ELECTRIC.POWER.3_PHASE_SYMMETRIC","value":2.2}]} +[FLEXMEASURES][2025-11-03 08:13:32,776] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:13:32,593] DEBUG: {"message_type":"PowerMeasurement","message_id":"c8d6c04a-eb31-46d6-a307-f5de1c6e8375","measurement_timestamp":"2025-11-03T08:13:05.725115Z","values":[{"commodity_quantity":"ELECTRIC.POWER.3_PHASE_SYMMETRIC","value":2.8}]} +[FLEXMEASURES][2025-11-03 08:13:34,551] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:13:36,544] INFO: ⚙️ FRBC.ActuatorStatus +[FLEXMEASURES][2025-11-03 08:13:37,444] INFO: ⚙️ FRBC.ActuatorStatus +[FLEXMEASURES][2025-11-03 08:13:37,447] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:13:37,449] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:13:37,450] INFO: ⚙️ FRBC.ActuatorStatus +[FLEXMEASURES][2025-11-03 08:13:37,450] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:13:37,548] DEBUG: ⚙️ ActuatorStatus: factor=0.0 +[FLEXMEASURES][2025-11-03 08:13:37,553] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:13:37,553] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus +[FLEXMEASURES][2025-11-03 08:13:37,553] DEBUG: ⚙️ ActuatorStatus: factor=0.0 +[FLEXMEASURES][2025-11-03 08:13:37,554] DEBUG: ⚙️ ActuatorStatus: factor=1.0 +[FLEXMEASURES][2025-11-03 08:13:37,554] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:13:37,555] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus +[FLEXMEASURES][2025-11-03 08:13:37,554] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:13:37,555] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus +[FLEXMEASURES][2025-11-03 08:13:55,822] ERROR: NotFound:"The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again." [occurred at /usr/local/lib/python3.10/dist-packages/werkzeug/routing/map.py(match):629,URL was: /cgi-bin/luci/;stok=/locale] +Traceback (most recent call last): + File "/usr/local/lib/python3.10/dist-packages/flask/app.py", line 880, in full_dispatch_request + rv = self.dispatch_request() + File "/usr/local/lib/python3.10/dist-packages/flask/app.py", line 854, in dispatch_request + self.raise_routing_exception(req) + File "/usr/local/lib/python3.10/dist-packages/flask/app.py", line 463, in raise_routing_exception + raise request.routing_exception # type: ignore[misc] + File "/usr/local/lib/python3.10/dist-packages/flask/ctx.py", line 362, in match_request + result = self.url_adapter.match(return_rule=True) # type: ignore + File "/usr/local/lib/python3.10/dist-packages/werkzeug/routing/map.py", line 629, in match + raise NotFound() from None +werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. +[FLEXMEASURES][2025-11-03 08:14:02,291] INFO: ⚙️ FRBC.ActuatorStatus +[FLEXMEASURES][2025-11-03 08:14:02,297] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:14:02,321] DEBUG: ⚙️ ActuatorStatus: factor=1.0 +[FLEXMEASURES][2025-11-03 08:14:02,322] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:14:02,322] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus +[FLEXMEASURES][2025-11-03 08:14:02,323] INFO: 📥 FRBC.LeakageBehaviour +[FLEXMEASURES][2025-11-03 08:14:02,324] DEBUG: {"message_type":"FRBC.LeakageBehaviour","message_id":"34c000d1-0140-4589-988f-12c80902169f","valid_from":"2025-11-03T08:13:42.632614Z","elements":[{"fill_level_range":{"start_of_range":10.0,"end_of_range":61.5},"leakage_rate":0.00004464134898917508}]} +[FLEXMEASURES][2025-11-03 08:14:02,325] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:14:04,030] INFO: ⚙️ FRBC.ActuatorStatus +[FLEXMEASURES][2025-11-03 08:14:04,037] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:14:04,057] DEBUG: ⚙️ ActuatorStatus: factor=0.0 +[FLEXMEASURES][2025-11-03 08:14:04,057] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:14:04,058] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus +[FLEXMEASURES][2025-11-03 08:14:04,060] INFO: 📥 FRBC.LeakageBehaviour +[FLEXMEASURES][2025-11-03 08:14:04,061] DEBUG: {"message_type":"FRBC.LeakageBehaviour","message_id":"301c976d-a646-4711-95af-37a69bf14b1b","valid_from":"2025-11-03T08:13:44.451202Z","elements":[{"fill_level_range":{"start_of_range":10.0,"end_of_range":61.5},"leakage_rate":0.00004222830309786831}]} +[FLEXMEASURES][2025-11-03 08:14:04,061] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:14:04,091] INFO: ⚙️ FRBC.ActuatorStatus +[FLEXMEASURES][2025-11-03 08:14:04,091] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:14:04,100] DEBUG: ⚙️ ActuatorStatus: factor=0.0 +[FLEXMEASURES][2025-11-03 08:14:04,100] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:14:04,100] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus +[FLEXMEASURES][2025-11-03 08:14:04,102] INFO: 📥 FRBC.LeakageBehaviour +[FLEXMEASURES][2025-11-03 08:14:04,103] DEBUG: {"message_type":"FRBC.LeakageBehaviour","message_id":"80a4c0a4-8814-4e21-9f1f-5cd038d4de6d","valid_from":"2025-11-03T08:13:44.479542Z","elements":[{"fill_level_range":{"start_of_range":10.0,"end_of_range":45.0},"leakage_rate":0.00004464134898917508}]} +[FLEXMEASURES][2025-11-03 08:14:04,103] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:15:14,782] INFO: 🔋 FRBC.StorageStatus +[FLEXMEASURES][2025-11-03 08:15:19,702] INFO: 🔋 FRBC.StorageStatus +[FLEXMEASURES][2025-11-03 08:15:19,700] INFO: 🔋 FRBC.StorageStatus +[FLEXMEASURES][2025-11-03 08:15:19,798] DEBUG: {"message_type":"FRBC.StorageStatus","message_id":"d0970b64-b069-4738-96c5-b4318e6ce5cf","present_fill_level":42.4669997} +[FLEXMEASURES][2025-11-03 08:15:19,858] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:15:19,861] DEBUG: {"message_type":"FRBC.StorageStatus","message_id":"e101ac35-566d-4a27-8055-625ea344f50b","present_fill_level":16.182} +[FLEXMEASURES][2025-11-03 08:15:19,902] DEBUG: {"message_type":"FRBC.StorageStatus","message_id":"fdef46a5-c812-4167-a3db-22518aa18654","present_fill_level":29.5889991} +[FLEXMEASURES][2025-11-03 08:15:19,900] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:15:19,939] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:15:20,022] WARNING: Resource could not be saved as an asset: This session is provisioning a new connection; concurrent operations are not permitted (Background on this error at: https://sqlalche.me/e/20/isce) +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:633: SAWarning: Object of type not in session, add operation along 'Sensor.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + df = pd.DataFrame(session.execute(q)) +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:633: SAWarning: Object of type not in session, add operation along 'DataSource.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + df = pd.DataFrame(session.execute(q)) +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:633: SAWarning: Object of type not in session, add operation along 'Sensor.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + df = pd.DataFrame(session.execute(q)) +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:633: SAWarning: Object of type not in session, add operation along 'DataSource.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + df = pd.DataFrame(session.execute(q)) +[FLEXMEASURES][2025-11-03 08:15:21,233] INFO: SAVING TO DB... +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:332: SAWarning: Object of type not in session, add operation along 'Sensor.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + session.execute(smt) +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:332: SAWarning: Object of type not in session, add operation along 'DataSource.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + session.execute(smt) +[FLEXMEASURES][2025-11-03 08:15:21,464] INFO: 🔋 StorageStatus: 16.2% +[FLEXMEASURES][2025-11-03 08:15:21,471] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ✅ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:15:21,471] INFO: ⏳ Waiting for: FillLevelTargetProfile +[FLEXMEASURES][2025-11-03 08:15:21,516] INFO: 🎯 FRBC.FillLevelTargetProfile +[FLEXMEASURES][2025-11-03 08:15:21,528] DEBUG: {"message_type":"FRBC.FillLevelTargetProfile","message_id":"a9fbad67-2b93-493e-8c95-11098f9ba85a","start_time":"2025-11-02T23:00:00Z","elements":[{"duration":23400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":55.0}},{"duration":5400000,"fill_level_range":{"start_of_range":51.5,"end_of_range":55.0}},{"duration":32400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":55.0}},{"duration":10800000,"fill_level_range":{"start_of_range":51.5,"end_of_range":55.0}},{"duration":14400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":55.0}},{"duration":23400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":55.0}},{"duration":5400000,"fill_level_range":{"start_of_range":51.5,"end_of_range":55.0}},{"duration":32400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":55.0}},{"duration":10800000,"fill_level_range":{"start_of_range":51.5,"end_of_range":55.0}},{"duration":14400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":55.0}}]} +[FLEXMEASURES][2025-11-03 08:15:21,531] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:15:21,587] DEBUG: 🎯 Start: 23:00:00 +[FLEXMEASURES][2025-11-03 08:15:21,591] INFO: 🎯 TargetProfile: 10 element(s) +[FLEXMEASURES][2025-11-03 08:15:21,592] DEBUG: 📊 Device readiness: ✅ SystemDescription | ✅ FillLevelTargetProfile | ✅ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:15:21,594] INFO: 🎯 Generating instructions for 3c4cdc54... +[FLEXMEASURES][2025-11-03 08:15:21,595] DEBUG: 🔧 Creating device state for 3c4cdc54... +[FLEXMEASURES][2025-11-03 08:15:21,636] DEBUG: Storage status used for scheduler: message_type='FRBC.StorageStatus' message_id=UUID('e101ac35-566d-4a27-8055-625ea344f50b') present_fill_level=16.182 +[FLEXMEASURES][2025-11-03 08:15:21,642] DEBUG: Present fill level used for scheduler: 16.182 +[FLEXMEASURES][2025-11-03 08:15:21,642] DEBUG: ✅ Device state ready: 3c4cdc54... +[FLEXMEASURES][2025-11-03 08:15:21,644] INFO: 🧮 S2FlaskScheduler started +[FLEXMEASURES][2025-11-03 08:15:21,646] DEBUG: 🔧 Creating device state for 3c4cdc54... +[FLEXMEASURES][2025-11-03 08:15:21,649] DEBUG: Storage status used for scheduler: message_type='FRBC.StorageStatus' message_id=UUID('e101ac35-566d-4a27-8055-625ea344f50b') present_fill_level=16.182 +[FLEXMEASURES][2025-11-03 08:15:21,649] DEBUG: Present fill level used for scheduler: 16.182 +[FLEXMEASURES][2025-11-03 08:15:21,649] DEBUG: ✅ Device state ready: 3c4cdc54... +[FLEXMEASURES][2025-11-03 08:15:21,814] INFO: SAVING TO DB... +[FLEXMEASURES][2025-11-03 08:15:21,880] WARNING: ⚠️ All prices missing, assuming 1 EUR/MWh +[FLEXMEASURES][2025-11-03 08:15:21,923] DEBUG: 📊 Cluster: 1 device(s) in state +[FLEXMEASURES][2025-11-03 08:15:21,928] INFO: 📊 Planning: 24.0h window (08:15 → 08:15) +[FLEXMEASURES][2025-11-03 08:15:21,932] DEBUG: ⏱️ Resolution: 0:05:00, Belief time: 17:05:00 +[FLEXMEASURES][2025-11-03 08:15:21,932] DEBUG: 🧮 Running optimization algorithm... +[FLEXMEASURES][2025-11-03 08:15:21,932] WARNING: CongestionPoint without target! CongestionPoint: . Generating empty target. +[FLEXMEASURES][2025-11-03 08:15:21,934] DEBUG: S2 FRBC planner created! +[FLEXMEASURES][2025-11-03 08:15:22,005] INFO: SAVING TO DB... +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:332: SAWarning: Object of type not in session, add operation along 'Sensor.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + session.execute(smt) +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:332: SAWarning: Object of type not in session, add operation along 'DataSource.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + session.execute(smt) +[FLEXMEASURES][2025-11-03 08:24:25,249] INFO: 🔋 StorageStatus: 42.5% +[FLEXMEASURES][2025-11-03 08:24:25,252] INFO: 🔋 StorageStatus: 29.6% +[FLEXMEASURES][2025-11-03 08:24:25,258] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ✅ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:24:25,258] INFO: ⏳ Waiting for: FillLevelTargetProfile +[FLEXMEASURES][2025-11-03 08:24:25,259] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ✅ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:24:25,259] INFO: ⏳ Waiting for: FillLevelTargetProfile +[FLEXMEASURES][2025-11-03 08:24:25,327] INFO: 🎯 FRBC.FillLevelTargetProfile +[FLEXMEASURES][2025-11-03 08:24:25,326] INFO: 🎯 FRBC.FillLevelTargetProfile +[FLEXMEASURES][2025-11-03 08:24:25,335] DEBUG: {"message_type":"FRBC.FillLevelTargetProfile","message_id":"c208fb58-c2ac-4771-a6cd-77e9a8e4ac86","start_time":"2025-11-02T23:00:00Z","elements":[{"duration":23400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":5400000,"fill_level_range":{"start_of_range":55.5,"end_of_range":59.0}},{"duration":32400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":10800000,"fill_level_range":{"start_of_range":55.5,"end_of_range":59.0}},{"duration":14400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":23400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":5400000,"fill_level_range":{"start_of_range":55.5,"end_of_range":59.0}},{"duration":32400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":10800000,"fill_level_range":{"start_of_range":55.5,"end_of_range":59.0}},{"duration":14400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}}]} +[FLEXMEASURES][2025-11-03 08:24:25,336] DEBUG: {"message_type":"FRBC.FillLevelTargetProfile","message_id":"936aaf07-3a83-48c2-9e5c-e378f9548146","start_time":"2025-11-02T23:00:00Z","elements":[{"duration":23400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":58.5}},{"duration":5400000,"fill_level_range":{"start_of_range":57.0,"end_of_range":58.5}},{"duration":32400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":58.5}},{"duration":10800000,"fill_level_range":{"start_of_range":57.0,"end_of_range":58.5}},{"duration":14400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":58.5}},{"duration":23400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":58.5}},{"duration":5400000,"fill_level_range":{"start_of_range":57.0,"end_of_range":58.5}},{"duration":32400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":58.5}},{"duration":10800000,"fill_level_range":{"start_of_range":57.0,"end_of_range":58.5}},{"duration":14400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":58.5}}]} +[FLEXMEASURES][2025-11-03 08:24:25,338] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:24:25,338] WARNING: ⚠️ Connection closed during response +[FLEXMEASURES][2025-11-03 08:24:25,337] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-11-03 08:24:25,405] WARNING: ⚠️ Connection closed during response +[FLEXMEASURES][2025-11-03 08:24:25,591] DEBUG: 🎯 Start: 23:00:00 +[FLEXMEASURES][2025-11-03 08:24:25,593] DEBUG: 🎯 Start: 23:00:00 +[FLEXMEASURES][2025-11-03 08:24:25,594] INFO: 🎯 TargetProfile: 10 element(s) +[FLEXMEASURES][2025-11-03 08:24:25,594] INFO: 🎯 TargetProfile: 10 element(s) +[FLEXMEASURES][2025-11-03 08:24:25,596] DEBUG: 📊 Device readiness: ✅ SystemDescription | ✅ FillLevelTargetProfile | ✅ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:24:25,599] INFO: 🎯 Generating instructions for c88e6893... +[FLEXMEASURES][2025-11-03 08:24:25,600] DEBUG: 📊 Device readiness: ✅ SystemDescription | ✅ FillLevelTargetProfile | ✅ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-11-03 08:24:25,602] DEBUG: 🔧 Creating device state for c88e6893... +[FLEXMEASURES][2025-11-03 08:24:25,602] INFO: 🎯 Generating instructions for 9ec19d27... +[FLEXMEASURES][2025-11-03 08:24:25,634] DEBUG: Storage status used for scheduler: message_type='FRBC.StorageStatus' message_id=UUID('fdef46a5-c812-4167-a3db-22518aa18654') present_fill_level=29.5889991 +[FLEXMEASURES][2025-11-03 08:24:25,636] DEBUG: Present fill level used for scheduler: 29.5889991 +[FLEXMEASURES][2025-11-03 08:24:25,636] DEBUG: ✅ Device state ready: c88e6893... +[FLEXMEASURES][2025-11-03 08:24:25,636] DEBUG: 🔧 Creating device state for 9ec19d27... +[FLEXMEASURES][2025-11-03 08:24:25,637] INFO: 🧮 S2FlaskScheduler started +[FLEXMEASURES][2025-11-03 08:24:25,639] DEBUG: 🔧 Creating device state for 9ec19d27... +[FLEXMEASURES][2025-11-03 08:24:25,640] DEBUG: Storage status used for scheduler: message_type='FRBC.StorageStatus' message_id=UUID('d0970b64-b069-4738-96c5-b4318e6ce5cf') present_fill_level=42.4669997 +[FLEXMEASURES][2025-11-03 08:24:25,640] DEBUG: Present fill level used for scheduler: 42.4669997 +[FLEXMEASURES][2025-11-03 08:24:25,641] DEBUG: ✅ Device state ready: 9ec19d27... +[FLEXMEASURES][2025-11-03 08:24:25,639] DEBUG: Storage status used for scheduler: message_type='FRBC.StorageStatus' message_id=UUID('d0970b64-b069-4738-96c5-b4318e6ce5cf') present_fill_level=42.4669997 +[FLEXMEASURES][2025-11-03 08:24:25,672] DEBUG: Present fill level used for scheduler: 42.4669997 +[FLEXMEASURES][2025-11-03 08:24:25,673] DEBUG: ✅ Device state ready: 9ec19d27... +[FLEXMEASURES][2025-11-03 08:24:25,673] INFO: 🧮 S2FlaskScheduler started +[FLEXMEASURES][2025-11-03 08:24:25,680] DEBUG: 🔧 Creating device state for 9ec19d27... +[FLEXMEASURES][2025-11-03 08:24:25,712] DEBUG: Storage status used for scheduler: message_type='FRBC.StorageStatus' message_id=UUID('d0970b64-b069-4738-96c5-b4318e6ce5cf') present_fill_level=42.4669997 +[FLEXMEASURES][2025-11-03 08:24:25,720] DEBUG: Present fill level used for scheduler: 42.4669997 +[FLEXMEASURES][2025-11-03 08:24:25,720] DEBUG: ✅ Device state ready: 9ec19d27... +Current planning is within the congestion target range. Returning it. +difference_profile has no Joule elements, using the target directly +Improving-------------------------> +diff_to_global_target has no Joule elements, using the target directly +CP '': Selected best controller 'FRBC Device 3c4cdc54-1852-4fe8-963a-57c03499058f' with improvement of 0. +Root controller: selected best controller 'FRBC Device 3c4cdc54-1852-4fe8-963a-57c03499058f' with global energy impr 0, cost impr [0.], CP impr 0.0. Accepted 1 proposal(s). Iteration 1. +Optimizing priority class 1 was done after 1 iterations. +[FLEXMEASURES][2025-11-03 08:24:25,763] DEBUG: {'device_id': '3c4cdc54-1852-4fe8-963a-57c03499058f', 'device_name': 'FRBC Device 3c4cdc54-1852-4fe8-963a-57c03499058f', 'connection_id': '3c4cdc54-1852-4fe8-963a-57c03499058f_connection', 'energy_profile': , 'fill_level_profile': , 'instruction_profile': } +[FLEXMEASURES][2025-11-03 08:24:25,789] INFO: Generated new plan in 543854.231 ms diff --git a/flexmeasures_s2/profile_steering/examples/itho_example.txt b/flexmeasures_s2/profile_steering/examples/itho_example.txt new file mode 100644 index 0000000..7b2cbb5 --- /dev/null +++ b/flexmeasures_s2/profile_steering/examples/itho_example.txt @@ -0,0 +1,129 @@ +[FLEXMEASURES][2025-10-29 10:15:02,774] INFO: 🤝 Handshake +[FLEXMEASURES][2025-10-29 10:15:02,775] DEBUG: {"message_type":"Handshake","message_id":"946e9f1c-8811-4146-a777-dc30fc53e370","role":"RM","supported_protocol_versions":["0.0.2-beta"]} +[FLEXMEASURES][2025-10-29 10:15:02,775] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:15:02,777] DEBUG: {"message_type":"Handshake","message_id":"946e9f1c-8811-4146-a777-dc30fc53e370","role":"RM","supported_protocol_versions":["0.0.2-beta"]} +[FLEXMEASURES][2025-10-29 10:15:02,778] INFO: 🤝 Handshake complete (protocol 0.0.2-beta) +[FLEXMEASURES][2025-10-29 10:15:02,779] INFO: 📤 SelectControlType: FRBC +[FLEXMEASURES][2025-10-29 10:15:02,825] INFO: 📥 ReceptionStatus +[FLEXMEASURES][2025-10-29 10:15:02,827] DEBUG: {"message_type":"ReceptionStatus","subject_message_id":"9a26b47c-4b5f-4671-a0e9-6ef16d5890a6","status":"OK","diagnostic_label":"Processed okay."} +[FLEXMEASURES][2025-10-29 10:15:02,827] DEBUG: {"message_type":"ReceptionStatus","subject_message_id":"9a26b47c-4b5f-4671-a0e9-6ef16d5890a6","status":"OK","diagnostic_label":"Processed okay."} +[FLEXMEASURES][2025-10-29 10:15:02,830] INFO: 📝 ResourceManagerDetails +[FLEXMEASURES][2025-10-29 10:15:02,831] DEBUG: {"message_type":"ResourceManagerDetails","message_id":"539400ba-db11-4267-bcfd-0674262de7f2","resource_id":"9ec19d27-6b5b-44cf-a43c-9d22b16d3a6a","name":"WPU 5G #WPUTESTKASTS2","roles":[{"role":"ENERGY_CONSUMER","commodity":"ELECTRICITY"}],"manufacturer":"Itho Daalderop","model":"5G - 47177","serial_number":"#WPUTESTKASTS2","firmware_version":"83.0.0","instruction_processing_delay":150000,"available_control_types":["FILL_RATE_BASED_CONTROL"],"provides_forecast":true,"provides_power_measurement_types":["ELECTRIC.POWER.L1"]} +[FLEXMEASURES][2025-10-29 10:15:02,832] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:15:02,832] INFO: 📝 RM registered: 9ec19d27... (WPU 5G #WPUTESTKASTS2) +[FLEXMEASURES][2025-10-29 10:15:02,865] INFO: 📥 ReceptionStatus +[FLEXMEASURES][2025-10-29 10:15:02,867] DEBUG: {"message_type":"ReceptionStatus","subject_message_id":"03ddcf93-e5be-4068-bafb-84f7eea57b62","status":"OK","diagnostic_label":"Processed okay."} +[FLEXMEASURES][2025-10-29 10:15:02,867] DEBUG: {"message_type":"ReceptionStatus","subject_message_id":"03ddcf93-e5be-4068-bafb-84f7eea57b62","status":"OK","diagnostic_label":"Processed okay."} +[FLEXMEASURES][2025-10-29 10:15:22,775] INFO: 📥 PowerMeasurement +[FLEXMEASURES][2025-10-29 10:15:22,776] DEBUG: {"message_type":"PowerMeasurement","message_id":"5b836dc1-1ab9-496e-83b0-533ce79f9753","measurement_timestamp":"2025-10-29T10:15:04.430142Z","values":[{"commodity_quantity":"ELECTRIC.POWER.L1","value":1100.0}]} +[FLEXMEASURES][2025-10-29 10:15:22,776] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:15:22,778] INFO: 📋 FRBC.SystemDescription +[FLEXMEASURES][2025-10-29 10:15:22,779] DEBUG: {"message_type":"FRBC.SystemDescription","message_id":"b155d7ed-8a46-4511-8c5a-1aa88e66b7b3","valid_from":"2025-10-29T10:15:04.774941Z","actuators":[{"id":"189f6a58-e78a-4c3f-bcda-6cd151342285","diagnostic_label":"Heat Pump (DHW)","supported_commodities":["ELECTRICITY"],"operation_modes":[{"id":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","diagnostic_label":"Off","elements":[{"fill_level_range":{"start_of_range":0.0,"end_of_range":100.0},"fill_rate":{"start_of_range":0.0,"end_of_range":0.0},"power_ranges":[{"start_of_range":0.0,"end_of_range":0.0,"commodity_quantity":"ELECTRIC.POWER.L1"}],"running_costs":{"start_of_range":0.0,"end_of_range":0.0}}],"abnormal_condition_only":false},{"id":"31314092-4456-43f8-89dd-0421194bc821","diagnostic_label":"DHW","elements":[{"fill_level_range":{"start_of_range":10.0,"end_of_range":61.5},"fill_rate":{"start_of_range":0.0024383534802858943,"end_of_range":0.0024383534802858943},"power_ranges":[{"start_of_range":1100.0,"end_of_range":1100.0,"commodity_quantity":"ELECTRIC.POWER.L1"}]}],"abnormal_condition_only":false}],"transitions":[{"id":"4359a2e3-8782-4192-9775-2a29b828c45e","from":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","to":"31314092-4456-43f8-89dd-0421194bc821","start_timers":["702cd17f-ac40-429e-93d4-ce69c8eb8040"],"blocking_timers":["b27ef8c9-c440-44cb-8deb-f7f85f491a92"],"transition_duration":300000,"abnormal_condition_only":false},{"id":"8d3bdeae-5052-4579-a62b-a36b427df63a","from":"31314092-4456-43f8-89dd-0421194bc821","to":"959eb2c3-3d92-4ca1-8005-1d9caab972a5","start_timers":["b27ef8c9-c440-44cb-8deb-f7f85f491a92"],"blocking_timers":["702cd17f-ac40-429e-93d4-ce69c8eb8040"],"transition_duration":180000,"abnormal_condition_only":false}],"timers":[{"id":"702cd17f-ac40-429e-93d4-ce69c8eb8040","diagnostic_label":"DHW Minimum On Time","duration":1800000},{"id":"b27ef8c9-c440-44cb-8deb-f7f85f491a92","diagnostic_label":"DHW Minimum Off Time","duration":600000}]}],"storage":{"diagnostic_label":"DHW Buffer","fill_level_label":"Temperature in degrees Celcius","provides_leakage_behaviour":true,"provides_fill_level_target_profile":true,"provides_usage_forecast":true,"fill_level_range":{"start_of_range":10.0,"end_of_range":61.5}}} +[FLEXMEASURES][2025-10-29 10:15:22,779] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:15:22,791] DEBUG: ⚙️ Actuator 189f6a58...: 2 modes, 2 transitions, 2 timers +[FLEXMEASURES][2025-10-29 10:15:22,797] DEBUG: 💾 Storage: 10.0-61.5 Temperature in degrees Celcius +[FLEXMEASURES][2025-10-29 10:15:22,798] INFO: 📋 SystemDescription: 1 actuator(s) +[FLEXMEASURES][2025-10-29 10:15:22,799] DEBUG: ⏳ Missing actuator status for: 189f6a58-e78a-4c3f-bcda-6cd151342285 +[FLEXMEASURES][2025-10-29 10:15:22,799] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ❌ ActuatorStatus (0/1 received) +[FLEXMEASURES][2025-10-29 10:15:22,799] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus, ActuatorStatus +[FLEXMEASURES][2025-10-29 10:15:22,863] INFO: 📥 FRBC.LeakageBehaviour +[FLEXMEASURES][2025-10-29 10:15:22,865] DEBUG: {"message_type":"FRBC.LeakageBehaviour","message_id":"49a61e0c-9a09-4902-b5a0-61a1f83240a3","valid_from":"2025-10-29T10:15:03.117182Z","elements":[{"fill_level_range":{"start_of_range":10.0,"end_of_range":61.5},"leakage_rate":0.00004464134898917508}]} +[FLEXMEASURES][2025-10-29 10:15:22,865] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:15:22,867] INFO: 🔋 FRBC.StorageStatus +[FLEXMEASURES][2025-10-29 10:15:22,868] DEBUG: {"message_type":"FRBC.StorageStatus","message_id":"4edd0d97-e461-41ec-acd2-d4f0da6f09d8","present_fill_level":24.433} +[FLEXMEASURES][2025-10-29 10:15:22,868] DEBUG: ✅ ReceptionStatus: OK +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:633: SAWarning: Object of type not in session, add operation along 'Sensor.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + df = pd.DataFrame(session.execute(q)) +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:633: SAWarning: Object of type not in session, add operation along 'DataSource.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + df = pd.DataFrame(session.execute(q)) +[FLEXMEASURES][2025-10-29 10:15:22,989] INFO: SAVING TO DB... +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:332: SAWarning: Object of type not in session, add operation along 'Sensor.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + session.execute(smt) +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:332: SAWarning: Object of type not in session, add operation along 'DataSource.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + session.execute(smt) +[FLEXMEASURES][2025-10-29 10:15:23,015] INFO: 🔋 StorageStatus: 24.4% +[FLEXMEASURES][2025-10-29 10:15:23,015] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ✅ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-10-29 10:15:23,016] INFO: ⏳ Waiting for: FillLevelTargetProfile +[FLEXMEASURES][2025-10-29 10:15:26,100] INFO: 📊 InstructionStatusUpdate +[FLEXMEASURES][2025-10-29 10:15:26,102] DEBUG: {"message_type":"InstructionStatusUpdate","message_id":"0f7e0a49-a9c8-43c3-89b9-4e8434d52dd0","instruction_id":"25f18935-3bb7-4355-85db-36b389fb63f3","status_type":"ACCEPTED","timestamp":"2025-10-29T10:15:06.243494Z"} +[FLEXMEASURES][2025-10-29 10:15:26,102] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:15:26,103] INFO: ✅ Instruction 25f18935... → ACCEPTED +[FLEXMEASURES][2025-10-29 10:15:26,104] DEBUG: 📋 Full instruction ID: 25f18935-3bb7-4355-85db-36b389fb63f3 +[FLEXMEASURES][2025-10-29 10:15:26,105] INFO: 📊 InstructionStatusUpdate +[FLEXMEASURES][2025-10-29 10:15:26,106] DEBUG: {"message_type":"InstructionStatusUpdate","message_id":"d7c7c494-67e7-48b5-8866-afde8e70a3db","instruction_id":"e70f62ee-8585-4bb8-9a96-a2553d2c0c8d","status_type":"STARTED","timestamp":"2025-10-29T10:15:08.583918Z"} +[FLEXMEASURES][2025-10-29 10:15:26,106] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:15:26,106] INFO: ▶️ Instruction e70f62ee... → STARTED +[FLEXMEASURES][2025-10-29 10:15:26,106] DEBUG: 📋 Full instruction ID: e70f62ee-8585-4bb8-9a96-a2553d2c0c8d +[FLEXMEASURES][2025-10-29 10:15:26,107] DEBUG: 🗑️ Removed e70f62ee... from memory +[FLEXMEASURES][2025-10-29 10:16:22,819] INFO: ⚙️ FRBC.ActuatorStatus +[FLEXMEASURES][2025-10-29 10:16:22,820] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:16:22,832] DEBUG: ⚙️ ActuatorStatus: factor=1.0 +[FLEXMEASURES][2025-10-29 10:16:22,833] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-10-29 10:16:22,833] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus +[FLEXMEASURES][2025-10-29 10:16:22,836] INFO: ⚙️ FRBC.ActuatorStatus +[FLEXMEASURES][2025-10-29 10:16:22,837] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:16:22,854] DEBUG: ⚙️ ActuatorStatus: factor=1.0 +[FLEXMEASURES][2025-10-29 10:16:22,854] DEBUG: 📊 Device readiness: ✅ SystemDescription | ❌ FillLevelTargetProfile | ❌ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-10-29 10:16:22,855] INFO: ⏳ Waiting for: FillLevelTargetProfile, StorageStatus +[FLEXMEASURES][2025-10-29 10:16:22,920] INFO: 🎯 FRBC.FillLevelTargetProfile +[FLEXMEASURES][2025-10-29 10:16:22,920] DEBUG: {"message_type":"FRBC.FillLevelTargetProfile","message_id":"0f7c701c-2d9f-44f0-8a4f-942afdf8d279","start_time":"2025-10-28T23:00:00Z","elements":[{"duration":23400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":5400000,"fill_level_range":{"start_of_range":55.5,"end_of_range":59.0}},{"duration":32400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":10800000,"fill_level_range":{"start_of_range":55.5,"end_of_range":59.0}},{"duration":14400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":23400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":5400000,"fill_level_range":{"start_of_range":55.5,"end_of_range":59.0}},{"duration":32400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}},{"duration":10800000,"fill_level_range":{"start_of_range":55.5,"end_of_range":59.0}},{"duration":14400000,"fill_level_range":{"start_of_range":10.0,"end_of_range":59.0}}]} +[FLEXMEASURES][2025-10-29 10:16:22,921] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:16:22,938] DEBUG: 🎯 Start: 23:00:00 +[FLEXMEASURES][2025-10-29 10:16:22,938] INFO: 🎯 TargetProfile: 10 element(s) +[FLEXMEASURES][2025-10-29 10:16:22,938] DEBUG: 📊 Device readiness: ✅ SystemDescription | ✅ FillLevelTargetProfile | ✅ StorageStatus | ✅ ActuatorStatus (all 1 received) +[FLEXMEASURES][2025-10-29 10:16:22,940] INFO: 🎯 Generating instructions for c88e6893... +[FLEXMEASURES][2025-10-29 10:16:22,941] DEBUG: 🔧 Creating device state for c88e6893... +[FLEXMEASURES][2025-10-29 10:16:22,941] DEBUG: ✅ Device state ready: c88e6893... +[FLEXMEASURES][2025-10-29 10:16:22,942] INFO: 🧮 S2FlaskScheduler started +[FLEXMEASURES][2025-10-29 10:16:22,943] DEBUG: 🔧 Creating device state for c88e6893... +[FLEXMEASURES][2025-10-29 10:16:22,943] DEBUG: ✅ Device state ready: c88e6893... +[FLEXMEASURES][2025-10-29 10:16:23,026] DEBUG: Forward filling 135 missing prices +[FLEXMEASURES][2025-10-29 10:16:23,027] DEBUG: 📊 Cluster: 1 device(s) in state +[FLEXMEASURES][2025-10-29 10:16:23,027] INFO: Planning service initialized +[FLEXMEASURES][2025-10-29 10:16:23,028] DEBUG: ⚙️ Planning service initialized +[FLEXMEASURES][2025-10-29 10:16:23,028] INFO: 📊 Planning: 24.0h window (10:15 → 10:15) +[FLEXMEASURES][2025-10-29 10:16:23,028] DEBUG: ⏱️ Resolution: 0:05:00, Belief time: 10:25:00 +[FLEXMEASURES][2025-10-29 10:16:23,028] DEBUG: 🧮 Running optimization algorithm... +[FLEXMEASURES][2025-10-29 10:16:23,028] WARNING: CongestionPoint without target! CongestionPoint: . Generating empty target. +[FLEXMEASURES][2025-10-29 10:16:23,029] DEBUG: S2 FRBC planner created! +Current planning is within the congestion target range. Returning it. +difference_profile has no Joule elements, using the target directly +Improving-------------------------> +diff_to_global_target has no Joule elements, using the target directly +CP '': Selected best controller 'FRBC Device c88e6893-f2f2-4125-893f-5a3316505152' with improvement of 0. +Root controller: selected best controller 'FRBC Device c88e6893-f2f2-4125-893f-5a3316505152' with global energy impr 0, cost impr [0.], CP impr 0.0. Accepted 1 proposal(s). Iteration 1. +Optimizing priority class 1 was done after 1 iterations. +[FLEXMEASURES][2025-10-29 10:16:23,711] DEBUG: {'device_id': 'c88e6893-f2f2-4125-893f-5a3316505152', 'device_name': 'FRBC Device c88e6893-f2f2-4125-893f-5a3316505152', 'connection_id': 'c88e6893-f2f2-4125-893f-5a3316505152_connection', 'energy_profile': , 'fill_level_profile': , 'instruction_profile': } +[FLEXMEASURES][2025-10-29 10:16:23,719] INFO: Generated new plan in 691.228 ms +[FLEXMEASURES][2025-10-29 10:16:23,720] DEBUG: 🔄 Converting cluster plan to instructions... +[FLEXMEASURES][2025-10-29 10:16:23,720] DEBUG: 🔧 Device c88e6893...: converting 288 FRBC instructions +[FLEXMEASURES][2025-10-29 10:16:23,720] INFO: ✅ Generated 288 FRBC instruction(s) +[FLEXMEASURES][2025-10-29 10:16:23,721] DEBUG: 📊 Mode 31314092...: 6 instruction(s) +[FLEXMEASURES][2025-10-29 10:16:23,721] DEBUG: 📊 Mode 959eb2c3...: 282 instruction(s) +[FLEXMEASURES][2025-10-29 10:16:23,721] DEBUG: 📊 Processing energy profiles for 1 device(s) +[FLEXMEASURES][2025-10-29 10:16:23,721] DEBUG: 💡 Device c88e6893...: 288 energy values +[FLEXMEASURES][2025-10-29 10:16:23,722] INFO: 🔽 Filtered: 288 → 2 instructions (skipped 286 duplicate modes) +[FLEXMEASURES][2025-10-29 10:16:23,722] INFO: 📤 Sending 2 instruction(s): +[FLEXMEASURES][2025-10-29 10:16:23,723] INFO: 1. 286cc6a8... | mode: 31314092... | factor: 0.00 | actuator: 189f6a58... | exec: 10:15:00 +[FLEXMEASURES][2025-10-29 10:16:23,723] DEBUG: 📋 Full instruction ID: 286cc6a8-31a1-42b1-9f1a-4216cfd853d3 +[FLEXMEASURES][2025-10-29 10:16:23,723] DEBUG: 🔧 Full operation mode ID: 31314092-4456-43f8-89dd-0421194bc821 +[FLEXMEASURES][2025-10-29 10:16:23,723] DEBUG: ⚙️ Full actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 +[FLEXMEASURES][2025-10-29 10:16:23,723] INFO: 2. 5e1dd26b... | mode: 959eb2c3... | factor: 0.00 | actuator: 189f6a58... | exec: 10:45:00 +[FLEXMEASURES][2025-10-29 10:16:23,724] DEBUG: 📋 Full instruction ID: 5e1dd26b-0678-4196-bdb5-377eb8d9a164 +[FLEXMEASURES][2025-10-29 10:16:23,724] DEBUG: 🔧 Full operation mode ID: 959eb2c3-3d92-4ca1-8005-1d9caab972a5 +[FLEXMEASURES][2025-10-29 10:16:23,724] DEBUG: ⚙️ Full actuator ID: 189f6a58-e78a-4c3f-bcda-6cd151342285 +[FLEXMEASURES][2025-10-29 10:16:23,724] DEBUG: 💾 Saving 288 energy values for device c88e6893... (J) +[FLEXMEASURES][2025-10-29 10:16:24,018] INFO: SAVING TO DB... +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:332: SAWarning: Object of type not in session, add operation along 'Sensor.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + session.execute(smt) +/usr/local/lib/python3.10/dist-packages/timely_beliefs/beliefs/classes.py:332: SAWarning: Object of type not in session, add operation along 'DataSource.beliefs' will not proceed (This warning originated from the Session 'autoflush' process, which was invoked automatically in response to a user-initiated operation.) + session.execute(smt) +[FLEXMEASURES][2025-10-29 10:16:24,038] INFO: 💾 Saved energy data for 1 device(s) +[FLEXMEASURES][2025-10-29 10:16:24,052] INFO: 📥 FRBC.TimerStatus +[FLEXMEASURES][2025-10-29 10:16:24,053] DEBUG: {"message_type":"FRBC.TimerStatus","message_id":"9eb39270-1440-47f7-b5d0-f0e15fda5be5","timer_id":"702cd17f-ac40-429e-93d4-ce69c8eb8040","actuator_id":"189f6a58-e78a-4c3f-bcda-6cd151342285","finished_at":"2025-10-29T10:00:47.087326Z"} +[FLEXMEASURES][2025-10-29 10:16:24,053] DEBUG: ✅ ReceptionStatus: OK +[FLEXMEASURES][2025-10-29 10:16:24,055] INFO: 📥 ReceptionStatus +[FLEXMEASURES][2025-10-29 10:16:24,056] DEBUG: {"message_type":"ReceptionStatus","subject_message_id":"286cc6a8-31a1-42b1-9f1a-4216cfd853d3","status":"OK","diagnostic_label":"Processed okay."} +[FLEXMEASURES][2025-10-29 10:16:24,056] DEBUG: {"message_type":"ReceptionStatus","subject_message_id":"286cc6a8-31a1-42b1-9f1a-4216cfd853d3","status":"OK","diagnostic_label":"Processed okay."} +[FLEXMEASURES][2025-10-29 10:16:24,057] INFO: 📥 ReceptionStatus +[FLEXMEASURES][2025-10-29 10:16:24,058] DEBUG: {"message_type":"ReceptionStatus","subject_message_id":"5e1dd26b-0678-4196-bdb5-377eb8d9a164","status":"OK","diagnostic_label":"Processed okay."} diff --git a/flexmeasures_s2/profile_steering/planning_service_impl.py b/flexmeasures_s2/profile_steering/planning_service_impl.py new file mode 100644 index 0000000..5c35318 --- /dev/null +++ b/flexmeasures_s2/profile_steering/planning_service_impl.py @@ -0,0 +1,271 @@ +from datetime import datetime +from typing import Any + +# Core profile steering imports +from flexmeasures_s2.profile_steering.root_planner import RootPlanner +from flexmeasures_s2.profile_steering.congestion_point_planner import ( + CongestionPointPlanner, +) + +# Common data types +from flexmeasures_s2.profile_steering.common.joule_range_profile import ( + JouleRangeProfile, +) + +# Import from common data structures to avoid circular imports +from flexmeasures_s2.profile_steering.common_data_structures import ( + ClusterState, +) + +# Import cluster related classes +from flexmeasures_s2.profile_steering.cluster_plan import ClusterPlan, ClusterPlanData +from flexmeasures_s2.profile_steering.cluster_target import ClusterTarget + +# Device planner imports +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_planner import ( + S2FrbcDevicePlanner, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_planner import ( + S2NoControlDevicePlanner, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_state import ( + S2NoControlDeviceState, +) + +# Logger setup +import logging + +logger = logging.getLogger(__name__) + + +class PlanningServiceConfig: + """Configuration for the planning service.""" + + def __init__( + self, + energy_improvement_criterion: float = 0.01, + cost_improvement_criterion: float = 0.01, + congestion_retry_iterations: int = 5, + multithreaded: bool = False, + ): + self._energy_improvement_criterion = energy_improvement_criterion + self._cost_improvement_criterion = cost_improvement_criterion + self._congestion_retry_iterations = congestion_retry_iterations + self._multithreaded = multithreaded + + def energy_improvement_criterion(self) -> float: + return self._energy_improvement_criterion + + def cost_improvement_criterion(self) -> float: + return self._cost_improvement_criterion + + def congestion_retry_iterations(self) -> int: + return self._congestion_retry_iterations + + def multithreaded(self) -> bool: + return self._multithreaded + + +class PlanningService: + """Interface for planning services.""" + + def plan( + self, + state: ClusterState, + target: ClusterTarget, + planning_window: int, + reason: str, + plan_due_by_date: datetime, + optimize_for_target: bool, + max_priority_class: int, + ) -> ClusterPlan: + """Create a plan for the cluster.""" + raise NotImplementedError("Subclasses must implement this method") + + +class PlanningServiceImpl(PlanningService): + """Implementation of the planning service.""" + + DEFAULT_CONGESTION_POINT = "" + + def __init__(self, config: PlanningServiceConfig, context: Any = None): + """Initialize the planning service. + + Args: + config: Configuration for the planning service + context: Execution context (used for multithreading) + """ + self.config = config + self.context = context + # logger.info("Planning service initialized") + + def get_congestion_point( + self, cluster_state: ClusterState, connection_id: str + ) -> str: + """Get the congestion point for a connection ID. + + Args: + cluster_state: The state of the cluster + connection_id: The connection ID to get the congestion point for + + Returns: + The congestion point ID, or DEFAULT_CONGESTION_POINT if none is assigned + """ + congestion_point = cluster_state.get_congestion_point(connection_id) + if congestion_point is None: + # This can happen if a device has no congestion point assigned yet. + # We handle this by giving them all the empty congestion point. + return self.DEFAULT_CONGESTION_POINT + return congestion_point + + def create_controller_tree( + self, + cluster_state: ClusterState, + target: ClusterTarget, + plan_due_by_date: datetime, + ) -> RootPlanner: + """Create a tree of controllers for planning. + + Args: + cluster_state: The state of the cluster + target: The target for the cluster + plan_due_by_date: The date by which planning must be completed + + Returns: + A RootPlanner with appropriate device planners added + """ + # Always accepting all targets is NOT possible if there is an energy target + always_accept_all_proposals = not target.contains_energy_target() + + root_planner = RootPlanner( + target.get_global_target_profile(), + self.config.energy_improvement_criterion(), + self.config.cost_improvement_criterion(), + always_accept_all_proposals, + self.context, + ) + + for device_id, device_state in cluster_state.get_device_states().items(): + congestion_point = self.get_congestion_point( + cluster_state, device_state.connection_id + ) + cpc = root_planner.get_congestion_point_controller(congestion_point) + + if cpc is None: + # Create a new congestion point controller if one doesn't exist yet + congestion_point_target = target.get_congestion_point_target( + congestion_point + ) + if congestion_point == self.DEFAULT_CONGESTION_POINT: + # This is a dummy congestion point. We will give it an empty profile. + congestion_point_target = JouleRangeProfile( + target.get_global_target_profile().metadata, + elements=congestion_point_target.elements, # type: ignore[union-attr] + ) + + cpc = CongestionPointPlanner(congestion_point, congestion_point_target, self.config.multithreaded()) # type: ignore[arg-type] + root_planner.add_congestion_point_controller(cpc) + + # Add the appropriate device planner based on the device state type + if isinstance(device_state, S2FrbcDeviceState): + # logger.debug("S2 FRBC planner created!") + cpc.add_device_controller( + S2FrbcDevicePlanner( + device_state, + target.metadata, + plan_due_by_date, + congestion_point, + ) + ) + elif isinstance(device_state, S2NoControlDeviceState): + logger.debug("S2 NoControl planner created!") + cpc.add_device_controller( + S2NoControlDevicePlanner( + device_state, + target.metadata, + congestion_point, + ) + ) + # Add other device types here as needed + else: + logger.warning( + f"Unknown device! No device planner added for {device_state}" + ) + + return root_planner + + def plan( + self, + state: ClusterState, + target: ClusterTarget, + planning_window: int, + reason: str, + plan_due_by_date: datetime, + optimize_for_target: bool, + max_priority_class: int, + ) -> ClusterPlan: + """Create a plan for the cluster. + + Args: + state: The state of the cluster + target: The target for the cluster + planning_window: The planning window in seconds + reason: The reason for planning + plan_due_by_date: The date by which planning must be completed + optimize_for_target: Whether to optimize for the target + max_priority_class: The maximum priority class to optimize + + Returns: + A ClusterPlan for the cluster + """ + # start_time = datetime.now() + + # Make sure that all congestion points in the ClusterState have a target: + for cp in state.get_congestion_points(): + congestion_point_target = target.get_congestion_point_target(cp) + if congestion_point_target is None and cp is not None: + # We don't have a target for the congestion point + logger.warning( + f"CongestionPoint without target! CongestionPoint: {cp}. Generating empty target." + ) + target.set_congestion_point_target( + congestion_point_id=cp, + congestion_point_target=JouleRangeProfile( + profile_start=target.get_global_target_profile().metadata, + ), + ) + + # Create a tree of controllers and run the planning algorithm + root_controller = self.create_controller_tree(state, target, plan_due_by_date) + + try: + root_controller.plan( + plan_due_by_date, + optimize_for_target, + max_priority_class, + self.config.multithreaded(), + ) + + # Collect device plans + device_plans = [] + for cpc in root_controller.cp_controllers: + for device in cpc.devices: + device_plans.append(device.get_device_plan()) + + # Create and return the cluster plan + plan_data = ClusterPlanData(device_plans, target.metadata) # type: ignore[arg-type] + plan = ClusterPlan(state, target, plan_data, reason, plan_due_by_date, None) + + # end_time = datetime.now() + # execution_time = ( + # end_time - start_time + # ).total_seconds() * 1000 # Convert to milliseconds + # logger.info(f"Generated new plan in {execution_time} ms") + + return plan + except Exception as e: + logger.error(f"Error during planning: {e}") + raise diff --git a/flexmeasures_s2/profile_steering/root_planner.py b/flexmeasures_s2/profile_steering/root_planner.py new file mode 100644 index 0000000..980afc7 --- /dev/null +++ b/flexmeasures_s2/profile_steering/root_planner.py @@ -0,0 +1,200 @@ +from typing import List, Any, Optional +from datetime import datetime +from flexmeasures_s2.profile_steering.common.joule_profile import JouleProfile +from .congestion_point_planner import CongestionPointPlanner +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile + + +class RootPlanner: + MAX_ITERATIONS = 1000 + + def __init__( + self, + target: TargetProfile, + energy_iteration_criterion: float, + cost_iteration_criterion: float, + always_accept_all_proposals: bool, + context: Any, + ): + """ + target: An object that provides a profile. + It must support a method get_profile_start(), + have attributes timestep_duration and nr_of_timesteps, + and (for optimization purposes) support a subtract() method. + always_accept_all_proposals: If True, accept all valid proposals (for pure cost targets) + context: In a full implementation, this might be an executor or similar. Here it is passed along. + """ + self.context = context + self.target = self.remove_null_values(target) + self.energy_iteration_criterion = energy_iteration_criterion + self.cost_iteration_criterion = cost_iteration_criterion + self.always_accept_all_proposals = always_accept_all_proposals + # Create an empty JouleProfile. + # We assume that target exposes get_profile_start(), timestep_duration and nr_of_timesteps. + self.empty_profile = JouleProfile( + self.target.metadata.profile_start, + self.target.metadata.timestep_duration, + elements=[0] * self.target.metadata.nr_of_timesteps, + ) + self.cp_controllers: List[CongestionPointPlanner] = [] + self.root_ctrl_planning = self.empty_profile + + def remove_null_values(self, target: Any) -> Any: + # TODO: Stub: simply return the target. + # In a full implementation, you would remove or replace null elements. + return target + + def add_congestion_point_controller(self, cpc: CongestionPointPlanner): + self.cp_controllers.append(cpc) + + def get_congestion_point_controller( + self, cp_id: str + ) -> Optional[CongestionPointPlanner]: + for cp in self.cp_controllers: + if cp.congestion_point_id == cp_id: + return cp + return None + + def plan( # noqa: C901 + self, + plan_due_by_date: datetime, + optimize_for_target: bool, + max_priority_class_external: int, + multithreaded: bool = False, + ): + # Compute an initial plan by summing each congestion point's initial planning. + self.root_ctrl_planning = self.empty_profile + for cpc in self.cp_controllers: + initial_plan = cpc.create_initial_planning(plan_due_by_date) + self.root_ctrl_planning = self.root_ctrl_planning.add(initial_plan) + + if not optimize_for_target: + return + + if not self.cp_controllers: + return + + # Determine maximum and minimum priority classes across congestion points. + max_priority_class = max( + cpc.max_priority_class() for cpc in self.cp_controllers + ) + min_priority_class = min( + cpc.min_priority_class() for cpc in self.cp_controllers + ) + + # Iterate over the priority classes. + for priority_class in range( + min_priority_class, min(max_priority_class, max_priority_class_external) + 1 + ): + i = 0 + best_proposal = None + + # Simulate a do-while loop: we run at least once. + while True: + # Compute the difference profile + if self.target.nr_of_joule_target_elements() != 0: + difference_profile: TargetProfile = self.target.subtract( + self.root_ctrl_planning + ) + else: + difference_profile = self.target + # print( + # "difference_profile has no Joule elements, using the target directly" + # ) + + best_proposal = None + + # Get proposals from each congestion point controller + proposals = [] + for cpc in self.cp_controllers: + # print("Improving------------------------->") + try: + proposal = cpc.create_improved_planning( + difference_profile, + priority_class, + plan_due_by_date, + ) + if proposal is not None: + proposals.append(proposal) + if best_proposal is None or proposal.is_preferred_to( + best_proposal + ): + best_proposal = proposal + except Exception: + # print(f"Error getting proposal from controller: {e}") + continue + + if best_proposal is None: + # No proposal could be generated; exit inner loop. + break + + # Update root controller's own planning + if self.always_accept_all_proposals: + # If we're NOT optimizing for a Joule target or congestion target, we can + # accept all proposals for efficiency + for proposal in proposals: + self._accept_proposal(proposal) + else: + # If we're optimizing for a Joule target or congestion target we only accept + # one proposal + self._accept_proposal(best_proposal) + + i += 1 + # print( + # f"Root controller: selected best controller '{best_proposal.origin.device_name}' with global energy impr {best_proposal.get_global_improvement_value()}, cost impr {best_proposal.get_cost_improvement_value()}, CP impr {best_proposal.get_congestion_improvement_value()}. Accepted {accepted_proposals} proposal(s). Iteration {i}." + # ) + + # Check stopping criteria: if improvement values are below thresholds or max iterations reached. + if self.always_accept_all_proposals: + # For pure cost targets, check cost improvement + if ( + best_proposal.get_cost_improvement_value() + <= self.cost_iteration_criterion + ) or i >= self.MAX_ITERATIONS: + break + else: + # For energy targets, check energy improvement (original behavior) + if ( + best_proposal.get_global_improvement_value() + <= self.energy_iteration_criterion + ) or i >= self.MAX_ITERATIONS: + break + + # print( + # f"Optimizing priority class {priority_class} was done after {i} iterations." + # ) + if i >= self.MAX_ITERATIONS: + # print( + # f"Warning: Optimization stopped due to iteration limit. Priority class: {priority_class}, Iterations: {i}" + # ) + pass + + def _accept_proposal(self, proposal): + """Accept a proposal and update the planning accordingly.""" + # Update the root controller's planning based on the proposal. + self.root_ctrl_planning = self.root_ctrl_planning.subtract(proposal.old_plan) + self.root_ctrl_planning = self.root_ctrl_planning.add(proposal.proposed_plan) + + # Find the real device object and explicitly update its state. + # This is crucial for parallel execution as proposal.origin is a copy. + cp_id_of_origin = proposal.origin.congestion_point_id + congestion_point_controller = self.get_congestion_point_controller( + cp_id_of_origin + ) + if congestion_point_controller is None: + raise Exception( + f"Could not find CongestionPointController with id {cp_id_of_origin}" + ) + + real_device = None + for dev in congestion_point_controller.devices: + if dev.device_id == proposal.origin.device_id: + real_device = dev + break + + if real_device is None: + raise Exception( + f"Could not find device with id {proposal.origin.device_id} in CP {cp_id_of_origin}" + ) + plan_to_accept = proposal.origin.get_latest_plan() + real_device.set_accepted_plan(plan_to_accept) diff --git a/flexmeasures_s2/profile_steering/s2_utils/__init__.py b/flexmeasures_s2/profile_steering/s2_utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flexmeasures_s2/profile_steering/s2_utils/number_range_wrapper.py b/flexmeasures_s2/profile_steering/s2_utils/number_range_wrapper.py new file mode 100644 index 0000000..a6311b2 --- /dev/null +++ b/flexmeasures_s2/profile_steering/s2_utils/number_range_wrapper.py @@ -0,0 +1,18 @@ +class NumberRangeWrapper: + def __init__(self, start_of_range, end_of_range): + self.start_of_range = start_of_range + self.end_of_range = end_of_range + + def __eq__(self, other): + if not isinstance(other, NumberRangeWrapper): + return False + return ( + self.start_of_range == other.start_of_range + and self.end_of_range == other.end_of_range + ) + + def __hash__(self): + return hash((self.start_of_range, self.end_of_range)) + + def __str__(self): + return f"NumberRangeWrapper(startOfRange={self.start_of_range}, endOfRange={self.end_of_range})" diff --git a/flexmeasures_s2/pytest.ini b/flexmeasures_s2/pytest.ini new file mode 100644 index 0000000..c0511c0 --- /dev/null +++ b/flexmeasures_s2/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +log_cli = true diff --git a/flexmeasures_s2/scheduler/s2_frbc_device_state.py b/flexmeasures_s2/scheduler/s2_frbc_device_state.py new file mode 100644 index 0000000..2a93613 --- /dev/null +++ b/flexmeasures_s2/scheduler/s2_frbc_device_state.py @@ -0,0 +1,11 @@ +from s2python.frbc import ( + FRBCSystemDescription, +) + +from typing import List +from flexmeasures_s2.profile_steering.common.pydantic_base import FlexMeasuresBaseModel + + +class S2FrbcDeviceState(FlexMeasuresBaseModel): + + system_descriptions: List[FRBCSystemDescription] diff --git a/flexmeasures_s2/scheduler/scheduler_flask.py b/flexmeasures_s2/scheduler/scheduler_flask.py new file mode 100644 index 0000000..5018b98 --- /dev/null +++ b/flexmeasures_s2/scheduler/scheduler_flask.py @@ -0,0 +1,998 @@ +from datetime import datetime, timezone +from typing import Any, Dict +import uuid + +from flask import current_app as app +import pandas as pd + +from flexmeasures import Scheduler, Sensor +from flexmeasures.data import db +from flexmeasures.data.models.planning.utils import initialize_index +from flexmeasures.data.queries.utils import simplify_index +from flexmeasures.utils.flexmeasures_inflection import pluralize + +# Profile steering imports +from flexmeasures_s2.profile_steering.common_data_structures import ClusterState +from flexmeasures_s2.profile_steering.cluster_plan import ClusterPlan +from flexmeasures_s2.profile_steering.cluster_target import ClusterTarget +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state import ( + S2DdbcDeviceState, +) +from flexmeasures_s2.profile_steering.common.profile_metadata import ProfileMetadata +from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile +from s2python.frbc import ( + FRBCInstruction, + FRBCFillLevelTargetProfile, + FRBCFillLevelTargetProfileElement, + FRBCUsageForecast, + FRBCUsageForecastElement, +) +from s2python.common import Duration + +from flexmeasures_s2.scheduler.schedulers import ( + PlanningServiceConfig, + PlanningServiceImpl, +) + + +def adjust_fill_level_target_profile_for_current_time( + fill_level_target_profile: FRBCFillLevelTargetProfile, + current_time: datetime, +) -> FRBCFillLevelTargetProfile: + """ + Adjust fill level target profile when current time is ahead of profile start_time. + + Removes elements that have already passed and adjusts the start_time to current_time. + This keeps fill_level_ranges at fixed positions in time regardless of when scheduling happens. + + Args: + fill_level_target_profile: The original fill level target profile + current_time: The current scheduling time (when planning actually happens) + + Returns: + Adjusted fill level target profile with start_time set to current_time + """ + if fill_level_target_profile is None: + return None + + profile_start = fill_level_target_profile.start_time + if isinstance(profile_start, datetime): + profile_start = ( + profile_start.replace(tzinfo=timezone.utc) + if profile_start.tzinfo is None + else profile_start + ) + else: + profile_start = profile_start.astimezone(timezone.utc) + + current_time = ( + current_time.replace(tzinfo=timezone.utc) + if current_time.tzinfo is None + else current_time + ) + + # If current time is not ahead of profile start, just update start_time + if current_time <= profile_start: + return fill_level_target_profile.model_copy(update={"start_time": current_time}) + + # Calculate elapsed time since profile start + elapsed_time_ms = int((current_time - profile_start).total_seconds() * 1000) + + # Helper function to extract duration in milliseconds + def get_duration_ms(elem): + duration = elem.duration + if isinstance(duration, (int, float)): + return int(duration) + elif hasattr(duration, "root"): + return int(duration.root) + else: + return int(duration) + + # Find which elements have passed and which we're currently in + remaining_elements = [] + cumulative_duration_ms = 0 + + for element in fill_level_target_profile.elements: + element_duration_ms = get_duration_ms(element) + element_end_ms = cumulative_duration_ms + element_duration_ms + + if element_end_ms <= elapsed_time_ms: + # This element has completely passed, skip it + cumulative_duration_ms = element_end_ms + continue + elif cumulative_duration_ms < elapsed_time_ms: + # We're in the middle of this element, truncate it + remaining_duration_ms = element_end_ms - elapsed_time_ms + if remaining_duration_ms > 0: + remaining_elements.append( + FRBCFillLevelTargetProfileElement( + duration=Duration(root=remaining_duration_ms), + fill_level_range=element.fill_level_range, + ) + ) + cumulative_duration_ms = element_end_ms + else: + # This element is in the future, keep it as-is + remaining_elements.append(element) + cumulative_duration_ms = element_end_ms + + # Create adjusted profile with current_time as start_time + adjusted_profile = FRBCFillLevelTargetProfile( + message_id=str(uuid.uuid4()), + start_time=current_time, + elements=remaining_elements, + ) + + return adjusted_profile + + +def adjust_usage_forecast_for_current_time( + usage_forecast: FRBCUsageForecast, + current_time: datetime, +) -> FRBCUsageForecast: + """ + Adjust usage forecast when current time is ahead of forecast start_time. + + Removes elements that have already passed and adjusts the start_time to current_time. + This keeps usage_rate values at fixed positions in time regardless of when scheduling happens. + + Args: + usage_forecast: The original usage forecast + current_time: The current scheduling time (when planning actually happens) + + Returns: + Adjusted usage forecast with start_time set to current_time + """ + if usage_forecast is None: + return None + + forecast_start = usage_forecast.start_time + if isinstance(forecast_start, datetime): + forecast_start = ( + forecast_start.replace(tzinfo=timezone.utc) + if forecast_start.tzinfo is None + else forecast_start + ) + else: + forecast_start = forecast_start.astimezone(timezone.utc) + + current_time = ( + current_time.replace(tzinfo=timezone.utc) + if current_time.tzinfo is None + else current_time + ) + + # If current time is not ahead of forecast start, just update start_time + if current_time <= forecast_start: + return usage_forecast.model_copy(update={"start_time": current_time}) + + # Calculate elapsed time since forecast start + elapsed_time_ms = int((current_time - forecast_start).total_seconds() * 1000) + + # Helper function to extract duration in milliseconds + def get_duration_ms(elem): + duration = elem.duration + if isinstance(duration, (int, float)): + return int(duration) + elif hasattr(duration, "root"): + return int(duration.root) + else: + return int(duration) + + # Find which elements have passed and which we're currently in + remaining_elements = [] + cumulative_duration_ms = 0 + + for element in usage_forecast.elements: + element_duration_ms = get_duration_ms(element) + element_end_ms = cumulative_duration_ms + element_duration_ms + + if element_end_ms <= elapsed_time_ms: + # This element has completely passed, skip it + cumulative_duration_ms = element_end_ms + continue + elif cumulative_duration_ms < elapsed_time_ms: + # We're in the middle of this element, truncate it + remaining_duration_ms = element_end_ms - elapsed_time_ms + if remaining_duration_ms > 0: + remaining_elements.append( + FRBCUsageForecastElement( + duration=Duration(root=remaining_duration_ms), + usage_rate_expected=element.usage_rate_expected, + usage_rate_upper_limit=element.usage_rate_upper_limit, + usage_rate_upper_95PPR=element.usage_rate_upper_95PPR, + usage_rate_upper_68PPR=element.usage_rate_upper_68PPR, + usage_rate_lower_68PPR=element.usage_rate_lower_68PPR, + usage_rate_lower_95PPR=element.usage_rate_lower_95PPR, + usage_rate_lower_limit=element.usage_rate_lower_limit, + ) + ) + cumulative_duration_ms = element_end_ms + else: + # This element is in the future, keep it as-is + remaining_elements.append(element) + cumulative_duration_ms = element_end_ms + + # Create adjusted forecast with current_time as start_time + adjusted_forecast = FRBCUsageForecast( + message_id=str(uuid.uuid4()), + start_time=current_time, + elements=remaining_elements, + ) + + return adjusted_forecast + + +class S2FlaskScheduler(Scheduler): + """ + S2FlaskScheduler integrates the profile steering planning service with FlexMeasures. + + This is the Flask-compatible version that uses app.logger and app.config + for integration within the FlexMeasures application context. + + This scheduler uses the PlanningServiceImpl to create optimal energy profiles + for devices in a cluster based on targets and constraints. + """ + + __author__ = "TNO" + __version__ = "1" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.planning_service = None + self.config_deserialized = False + self.frbc_device_data = None # Store FRBC device data from WebSocket + self.ddbc_device_data = None # Store DDBC device data from WebSocket + + def compute(self, *args, **kwargs): + """ + Compute the optimal energy profile using the S2 profile steering algorithm. + + Returns: + List: List containing FRBCInstruction objects and metadata dicts + """ + if not self.config_deserialized: + self.deserialize_config() + + try: + + app.logger.info("🧮 S2FlaskScheduler started") + + # Check if we have either FRBC or DDBC device data + has_frbc = ( + hasattr(self, "frbc_device_data") and self.frbc_device_data is not None + ) + has_ddbc = ( + hasattr(self, "ddbc_device_data") and self.ddbc_device_data is not None + ) + + if not has_frbc and not has_ddbc: + app.logger.error("❌ No device data available (neither FRBC nor DDBC)") + return [] + + # Create device states from available data + device_states, cluster_target = self._create_cluster_state_and_target() + + if not device_states: + app.logger.warning("⚠️ No device states created") + return [] + + # Create cluster state + cluster_state = ClusterState( + timestamp=datetime.now(), + device_states=device_states, + congestion_points_by_connection_id={ + device_id: "" for device_id in device_states.keys() + }, + ) + + app.logger.debug(f"📊 Cluster: {len(device_states)} device(s) in state") + + # Get planning service + planning_service = self._get_planning_service() + + # Calculate planning window + planning_window_seconds = (self.end - self.start).total_seconds() + planning_hours = planning_window_seconds / 3600 + + app.logger.info( + f"📊 Planning: {planning_hours:.1f}h window ({self.start.strftime('%H:%M')} → {self.end.strftime('%H:%M')})" + ) + app.logger.debug( + f" ⏱️ Resolution: {self.resolution}, Belief time: {self.belief_time.strftime('%H:%M:%S') if self.belief_time else 'N/A'}" + ) + + # Generate plan + app.logger.debug("🧮 Running optimization algorithm...") + cluster_plan = planning_service.plan( + state=cluster_state, + target=cluster_target, + planning_window=planning_window_seconds, + reason="S2 WebSocket planning request", + plan_due_by_date=self.start, + optimize_for_target=True, + max_priority_class=1, + ) + + if cluster_plan is None: + app.logger.error("❌ Planning failed: returned None") + return [] + + # Convert cluster plan to instructions + app.logger.debug("🔄 Converting cluster plan to instructions...") + instructions = self._convert_cluster_plan_to_instructions(cluster_plan) + n_frbc_instructions = sum( + 1 for i in instructions if isinstance(i, FRBCInstruction) + ) + + # Log instruction details + if n_frbc_instructions > 0: + frbc_only = [i for i in instructions if isinstance(i, FRBCInstruction)] + # Group by operation mode + mode_counts = {} + for instr in frbc_only: + mode_id = str(instr.operation_mode)[:8] + mode_counts[mode_id] = mode_counts.get(mode_id, 0) + 1 + + app.logger.info( + f"✅ Generated {n_frbc_instructions} FRBC instruction(s)" + ) + for mode_id, count in mode_counts.items(): + app.logger.debug(f" 📊 Mode {mode_id}...: {count} instruction(s)") + + # Add energy data entry for potential storage + try: + device_plans = cluster_plan.get_plan_data().get_device_plans() + n_devices = len(device_plans) if device_plans else 0 + if n_devices > 0: + app.logger.debug( + f"📊 Processing energy profiles for {n_devices} device(s)" + ) + + for device_plan in device_plans: + n_energy_values = ( + len(device_plan.energy_profile.elements) + if device_plan.energy_profile + else 0 + ) + app.logger.debug( + f" 💡 Device {device_plan.device_id[:8]}...: {n_energy_values} energy values" + ) + instructions.append( + { + "device": device_plan.device_id, + "data": pd.Series( + device_plan.energy_profile.elements, + index=pd.date_range( + self.start, + self.end, + freq=self.resolution, + inclusive="left", + ), + ), + "unit": "J", + } + ) + instructions.append( + { + "fill level": device_plan.device_id, + "data": pd.Series( + device_plan.fill_level_profile.elements, + index=pd.date_range( + self.start, + self.end, + freq=self.resolution, + inclusive="left", + ), + ), + "unit": "", + } + ) + except Exception as exc: + app.logger.warning(f"⚠️ Energy profile retrieval failed: {str(exc)}") + + return instructions + + except Exception as e: + app.logger.error(f"❌ Scheduler error: {e}") + import traceback + + app.logger.debug(f"Traceback: {traceback.format_exc()}") + return [] + + def _get_planning_service(self) -> PlanningServiceImpl: + """Get or create the planning service instance.""" + if not hasattr(self, "planning_service") or self.planning_service is None: + config = PlanningServiceConfig( + energy_improvement_criterion=10.0, + cost_improvement_criterion=1.0, + congestion_retry_iterations=10, + multithreaded=False, + ) + self.planning_service = PlanningServiceImpl(config) + app.logger.debug("⚙️ Planning service initialized") + return self.planning_service + + def _create_cluster_state_and_target(self): + """Create cluster state and target from FRBC or DDBC device data.""" + device_states = {} + + # Try to create device states from FRBC data + if hasattr(self, "frbc_device_data") and self.frbc_device_data is not None: + frbc_states = self.create_device_states_from_frbc_data() + device_states.update(frbc_states) + app.logger.debug(f"Created {len(frbc_states)} FRBC device state(s)") + + # Try to create device states from DDBC data + if hasattr(self, "ddbc_device_data") and self.ddbc_device_data is not None: + ddbc_states = self.create_device_states_from_ddbc_data() + device_states.update(ddbc_states) + app.logger.debug(f"Created {len(ddbc_states)} DDBC device state(s)") + + if not device_states: + return device_states, None + + # Create cluster target + cluster_target = self._create_cluster_target() + + return device_states, cluster_target + + def _create_cluster_target(self) -> ClusterTarget: + """Create cluster target profile.""" + + # Calculate profile metadata + profile_metadata = ProfileMetadata( + profile_start=self.start, + timestep_duration=self.resolution, + nr_of_timesteps=int((self.end - self.start) / self.resolution), + ) + + # Get target elements (this could be from sensor data or configuration) + target_elements = self._get_target_elements(profile_metadata.nr_of_timesteps) + + # Type ignore: TargetProfile constructor accepts List[int] and converts to JouleElement + target_mode = app.config.get("FLEXMEASURES_S2_TARGET_MODE", "costs") + if target_mode == "energy": + global_target_profile = TargetProfile( + profile_start=profile_metadata.profile_start, + timestep_duration=profile_metadata.timestep_duration, + elements=target_elements, # type: ignore[arg-type] + ) + else: # target_mode == "costs" + price_sensor_id = app.config.get("FLEXMEASURES_S2_PRICE_SENSOR", 2) + price_sensor = db.session.get(Sensor, price_sensor_id) + if price_sensor is None: + app.logger.warning("⚠️ No price sensor found, using energy target") + global_target_profile = TargetProfile( + profile_start=profile_metadata.profile_start, + timestep_duration=profile_metadata.timestep_duration, + elements=target_elements, # type: ignore[arg-type] + ) + else: + # Query tariff data for the planning period + tariffs = price_sensor.search_beliefs( + event_starts_after=self.start, + event_ends_before=self.end, + resolution=self.resolution, + beliefs_before=self.belief_time, + most_recent_beliefs_only=True, + ) + + if ( + n_missing_prices := (self.end - self.start) // self.resolution + - len(tariffs) + ) > 0: + tariffs = simplify_index(tariffs) + tariffs = tariffs.reindex( + initialize_index( + start=self.start, end=self.end, resolution=self.resolution + ) + ) + if n_missing_prices == len(tariffs): + app.logger.warning("⚠️ All prices missing, assuming 1 EUR/MWh") + tariffs = tariffs.fillna(1) + else: + app.logger.debug( + f"Forward filling {n_missing_prices} missing {pluralize('price', n_missing_prices)}" + ) + tariffs = tariffs.ffill() + + global_target_profile = TargetProfile.from_tariff_values( + metadata=profile_metadata, + tariff_values=tariffs.values, + ) + + # Create cluster target + cluster_target = ClusterTarget( + generated_at=datetime.now(), + parent_id=None, + generated_by=None, + global_target_profile=global_target_profile, + congestion_point_targets={}, + ) + + return cluster_target + + def _get_target_elements(self, num_elements: int) -> list[int]: + """Get target elements for the planning horizon.""" + # This could be configured via app.config or calculated based on business logic + # For now, use a simple pattern similar to the example + target_elements = [] + + # Simple pattern: low consumption at night, higher during day + for i in range(num_elements): + hour_of_day = (i * (self.resolution.total_seconds() / 3600)) % 24 + if 0 <= hour_of_day < 6: # Night: 0 consumption + target_elements.append(0) + elif 6 <= hour_of_day < 9: # Morning: moderate consumption + target_elements.append(4200000) # 4.2 MJ + elif 9 <= hour_of_day < 17: # Day: no specific target + target_elements.append(0) + elif 17 <= hour_of_day < 21: # Evening: moderate consumption + target_elements.append(4200000) # 4.2 MJ + else: # Late evening: high consumption + target_elements.append(8800000) # 8.8 MJ + + return target_elements + + def _convert_cluster_plan_to_instructions(self, cluster_plan: ClusterPlan) -> list: + """Convert cluster plan to FRBC instructions.""" + instructions = [] + + # Get device plans from cluster plan + device_plans = cluster_plan.get_plan_data().get_device_plans() + + for device_plan in device_plans: + if device_plan is None: + continue + + try: + # Convert device plan to instructions + if device_plan.instruction_profile is None: + continue + + device_instructions = device_plan.instruction_profile.elements + + frbc_count = sum( + 1 for i in device_instructions if isinstance(i, FRBCInstruction) + ) + app.logger.debug( + f"🔧 Device {device_plan.device_id[:8]}...: converting {frbc_count} FRBC instructions" + ) + + for instruction in device_instructions: + if isinstance(instruction, FRBCInstruction): + instructions.append(instruction) + + # Add metadata about the plan + instructions.append( + { + "device_id": device_plan.device_id, + "plan_type": "FRBC", + "num_instructions": len(device_instructions), + } + ) + + except Exception as e: + app.logger.error( + f"❌ Conversion failed for device {device_plan.device_id[:8] if hasattr(device_plan, 'device_id') else 'unknown'}...: {e}" + ) + continue + + return instructions + + def set_frbc_device_data(self, device_data: Any): + """Set FRBC device data for planning.""" + self.frbc_device_data = device_data + if hasattr(device_data, "resource_id"): + app.logger.debug( + f"FRBC device data set for device {device_data.resource_id}" + ) + elif isinstance(device_data, dict): + app.logger.debug(f"FRBC device data set for {len(device_data)} devices") + else: + app.logger.debug(f"FRBC device data set: {type(device_data)}") + + def create_device_states_from_frbc_data(self) -> Dict[str, Any]: + """ + Create device states from received FRBC data. + + Returns: + Dict[str, Any]: Dictionary of device states created from FRBC data + """ + from s2python.common import PowerValue, CommodityQuantity + + if not hasattr(self, "frbc_device_data") or self.frbc_device_data is None: + app.logger.warning("⚠️ No FRBC device data") + return {} + + device_states = {} + + # Handle single FRBCDeviceData object from WebSocket + if hasattr(self.frbc_device_data, "resource_id"): + frbc_data = self.frbc_device_data + device_id = frbc_data.resource_id or "frbc_device_1" + + try: + app.logger.debug(f"🔧 Creating device state for {device_id[:8]}...") + + # Extract information from received FRBC data object + system_desc = frbc_data.system_description + storage_status = frbc_data.storage_status + actuator_statuses = ( + list(frbc_data.actuator_statuses.values()) + if hasattr(frbc_data, "actuator_statuses") + else [] + ) + fill_level_target_profile = ( + frbc_data.fill_level_target_profile + if hasattr(frbc_data, "fill_level_target_profile") + else None + ) + usage_forecast = ( + frbc_data.usage_forecast + if hasattr(frbc_data, "usage_forecast") + else None + ) + leakage_behaviour = ( + frbc_data.leakage_behaviour + if hasattr(frbc_data, "leakage_behaviour") + else None + ) + + # Adjust fill level target profile for scheduler start time + # This removes elements that have already passed and adjusts start_time + if fill_level_target_profile: + original_start = fill_level_target_profile.start_time + n_original = ( + len(fill_level_target_profile.elements) + if fill_level_target_profile.elements + else 0 + ) + adjusted_profile = ( + adjust_fill_level_target_profile_for_current_time( + fill_level_target_profile, self.start + ) + ) + if adjusted_profile: + fill_level_target_profile = adjusted_profile + if original_start != self.start: + n_adjusted = ( + len(adjusted_profile.elements) + if adjusted_profile.elements + else 0 + ) + app.logger.debug( + f"Adjusted fill level target profile: " + f"{original_start} → {self.start}, " + f"elements: {n_original} → {n_adjusted}" + ) + + # Adjust usage forecast for scheduler start time + # This removes elements that have already passed and adjusts start_time + if usage_forecast: + original_start = usage_forecast.start_time + n_original = ( + len(usage_forecast.elements) if usage_forecast.elements else 0 + ) + adjusted_forecast = adjust_usage_forecast_for_current_time( + usage_forecast, self.start + ) + if adjusted_forecast: + usage_forecast = adjusted_forecast + if original_start != self.start: + n_adjusted = ( + len(adjusted_forecast.elements) + if adjusted_forecast.elements + else 0 + ) + app.logger.debug( + f"Adjusted usage forecast: " + f"{original_start} → {self.start}, " + f"elements: {n_original} → {n_adjusted}" + ) + + # Create device state using the received FRBC data + device_state = S2FrbcDeviceState( + device_id=device_id, + device_name=f"FRBC Device {device_id}", + connection_id=f"{device_id}_connection", + priority_class=1, + timestamp=self.start, + energy_in_current_timestep=PowerValue( + value=0, commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1 + ), + is_online=True, + power_forecast=None, + system_descriptions=[system_desc] if system_desc else [], + leakage_behaviours=[leakage_behaviour] if leakage_behaviour else [], + usage_forecasts=[usage_forecast] if usage_forecast else [], + fill_level_target_profiles=[fill_level_target_profile] + if fill_level_target_profile + else [], + computational_parameters=S2FrbcDeviceState.ComputationalParameters( + 100, 20 + ), + actuator_statuses=actuator_statuses, + storage_status=storage_status, # Single object, not a list + ) + app.logger.debug(f"Storage status used for scheduler: {storage_status}") + if storage_status: + app.logger.debug( + f"Present fill level used for scheduler: {storage_status.present_fill_level}" + ) + + # Log which profiles are being used + if fill_level_target_profile: + n_elements = ( + len(fill_level_target_profile.elements) + if fill_level_target_profile.elements + else 0 + ) + app.logger.debug( + f"Fill level target profile: {n_elements} element(s)" + ) + else: + app.logger.debug("Fill level target profile: NOT PROVIDED") + + if usage_forecast: + n_elements = ( + len(usage_forecast.elements) if usage_forecast.elements else 0 + ) + app.logger.debug(f"Usage forecast: {n_elements} element(s)") + else: + app.logger.debug("Usage forecast: NOT PROVIDED") + + if leakage_behaviour: + n_elements = ( + len(leakage_behaviour.elements) + if leakage_behaviour.elements + else 0 + ) + app.logger.debug(f"Leakage behaviour: {n_elements} element(s)") + else: + app.logger.debug("Leakage behaviour: NOT PROVIDED") + + device_states[device_id] = device_state + app.logger.debug(f"✅ Device state ready: {device_id[:8]}...") + + except Exception as e: + app.logger.error( + f"❌ Device state creation failed for {device_id[:8]}...: {e}" + ) + + # Handle dictionary of device data (backward compatibility) + elif isinstance(self.frbc_device_data, dict): + for device_id, frbc_data in self.frbc_device_data.items(): + try: + app.logger.debug(f"🔧 Creating device state for {device_id[:8]}...") + + # Extract information from received FRBC data + system_desc = frbc_data.get("system_description") + storage_status = frbc_data.get("storage_status") + actuator_statuses = ( + list(frbc_data.get("actuator_statuses", {}).values()) + if "actuator_statuses" in frbc_data + else [frbc_data.get("actuator_status")] + if frbc_data.get("actuator_status") + else [] + ) + fill_level_target_profile = frbc_data.get( + "fill_level_target_profile" + ) + usage_forecast = frbc_data.get("usage_forecast") + leakage_behaviour = frbc_data.get("leakage_behaviour") + + # Adjust fill level target profile for scheduler start time + # This removes elements that have already passed and adjusts start_time + if fill_level_target_profile and hasattr( + fill_level_target_profile, "start_time" + ): + original_start = fill_level_target_profile.start_time + n_original = ( + len(fill_level_target_profile.elements) + if fill_level_target_profile.elements + else 0 + ) + adjusted_profile = ( + adjust_fill_level_target_profile_for_current_time( + fill_level_target_profile, self.start + ) + ) + if adjusted_profile: + fill_level_target_profile = adjusted_profile + if original_start != self.start: + n_adjusted = ( + len(adjusted_profile.elements) + if adjusted_profile.elements + else 0 + ) + app.logger.debug( + f"Adjusted fill level target profile: " + f"{original_start} → {self.start}, " + f"elements: {n_original} → {n_adjusted}" + ) + + # Adjust usage forecast for scheduler start time + # This removes elements that have already passed and adjusts start_time + if usage_forecast and hasattr(usage_forecast, "start_time"): + original_start = usage_forecast.start_time + n_original = ( + len(usage_forecast.elements) + if usage_forecast.elements + else 0 + ) + adjusted_forecast = adjust_usage_forecast_for_current_time( + usage_forecast, self.start + ) + if adjusted_forecast: + usage_forecast = adjusted_forecast + if original_start != self.start: + n_adjusted = ( + len(adjusted_forecast.elements) + if adjusted_forecast.elements + else 0 + ) + app.logger.debug( + f"Adjusted usage forecast: " + f"{original_start} → {self.start}, " + f"elements: {n_original} → {n_adjusted}" + ) + + # Create device state using the received FRBC data + device_state = S2FrbcDeviceState( + device_id=device_id, + device_name=f"FRBC Device {device_id}", + connection_id=f"{device_id}_connection", + priority_class=1, + timestamp=self.start, + energy_in_current_timestep=PowerValue( + value=0, + commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1, + ), + is_online=True, + power_forecast=None, + system_descriptions=[system_desc] if system_desc else [], + leakage_behaviours=[leakage_behaviour] + if leakage_behaviour + else [], + usage_forecasts=[usage_forecast] if usage_forecast else [], + fill_level_target_profiles=[fill_level_target_profile] + if fill_level_target_profile + else [], + computational_parameters=S2FrbcDeviceState.ComputationalParameters( + 100, 20 + ), + actuator_statuses=actuator_statuses, + storage_status=storage_status, # Single object, not a list + ) + + device_states[device_id] = device_state + app.logger.debug(f"✅ Device state ready: {device_id[:8]}...") + + except Exception as e: + app.logger.error( + f"❌ Device state creation failed for {device_id[:8]}...: {e}" + ) + continue + else: + app.logger.error( + f"❌ Unexpected FRBC data type: {type(self.frbc_device_data)}" + ) + + return device_states + + def create_device_states_from_ddbc_data(self) -> Dict[str, Any]: + """ + Create device states from received DDBC data. + + Returns: + Dict[str, Any]: Dictionary of device states created from DDBC data + """ + if not hasattr(self, "ddbc_device_data") or self.ddbc_device_data is None: + app.logger.warning("⚠️ No DDBC device data") + return {} + + device_states = {} + + # Handle single DDBCDeviceData object + if hasattr(self.ddbc_device_data, "resource_id"): + ddbc_data = self.ddbc_device_data + device_id = ddbc_data.resource_id or "ddbc_device_1" + + try: + app.logger.debug(f"🔧 Creating DDBC device state for {device_id[:8]}...") + + # Extract information from received DDBC data object + system_desc = ddbc_data.system_description + demand_forecasts = ( + ddbc_data.demand_forecasts + if hasattr(ddbc_data, "demand_forecasts") + else [] + ) + actuator_statuses = ( + ddbc_data.actuator_statuses + if hasattr(ddbc_data, "actuator_statuses") + else {} + ) + + # Create device state using the received DDBC data + device_state = S2DdbcDeviceState( + device_id=device_id, + device_name=f"DDBC Device {device_id}", + connection_id=f"{device_id}_connection", + priority_class=0, + timestamp=self.start, + energy_in_current_timestep=0.0, + is_online=True, + power_forecast=None, + system_descriptions=[system_desc] if system_desc else [], + demand_forecasts=demand_forecasts, + actuator_statuses=actuator_statuses, + gas_price_per_m3=2.0, # €2 per m3 of gas + ) + + device_states[device_id] = device_state + app.logger.debug(f"✅ DDBC device state ready: {device_id[:8]}...") + + except Exception as e: + app.logger.error( + f"❌ DDBC device state creation failed for {device_id[:8]}...: {e}" + ) + import traceback + + app.logger.debug(traceback.format_exc()) + + # Handle dictionary of device data (backward compatibility) + elif isinstance(self.ddbc_device_data, dict): + for device_id, ddbc_data in self.ddbc_device_data.items(): + try: + app.logger.debug( + f"🔧 Creating DDBC device state for {device_id[:8]}..." + ) + + # Extract information from received DDBC data + system_desc = ddbc_data.get("system_description") + demand_forecasts = ddbc_data.get("demand_forecasts", []) + actuator_statuses = ddbc_data.get("actuator_statuses", {}) + + # Create device state using the received DDBC data + device_state = S2DdbcDeviceState( + device_id=device_id, + device_name=f"DDBC Device {device_id}", + connection_id=f"{device_id}_connection", + priority_class=0, + timestamp=self.start, + energy_in_current_timestep=0.0, + is_online=True, + power_forecast=None, + system_descriptions=[system_desc] if system_desc else [], + demand_forecasts=demand_forecasts, + actuator_statuses=actuator_statuses, + gas_price_per_m3=2.0, # €2 per m3 of gas + ) + + device_states[device_id] = device_state + app.logger.debug(f"✅ DDBC device state ready: {device_id[:8]}...") + + except Exception as e: + app.logger.error( + f"❌ DDBC device state creation failed for {device_id[:8]}...: {e}" + ) + continue + else: + app.logger.error( + f"❌ Unexpected DDBC data type: {type(self.ddbc_device_data)}" + ) + + return device_states + + def deserialize_config(self): + """Deserialize the flex_model configuration.""" + # For now, we use default configuration + # This could be extended to read from self.flex_model if needed + self.config_deserialized = True + app.logger.debug("⚙️ Config deserialized") diff --git a/flexmeasures_s2/scheduler/schedulers.py b/flexmeasures_s2/scheduler/schedulers.py index 7ab3080..a2e8bc7 100644 --- a/flexmeasures_s2/scheduler/schedulers.py +++ b/flexmeasures_s2/scheduler/schedulers.py @@ -1,24 +1,800 @@ import pandas as pd +from datetime import datetime +from typing import Any, Dict, Optional +import logging + from flexmeasures import Scheduler +# Profile steering imports +from flexmeasures_s2.profile_steering.root_planner import RootPlanner +from flexmeasures_s2.profile_steering.congestion_point_planner import ( + CongestionPointPlanner, +) +from flexmeasures_s2.profile_steering.common.joule_range_profile import ( + JouleRangeProfile, +) +from flexmeasures_s2.profile_steering.common_data_structures import ( + ClusterState, +) +from flexmeasures_s2.profile_steering.cluster_plan import ClusterPlan, ClusterPlanData +from flexmeasures_s2.profile_steering.cluster_target import ClusterTarget +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_planner import ( + S2FrbcDevicePlanner, +) +from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_planner import ( + S2NoControlDevicePlanner, +) +from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_state import ( + S2NoControlDeviceState, +) + +# NoControl planner is on a different branch +# from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_planner import ( +# S2NoControlDevicePlanner, +# ) +# from flexmeasures_s2.profile_steering.device_planner.nocontrol.s2_nocontrol_device_state import ( +# S2NoControlDeviceState, +# ) +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_planner import ( + S2DdbcDevicePlanner, +) +from flexmeasures_s2.profile_steering.device_planner.ddbc.s2_ddbc_device_state import ( + S2DdbcDeviceState, +) + +# Schema imports +from flexmeasures_s2.scheduler.schemas import S2FlexModelSchema, TNOFlexContextSchema + +# Logger setup +logger = logging.getLogger(__name__) + + +class PlanningServiceConfig: + """Configuration for the planning service.""" + + def __init__( + self, + energy_improvement_criterion: float = 0.01, + cost_improvement_criterion: float = 0.01, + congestion_retry_iterations: int = 5, + multithreaded: bool = False, + ): + self._energy_improvement_criterion = energy_improvement_criterion + self._cost_improvement_criterion = cost_improvement_criterion + self._congestion_retry_iterations = congestion_retry_iterations + self._multithreaded = multithreaded + + def energy_improvement_criterion(self) -> float: + return self._energy_improvement_criterion + + def cost_improvement_criterion(self) -> float: + return self._cost_improvement_criterion + + def congestion_retry_iterations(self) -> int: + return self._congestion_retry_iterations + + def multithreaded(self) -> bool: + return self._multithreaded + + +class PlanningService: + """Interface for planning services.""" + + def plan( + self, + state: ClusterState, + target: ClusterTarget, + planning_window: int, + reason: str, + plan_due_by_date: datetime, + optimize_for_target: bool, + max_priority_class: int, + ) -> ClusterPlan: + """Create a plan for the cluster.""" + raise NotImplementedError("Subclasses must implement this method") + + +class PlanningServiceImpl(PlanningService): + """Implementation of the planning service.""" + + DEFAULT_CONGESTION_POINT = "" + + def __init__(self, config: PlanningServiceConfig, context: Any = None): + """Initialize the planning service. + + Args: + config: Configuration for the planning service + context: Execution context (used for multithreading) + """ + self.config = config + self.context = context + logger.info("Planning service initialized") + + def get_congestion_point( + self, cluster_state: ClusterState, connection_id: str + ) -> str: + """Get the congestion point for a connection ID. + + Args: + cluster_state: The state of the cluster + connection_id: The connection ID to get the congestion point for + + Returns: + The congestion point ID, or DEFAULT_CONGESTION_POINT if none is assigned + """ + congestion_point = cluster_state.get_congestion_point(connection_id) + if congestion_point is None: + # This can happen if a device has no congestion point assigned yet. + # We handle this by giving them all the empty congestion point. + return self.DEFAULT_CONGESTION_POINT + return congestion_point + + def create_controller_tree( + self, + cluster_state: ClusterState, + target: ClusterTarget, + plan_due_by_date: datetime, + ) -> RootPlanner: + """Create a tree of controllers for planning. + + Args: + cluster_state: The state of the cluster + target: The target for the cluster + plan_due_by_date: The date by which planning must be completed + + Returns: + A RootPlanner with appropriate device planners added + """ + # Always accepting all targets is NOT possible if there is an energy target + always_accept_all_proposals = not target.contains_energy_target() + + root_planner = RootPlanner( + target.get_global_target_profile(), + self.config.energy_improvement_criterion(), + self.config.cost_improvement_criterion(), + always_accept_all_proposals, + self.context, + ) + + for device_id, device_state in cluster_state.get_device_states().items(): + congestion_point = self.get_congestion_point( + cluster_state, device_state.connection_id + ) + cpc = root_planner.get_congestion_point_controller(congestion_point) + + if cpc is None: + # Create a new congestion point controller if one doesn't exist yet + congestion_point_target = target.get_congestion_point_target( + congestion_point + ) + if congestion_point == self.DEFAULT_CONGESTION_POINT: + # This is a dummy congestion point. We will give it an empty profile. + congestion_point_target = JouleRangeProfile( + target.get_global_target_profile().metadata, + elements=congestion_point_target.elements + if congestion_point_target is not None + else [], + ) + + cpc = CongestionPointPlanner(congestion_point, congestion_point_target, self.config.multithreaded()) # type: ignore[arg-type] + root_planner.add_congestion_point_controller(cpc) + + # Add the appropriate device planner based on the device state type + if isinstance(device_state, S2FrbcDeviceState): + logger.debug("S2 FRBC planner created!") + cpc.add_device_controller( + S2FrbcDevicePlanner( + device_state, + target.metadata, + plan_due_by_date, + congestion_point, + ) + ) + # elif isinstance(device_state, S2NoControlDeviceState): + # logger.debug("S2 NoControl planner created!") + # cpc.add_device_controller( + # S2NoControlDevicePlanner( + # device_state, + # target.metadata, + # congestion_point, + # ) + # ) + elif isinstance(device_state, S2DdbcDeviceState): + logger.debug("S2 DDBC planner created!") + cpc.add_device_controller( + S2DdbcDevicePlanner( + device_state, + target.metadata, + plan_due_by_date, + congestion_point, + ) + ) + # Add other device types here as needed + else: + logger.warning( + f"Unknown device! No device planner added for {device_state}" + ) + + return root_planner + + def plan( + self, + state: ClusterState, + target: ClusterTarget, + planning_window: int, + reason: str, + plan_due_by_date: datetime, + optimize_for_target: bool, + max_priority_class: int, + ) -> ClusterPlan: + """Create a plan for the cluster. + + Args: + state: The state of the cluster + target: The target for the cluster + planning_window: The planning window in seconds + reason: The reason for planning + plan_due_by_date: The date by which planning must be completed + optimize_for_target: Whether to optimize for the target + max_priority_class: The maximum priority class to optimize + + Returns: + A ClusterPlan for the cluster + """ + start_time = datetime.now() + + # Make sure that all congestion points in the ClusterState have a target: + for cp in state.get_congestion_points(): + congestion_point_target = target.get_congestion_point_target(cp) + if congestion_point_target is None and cp is not None: + # We don't have a target for the congestion point + logger.warning( + f"CongestionPoint without target! CongestionPoint: {cp}. Generating empty target." + ) + target.set_congestion_point_target( + congestion_point_id=cp, + congestion_point_target=JouleRangeProfile( + profile_start=target.get_global_target_profile().metadata, + ), + ) + + # Create a tree of controllers and run the planning algorithm + root_controller = self.create_controller_tree(state, target, plan_due_by_date) + + try: + root_controller.plan( + plan_due_by_date, + optimize_for_target, + max_priority_class, + self.config.multithreaded(), + ) + + # Collect device plans + device_plans = [] + for cpc in root_controller.cp_controllers: + for device in cpc.devices: + device_plans.append(device.get_device_plan()) + + # Create and return the cluster plan + plan_data = ClusterPlanData(device_plans, target.metadata) # type: ignore[arg-type] + plan = ClusterPlan(state, target, plan_data, reason, plan_due_by_date, None) + + end_time = datetime.now() + execution_time = ( + end_time - start_time + ).total_seconds() * 1000 # Convert to milliseconds + logger.info(f"Generated new plan in {execution_time} ms") + + return plan + except Exception as e: + logger.error(f"Error during planning: {e}") + raise + class S2Scheduler(Scheduler): + """ + S2Scheduler integrates the profile steering planning service with FlexMeasures. + + This scheduler uses the PlanningServiceImpl to create optimal energy profiles + for devices in a cluster based on targets and constraints. + """ __author__ = "TNO" __version__ = "1" + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.planning_service = None + self.config_deserialized = False + self.frbc_device_data = None # Store FRBC device data from WebSocket + def compute(self, *args, **kwargs): """ - Just a dummy scheduler that always plans to consume at maximum capacity. - (Schedulers return positive values for consumption, and negative values for production) + Compute the optimal energy profile using the S2 profile steering algorithm. + + Returns: + List: List containing FRBCInstruction objects and metadata dicts """ - return pd.Series( - self.sensor.get_attribute("capacity_in_mw"), - index=pd.date_range( - self.start, self.end, freq=self.resolution, inclusive="left" - ), - ) + if not self.config_deserialized: + self.deserialize_config() + + try: + # Create planning service + config = PlanningServiceConfig() + planning_service = PlanningServiceImpl(config) + + # Use FRBC device data if available, otherwise use mock data + if self.frbc_device_data is not None: + logger.info("Creating device states and cluster target from FRBC data") + device_states = self.create_device_states_from_frbc_data() + cluster_target = self.create_cluster_target_from_frbc_data() + else: + # Fallback to mock data for testing + logger.info("Using mock device states and cluster target") + device_states = self.create_mock_device_states() + cluster_target = self.create_mock_cluster_target() + + logger.info(f"Created cluster state with {len(device_states)} devices") + cluster_state = ClusterState(self.start, device_states, {}) + + # Generate plan + logger.info("Starting planning service...") + try: + cluster_plan = planning_service.plan( + state=cluster_state, + target=cluster_target, + planning_window=int((self.end - self.start).total_seconds()), + reason="S2 scheduling", + plan_due_by_date=self.start + pd.Timedelta(seconds=10), + optimize_for_target=True, + max_priority_class=1, + ) + logger.info("Planning service completed successfully") + except Exception as planning_error: + logger.error(f"Planning service failed: {planning_error}") + # Generate instructions directly without planning + if self.frbc_device_data is not None: + logger.info("Falling back to simple FRBC instruction generation") + instructions = self._generate_simple_frbc_instructions() + else: + instructions = [] + + # Create empty energy data + num_timesteps = int((self.end - self.start) / self.resolution) + energy_data = { + "sensor": self.sensor, + "data": pd.Series( + [0] * num_timesteps, + index=pd.date_range( + self.start, self.end, freq=self.resolution, inclusive="left" + ), + ), + } + return instructions + [energy_data] + + # Extract FRBCInstructions from device plans + instructions = [] + device_plans = cluster_plan.get_plan_data().get_device_plans() + + for device_plan in device_plans: + if device_plan and device_plan.instruction_profile: + instructions.extend(device_plan.instruction_profile.elements) + + # If we have FRBC device data but no instructions from planning, + # generate simple instructions based on the received data + if not instructions and self.frbc_device_data is not None: + logger.info( + "No instructions from planning service, generating simple FRBC instructions" + ) + instructions = self._generate_simple_frbc_instructions() + + # Add energy data entry for potential storage + try: + energy_profile = cluster_plan.get_joule_profile() + if energy_profile is not None and energy_profile.elements is not None: + energy_data = { + "sensor": self.sensor, + "data": pd.Series( + energy_profile.elements, + index=pd.date_range( + self.start, + self.end, + freq=self.resolution, + inclusive="left", + ), + ), + } + else: + # Create empty energy data if profile is None or has no elements + num_timesteps = int((self.end - self.start) / self.resolution) + energy_data = { + "sensor": self.sensor, + "data": pd.Series( + [0] * num_timesteps, + index=pd.date_range( + self.start, + self.end, + freq=self.resolution, + inclusive="left", + ), + ), + } + except Exception as profile_error: + logger.warning( + f"Failed to get energy profile: {profile_error}, using fallback" + ) + # Create empty energy data as fallback + num_timesteps = int((self.end - self.start) / self.resolution) + energy_data = { + "sensor": self.sensor, + "data": pd.Series( + [0] * num_timesteps, + index=pd.date_range( + self.start, self.end, freq=self.resolution, inclusive="left" + ), + ), + } + + return instructions + [energy_data] + + except Exception as e: + logger.error(f"Error in S2Scheduler.compute(): {e}") + import traceback + + logger.debug(f"Traceback: {traceback.format_exc()}") + # Return empty list on error + return [] def deserialize_config(self): - """Do not care about any flex config sent in.""" + """Deserialize the flex configuration from asset attributes.""" + # Find flex-model in asset attributes + self.flex_model = self.asset.attributes.get("flex-model", {}) + + self.deserialize_flex_config() self.config_deserialized = True + + def deserialize_flex_config(self): + """Deserialize flex-model and flex-context""" + # Deserialize flex-model + self.flex_model = S2FlexModelSchema().load(self.flex_model) + + # Deserialize self.flex_context + self.flex_context = TNOFlexContextSchema().load(self.flex_context) + + def create_planning_service( + self, config: Optional[PlanningServiceConfig] = None + ) -> PlanningServiceImpl: + """ + Create a planning service instance with the given configuration. + + Args: + config: Planning service configuration. If None, uses default values. + + Returns: + PlanningServiceImpl: Configured planning service instance + """ + if config is None: + config = PlanningServiceConfig() + + return PlanningServiceImpl(config) + + def create_cluster_state(self, device_states: Dict[str, Any]) -> ClusterState: + """ + Create a ClusterState from device states. + + Args: + device_states: Dictionary of device states + + Returns: + ClusterState: Cluster state for planning + """ + # TODO: Implement conversion from FlexMeasures device data to ClusterState + raise NotImplementedError("create_cluster_state() needs to be implemented") + + def create_cluster_target(self, target_profile: Any) -> ClusterTarget: + """ + Create a ClusterTarget from target profile data. + + Args: + target_profile: Target profile data from flex_model + + Returns: + ClusterTarget: Cluster target for planning + """ + # TODO: Implement conversion from flex_model to ClusterTarget + raise NotImplementedError("create_cluster_target() needs to be implemented") + + def create_mock_device_states(self) -> Dict[str, Any]: + """ + Create mock device states for testing. + + Returns: + Dict[str, Any]: Dictionary of mock device states + """ + from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, + ) + from s2python.common import PowerValue, CommodityQuantity + + # Create a simple mock device state for testing + mock_device_state = S2FrbcDeviceState( + device_id="mock_device_1", + device_name="Mock Device 1", + connection_id="mock_connection_1", + priority_class=1, + timestamp=self.start, + energy_in_current_timestep=PowerValue( + value=0, commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1 + ), + is_online=True, + power_forecast=None, + system_descriptions=[], + leakage_behaviours=[], + usage_forecasts=[], + fill_level_target_profiles=[], + computational_parameters=S2FrbcDeviceState.ComputationalParameters(100, 20), + actuator_statuses=[], + storage_status=[], + ) + + return {"mock_device_1": mock_device_state} + + def create_mock_cluster_target(self) -> ClusterTarget: + """ + Create a mock cluster target for testing. + + Returns: + ClusterTarget: Mock cluster target + """ + from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile + from flexmeasures_s2.profile_steering.common.profile_metadata import ( + ProfileMetadata, + ) + + # Create mock profile metadata + profile_metadata = ProfileMetadata( + profile_start=self.start, + timestep_duration=self.resolution, + nr_of_timesteps=int((self.end - self.start) / self.resolution), + ) + + # Create a simple target profile with zeros + target_elements = [0] * profile_metadata.nr_of_timesteps + # Type ignore: TargetProfile constructor accepts List[int] and converts to JouleElement + global_target_profile = TargetProfile( + profile_start=profile_metadata.profile_start, + timestep_duration=profile_metadata.timestep_duration, + elements=target_elements, # type: ignore[arg-type] + ) + + return ClusterTarget( + generated_at=self.start, + parent_id=None, + generated_by=None, + global_target_profile=global_target_profile, + congestion_point_targets={}, + ) + + def create_device_states_from_frbc_data(self) -> Dict[str, Any]: + """ + Create device states from received FRBC data. + + Returns: + Dict[str, Any]: Dictionary of device states created from FRBC data + """ + from flexmeasures_s2.profile_steering.device_planner.frbc.s2_frbc_device_state import ( + S2FrbcDeviceState, + ) + from s2python.common import PowerValue, CommodityQuantity + + if self.frbc_device_data is None: + return self.create_mock_device_states() + + # Extract information from received FRBC data + device_id = self.frbc_device_data.resource_id or "frbc_device_1" + system_desc = self.frbc_device_data.system_description + storage_status = self.frbc_device_data.storage_status + + # Create device state using the received FRBC data + device_state = S2FrbcDeviceState( + device_id=device_id, + device_name=f"FRBC Device {device_id}", + connection_id=f"{device_id}_connection", + priority_class=1, + timestamp=self.start, + energy_in_current_timestep=PowerValue( + value=0, commodity_quantity=CommodityQuantity.ELECTRIC_POWER_L1 + ), + is_online=True, + power_forecast=None, + system_descriptions=[system_desc] if system_desc else [], + leakage_behaviours=[], + usage_forecasts=[], + fill_level_target_profiles=[self.frbc_device_data.fill_level_target_profile] + if self.frbc_device_data.fill_level_target_profile + else [], + computational_parameters=S2FrbcDeviceState.ComputationalParameters(100, 20), + actuator_statuses=list(self.frbc_device_data.actuator_statuses.values()) + if hasattr(self.frbc_device_data, "actuator_statuses") + else [], + storage_status=[storage_status] if storage_status else [], + ) + + return {device_id: device_state} + + def create_cluster_target_from_frbc_data(self) -> ClusterTarget: + """ + Create a cluster target from FRBC device data. + + Returns: + ClusterTarget: Cluster target based on FRBC data + """ + from flexmeasures_s2.profile_steering.common.target_profile import TargetProfile + from flexmeasures_s2.profile_steering.common.profile_metadata import ( + ProfileMetadata, + ) + + if ( + self.frbc_device_data is None + or self.frbc_device_data.fill_level_target_profile is None + ): + return self.create_mock_cluster_target() + + # Create profile metadata + profile_metadata = ProfileMetadata( + profile_start=self.start, + timestep_duration=self.resolution, + nr_of_timesteps=int((self.end - self.start) / self.resolution), + ) + + # Convert FRBC fill level target to energy target + # This is a simplified conversion - in practice you'd need more sophisticated logic + target_elements = self._convert_frbc_fill_level_to_energy_target( + self.frbc_device_data.fill_level_target_profile, + profile_metadata.nr_of_timesteps, + ) + + # Type ignore: TargetProfile constructor accepts List[int] and converts to JouleElement + target_mode = "costs" # Default mode when running outside Flask context + logging.debug(f"Target mode = {target_mode}") + if target_mode == "energy": + global_target_profile = TargetProfile( + profile_start=profile_metadata.profile_start, + timestep_duration=profile_metadata.timestep_duration, + elements=target_elements, # type: ignore[arg-type] + ) + elif target_mode == "costs": + # For standalone operation, fall back to energy target mode + logging.warning( + "Cost target mode requires Flask context, falling back to energy target mode" + ) + # Fall back to creating a simple energy target + global_target_profile = TargetProfile( + profile_start=profile_metadata.profile_start, + timestep_duration=profile_metadata.timestep_duration, + elements=target_elements, # type: ignore[arg-type] + ) + else: + raise ValueError(f"Unknown FLEXMEASURES_S2_TARGET_MODE='{target_mode}'") + + return ClusterTarget( + generated_at=self.start, + parent_id=None, + generated_by=None, + global_target_profile=global_target_profile, + congestion_point_targets={}, + ) + + def _convert_frbc_fill_level_to_energy_target( + self, fill_level_profile, nr_timesteps: int + ) -> list: + """ + Convert FRBC fill level target profile to energy target profile. + + This is a simplified conversion for demonstration. + """ + # Simple conversion: aim for charging when fill level targets are higher + target_elements = [] + + if fill_level_profile and fill_level_profile.elements: + # For each target element, determine if we need to charge/discharge + current_timestep = 0 + + for element in fill_level_profile.elements: + duration_seconds = ( + getattr(element.duration, "value", 0) / 1000 + ) # Convert ms to seconds + timesteps_for_element = max( + 1, int(duration_seconds / self.resolution.total_seconds()) + ) + + # Simple logic: if target range is high, we want to charge (positive energy) + target_range_avg = ( + element.fill_level_range.start_of_range + + element.fill_level_range.end_of_range + ) / 2 + + if target_range_avg > 50: # Above 50% - charging target + energy_target = 10000 # 10kJ per timestep + else: # Below 50% - minimal energy + energy_target = 1000 # 1kJ per timestep + + # Add target for this duration + for _ in range( + min(timesteps_for_element, nr_timesteps - current_timestep) + ): + target_elements.append(energy_target) + current_timestep += 1 + + if current_timestep >= nr_timesteps: + break + + # Fill remaining timesteps with zeros + while len(target_elements) < nr_timesteps: + target_elements.append(0) + + return target_elements[:nr_timesteps] + + def _generate_simple_frbc_instructions(self) -> list: + """ + Generate simple FRBC instructions based on received device data. + + Returns: + List of FRBCInstruction objects + """ + from s2python.frbc import FRBCInstruction + from datetime import timezone + import uuid + + if ( + self.frbc_device_data is None + or self.frbc_device_data.system_description is None + ): + return [] + + instructions = [] + system_desc = self.frbc_device_data.system_description + fill_level_target = self.frbc_device_data.fill_level_target_profile + + # Extract actuator and operation mode information + if system_desc.actuators: + actuator = system_desc.actuators[0] # Use first actuator + if actuator.operation_modes: + operation_mode = actuator.operation_modes[0] # Use first operation mode + + # Determine operation mode factor based on fill level targets + operation_mode_factor = 0.5 # Default + + if fill_level_target and fill_level_target.elements: + # Simple logic: higher target ranges get higher factors + for element in fill_level_target.elements: + target_avg = ( + element.fill_level_range.start_of_range + + element.fill_level_range.end_of_range + ) / 2 + if target_avg > 50: + operation_mode_factor = 0.8 # Higher factor for charging + else: + operation_mode_factor = 0.2 # Lower factor for maintaining + break # Use first element for simplicity + + # Generate instruction for near future + execution_time = self.start.replace(tzinfo=timezone.utc) + + instruction = FRBCInstruction( + message_id=str(uuid.uuid4()), + id=str(uuid.uuid4()), + actuator_id=str(actuator.id), + operation_mode=str(operation_mode.id), + operation_mode_factor=operation_mode_factor, + execution_time=execution_time, + abnormal_condition=False, + ) + + instructions.append(instruction) + logger.info(f"Generated FRBC instruction: {instruction.to_json()}") + + return instructions diff --git a/flexmeasures_s2/scheduler/schemas.py b/flexmeasures_s2/scheduler/schemas.py index 9e42dfa..6cc8c07 100644 --- a/flexmeasures_s2/scheduler/schemas.py +++ b/flexmeasures_s2/scheduler/schemas.py @@ -1,5 +1,34 @@ -from marshmallow import Schema +from __future__ import annotations +from pydantic import BaseModel -class S2FlexModelSchema(Schema): - ... +class PowerValue(BaseModel): + value: float + + +class Schedule(BaseModel): + values: list[PowerValue] + + +class S2FlexModelSchema(BaseModel): + """Schema for S2 Flex Model validation.""" + + def load(self, data): + """Load and validate data.""" + return data # Pass-through for now + + +class TNOFlexContextSchema(BaseModel): + """Schema for TNO Flex Context validation.""" + + def load(self, data): + """Load and validate data.""" + return data # Pass-through for now + + +class TNOTargetProfile(BaseModel): + """Schema for TNO Target Profile validation.""" + + def load(self, data): + """Load and validate data.""" + return data # Pass-through for now diff --git a/flexmeasures_s2/scheduler/test_frbc_device.json b/flexmeasures_s2/scheduler/test_frbc_device.json new file mode 100644 index 0000000..ef38b22 --- /dev/null +++ b/flexmeasures_s2/scheduler/test_frbc_device.json @@ -0,0 +1,123 @@ +{ + "system_descriptions": [ + { + "message_type": "FRBC.SystemDescription", + "message_id": "f6769b77-3d85-4d61-8a28-3bd70fc5cef4", + "valid_from": "2025-01-21 17:52:08.121054+00:00", + "actuators": [ + { + "id": "1ebd596b-3031-403f-95a1-9520550b161b", + "diagnostic_label": "charge", + "supported_commodities": [ + "Commodity.ELECTRICITY" + ], + "operation_modes": [ + { + "id": "charge.on", + "diagnostic_label": "charge.on", + "elements": [ + { + "fill_level_range": { + "start_of_range": 0.0, + "end_of_range": 100.0 + }, + "fill_rate": { + "start_of_range": 0.0054012349, + "end_of_range": 0.0054012349 + }, + "power_ranges": [ + { + "start_of_range": 28000.0, + "end_of_range": 28000.0, + "commodity_quantity": "CommodityQuantity.ELECTRIC_POWER_L1" + } + ], + "running_costs": null + } + ], + "abnormal_condition_only": false + }, + { + "id": "charge.off", + "diagnostic_label": "charge.off", + "elements": [ + { + "fill_level_range": { + "start_of_range": 0.0, + "end_of_range": 100.0 + }, + "fill_rate": { + "start_of_range": 0.0, + "end_of_range": 0.0 + }, + "power_ranges": [ + { + "start_of_range": 0.0, + "end_of_range": 0.0, + "commodity_quantity": "CommodityQuantity.ELECTRIC_POWER_L1" + } + ], + "running_costs": null + } + ], + "abnormal_condition_only": false + } + ], + "transitions": [ + { + "id": "off.to.on", + "from_": "charge.off", + "to": "charge.on", + "start_timers": [ + "on.to.off.timer" + ], + "blocking_timers": [ + "off.to.on.timer" + ], + "transition_costs": null, + "transition_duration": null, + "abnormal_condition_only": false + }, + { + "id": "on.to.off", + "from_": "charge.on", + "to": "charge.off", + "start_timers": [ + "off.to.on.timer" + ], + "blocking_timers": [ + "on.to.off.timer" + ], + "transition_costs": null, + "transition_duration": null, + "abnormal_condition_only": false + } + ], + "timers": [ + { + "id": "on.to.off.timer", + "diagnostic_label": "on.to.off.timer", + "duration": 30 + }, + { + "id": "off.to.on.timer", + "diagnostic_label": "off.to.on.timer", + "duration": 30 + } + ] + } + ], + "storage": { + "diagnostic_label": "battery", + "fill_level_label": "SoC %", + "provides_leakage_behaviour": false, + "provides_fill_level_target_profile": true, + "provides_usage_forecast": false, + "fill_level_range": { + "start_of_range": 0.0, + "end_of_range": 100.0 + } + } + } + ] +} \ No newline at end of file diff --git a/flexmeasures_s2/scheduler/tests/__init__.py b/flexmeasures_s2/scheduler/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flexmeasures_s2/scheduler/tests/test_schemas.py b/flexmeasures_s2/scheduler/tests/test_schemas.py new file mode 100644 index 0000000..0f61a4d --- /dev/null +++ b/flexmeasures_s2/scheduler/tests/test_schemas.py @@ -0,0 +1,20 @@ +import pytest + +from flexmeasures_s2.scheduler.schemas import TNOTargetProfile + + +@pytest.mark.parametrize( + "target_profile", + [ + # todo: port test cases from Java test + {}, + { + "start": "2025-01-20T13:00+01", + "duration": "PT3H", + "values": [0, 1, 2], + }, + ], +) +def test_tno_profile_schema(target_profile: dict): + """Check whether the profile schema""" + TNOTargetProfile().load(target_profile) diff --git a/profiling_res.txt b/profiling_res.txt new file mode 100644 index 0000000..e69de29 diff --git a/requirements/app.in b/requirements/app.in index 3a17a94..b4916df 100644 --- a/requirements/app.in +++ b/requirements/app.in @@ -1,2 +1,4 @@ -flexmeasures>=0.24.0 +flexmeasures>=0.27.0 s2-python +cryptography>=44.0.2 +inflect>=7.5.0 diff --git a/requirements/app.txt b/requirements/app.txt index 67d7209..a410a53 100644 --- a/requirements/app.txt +++ b/requirements/app.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.12 # by the following command: # # pip-compile --output-file=requirements/app.txt requirements/app.in @@ -14,6 +14,8 @@ argon2-cffi-bindings==21.2.0 # via argon2-cffi arrow==1.3.0 # via rq-dashboard +asn1crypto==1.5.1 + # via webauthn attrs==24.3.0 # via # jsonschema @@ -28,12 +30,16 @@ blinker==1.9.0 # flask-mail # flask-principal # sentry-sdk +cbor2==5.6.5 + # via webauthn certifi==2024.12.14 # via # requests # sentry-sdk cffi==1.17.1 - # via argon2-cffi-bindings + # via + # argon2-cffi-bindings + # cryptography charset-normalizer==3.4.1 # via requests click==8.1.8 @@ -49,6 +55,12 @@ contourpy==1.3.1 # via matplotlib convertdate==2.4.0 # via workalendar +cryptography==45.0.6 + # via + # -r requirements/app.in + # flask-security-too + # pyopenssl + # webauthn cycler==0.12.1 # via matplotlib dill==0.3.9 @@ -96,11 +108,14 @@ flask-migrate==4.1.0 # via flexmeasures flask-principal==0.4.0 # via flask-security-too -flask-security-too==5.5.2 - # via flexmeasures +flask-security-too[fsqla,mfa]==5.5.2 + # via + # flask-security-too + # flexmeasures flask-sqlalchemy==3.1.1 # via # flask-migrate + # flask-security-too # flexmeasures flask-sslify==0.1.5 # via flexmeasures @@ -110,14 +125,12 @@ flask-wtf==1.2.2 # flexmeasures flexcache==0.3 # via pint -flexmeasures==0.24.0 +flexmeasures==0.27.0 # via -r requirements/app.in flexparser==0.4 # via pint fonttools==4.55.3 # via matplotlib -greenlet==3.1.1 - # via sqlalchemy humanize==4.11.0 # via flexmeasures idna==3.10 @@ -221,6 +234,8 @@ passlib==1.7.4 # via flask-security-too patsy==1.0.1 # via statsmodels +phonenumberslite==9.0.11 + # via flask-security-too pillow==11.1.0 # via # flexmeasures @@ -245,6 +260,7 @@ pycparser==2.22 # via cffi pydantic==1.10.20 # via + # -r requirements/app.in # flexmeasures # inflect # s2-python @@ -254,6 +270,8 @@ pymeeus==0.5.12 # via convertdate pyomo==6.8.2 # via flexmeasures +pyopenssl==25.1.0 + # via webauthn pyparsing==3.2.1 # via matplotlib python-dateutil==2.9.0.post0 @@ -274,6 +292,8 @@ pytz==2024.2 # timetomodel pyyaml==6.0.2 # via flexmeasures +qrcode==8.2 + # via flask-security-too redis==5.2.1 # via # flexmeasures @@ -327,18 +347,22 @@ sktime==0.35.0 sqlalchemy==2.0.37 # via # alembic + # flask-security-too # flask-sqlalchemy # flexmeasures # marshmallow-sqlalchemy + # sqlalchemy-utils # timely-beliefs # timetomodel +sqlalchemy-utils==0.41.2 + # via flask-security-too statsmodels==0.14.4 # via timetomodel tabulate==0.9.0 # via flexmeasures threadpoolctl==3.5.0 # via scikit-learn -timely-beliefs[forecast]==3.1.0 +timely-beliefs[forecast]==3.2.1 # via flexmeasures timetomodel==0.7.3 # via flexmeasures @@ -355,6 +379,7 @@ typing-extensions==4.12.2 # pint # py-moneyed # pydantic + # pyopenssl # sqlalchemy tzdata==2024.2 # via pandas @@ -368,6 +393,8 @@ vl-convert-python==1.7.0 # via flexmeasures webargs==8.6.0 # via flexmeasures +webauthn==2.6.0 + # via flask-security-too werkzeug==3.1.3 # via # flask diff --git a/requirements/testi.txt b/requirements/testi.txt new file mode 100644 index 0000000..c481ebb --- /dev/null +++ b/requirements/testi.txt @@ -0,0 +1,25 @@ +test_frbc_device.py::test_connexxion_ev_bus_baseline_byd_225 +-------------------------------- live log call --------------------------------- +DEBUG root:test_frbc_device.py:189 id_on_operation_mode: 8c46733e-0c68-4175-85db-4e28ef11ecf9 +DEBUG root:test_frbc_device.py:209 id_off_operation_mode: bbc4e2c2-599b-411b-b987-858d148846a4 +DEBUG root:test_frbc_device.py:219 id_on_to_off_timer: bcafc296-929e-4973-b447-bc18f7d3ceb3 +DEBUG root:test_frbc_device.py:227 id_off_to_on_timer: 412f76c3-6bb1-4654-b9c2-d31e50492987 +DEBUG root:test_frbc_device.py:235 transition_id_from_on_to_off: 5b286161-3f7f-43f6-b019-b3c808c2d376 +DEBUG root:test_frbc_device.py:247 transition_id_from_off_to_on: 24e5c3d3-4d7f-4c7e-a598-7c096f27083b +DEBUG root:test_frbc_device.py:259 charge_actuator_id: 91b16e98-47b1-463a-b679-f5baf6ee8cb7 +DEBUG root:test_frbc_device.py:277 storage_status_id: 41f861c7-f9b7-46bb-94c0-1e131170bcbd +DEBUG root:test_frbc_device.py:305 leakage_id: 14dac666-eb11-4acb-a5ec-400a051cd1b4 +DEBUG root:test_frbc_device.py:324 usage_id: 351fb97b-67e7-4901-9fcd-485cef127b0c +DEBUG root:test_frbc_device.py:351 fill_level_id: 632d6d5f-efb9-48dd-b22e-f08db900d956 +DEBUG root:test_frbc_device.py:375 id_off_operation_mode_driving: b99c327d-8866-46be-9514-32851ccb50ef +DEBUG root:test_frbc_device.py:384 off_actuator_id_driving: 8e1dc01b-4b8b-426b-a98a-d9f0cabe3503 +DEBUG root:test_frbc_device.py:189 id_on_operation_mode: 74e2d319-6fe4-4a0f-add4-e2709f2e21e0 +DEBUG root:test_frbc_device.py:209 id_off_operation_mode: 4a7f2a5a-d519-4803-8719-7f3d22ade46c +DEBUG root:test_frbc_device.py:219 id_on_to_off_timer: 5c33e567-213a-4b2f-8575-808ea27b79f7 +DEBUG root:test_frbc_device.py:227 id_off_to_on_timer: 83962f5e-5e0f-4173-88de-2ec1e0eabcd0 +DEBUG root:test_frbc_device.py:235 transition_id_from_on_to_off: a65929ed-f7cd-4e7b-860d-9bfd68be9d6b +DEBUG root:test_frbc_device.py:247 transition_id_from_off_to_on: 5c3e73cc-1b8e-4c6c-87d6-1ba076daeacb +DEBUG root:test_frbc_device.py:259 charge_actuator_id: 3e728f7a-82c7-4a44-a1ea-7f8a220b8ed7 +DEBUG root:test_frbc_device.py:277 storage_status_id: 38abda5b-6774-439d-a319-2a50671595bb +DEBUG root:test_frbc_device.py:305 leakage_id: 2ba72dcf-546d-45a2-9c87-1492437dd2c9 +DEBUG root:test_frbc_device.py:324 usage_id: d3132d10-e226-4763-adae-bd9492f8251d \ No newline at end of file diff --git a/run_mypy.sh b/run_mypy.sh index f7b3c44..52258c9 100755 --- a/run_mypy.sh +++ b/run_mypy.sh @@ -2,5 +2,5 @@ set -e pip install mypy pip install types-pytz types-requests types-Flask types-click types-redis types-tzlocal types-python-dateutil types-setuptools -files=$(find . -name \*.py -not -path "./venv/*" -not -path ".egg/*" -not -path "./build/*" -not -path "./dist/*") +files=$(find . -name \*.py -not -path "./venv/*" -not -path "./.eggs/*" -not -path "./build/*" -not -path "./dist/*" -not -path "./.mypy_cache/*") mypy --follow-imports skip --ignore-missing-imports $files diff --git a/setup.cfg b/setup.cfg index 72b2bac..291efbb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,5 +7,5 @@ exclude = .git,__pycache__,documentation max-line-length = 160 max-complexity = 13 select = B,C,E,F,W,B9 -ignore = E501, W503, E203 +ignore = E501, W503, E203, C901, E231