Environmental data
Load the daily readings of a national meteorological service into DHIS2, under the org units of its stations.
This page concludes the One Health series. The DHIS2 Climate app imports global datasets on its own, and what is left are national sources - the stations of a meteorological service, or the sampling sites of environmental surveillance. The service below reads yesterday's readings of every station once a day and posts them to a daily data set in public health, under the org unit each station is in.
The source
The examples use a REST outgoing connection named Met Service, pointing to an API that returns one observation per station and day:
{
"observations": [
{
"station": "ST-0412",
"rainfall_mm": 18.6,
"temperature_max": 31.4,
"temperature_min": null
},
{
"station": "ST-0415",
"rainfall_mm": 0.0,
"temperature_max": 33.1,
"temperature_min": 21.7
}
]
}
stations.ini is a config table with the org unit of each station, and environment.ini has the data element each measurement is recorded under:
# config/user-conf/environment.ini
[elements]
rainfall_mm = Rk2vT8nWq4L
temperature_max = Hs6bX1cMp9D
temperature_min = Zf4jA7yEu3K
Build the data values
Each measurement a station reported becomes one data value, as a string. A measurement the station did not report is null in the response and is left out:
# -*- coding: utf-8 -*-
# stdlib
from datetime import date, timedelta
# Zato
from zato.server.service import Service
class LoadEnvironment(Service):
name = 'dhis2.one-health.load-environment'
def build_values(self, reading:'dict', org_unit:'str', period:'str') -> 'list':
elements = self.config.environment.elements
out = []
for name, data_element in elements.items():
measured = reading[name]
if measured is None:
continue
value = str(measured)
data_value = {
'dataElement': data_element,
'period': period,
'orgUnit': org_unit,
'value': value,
}
out.append(data_value)
return out
Post the day
The period of a daily data set is the date written as YYYYMMDD:
def handle(self) -> 'None':
stations = self.config.stations
today = date.today()
yesterday = today - timedelta(days=1)
period = yesterday.strftime('%Y%m%d')
day = yesterday.isoformat()
params = {'date': day}
conn = self.rest['Met Service']
response = conn.get(params=params)
observations = response.data['observations']
data_values = []
for reading in observations:
# A station no org unit is mapped to is logged and left out ..
station = reading['station']
org_unit = stations.translate(source='MET_SERVICE', code=station)
if org_unit is None:
self.logger.warning('No org unit for station %s', station)
continue
# .. and every other one adds its measurements.
values = self.build_values(reading, org_unit, period)
data_values.extend(values)
payload = {'dataValues': data_values}
conn = self.rest['Public Health Data Values']
conn.post(payload)
A station added to the network is a line in stations.ini, and a measurement added to the API is a line in environment.ini and a data element in the data set.
The schedule
The service runs from a daily scheduler job, timed after the source has published the previous day's readings:

See also
| Feature | What it does |
|---|---|
| Calling REST APIs | Query parameters and response objects |
| Config tables | Translate the codes of one party into another's |