/
sensors.py
156 lines (127 loc) · 5.06 KB
/
sensors.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import json
from flask_classful import FlaskView, route
from flask_json import as_json
from flask_security import auth_required
from timely_beliefs import BeliefsDataFrame
from webargs.flaskparser import use_args, use_kwargs
from flexmeasures.api.common.schemas.sensor_data import (
GetSensorDataSchema,
PostSensorDataSchema,
)
from flexmeasures.api.common.schemas.users import AccountIdField
from flexmeasures.api.common.utils.api_utils import save_and_enqueue
from flexmeasures.auth.decorators import permission_required_for_context
from flexmeasures.data.models.user import Account
from flexmeasures.data.schemas.sensors import SensorSchema
from flexmeasures.data.services.sensors import get_sensors
# Instantiate schemas outside of endpoint logic to minimize response time
get_sensor_schema = GetSensorDataSchema()
post_sensor_schema = PostSensorDataSchema()
sensors_schema = SensorSchema(many=True)
class SensorAPI(FlaskView):
route_base = "/sensors"
trailing_slash = False
decorators = [auth_required()]
@route("/", methods=["GET"])
@use_kwargs(
{
"account": AccountIdField(
data_key="account_id", load_default=AccountIdField.load_current
),
},
location="query",
)
@permission_required_for_context("read", arg_name="account")
@as_json
def index(self, account: Account):
"""API endpoint to list all sensors of an account.
.. :quickref: Sensor; Download sensor list
This endpoint returns all accessible sensors.
Accessible sensors are sensors in the same account as the current user.
Only admins can use this endpoint to fetch sensors from a different account (by using the `account_id` query parameter).
**Example response**
An example of one sensor being returned:
.. sourcecode:: json
[
{
"entity_address": "ea1.2021-01.io.flexmeasures.company:fm1.42",
"event_resolution": 15,
"generic_asset_id": 1,
"name": "Gas demand",
"timezone": "Europe/Amsterdam",
"unit": "m\u00b3/h"
}
]
:reqheader Authorization: The authentication token
:reqheader Content-Type: application/json
:resheader Content-Type: application/json
:status 200: PROCESSED
:status 400: INVALID_REQUEST
:status 401: UNAUTHORIZED
:status 403: INVALID_SENDER
:status 422: UNPROCESSABLE_ENTITY
"""
sensors = get_sensors(account_name=account.name)
return sensors_schema.dump(sensors), 200
@route("/data", methods=["POST"])
@use_args(
post_sensor_schema,
location="json",
)
def post_data(self, bdf: BeliefsDataFrame):
"""
Post sensor data to FlexMeasures.
.. :quickref: Data; Upload sensor data
**Example request**
.. code-block:: json
{
"sensor": "ea1.2021-01.io.flexmeasures:fm1.1",
"values": [-11.28, -11.28, -11.28, -11.28],
"start": "2021-06-07T00:00:00+02:00",
"duration": "PT1H",
"unit": "m³/h"
}
The above request posts four values for a duration of one hour, where the first
event start is at the given start time, and subsequent values start in 15 minute intervals throughout the one hour duration.
The sensor is the one with ID=1.
The unit has to be convertible to the sensor's unit.
The resolution of the data has to match the sensor's required resolution, but
FlexMeasures will attempt to upsample lower resolutions.
:reqheader Authorization: The authentication token
:reqheader Content-Type: application/json
:resheader Content-Type: application/json
:status 200: PROCESSED
:status 400: INVALID_REQUEST
:status 401: UNAUTHORIZED
:status 403: INVALID_SENDER
:status 422: UNPROCESSABLE_ENTITY
"""
response, code = save_and_enqueue(bdf)
return response, code
@route("/data", methods=["GET"])
@use_args(
get_sensor_schema,
location="query",
)
def get_data(self, response: dict):
"""Get sensor data from FlexMeasures.
.. :quickref: Data; Download sensor data
**Example request**
.. code-block:: json
{
"sensor": "ea1.2021-01.io.flexmeasures:fm1.1",
"start": "2021-06-07T00:00:00+02:00",
"duration": "PT1H",
"unit": "m³/h"
}
The unit has to be convertible from the sensor's unit.
:reqheader Authorization: The authentication token
:reqheader Content-Type: application/json
:resheader Content-Type: application/json
:status 200: PROCESSED
:status 400: INVALID_REQUEST
:status 401: UNAUTHORIZED
:status 403: INVALID_SENDER
:status 422: UNPROCESSABLE_ENTITY
"""
return json.dumps(response)