diff --git a/.gitignore b/.gitignore
index b3d698dd73e02f9b13fe28dc1f94a02d8b7218ec..9cbcb6fada295dbd9f98d5dd3053dbe7b118386d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@
 *.swo
 __pycache__
 *.pyc
-
+/venv/
+/.mypy_cache
+/.idea
diff --git a/plugins/collectd.py b/plugins/collectd.py
index 7a33ec33acd4bfdc69a6b01e57cdc5b0ef1f2bc7..18ae0d6ad6cf145be473a74135908fe55f218f09 100644
--- a/plugins/collectd.py
+++ b/plugins/collectd.py
@@ -1,13 +1,16 @@
 import asyncio
 import time
 
+
 def init(monitor):
     return PluginCollectd(monitor)
 
+
 class PluginCollectd:
     """
     Implements a super simple collectd interface for only sending temperature data
     """
+
     def __init__(self, monitor):
         self.loop = asyncio.get_event_loop()
         self.config = monitor.config
@@ -48,7 +51,7 @@ class PluginCollectd:
             interval,
             timestamp,
             value)
-        #print("Sending data:", data.strip())
+        # print("Sending data:", data.strip())
         self._writer.write(data.encode('utf-8'))
         await self._writer.drain()
 
@@ -63,7 +66,7 @@ class PluginCollectd:
             await self.reconnect()
         else:
             pass
-            #print("recv:", line)
+            # print("recv:", line)
 
     async def send_sensor_values(self, sensor):
         """
diff --git a/plugins/mail.py b/plugins/mail.py
index 1416fef6551d55373659ed843b1fc9ac5cef5618..68bf81a36a8c0afc4358d8e60547c4e13014d733 100644
--- a/plugins/mail.py
+++ b/plugins/mail.py
@@ -71,6 +71,22 @@ I will try to fix this issue by reconnecting...
 Regards, Temperature
 """
 
+SENSOR_TEMPERATURE_WARNING_SUBJECT = "Temperaturwarnung Serverraum"
+SENSOR_TEMPERATURE_WARNING_BODY = """Hi Guys,
+
+Die Temperaturen im Serverraum werden langsam Bedenklich:
+
+{temperatures}
+
+Auslöser: {reason}
+
+Aktuelle Temperaturen:
+{alltemperatures}
+
+Bitte haltet die Temperaturen im Auge und fahrt eventuell heiß laufende Server herunter
+
+with love,
+Temperator"""
 
 
 def init(monitor):
@@ -79,10 +95,12 @@ def init(monitor):
     """
     return PluginMail(monitor)
 
+
 class PluginMail:
     """
     Handle all the mail sending stuff
     """
+
     def __init__(self, monitor):
         self.monitor = monitor
         self.config = self.monitor.config
@@ -115,7 +133,7 @@ class PluginMail:
 
         self._mail_rate_limit[subject] = time.time()
         smtp = smtplib.SMTP("mail.stusta.mhn.de")
-        #smtp.sendmail(msg['From'], recipients, msg.as_string())
+        # smtp.sendmail(msg['From'], recipients, msg.as_string())
         smtp.quit()
 
     async def err_nodata(self, **kwargs):
@@ -143,26 +161,7 @@ class PluginMail:
             SENSOR_MEASUREMENT_MISSED_SUBJECT,
             SENSOR_MEASUREMENT_MISSED_BODY.format(**kwargs))
 
-
     async def temperature_warning(self, source, urgent=False, **kwargs):
-        subject = "Temperaturwarnung Serverraum"
-
-        body = """Hi Guys,
-
-Die Temperaturen im Serverraum werden langsam Bedenklich:
-
-{temperatures}
-
-Auslöser: {reason}
-
-Aktuelle Temperaturen:
-{alltemperatures}
-
-Bitte haltet die Temperaturen im Auge und fahrt eventuell heiß laufende Server herunter
-
-with love,
-Temperator"""
-
         if source == "tempdiff":
             temperatures = "{name1}:{temp1}\n{name2}:{temp2}".format(**kwargs)
             reason = "Differenztemperatur: {tempdiff}".format(**kwargs)
@@ -173,8 +172,13 @@ Temperator"""
         alltemperatures = '\n'.join([
             "{}: {}".format(sensor.name, sensor.temperature) if sensor.valid
             else "{}: INVALID".format(sensor.name)
-            for sensor in self.monitor.sensors.values() ])
+            for sensor in self.monitor.sensors.values()])
 
-        await self.send_mail(subject, body.format(
-            temperatures=temperatures, reason=reason, alltemperatures=alltemperatures),
-            urgent=urgent)
+        await self.send_mail(
+            SENSOR_TEMPERATURE_WARNING_SUBJECT,
+            SENSOR_TEMPERATURE_WARNING_BODY.format(
+                temperatures=temperatures,
+                reason=reason,
+                alltemperatures=alltemperatures),
+            urgent=urgent
+        )
diff --git a/plugins/prometheus.py b/plugins/prometheus.py
new file mode 100644
index 0000000000000000000000000000000000000000..4812187440c1c6f3adba62c5de160dee433ca18a
--- /dev/null
+++ b/plugins/prometheus.py
@@ -0,0 +1,54 @@
+import asyncio
+
+from prometheus_client import start_http_server, Gauge
+
+
+def init(monitor):
+    return PluginPrometheus(monitor)
+
+
+class PluginPrometheus:
+    def __init__(self, monitor):
+        self.loop = asyncio.get_event_loop()
+        self.config = monitor.config
+        self.last_store = 0
+        self.monitor = monitor
+
+        self.sensor_metrics = Gauge(
+            name=self.config["prometheus"]["sensor_metric_name"],
+            documentation="Container Temperature Measurements",
+            labelnames=["sensor"]
+        )
+
+        self.aggregated_metrics = Gauge(
+            name=self.config["prometheus"]["aggregated_metric_name"],
+            documentation="Container Temperature Aggregations",
+            labelnames=["group", "type"]
+        )
+
+        start_http_server(
+            addr=self.config["prometheus"].get('address', 'localhost'),
+            port=self.config["prometheus"]["port"]
+        )
+
+    async def update_sensor_values(self, sensor):
+        """
+        update
+        """
+        self.sensor_metrics.labels(sensor=sensor.name).set(sensor.temperature)
+
+    async def send_stats_graph(self, graph, stattype, stattime, statval):
+        """
+        to be called as a plugin callback to export aggregated measurements
+        """
+        label_group = stattype.split("-")[1]
+        label_type = stattype.split("-")[2]
+        self.aggregated_metrics.labels(group=label_group, type=label_type).set(statval)
+
+    async def sensor_update(self):
+        """
+        Receive sensor data to store them regularely into collectd
+        """
+        for sensor in self.monitor.sensors.values():
+            if sensor.valid:
+                await self.update_sensor_values(sensor)
diff --git a/plugins/warnings.py b/plugins/warnings.py
index 372a898a34fb4b23736eef071a10f0e39f070c72..591912bfaf96b70e9e5e34f6fdc7cbeb8dfc9be6 100644
--- a/plugins/warnings.py
+++ b/plugins/warnings.py
@@ -1,19 +1,22 @@
 import time
 
+
 def init(monitor):
     """ Plugin interface method """
     return PluginWarning(monitor)
 
+
 class PluginWarning:
     """
     Generate all kind of warnings whenever needed and observe the sensor
     if they see a problematic situation in the container
     """
+
     def __init__(self, monitor):
         self.monitor = monitor
 
         self.revmapping = {
-            sensor.name : sensor
+            sensor.name: sensor
             for sensor in self.monitor.sensors.values()
         }
 
@@ -44,7 +47,7 @@ class PluginWarning:
             return [], 0, 0, 0, 0
 
         avg = sum(sensor.temperature for sensor in sensors) / len(sensors)
-        var = sum((sensor.temperature - avg)**2 for sensor in sensors) / len(sensors)
+        var = sum((sensor.temperature - avg) ** 2 for sensor in sensors) / len(sensors)
 
         sensormin = +9999
         sensormax = -9999
@@ -56,7 +59,6 @@ class PluginWarning:
 
         return sensors, sensormin, sensormax, avg, var
 
-
     async def sensor_update(self):
         """
         First generate stats and relay them to the collectd module, then use these stats
@@ -74,30 +76,30 @@ class PluginWarning:
         if floor_sensors:
             await self.monitor.call_plugin(
                 "send_stats_graph", graph="stats",
-                stattype="temperature-floormin", stattime=now, statval=floor_min)
+                stattype="temperature-floor-min", stattime=now, statval=floor_min)
             await self.monitor.call_plugin(
                 "send_stats_graph", graph="stats",
-                stattype="temperature-floormax", stattime=now, statval=floor_max)
+                stattype="temperature-floor-max", stattime=now, statval=floor_max)
             await self.monitor.call_plugin(
                 "send_stats_graph", graph="stats",
-                stattype="temperature-flooravg", stattime=now, statval=floor_avg)
+                stattype="temperature-floor-avg", stattime=now, statval=floor_avg)
             await self.monitor.call_plugin(
                 "send_stats_graph", graph="stats",
-                stattype="temperature-floorvar", stattime=now, statval=floor_var)
+                stattype="temperature-floor-var", stattime=now, statval=floor_var)
 
         if ceil_sensors:
             await self.monitor.call_plugin(
                 "send_stats_graph", graph="stats",
-                stattype="temperature-ceilmin", stattime=now, statval=ceil_min)
+                stattype="temperature-ceil-min", stattime=now, statval=ceil_min)
             await self.monitor.call_plugin(
                 "send_stats_graph", graph="stats",
-                stattype="temperature-ceilmax", stattime=now, statval=ceil_max)
+                stattype="temperature-ceil-max", stattime=now, statval=ceil_max)
             await self.monitor.call_plugin(
                 "send_stats_graph", graph="stats",
-                stattype="temperature-ceilavg", stattime=now, statval=ceil_avg)
+                stattype="temperature-ceil-avg", stattime=now, statval=ceil_avg)
             await self.monitor.call_plugin(
                 "send_stats_graph", graph="stats",
-                stattype="temperature-ceilvar", stattime=now, statval=ceil_var)
+                stattype="temperature-ceil-var", stattime=now, statval=ceil_var)
 
         if floor_sensors and ceil_sensors:
             # Else we already have sent warning messages for broken sensors
@@ -112,7 +114,6 @@ class PluginWarning:
             print("ceil:  min {:05.2f} max {:05.2f} avg {:05.2f} var {:05.2f}".format(
                 ceil_min, ceil_max, ceil_avg, ceil_var))
 
-
             # Here comes the warning magic
 
             # Critical: ceiling temperature > threshold (sane default: 45)
@@ -132,7 +133,7 @@ class PluginWarning:
 
             # Warning: temperature difference > threshold (sane default: 17)
             if ceil_max > int(self.warning_conf['min_ceiling_warning']):
-                if  tempdiff > int(self.warning_conf['floor_ceiling_diff']):
+                if tempdiff > int(self.warning_conf['floor_ceiling_diff']):
                     await self.monitor.call_plugin("temperature_warning",
                                                    source="tempdiff",
                                                    name1="floor",
@@ -140,4 +141,3 @@ class PluginWarning:
                                                    temp1=floor_avg,
                                                    temp2=ceil_avg,
                                                    tempdiff=tempdiff)
-
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0ece5484f3e0dbee5d7a71d403f1fbb806aa6a39
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+prometheus-client==0.7.1
+pyserial==3.4
+pyserial-asyncio==0.4
\ No newline at end of file
diff --git a/tempermon.ini b/tempermon.ini
index 6e98a68c14c949cc041419f2e394c7526fcc923b..a86cfdf573b5a456f07bc9f58187a542208dd585 100644
--- a/tempermon.ini
+++ b/tempermon.ini
@@ -1,3 +1,6 @@
+[general]
+plugins = prometheus,mail,warnings
+
 [serial]
 #port=/dev/ttyUSB0
 port=/tmp/temperature_pts
@@ -10,6 +13,11 @@ socketpath=/tmp/collectd_sock
 hostname=hugin
 interval=1
 
+[prometheus]
+sensor_metric_name=ssn_container_temperature
+aggregated_metric_name=ssn_container_temperature_agg
+port=9199
+
 [mail]
 from=Temperman <root@temperator.stusta.de>
 to=jw@stusta.de,markus.hefele@stusta.de
@@ -24,7 +32,6 @@ min_ceiling_warning=35
 floor_ceiling_diff=15
 ceiling_warning_level=40
 
-
 [testsensor]
 name=Test
 calibration=5
diff --git a/tempermonitor.py b/tempermonitor.py
index 3c26e86dcb789770f33da4fd26b7b7283394307e..f4e51f7c58e45d6ebbf466d4183f0ddc73d68fc6 100755
--- a/tempermonitor.py
+++ b/tempermonitor.py
@@ -9,6 +9,7 @@ under the terms as stated in the LICENSE.md file.
 Changelog:
 
 2018-08 jotweh: reimplemented using a micropython-esp32
+2020-04 milo: added prometheus plugin
 
 Open issues:
 
@@ -26,25 +27,28 @@ from pathlib import Path
 import serial_asyncio
 import serial
 
+
 class Sensor:
     """
-    One instance as sensor posing as measurementproxy
+    One instance as sensor posing as measurement proxy
     """
+
     def __init__(self, config, owid):
         self.temperature = None
         self.last_update = 0
         self.calibration = 0
         self.valid = True
 
-        try:
-            if owid in config:
-                self.name = config[owid]['name']
-                self.calibration = config[owid]['calibration']
-            else:
-                print("Invalid Config: missing section {}".format(owid))
-        except KeyError as exc:
-            print("Invalid Config: for {}: {}".format(owid, exc))
-            raise
+        if owid not in config:
+            print(f"Invalid Config: missing section {owid}")
+            return
+
+        if 'name' not in config[owid] and 'calibration' not in config[owid]:
+            print(f"Invalid Config for: {owid}")
+            raise RuntimeError(f"Invalid Config for: {owid}")
+
+        self.name = config[owid]['name']
+        self.calibration = config[owid]['calibration']
 
     def update(self, temperature):
         """
@@ -53,6 +57,7 @@ class Sensor:
         self.temperature = float(temperature)
         self.last_update = time.time()
 
+
 class TempMonitor:
     """
     Interact with the esp-one-wire interface that sends:
@@ -131,7 +136,7 @@ class TempMonitor:
             # Wait for the next line
 
             if time.time() - last_valid_data_received > 1800:
-                self.call_plugin("err_no_valid_data", last_line=line)
+                await self.call_plugin("err_no_valid_data", last_line=line)
 
             try:
                 line = await asyncio.wait_for(
@@ -149,8 +154,7 @@ class TempMonitor:
                 line = line.decode('ascii').strip()
             except UnicodeError:
                 continue
-            #print("recv:", line)
-
+            # print("recv:", line)
 
             if line == '':
                 # Block has ended
@@ -237,6 +241,7 @@ def setup_plugin(filename, plugin):
     if not getattr(plugin, "name", None):
         plugin.name = filename
 
+
 def main():
     """
     Start the tempmonitor
@@ -252,8 +257,11 @@ def main():
 
     plugin_path = Path(__file__).resolve().parent / "plugins"
     print("Loading plugins from {}".format(plugin_path))
+    active_plugins = monitor.config["general"]["plugins"].split(",")
+    print(f"Active plugins: {active_plugins}")
+
     for filename in plugin_path.glob("*.py"):
-        if (plugin_path / filename).exists():
+        if (plugin_path / filename).exists() and filename.name in active_plugins:
             print("loading {}".format(filename.name))
             modname = "plugins." + filename.name.split('.')[0]
             module = importlib.import_module(modname)
@@ -269,5 +277,6 @@ def main():
     finally:
         loop.run_until_complete(monitor.teardown())
 
+
 if __name__ == "__main__":
     main()