snap7_server.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. from psutil import cpu_times
  2. import snap7
  3. import logging
  4. import struct
  5. import re
  6. from datetime import datetime, tzinfo
  7. from inputs.common import Input
  8. localtz = datetime.now().astimezone().tzinfo
  9. class SiemensServer(Input):
  10. interval = 0.02
  11. time_offset = None
  12. def __init__(self):
  13. super().__init__(self.read_handler)
  14. self.server = snap7.server.Server(True)
  15. size = 100
  16. self.DB1 = (snap7.types.wordlen_to_ctypes[snap7.types.WordLen.Byte.value] * size)()
  17. self.DB2 = (snap7.types.wordlen_to_ctypes[snap7.types.WordLen.Byte.value] * size)()
  18. self.server.register_area(snap7.types.srvAreaDB, 1, self.DB1)
  19. self.server.register_area(snap7.types.srvAreaDB, 2, self.DB2)
  20. self.server.start(102)
  21. def read_handler(self):
  22. event : snap7.types.SrvEvent
  23. while event := self.server.pick_event():
  24. text = self.server.event_text(event)
  25. match = re.match("^(?P<datetime>\d+-\d+-\d+ \d+:\d+:\d+) \[(?P<host>[\w\.:]+)\] (?P<type>[\w ]+), Area : (?P<area>.+), Start : (?P<start>\d+), Size : (?P<size>\d+) --> (?P<response>.+)$", text)
  26. if not match:
  27. logging.warn(text)
  28. continue
  29. if match.group("type") != "Write request":
  30. logging.warn(text)
  31. continue
  32. if int(match.group("start")) + int(match.group("size")) <= 4:
  33. continue
  34. if match.group("area") == "DB1":
  35. raw = bytearray(self.DB1)
  36. timestamp = self.get_timestamp(raw[0:4])
  37. self.queue_ifm_from_bytes("S7", timestamp, raw[4:34])
  38. elif match.group("area") == "DB2":
  39. raw = bytearray(self.DB2)
  40. timestamp = self.get_timestamp(raw[0:4])
  41. self.queue_energy_meter_from_bytes("S7", timestamp, raw[4:40])
  42. def get_timestamp(self, raw):
  43. now = datetime.now(localtz)
  44. cpu_time = struct.unpack(">I", raw)[0] / 1000
  45. offset = now.timestamp() - cpu_time
  46. if self.time_offset:
  47. self.time_offset = self.time_offset * 0.999 + offset * 0.001
  48. else:
  49. self.time_offset = offset
  50. timestamp = datetime.fromtimestamp(self.time_offset + cpu_time, localtz)
  51. return timestamp