""" NMEA2000-Gerät - auf dem Bus erkannte Geräte - für das eigene Gerät steht initUid() zur Verfügung TODO - logging """ import time import struct from . import lookup class Device(): def __init__(self, address): # WIP: Felder können sich noch ändern! self.address = address # Kann sich zur Laufzeit ändern self.lastseen = time.time() self.lastpinfo = None # Wann letztes Mal Productinfo erhalten? self.lastcinfo = None # Wann letztes Mal Configurationinfo erhalten? self.has_cinfo = True # Weitere Abfragen können verhindert werden # Device info self.NAME = 0 # Wird über getNAME (address claim) gefüllt, 64bit Integer self.uniqueid = None # Z.B. aus der Geräteseriennummer abgeleitet self.manufacturercode = 2046 # Open Boat Projects self.instance = 0 # default 0 self.instlower = 0 # 3bit, ISO ECU Instance self.instupper = 0 # 5bit, ISO Function Instance self.sysinstance = 0 # used with bridged networks, default 0 self.industrygroup = None self.devicefunction = None self.deviceclass = None # Product info self.product = None # Product name self.productcode = None # Product code self.serial = None self.modelvers = None # Hardware Version self.softvers = None # Current Software Version self.n2kvers = None # NMEA2000 Network Message Database Version self.certlevel = None # NMEA2000 Certification Level self.loadequiv = None # NMEA2000 LEN # Configuration info self.instdesc1 = None self.instdesc2 = None self.manufinfo = None # Additional data self.customname = None # User defined device name def _ISOtime(self, epoch): if not epoch: return "n/a" return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(epoch)) def initUid(self): # Initialize unique id from raspi cpu id and return 21bit value with open("/sys/firmware/devicetree/base/serial-number", "r") as f: hexid = f.read().rstrip('\x00') return int(hexid, 16) & 0x001FFFFF # 21bit mask def getNAME(self): """ NAME is unique on bus Returns bytearray and sets integer NAME for later easy and fast access """ data = bytearray() data.extend(struct.pack(' 0.25: # recv ist blocking. if timeout reached msg should be None msg = bus.recv(0.25) if msg: baseid = (msg.arbitration_id & 0x3ffff00) >> 8 pgn = baseid & 0xffff00 if not pgn == 60928: continue dest = baseid & 0x0000ff if dest == 0xff: print("Claim detected for 0xff (broadcast)") if self.NAME > struct.unpack_from(' 0.25): print("claim seems ok after 250ms") return claim_ok def __str__(self): out = f"Device: {self.address} : '{self.product}'\n" out += " NAME: {} ({})\n".format(self.getNAME(), self.NAME) out += " last seen: {}\n".format(self._ISOtime(self.lastseen)) out += " Device info\n" out += f" Unique ID: {self.uniqueid}\n" out += f" Instance: {self.instance} ({self.instupper}/{self.instlower})\n" out += f" System instance: {self.sysinstance}\n" try: devfnname = lookup.devicefunction[self.deviceclass][self.devicefunction] except KeyError: devfnname = "*key error*" out += f" Device function: {devfnname} ({self.devicefunction})\n" try: devclassname = lookup.deviceclass[self.deviceclass] except KeyError: devclassname = "*key error*" out += f" Device class: {devclassname} ({self.deviceclass})\n" try: igrpname = lookup.industrygroup[self.industrygroup] except KeyError: igrpname = "*key error*" out += f" Industry group: {igrpname} ({self.industrygroup})\n" try: manufname = lookup.manufacturer[self.manufacturercode] except KeyError: manufname = "*key error*" out += f" Manufacturer code: {manufname} ({self.manufacturercode})\n" out += " Product info at {}\n".format(self._ISOtime(self.lastpinfo)) out += f" Product Code: {self.productcode}\n" out += f" Product: {self.product}\n" out += f" Serial: {self.serial}\n" out += f" Model Version: {self.modelvers}\n" out += f" Software Version: {self.softvers}\n" out += f" NMEA2000 Version: {self.n2kvers}\n" out += f" Cert-Level: {lookup.certlevel[self.certlevel]} ({self.certlevel})\n" out += f" LEN: {self.loadequiv}\n" out += " Configuration info at {}\n".format(self._ISOtime(self.lastcinfo)) if self.has_cinfo: out += f" Installation description 1: {self.instdesc1}\n" out += f" Installation description 2: {self.instdesc2}\n" out += f" Manufacturer info: {self.manufinfo}\n" else: out += " not available\n" return out