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

Offer asset grouping by location #148

Merged
merged 3 commits into from Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions documentation/changelog.rst
Expand Up @@ -7,6 +7,8 @@ v0.6.0 | July XX, 2021

New features
-----------
* Analytics view offers grouping of all assets by location [see `PR #148 <http://www.github.com/SeitaBV/flexmeasures/pull/148>`_]


Bugfixes
-----------
Expand Down
48 changes: 29 additions & 19 deletions flexmeasures/data/services/resources.py
Expand Up @@ -116,8 +116,8 @@ def get_asset_group_queries(
Valid names are:
- "renewables", to query all solar and wind assets
- "EVSE", to query all Electric Vehicle Supply Equipment
- "each Charge Point", to query each individual Charge Point
(i.e. all EVSE at 1 location)
- "location", to query each individual location with assets
(i.e. all EVSE at 1 location or each household)
:param all_users: if True, do not filter out assets that do not belong to the user (use with care)
"""

Expand All @@ -141,19 +141,18 @@ def get_asset_group_queries(
asset_type_name=asset_type.name
)

# 3. Finally, we group assets by location
if "location" in custom_additional_groups:
asset_queries.update(get_location_queries())

if not all_users:
asset_queries = mask_inaccessible_assets(asset_queries)

# 3. We group EVSE assets by location (if they share a location, they belong to the same Charge Point)
if "each Charge Point" in custom_additional_groups:
asset_queries.update(get_charge_point_queries())

return asset_queries


def get_charge_point_queries() -> Dict[str, Query]:
def get_location_queries() -> Dict[str, Query]:
"""
A Charge Point is defined similarly to asset groups (see get_asset_group_queries).
We group EVSE assets by location (if they share a location, they belong to the same Charge Point)
Like get_asset_group_queries, the values in the returned dict still need an executive call, like all(), count() or first().

Expand All @@ -163,18 +162,29 @@ def get_charge_point_queries() -> Dict[str, Query]:
evse_display_name = "Seoul Hilton - charger 1"
Then:
charge_point_display_name = "Seoul Hilton (Charge Point)"

A Charge Point is a special case. If all assets on a location are of type EVSE,
we can call the location a "Charge Point".
"""
asset_queries = {}
all_evse_assets = Asset.query.filter(
Asset.asset_type_name.in_(["one-way_evse", "two-way_evse"])
).all()
cp_groups = group_assets_by_location(all_evse_assets)
for cp_group in cp_groups:
charge_point_name = cp_group[0].display_name.split(" -")[0] + " (Charge Point)"
asset_queries[charge_point_name] = Asset.query.filter(
Asset.name.in_([evse.name for evse in cp_group])
all_assets = Asset.query.all()
loc_groups = group_assets_by_location(all_assets)
for loc_group in loc_groups:
if len(loc_group) == 1:
continue
location_type = "(Location)"
if all(
[
asset.asset_type_name in ["one-way_evse", "two-way_evse"]
for asset in loc_group
]
):
location_type = "(Charge Point)"
location_name = f"{loc_group[0].display_name.split(' -')[0]} {location_type}"
asset_queries[location_name] = Asset.query.filter(
Asset.name.in_([asset.name for asset in loc_group])
)
return mask_inaccessible_assets(asset_queries)
return asset_queries


def mask_inaccessible_assets(
Expand Down Expand Up @@ -316,7 +326,7 @@ def __init__(self, name: str):

# Query assets for all users to set some public information about the resource
asset_queries = get_asset_group_queries(
custom_additional_groups=["renewables", "EVSE", "each Charge Point"],
custom_additional_groups=["renewables", "EVSE", "location"],
all_users=True,
)
asset_query = (
Expand Down Expand Up @@ -382,7 +392,7 @@ def hover_label(self) -> Optional[str]:

@property
def parameterized_name(self) -> str:
"""Get a parameterized name for use in javascript."""
"""Get a parametrized name for use in javascript."""
return parameterize(self.name)

def load_sensor_data(
Expand Down
16 changes: 8 additions & 8 deletions flexmeasures/ui/views/analytics.py
Expand Up @@ -56,7 +56,7 @@ def analytics_view():
markets = get_markets()
assets = get_assets(order_by_asset_attribute="display_name", order_direction="asc")
asset_groups = get_asset_group_queries(
custom_additional_groups=["renewables", "EVSE", "each Charge Point"]
custom_additional_groups=["renewables", "EVSE", "location"]
)
asset_group_names: List[str] = [
group for group in asset_groups if asset_groups[group].count() > 0
Expand Down Expand Up @@ -138,7 +138,7 @@ def analytics_view():
tools=tools,
)
# the bottom plots need a separate x axis if they get their own legend (Bokeh complains otherwise)
# this means in that in that corner case zooming will not work across all foour plots
# this means in that in that corner case zooming will not work across all four plots
prices_fig = make_prices_figure(
data["prices"],
data["prices_forecast"],
Expand Down Expand Up @@ -230,7 +230,7 @@ def analytics_data_view(content, content_type):
# Maybe move some of this stuff into get_data_and_metrics
assets = get_assets(order_by_asset_attribute="display_name", order_direction="asc")
asset_groups = get_asset_group_queries(
custom_additional_groups=["renewables", "EVSE", "each Charge Point"]
custom_additional_groups=["renewables", "EVSE", "location"]
)
asset_group_names: List[str] = [
group for group in asset_groups if asset_groups[group].count() > 0
Expand Down Expand Up @@ -263,7 +263,7 @@ def analytics_data_view(content, content_type):
selected_resource.assets,
)

hor = session["forecast_horizon"]
horizon = session["forecast_horizon"]
rev_cost_header = (
"costs/revenues" if show_consumption_as_positive else "revenues/costs"
)
Expand All @@ -276,19 +276,19 @@ def analytics_data_view(content, content_type):
"power_data_label",
"power",
"power_forecast_label",
f"power_forecast_{hor}",
f"power_forecast_{horizon}",
f"{weather_type}_label",
f"{weather_type}",
f"{weather_type}_forecast_label",
f"{weather_type}_forecast_{hor}",
f"{weather_type}_forecast_{horizon}",
"price_label",
f"price_on_{selected_market.name}",
"price_forecast_label",
f"price_forecast_{hor}",
f"price_forecast_{horizon}",
f"{rev_cost_header}_label",
rev_cost_header,
f"{rev_cost_header}_forecast_label",
f"{rev_cost_header}_forecast_{hor}",
f"{rev_cost_header}_forecast_{horizon}",
]
source_units = [
"",
Expand Down