sensors.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import json
  2. from altair.utils.html import spec_to_html
  3. from flask import current_app, request
  4. from flask_classful import FlaskView, route
  5. from flask_security import auth_required, login_required
  6. from werkzeug.exceptions import NotFound
  7. from marshmallow import fields
  8. from webargs.flaskparser import use_kwargs
  9. from flexmeasures.data import db
  10. from flexmeasures.data.schemas import StartEndTimeSchema
  11. from flexmeasures.data.schemas.times import AwareDateTimeField
  12. from flexmeasures.api.dev.sensors import SensorAPI
  13. from flexmeasures import Sensor
  14. from flexmeasures.ui.utils.view_utils import render_flexmeasures_template
  15. from flexmeasures.ui.utils.chart_defaults import chart_options
  16. from flexmeasures.ui.utils.breadcrumb_utils import get_breadcrumb_info
  17. from flexmeasures.ui.views.assets.utils import (
  18. user_can_delete,
  19. user_can_update,
  20. )
  21. class SensorUI(FlaskView):
  22. """
  23. This view creates several new UI endpoints for viewing sensors.
  24. todo: consider extending this view for crud purposes
  25. """
  26. route_base = "/sensors"
  27. trailing_slash = False
  28. @auth_required()
  29. @route("/<id>/chart")
  30. @use_kwargs(
  31. {
  32. "event_starts_after": AwareDateTimeField(format="iso", required=False),
  33. "event_ends_before": AwareDateTimeField(format="iso", required=False),
  34. "beliefs_after": AwareDateTimeField(format="iso", required=False),
  35. "beliefs_before": AwareDateTimeField(format="iso", required=False),
  36. "include_sensor_annotations": fields.Bool(required=False),
  37. "include_asset_annotations": fields.Bool(required=False),
  38. "include_account_annotations": fields.Bool(required=False),
  39. "dataset_name": fields.Str(required=False),
  40. "chart_theme": fields.Str(required=False),
  41. },
  42. location="query",
  43. )
  44. def get_chart(self, id, **kwargs):
  45. """GET from /sensors/<id>/chart"""
  46. # Chart theme
  47. chart_theme = kwargs.pop("chart_theme", None)
  48. embed_options = chart_options.copy()
  49. if chart_theme:
  50. embed_options["theme"] = chart_theme
  51. embed_options["tooltip"]["theme"] = chart_theme
  52. # Chart specs
  53. chart_specs = SensorAPI().get_chart(id, include_data=True, **kwargs)
  54. return spec_to_html(
  55. json.loads(chart_specs),
  56. mode=embed_options["mode"],
  57. vega_version=current_app.config.get("FLEXMEASURES_JS_VERSIONS")["vega"],
  58. vegaembed_version=current_app.config.get("FLEXMEASURES_JS_VERSIONS")[
  59. "vegaembed"
  60. ],
  61. vegalite_version=current_app.config.get("FLEXMEASURES_JS_VERSIONS")[
  62. "vegalite"
  63. ],
  64. embed_options=embed_options,
  65. ).replace('<div id="vis"></div>', '<div id="vis" style="width: 100%;"></div>')
  66. @use_kwargs(StartEndTimeSchema, location="query")
  67. @login_required
  68. def get(self, id: int, **kwargs):
  69. """GET from /sensors/<id>
  70. The following query parameters are supported (should be used only together):
  71. - start_time: minimum time of the events to be shown
  72. - end_time: maximum time of the events to be shown
  73. """
  74. sensor = db.session.get(Sensor, id)
  75. if sensor is None:
  76. raise NotFound
  77. return render_flexmeasures_template(
  78. "sensors/index.html",
  79. sensor=sensor,
  80. user_can_update_sensor=user_can_update(sensor),
  81. user_can_delete_sensor=user_can_delete(sensor),
  82. msg="",
  83. breadcrumb_info=get_breadcrumb_info(sensor),
  84. event_starts_after=request.args.get("start_time"),
  85. event_ends_before=request.args.get("end_time"),
  86. )