Skip to content

Commit

Permalink
Cli command for adding a toy account (#368)
Browse files Browse the repository at this point in the history
* adding initial structure: better name and safer against already existing data

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* command to add toy account, default implementation: a battery

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* use an email with a real domain because for undetectable reasons, the user can otherwise not log in :/

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* simplify the parameter names for IDs, humanize dates/deltas in show_data CLI

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* less session flushing by assigning models to relationships, instead of IDs

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* do not require energy/power sensors anymore for assets to be shown on dashboard

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* protect latest state view from failing with no capacity on sensor

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* Add capacity_in_mw attribute to battery asset

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* document the new CLI command

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* mention a command renaming I did

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* choose better resolutions, display market sensor at the end.

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* fix parameter name

Signed-off-by: Nicolas Höning <nicolas@seita.nl>

* add min-soc and max-soc attributes to battery asset, plus small fixes from review

Signed-off-by: Nicolas Höning <nicolas@seita.nl>
  • Loading branch information
nhoening committed Feb 25, 2022
1 parent 2e035c6 commit ca7e715
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 97 deletions.
2 changes: 2 additions & 0 deletions documentation/changelog.rst
Expand Up @@ -14,8 +14,10 @@ New features
* Add CLI option to specify custom strings that should be interpreted as NaN values when reading in time series data from CSV [see `PR #357 <http://www.github.com/FlexMeasures/flexmeasures/pull/357>`_]
* Add CLI commands ``flexmeasures add sensor``, ``flexmeasures add asset-type``, ``flexmeasures add beliefs`` (which were experimental features before). [see `PR #337 <http://www.github.com/FlexMeasures/flexmeasures/pull/337>`_]
* Add CLI commands for showing data [see `PR #339 <http://www.github.com/FlexMeasures/flexmeasures/pull/339>`_]

* Add CLI command for attaching annotations to assets: ``flexmeasures add holidays`` adds public holidays [see `PR #343 <http://www.github.com/FlexMeasures/flexmeasures/pull/343>`_]
* Add CLI command for resampling existing sensor data to new resolution [see `PR #360 <http://www.github.com/FlexMeasures/flexmeasures/pull/360>`_]
* Add CLI command to add a toy account for tutorials and trying things [see `PR #368 <http://www.github.com/FlexMeasures/flexmeasures/pull/368>`_].
* Support for percent (%) and permille (‰) sensor units [see `PR #359 <http://www.github.com/FlexMeasures/flexmeasures/pull/359>`_]

Bugfixes
Expand Down
14 changes: 8 additions & 6 deletions documentation/cli/change_log.rst
Expand Up @@ -7,22 +7,24 @@ FlexMeasures CLI Changelog
since v0.9.0 | January 26, 2022
=====================

* add CLI comands for showing data ``flexmeasures show accounts``, ``flexmeasures show account``, ``flexmeasures show roles``, ``flexmeasures show asset-types``, ``flexmeasures show asset`` and ``flexmeasures show data-sources``.
* Add CLI commands for showing data ``flexmeasures show accounts``, ``flexmeasures show account``, ``flexmeasures show roles``, ``flexmeasures show asset-types``, ``flexmeasures show asset`` and ``flexmeasures show data-sources``.
* Add ``flexmeasures db-ops resample-data`` CLI command to resample sensor data to a different resolution.
* Add ``flexmeasures add toy-account`` for tutorials and trying things.
* Rename ``flexmeasures add structure`` to ``flexmeasures add initial-structure``.


since v0.9.0 | January 26, 2022
since v0.8.0 | January 26, 2022
=====================

* add ``flexmeasures add sensor``, ''flexmeasures add asset-type``, ```flexmeasures add beliefs``. These were previously experimental features (under the `dev-add` command group).
* Add ``flexmeasures add sensor``, ''flexmeasures add asset-type``, ```flexmeasures add beliefs``. These were previously experimental features (under the `dev-add` command group).
* ``flexmeasures add asset`` now directly creates an asset in the new data model.
* add ``flexmeasures delete sensor``, ``flexmeasures delete nan-beliefs`` and ``flexmeasures delete unchanged-beliefs``.
* Add ``flexmeasures delete sensor``, ``flexmeasures delete nan-beliefs`` and ``flexmeasures delete unchanged-beliefs``.


since v0.6.0 | April 2, 2021
=====================

* add ``flexmeasures add account``, ``flexmeasures delete account``, and the ``--account-id`` param to ``flexmeasures add user``.
* Add ``flexmeasures add account``, ``flexmeasures delete account``, and the ``--account-id`` param to ``flexmeasures add user``.


since v0.4.0 | April 2, 2021
Expand All @@ -36,4 +38,4 @@ since v0.3.0 | April 2, 2021

* Refactor CLI into the main groups ``add``, ``delete``, ``jobs`` and ``db-ops``
* Add ``flexmeasures add asset``, ``flexmeasures add user`` and ``flexmeasures add weather-sensor``
* split the ``populate-db`` command into ``flexmeasures add structure`` and ``flexmeasures add forecasts``
* Split the ``populate-db`` command into ``flexmeasures add structure`` and ``flexmeasures add forecasts``
6 changes: 3 additions & 3 deletions documentation/cli/commands.rst
Expand Up @@ -23,8 +23,7 @@ of which some are referred to in this documentation.
--------------

================================================= =======================================
``flexmeasures add structure`` Initialize structural data like asset types,
market types and weather sensor types.
``flexmeasures add initial-structure`` Initialize structural data like users, roles and asset types.
``flexmeasures add account-role`` Create a FlexMeasures tenant account role.
``flexmeasures add account`` Create a FlexMeasures tenant account.
``flexmeasures add user`` Create a FlexMeasures user.
Expand All @@ -35,6 +34,7 @@ of which some are referred to in this documentation.
``flexmeasures add external-weather-forecasts`` Collect weather forecasts from the DarkSky API.
``flexmeasures add beliefs`` Load beliefs from file.
``flexmeasures add forecasts`` Create forecasts.
``flexmeasures add toy-account`` Create a toy account, for tutorials and trying things.
================================================= =======================================


Expand All @@ -56,7 +56,7 @@ of which some are referred to in this documentation.

================================================= =======================================
``flexmeasures delete structure`` Delete all structural (non time-series) data like assets (types),
markets (types) and weather sensors (types) and users.
roles and users.
``flexmeasures delete account-role`` Delete a tenant account role.
``flexmeasures delete account`` Delete a tenant account & also their users (with assets and power measurements).
``flexmeasures delete user`` Delete a user & also their assets and power measurements.
Expand Down
87 changes: 83 additions & 4 deletions flexmeasures/cli/data_add.py
Expand Up @@ -15,6 +15,11 @@
from workalendar.registry import registry as workalendar_registry

from flexmeasures.data import db
from flexmeasures.data.scripts.data_gen import (
add_transmission_zone_asset,
populate_initial_structure,
add_default_asset_types,
)
from flexmeasures.data.services.forecasting import create_forecasting_jobs
from flexmeasures.data.services.users import create_user
from flexmeasures.data.models.user import Account, AccountRole, RolesAccounts
Expand Down Expand Up @@ -297,13 +302,11 @@ def add_weather_sensor(**args):
print(f" You can access it at its entity address {sensor.entity_address}")


@fm_add_data.command("structure")
@fm_add_data.command("initial-structure")
@with_appcontext
def add_initial_structure():
"""Initialize useful structural data."""
from flexmeasures.data.scripts.data_gen import populate_structure

populate_structure(db)
populate_initial_structure(db)


@fm_add_data.command("beliefs")
Expand Down Expand Up @@ -799,6 +802,82 @@ def create_forecasts(
)


@fm_add_data.command("toy-account")
@with_appcontext
@click.option(
"--kind",
default="battery",
type=click.Choice(["battery"]),
help="What kind of toy account. Defaults to a battery.",
)
@click.option("--name", type=str, default="Toy Account", help="Name of the account")
def add_toy_account(kind: str, name: str):
"""
Create a toy account, for tutorials and trying things.
"""
asset_types = add_default_asset_types(db=db)
location = (52.374, 4.88969) # Amsterdam
if kind == "battery":
# make an account (if not exist)
account = Account.query.filter(Account.name == name).one_or_none()
if account:
click.echo(f"Account {name} already exists. Aborting ...")
raise click.Abort()
# make an account user (account-admin?)
user = create_user(
email="toy-user@flexmeasures.io",
check_email_deliverability=False,
password="toy-password",
user_roles=["account-admin"],
account_name=name,
)
# make assets
for asset_type in ("solar", "building", "battery"):
asset = GenericAsset(
name=f"toy-{asset_type}",
generic_asset_type=asset_types[asset_type],
owner=user.account,
latitude=location[0],
longitude=location[1],
)
db.session.add(asset)
if asset_type == "battery":
asset.attributes = dict(
capacity_in_mw=0.005, min_soc_in_mwh=0.0005, max_soc_in_mwh=0.0045
)
# add charging sensor to battery
charging_sensor = Sensor(
name="charging",
generic_asset=asset,
unit="kW",
timezone="Europe/Amsterdam",
event_resolution=timedelta(minutes=15),
)
db.session.add(charging_sensor)

# add public day-ahead market (as sensor of transmission zone asset)
nl_zone = add_transmission_zone_asset("NL", db=db)
day_ahead_sensor = Sensor.query.filter(
Sensor.generic_asset == nl_zone, Sensor.name == "Day ahead prices"
).one_or_none()
if not day_ahead_sensor:
day_ahead_sensor = Sensor(
name="Day ahead prices",
generic_asset=nl_zone,
unit="EUR/MWh",
timezone="Europe/Amsterdam",
event_resolution=timedelta(minutes=60),
)
db.session.add(day_ahead_sensor)

db.session.commit()

click.echo(
f"Toy account {name} with user {user.email} created successfully. You might want to run `flexmeasures show account --id {user.account.id}`"
)
click.echo(f"The sensor for Day ahead prices is {day_ahead_sensor}.")


@fm_add_data.command("external-weather-forecasts")
@with_appcontext
@click.option(
Expand Down
5 changes: 3 additions & 2 deletions flexmeasures/cli/data_delete.py
Expand Up @@ -144,7 +144,7 @@ def delete_structure(force):
TODO: This could in our future data model (currently in development) be replaced by
`flexmeasures delete generic-asset-type`, `flexmeasures delete generic-asset`
and `flexmeasures delete sensor`.
and so on.
"""
if not force:
confirm_deletion(structure=True)
Expand Down Expand Up @@ -298,7 +298,8 @@ def delete_nan_beliefs(sensor_id: Optional[int] = None):
@fm_delete_data.command("sensor")
@with_appcontext
@click.option(
"--sensor-id",
"--id",
"sensor_id",
type=int,
required=True,
help="Delete a single sensor and its (time series) data. Follow up with the sensor's ID.",
Expand Down
9 changes: 5 additions & 4 deletions flexmeasures/cli/data_show.py
Expand Up @@ -4,6 +4,7 @@
from flask import current_app as app
from flask.cli import with_appcontext
from tabulate import tabulate
from humanize import naturaldelta, naturaltime

from flexmeasures.data.models.user import Account, AccountRole, User, Role
from flexmeasures.data.models.data_sources import DataSource
Expand Down Expand Up @@ -71,7 +72,7 @@ def list_roles():

@fm_show_data.command("account")
@with_appcontext
@click.option("--account-id", type=int, required=True)
@click.option("--id", "account_id", type=int, required=True)
def show_account(account_id):
"""
Show information about an account, including users and assets.
Expand Down Expand Up @@ -103,7 +104,7 @@ def show_account(account_id):
user.id,
user.username,
user.email,
user.last_login_at,
naturaltime(user.last_login_at),
"".join([role.name for role in user.roles]),
)
for user in users
Expand Down Expand Up @@ -149,7 +150,7 @@ def list_asset_types():

@fm_show_data.command("asset")
@with_appcontext
@click.option("--asset-id", type=int, required=True)
@click.option("--id", "asset_id", type=int, required=True)
def show_generic_asset(asset_id):
"""
Show asset info and list sensors
Expand Down Expand Up @@ -185,7 +186,7 @@ def show_generic_asset(asset_id):
sensor.id,
sensor.name,
sensor.unit,
sensor.event_resolution,
naturaldelta(sensor.event_resolution),
sensor.timezone,
"".join([f"{k}:{v}\n" for k, v in sensor.attributes.items()]),
)
Expand Down
2 changes: 1 addition & 1 deletion flexmeasures/data/models/data_sources.py
Expand Up @@ -41,7 +41,7 @@ def __init__(
if user is not None:
name = user.username
type = "user"
self.user_id = user.id
self.user = user
elif user is None and type == "user":
raise TypeError("A data source cannot have type 'user' but no user set.")
self.type = type
Expand Down

0 comments on commit ca7e715

Please sign in to comment.