From 241f2843f230df3e7d8fe3b2d62fb77811632d41 Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Wed, 22 Jan 2025 15:05:51 +0100
Subject: [PATCH 01/12] add implementaion for measure endpoint

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 158 ++++++++++++++++++++++
 1 file changed, 158 insertions(+)
 create mode 100644 cron/scripts/ext_api_sync/uba_api_sync.py

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
new file mode 100644
index 00000000..c7bfd153
--- /dev/null
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -0,0 +1,158 @@
+#! /usr/bin/env python3
+
+import requests
+import os
+import logging
+import json
+import click
+
+
+api_base_url = os.environ.get("DB_API_BASE_URL")
+
+
+def get_components_and_scopes():
+    """Get components (i.e measured quantites) and scopes (aggregation infos) for later mapping"""
+    response_components = requests.get(
+        "https://www.umweltbundesamt.de/api/air_data/v3/components/json"
+    )
+    response_scopes = requests.get(
+        "https://www.umweltbundesamt.de/api/air_data/v3/scopes/json"
+    )
+    if response_components.status_code == 200 and response_scopes.status_code == 200:
+        components = {
+            int(v[0]): v[1]
+            for k, v in response_components.json().items()
+            if k not in ["count", "indices"]
+        }
+        scopes = {
+            int(v[0]): v[1]
+            for k, v in response_scopes.json().items()
+            if k not in ["count", "indices"]
+        }
+        return components, scopes
+
+
+def get_station_info(station_id: str) -> list:
+    """Get all available components and scope combinations of a given station"""
+    station_info = list()
+    response = requests.get(
+        "https://www.umweltbundesamt.de/api/air_data/v3/measures/limits"
+    )
+    if response.status_code == 200:
+        response_json = response.json()["data"]
+        for k, v in response_json.items():
+            if v[2] == station_id:
+                station_info.append({"scope": int(v[0]), "component": int(v[1])})
+        return station_info
+
+
+def request_uba_api(
+    station_id: str,
+    component_id: int,
+    scope_id: int,
+    date_from: str,
+    date_to: str,
+    time_from: int,
+    time_to: int,
+) -> dict:
+    """Request uba api measure endpoint for a given component and scope and a given time range"""
+    params = {
+        "date_from": date_from,
+        "date_to": date_to,
+        "time_from": time_from,
+        "time_to": time_to,
+        "station": station_id,
+        "component": component_id,
+        "scope": scope_id,
+    }
+    response = requests.get(
+        url="https://www.umweltbundesamt.de/api/air_data/v3/measures/json",
+        params=params,
+    )
+    if response.status_code == 200:
+        response_json = response.json()["data"][station_id]
+        if response_json:
+            return response_json
+
+
+def combine_uba_responses(
+    station_id: str,
+    date_from: str,
+    date_to: str,
+    time_from: int,
+    time_to: int,
+) -> list:
+    """Combine uba respones for all component/scope combinations into one object"""
+    uba_data = list()
+    station_info = get_station_info(station_id)
+    components, scopes = get_components_and_scopes()
+    for entry in station_info:
+        response = request_uba_api(
+            station_id,
+            entry["component"],
+            entry["scope"],
+            date_from,
+            date_to,
+            time_from,
+            time_to,
+        )
+        for k, v in response.items():
+            uba_data.append(
+                {
+                    "timestamp": v[3],
+                    "value": v[2],
+                    "parameter": f"{components[entry['component']]} {scopes[entry['scope']]}",
+                }
+            )
+    return uba_data
+
+
+def parse_uba_data(uba_data: list, station_id: str) -> dict:
+    """Creates POST body from combined uba data"""
+    bodies = []
+    source = {"uba_station_id": station_id}
+    for entry in uba_data:
+        if entry["timestamp"][11:13] == "24":
+            entry["timestamp"] = (
+                entry["timestamp"][:11] + "00" + entry["timestamp"][13:]
+            )
+        if entry["value"]:
+            body = {
+                "result_time": entry["timestamp"],
+                "result_type": 0,
+                "result_number": entry["value"],
+                "datastream_pos": entry["parameter"],
+                "parameters": json.dumps(
+                    {"origin": "uba_data", "column_header": source}
+                ),
+            }
+            bodies.append(body)
+    return {"observations": bodies}
+
+
+@click.command()
+@click.argument("thing_uuid")
+@click.argument("parameters")
+@click.argument("target_uri")
+def main(thing_uuid, parameters, target_uri):
+    logging.basicConfig(level=os.environ.get("LOG_LEVEL", "INFO").upper())
+
+    params = json.loads(parameters.replace("'", '"'))
+    uba_data = combine_uba_responses(params["station_id"])
+    parsed_observations = parse_uba_data(uba_data, params["station_id"])
+    req = requests.post(
+        f"{api_base_url}/observations/upsert/{thing_uuid}",
+        json=parsed_observations,
+        headers={"Content-type": "application/json"},
+    )
+    if req.status_code == 201:
+        logging.info(
+            f"Successfully inserted {len(parsed_observations['observations'])} "
+            f"observations for thing {thing_uuid} from UBA API into TimeIO DB"
+        )
+    else:
+        logging.error(f"{req.text}")
+
+
+if __name__ == "__main__":
+    main()
-- 
GitLab


From 0a19ca4a898284f6b53285a083aa20a8f88be44b Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Thu, 23 Jan 2025 13:53:12 +0100
Subject: [PATCH 02/12] add airquality data

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 96 +++++++++++++++++++----
 1 file changed, 82 insertions(+), 14 deletions(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index c7bfd153..8508df9e 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -46,7 +46,7 @@ def get_station_info(station_id: str) -> list:
         return station_info
 
 
-def request_uba_api(
+def request_measure_endpoint(
     station_id: str,
     component_id: int,
     scope_id: int,
@@ -75,19 +75,20 @@ def request_uba_api(
             return response_json
 
 
-def combine_uba_responses(
+def combine_measure_responses(
     station_id: str,
     date_from: str,
     date_to: str,
     time_from: int,
     time_to: int,
+    components: dict,
+    scopes: dict,
 ) -> list:
     """Combine uba respones for all component/scope combinations into one object"""
-    uba_data = list()
+    measure_data = list()
     station_info = get_station_info(station_id)
-    components, scopes = get_components_and_scopes()
     for entry in station_info:
-        response = request_uba_api(
+        response = request_measure_endpoint(
             station_id,
             entry["component"],
             entry["scope"],
@@ -97,21 +98,21 @@ def combine_uba_responses(
             time_to,
         )
         for k, v in response.items():
-            uba_data.append(
+            measure_data.append(
                 {
                     "timestamp": v[3],
                     "value": v[2],
-                    "parameter": f"{components[entry['component']]} {scopes[entry['scope']]}",
+                    "measure": f"{components[entry['component']]} {scopes[entry['scope']]}",
                 }
             )
-    return uba_data
+    return measure_data
 
 
-def parse_uba_data(uba_data: list, station_id: str) -> dict:
+def parse_measure_data(measure_data: list, station_id: str) -> list:
     """Creates POST body from combined uba data"""
     bodies = []
     source = {"uba_station_id": station_id}
-    for entry in uba_data:
+    for entry in measure_data:
         if entry["timestamp"][11:13] == "24":
             entry["timestamp"] = (
                 entry["timestamp"][:11] + "00" + entry["timestamp"][13:]
@@ -121,13 +122,72 @@ def parse_uba_data(uba_data: list, station_id: str) -> dict:
                 "result_time": entry["timestamp"],
                 "result_type": 0,
                 "result_number": entry["value"],
-                "datastream_pos": entry["parameter"],
+                "datastream_pos": entry["measure"],
                 "parameters": json.dumps(
                     {"origin": "uba_data", "column_header": source}
                 ),
             }
             bodies.append(body)
-    return {"observations": bodies}
+    return bodies
+
+
+def get_airquality_data(
+    station_id: str,
+    date_from: str,
+    date_to: str,
+    time_from: int,
+    time_to: int,
+    components: dict,
+) -> list:
+    params = {
+        "date_from": date_from,
+        "date_to": date_to,
+        "time_from": time_from,
+        "time_to": time_to,
+        "station": station_id,
+    }
+    response = requests.get(
+        "https://www.umweltbundesamt.de/api/air_data/v3/airquality/json", params=params
+    )
+    response_data = response.json()["data"][station_id]
+    aqi_data = list()
+    for k, v in response_data.items():
+        pollutant_info = list()
+        for i in range(3, len(v)):
+            entry = {"component": components[v[i][0]], "airquality_index": v[i][2]}
+            pollutant_info.append(entry)
+        aqi_data.append(
+            {
+                "timestamp": v[0],
+                "airquality_index": v[1],
+                "data_complete": v[2],
+                "pollutant_info": pollutant_info,
+            }
+        )
+    return aqi_data
+
+
+def parse_aqi_data(aqi_data: list, station_id: str) -> list:
+    bodies = []
+    for entry in aqi_data:
+        source = {
+            "uba_station_id": station_id,
+            "endpoint": "/airquality",
+            "pollutant_info": entry["pollutant_info"],
+        }
+        if entry["timestamp"][11:13] == "24":
+            entry["timestamp"] = (
+                entry["timestamp"][:11] + "00" + entry["timestamp"][13:]
+            )
+        body = {
+            "result_time": entry["timestamp"],
+            "result_type": 0,
+            "result_number": entry["airquality_index"],
+            "datastream_pos": "AQI",
+            "parameters": json.dumps({"origin": "uba_data", "column_header": source}),
+        }
+        bodies.append(body)
+    return bodies
 
 
 @click.command()
@@ -138,8 +198,16 @@ def main(thing_uuid, parameters, target_uri):
     logging.basicConfig(level=os.environ.get("LOG_LEVEL", "INFO").upper())
 
     params = json.loads(parameters.replace("'", '"'))
-    uba_data = combine_uba_responses(params["station_id"])
-    parsed_observations = parse_uba_data(uba_data, params["station_id"])
+    components, scopes = get_components_and_scopes()
+    measure_data = combine_measure_responses(
+        params["station_id"], date_from, date_to, time_from, time_to, components, scopes
+    )
+    aqi_data = get_airquality_data(
+        params["station_id"], date_from, date_to, time_from, time_to, components
+    )
+    parsed_measure_data = parse_measure_data(measure_data, params["station_id"])
+    parsed_aqi_data = parse_aqi_data(aqi_data, params["station_id"])
+    parsed_observations = {"observations": parsed_measure_data + parsed_aqi_data}
     req = requests.post(
         f"{api_base_url}/observations/upsert/{thing_uuid}",
         json=parsed_observations,
-- 
GitLab


From 5562998861e6f875fdd10d105325d9b7ca2e6c3e Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Mon, 27 Jan 2025 11:39:01 +0100
Subject: [PATCH 03/12] add datetime parameters and mapping to uba datetime
 logic

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 44 +++++++++++++++++++----
 1 file changed, 38 insertions(+), 6 deletions(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index 8508df9e..eb94a33b 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -6,10 +6,41 @@ import logging
 import json
 import click
 
+from datetime import datetime, timedelta
+
 
 api_base_url = os.environ.get("DB_API_BASE_URL")
 
 
+def adjust_datetime(datetime_str: str) -> str:
+    """UBA API returns datetime format with hours from 1 to 24 so it has to be parsed for timeIO DB API"""
+    date = datetime.strptime(datetime_str[0:10], "%Y-%m-%d")
+    date_adjusted = date + timedelta(days=1)
+
+    return date_adjusted.strftime("%Y-%m-%d %H:%M:%S")
+
+
+def get_timerange_parameters():
+    """UBA API expects time_from/time_to in the range of 1 to 24"""
+    datetime_now = datetime.now()
+    datetime_from = datetime_now - timedelta(hours=1)
+    if datetime_now.hour == 0:
+        time_to = 24
+        date_to = (datetime_now - timedelta(days=1)).strftime("%Y-%m-%d")
+    else:
+        time_to = datetime_now.hour
+        date_to = datetime_now.strftime("%Y-%m-%d")
+
+    if datetime_from.hour == 0:
+        time_from = 24
+        date_from = (datetime_from - timedelta(days=1)).strftime("%Y-%m-%d")
+    else:
+        time_from = datetime_from.hour
+        date_from = datetime_from.strftime("%Y-%m-%d")
+
+    return date_from, time_from, date_to, time_to
+
+
 def get_components_and_scopes():
     """Get components (i.e measured quantites) and scopes (aggregation infos) for later mapping"""
     response_components = requests.get(
@@ -70,9 +101,11 @@ def request_measure_endpoint(
         params=params,
     )
     if response.status_code == 200:
-        response_json = response.json()["data"][station_id]
-        if response_json:
-            return response_json
+        response_json = response.json()
+        if response_json["data"]:
+            return response_json["data"][station_id]
+        else:
+            return response_json["data"]
 
 
 def combine_measure_responses(
@@ -114,9 +147,7 @@ def parse_measure_data(measure_data: list, station_id: str) -> list:
     source = {"uba_station_id": station_id}
     for entry in measure_data:
         if entry["timestamp"][11:13] == "24":
-            entry["timestamp"] = (
-                entry["timestamp"][:11] + "00" + entry["timestamp"][13:]
-            )
+            entry["timestamp"] = adjust_datetime(entry["timestamp"])
         if entry["value"]:
             body = {
                 "result_time": entry["timestamp"],
@@ -198,6 +229,7 @@ def main(thing_uuid, parameters, target_uri):
     logging.basicConfig(level=os.environ.get("LOG_LEVEL", "INFO").upper())
 
     params = json.loads(parameters.replace("'", '"'))
+    date_from, time_from, date_to, time_to = get_timerange_parameters()
     components, scopes = get_components_and_scopes()
     measure_data = combine_measure_responses(
         params["station_id"], date_from, date_to, time_from, time_to, components, scopes
-- 
GitLab


From b01d46933af090eb52df1c39276fd1be0ea66739 Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Mon, 27 Jan 2025 11:49:27 +0100
Subject: [PATCH 04/12] extend source info

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index eb94a33b..410afd96 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -144,7 +144,10 @@ def combine_measure_responses(
 def parse_measure_data(measure_data: list, station_id: str) -> list:
     """Creates POST body from combined uba data"""
     bodies = []
-    source = {"uba_station_id": station_id}
+    source = {
+        "uba_station_id": station_id,
+        "endpoint": "/measures",
+    }
     for entry in measure_data:
         if entry["timestamp"][11:13] == "24":
             entry["timestamp"] = adjust_datetime(entry["timestamp"])
-- 
GitLab


From 2d9cbf7682764cfe020feaa16b5f67763090d60b Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Mon, 27 Jan 2025 14:36:42 +0100
Subject: [PATCH 05/12] add api doc links for uba and dwd

---
 cron/scripts/ext_api_sync/dwd_api_sync.py | 2 ++
 cron/scripts/ext_api_sync/uba_api_sync.py | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/cron/scripts/ext_api_sync/dwd_api_sync.py b/cron/scripts/ext_api_sync/dwd_api_sync.py
index 900084af..427d579b 100755
--- a/cron/scripts/ext_api_sync/dwd_api_sync.py
+++ b/cron/scripts/ext_api_sync/dwd_api_sync.py
@@ -1,5 +1,7 @@
 #! /usr/bin/env python3
 
+# DWD Brightsky API docs: https://brightsky.dev/docs/#/operations/getWeather
+
 import requests
 import os
 import logging
diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index 410afd96..aae108ac 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -1,5 +1,7 @@
 #! /usr/bin/env python3
 
+# UBA API docs: https://www.umweltbundesamt.de/daten/luft/luftdaten/doc
+
 import requests
 import os
 import logging
-- 
GitLab


From 3ae3b04402496448e66cc62c1547ca84bf679814 Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Mon, 27 Jan 2025 14:43:10 +0100
Subject: [PATCH 06/12] adjust datetime for airquality parsing

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 25 ++++++++++++-----------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index aae108ac..db7f8328 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -144,7 +144,7 @@ def combine_measure_responses(
 
 
 def parse_measure_data(measure_data: list, station_id: str) -> list:
-    """Creates POST body from combined uba data"""
+    """Creates POST body from combined uba measures data"""
     bodies = []
     source = {
         "uba_station_id": station_id,
@@ -175,6 +175,7 @@ def get_airquality_data(
     time_to: int,
     components: dict,
 ) -> list:
+    """Request uba api airquality endpoint for a given station_id and time range"""
     params = {
         "date_from": date_from,
         "date_to": date_to,
@@ -204,6 +205,7 @@ def get_airquality_data(
 
 
 def parse_aqi_data(aqi_data: list, station_id: str) -> list:
+    """Creates POST body from uba air quality data"""
     bodies = []
     for entry in aqi_data:
         source = {
@@ -212,17 +214,16 @@ def parse_aqi_data(aqi_data: list, station_id: str) -> list:
             "pollutant_info": entry["pollutant_info"],
         }
         if entry["timestamp"][11:13] == "24":
-            entry["timestamp"] = (
-                entry["timestamp"][:11] + "00" + entry["timestamp"][13:]
-            )
-        body = {
-            "result_time": entry["timestamp"],
-            "result_type": 0,
-            "result_number": entry["airquality_index"],
-            "datastream_pos": "AQI",
-            "parameters": json.dumps({"origin": "uba_data", "column_header": source}),
-        }
-        bodies.append(body)
+            entry["timestamp"] = adjust_datetime(entry["timestamp"])
+        if entry["airquality_index"]:
+            body = {
+                "result_time": entry["timestamp"],
+                "result_type": 0,
+                "result_number": entry["airquality_index"],
+                "datastream_pos": "AQI",
+                "parameters": json.dumps({"origin": "uba_data", "column_header": source}),
+            }
+            bodies.append(body)
     return bodies
 
 
-- 
GitLab


From e8e2c57ee5b296a2f738b0c5d1e02a8f726574ae Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Mon, 27 Jan 2025 14:43:54 +0100
Subject: [PATCH 07/12] black

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index db7f8328..fcbe3a45 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -221,7 +221,9 @@ def parse_aqi_data(aqi_data: list, station_id: str) -> list:
                 "result_type": 0,
                 "result_number": entry["airquality_index"],
                 "datastream_pos": "AQI",
-                "parameters": json.dumps({"origin": "uba_data", "column_header": source}),
+                "parameters": json.dumps(
+                    {"origin": "uba_data", "column_header": source}
+                ),
             }
             bodies.append(body)
     return bodies
-- 
GitLab


From 974e37515925c7121be64bf9705c968bbbcb868e Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Tue, 28 Jan 2025 14:28:31 +0100
Subject: [PATCH 08/12] add send_mqtt_info

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index fcbe3a45..55b40770 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -7,6 +7,7 @@ import os
 import logging
 import json
 import click
+import mqtt
 
 from datetime import datetime, timedelta
 
@@ -248,19 +249,21 @@ def main(thing_uuid, parameters, target_uri):
     parsed_measure_data = parse_measure_data(measure_data, params["station_id"])
     parsed_aqi_data = parse_aqi_data(aqi_data, params["station_id"])
     parsed_observations = {"observations": parsed_measure_data + parsed_aqi_data}
-    req = requests.post(
+    resp = requests.post(
         f"{api_base_url}/observations/upsert/{thing_uuid}",
         json=parsed_observations,
         headers={"Content-type": "application/json"},
     )
-    if req.status_code == 201:
-        logging.info(
-            f"Successfully inserted {len(parsed_observations['observations'])} "
-            f"observations for thing {thing_uuid} from UBA API into TimeIO DB"
-        )
-    else:
-        logging.error(f"{req.text}")
+    if resp.status_code != 201:
+        logging.error(f"{resp.text}")
+        resp.raise_for_status()
+        # exit
 
+    logging.info(
+        f"Successfully inserted {len(parsed_observations['observations'])} "
+        f"observations for thing {thing_uuid} from UBA API into TimeIO DB"
+    )
+    mqtt.send_mqtt_info("data_parsed", json.dumps({"thing_uuid": thing_uuid}))
 
 if __name__ == "__main__":
     main()
-- 
GitLab


From 74fac208061a542b550c323331a28758cf850617 Mon Sep 17 00:00:00 2001
From: Florian Gransee <florian.gransee@ufz.de>
Date: Tue, 28 Jan 2025 14:36:53 +0100
Subject: [PATCH 09/12] change list definition

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index 55b40770..9f89885b 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -121,7 +121,7 @@ def combine_measure_responses(
     scopes: dict,
 ) -> list:
     """Combine uba respones for all component/scope combinations into one object"""
-    measure_data = list()
+    measure_data = []
     station_info = get_station_info(station_id)
     for entry in station_info:
         response = request_measure_endpoint(
-- 
GitLab


From fd4ca2a629112e3953557310bd3af8dbab2164ef Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Tue, 28 Jan 2025 14:35:52 +0100
Subject: [PATCH 10/12] adjust docstrings

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index 9f89885b..293adbd2 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -16,7 +16,9 @@ api_base_url = os.environ.get("DB_API_BASE_URL")
 
 
 def adjust_datetime(datetime_str: str) -> str:
-    """UBA API returns datetime format with hours from 1 to 24 so it has to be parsed for timeIO DB API"""
+    """UBA API returns datetime format with hours from 1 to 24 so it
+    has to be parsed for timeIO DB API
+    """
     date = datetime.strptime(datetime_str[0:10], "%Y-%m-%d")
     date_adjusted = date + timedelta(days=1)
 
@@ -121,7 +123,7 @@ def combine_measure_responses(
     scopes: dict,
 ) -> list:
     """Combine uba respones for all component/scope combinations into one object"""
-    measure_data = []
+    measure_data = list()
     station_info = get_station_info(station_id)
     for entry in station_info:
         response = request_measure_endpoint(
-- 
GitLab


From 8a3bd539c83b0749c02fd03c0e110c2e72fc1030 Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Tue, 28 Jan 2025 14:40:31 +0100
Subject: [PATCH 11/12] adjust docstrings

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index 293adbd2..46443fc7 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -47,7 +47,9 @@ def get_timerange_parameters():
 
 
 def get_components_and_scopes():
-    """Get components (i.e measured quantites) and scopes (aggregation infos) for later mapping"""
+    """Get components (i.e measured quantites) and scopes
+    (aggregation infos) for later mapping
+    """
     response_components = requests.get(
         "https://www.umweltbundesamt.de/api/air_data/v3/components/json"
     )
@@ -69,7 +71,9 @@ def get_components_and_scopes():
 
 
 def get_station_info(station_id: str) -> list:
-    """Get all available components and scope combinations of a given station"""
+    """Get all available components and scope combinations of a given
+    station
+    """
     station_info = list()
     response = requests.get(
         "https://www.umweltbundesamt.de/api/air_data/v3/measures/limits"
@@ -91,7 +95,9 @@ def request_measure_endpoint(
     time_from: int,
     time_to: int,
 ) -> dict:
-    """Request uba api measure endpoint for a given component and scope and a given time range"""
+    """Request uba api measure endpoint for a given component and scope
+    and a given time range
+    """
     params = {
         "date_from": date_from,
         "date_to": date_to,
@@ -122,7 +128,9 @@ def combine_measure_responses(
     components: dict,
     scopes: dict,
 ) -> list:
-    """Combine uba respones for all component/scope combinations into one object"""
+    """Combine uba respones for all component/scope combinations into
+    one object
+    """
     measure_data = list()
     station_info = get_station_info(station_id)
     for entry in station_info:
@@ -178,7 +186,9 @@ def get_airquality_data(
     time_to: int,
     components: dict,
 ) -> list:
-    """Request uba api airquality endpoint for a given station_id and time range"""
+    """Request uba api airquality endpoint for a given station_id and
+    time range
+    """
     params = {
         "date_from": date_from,
         "date_to": date_to,
-- 
GitLab


From a770fa2e7a2334a5b4f1c92ac76edf91c8e27d0f Mon Sep 17 00:00:00 2001
From: granseef <florian.gransee@ufz.de>
Date: Tue, 28 Jan 2025 14:52:38 +0100
Subject: [PATCH 12/12] make use of raise_for_status

---
 cron/scripts/ext_api_sync/uba_api_sync.py | 50 ++++++++++++-----------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/cron/scripts/ext_api_sync/uba_api_sync.py b/cron/scripts/ext_api_sync/uba_api_sync.py
index 46443fc7..0934cb80 100644
--- a/cron/scripts/ext_api_sync/uba_api_sync.py
+++ b/cron/scripts/ext_api_sync/uba_api_sync.py
@@ -53,21 +53,22 @@ def get_components_and_scopes():
     response_components = requests.get(
         "https://www.umweltbundesamt.de/api/air_data/v3/components/json"
     )
+    response_components.raise_for_status()
     response_scopes = requests.get(
         "https://www.umweltbundesamt.de/api/air_data/v3/scopes/json"
     )
-    if response_components.status_code == 200 and response_scopes.status_code == 200:
-        components = {
-            int(v[0]): v[1]
-            for k, v in response_components.json().items()
-            if k not in ["count", "indices"]
-        }
-        scopes = {
-            int(v[0]): v[1]
-            for k, v in response_scopes.json().items()
-            if k not in ["count", "indices"]
-        }
-        return components, scopes
+    response_scopes.raise_for_status()
+    components = {
+        int(v[0]): v[1]
+        for k, v in response_components.json().items()
+        if k not in ["count", "indices"]
+    }
+    scopes = {
+        int(v[0]): v[1]
+        for k, v in response_scopes.json().items()
+        if k not in ["count", "indices"]
+    }
+    return components, scopes
 
 
 def get_station_info(station_id: str) -> list:
@@ -78,12 +79,12 @@ def get_station_info(station_id: str) -> list:
     response = requests.get(
         "https://www.umweltbundesamt.de/api/air_data/v3/measures/limits"
     )
-    if response.status_code == 200:
-        response_json = response.json()["data"]
-        for k, v in response_json.items():
-            if v[2] == station_id:
-                station_info.append({"scope": int(v[0]), "component": int(v[1])})
-        return station_info
+    response.raise_for_status()
+    response_json = response.json()["data"]
+    for k, v in response_json.items():
+        if v[2] == station_id:
+            station_info.append({"scope": int(v[0]), "component": int(v[1])})
+    return station_info
 
 
 def request_measure_endpoint(
@@ -111,12 +112,12 @@ def request_measure_endpoint(
         url="https://www.umweltbundesamt.de/api/air_data/v3/measures/json",
         params=params,
     )
-    if response.status_code == 200:
-        response_json = response.json()
-        if response_json["data"]:
-            return response_json["data"][station_id]
-        else:
-            return response_json["data"]
+    response.raise_for_status()
+    response_json = response.json()
+    if response_json["data"]:
+        return response_json["data"][station_id]
+    else:
+        return response_json["data"]
 
 
 def combine_measure_responses(
@@ -199,6 +200,7 @@ def get_airquality_data(
     response = requests.get(
         "https://www.umweltbundesamt.de/api/air_data/v3/airquality/json", params=params
     )
+    response.raise_for_status()
     response_data = response.json()["data"][station_id]
     aqi_data = list()
     for k, v in response_data.items():
-- 
GitLab