diff --git a/documentation/tut/toy-example-expanded.rst b/documentation/tut/toy-example-expanded.rst index 78dbff202..cec1c79e7 100644 --- a/documentation/tut/toy-example-expanded.rst +++ b/documentation/tut/toy-example-expanded.rst @@ -117,6 +117,12 @@ In the case of the scheduler that we ran in the previous tutorial, which did not .. note:: You can add arbitrary sensors to a chart using the attribute ``sensors_to_show``. See :ref:`view_asset-data` for more. +A nice feature is that you can check the data connectivity status of your building asset. Now that we have made the schedule, both lamps are green. You can also view it in `FlexMeasures UI `_ : + +.. image:: https://github.com/FlexMeasures/screenshots/raw/main/tut/toy-schedule/screenshot_building_status.png + :align: center +| + We hope this part of the tutorial shows how to incorporate a limited grid connection rather easily with FlexMeasures. There are more ways to model such settings, but this is a straightforward one. This tutorial showed a quick way to add an inflexible load (like solar power) and a grid connection. diff --git a/documentation/tut/toy-example-setup.rst b/documentation/tut/toy-example-setup.rst index cff3e2fe0..907522808 100644 --- a/documentation/tut/toy-example-setup.rst +++ b/documentation/tut/toy-example-setup.rst @@ -173,19 +173,42 @@ If you want, you can inspect what you created: All assets: - ID Name Type Location + ID Name Type Location ---- ----------- ------- ----------------- - 2 toy-battery battery (52.374, 4.88969) - 3 toy-solar solar (52.374, 4.88969) + 2 toy-building building (52.374, 4.88969) + 3 toy-battery battery (52.374, 4.88969) + 4 toy-solar solar (52.374, 4.88969) .. code-block:: bash $ flexmeasures show asset --id 2 ========================= - Asset toy-battery (ID: 2) + Asset toy-building (ID: 2) ========================= + Type Location Attributes + ------- ----------------- ---------------------------- + building (52.374, 4.88969) + + ==================================== + Child assets of toy-building (ID: 2) + ==================================== + + Id Name Type + ------- ----------------- ---------------------------- + 3 toy-battery battery + 4 toy-solar solar + + No sensors in asset ... + + $ flexmeasures show asset --id 3 + + ================================== + Asset toy-battery (ID: 3) + Child of asset toy-building (ID: 2) + ================================== + Type Location Attributes ------- ----------------- ---------------------------- battery (52.374, 4.88969) capacity_in_mw: 0.5 @@ -193,6 +216,12 @@ If you want, you can inspect what you created: max_soc_in_mwh: 0.45 sensors_to_show: [1, [3, 2]] + ==================================== + Child assets of toy-battery (ID: 3) + ==================================== + + No children assets ... + All sensors in asset: ID Name Unit Resolution Timezone Attributes @@ -200,7 +229,6 @@ If you want, you can inspect what you created: 2 discharging MW 15 minutes Europe/Amsterdam - Yes, that is quite a large battery :) .. note:: Obviously, you can use the ``flexmeasures`` command to create your own, custom account and assets. See :ref:`cli`. And to create, edit or read asset data via the API, see :ref:`v3_0`. diff --git a/flexmeasures/cli/data_add.py b/flexmeasures/cli/data_add.py index bdd253ca1..7f1ac3e3c 100755 --- a/flexmeasures/cli/data_add.py +++ b/flexmeasures/cli/data_add.py @@ -2005,8 +2005,13 @@ def create_asset_with_one_sensor( asset_type: str, sensor_name: str, unit: str = "MW", + parent_asset_id: int | None = None, **asset_attributes, ): + asset_kwargs = dict() + if parent_asset_id is not None: + asset_kwargs["parent_asset_id"] = parent_asset_id + asset = get_or_create_model( GenericAsset, name=asset_name, @@ -2014,6 +2019,7 @@ def create_asset_with_one_sensor( owner=db.session.get(Account, account_id), latitude=location[0], longitude=location[1], + **asset_kwargs, ) if len(asset_attributes) > 0: asset.attributes = asset_attributes @@ -2031,12 +2037,24 @@ def create_asset_with_one_sensor( ) return sensor + # create building asset + building_asset = get_or_create_model( + GenericAsset, + name="toy-building", + generic_asset_type=asset_types["building"], + owner=db.session.get(Account, account_id), + latitude=location[0], + longitude=location[1], + ) + db.session.flush() + if kind == "battery": # create battery discharging_sensor = create_asset_with_one_sensor( "toy-battery", "battery", "discharging", + parent_asset_id=building_asset.id, capacity_in_mw=0.5, min_soc_in_mwh=0.05, max_soc_in_mwh=0.45, @@ -2044,9 +2062,7 @@ def create_asset_with_one_sensor( # create solar production_sensor = create_asset_with_one_sensor( - "toy-solar", - "solar", - "production", + "toy-solar", "solar", "production", parent_asset_id=building_asset.id ) # add day-ahead price sensor and PV production sensor to show on the battery's asset page @@ -2118,7 +2134,7 @@ def create_asset_with_one_sensor( grid_connection_capacity = get_or_create_model( Sensor, name="grid connection capacity", - generic_asset=nl_zone, + generic_asset=building_asset, timezone="Europe/Amsterdam", event_resolution="P1Y", unit="MW", @@ -2146,9 +2162,7 @@ def create_asset_with_one_sensor( db.session.commit() headroom = create_asset_with_one_sensor( - "toy-battery", - "battery", - "headroom", + "toy-battery", "battery", "headroom", parent_asset_id=building_asset.id ) db.session.commit() diff --git a/flexmeasures/cli/data_show.py b/flexmeasures/cli/data_show.py index 48859b1eb..d3e2259de 100644 --- a/flexmeasures/cli/data_show.py +++ b/flexmeasures/cli/data_show.py @@ -188,9 +188,14 @@ def show_generic_asset(asset): """ Show asset info and list sensors """ - click.echo(f"======{len(asset.name) * '='}========") + separator_num = 18 if asset.parent_asset is not None else 8 + click.echo(f"======{len(asset.name) * '='}{separator_num * '='}") click.echo(f"Asset {asset.name} (ID: {asset.id})") - click.echo(f"======{len(asset.name) * '='}========\n") + if asset.parent_asset is not None: + click.echo( + f"Child of asset {asset.parent_asset.name} (ID: {asset.parent_asset.id})" + ) + click.echo(f"======{len(asset.name) * '='}{separator_num * '='}\n") asset_data = [ ( @@ -201,6 +206,23 @@ def show_generic_asset(asset): ] click.echo(tabulate(asset_data, headers=["Type", "Location", "Attributes"])) + child_asset_data = [ + ( + child.id, + child.name, + child.generic_asset_type.name, + ) + for child in asset.child_assets + ] + click.echo() + click.echo(f"======{len(asset.name) * '='}===================") + click.echo(f"Child assets of {asset.name} (ID: {asset.id})") + click.echo(f"======{len(asset.name) * '='}===================\n") + if child_asset_data: + click.echo(tabulate(child_asset_data, headers=["Id", "Name", "Type"])) + else: + click.secho("No children assets ...", **MsgStyle.WARN) + click.echo() sensors = db.session.scalars( select(Sensor).filter_by(generic_asset_id=asset.id).order_by(Sensor.name)