openmeter package

Submodules

openmeter.client module

class openmeter.client.OpenMeterClient(personal_access_token: str)[source]

Bases: object

Api class to handle get, post and patch requests of openmeter api, base_url is set to v1 version right now, for more info see https://api.openmeter.de/v1/docs.

Args:
access_token (str):

access_token of the client

Example 1:

One could use the demo token or a personal access token generated from https://appstore.logarithmo.de/app/openmeterplatform/v1/demo/page-interface Please note that demo token has limitations and is only for quick testing

>>> om_client = OpenMeterClient(personal_access_token=your_personal_access_token)
>>> demo_client = OpenMeterClient(personal_access_token="969AC556-9185-48B2-97D2-D72341911067")

For all the examples here after, om_client and demo_client will be used interchangebly.
property api_key

property to get the api key of the client.

Returns:
api_key (str):

The api key of the client.

api_status()[source]

method to get the current status of https://api.openmeter.de/v1/docs

Returns:
api_status (str):

Returns OK if the api is live, otherwise ERROR.

get_all_sensors_from_same_location(sensor_id: str = None, location_id: str = None)[source]

Example method to retrives similar sensors based on a query sensor_id or location_id, only one of the two parameters can be provided.

Args:
sensor_id:

sensor id of an existing sensor

location_id:

location id of an existing sensor

Returns:

pandas.DataFrame: The meta data of filtered sensors.

get_meta_data(sensor_id: str = None, private_id: str = None, location_id: str = None, energy_type: str = None, measurement_category: str = None, measurement_type: str = None, measurement_unit: str = None, measurement_value_type: str = None, measurement_frequency: str = None, country: str = None, federal_state: str = None, city: str = None, post_code: str = None, category: str = None, usage: str = None, usage_detail: str = None, page: int = None)[source]

Retrieve the meta data of sensors based on conditional filters, for detailed instructions visit https://api.openmeter.de/v1/docs#/Meta%20Data/read_meta_data_meta_data_get

Args:
sensor_id (str):

The sensor ID.

private_id (str):

The private ID.

location_id (str):

The location ID.

energy_type (str):

The energy type.

measurement_category (str):

The measurement category.

measurement_type (str):

The measurement type.

measurement_unit (str):

The measurement unit.

measurement_value_type (str):

The measurement value type.

measurement_frequency (str):

The measurement frequency.

country (str):

The country.

federal_state (str):

The federal state.

city (str):

The city.

post_code (str):

The postal code.

category (str):

The category.

usage (str):

The usage.

usage_detail (str):

The usage detail.

page (int):

The page number.

Returns:

pandas.DataFrame: The meta data of filtered sensors.

Example 1:

In the following example we retrieve the meta data of a single sensor using the sensor id directly and print measurement_type, unit and frequency.

>>> sensor_id = "78347197-77dc-4861-ae1f-19f21a6ff510"
>>> meter_data = demo_client.get_meta_data(sensor_id=sensor_id)
>>> print(meter_data[["measurement_type", "measurement_unit", "measurement_frequency"]])
measurement_type measurement_unit measurement_frequency
0       Wirkarbeit              kWh                 15min

>>> print(meter_data.filter(like="location"))
                            location_id  ... location_latitude
0  4603629f-ac04-4f38-b3e2-54b98615db83  ...          51.19193
Example 2:

Filtering the sensors based on multiple conditions to do analysis on a group of sensors, as you can observe from the filtered_sensors dataframe info, metadata for most sensors is available, one could also build filters using a combination of sensor metadata and location attributes to make more meaningful analysis of sensors of interest

>>> filtered_sensors = demo_client.get_meta_data(energy_type="Strom", measurement_frequency="24h")
>>> print(filtered_sensors.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2252 entries, 0 to 2251
Data columns (total 30 columns):
#   Column                      Non-Null Count  Dtype
---  ------                      --------------  -----
0   id                          2252 non-null   object
1   created_at                  2252 non-null   object
2   updated_at                  2252 non-null   object
3   measures_from               2078 non-null   object
4   measures_to                 2078 non-null   object
5   measures_count              0 non-null      object
6   energy_type                 2252 non-null   object
7   measurement_category        2252 non-null   object
8   measurement_type            2252 non-null   object
9   measurement_unit            2252 non-null   object
10  measurement_value_type      2252 non-null   object
11  measurement_frequency       2252 non-null   object
12  notes                       118 non-null    object
13  private_id                  0 non-null      object
14  measurement_timezone        2252 non-null   object
15  location_id                 2252 non-null   object
16  location_created_at         2252 non-null   object
17  location_updated_at         2252 non-null   object
18  location_country            2252 non-null   object
19  location_federal_state      2252 non-null   object
20  location_city               2251 non-null   object
21  location_post_code          2250 non-null   float64
22  location_category           2252 non-null   object
23  location_usage              2232 non-null   object
24  location_usage_detail       564 non-null    object
25  location_area               2084 non-null   float64
26  location_construction_year  573 non-null    float64
27  location_private_id         0 non-null      object
28  location_longitude          2202 non-null   float64
29  location_latitude           2202 non-null   float64
dtypes: float64(5), object(25)
memory usage: 527.9+ KB
get_meta_data_distinct(attribute_name: str)[source]

method to read the unique values of the metadata attributes, for detailed instructions visit https://api.openmeter.de/v1/docs#/Meta%20Data/read_attributes_meta_data_distinct_values_get

Args:
attribute_name:

the name of the metadata field.

Returns:

list: a list of unique values of the metadata field.

Example 1:

Some attributes have restrictions on the possible values for an attribute to standardize the metadata, use this method for reading the current possible values

>>> measurement_types = om_client.get_meta_data_distinct(attribute_name="measurement_type")
>>> print(measurement_types)
['Blindleistung', 'Wassermenge', 'bereitgestellte Leistung', 'Wirkleistung', 'Blindarbeit', 'Wirkarbeit (Brennwert)', 'Brennstoffmenge', 'Wirkarbeit']
>>> measurement_units = om_client.get_meta_data_distinct(attribute_name="measurement_unit")
>>> print(measurement_units)
['kVArh', 'kWh', 'm³', 'kW', 'kWh(Hs)', 'kVAr', 'MWh']
get_timeseries(sensor_id: str, from_timestamp: Timestamp = None, to_timestamp: Timestamp = None)[source]

method to retrieve timeseries data for a given sensor, for detailed instructions please visit https://api.openmeter.de/v1/docs#/Timeseries/read_timeseries_timeseries_get

Args:
sensor_id:

id of an existing sensor

from_timestamp:

Optional, timestamp from which data is to retrieved

to_timestamp:

Optional, timestamp to which data is to retrieved

Returns:

pandas.DataFrame: a dataframe containing the timeseries data of the sensor.

Example 1:

To retrieve all the timeseries data of a particular sensor

>>> chosen_sensor_id = '78347197-77dc-4861-ae1f-19f21a6ff510'
>>> ts_data = om_client.get_timeseries(sensor_id=chosen_sensor_id)
>>> print(ts_data)
                    timestamps  values
0     2000-01-01 01:00:00+01:00    0.20
1     2000-01-01 02:00:00+01:00    0.20
2     2000-01-01 03:00:00+01:00    0.20
3     2000-01-01 04:00:00+01:00    0.20
4     2000-01-01 05:00:00+01:00    0.20
...                         ...     ...
23276 2023-12-10 23:00:00+01:00  108.55
23277 2023-12-10 23:15:00+01:00   27.15
23278 2023-12-10 23:30:00+01:00   27.10
23279 2023-12-10 23:45:00+01:00   27.15
23280 2023-12-11 00:00:00+01:00  108.75

[323291 rows x 2 columns]
Example 2:

To retrieve the timeseries data of a particular sensor between any two dates

>>> import pandas as pd
>>> from_ts = pd.Timestamp("2020-01-01 00:00:00")
>>> to_ts = pd.Timestamp("2023-12-31 23:59:59")

>>> chosen_sensor_id = '78347197-77dc-4861-ae1f-19f21a6ff510'
>>> ts_data = om_client.get_timeseries(sensor_id=chosen_sensor_id, from_timestamp=from_ts, to_timestamp=to_ts)
>>> print(ts_data)
                    timestamps  values
0    2020-01-01 01:00:00+01:00   28.70
1    2020-01-01 01:15:00+01:00   28.45
2    2020-01-01 01:30:00+01:00   28.30
3    2020-01-01 01:45:00+01:00   28.50
4    2020-01-01 02:00:00+01:00   28.35
...                        ...     ...
3038 2023-12-10 23:00:00+01:00  108.55
3039 2023-12-10 23:15:00+01:00   27.15
3040 2023-12-10 23:30:00+01:00   27.10
3041 2023-12-10 23:45:00+01:00   27.15
3042 2023-12-11 00:00:00+01:00  108.75

[123047 rows x 2 columns]
get_timeseries_weather(location_id: str, weather_type: str, from_timestamp: Timestamp = None, to_timestamp: Timestamp = None)[source]

method to retrieve weather data for a given location of a sensor, for detailed instructions please visit https://api.openmeter.de/v1/docs#/Weather/read_timeseries_weather_timeseries_weather_get

Args:
location_id:

location id of an existing sensor

weather_type:

weather type to retrieve

from_timestamp:

Optional, timestamp from which data is to retrieved

to_timestamp:

Optional, timestamp to which data is to retrieved

Returns:

pandas.DataFrame: a dataframe containing the chosen weather data closest to the sensor.

Example 1:

To retrieve all the available wind timeseries data of a particular location

>>> chosen_location_id = '4603629f-ac04-4f38-b3e2-54b98615db83'
>>> wind_data = om_client.get_timeseries_weather(location_id=chosen_location_id, weather_type="wind")
>>> print(wind_data)
                    timestamps  values
0      2016-01-30T01:00:00+01:00    11.0
1      2016-01-30T02:00:00+01:00    10.7
2      2016-01-30T03:00:00+01:00    10.9
3      2016-01-30T04:00:00+01:00    10.6
4      2016-01-30T05:00:00+01:00    10.6
...                          ...     ...
68721  2023-12-10T19:00:00+01:00     7.7
68722  2023-12-10T20:00:00+01:00     8.8
68723  2023-12-10T21:00:00+01:00     8.0
68724  2023-12-10T22:00:00+01:00    10.3
68725  2023-12-10T23:00:00+01:00     9.4

[68726 rows x 2 columns]
Example 2:

To retrieve all the available solar timeseries data of a particular location

>>> chosen_location_id = '4603629f-ac04-4f38-b3e2-54b98615db83'
>>> solar_data = om_client.get_timeseries_weather(location_id=chosen_location_id, weather_type="solar")
>>> print(solar_data)
                     timestamps  values
0     2023-09-01T02:00:00+02:00     0.0
1     2023-09-01T03:00:00+02:00     0.0
2     2023-09-01T04:00:00+02:00     0.0
3     2023-09-01T05:00:00+02:00     0.0
4     2023-09-01T06:00:00+02:00     0.0
...                         ...     ...
2179  2023-11-30T20:00:00+01:00     0.0
2180  2023-11-30T21:00:00+01:00     0.0
2181  2023-11-30T22:00:00+01:00     0.0
2182  2023-11-30T23:00:00+01:00     0.0
2183  2023-12-01T00:00:00+01:00     0.0

[2184 rows x 2 columns]
Example 3:

To retrieve all the available temperature timeseries data of a particular location

>>> chosen_location_id = '4603629f-ac04-4f38-b3e2-54b98615db83'
>>> temperature_data = om_client.get_timeseries_weather(location_id=chosen_location_id, weather_type="temperature")
>>> print(temperature_data)
                    timestamps  values
0       1999-12-31T23:00:00+01:00     4.3
1       2000-01-01T00:00:00+01:00     4.2
2       2000-01-01T01:00:00+01:00     4.3
3       2000-01-01T02:00:00+01:00     4.3
4       2000-01-01T03:00:00+01:00     4.5
...                           ...     ...
209802  2023-12-10T19:00:00+01:00     9.4
209803  2023-12-10T20:00:00+01:00     8.4
209804  2023-12-10T21:00:00+01:00     9.7
209805  2023-12-10T22:00:00+01:00    11.2
209806  2023-12-10T23:00:00+01:00    11.1

[209807 rows x 2 columns]
Example 4:

To retrieve the available weather timeseries data for a particular location between the dates of interest, the same logic applies to all weather_type attributes

>>> import pandas as pd
>>> from_ts = pd.Timestamp("2020-01-01 00:00:00")
>>> to_ts = pd.Timestamp("2023-12-31 23:59:59")

>>> chosen_location_id = '4603629f-ac04-4f38-b3e2-54b98615db83'
>>> temperature_data = om_client.get_timeseries_weather(location_id=chosen_location_id, weather_type="temperature", from_timestamp=from_ts, to_timestamp=to_ts)
>>> print(temperature_data)
                    timestamps  values
0      2020-01-01T00:00:00+01:00     1.7
1      2020-01-01T01:00:00+01:00     1.1
2      2020-01-01T02:00:00+01:00     1.1
3      2020-01-01T03:00:00+01:00     0.8
4      2020-01-01T04:00:00+01:00     0.0
...                          ...     ...
34724  2023-12-20T20:00:00+01:00     8.2
34725  2023-12-20T21:00:00+01:00     8.3
34726  2023-12-20T22:00:00+01:00     8.2
34727  2023-12-20T23:00:00+01:00     8.1
34728  2023-12-21T00:00:00+01:00     8.2

[34729 rows x 2 columns]
patch_meta_data(sensor_id: str, sensor_meta_data: dict)[source]

method to update metadata of an existing sensor, location data of a sensor can also be updated, for detailed instructions please visit https://api.openmeter.de/v1/docs#/Meta%20Data/update_meta_data_meta_data_patch

Args:
sensor_id:

id of an existing sensor.

sensor_meta_data:

the dictionary with the updated information fields.

Returns:

dict: containing information of update status of sensor.

Example 1:

Updating sensor and location information to correct errors is possible using the patch_metadata method it’s also flexible to just provide the information of the attributes you’d like to update which leaves the rest of the attributes as is in the database, in the following example, the changes are only being made in the attributes energy_type, measurement_type, measurement_unit, measurement_value_type and measurement_frequency

>>> patch_metadata = {
        "energy_type": "Wasser",
        "measurement_type": "Wassermenge",
        "measurement_unit": "kW",
        "measurement_value_type": "Differenzmengenwert",
        "measurement_frequency": "15min",
    }
>>> response_patch = om_client.patch_meta_data(sensor_id="c8abf795-39fc-4d3f-a05d-0ca6f590bc27", sensor_meta_data=patch_metadata)
>>> print(response_patch)
{'detail': 'Meta Data updates accepted for sensor id - c8abf795-39fc-4d3f-a05d-0ca6f590bc27'}
Example 2:

It’s also possible to update location information using the same method, here’s a case where the updates are being made to location object as well to change the federal_state and category of a location object

>>> patch_metadata = {
        "energy_type": "Wasser",
        "measurement_category": "Verbrauch",
        "measurement_type": "Wassermenge",
        "measurement_unit": "kW",
        "measurement_value_type": "Differenzmengenwert",
        "measurement_frequency": "15min",
        "location": {
            "federal_state": "Bayern",
            "category": "Privat",
        }
    }
>>> response_patch = om_client.patch_meta_data(sensor_id="c8abf795-39fc-4d3f-a05d-0ca6f590bc27", sensor_meta_data=patch_metadata)
>>> print(response_patch)
{'detail': 'Meta Data updates accepted for sensor id - c8abf795-39fc-4d3f-a05d-0ca6f590bc27'}

please note that patch method doesn’t return the metadata of the sensor but the status itself, you could use the get_meta_data method to validate the updates

post_meta_data(sensor_meta_data: dict, location_id: str = None)[source]

method to create a new sensor, provides the functionality to attach an existing location object to a new sensor being created, if no location_id is being provided, then the meta_data dictionary needs to contain location information, for detailed instructions visit https://api.openmeter.de/v1/docs#/Meta%20Data/write_meta_data_meta_data_post

Args:
sensor_meta_data:

the meta data information of a new sensor

location_id:

Optional, if provided, needs to be in the database.

Returns:

dict: a nested dictionary containing the sensor metadata along with the id of sensor and location(new/existing) information is returned.

Example 1:

For instance, if one is creating a new sensor and a new location, it’s necessary to provide the metadata of the sensor and also the location information together as follows, the returned response consists of the new sensor and location ids generated along with customer information, please save the sensor ids for retrieving the information later using get_meta_data method

>>> test_metadata = {
        "energy_type": "Strom",
        "measurement_category": "Verbrauch",
        "measurement_type": "Wirkarbeit (Brennwert)",
        "measurement_unit": "kWh(Hs)",
        "measurement_value_type": "Zaehlerstand",
        "measurement_frequency": "24h",
        "notes": "This sensor was newly installed in 2022",
        "private_id": "string",
        "measurement_timezone": "Europe_Berlin",
        "location": {
            "country": "Deutschland",
            "federal_state": "Baden-Wuerttemberg",
            "city": "string",
            "post_code": 0,
            "category": "Gewerblich",
            "usage": "string",
            "usage_detail": "string",
            "area": 230.5,
            "construction_year": 1970,
            "private_id": "string",
        }
    }
>>> response_post = om_client.post_meta_data(sensor_meta_data=test_metadata)
>>> print(response_post)
{'id': 'c8abf795-39fc-4d3f-a05d-0ca6f590bc27', 'created_at': '2023-12-21T13:06:38.578186+00:00', 'updated_at': '2023-12-21T13:06:38.578208+00:00',
'measures_from': None, 'measures_to': None, 'measures_count': None, 'energy_type': 'Strom', 'measurement_category': 'Verbrauch',
'measurement_type': 'Wirkarbeit (Brennwert)', 'measurement_unit': 'kWh(Hs)', 'measurement_value_type': 'Zaehlerstand',
'measurement_frequency': '24h', 'notes': 'This sensor was newly installed in 2022', 'private_id': 'string', 'measurement_timezone': 'Europe_Berlin',
'customer': {'name': 'Some User', 'email': 'newuseremail@gmail.com', 'role': 'USER'},
'location': {'id': '86ab8bd5-1776-4185-b0dd-73da667cc914', 'created_at': '2023-12-21T13:06:38.577427+00:00', 'updated_at': '2023-12-21T13:06:38.577522+00:00',
'country': 'Deutschland', 'federal_state': 'Baden-Wuerttemberg', 'city': 'string', 'post_code': 0, 'category': 'Gewerblich', 'usage': 'string',
'usage_detail': 'string', 'area': 230.5, 'construction_year': 1970, 'private_id': 'string', 'longitude': 0.0, 'latitude': 0.0}}
Example 2:

There may be cases where you already created a sensor with a location, and you would like to use the same location for other new sensors, to handle this scenario, one could use the location_id attribute directly instead of passing a nested location object in the metadata, here’s a simple example case where the location_id obtained from the previous post request is being used here to create another sensor

>>> test_metadata = {
        "energy_type": "Strom",
        "measurement_category": "Verbrauch",
        "measurement_type": "Wirkarbeit",
        "measurement_unit": "kWh",
        "measurement_value_type": "Differenzmengenwert",
        "measurement_frequency": "24h",
        "notes": "energy consumption",
        "private_id": "sensor_home_2022",
        "measurement_timezone": "Europe_Berlin",
    }
>>> response_post = om_client.post_meta_data(sensor_meta_data=test_metadata, location_id="86ab8bd5-1776-4185-b0dd-73da667cc914")

The response would be same as above with the existing location linked to the new sensor.
post_timeseries(sensor_id: str, timeseries_data: dict)[source]

method to add/update timeseries data of an existing sensor, for detailed instructions please visit https://api.openmeter.de/v1/docs#/Timeseries/write_timeseries_timeseries_post

Args:
sensor_id:

id of an existing sensor

timeseries_data:

dictionary object containing separate lists for timestamps and values.

Returns:

requests.Response: the response object of the post request informing the status of updates.

Example 1:

To add timeseries data of a sensor, the timestamps and values have to be of the same length as follows, also please note that to update the data as well, the same method can be used.

>>> sensor_id = "c8abf795-39fc-4d3f-a05d-0ca6f590bc27"
>>> data = {
        "timestamps": [
            "2022-01-01 15:00:00",
            "2022-01-01 15:15:00",
            "2022-01-01 15:30:00"
        ],
        "values": [
            18,
            20,
            22
        ]
    }
>>> post_ts_response = om_client.post_timeseries(sensor_id=sensor_id, timeseries_data=data)
>>> print(post_ts_response)
{'detail': 'Timeseries Data updates accepted for sensor id - c8abf795-39fc-4d3f-a05d-0ca6f590bc27'}

The easiest way to validate the updates is to use the get_timeseries method
test_request_status(result)[source]

generalized method to test the result status for exceptions.

Args:
result:

the response of the requests.get, requests.post….etc..

Returns:
result:

the response of the requests.get, requests.post….etc..

Module contents