''' Created on 11.06.2015 @author: wn ''' import MeterbusTypeConversion class MeterbusLibException(Exception): pass class InvalidFrameCodeException(MeterbusLibException): pass class InvalidFrameException(MeterbusLibException): pass class InvalidChecksumException(MeterbusLibException): pass class InvalidStopCharException(MeterbusLibException): pass class InvalidStartCharException(MeterbusLibException): pass class InvalidLengthException(MeterbusLibException): pass class InvalidSecondLengthException(MeterbusLibException): pass class PayloadTooShortException(MeterbusLibException): pass class Frame(object): def __init__(self, startCharacter, frameLength, firstPayload, telegram): self.telegram = telegram self.frameName = self.__class__.__name__ self.frameLength = frameLength self.payloadLength = self.frameLength - 6 self.frameStartCharacter = startCharacter self.firstPayload = firstPayload def parse(self): if self.telegram[0] != self.frameStartCharacter: raise InvalidStartCharException() if len(self.telegram) != self.frameLength: raise InvalidLengthException() self.verifyChecksumAndEnd() self.parse2() def verifyChecksumAndEnd(self): if (self.firstPayload != 0): checksum = sum(self.telegram[self.firstPayload:-2]) & 0xff if checksum != self.telegram[-2]: raise InvalidChecksumException() if self.telegram[-1] != 0x16: raise InvalidStopCharException() def parse2(self): raise NotImplementedError def getJSON(self): raise NotImplementedError class SingleCharacter(Frame): def __init__(self, telegram): super(SingleCharacter, self).__init__(0xe5, 1, 0, telegram) def parse2(self): pass class ShortFrame(Frame): def __init__(self, telegram): super(ShortFrame, self).__init__(0x10, 5, 1, telegram) def parse2(self): self.cField = self.telegram[1] self.address = self.telegram[2] class ControlFrame(Frame): def __init__(self, telegram): super(ControlFrame, self).__init__(0x68, (telegram[1] + 6), 4, telegram) def parse2(self): if self.telegram[2] != self.payloadLength: raise InvalidSecondLengthException if self.payloadLength < 3: raise PayloadTooShortException("too short for c, a, ci fields") self.cField = self.telegram[4] self.address = self.telegram[5] self.ciField = self.telegram[6] class LongFrame(ControlFrame): class FixedDataHeader(object): def __init__(self, data): self.data = data print("Fixed header length: %d" % len(self.data)) def parse(self): self.identNr = MeterbusTypeConversion.bcd(self.data[:4]) self.manufacturer = self.data[4:6] self.version = self.data[6] self.medium = self.data[7] self.accessNo = self.data[8] self.status = self.data[9] self.signature = self.data[10:] def parse2(self): super(LongFrame, self).parse2() if self.payloadLength < 3 + 12: raise PayloadTooShortException("too short for fixed data header") self.fixedDataHeader = LongFrame.FixedDataHeader(self.telegram[7:19]) self.fixedDataHeader.parse() class Telegram(object): def __init__(self): pass def fromHexString(self, hexString): self.hexString = hexString octetList = [int(o, 16) for o in self.hexString.split(' ')] self.telegram = bytearray(octetList) for i in self.telegram: print(int(i)) def toHexString(self): return str([hex(b) for b in self.telegram]) def parse(self): if self.telegram[0] == 0x68 and self.telegram[1] == 0x03: self.frame = ControlFrame(self.telegram) elif self.telegram[0] == 0x68: self.frame = LongFrame(self.telegram) elif self.telegram[0] == 0x10: self.frame = ShortFrame(self.telegram) elif self.telegram[0] == 0xe5: self.frame = SingleCharacter(self.telegram) else: raise InvalidStartCharException() self.frame.parse() print("Frame is %s" % self.frame)