--- /dev/null
+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()
+
--- /dev/null
+#!/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()
--- /dev/null
+#!/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',
+ ]
+)
+