Skip to content

Commit 8b661c3

Browse files
Create MISO grid alert parser (#8173)
* Update US_MISO.py * delete target_datetime and sourceType * include date_time in parser parameters * Update US_MISO.py
1 parent 3b508f4 commit 8b661c3

File tree

2 files changed

+70
-5
lines changed

2 files changed

+70
-5
lines changed

config/zones/US-MIDW-MISO.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,7 @@ parsers:
932932
production: EIA.fetch_production_mix
933933
productionCapacity: EIA.fetch_production_capacity
934934
productionPerModeForecast: US_MISO.fetch_wind_solar_forecasts
935+
gridAlerts: US_MISO.fetch_grid_alerts
935936
region: Americas
936937
sources:
937938
INCER ACV:

parsers/US_MISO.py

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@
1414

1515
from electricitymap.contrib.config import ZoneKey
1616
from electricitymap.contrib.lib.models.event_lists import (
17+
GridAlertList,
1718
ProductionBreakdownList,
1819
TotalConsumptionList,
1920
)
20-
from electricitymap.contrib.lib.models.events import EventSourceType, ProductionMix
21+
from electricitymap.contrib.lib.models.events import (
22+
EventSourceType,
23+
GridAlertType,
24+
ProductionMix,
25+
)
2126

2227
SOURCE = "misoenergy.org"
2328
ZONE = "US-MIDW-MISO"
@@ -217,11 +222,70 @@ def fetch_wind_solar_forecasts(
217222
return production_breakdowns.to_list()
218223

219224

225+
def fetch_grid_alerts(
226+
zone_key: ZoneKey = ZoneKey(ZONE),
227+
session: Session | None = None,
228+
target_datetime: datetime | None = None,
229+
logger: Logger = getLogger(__name__),
230+
) -> list[dict[str, Any]]:
231+
"""Fetch Grid Alerts from MISO"""
232+
session = session or Session()
233+
234+
# API URL
235+
url = "https://www.misoenergy.org/api/topicnotifications/getrecentnotifications"
236+
237+
# Request payload (can be adjusted if you want specific filters)
238+
payload = {"topics": ["RealTime"], "take": 0} # take 0 is equal to get all possible
239+
# TODO: do we just need the last one?
240+
241+
# Request headers
242+
headers = {
243+
"Content-Type": "application/json",
244+
"Accept": "application/json",
245+
"User-Agent": "Mozilla/5.0",
246+
"Referer": "https://www.misoenergy.org/markets-and-operations/notifications/real-time-operations-notifications/",
247+
"X-Requested-With": "XMLHttpRequest",
248+
}
249+
250+
# Make the POST request
251+
response = session.post(url, json=payload, headers=headers)
252+
253+
# Check for success
254+
if response.status_code == 200:
255+
notifications = response.json()
256+
257+
# TODO: maybe extract locationRegion from each notification?
258+
# TODO: maybe extract startTime and endTime from each notification?
259+
# TODO: maybe extract alertType from each notification?
260+
261+
# Record events in grid_alert_list
262+
grid_alert_list = GridAlertList(logger)
263+
for notification in notifications:
264+
publish_datetime = datetime.fromisoformat(
265+
notification["publishDateUnformatted"]
266+
) # in UTC
267+
grid_alert_list.append(
268+
zoneKey=zone_key,
269+
locationRegion=None,
270+
source=SOURCE,
271+
alertType=GridAlertType.undefined,
272+
message=notification["subject"] + "\n" + notification["body"],
273+
issuedTime=publish_datetime,
274+
startTime=None, # if None, it defaults to issuedTime
275+
endTime=None,
276+
)
277+
return grid_alert_list.to_list()
278+
279+
220280
if __name__ == "__main__":
221-
# print("fetch_production() ->")
222-
# print(fetch_production())
281+
from pprint import pprint
282+
283+
print("fetch_production() ->")
284+
print(fetch_production())
223285

224286
print(fetch_consumption_forecast())
225287

226-
# print("fetch_wind_solar_forecasts() ->")
227-
# print(fetch_wind_solar_forecasts())
288+
print("fetch_wind_solar_forecasts() ->")
289+
print(fetch_wind_solar_forecasts())
290+
291+
pprint(fetch_grid_alerts())

0 commit comments

Comments
 (0)