Skip to content

Services

The core of wetterdienst is to provide data but as we don't collect the data ourselves we rely on consuming data of already existing services - mostly governmental services. To simplify the implementation of weather services we created data models, enumerations and classes that should be used in order to adapt whatever API is offered by a service to the general scheme of wetterdienst with some handful of attributes to define each API and streamline internal workflows. The following paragraphs describe how we can/may/should implement a new weather service in wetterdienst as far as our own experience goes. We'll give examples based on the DwdObservationRequest implementation.

Step 1: Metadata

The basis for the implementation of a new service is the extensive metadata model. The metadata model is a layered abstraction of inheritance looking roughly like resolutions -> datasets -> parameters which means that the uppermost layer is the resolution, which contains one or more datasets, which in turn contain one or more parameters. The following example reflects this structure for the MINUTE_1 dataset PRECIPITATION of DwdObservationRequest.

DwdObservationMetadata = {
    "resolutions": [
        {
            "name": "1_minute",
            "name_original": "1_minute",
            "periods": ["historical", "recent", "now"],
            "date_required": False,
            "datasets": [
                {
                    "name": "precipitation",
                    "name_original": "precipitation",
                    "grouped": True,
                    "parameters": [
                        {
                            "name": "quality",
                            "name_original": "qn",
                            "unit_type": "dimensionless",
                            "unit": "dimensionless",
                        },
                        {
                            "name": "precipitation_height",
                            "name_original": "rs_01",
                            "unit_type": "precipitation",
                            "unit": "millimeter",
                        },
                        {
                            "name": "precipitation_height_droplet",
                            "name_original": "rth_01",
                            "unit_type": "precipitation",
                            "unit": "millimeter",
                        },
                        {
                            "name": "precipitation_height_rocker",
                            "name_original": "rwh_01",
                            "unit_type": "precipitation",
                            "unit": "millimeter",
                        },
                        {
                            "name": "precipitation_index",
                            "name_original": "rs_ind_01",
                            "unit_type": "dimensionless",
                            "unit": "dimensionless",
                        },
                    ],
                }
            ],
        }
    ]
}

The attributes periods and date_required are actually required for each dataset but if they are equal for all datasets of a resolution they can be defined on the resolution level instead saving you some lines of code. The grouped attribute is used to define if data is provided eather as one for the whole dataset or for each parameter separately. If grouped is True the data is provided as one for the whole dataset, if False the data is provided for each parameter separately. If grouped is True the collect_station_parameter_or_dataset method expects parameter_or_dataset to be of DatasetModel type, if False it expects ParameterModel type.

Given the metadata model above you can request either the whole dataset or a specific parameter of the dataset.

Requesting the whole dataset:

from wetterdienst.provider.dwd.observation import DwdObservationRequest, DwdObservationMetadata

DwdObservationRequest(
    parameters=[DwdObservationMetadata.minute_1.precipitation]
)

or equally

from wetterdienst.provider.dwd.observation import DwdObservationRequest

DwdObservationRequest(
    parameters=[("minute_1", "precipitation")]
)

Requesting a specific parameter of the dataset:

from wetterdienst.provider.dwd.observation import DwdObservationRequest, DwdObservationMetadata

DwdObservationRequest(
    parameters=[DwdObservationMetadata.minute_1.precipitation.precipitation_height]
)

or equally

from wetterdienst.provider.dwd.observation import DwdObservationRequest

DwdObservationRequest(
    parameters=[("minute_1", "precipitation", "precipitation_height")]
)

Step 2: Request class

The request class represents a request and carries all the required attributes as well as the values class that is responsible for acquiring the data later on. The implementation is based on TimeseriesRequest from wetterdienst.core.

Attributes:

@property
@abstractmethod
def provider(self) -> Provider:
    """Optional enumeration for multiple resolutions"""
    pass

@property
@abstractmethod
def kind(self) -> Kind:
    """Optional enumeration for multiple resolutions"""
    pass

@property
@abstractmethod
def _values(self):
    """Class to get the values for a request"""
    pass


@property
@abstractmethod
def metadata(self):
    """Metadata for the request"""
    pass

TimeseriesRequest has one abstract method that has to be implemented: the _all which manages to get a listing of stations for the requested datasets/parameters. The listing includes:

  • station_id
  • start_date
  • end_date
  • height
  • name
  • state
  • latitude
  • longitude

Step 3: Values class

The values class is based on TimeseriesValues and manages the acquisition of actual data. The class is also part of the TimeseriesRequest being accessed via the _values property. It has to implement the _collect_station_parameter method that takes care of getting values of a parameter/dataset for a station id.