]> jspc29.x-matter.uni-frankfurt.de Git - mvd_epics.git/commitdiff
EPICS -> MQTT Bridge added
authorPhilipp Klaus <klaus@physik.uni-frankfurt.de>
Tue, 30 May 2017 16:51:31 +0000 (18:51 +0200)
committerPhilipp Klaus <klaus@physik.uni-frankfurt.de>
Tue, 30 May 2017 16:51:31 +0000 (18:51 +0200)
epics_mqtt_bridge/epics_mqtt_bridge/__init__.py [new file with mode: 0644]
epics_mqtt_bridge/epics_mqtt_bridge/cli.py [new file with mode: 0644]
epics_mqtt_bridge/setup.py [new file with mode: 0644]

diff --git a/epics_mqtt_bridge/epics_mqtt_bridge/__init__.py b/epics_mqtt_bridge/epics_mqtt_bridge/__init__.py
new file mode 100644 (file)
index 0000000..fb06b89
--- /dev/null
@@ -0,0 +1,79 @@
+import epics
+import paho.mqtt.publish as publish
+
+import os
+import logging
+
+logger = logging.getLogger(__name__)
+
+class EPICS_MQTT_Bridge():
+    def __init__(self, config):
+        self.config = config
+
+        self.EPICS_CA_ADDR_LIST = config.get('EPICS', 'EPICS_CA_ADDR_LIST', fallback=None)
+        self.PYEPICS_LIBCA      = config.get('EPICS', 'PYEPICS_LIBCA',      fallback=None)
+        self.EPICS_BASE         = config.get('EPICS', 'EPICS_BASE',         fallback=None)
+        self.EPICS_HOST_ARCH    = config.get('EPICS', 'EPICS_HOST_ARCH',    fallback=None)
+
+        if self.EPICS_CA_ADDR_LIST: os.putenv('EPICS_CA_ADDR_LIST', self.EPICS_CA_ADDR_LIST)
+        if self.PYEPICS_LIBCA:      os.putenv('PYEPICS_LIBCA',      self.PYEPICS_LIBCA)
+        if self.EPICS_BASE:         os.putenv('EPICS_BASE',         self.EPICS_BASE)
+        if self.EPICS_HOST_ARCH:    os.putenv('EPICS_HOST_ARCH',    self.EPICS_HOST_ARCH)
+
+        self.MQTT_hostname = config.get('MQTT', 'Hostname')
+
+        self.DEBUG = False
+
+        logger.info("Using the following EPICS LIBCA: %s", epics.ca.find_libca())
+
+    def check_once(self):
+        msgs = []
+        for pvname in self.config['PVs']:
+            logger.info("Query the following PV: %s", pvname)
+            pv = epics.pv.get_pv(pvname)
+            char_val = pv.get(as_string=True, use_monitor=False)
+            logger.info("Current Value: %s = %s", pvname, char_val)
+            msgs.append({'topic': pvname.replace(':', '/'), 'payload': char_val})
+        publish.multiple(msgs, hostname=self.MQTT_hostname)
+
+    def epics_connection_callback(self, pvname, conn, **kwarg):
+        """
+        Callback function for PV changes
+        http://cars9.uchicago.edu/software/python/pyepics3/pv.html#pv-callbacks-label
+        """
+        publish.single(pvname+'.CONNECTED', int(conn), hostname=self.MQTT_hostname)
+
+    def epics_callback(self, pvname, value, char_value, precision, **kwarg):
+        """
+        Callback function for PV changes
+        http://cars9.uchicago.edu/software/python/pyepics3/pv.html#pv-callbacks-label
+        """
+        if precision:
+            out_val = ('{:.' + str(precision) + 'f}').format(value)
+        else:
+            out_val = char_value
+        logger.debug("PV Change: %s = %s", pvname, out_val)
+        publish.single(pvname, out_val, hostname=self.MQTT_hostname)
+
+    def monitor(self):
+        """
+        Start monitoring all PVs
+        Alternative implementation:
+        http://cars9.uchicago.edu/software/python/pyepics3/pv.html#example-of-connection-callback
+        """
+        for pvname in self.config['PVs']:
+            logger.info("Starting to monitor the following PV: %s", pvname)
+            pv = epics.pv.get_pv(pvname, form='native')
+            pv.connection_callbacks = [self.epics_connection_callback]
+            pv.get(use_monitor=False) # query once
+            pv.add_callback(callback=self.epics_callback, with_ctrlvars=True, run_now=True)
+
+    def monitor_clear(self):
+        """
+        Clear the monitor of all PVs.
+        """
+        for pvname in self.config['PVs']:
+            logger.info("Clear monitor of the following PV: %s", pvname)
+            pv = epics.get_pv(pvname, form='native')
+            pv.disconnect()
+
diff --git a/epics_mqtt_bridge/epics_mqtt_bridge/cli.py b/epics_mqtt_bridge/epics_mqtt_bridge/cli.py
new file mode 100644 (file)
index 0000000..939ec1c
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+from . import EPICS_MQTT_Bridge
+
+import argparse
+import configparser
+import sys
+import logging
+import time
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--configuration', '-c', help='configuration file')
+    parser.add_argument('--debug', action='store_true', help='enable debugging mode')
+    args = parser.parse_args()
+    if args.debug: logging.basicConfig(level='DEBUG')
+    config = configparser.ConfigParser(delimiters=('=',))
+    config.optionxform = lambda option: option
+    config.read(args.configuration)
+    if any(s not in config.sections() for s in ('MQTT', 'PVs', 'EPICS')):
+        sys.stderr.write("Not a suitable config file: Sections EPICS, MQTT, PVs required.\n")
+        sys.exit(2)
+    emb = EPICS_MQTT_Bridge(config)
+    #emb.check_once()
+    emb.monitor()
+    try:
+        while True:
+            time.sleep(0.1)
+    except KeyboardInterrupt:
+        emb.monitor_clear()
+
+if __name__ == "__main__": main()
diff --git a/epics_mqtt_bridge/setup.py b/epics_mqtt_bridge/setup.py
new file mode 100644 (file)
index 0000000..985c703
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+try:
+    from setuptools import setup
+except ImportError:
+    from distutils.core import setup
+
+setup(name='epics_mqtt_bridge',
+      version = '0.1.dev0',
+      description = 'Python package to bridge EPICS PVs to MQTT topics',
+      long_description = '',
+      author = 'Philipp Klaus',
+      author_email = 'klaus@physik.uni-frankfurt.de',
+      url = 'https://github.com/pklaus/epics_mqtt_bridge',
+      license = 'GPL',
+      packages = ['epics_mqtt_bridge',],
+      entry_points = {
+          'console_scripts': [
+              'epics_mqtt_bridge  = epics_mqtt_bridge.cli:main',
+          ],
+      },
+      include_package_data = False,
+      zip_safe = True,
+      platforms = 'any',
+      install_requires = [
+          "pyepics",
+          "paho-mqtt",
+      ],
+      keywords = 'EPICS MQTT Bridge',
+      classifiers = [
+          'Development Status :: 4 - Beta',
+          'Operating System :: OS Independent',
+          'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
+          'Programming Language :: Python',
+          'Programming Language :: Python :: 3',
+          'Topic :: Scientific/Engineering :: Visualization',
+          'Topic :: System :: Hardware :: Hardware Drivers',
+      ]
+)
+