diff --git a/enocean/communicators/ESP2communicator.py b/enocean/communicators/ESP2communicator.py
new file mode 100644
index 0000000..67726b4
--- /dev/null
+++ b/enocean/communicators/ESP2communicator.py
@@ -0,0 +1,108 @@
+# -*- encoding: utf-8 -*-
+from __future__ import print_function, unicode_literals, division, absolute_import
+import logging
+
+import threading
+try:
+    import queue
+except ImportError:
+    import Queue as queue
+from enocean.protocol.packet import Packet
+from enocean.protocol.constants import PACKET, PARSE_RESULT, RETURN_CODE
+
+
+class ESP2Communicator(threading.Thread):
+    '''
+    Communicator base-class for EnOcean.
+    Not to be used directly, only serves as base class for SerialCommunicator etc.
+    '''
+    logger = logging.getLogger('enocean.communicators.ESP2Communicator')
+
+    def __init__(self, callback=None, teach_in=True):
+        super(ESP2Communicator, self).__init__()
+        # Create an event to stop the thread
+        self._stop_flag = threading.Event()
+        # Input buffer
+        self._buffer = []
+        # Setup packet queues
+        self.transmit = queue.Queue()
+        self.receive = queue.Queue()
+        # Set the callback method
+        self.__callback = callback
+        # Internal variable for the Base ID of the module.
+        self._base_id = None
+        # Should new messages be learned automatically? Defaults to True.
+        # TODO: Not sure if we should use CO_WR_LEARNMODE??
+        self.teach_in = teach_in
+
+    def _get_from_send_queue(self):
+        ''' Get message from send queue, if one exists '''
+        try:
+            packet = self.transmit.get(block=False)
+            #self.logger.info('Sending packet')
+            #self.logger.debug(packet)
+            return packet
+        except queue.Empty:
+            pass
+        return None
+
+    def send(self, packet):
+        if not isinstance(packet, Packet):
+            self.logger.error('Object to send must be an instance of Packet')
+            return False
+        self.transmit.put(packet)
+        return True
+
+    def stop(self):
+        self._stop_flag.set()
+
+    def parse(self):
+        ''' Parses messages and puts them to receive queue '''
+        # Loop while we get new messages
+        while True:
+            status, self._buffer, packet = Packet.parse_msg_ESP2(self._buffer, communicator=self)
+            # If message is incomplete -> break the loop
+            if status == PARSE_RESULT.INCOMPLETE:
+                return status
+
+            # If message is OK, add it to receive queue or send to the callback method
+            if status == PARSE_RESULT.OK and packet:
+                if self.__callback is None:
+                    self.receive.put(packet)
+                else:
+                    self.__callback(packet)
+                #self.logger.debug(packet)
+
+    @property
+    def base_id(self):
+        ''' Fetches Base ID from the transmitter, if required. Otherwise returns the currently set Base ID. '''
+        # If base id is already set, return it.
+        if self._base_id is not None:
+            return self._base_id
+
+        # Send COMMON_COMMAND 0x08, CO_RD_IDBASE request to the module
+        self.send(Packet(PACKET.COMMON_COMMAND, data=[0x08]))
+        # Loop over 10 times, to make sure we catch the response.
+        # Thanks to timeout, shouldn't take more than a second.
+        # Unfortunately, all other messages received during this time are ignored.
+        for i in range(0, 10):
+            try:
+                packet = self.receive.get(block=True, timeout=0.1)
+                # We're only interested in responses to the request in question.
+                if packet.packet_type == PACKET.RESPONSE and packet.response == RETURN_CODE.OK and len(packet.response_data) == 4:
+                    # Base ID is set in the response data.
+                    self._base_id = packet.response_data
+                    # Put packet back to the Queue, so the user can also react to it if required...
+                    self.receive.put(packet)
+                    break
+                # Put other packets back to the Queue.
+                self.receive.put(packet)
+            except queue.Empty:
+                continue
+        # Return the current Base ID (might be None).
+        return self._base_id
+
+    @base_id.setter
+    def base_id(self, base_id):
+        ''' Sets the Base ID manually, only for testing purposes. '''
+        self._base_id = base_id
diff --git a/enocean/communicators/ESP2serialcommunicator.py b/enocean/communicators/ESP2serialcommunicator.py
new file mode 100644
index 0000000..9b5e11b
--- /dev/null
+++ b/enocean/communicators/ESP2serialcommunicator.py
@@ -0,0 +1,43 @@
+# -*- encoding: utf-8 -*-
+from __future__ import print_function, unicode_literals, division, absolute_import
+import logging
+import serial
+import time
+
+from enocean.communicators.ESP2communicator import ESP2Communicator
+
+
+class ESP2SerialCommunicator(ESP2Communicator):
+    ''' Serial port communicator class for EnOcean radio '''
+    logger = logging.getLogger('enocean.communicators.ESP2SerialCommunicator')
+
+    def __init__(self, port='/dev/ttyS0', callback=None):
+        super(ESP2SerialCommunicator, self).__init__(callback)
+        # Initialize serial port
+        self.__ser = serial.Serial(port, 57600, timeout=0.1)
+
+    def run(self):
+        self.logger.info('SerialCommunicator started')
+        while not self._stop_flag.is_set():
+            # If there's messages in transmit queue
+            # send them
+            while True:
+                packet = self._get_from_send_queue()
+                if not packet:
+                    break
+                try:
+                    self.__ser.write(bytearray(packet.build_ESP2()))
+                except serial.SerialException:
+                    self.stop()
+
+            # Read chars from serial port as hex numbers
+            try:
+                self._buffer.extend(bytearray(self.__ser.read(16)))
+            except serial.SerialException:
+                self.logger.error('Serial port exception! (device disconnected or multiple access on port?)')
+                self.stop()
+            self.parse()
+            time.sleep(0)
+
+        self.__ser.close()
+        self.logger.info('SerialCommunicator stopped')
diff --git a/enocean/manufacturer/eltako.py b/enocean/manufacturer/eltako.py
new file mode 100644
index 0000000..cab2bca
--- /dev/null
+++ b/enocean/manufacturer/eltako.py
@@ -0,0 +1,555 @@
+# -*- encoding: utf-8 -*-
+from enum import Enum
+from enum import IntEnum
+from enocean.protocol.packet import RadioPacket
+from enocean.protocol.constants import MSGSTATUS, RORG
+import datetime
+
+
+class HCState(Enum):
+    Normal = 2
+    Absenkung = 1
+    Aus = 0
+    Frostschutz = -1
+
+
+class FSB14State(Enum):
+    open_ack = 2
+    down_ack = -2
+    run_up = 1
+    run_down = -1
+    stop = 0
+
+
+class FSB14Cmd(IntEnum):
+    up = 1
+    down = -1
+    stop = 0
+
+
+class RockerButton(IntEnum):
+    RightTop = 0x70
+    RightBottom = 0x50
+    LeftTop = 0x30
+    LeftBottom = 0x10
+    Off = 0x00
+
+
+class RockerEvent(IntEnum):
+    Press = 1
+    Longpress_2s = 2
+    Longpress_5s = 5
+
+
+def checkEqual(lst):
+   return lst[1:] == lst[:-1]
+
+class ButtonEvent():
+    def __init__(self, addr, time, button):
+        self.addr = addr
+        self.time = time
+        self.button = button
+
+
+class FTS14EM:
+    def __init__(self):
+        self.states = []
+
+    def new_event(self, packet):
+        timeNow = datetime.datetime.now()
+        if packet.sender[0:2] == [0x00, 0x00] and packet.sender[2] <= 0x19 and packet.sender[2] >= 0x10:
+            if packet.rorg == RORG.RPS:
+                if packet.data[1] != RockerButton.Off:
+                    self.states.insert(0, ButtonEvent(packet.sender_hex, timeNow, RockerButton(packet.data[1])))
+                    return None
+                else:
+                    for i, item in enumerate(self.states):
+                        if item.addr == packet.sender_hex:
+                            delta_s = (timeNow - item.time).seconds
+                            delta_us = (timeNow - item.time).microseconds
+                            delta = delta_s + delta_us/1000000.0
+                            if delta < 2:
+                                ev_type = RockerEvent.Press
+                            elif delta >= 2 and delta <= 5:
+                                ev_type = RockerEvent.Longpress_2s
+                            elif delta > 5:
+                                ev_type = RockerEvent.Longpress_5s
+                            else:
+                                ev_type = RockerEvent.Press
+                            msg_id = packet.sender_hex
+                            self.states.pop(i)
+                            return msg_id, ev_type
+                        else:
+                            #might be the case on start when a button has just been pressed
+                            return None
+
+
+class FTR65HS:
+    def __init__(self, ID, Name):
+        self.state = HCState.Normal
+        self.NRValue = 0
+        self.SetPoint = [0.0, 0.0, 0.0, 0.0, 0.0]
+        self.Temp = [0.0, 0.0, 0.0, 0.0, 0.0]
+        self.ID = ID
+        self.Name = Name
+
+    def decode(self, packet):
+        if packet.rorg == RORG.BS4:
+            if packet.data[1] == 0x00:
+                self.NRValue = 0
+                self.state = HCState.Normal
+            elif packet.data[1] == 0x19:
+                self.NRValue = -4
+                self.state = HCState.Absenkung
+            elif packet.data[1] == 0x0C:
+                self.NRValue = -2
+                self.state = HCState.Absenkung
+            elif packet.data[1] == 0x06:
+                self.NRValue = -1
+                self.state = HCState.Absenkung
+            else:
+                self.NRValue = 0
+
+            #update data point lists
+            self.SetPoint.insert(0, packet.data[2]*(40.0 / 255))
+            self.Temp.insert(0, (0xFF - packet.data[3])*(40.0 / 255))
+            self.SetPoint.pop()
+            self.Temp.pop()
+
+            # check if is actually turned of...
+            if self.state is not HCState.Absenkung:
+                if self.SetPoint[0] != self.Temp[0]:
+                    self.state = HCState.Normal
+                else:
+                    if (self.SetPoint[1] == self.Temp[1] and self.SetPoint[2] != self.SetPoint[1]) or \
+                       (self.SetPoint == self.Temp): # and not checkEqual(self.Temp)
+                        # last two messages setpoint and temp were equal and setpoint actually changed
+                        self.state = HCState.Aus
+
+            #print('%s, Status: %s ' % (self.Name, self.state.value))
+            #print('%s, Sollwert: %.2f °C' % (self.Name, self.SetPoint[0]))
+            #print('%s, Istwert: %.2f °C' % (self.Name, self.Temp[0]))
+            return [self.Temp[0], self.SetPoint[0], self.state.value]
+
+
+class FAE14:
+    def __init__(self, ID, Name, sID):
+        self.state = HCState.Normal
+        self.NRValue = 0
+        self.SetPoint = [0.0, 0.0, 0.0, 0.0, 0.0]
+        self.Temp = [0.0, 0.0, 0.0, 0.0, 0.0]
+        self.ID = ID
+        self.Name = Name
+        self.sID = sID
+
+    def decode(self, packet):
+        if packet.rorg == RORG.BS4:
+            if packet.data[1] == 0x00:
+                self.NRValue = 0
+                self.state = HCState.Normal
+            elif packet.data[1] == 0x19:
+                self.NRValue = -4
+                self.state = HCState.Absenkung
+            elif packet.data[1] == 0x0C:
+                self.NRValue = -2
+                self.state = HCState.Absenkung
+            elif packet.data[1] == 0x06:
+                self.NRValue = -1
+                self.state = HCState.Absenkung
+            else:
+                self.NRValue = 0
+
+            #update data point lists
+            self.SetPoint.insert(0, packet.data[2]*(40.0 / 255))
+            self.Temp.insert(0, (0xFF - packet.data[3])*(40.0 / 255))
+            self.SetPoint.pop()
+            self.Temp.pop()
+
+            # check if is actually turned of...
+            if self.state is not HCState.Absenkung:
+                if self.SetPoint[0] != self.Temp[0]:
+                    self.state = HCState.Normal
+                else:
+                    if (self.SetPoint[1] == self.Temp[1] and self.SetPoint[2] != self.SetPoint[1]) or \
+                       (self.SetPoint == self.Temp): # and not checkEqual(self.Temp)
+                        # last two messages setpoint and temp were equal and setpoint actually changed
+                        self.state = HCState.Aus
+
+            #print('%s, Status: %s ' % (self.Name, self.state.value))
+            #print('%s, Sollwert: %.2f °C' % (self.Name, self.SetPoint[0]))
+            #print('%s, Istwert: %.2f °C' % (self.Name, self.Temp[0]))
+            return [self.Temp[0], self.SetPoint[0], self.state.value]
+
+        elif packet.rorg == RORG.RPS:
+            if packet.data[1] == 0x70:
+                self.NRValue = 0
+                if self.state == HCState.Normal:
+                    self.state = HCState.Normal
+                else:
+                    self.state = HCState.Aus
+            elif packet.data[1] == 0x50:
+                self.NRValue = -4
+                self.state = HCState.Absenkung
+            elif packet.data[1] == 0x30:
+                self.NRValue = -2
+                self.state = HCState.Absenkung
+            elif packet.data[1] == 0x10:
+                self.NRValue = 0
+                self.state = HCState.Frostschutz
+
+            #print('%s, Status: %s ' % (self.Name, self.state.value))
+            return [self.state.value]
+
+    def send_SetPoint(self, SetPoint, learn=0, block=0):
+        if not learn:
+            stateByte = ((int(block) & 0x01) << 1) | 0x01 << 3
+
+            spTemp = SetPoint*(255/40.0)
+
+            sendMsg = RadioPacket.create_ESP2(rorg=RORG.BS4, rorg_func=0x00, rorg_type=0x00,
+                                                sender=self.sID,
+                                                command=[0x00, int(spTemp), 0x00, stateByte],
+                                                status=MSGSTATUS.BS4
+                                                )
+
+        else:
+            sendMsg = RadioPacket.create_ESP2(rorg=RORG.BS4, rorg_func=0x00, rorg_type=0x00,
+                                              sender=self.sID,
+                                              command=[0x40, 0x30, 0x0D, 0x85],
+                                              status=MSGSTATUS.BS4
+                                              )
+
+        return [sendMsg]
+
+    def send_Release(self):
+        stateByte = (0x01 << 1) | 0x01 << 3
+
+        spTemp = 0x00
+
+        sendMsg = RadioPacket.create_ESP2(rorg=RORG.BS4, rorg_func=0x00, rorg_type=0x00,
+                                            sender=self.sID,
+                                            command=[0x00, int(spTemp), 0x00, stateByte],
+                                            status=MSGSTATUS.BS4
+                                            )
+
+        return [sendMsg]
+
+
+class TFUTH:
+    def __init__(self, ID, Name):
+        self.state = HCState.Normal
+        self.NRValue = 0
+        self.SetPoint = [0.0, 0.0, 0.0, 0.0, 0.0]
+        self.Temp = [0.0, 0.0, 0.0, 0.0, 0.0]
+        self.RHL = 0.0
+        self.ID = ID
+        self.Name = Name
+
+    def decode(self, packet):
+        if packet.rorg == RORG.BS4:
+            if packet.data[1] == 0x00:
+                self.NRValue = 0
+                self.state = HCState.Normal
+            elif packet.data[1] == 0x19:
+                self.NRValue = -4
+                self.state = HCState.Absenkung
+            elif packet.data[1] == 0x0C:
+                self.NRValue = -2
+                self.state = HCState.Absenkung
+            elif packet.data[1] == 0x06:
+                self.NRValue = -1
+                self.state = HCState.Absenkung
+            else:
+                self.NRValue = 0
+
+            # update data point lists
+            self.SetPoint.insert(0, packet.data[2]*(40.0 / 255))
+            self.Temp.insert(0, (0xFF - packet.data[3])*(40.0 / 255))
+            self.SetPoint.pop()
+            self.Temp.pop()
+
+            # check if is actually turned of...
+            if self.state is not HCState.Absenkung:
+                if self.SetPoint[0] != self.Temp[0]:
+                    self.state = HCState.Normal
+                else:
+                    if (self.SetPoint[1] == self.Temp[1] and self.SetPoint[2] != self.SetPoint[1]) or \
+                       (self.SetPoint == self.Temp):   # and not checkEqual(self.Temp)
+                       # last two messages setpoint and temp were equal and setpoint actually changed
+                        self.state = HCState.Aus
+
+            #print('%s, Status: %s ' % (self.Name, self.state.value))
+            #print('%s, Sollwert: %.2f °C' % (self.Name, self.SetPoint[0]))
+            #print('%s, Istwert: %.2f °C' % (self.Name, self.Temp[0]))
+            return [self.Temp[0], self.SetPoint[0], self.state.value]
+
+    def decode_humidity(self, packet):
+        if packet.rorg == RORG.BS4:
+            self.RHL = packet.data[2]*(100.0/250)
+            #print('%s, rel. Feuchte: %.2f%%' % (self.Name, self.RHL))
+            return self.RHL
+
+
+class FSB14:
+    def __init__(self, ID, Name, tRun_s, tFull_s, sID):
+        self.state = FSB14State.open_ack
+        self.pos = 0.0
+        self.ID = ID
+        self.Name = Name
+        self.tRun_s = tRun_s
+        self.tFull_s = tFull_s
+        self.sID = sID
+        self.isMoving = False
+
+    def decode(self, packet):
+        if packet.rorg == RORG.RPS:
+            if packet.data[1] == 0x70:
+                self.pos = 0.0
+                self.state = FSB14State.open_ack
+                self.isMoving = False
+            if packet.data[1] == 0x50:
+                self.pos = 100.0
+                self.state = FSB14State.down_ack
+                self.isMoving = False
+            if packet.data[1] == 0x01:
+                self.state = FSB14State.run_up
+                self.isMoving = True
+            if packet.data[1] == 0x02:
+                self.state = FSB14State.run_down
+                self.isMoving = True
+
+            #print('%s, Status: %s ' % (self.Name, self.state.value))
+            #print('%s, Position: %.2f%%' % (self.Name, self.pos))
+            return [self.pos, self.state.value]
+
+        if packet.rorg == RORG.BS4:
+            self.state = FSB14State.stop
+            self.isMoving = False
+
+            drivetime_ms = (packet.data[1] << 8) | packet.data[2]
+            drivetime_s = drivetime_ms/10.0
+
+            if packet.data[3] == 0x01:
+                self.pos -= drivetime_s/self.tRun_s*100.0
+            if packet.data[3] == 0x02:
+                self.pos += drivetime_s/self.tRun_s*100.0
+
+            #print('%s, Status: %s ' % (self.Name, self.state.value))
+            #print('%s, Position: %.2f%%' % (self.Name, self.pos))
+            return [self.pos, self.state.value]
+
+    def send_Move(self, newpos=None, newState=None, learn=0, block=0):
+        if not learn:
+            if newState is not None:
+                newState = FSB14Cmd(newState)
+
+            stateByte = ((int(block) & 0x01) << 2) | (0x01 << 1) | 0x01 << 3
+
+            if newState == FSB14Cmd.stop:
+                compState = 0x00
+                self.isMoving = False
+                sendMsg = RadioPacket.create_ESP2(rorg=RORG.BS4, rorg_func=0x00, rorg_type=0x00,
+                                                sender=self.sID,
+                                                command=[0x00, 0x00, compState, stateByte],
+                                                status=MSGSTATUS.BS4
+                                                )
+            else:
+                if newpos is None:
+                    if newState == FSB14Cmd.up:
+                        newpos = 0.0
+                    elif newState == FSB14Cmd.down:
+                        newpos = 100.0
+                    else:
+                        return []
+
+                deltapos = abs(newpos - self.pos)
+                runtime = (self.tRun_s/100.0)*deltapos*10
+
+                if newpos == 0.0 or newpos == 100.0:
+                    runtime = self.tFull_s * 10
+
+                if newpos > self.pos:
+                    #down
+                    compState = 0x02
+                else:
+                    #up
+                    compState = 0x01
+
+                #override, not properly initialized...
+                if self.pos < 0.0 or self.pos > 100.0:
+                    #do an init run...sorry
+                    runtime = self.tFull_s * 10
+                    compState = 0x01
+
+                sendMsg = RadioPacket.create_ESP2(rorg=RORG.BS4, rorg_func=0x00, rorg_type=0x00,
+                                                  sender=self.sID,
+                                                  command=[((int(runtime) & 0xFF00) >> 8), int(runtime) & 0xFF, compState, stateByte],
+                                                  status=MSGSTATUS.BS4
+                                                  )
+
+                self.isMoving = True
+
+        else:
+            sendMsg = RadioPacket.create_ESP2(rorg=RORG.BS4, rorg_func=0x00, rorg_type=0x00,
+                                              sender=self.sID,
+                                              command=[0xFF, 0xF8, 0x0D, 0x80],
+                                              status=MSGSTATUS.BS4
+                                              )
+
+        return [sendMsg]
+
+
+class FWS61:
+    def __init__(self, ID, Name):
+        self.ID = ID
+        self.Name = Name
+
+    def decode(self, packet):
+        if packet.data[4] == 0x1A or packet.data[4] == 0x18:
+            dawn = packet.data[1]*(1000.0/255)
+            temp = (packet.data[2]*(120.0/255))-40.0
+            wind = packet.data[3]*(70.0/255)
+            if packet.data[4] == 0x1A:
+                rain = 1
+            elif packet.data[4] == 0x18:
+                rain = 0
+
+            #print('%s, Dämmerung: %.2f Lux' % (self.Name, dawn))
+            #print('%s, Temperatur: %.2f °C' % (self.Name, temp))
+            #print('%s, Wind: %.2f m/s' % (self.Name, wind))
+            #print('%s, %s' % (self.Name, rain))
+            return [0, dawn, temp, wind, rain]
+        elif packet.data[4] == 0x28:
+            sun_west = packet.data[1]*(150.0/255)
+            sun_south = packet.data[2]*(150.0/255)
+            sun_east = packet.data[3]*(150.0/255)
+            #print('%s, Sonne West: %.2f kLux' % (self.Name, sun_west))
+            #print('%s, Sonne Süd: %.2f kLux' % (self.Name, sun_south))
+            #print('%s, Sonne Ost: %.2f kLux' % (self.Name, sun_east))
+            return [1, sun_west, sun_south, sun_east]
+
+class FUD14:
+    def __init__(self, ID, Name, sIDdim, sIDsleep=[0, 0, 0, 0], sIDwake=[0, 0, 0, 0]):
+        self.ID = ID
+        self.Name = Name
+        self.isOn = 0
+        self.dimval = 0.0
+        self.sIDdim = sIDdim
+        self.sIDsleep = sIDsleep
+        self.sIDwake = sIDwake
+
+    def decode(self, packet):
+        if packet.rorg == RORG.BS4:
+            if packet.data[4] == 0x08:
+                self.isOn = 0
+            elif packet.data[4] == 0x09:
+                self.isOn = 1
+            else:
+                self.isOn = 0
+            self.dimval = packet.data[2]
+
+            #print('%s, Dimmwert: %d%% Status: %d' % (self.Name, self.dimval, self.isOn))
+            return [self.dimval, self.isOn]
+        if packet.rorg == RORG.RPS:
+            if packet.data[1] == 0x50:
+                self.isOn = 0
+            elif packet.data[1] == 0x70:
+                self.isOn = 1
+            #print('%s, Status: %d ' % (self.Name, self.isOn))
+            return [self.dimval, self.isOn]
+
+    def send_DimMsg(self, newVal=None, newState=None, dimSpeed=0, learn=0, block=0):
+        if not learn:
+            if newVal is None and newState is None:
+                return []
+
+            if newVal == 0:
+                newState = 0
+                newVal = self.dimval #safe current value in actuator for manual switch use
+            elif newVal is None:
+                if newState == 1:
+                    newVal = 100.0
+                else:
+                    newVal = self.dimval
+
+            if newState is None:
+                if self.isOn == 0 and newVal != 0:
+                    newState = 1
+                else:
+                    newState = self.isOn
+
+            stateByte = (int(newState) & 0x01) | ((int(block) & 0x01) << 2) | 0x01 << 3
+            sendMsg = RadioPacket.create_ESP2(rorg=RORG.BS4, rorg_func=0x00, rorg_type=0x00,
+                                            sender=self.sIDdim,
+                                            command=[0x02, int(newVal) & 0xFF, int(dimSpeed) & 0xFF, stateByte],
+                                            status=MSGSTATUS.BS4
+                                            )
+        else:
+            sendMsg = RadioPacket.create_ESP2(rorg=RORG.BS4, rorg_func=0x00, rorg_type=0x00,
+                                              sender=self.sIDdim,
+                                              command=[0xE0, 0x40, 0x0D, 0x80],
+                                              status=MSGSTATUS.BS4
+                                              )
+        return [sendMsg]
+
+    def send_SleepDimMsg(self):
+        onMsg = RadioPacket.create_ESP2(rorg=RORG.RPS, rorg_func=0x00, rorg_type=0x00,
+                                        sender=self.sIDsleep,
+                                        command=[0x30, 0x00, 0x00, 0x00],
+                                        status=MSGSTATUS.T2NMsg
+                                        )
+
+        offMsg = RadioPacket.create_ESP2(rorg=RORG.RPS, rorg_func=0x00, rorg_type=0x00,
+                                         sender=self.sIDsleep,
+                                         command=[0x00, 0x00, 0x00, 0x00],
+                                         status=MSGSTATUS.T2UMsg
+                                         )
+        return [onMsg, offMsg]
+
+
+    def send_WakeDimMsg(self):
+        onMsg = RadioPacket.create_ESP2(rorg=RORG.RPS, rorg_func=0x00, rorg_type=0x00,
+                                        sender=self.sIDwake,
+                                        command=[0x30, 0x00, 0x00, 0x00],
+                                        status=MSGSTATUS.T2NMsg
+                                        )
+
+        offMsg = RadioPacket.create_ESP2(rorg=RORG.RPS, rorg_func=0x00, rorg_type=0x00,
+                                         sender=self.sIDwake,
+                                         command=[0x00, 0x00, 0x00, 0x00],
+                                         status=MSGSTATUS.T2UMsg
+                                         )
+        return [onMsg, offMsg]
+
+
+class FSR_FTN_14:
+    def __init__(self, ID, Name, sID):
+        self.ID = ID
+        self.Name = Name
+        self.isOn = 0
+        self.sIDonoff = sID
+
+    def decode(self, packet):
+        if packet.rorg == RORG.RPS:
+            if packet.data[1] == 0x50:
+                self.isOn = 0
+            elif packet.data[1] == 0x70:
+                self.isOn = 1
+            #print('%s, Status: %d ' % (self.Name, self.isOn))
+
+            return self.isOn
+
+    def send_toggle(self, RockerPos = RockerButton.RightTop):
+        onMsg = RadioPacket.create_ESP2(rorg=RORG.RPS, rorg_func=0x00, rorg_type=0x00,
+                                        sender=self.sIDonoff,
+                                        command=[RockerPos, 0x00, 0x00, 0x00],
+                                        status=MSGSTATUS.T2NMsg
+                                        )
+
+        offMsg = RadioPacket.create_ESP2(rorg=RORG.RPS, rorg_func=0x00, rorg_type=0x00,
+                                         sender=self.sIDonoff,
+                                         command=[RockerButton.Off, 0x00, 0x00, 0x00],
+                                         status=MSGSTATUS.T2UMsg
+                                         )
+        return [onMsg, offMsg]
+
diff --git a/enocean/protocol/constants.py b/enocean/protocol/constants.py
index 1425193..22ad601 100644
--- a/enocean/protocol/constants.py
+++ b/enocean/protocol/constants.py
@@ -35,6 +35,26 @@ class EVENT_CODE(IntEnum):
     CO_EVENT_SECUREDEVICES = 0x05
 
 
+# ESP2 ORG EnOcean_Equipment_Profiles_2.0.pdf
+class ORG(IntEnum):
+    BS4 = 0x07
+    BS1 = 0x06
+    RPS = 0x05
+
+#ESP2 Message Status Field EnOcean_Equipment_Profiles_2.0.pdf
+class MSGSTATUS(IntEnum):
+    #RPS definitions
+    T2Msg = 0x20
+    NMsg = 0x10
+    T2NMsg = 0x30
+    T2UMsg = 0x20
+    T1NMsg = 0x10
+    T1UMsg = 0x00
+    #BS4 definitions
+    BS4 = 0x00 #must be zero in BS4 messages with RP count of 0
+    #BS1 definitions
+    BS1 = 0x00 #must be zero in BS1 too
+
 # EnOcean_Equipment_Profiles_EEP_V2.61_public.pdf / 8
 class RORG(IntEnum):
     UNDEFINED = 0x00
diff --git a/enocean/protocol/crc8.py b/enocean/protocol/crc8.py
index 5dd9b9d..b057724 100644
--- a/enocean/protocol/crc8.py
+++ b/enocean/protocol/crc8.py
@@ -39,3 +39,10 @@ def calc(msg):
     for byte in msg:
         checksum = CRC_TABLE[checksum & 0xFF ^ byte & 0xFF]
     return checksum
+
+def calc_ESP2(msg):
+    checksum=0
+    for byte in msg:
+        checksum += byte
+        checksum &= 0xFF
+    return checksum
\ No newline at end of file
diff --git a/enocean/protocol/packet.py b/enocean/protocol/packet.py
index 1cba721..7c6ffdf 100644
--- a/enocean/protocol/packet.py
+++ b/enocean/protocol/packet.py
@@ -6,7 +6,7 @@
 import enocean.utils
 from enocean.protocol import crc8
 from enocean.protocol.eep import EEP
-from enocean.protocol.constants import PACKET, RORG, PARSE_RESULT, DB0, DB2, DB3, DB4, DB6
+from enocean.protocol.constants import PACKET as PACKET, RORG, ORG, PARSE_RESULT, DB0, DB2, DB3, DB4, DB6
 
 
 class Packet(object):
@@ -160,6 +160,93 @@ def parse_msg(buf, communicator=None):
 
         return PARSE_RESULT.OK, buf, packet
 
+
+    @staticmethod
+    def parse_msg_ESP2(buf, communicator=None):
+        '''
+        Parses message from buffer.
+        returns:
+            - PARSE_RESULT
+            - remaining buffer
+            - Packet -object (if message was valid, else None)
+        '''
+        # If the buffer doesn't contain 0xA5 (start char)
+        # the message isn't needed -> ignore
+        # if 0xA5 not in buf:
+        #     return PARSE_RESULT.INCOMPLETE, [], None
+        # else:
+        #     if buf[list(buf).index(0xA5)+1] != 0x5A:
+        #         return PARSE_RESULT.INCOMPLETE, [], None
+
+        if not buf:
+            return PARSE_RESULT.INCOMPLETE, [], None
+            
+        if 0xA5 not in buf:
+            return PARSE_RESULT.INCOMPLETE, [], None
+
+        msg_len = 0
+
+        for index,value in enumerate(buf):
+            try:
+                if buf[index] == 0xA5 and buf[index+1] == 0x5A:
+                    data_len = buf[index+2] & 0x1F
+                    HSEQ = buf[index+2] >> 5
+                    opt_len = 0
+                    msg_len = data_len
+                    if len(buf[index+2:]) < msg_len:
+                        # If buffer isn't long enough, the message is incomplete
+                        return PARSE_RESULT.INCOMPLETE, buf, None
+                    crcval = crc8.calc_ESP2(buf[index+2:index+2+data_len])
+                    if buf[index+2+data_len] == crcval:
+                        buf = buf[index+2:]
+                        break
+                    else:
+                        Packet.logger.error('Data CRC error!')
+                        return PARSE_RESULT.CRC_MISMATCH, buf, None
+            except IndexError:
+                # If the fields don't exist, message is incomplete
+                return PARSE_RESULT.INCOMPLETE, buf, None
+
+        if msg_len == 0:
+            Packet.logger.error('Data Length is Zero!')
+            return PARSE_RESULT.INCOMPLETE, [], None
+
+        msg = buf[0:msg_len]
+        buf = buf[msg_len+1:]
+
+        packet_type = HSEQ
+        data = msg[1:data_len]
+        opt_data = []
+
+        #Adopt ORG to RORG for ESP2
+        if data[0] == ORG.BS1:
+            data[0] = RORG.BS1
+        if data[0] == ORG.BS4:
+            data[0] = RORG.BS4
+        if data[0] == ORG.RPS:
+            data[0] = RORG.RPS
+
+        # If we got this far, everything went ok (?)
+        if packet_type == PACKET.RADIO:
+            # Need to handle UTE Teach-in here, as it's a separate packet type...
+            if data[0] == RORG.UTE:
+                packet = UTETeachIn(packet_type, data, opt_data, communicator=communicator)
+                # Send a response automatically, works only if
+                # - communicator is set
+                # - communicator.teach_in == True
+                packet.send_response()
+            else:
+                packet = RadioPacket(packet_type, data, opt_data)
+        elif packet_type == PACKET.RESPONSE:
+            packet = ResponsePacket(packet_type, data, opt_data)
+        elif packet_type == PACKET.EVENT:
+            #packet = EventPacket(packet_type, data, opt_data)
+            packet = RadioPacket(packet_type, data, opt_data)
+        else:
+            packet = Packet(packet_type, data, opt_data)
+
+        return PARSE_RESULT.OK, buf, packet
+
     @staticmethod
     def create(packet_type, rorg, rorg_func, rorg_type, direction=None, command=None,
                destination=None,
@@ -242,6 +329,94 @@ def create(packet_type, rorg, rorg_func, rorg_type, direction=None, command=None
         packet.parse_eep(rorg_func, rorg_type, direction, command)
         return packet
 
+    @staticmethod
+    def create_ESP2(packet_type, rorg, direction=None, command=None,
+               destination=None,
+               sender=None,
+               learn=False,
+               status=0x00, **kwargs):
+        '''
+        Creates an packet ready for sending.
+        Uses rorg, rorg_func and rorg_type to determine the values set based on EEP.
+        Additional arguments (**kwargs) are used for setting the values.
+
+        Currently only supports:
+            - PACKET.RADIO
+            - RORGs RPS, BS1, BS4, VLD.
+
+        TODO:
+            - Require sender to be set? Would force the "correct" sender to be set.
+            - Do we need to set telegram control bits?
+              Might be useful for acting as a repeater?
+        '''
+
+        if packet_type != PACKET.RADIO:
+            # At least for now, only support PACKET.RADIO.
+            raise ValueError('Packet type not supported by this function.')
+
+        if rorg not in [RORG.RPS, RORG.BS1, RORG.BS4]:
+            # At least for now, only support these RORGS.
+            raise ValueError('RORG not supported by this function.')
+
+        if destination is None:
+            destination = [0xFF, 0xFF, 0xFF, 0xFF]
+
+        # TODO: Should use the correct Base ID as default.
+        #       Might want to change the sender to be an offset from the actual address?
+        if sender is None:
+            Packet.logger.warning('Replacing sender with default address.')
+            sender = [0xDE, 0xAD, 0xBE, 0xEF]
+
+        if not isinstance(destination, list) or len(destination) != 4:
+            raise ValueError('Destination must a list containing 4 (numeric) values.')
+
+        if not isinstance(sender, list) or len(sender) != 4:
+            raise ValueError('Sender must a list containing 4 (numeric) values.')
+
+        packet = Packet(packet_type, data=[], optional=[])
+        packet.rorg = rorg
+
+        if packet.rorg == RORG.BS1:
+            packet.rorg = ORG.BS1
+        if packet.rorg == RORG.BS4:
+            packet.rorg = ORG.BS4
+        if packet.rorg == RORG.RPS:
+            packet.rorg = ORG.RPS
+
+        packet.data = [packet.rorg]
+        # Select EEP at this point, so we know how many bits we're dealing with (for VLD).
+        #packet.select_eep(rorg_func, rorg_type, direction, command)
+
+        # Initialize data depending on the profile.
+       # if rorg in [RORG.RPS, RORG.BS1]:
+       #     packet.data.extend([0])
+        #elif rorg == RORG.BS4:
+        packet.data.extend(command)
+        #else:
+          #  packet.data.extend([0] * int(packet._profile.get('bits', '1')))
+        packet.data.extend(sender)
+        packet.data.extend([0])
+        # Always use sub-telegram 3, maximum dbm (as per spec, when sending),
+        # and no security (security not supported as per EnOcean Serial Protocol).
+        #packet.optional = [3] + destination + [0xFF] + [0]
+
+        #if command:
+            # Set CMD to command, if applicable.. Helps with VLD.
+            #kwargs['CMD'] = command
+
+        #packet.set_eep(kwargs)
+        if rorg in [RORG.BS1, RORG.BS4] and not learn:
+            if rorg == RORG.BS1:
+                packet.data[1] |= (1 << 3)
+            if rorg == RORG.BS4:
+                packet.data[4] |= (1 << 3)
+        packet.data[-1] = status
+
+        # Parse the built packet, so it corresponds to the received packages
+        # For example, stuff like RadioPacket.learn should be set.
+        packet = Packet.parse_msg_ESP2(packet.build_ESP2())[2]
+        return packet
+
     def parse(self):
         ''' Parse data from Packet '''
         # Parse status from messages
@@ -287,6 +462,23 @@ def build(self):
         ords.append(crc8.calc(ords[6:]))
         return ords
 
+    def build_ESP2(self):
+        ''' Build Packet for sending to EnOcean controller '''
+        data_length = len(self.data)+1
+        ords = [0xA5, 0x5A, (data_length & 0x1F | ((int(self.packet_type)&0x07)<<5))]
+
+        if self.data[0] in [RORG.RPS, RORG.BS4, RORG.BS1]:
+            if self.data[0] == RORG.RPS:
+                self.data[0] = ORG.RPS
+            if self.data[0] == RORG.BS1:
+                self.data[0] = ORG.BS1
+            if self.data[0] == RORG.BS4:
+                self.data[0] = ORG.BS4
+
+        ords.extend(self.data)
+        ords.append(crc8.calc_ESP2(ords[2:]))
+        return ords
+
 
 class RadioPacket(Packet):
     destination = [0xFF, 0xFF, 0xFF, 0xFF]
@@ -304,6 +496,11 @@ def create(rorg, rorg_func, rorg_type, direction=None, command=None,
                destination=None, sender=None, learn=False, **kwargs):
         return Packet.create(PACKET.RADIO, rorg, rorg_func, rorg_type, direction, command, destination, sender, learn, **kwargs)
 
+    @staticmethod
+    def create_ESP2(rorg, rorg_func, rorg_type, direction=None, command=None,
+               destination=None, sender=None, learn=False, **kwargs):
+        return Packet.create_ESP2(PACKET.RADIO, rorg, direction, command, destination, sender, learn, **kwargs)
+
     @property
     def sender_int(self):
         return enocean.utils.combine_hex(self.sender)
@@ -321,8 +518,10 @@ def destination_hex(self):
         return enocean.utils.to_hex_string(self.destination)
 
     def parse(self):
-        self.destination = self.optional[1:5]
-        self.dBm = -self.optional[5]
+        if len(self.optional):
+            self.destination = self.optional[1:5]
+            self.dBm = -self.optional[5]
+
         self.sender = self.data[-5:-1]
         # Default to learn == True, as some devices don't have a learn button
         self.learn = True
diff --git a/examples/stoney/devicelist_example.py b/examples/stoney/devicelist_example.py
new file mode 100644
index 0000000..bb69630
--- /dev/null
+++ b/examples/stoney/devicelist_example.py
@@ -0,0 +1,38 @@
+# -*- encoding: utf-8 -*-
+from enocean.manufacturer.eltako import *
+
+roomsensors = []
+roomsensors.append(FTR65HS(u'EL:TA:KO:ID', 'my/mqtt/topic'))
+roomsensors.append(FTR65HS(u'EL:TA:KO:ID', 'my/mqtt/topic'))
+roomsensors.append(FTR65HS(u'EL:TA:KO:ID', 'my/mqtt/topic'))
+
+shutters = []
+shutters.append(FSB14(u'EL:TA:KO:ID', 'my/mqtt/topic', 25.0, 30.0, [0x00, 0x01, 0x02, 0x03]))
+shutters.append(FSB14(u'EL:TA:KO:ID', 'my/mqtt/topic', 25.0, 30.0, [0x00, 0x01, 0x02, 0x03]))
+shutters.append(FSB14(u'EL:TA:KO:ID', 'my/mqtt/topic', 25.0, 30.0, [0x00, 0x01, 0x02, 0x03]))
+
+dimmer = []
+dim1 = FUD14(u'EL:TA:KO:ID', 'my/mqtt/topic', [0x00, 0x01, 0x02, 0x03])
+dimmer.append(dim1)
+dim2 = FUD14(u'EL:TA:KO:ID', 'my/mqtt/topic', [0x00, 0x01, 0x02, 0x03], [0x00, 0x01, 0x02, 0x03])
+dimmer.append(dim2)
+dim3 = FUD14(u'EL:TA:KO:ID', 'my/mqtt/topic', [0x00, 0x01, 0x02, 0x03], [0x00, 0x01, 0x02, 0x03], [0x00, 0x01, 0x02, 0x03])
+dimmer.append(dim3)
+
+
+hygrometer = []
+hygrometer.append(TFUTH(u'EL:TA:KO:ID', 'my/mqtt/topic'))
+hygrometer.append(TFUTH(u'EL:TA:KO:ID', 'my/mqtt/topic'))
+
+thermostate = []
+thermostate.append(FAE14(u'EL:TA:KO:ID', 'my/mqtt/topic', [0x00, 0x01, 0x02, 0x03]))
+thermostate.append(FAE14(u'EL:TA:KO:ID', 'my/mqtt/topic', [0x00, 0x01, 0x02, 0x03]))
+
+weatherstation = FWS61(u'EL:TA:KO:ID', 'my/mqtt/topic')
+rockers = FTS14EM()
+
+switches = []
+sw1 = FSR_FTN_14(u'EL:TA:KO:ID', 'my/mqtt/topic', [0x00, 0x01, 0x02, 0x03])
+switches.append(sw1)
+sw2 = FSR_FTN_14(u'EL:TA:KO:ID', 'my/mqtt/topic', [0x00, 0x01, 0x02, 0x03])
+switches.append(sw2)
\ No newline at end of file
diff --git a/examples/stoney/enocean_backend.py b/examples/stoney/enocean_backend.py
new file mode 100644
index 0000000..028cf36
--- /dev/null
+++ b/examples/stoney/enocean_backend.py
@@ -0,0 +1,263 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+from enocean.consolelogger import init_logging
+import enocean.utils
+from enocean.communicators.ESP2serialcommunicator import ESP2SerialCommunicator
+from enocean.protocol.constants import PACKET, RORG
+from enocean.manufacturer.eltako import *
+import sys
+import traceback
+from time import sleep
+import paho.mqtt.client as paho
+from enocean.example.devicelist_example import *
+import threading, logging
+
+try:
+    import queue
+except ImportError:
+    import Queue as queue
+
+class BreakIt(Exception): pass
+
+def eno_worker(wstop):
+    # endless loop receiving radio packets
+    mainlogger.info("Worker started...")
+    while 1:
+        try:
+            if wstop.isSet():
+                break
+
+            # Loop to empty the queue...
+            packet = esp2com.receive.get(block=True, timeout=1)
+
+            if (packet.packet_type in [PACKET.RADIO, PACKET.EVENT]) and (packet.rorg in [RORG.RPS, RORG.BS4, RORG.BS1]):
+
+                button = rockers.new_event(packet)
+                if button is not None:
+                    if button[1] is RockerEvent.Press:
+                        cmqtt.publish("my/home/automation/topic/button/press", payload=button[0], qos=2, retain=False)
+                    if button[1] is RockerEvent.Longpress_2s:
+                        cmqtt.publish("my/home/automation/topic/button/longpress2", payload=button[0], qos=2, retain=False)
+                    if button[1] is RockerEvent.Longpress_5s:
+                        cmqtt.publish("my/home/automation/topic/button/longpress5", payload=button[0], qos=2, retain=False)
+
+                for item in hygrometer:
+                    if packet.sender_hex == item.ID:
+                        EnoValList = item.decode_humidity(packet)
+                        cmqtt.publish(item.Name, payload=EnoValList, qos=2, retain=True)
+                        raise BreakIt
+
+                for item in roomsensors:
+                    if packet.sender_hex == item.ID:
+                        EnoValList = item.decode(packet)
+                        cmqtt.publish(item.Name + "/temperature", payload=EnoValList[0], qos=2, retain=True)
+                        cmqtt.publish(item.Name + "/setpoint", payload=EnoValList[1], qos=2, retain=True)
+                        cmqtt.publish(item.Name + "/state", payload=EnoValList[2], qos=2, retain=True)
+                        raise BreakIt
+
+                if packet.sender_hex == weatherstation.ID:
+                    item = weatherstation
+                    EnoValList = item.decode(packet)
+                    if EnoValList[0] == 0:
+                        cmqtt.publish(item.Name + "/lightsensor", payload=EnoValList[1], qos=2, retain=True)
+                        cmqtt.publish(item.Name + "/temperature", payload=EnoValList[2], qos=2, retain=True)
+                        cmqtt.publish(item.Name + "/windspeed", payload=EnoValList[3], qos=2, retain=True)
+                        cmqtt.publish(item.Name + "/rain", payload=EnoValList[4], qos=2, retain=True)
+                    else:
+                        cmqtt.publish(item.Name + "/sun/west", payload=EnoValList[1], qos=2, retain=True)
+                        cmqtt.publish(item.Name + "/sun/south", payload=EnoValList[2], qos=2, retain=True)
+                        cmqtt.publish(item.Name + "/sun/east", payload=EnoValList[3], qos=2, retain=True)
+
+                    raise BreakIt
+
+                for item in thermostate:
+                    if packet.sender_hex == item.ID:
+                        EnoValList = item.decode(packet)
+                        if len(EnoValList) == 3:
+                            cmqtt.publish(item.Name + "/temperature", payload=EnoValList[0], qos=2, retain=True)
+                            cmqtt.publish(item.Name + "/setpoint", payload=EnoValList[1], qos=2, retain=True)
+                            cmqtt.publish(item.Name + "/state", payload=EnoValList[2], qos=2, retain=True)
+                        else:
+                            cmqtt.publish(item.Name + "/state", payload=EnoValList[0], qos=2, retain=True)
+
+                        raise BreakIt
+
+                for item in shutters:
+                    if packet.sender_hex == item.ID:
+                        EnoValList = item.decode(packet)
+                        cmqtt.publish(item.Name + "/position", payload=EnoValList[0], qos=2, retain=True)
+                        cmqtt.publish(item.Name + "/state", payload=EnoValList[1], qos=2, retain=True)
+                        raise BreakIt
+
+                for item in dimmer:
+                    if packet.sender_hex == item.ID:
+                        EnoValList = item.decode(packet)
+                        cmqtt.publish(item.Name + "/dimmvalue", payload=EnoValList[0], qos=2, retain=True)
+                        cmqtt.publish(item.Name + "/state", payload=EnoValList[1], qos=2, retain=True)
+                        raise BreakIt
+
+                for item in switches:
+                    if packet.sender_hex == item.ID:
+                        EnoValList = item.decode(packet)
+                        cmqtt.publish(item.Name + "/state", payload=EnoValList, qos=2, retain=True)
+                        raise BreakIt
+
+        except queue.Empty:
+            continue
+        except BreakIt:
+            continue
+        except KeyboardInterrupt:
+            break
+        except Exception:
+            traceback.print_exc(file=sys.stdout)
+            break
+
+
+def SendSwToggle(communicator, messages):
+    communicator.send(messages[0])
+    sleep(0.1)
+    communicator.send(messages[1])
+
+
+def on_message_set_dimmerstate(client, userdata, message):
+    for item in dimmer:
+        if item.Name in message.topic and message.payload != None:
+            try:
+                newvalue = int(message.payload)
+            except ValueError:
+                mainlogger.info("Value Error happened with " + str(message.topic))
+                return
+
+            esp2com.send(item.send_DimMsg(newState=newvalue)[0])
+
+
+def on_message_light_toggle(client, userdata, message):
+    for item in schwitches:
+        if item.Name in message.topic:
+            eno_msg = item.send_toggle()
+            SendSwToggle(esp2com, eno_msg)
+
+
+def on_message_set_brightness(client, userdata, message):
+    for item in dimmer:
+        if item.Name in message.topic and message.payload != None:
+            try:
+                newvalue = float(message.payload)
+            except ValueError:
+                mainlogger.info("Value Error happened with " + str(message.topic))
+                return
+
+            esp2com.send(item.send_DimMsg(newVal=newvalue)[0])
+
+
+def on_message_shutter_set_state(client, userdata, message):
+    for item in shutters:
+        if item.Name in message.topic and message.payload != None:
+            try:
+                newvalue = int(message.payload)
+            except ValueError:
+                mainlogger.info("Value Error happened with " + str(message.topic))
+                return
+
+            esp2com.send(item.send_Move(newState=newvalue)[0])
+
+
+def on_message_shutter_set_pos(client, userdata, message):
+    for item in schutters:
+        if item.Name in message.topic and message.payload != None:
+            if item.isMoving:
+                #if shutter is moving, stop it first and wait for a position update...
+                #tested ok, works perfectly
+                runpos = item.pos
+                esp2com.send(item.send_Move(newState="Stop")[0])
+                timesslept = 0
+                while runpos == item.pos:
+                    sleep(0.05)
+                    timesslept+=1
+                    if timesslept*0.05 >= item.tFull_s:
+                        #seems like we already were in an endstop, eltako behaviour...
+                        break
+            #print("Sleep loop delay " + str(timesslept*50.0) + "ms, ran " + str(timesslept) + " times...")
+            try:
+                newvalue = float(message.payload)
+            except ValueError:
+                mainlogger.info("Value Error happened with " + str(message.topic))
+                return
+
+            esp2com.send(item.send_Move(newpos=float(message.payload))[0])
+
+
+def on_message_thermo_set_temp(client, userdata, message):
+    for item in thermostate:
+        if item.Name in message.topic and message.payload != None:
+            try:
+                newvalue = float(message.payload)
+            except ValueError:
+                mainlogger.info("Value Error happened with " + str(message.topic))
+                return
+
+            esp2com.send(item.send_SetPoint(SetPoint=newvalue, block=1)[0])
+
+
+def on_message_thermo_set_release(client, userdata, message):
+    for item in thermostate:
+        if item.Name in message.topic and message.payload != None:
+            esp2com.send(item.send_Release()[0])
+
+
+def on_connect(client, userdata, flags, rc):
+    cmqtt.subscribe("my/home/automation/topic/#", qos=2)
+    mainlogger.info("Connected to MQTT-Broker with result code "+str(rc))
+
+
+def on_disconnect(cmqtt, obj, rc):
+    mainlogger.info("Disconnected from MQTT-Broker with result code "+str(rc))
+
+
+def on_message(mosq, obj, msg):
+    mainlogger.info("From mqtt-broker: " + msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
+
+
+init_logging()
+
+mainlogger = logging.getLogger('eno_backend')
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+mainlogger.setLevel(logging.DEBUG)
+stream_handler = logging.StreamHandler()
+stream_handler.setLevel(logging.DEBUG)
+stream_handler.setFormatter(formatter)
+mainlogger.addHandler(stream_handler)
+
+esp2com = ESP2SerialCommunicator()
+cmqtt = paho.Client(client_id="", clean_session=True)
+cmqtt.username_pw_set(username="", password="")
+cmqtt.message_callback_add("my/home/automation/topic", on_message_set_brightness)
+cmqtt.message_callback_add("my/home/automation/topic", on_message_set_dimmerstate)
+cmqtt.message_callback_add("my/home/automation/topic", on_message_light_toggle)
+cmqtt.message_callback_add("my/home/automation/topic", on_message_shutter_set_state)
+cmqtt.message_callback_add("my/home/automation/topic", on_message_shutter_set_pos)
+cmqtt.message_callback_add("my/home/automation/topic", on_message_thermo_set_temp)
+cmqtt.message_callback_add("my/home/automation/topic", on_message_thermo_set_release)
+cmqtt.on_message = on_message
+cmqtt.on_connect = on_connect
+cmqtt.on_disconnect = on_disconnect
+
+cmqtt.connect("", port=0000)
+esp2com.start()
+
+wstop = threading.Event()
+t = threading.Thread(name='eno-worker', target=eno_worker, args=(wstop,))
+t.start()
+
+mainlogger.info("Starting MQTT...")
+
+cmqtt.loop_forever()
+
+mainlogger.info('MQTT Exited, stopping other workers...')
+
+if t.is_alive():
+    wstop.set()
+    t.join(timeout=10)
+
+if esp2com.is_alive():
+    esp2com.stop()
diff --git a/examples/stoney/enocean_mqtt_influx.py b/examples/stoney/enocean_mqtt_influx.py
new file mode 100644
index 0000000..5571cd8
--- /dev/null
+++ b/examples/stoney/enocean_mqtt_influx.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+import paho.mqtt.client as mqtt
+import datetime
+import time
+from influxdb import InfluxDBClient
+import logging
+
+def on_connect(client, userdata, flags, rc):
+    print("Connected with result code "+str(rc))
+    client.subscribe("my/home/automation/topic/#", qos=2)
+    client.subscribe("my/home/automation/topic/#", qos=2)
+    client.subscribe("my/home/automation/topic/#", qos=2)
+    client.subscribe("my/home/automation/topic/hygro", qos=2)
+    client.subscribe("my/home/automation/topic/#", qos=2)
+
+def on_message(client, userdata, msg):
+    # Use utc as timestamp
+    receiveTime=datetime.datetime.utcnow()
+   
+    isfloatValue=False
+    try:
+        # Convert the string to a float so that it is stored as a number and not a string in the database
+        message=msg.payload.decode("utf-8")
+        val = float(message)
+        isfloatValue=True
+    except ValueError:
+        isfloatValue=False
+        mainlogger.info("got a non-float from " + str(msg.topic))
+
+    if isfloatValue:
+        mainlogger.info(str(msg.topic) + ": " + str(msg.payload))
+
+        json_body = [
+            {
+                "measurement": msg.topic,
+                "time": receiveTime,
+                "fields": {
+                    "value": val
+                }
+            }
+        ]
+
+        try:
+            dbclient.write_points(json_body)
+        except:
+            mainlogger.info("ERROR WHILE SENDING TO INFLUX!!")
+
+    # else:
+    #     print(str(receiveTime) + ": " + msg.topic + " " + message)
+    #
+    #     json_body = [
+    #         {
+    #             "measurement": msg.topic,
+    #             "time": receiveTime,
+    #             "fields": {
+    #                 "value": message
+    #             }
+    #         }
+    #     ]
+    #
+    # dbclient.write_points(json_body)
+
+# Set up a client for InfluxDB
+
+
+mainlogger = logging.getLogger('eno_influx_logger')
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+mainlogger.setLevel(logging.DEBUG)
+stream_handler = logging.StreamHandler()
+stream_handler.setLevel(logging.DEBUG)
+stream_handler.setFormatter(formatter)
+mainlogger.addHandler(stream_handler)
+
+mainlogger.info("Starting...")
+dbclient = InfluxDBClient(host='', port=0000, database='')
+
+mainlogger.info("InfluxConn OK...")
+
+# Initialize the MQTT client that should connect to the Mosquitto broker
+client = mqtt.Client(client_id="")
+client.username_pw_set(username="", password="")
+client.on_connect = on_connect
+client.on_message = on_message
+connOK=False
+while(connOK == False):
+    try:
+        client.connect("", port=0000, keepalive=60, )
+        connOK = True
+        mainlogger.info("MQTTConn OK...")
+    except:
+        connOK = False
+    time.sleep(2)
+
+# Blocking loop to the Mosquitto broker
+client.loop_forever()
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index fb7ca9a..4a63d02 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,5 @@
 enum-compat>=0.0.2
 pyserial>=3.0
 beautifulsoup4>=4.3.2
+paho-mqtt
+influxdb