Files
ddOperApi/ddapioper.py
2020-02-10 22:40:06 +01:00

289 lines
7.8 KiB
Python

"""Module to connect to the dd-api-oper
This module contains the following classes:
* ddApiOper: Main class to connect to the dd api oper interface
* ddApiResult: Super class for results
- ddApiLocation: Result class for locations
- ddApiQuantitie: Result class for quantities
- ddApiValues: Result class for values
* ddApiOperHttpError: Exception class for http errors
See:
https://digitaledeltaorg.github.io/dd-oper.v201.html
"""
import logging
import requests
from datetime import datetime, timedelta
class ddApiOper:
"""
Class that connects to the digitale delta api with a client certificate.
Methods for retrieving:
- The list of locations
- The list of quantitiess
- The quantities of a location
- Values for a given process, location and quantity
"""
RWS_DD_API = "https://ddapi.rws.nl/dd-oper/2.0"
def __init__(self, certfile=None, certkey=None, url=RWS_DD_API, checkssl=True):
"""ddApiOper(certfile, certKey, url="https://ddapi.rws.nl/dd-oper/2.0", checkssl=True)
certfile: x509 pki overheidscertificaat
certKey: Unencrypted private key
url(optional): dd Api url (default https://ddapi.rws.nl/dd-oper/2.0)
checkssl(optional): Check ssl keychain (default true)
Details for the certificate files see:
https://requests.readthedocs.io/en/master/user/advanced/#client-side-certificates
"""
self.certfile = certfile
self.certkey = certkey
self.url = url
self.checkssl = checkssl
logging.debug("ddApiOper.__init__(%s)" % url)
def get(self, url):
"""get(url)
Get the json data from the dd-api with pyton request.
Note: Internal use!
"""
logging.debug("ddApiOper.get(%s)" % url)
try:
req = requests.get(url, cert=(self.certfile, self.certkey))
except Exception as e:
logging.exception("ddApiOper.get error: %s" % e)
raise(e)
if (req.status_code != 200):
raise ddApiOperHttpError(req.status_code)
return(req.json())
def locations(self):
"""locations()
Request the list of locations and return a ddApiLocation object.
"""
return(ddApiLocation(self.get(self.url + "/locations")["results"]))
def quantities(self):
"""quantities()
Request the list of quantities and return a ddApiQuntitie object.
"""
return(ddApiQuantitie(self.get(self.url + "/quantities")["results"]))
def locationQuantities(self, location):
"""locationQuantities(location)
location: A dd-api location (e.g. hoekvanholland)
Request the list of quantities from a location and return
a ddApiQuntitie object.
"""
return(ddApiQuantitie(self.get(self.url + "/locations/%s/quantities" % location)["results"]))
def values(self, location, quantitie, process="measurement",
starttime=None, endtime=None,
intervalLength="10min", aspectset="minimum"):
"""values(location, quantitie, process="measurement",
starttime=None, endtime=None, intervalLength="10min", aspectset="minimum")
location: A dd-api location (e.g. hoekvanholland)
quantitie: A dd-api quantitie (e.g. waterlevel)
process(optional): Default measurement (forecast, astronomical, advise)
starttime(optional): Start of the time serie (Default 24 hours ago)
endtime(optional): End of the time serie (Default now)
intervalLength(optional): Interval between measurements (default 10 min)
aspectset(optional): Default minimum (normal, maximum)
"""
if not endtime:
endtime = datetime.utcnow()
if not starttime:
starttime = endtime - timedelta(days=1)
if type(starttime) == datetime:
starttime = starttime.isoformat() + "Z"
if type(endtime) == datetime:
endtime = endtime.isoformat() + "Z"
logging.debug("ddApiOper.values(%s, %s, %s, %s, %s, %s, %s)" % (
location, quantitie, process, starttime, endtime,
intervalLength, aspectset))
return(ddApiValues(self.get((
"%s"
"/locations/%s/quantities/%s"
"/timeseries?&startTime=%s&endTime=%s"
"&process=%s&intervalLength=%s&aspectSet=%s"
) %
(
self.url,
location, quantitie,
starttime, endtime,
process,
intervalLength, aspectset
))))
class ddApiResult(object):
"""
Class ddApiResult:
Base class for ddApiResults.
"""
def __init__(self, data):
"""ddApiResult(data)"""
self.data = data
class ddApiLocation(ddApiResult):
"""
Class ddApiLocation:
ddApi Result class for locations.
"""
def __init__(self, data):
super().__init__(data)
self.createIndex()
def createIndex(self):
"""createIndex()
Note: Internal function
"""
self.__index = {}
i = 0
for loc in self.data:
self.__index[loc["properties"]["locationName"]] = i
i+=1
def locationNames(self):
"""locationNames()
Returns a list of ddapi location names
"""
return(self.__index.keys())
def locationDetail(self, locationName):
"""locationDetail(locationName):
Returns the detais of a location from the list
"""
return(self.data[self.__index[locationName]])
def displayNameGlobal(self, locationName):
"""displayNameGlobal(locationName)
Returns the global display name of a location
"""
return(self.locationDetail(locationName)["properties"]["displayNameGlobal"])
def coordinate(self, locationName):
"""coordinate(locationName)
Returns the coordinates of a location
"""
return(self.locationDetail(locationName)["geometry"]["coordinates"])
class ddApiQuantitie(ddApiResult):
"""
Class ddApiQuantitie:
ddApi Result class for Quantities.
"""
def quantities(self):
"""quantities()
Returns a list of quantities
"""
return(self.data)
class ddApiValues(ddApiResult):
"""
Class ddApiValues:
ddApi Result class for values.
"""
def provider(self):
"""provider()
Returns the provider metadata.
"""
return(self.data["provider"])
def result(self, index=0):
"""result(index=0)
Returns the results part of the response.
"""
return(self.data["results"][index])
def aspectSet(self):
"""aspectSet()
Returns the metadata of the aspectSet
"""
return(self.result()["observationType"]["aspectSet"]["aspects"])
def location(self):
"""location()
Returns the location metadata
"""
return(self.result()["location"])
def source(self):
"""source()
Returns the source metadata
"""
return(self.result()["source"])
def values(self, index=0):
"""values(index=0)
Returns the values at ittorator of tupples.
(time, value)
(time, value)
Note:
Is this the correct return data format??
This may change!
"""
for e in self.result()["events"]:
yield (e["timeStamp"], e["aspects"][index]["points"][0]["value"])
def sip(self, index=0):
"""sip(index)
Returns the result set as string in the sip format!
"""
r = "!"
sep = " "
for e in self.result()["events"]:
v = e["aspects"][index]["points"][0]["value"]
q = e["aspects"][index]["points"][0]["quality"]
r += "%s%i/%i" % (sep, v, q)
sep = ";"
return(r)
class ddApiOperHttpError(Exception):
"""
Class ddApiOperHttpError
Exception class to use on http errors.
"""
def __init__(self, code):
self.code = code
if __name__ == "__main__":
pass