Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add flexmeasures add schedule generic command #730

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f64709a
test: add shiftable_load fixture
victorgarcia98 Jun 14, 2023
35ca7e7
test: move fixture setup_dummy_sensors from test_reporting.py to conf…
victorgarcia98 Jun 14, 2023
99af08c
feat: add ShiftableLoadFlexModelSchema
victorgarcia98 Jun 14, 2023
5216fa3
test: add ShiftableLoadFlexModelSchema tests
victorgarcia98 Jun 14, 2023
8faf7e5
feat: add ShiftableLoadScheduler
victorgarcia98 Jun 14, 2023
b1472a5
tests: add ShiftableLoadScheduler tests
victorgarcia98 Jun 14, 2023
e32767a
test: add required parameter
victorgarcia98 Jun 14, 2023
c1e9db5
Merge branch 'main' into feature/shiftable-load-scheduler
victorgarcia98 Jun 14, 2023
d26cd53
docs: improve docstrings
victorgarcia98 Jun 15, 2023
2ea9ad7
feat: add scheduler_class_str to create_scheduling_job make_schedule …
victorgarcia98 Jun 15, 2023
45cfdeb
docs: add new command to commands.rst
victorgarcia98 Jun 15, 2023
d4e0929
feat: add `flexmeasures add schedule generic` command
victorgarcia98 Jun 15, 2023
a5c5373
refactor: change `flexmeasures add schedule generic` function name
victorgarcia98 Jun 15, 2023
3016bdd
Merge branch 'main' into feature/shiftable-load-scheduler
victorgarcia98 Jul 20, 2023
48eed71
fix: pandas 2.0 deprecated argument
victorgarcia98 Jul 20, 2023
84c23be
Merge branch 'main' into feature/shiftable-load-scheduler
victorgarcia98 Jul 21, 2023
850dd51
docs: add changelog
victorgarcia98 Jul 21, 2023
b099e25
refactor: move TimeIntervalSchema to data.schemas.time
victorgarcia98 Jul 21, 2023
bf8c20d
refactor: rename cost_sensor to consumption_price_sensor
victorgarcia98 Jul 21, 2023
405ca40
docs: add attribute description
victorgarcia98 Jul 21, 2023
c20669c
address change requests
victorgarcia98 Jul 25, 2023
fbffd2e
Merge branch 'main' into feature/shiftable-load-scheduler
victorgarcia98 Jul 25, 2023
98d4a16
use consumption_price_sensor from flex_context
victorgarcia98 Jul 25, 2023
b991863
making block_invalid_starting_times_for_whole_process_scheduling work…
victorgarcia98 Jul 25, 2023
6822958
remove consumption_price_sensor from flex_model
victorgarcia98 Jul 25, 2023
f0c9624
Merge branch 'feature/shiftable-load-scheduler' into feature/cli-add-…
victorgarcia98 Jul 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion documentation/api/notation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,12 @@ Here are the three types of flexibility models you can expect to be built-in:

2) For **shiftable processes**

.. todo:: A simple and proven algorithm exists, but is awaiting proper integration into FlexMeasures, see `PR 729 <https://github.com/FlexMeasures/flexmeasures/pull/729>`_.
- ``power``: nominal power of the load.
- ``duration``: time that the load last.
- ``optimization_sense``: objective of the scheduler, to maximize or minimize.
- ``time_restrictions``: time periods in which the load cannot be schedule to.
- ``load_type``: Inflexible, Breakable or Shiftable.


3) For **buffer devices** (e.g. thermal energy storage systems connected to heat pumps), use the same flexibility parameters described above for storage devices. Here are some tips to model a buffer with these parameters:

Expand Down
2 changes: 1 addition & 1 deletion documentation/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ New features
* DataSource table now allows storing arbitrary attributes as a JSON (without content validation), similar to the Sensor and GenericAsset tables [see `PR #750 <https://www.github.com/FlexMeasures/flexmeasures/pull/750>`_]
* Added API endpoint `/sensor/<id>` for fetching a single sensor. [see `PR #759 <https://www.github.com/FlexMeasures/flexmeasures/pull/759>`_]
* The CLI now allows to set lists and dicts as asset & sensor attributes (formerly only single values) [see `PR #762 <https://www.github.com/FlexMeasures/flexmeasures/pull/762>`_]
* Add `ShiftableLoadScheduler` class, which optimizes loads activation using one of the following policies: inflexible, shiftable and breakable [see `PR #729 <https://www.github.com/FlexMeasures/flexmeasures/pull/729>`_]

Bugfixes
-----------
Expand All @@ -28,7 +29,6 @@ Infrastructure / Support
* The endpoint `[POST] /health/ready <api/v3_0.html#get--api-v3_0-health-ready>`_ returns the status of the Redis connection, if configured [see `PR #699 <https://www.github.com/FlexMeasures/flexmeasures/pull/699>`_]
* Document the `device_scheduler` linear program [see `PR #764 <https://www.github.com/FlexMeasures/flexmeasures/pull/764>`_].

/api/v3_0/health/ready

v0.14.2 | July 25, 2023
============================
Expand Down
1 change: 1 addition & 0 deletions documentation/cli/commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ of which some are referred to in this documentation.
``flexmeasures add source`` Add a new data source.
``flexmeasures add forecasts`` Create forecasts.
``flexmeasures add schedule for-storage`` Create a charging schedule for a storage asset.
``flexmeasures add schedule generic`` Create a schedule with any Scheduler class.
``flexmeasures add holidays`` Add holiday annotations to accounts and/or assets.
``flexmeasures add annotation`` Add annotation to accounts, assets and/or sensors.
``flexmeasures add toy-account`` Create a toy account, for tutorials and trying things.
Expand Down
149 changes: 149 additions & 0 deletions flexmeasures/cli/data_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,155 @@ def add_schedule_for_storage(
click.secho("New schedule is stored.", **MsgStyle.SUCCESS)


@create_schedule.command("generic")
@with_appcontext
@click.option(
"--sensor-id",
"sensor",
type=SensorIdField(),
required=True,
help="Create schedule for this sensor. Follow up with the sensor's ID.",
)
@click.option(
"--scheduler",
"scheduler_class",
default="",
type=click.STRING,
help="Scheduler class registered in flexmeasures.data.models.planning or in an available flexmeasures plugin."
" Use the command `flexmeasures show schedulers` to list all the available schedulers.",
)
@click.option(
"--edit-flex-model",
"edit_flex_model",
is_flag=True,
help="Whether to open your default editor to create/update the flex-model"
"The resulting flex-model is stored in /tmp/flex-model.json",
)
@click.option(
"--edit-flex-context",
"edit_flex_context",
is_flag=True,
help="Whether to open your default editor to create/update the flex-context"
"The resulting flex-context is stored in /tmp/flex-context.json",
)
@click.option(
"--start",
"start",
type=AwareDateTimeField(format="iso"),
required=True,
help="Schedule starts at this datetime. Follow up with a timezone-aware datetime in ISO 6801 format.",
)
@click.option(
"--duration",
"duration",
type=DurationField(),
required=True,
help="Duration of schedule, after --start. Follow up with a duration in ISO 6801 format, e.g. PT1H (1 hour) or PT45M (45 minutes).",
)
@click.option(
"--as-job",
"as_job",
is_flag=True,
help="Whether to queue a scheduling job instead of computing directly. "
"To process the job, run a worker (on any computer, but configured to the same databases) to process the 'scheduling' queue. Defaults to False.",
)
def add_schedule_generic(
scheduler_class,
sensor: Sensor,
start: datetime,
duration: timedelta,
as_job: bool = False,
edit_flex_model: bool = False,
edit_flex_context: bool = False,
):
"""Create a new schedule with a generic Scheduler class.

Example usage:

1. Run the command to add a new schedule:

flexmeasures add schedule generic --sensor-id 1 --scheduler ShiftableLoadScheduler --start 2023-01-01T00:00:00+01:00 --duration PT12H --edit-flex-model

2. Input the following flex-model:

{"cost-sensor": 2, "duration": "PT5H", "load-type": "INFLEXIBLE","power": 2.0}

3. Show the resulting schedule:

flexmeasures show beliefs --sensor-id 1 --start 2023-01-01T00:00:00+01:00 --duration PT12H


Add the following lines to your shell startup file (e.g. .bashrc) you change your default editor:

export EDITOR="code"
export VISOR="code"

Then, activate your startup file, for example:

source ~/.bashrc

"""

flex_model: dict | None = {}
if edit_flex_model:
flex_model = launch_editor_json("/tmp/flex_model.json")

if flex_model is None:
click.secho("Error decoding flex-model.", **MsgStyle.ERROR)
raise click.Abort()

flex_context: dict | None = {}
if edit_flex_context:
flex_context = launch_editor_json("/tmp/flex_context.json")

if flex_context is None:
click.secho("Error decoding flex-context.", **MsgStyle.ERROR)
raise click.Abort()

click.echo(f"flex_context={flex_context}")
click.echo(f"flex_model={flex_model}")

scheduling_kwargs = dict(
start=start,
end=start + duration,
belief_time=server_now(),
resolution=sensor.event_resolution,
flex_model=flex_model,
flex_context=flex_context,
)

if as_job:
job = create_scheduling_job(
sensor=sensor, scheduler_class_str=scheduler_class, **scheduling_kwargs
)
if job:
click.secho(
f"New scheduling job {job.id} has been added to the queue.",
**MsgStyle.SUCCESS,
)
else:
success = make_schedule(
sensor_id=sensor.id,
scheduler_class_str=scheduler_class,
**scheduling_kwargs,
)
if success:
click.secho("New schedule is stored.", **MsgStyle.SUCCESS)


def launch_editor_json(filename: str) -> dict | None:
"""Launch editor to create/edit a json object"""
click.edit("{\n}", filename=filename)

try:
with open(filename, "r") as f:
data = json.load(f)
except (json.JSONDecodeError, TypeError):
return None

return data


@fm_add_data.command("report")
@with_appcontext
@click.option(
Expand Down