"""Module to support the LmwSip class See: LmwSip""" import socket import ssl import select import time import re import logging class LmwSip: """Class to connect to the LMW Standard Interface prototcol (sip) This class iplement connection to the Rijkswaterstaat Meetnet Water (LMW) with the Standard Interface Protocol using the Rijkswaterstaat Meetnet Infrastructuur (RMI). https://waterberichtgeving.rws.nl/water-en-weer/metingen Support for: ti cmd(wn, vw, as) """ def __init__(self, user=None, password=None, host="sip-lmw.rws.nl", port=443, meetnet="LMW", ssl = True, check_ssl = True, timeout = 10, log = None): """LmwSip(user, password, [host], [port], [meetnet], [ssl], [check_ssl], [timeout], [log]) user(optinal): Lmw user name password(optional): Lmw password host(optional): Default sip-lmw.rws.nl port(optional): Default 443 meetnet(optional): Default LMW ssl(optional): Default true check_ssl(optional): true timeout(optional): 10 log(optional): None Opens the connection and logs in """ self.user = user self.password = password self.host = host self.port = port self.meetnet = meetnet self.ssl = ssl self.check_ssl = check_ssl self.timeout = timeout self._socket = None if (log != None): self.log = log self.log.debug("LmwSip.init") else: try: self.log = logging.getLogger("lmwsip") self.log.debug("LmwSip.init: Start log") except Exception as e: print("Logger failed: %s" % e) if (self.host != None): self.connect() if (self.user != None): self.login() def lasttime(self, parameter): # # Find the last valid 10 minute window. # The measurement of 12:00 is avaiable at 12:05:30. # Before 12:05:30 we should use 11:50:00. # # At 12:05:29 we substract 15:29 from the time! # # Also note that we use GMT. So we should add one hour # because we use GMT +1 (MET, UTC-1) # if (parameter.find("10") != -1): now=time.time() dt = now%600 if (dt < 330): now = 3000 + now - dt else: now = 3600 + now - dt else: # # e.g. H1 use 30 seconds to calculate the time. # dt = now%600 if (dt < 30): now = 3540 + now - dt else: now = 3600 + now - dt time_of_day=time.strftime("%H:%M", time.gmtime(now)) return { "day": time.strftime("%d-%m-%Y", time.gmtime(now)), "time_of_day": time.strftime("%H:%M", time.gmtime(now)) } def connect(self): """connect() connects to lmw with tcp using the values of the object creation. """ try: self._tcp = socket.create_connection((self.host, self.port)) except Exception as e: self.log.error("LmwSip.connect(%s, %s) failed: %s", self.host, self.port, e) raise LmwSipConnectError("LmwSip.connect: Socket create failed") if (self.ssl): try: self._context = ssl.create_default_context() self._context.check_hostname = self.check_ssl self._ssl = self._context.wrap_socket(self._tcp, server_hostname=self.host) self._socket = self._ssl except Exception as e: self.log.error("LmwSip.connect setup ssl failed:\n%s", e) raise LmwSipConnectError("LmwSip.connect: setup ssl failed") else: self._socket = self._tcp self._socket.settimeout(self.timeout) def closesocket(self): """Closes the socket and set the socket to None. Doesn't logout""" try: self.log.debug("LmwSip.closesocket") self._socket.close() except Exception as e: pass self._socket = None def send(self, sipcmd): """send(sipcmd) send a sip command to the server """ if self._socket != None: try: logcmd = sipcmd.strip('\r') if re.match("^LI", logcmd, re.IGNORECASE): logcmd = re.sub(",.*", ", ******", logcmd) self.log.debug("LmwSip.send(%s)" % logcmd) self._socket.sendall(sipcmd.encode('ascii')) except Exception as e: self.log.error("LmwSip.send(%s) failed: %s", sipcmd, e) self.closesocket() raise LmwSipConnectError("LmwSip.send: Socket connection lost") else: self.log.warn("LmwSip.send: No connection") def recv(self): """recv() recieve a answer from the sip server """ buf="" while self._socket != None and re.search("\r$", buf) == None: try: self.log.debug("LmwSip.recv: Waiting for data"); b = self._socket.recv(4096).decode('utf-8') if (b == ""): self.log.error("SipLmw.recv: socket closed") self.closesocket() raise LmwSipConnectError("LmwSip.recv: Socket close") else: buf += b except Exception as e: self.log.error("SipLmw.recv: socket timeout: %s", e) self.closesocket() raise LmwSipConnectError("LmwSip.recv: Socket timeout") if self._socket == None: self.log.warn("LmwSip.recv: No connection") elif buf[0] != '!': self.log.warn("LmwSip.recv: Sip error: %s" % buf.strip('\r')) else: self.log.debug("LmwSip.recv: result: %s" % buf.strip('\r')) return(buf) def login(self): """login() Login lmw using the object creation user, password. Raises a LmwLoginFailure exception on failure """ li="LI " + self.user + "," + self.password + "\r" self.send(li) d = self.recv() if (d[0] != '!'): raise LmwLoginFailure(self.user + ":" + d) def ti(self): """ti() Request the time from lmw and returns the string. Raises a LmwCmdWarn of failure """ ti="TI " + self.meetnet + "\r" self.send(ti) d = self.recv() return (d[2:-1]) def cmd(self, process, location, parameter, time_delta, day, time_of_day, cmd_type="DATA"): """cmd(process, location, parameter, time_delta, day, time_of_day) Send a cmd to LMW and returns the lmw string process: location: parameter: time_delta: