Beispiel #1
0
class Driver(threading.Thread):
    ''' driver class not used directly to standardize any type of protocol '''
    _logger = get_logger('rhum.drivers.Driver')

    def __init__(self, callback=None):
        super(Driver, self).__init__()
        # Create an event to stop the thread
        self._stop = threading.Event()

        # Setup messages queues
        self.transmit = queue.Queue()
        self.receive = queue.Queue()

        # Set the callback method
        self.__callback = callback

    def send(self, message):
        if not isinstance(message, EnOceanMessage):
            self._logger.error('Cannot send others objects than Message')
            return False
        self.transmit.put(message)
        return True

    def stop(self):
        self._stop.set()

    def test(self):
        return True

    def parse(self):
        ''' Parses messages and puts them to receive queue '''
Beispiel #2
0
class RadioERP1Message(EnOceanMessage):

    _logger = get_logger('rhum.drivers.enocean.messages.RadioERP1Message')

    def __init__(self, __type, __datas, __opts):
        self.__rorg = __datas[0:1][0]
        self.__subtelnum = None
        self.__destID = None
        self.__dBm = None
        self.__securityLevel = None

        if len(__opts) > 0:
            self.__subtelnum = __opts[0:1][0]
            self.__destID = ''.join(["%02X " % x for x in __opts[1:5]]).strip()
            self.__dBm = ''.join(["%02X " % x for x in __opts[5:6]]).strip()
            self.__securityLevel = ''.join(["%02X " % x
                                            for x in __opts[6:]]).strip()

        super(RadioERP1Message, self).__init__(__type, __datas, __opts)

    def isRadioERP1(self):
        return (self._get()[0] == PacketType.RADIO_ERP1.value)

    def getReturnType(self):
        return RadioERP1Type(self.__rorg)

    def __str__(self):
        strMsg = super(RadioERP1Message, self).__str__()
        strMsg += "\nR-ORG                : {0}".format(
            RadioERP1Type(self.__rorg))
        strMsg += "\nSubTelNum            : {0}".format(self.__subtelnum)
        strMsg += "\nDestination ID       : {0}".format(self.__destID)
        strMsg += "\ndBm                  : {0}".format(self.__dBm)
        strMsg += "\nSecurity Level       : {0}".format(self.__securityLevel)
        return strMsg
Beispiel #3
0
class VersionMessage(ResponseMessage):

    _logger = get_logger('rhum.drivers.enocean.messages.VersionMessage')

    def __init__(self, __type, __datas, __opts):
        super(VersionMessage, self).__init__(__type, __datas, __opts)

        self.__appmain = __datas[1:2][0]
        self.__appbeta = __datas[2:3][0]
        self.__appalpha = __datas[3:4][0]
        self.__appbuild = __datas[4:5][0]

        self.__apimain = __datas[5:6][0]
        self.__apibeta = __datas[6:7][0]
        self.__apialpha = __datas[7:8][0]
        self.__apibuild = __datas[8:9][0]

        self.__chipid = ''.join(["%02X " % x for x in __datas[9:13]]).strip()
        self.__chipversion = ''.join(["%02X " % x
                                      for x in __datas[13:17]]).strip()
        self.__desc = __datas[17:-1].decode(encoding='ASCII').strip()

    def __str__(self):
        strMsg = super(VersionMessage, self).__str__()
        strMsg += "\nApplication Version  : {0}.{1}.{2}.{3}".format(
            self.__appmain, self.__appbeta, self.__appalpha, self.__appbuild)
        strMsg += "\nAPI Version          : {0}.{1}.{2}.{3}".format(
            self.__apimain, self.__apibeta, self.__apialpha, self.__apibuild)
        strMsg += "\nChip ID              : {0}".format(self.__chipid)
        strMsg += "\nChip Version         : {0}".format(self.__chipversion)
        strMsg += "\nDescription          : {0}".format(self.__desc)
        return strMsg
Beispiel #4
0
class EnOceanMessage:

    _logger = get_logger('rhum.drivers.enocean.EnOceanMessage')
    __syncByte = 0x55

    def __init__(self, msgType=0xFF, datas=None, optDatas=None):
        self.__type = msgType
        self.__datas = []
        self.__optDatas = []

        if datas != None:
            self.__datas = datas

        if optDatas != None:
            self.__optDatas = optDatas

    def build(self):
        self._logger.debug('building message')
        buffer = []
        data_length = len(self.__datas)
        opt_length = len(self.__optDatas)

        #sync byte
        buffer.append(self.__syncByte)  # adding sync byte

        #header
        buffer.append((data_length >> 8) & 0xFF)  #first byte length data
        buffer.append(data_length & 0xFF)  #second byte length data
        buffer.append(opt_length & 0xFF)  #optionnal data length
        buffer.append(self.__type & 0xFF)  #packet type byte
        #CRC Header
        buffer.append(CRC8Utils.calc(buffer[1:5]))

        #data
        buffer += self.__datas
        buffer += self.__optDatas

        #CRC Data
        buffer.append(CRC8Utils.calc(buffer[6:]))

        self._logger.debug('buffer : {0}'.format(buffer))

        return buffer

    def _get(self):
        return self.__type, self.__datas, self.__optDatas

    def __str__(self):
        msg = ''.join(["\\x%02X" % x for x in bytes(self.build())]).strip()
        strMsg = "\nMessage              : {0}".format(msg)
        strMsg += "\nType                 : {0}".format(PacketType(
            self.__type))
        strMsg += "\nData Length          : {0}".format(len(self.__datas))
        strMsg += "\nOpt Length           : {0}".format(len(self.__optDatas))
        return strMsg
Beispiel #5
0
class Item:
    '''Item representation of all type of items'''

    __logger = get_logger('rhum.messages.item.Item')

    __type = None
    __value = None
    __id = None

    def __init__(self, itemType, itemId, itemValue=None):
        self.__type = itemType
        self.__id = itemId
        self.__value = itemValue
Beispiel #6
0
class RPSMessage(RadioERP1Message):

    _logger = get_logger('rhum.drivers.enocean.messages.radioerp1.RPSMessage')

    def __init__(self, __type, __datas, __opts):
        super(RPSMessage, self).__init__(__type, __datas, __opts)
        self.__data = ''.join(["%02X " % x for x in __datas[1:2]]).strip()
        self.__senderID = ''.join(["%02X " % x for x in __datas[2:6]]).strip()
        self.__status = ''.join(["%02X " % x for x in __datas[6:]]).strip()

    def __str__(self):
        strMsg = super(RPSMessage, self).__str__()
        strMsg += "\nSender ID            : {0}".format(self.__senderID)
        strMsg += "\nStatus               : {0}".format(self.__status)
        strMsg += "\nData                 : {0}".format(self.__data)
        return strMsg
Beispiel #7
0
class ResponseMessage(EnOceanMessage):

    _logger = get_logger('rhum.drivers.enocean.messages.ResponseMessage')

    def __init__(self, __type, __datas, __opts):
        super(ResponseMessage, self).__init__(__type, __datas, __opts)
        self.__returnCode = __datas[0:1][0]

    def isResponse(self):
        return (self._get()[0] == PacketType.RESPONSE.value)

    def getReturnCode(self):
        return ResponseType(self.__returnCode)

    def __str__(self):
        strMsg = super(ResponseMessage, self).__str__()
        strMsg += "\nResponse Return Code : {0}".format(
            ResponseType(self.__returnCode))
        return strMsg
Beispiel #8
0
class TypingMessage:

    _logger = get_logger('rhum.drivers.enocean.messages.TypingMessage')

    @classmethod
    def transform(cls, _type, _datas, _opts):

        msg = None
        if (PacketType(_type) == PacketType.RESPONSE):
            cls._logger.debug('receiving Response')
            msg = ResponseMessage(_type, _datas, _opts)
        elif (PacketType(_type) == PacketType.RADIO_ERP1):
            cls._logger.debug('receiving Radio ERP 1')
            msg = cls.__transformRadioERP1(_type, _datas, _opts)
        else:
            cls._logger.debug('receiving Unknow {0}'.format(PacketType(_type)))
            msg = EnOceanMessage(_type, _datas, _opts)

        return msg

    @classmethod
    def __transformRadioERP1(cls, _type, _datas, _opts):

        msg = RadioERP1Message(_type, _datas, _opts)
        if (RadioERP1Type.RPS == msg.getReturnType()):
            cls._logger.debug('receiving Radio ERP 1 : RPS')
            msg = RPSMessage(_type, _datas, _opts)
        elif (RadioERP1Type.BS1 == msg.getReturnType()):
            cls._logger.debug('receiving Radio ERP 1 : BS1')
            msg = BS1Message(_type, _datas, _opts)
        elif (RadioERP1Type.BS4 == msg.getReturnType()):
            cls._logger.debug('receiving Radio ERP 1 : BS4')
            msg = BS4Message(_type, _datas, _opts)

        else:
            cls._logger.debug('receiving Radio ERP 1 : {0}'.format(
                RadioERP1Type(_datas[0:1][0])))

        return msg
Beispiel #9
0
class BS4Message(RadioERP1Message):

    _logger = get_logger('rhum.drivers.enocean.messages.radioerp1.BS1Message')

    def __init__(self, __type, __datas, __opts):
        super(BS4Message, self).__init__(__type, __datas, __opts)
        self.__senderID = ''.join(["%02X " % x for x in __datas[5:9]]).strip()
        self.__status = ''.join(["%02X " % x for x in __datas[9:]]).strip()
        self.__data3 = ''.join(["%02X " % x for x in __datas[1:2]]).strip()
        self.__data2 = ''.join(["%02X " % x for x in __datas[2:3]]).strip()
        self.__data1 = ''.join(["%02X " % x for x in __datas[3:4]]).strip()
        self.__data0 = ''.join(["%02X " % x for x in __datas[4:5]]).strip()

    def __str__(self):
        strMsg = super(BS4Message, self).__str__()
        strMsg += "\nSender ID            : {0}".format(self.__senderID)
        strMsg += "\nStatus               : {0}".format(self.__status)
        strMsg += "\nData 0               : {0}".format(self.__data0)
        strMsg += "\nData 1               : {0}".format(self.__data1)
        strMsg += "\nData 2               : {0}".format(self.__data2)
        strMsg += "\nData 3               : {0}".format(self.__data3)
        return strMsg
Beispiel #10
0
class RhumDaemon(Daemon):
    __logger = get_logger('rhum.RhumDaemon')
    __driver_manager = DriverManager()

    def run(self):
        self.__load()
        while True:
            time.sleep(1)

    '''stop the daemon service'''

    def stop(self):
        self.__unload()
        return Daemon.stop(self)

    '''reload service method for deamon'''

    def reload(self):
        self.__unload()
        self.__load()

    '''Load driver manager to search and initiate drivers'''

    def __load(self):
        self.__logger.info('Loading service managers')
        self.__driver_manager.start()
        return True

    '''unloading threads correctly corresponding to drivers'''

    def __unload(self):
        self.__logger.info('Unloading service managers')
        self.__driver_manager.stop()
        if self.__driver_manager.isAlive():
            self.__driver_manager.join()
        return True
Beispiel #11
0
import sys
from rhum.rhumlogging import get_logger 
from rhum.rhum import RhumDaemon

_pid_file = '/tmp/daemon-rhum.pid'


if __name__ == "__main__":
    logger = get_logger('RHUM-MAIN')
    logger.debug('rhum service manager : ')
    
    daemon = RhumDaemon(_pid_file)
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            logger.info("Starting Rhum")
            daemon.start()
        elif 'stop' == sys.argv[1]:
            logger.info("Stopping Rhum")
            daemon.stop()
        elif 'restart' == sys.argv[1]:
            logger.info("Restarting Rhum")
            daemon.restart()
        elif 'reload' == sys.argv[1]:
            logger.info("Reloading Rhum")
            daemon.reload()
        else:
            logger.error("Unknow command of Rhum service")
            sys.exit(2)
        sys.exit(0)
    else:
        print("usage: {0} start|stop|restart".format(sys.argv[0]))
Beispiel #12
0
class DriverManager(Thread):
    ''' Driver Manager Class used to initiate the drivers '''
    _logger = get_logger('rhum.drivers.DriverManager')

    def __init__(self):
        super(DriverManager, self).__init__()
        # Create an event to stop the thread
        self.__stop = Event()
        self.__stop.clear()
        self.__drivers = []

    def stop(self):
        self.__stop.set()
        self._logger.info('stopping drivers')
        for driver in self.__drivers:
            driver.stop()
        #self.join()
        #drv.join()

    ''' driver Manager run '''

    def run(self):

        self._logger.info('initialize driver manager')

        #init the drivers searching
        self.__search_driver()

        for drv in self.__drivers:
            self._logger.info('starting driver {0}'.format(drv))
            drv.start()

        #while runing pause the manager in waiting command
        while not self.__stop.is_set():
            time.sleep(1)

    '''search and initiate driver manager'''

    def __search_driver(self):
        path = os.listdir(path='/dev/')
        tty = []
        for file in path:
            if file.find('AMA') != -1:
                tty.append(file)
            elif file.find('USB') != -1:
                tty.append(file)

        self._logger.debug('List tty')
        self._logger.debug(len(tty))
        '''test each tty port to connect with each driver'''
        for port_path in tty:
            path = '/dev/{0}'.format(port_path)
            self._logger.debug('test EnOcean Driver for {0}'.format(path))
            drive = EnOceanDriver(path)
            if drive.test():
                self._logger.info(
                    'EnOcean Driver selected for {0}'.format(path))
                self.__drivers.append(drive)
                continue

            self._logger.info('No Driver selected for {0}'.format(path))

        return True
Beispiel #13
0
class _CRC8:
    
    _logger = get_logger('rhum.utils.crc8')

    # CRC8 encode table will keep the calculated CRC8 of each byte to prevent multi calculation
    _crc8Encode = [
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        ]
    
    # #####
    # Internal method used to calculate the CRC8 for one byte
    #  and keep it in the corresponding entry of "crc8Encode"
    # ex: calculCRC8(0) will keep 0x00 in crc8Encode[0]
    def _calculCRC8(self,byte):
        self._logger.debug('no value in table for {0}'.format(byte))
        crc = byte;
        for j in range(0,8):
            self._logger.debug('run {0}'.format(j))
            crc = (crc << 1) ^ (0x07 if (crc & 0x80) else 0)
        self._crc8Encode[byte] = crc & 0xFF
        self._logger.debug('calculated value {0} for byte {1}'.format(self._crc8Encode[byte], byte))
    
    # #####
    # This method calculate the CRC8 of a byte array and return the result
    def calc(self, byte):
        crc = 0
        for c in byte:
            crcByte = crc & 0xFF ^ c & 0xFF
            if self._crc8Encode[crcByte] == -1:
                self._calculCRC8(crcByte)
            crc = self._crc8Encode[crcByte]
        self._logger.debug('message : {0} ; crc : {1}'.format(byte, crc))
        return crc
    
    # #####
    # This method convert any type of message to a byte array and return the result of
    # CRC8.calc with this byte array
    def calcAllTypes(self,msg):
        byte = []
        
        if type(msg) is list:
            byte = bytearray(msg)
        elif type(msg) is int:
            byte = msg.to_bytes((msg.bit_length() + 7) // 8, "big")
        else:
            byte = bytearray(str(msg), 'utf-8')
        return self.calc(byte)
        
    # #####
    # This method calculate the CRC8 of the message and return the result of CRC(msg) = crc
    def check(self, msg, crc):
        self._logger.debug('message to check : "{0}" against {1}'.format(msg, crc))
        test = self.calcAllTypes(msg)
        return (test == crc)
Beispiel #14
0
import sys
from rhum.rhumlogging import get_logger
from rhum.rhum import RhumDaemon

_pid_file = '/tmp/daemon-rhum.pid'

if __name__ == "__main__":
    logger = get_logger('RHUM-MAIN')
    logger.debug('rhum service manager : ')

    daemon = RhumDaemon(_pid_file)
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            logger.info("Starting Rhum")
            daemon.start()
        elif 'stop' == sys.argv[1]:
            logger.info("Stopping Rhum")
            daemon.stop()
        elif 'restart' == sys.argv[1]:
            logger.info("Restarting Rhum")
            daemon.restart()
        elif 'reload' == sys.argv[1]:
            logger.info("Reloading Rhum")
            daemon.reload()
        else:
            logger.error("Unknow command of Rhum service")
            sys.exit(2)
        sys.exit(0)
    else:
        print("usage: {0} start|stop|restart".format(sys.argv[0]))
        sys.exit(2)
Beispiel #15
0
class EnOceanDriver(Driver):
    
    _logger = get_logger('rhum.driver.enocean.EnOceanDriver')
    
    def __init__(self, port='/dev/ttyAMA0', callback=None):
        super(EnOceanDriver, self).__init__(callback)
        # Initialize serial port
        self.__buffer = []
        self.__port = port
        self._logger.debug('initialize connection to '.format(port))
        self.__connection = serial.Serial(self.__port, 57600, timeout=0)
        
    def stop(self):
        Driver.stop(self)
        self.__connection.close()
        self._logger.info('EnOcean Driver on {0} stopped'.format(self.__port))
        
    def run(self):
        self._logger.info('EnOcean Driver started on {0}'.format(self.__port))
        while not self._stop.is_set():
            # Read chars from serial port as hex numbers
            try:
                msg = self.parse()
                __type, __datas, __opts = msg._get()
                
                msg = TypingMessage.transform(__type, __datas, __opts)
                
                self._logger.info(msg)
            except serial.SerialException:
                self._logger.error('Serial port exception! (device disconnected or multiple access on port?)')
                break
            except Exception:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
                for line in lines:
                    self._logger.error(line)
            
        
    def test(self):
        msg = EnOceanMessage(PacketType.COMMON_COMMAND.value, [CommonCommandType.CD_R_VERSION.value])
        buffer = msg.build()
        self._logger.debug('EnOcean Driver message {0}'.format(buffer))
        self._logger.debug(self.__connection.isOpen())
        
        #for index in range(len(buffer)):
            #byte by byte tx
        buffer = bytes(buffer)
        self._logger.debug('writing byte {0}'.format(buffer))
        self.__connection.write(buffer)
            
        try:
            self._logger.debug('ask for parsing data')
            msg = self.parse()
            msg = VersionMessage(msg._get()[0], msg._get()[1], msg._get()[2])
            self._logger.info('EnOcean Test Message (Version)')
            self._logger.info(msg)
            
            if msg.isResponse() and msg.getReturnCode() == ResponseType.RET_OK:
                return True
            
        except Exception:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
            for line in lines:
                self._logger.error(line)
        
        self.__connection.close()
        return False
    
    def parse(self):
        Driver.parse(self)
        self._logger.debug('parsing data')
        msg = self._getSerialData()
        
        if isinstance(msg, EnOceanMessage):
            return msg
        
        raise Exception('No message parsed')
        
 
    def _getSerialData(self):
        
        self._logger.debug('searching for sync byte') 
        s = 0
        while s != b'\x55':
            if self.__connection.inWaiting() != 0:
                s = self.__connection.read(1)
     
        self._logger.debug('sync byte found')
        while self.__connection.inWaiting() < 5:  
            ()
            
        header = self.__connection.read(4) #read header fields
        headerCRC = self.__connection.read(1)[0] #read header crc field
        
        self._logger.debug('header reading : {0} and crc : {1}'.format(header, headerCRC))
         
 
        if (CRC8Utils.calc(header) == headerCRC):
            
            self._logger.debug('header CRC OK')
            data_length, opt_length, msgType = struct.unpack("!HBB", header)
            
            self._logger.debug('data_length {0}; opt_length {1}; msg_type {2}'.format( data_length, opt_length, msgType ))    
            totalDataLength = data_length + opt_length

            while self.__connection.inWaiting() < totalDataLength+1:  
                ()
            
            datas = self.__connection.read(data_length)                
            opts = self.__connection.read(opt_length)
            dataCRC = self.__connection.read(1)
            
            self._logger.debug('datas {0}; opts {1}; dataCRC {2}'.format( datas, opts, dataCRC ))
            
            if(self._logger.isEnabledFor(logging.DEBUG)):
                msg = header
                msg += bytes({headerCRC})
                msg += datas
                msg += opts
                msg += dataCRC
                self._logger.debug(msg) 
            
                
            if (CRC8Utils.calc(datas+opts) == dataCRC[0]): 
                return EnOceanMessage(msgType, datas, opts)    
            return "Data CRC Failed"
        return "Header CRC Failed"