/
routes.py
221 lines (172 loc) · 7.76 KB
/
routes.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
import copy
from flask_security import auth_token_required
from flexmeasures.auth.decorators import account_roles_accepted
from flexmeasures.api.common.utils.api_utils import list_access, append_doc_of
from flexmeasures.api.common.utils.decorators import as_response_type
from flexmeasures.api.v1 import implementations as v1_implementations
from flexmeasures.api.v1_1 import implementations as v1_1_implementations
from flexmeasures.api.v1_2 import routes as v1_2_routes
from flexmeasures.api.v1_3 import (
flexmeasures_api as flexmeasures_api_v1_3,
implementations as v1_3_implementations,
)
# The service listing for this API version (import from previous version or update if needed)
v1_3_service_listing = copy.deepcopy(v1_2_routes.v1_2_service_listing)
v1_3_service_listing["version"] = "1.3"
@flexmeasures_api_v1_3.route("/getDeviceMessage", methods=["GET"])
@as_response_type("GetDeviceMessageResponse")
@auth_token_required
@account_roles_accepted(*list_access(v1_3_service_listing, "getDeviceMessage"))
def get_device_message():
"""API endpoint to get device message.
.. :quickref: Control; Download control signal from the platform
**Optional fields**
- "duration" (6 hours by default; can be increased to plan further into the future)
**Example request**
This "GetDeviceMessageRequest" message requests targeted consumption for UDI event 203 of device 10 of owner 7.
.. code-block:: json
{
"type": "GetDeviceMessageRequest",
"event": "ea1.2021-01.io.flexmeasures.company:fm0.7:10:203:soc"
}
**Example response**
This "GetDeviceMessageResponse" message indicates that the target for UDI event 203 is to consume at various power
rates from 10am UTC onwards for a duration of 45 minutes.
.. sourcecode:: json
{
"type": "GetDeviceMessageResponse",
"event": "ea1.2021-01.io.flexmeasures.company:fm0.7:10:203:soc",
"values": [
2.15,
3,
2
],
"start": "2015-06-02T10:00:00+00:00",
"duration": "PT45M",
"unit": "MW"
}
:reqheader Authorization: The authentication token
:reqheader Content-Type: application/json
:resheader Content-Type: application/json
:status 200: PROCESSED
:status 400: INVALID_MESSAGE_TYPE, INVALID_TIMEZONE, INVALID_DOMAIN, INVALID_UNIT, UNKNOWN_SCHEDULE, UNRECOGNIZED_CONNECTION_GROUP, or UNRECOGNIZED_UDI_EVENT
:status 401: UNAUTHORIZED
:status 403: INVALID_SENDER
:status 405: INVALID_METHOD
:status 422: UNPROCESSABLE_ENTITY
"""
return v1_3_implementations.get_device_message_response()
@flexmeasures_api_v1_3.route("/postUdiEvent", methods=["POST"])
@as_response_type("PostUdiEventResponse")
@auth_token_required
@account_roles_accepted(*list_access(v1_3_service_listing, "postUdiEvent"))
def post_udi_event():
"""API endpoint to post UDI event. (UDI is the Universal Device Interface proposed by USEF for flexible device states)
.. :quickref: Control; Upload flexibility constraints to the platform
**Example request A**
This "PostUdiEventRequest" message posts a state of charge (soc) of 12.1 kWh at 10.00am
as UDI event 203 of device 10 of owner 7.
.. code-block:: json
{
"type": "PostUdiEventRequest",
"event": "ea1.2021-01.io.flexmeasures.company:7:10:203:soc",
"value": 12.1,
"unit": "kWh",
"datetime": "2015-06-02T10:00:00+00:00"
}
**Example request B**
This "PostUdiEventRequest" message posts a state of charge (soc) of 12.1 kWh at 10.00am,
and a target state of charge of 25 kWh at 4.00pm,
as UDI event 204 of device 10 of owner 7.
The minimum and maximum soc are set to 10 and 25 kWh, respectively.
Roundtrip efficiency for use in scheduling is set to 98%.
.. code-block:: json
{
"type": "PostUdiEventRequest",
"event": "ea1.2021-01.io.flexmeasures.company:fm0.7:10:204:soc-with-targets",
"value": 12.1,
"unit": "kWh",
"datetime": "2015-06-02T10:00:00+00:00",
"targets": [
{
"value": 25,
"datetime": "2015-06-02T16:00:00+00:00"
}
],
"soc_min": 10,
"soc_max": 25,
"roundtrip_efficiency": 0.98
}
**Example response**
This "PostUdiEventResponse" message indicates that the UDI event has been processed without any error.
.. sourcecode:: json
{
"type": "PostUdiEventResponse",
"status": "PROCESSED",
"message": "Request has been processed."
}
:reqheader Authorization: The authentication token
:reqheader Content-Type: application/json
:resheader Content-Type: application/json
:status 200: PROCESSED
:status 400: INCOMPLETE_UDI_EVENT, INVALID_MESSAGE_TYPE, INVALID_TIMEZONE, INVALID_DATETIME, INVALID_DOMAIN,
INVALID_UNIT, OUTDATED_UDI_EVENT, PTUS_INCOMPLETE, OUTDATED_UDI_EVENT or UNRECOGNIZED_UDI_EVENT
:status 401: UNAUTHORIZED
:status 403: INVALID_SENDER
:status 405: INVALID_METHOD
"""
return v1_3_implementations.post_udi_event_response()
@flexmeasures_api_v1_3.route("/getConnection", methods=["GET"])
@as_response_type("GetConnectionResponse")
@auth_token_required
@account_roles_accepted(*list_access(v1_3_service_listing, "getConnection"))
@append_doc_of(v1_2_routes.get_connection)
def get_connection():
return v1_1_implementations.get_connection_response()
@flexmeasures_api_v1_3.route("/postPriceData", methods=["POST"])
@as_response_type("PostPriceDataResponse")
@auth_token_required
@account_roles_accepted(*list_access(v1_3_service_listing, "postPriceData"))
@append_doc_of(v1_2_routes.post_price_data)
def post_price_data():
return v1_1_implementations.post_price_data_response()
@flexmeasures_api_v1_3.route("/postWeatherData", methods=["POST"])
@as_response_type("PostWeatherDataResponse")
@auth_token_required
@account_roles_accepted(*list_access(v1_3_service_listing, "postWeatherData"))
@append_doc_of(v1_2_routes.post_weather_data)
def post_weather_data():
return v1_1_implementations.post_weather_data_response()
@flexmeasures_api_v1_3.route("/getPrognosis", methods=["GET"])
@as_response_type("GetPrognosisResponse")
@auth_token_required
@account_roles_accepted(*list_access(v1_3_service_listing, "getPrognosis"))
@append_doc_of(v1_2_routes.get_prognosis)
def get_prognosis():
return v1_1_implementations.get_prognosis_response()
@flexmeasures_api_v1_3.route("/getMeterData", methods=["GET"])
@as_response_type("GetMeterDataResponse")
@auth_token_required
@account_roles_accepted(*list_access(v1_3_service_listing, "getMeterData"))
@append_doc_of(v1_2_routes.get_meter_data)
def get_meter_data():
return v1_implementations.get_meter_data_response()
@flexmeasures_api_v1_3.route("/postMeterData", methods=["POST"])
@as_response_type("PostMeterDataResponse")
@auth_token_required
@account_roles_accepted(*list_access(v1_3_service_listing, "postMeterData"))
@append_doc_of(v1_2_routes.post_meter_data)
def post_meter_data():
return v1_implementations.post_meter_data_response()
@flexmeasures_api_v1_3.route("/postPrognosis", methods=["POST"])
@as_response_type("PostPrognosisResponse")
@auth_token_required
@account_roles_accepted(*list_access(v1_3_service_listing, "postPrognosis"))
@append_doc_of(v1_2_routes.post_prognosis)
def post_prognosis():
return v1_1_implementations.post_prognosis_response()
@flexmeasures_api_v1_3.route("/getService", methods=["GET"])
@as_response_type("GetServiceResponse")
@append_doc_of(v1_2_routes.get_service)
def get_service(service_listing=v1_3_service_listing):
return v1_implementations.get_service_response(service_listing)