# -*- coding:utf8 -*- import asynchat import asyncore import socket import sys #import json # Master-Master # 1 quell # 1 ziel # 1 1primaerbefehl # 1 sekundaerbefehl # 1 n=laenge (bytes) # n daten.... # 1 CRC # 1 ack (=0x00 || 0xff) # 1 syn (=0xaa) # Master-Slave # 1 quell # 1 ziel # 1 1primaerbefehl # 1 sekundaerbefehl # 1 n=laenge (bytes) # n daten vom master/Anfrage.... # 1 CRC # 1 ack (=0x00 || 0xff) # 1 m=länge (bytes) # m daten vom slave/Antwort... # 1 syn (=0xaa) deviceDescription = [ {'address':0x03, 'type':'master', 'description':'Feuerungsautomat'}, {'address':0x10, 'type':'master', 'description':'Heizungsregler #2'}, {'address':0x30, 'type':'master', 'description':'Heizkreisregler 1'}, {'address':0x70, 'type':'master', 'description':'Heizkreisregler 2'}, {'address':0x71, 'type':'master', 'description':'Heizungsregler #9'}, {'address':0xf1, 'type':'master', 'description':'Heizungsregler #10'}, {'address':0x50, 'type':'slave', 'description':'Mischer 1'}, {'address':0x51, 'type':'slave', 'description':'Mischer 2'}, {'address':0x90, 'type':'slave', 'description':'Raumgeräte/Fernsteller 1'}, {'address':0x90, 'type':'slave', 'description':'Raumgeräte/Fernsteller 2'}, {'address':0xfe, 'type':'broadcast', 'description':'Broadcast'}, ] packetDescription = [ # Service 0x05 (Brennersteuerbefehle) {'primary':0x5, 'secondary':0x3, 'name':'Betriebsdaten des Feuerungsautomaten an den Regler Block1'}, {'primary':0x5, 'secondary':0x7, 'name':'Betriebsdaten des Reglers an den Feuerungsautomaten'}, # Service 0x07 (Systemdatenbefehle) {'primary':0x7, 'secondary':0x0, 'name':'Datum/Zeit - Meldung eines eBUS Masters'}, {'primary':0x7, 'secondary':0x4, 'name':'Identifikation'}, # Service 0x08 (Reglerbefehle) {'primary':0x8, 'secondary':0x0, 'name':'Sollwertübertragung des Reglers an andere Regler'}, # Response #p[0] = Einheit (1=>Liter, 2=>Kubik) #p[1] = 10^0 #p[2] = 10^2 #p[3] = 10^4 #p[4] = 10^6 {'primary':0x3, 'secondary':0x8, 'name':'Gesamtbrennstoffmengenzähle lesen'}, {'primary':''}, ] def formatHex(data): return " ".join(map(lambda byte: "%.2x"%ord(byte), data)) def getDsc(address): dev=filter(lambda dev: dev['address'] == address, deviceDescription) if len(dev)>0: return dev[0]['description'] else: return None class EbusPacket(object): def __init__(self, source, destination, primary_command, secondary_command): self.source = source self.destination = destination self.primary_command = primary_command self.secondary_command = secondary_command def name(self): desc = filter(lambda p: p['primary'] == self.primary_command \ and p['secondary'] == self.secondary_command, packetDescription) if len(desc) > 0: return desc[0]['name'] else: return "UNKNOWN" def __str__(self): return "<%-18s name=\"%-15s\" source=\"%s\" destination=\"%s\" primary=0x%x secondary=0x%x length=0x%x>" % \ (self.__class__.__name__, self.name(), getDsc(self.source), getDsc(self.destination), \ self.primary_command, self.secondary_command, self.length) class EbusMasterMaster(EbusPacket): def __init__(self, source, destination, primary_command, secondary_command, data): EbusPacket.__init__(self, source, destination, primary_command, secondary_command) self.length = len(data) self.data = data class EbusMasterSlave(EbusPacket): def __init__(self, source, destination, primary_command, secondary_command, request, response): EbusPacket.__init__(self, source, destination, primary_command, secondary_command) self.length = len(request) self.request = request self.response = response class EbusBroadcast(EbusPacket): def __init__(self, source, destination, primary_command, secondary_command, data): EbusPacket.__init__(self, source, destination, primary_command, secondary_command) self.length = len(data) self.data = data class Fetcher(asynchat.async_chat): def __init__(self): self.buffer = "" asynchat.async_chat.__init__(self) self.set_terminator("") self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect(("10.2.2.200", 7970)) self.packetIndex = 0 self.buf = "" def collect_incoming_data(self,data): for it in range(len(data)): if data[it] == "\xaa": if it+1 < len(data) and data[it+1] != "\xaa": self._parse(self.buf) self.buf = "" self.packetIndex = 0 else: self.buf += data[it] self.packetIndex = self.packetIndex + 1 #print "%.2x [%d]" % (ord(data[it]),self.packetIndex) def _parse(self,data): if len(data) < 2: print "GAGA" return source = ord(data[0]) destination = ord(data[1]) sourceDevice = filter(lambda dev: dev['address'] == source, deviceDescription) destinationDevice = filter(lambda dev: dev['address'] == destination, deviceDescription) if len(sourceDevice) == 0 or len(destinationDevice) == 0: print "Unbekanntes Paket: source=%x destination=%x" % (source, destination) return if len(data) < 9: print "Unvollständige Daten" return primaryCommand = ord(data[2]) secondaryCommand = ord(data[3]) payloadLength = ord(data[4]) payload = data[5:6+payloadLength] #delete 0x50 packets for devel if (primaryCommand == ord("\x50")): return #print "PR SC NN D0 D1 D2 D3 D4 D5 D6 D7 ..." #print "%.2x" % (primaryCommand,) #print "%.2x %.2x %.2x %s" % (primaryCommand,secondaryCommand,payloadLength,"bla") #print "%.2x %.2x %.2x %s" % (primaryCommand,secondaryCommand,payloadLength,formatHex(payload)) p = None if sourceDevice[0]['type'] == 'master' and destinationDevice[0]['type'] == 'master': p = EbusMasterMaster(source, destination, primaryCommand, secondaryCommand, payload) print p print "payload=%s" % formatHex(payload) elif sourceDevice[0]['type'] == 'master' and destinationDevice[0]['type'] == 'slave': p = EbusMasterSlave(source, destination, primaryCommand, secondaryCommand, payload, None) print p print "payload=%s" % formatHex(payload) elif sourceDevice[0]['type'] == 'master' and destinationDevice[0]['type'] == 'broadcast': p = EbusBroadcast(source, destination, primaryCommand, secondaryCommand, payload) print p print "payload=%s" % formatHex(payload) else: print "KOMISCHES ZEUG" return print "" Fetcher() asyncore.loop()