""" rfm69receiver - A RFM69 433MHz Receiver Using the Observer Pattern """ import time import struct from pprint import pprint import RFM69 from RFM69registers import RF69_433MHZ class RFM69Receiver(object): """ Receives Messages from a RFM69 Wireless SPI Transceiver and Can Notify Multiple Observers to Process the Messages """ def __init__(self, nodeID, netID, encKey=None): """ Initialize the Transceiver Module Arguments: nodeID: ID of the Node in the Network, typically 1 for the Receiver, between 1 and 255 netID: Network ID, all Nodes must use the same ID to communicate, between 1 and 255 encKey: 16 byte Encryption Key (AES-128). If None no encryption is used """ self.__observers = [] self.__running = False self.__lastsid = None self.__lastts = 0 try: print("Initializing RFM69 Module as Node " + str(nodeID) + " on Network " + str(netID)) self.__rfm = RFM69.RFM69(RF69_433MHZ, nodeID, netID, False, rstPin=22) self.__rfm.rcCalibration() if encKey != None: self.__rfm.encrypt(encKey) except: print("ERROR: Could not Initialize RFM69 Module") raise RuntimeError def __del__(self): """ Free the Receiver Module Resources on Exit """ print("Shutting Down RFM69 Module") self.__rfm.shutdown() def _rawbytes(self, s): """Convert a string to raw bytes without encoding""" outlist = [] for cp in s: num = ord(cp) if num < 255: outlist.append(struct.pack('B', num)) elif num < 65535: outlist.append(struct.pack('>H', num)) else: b = (num & 0xFF0000) >> 16 H = num & 0xFFFF outlist.append(struct.pack('>bH', b, H)) return b''.join(outlist) def _process(self, sid, data, rssi): """ Process received Data and Notify Registered Observers Arguments: sid: NodeID of the Sending Sensor data: Data String or byte array rssi: Signal Strength Indicator """ if self.__lastsid == sid and (time.time() - self.__lastts) < 10: self.__lastsid = sid self.__lastts = time.time() return self.__lastsid = sid self.__lastts = time.time() msg = {} msg['sid'] = sid msg['rssi'] = rssi if (data.find(';') != -1 and data.find('=') != -1): values = data.split(";") for value in values: vsplit = value.split("=") if vsplit[0] == "t" or vsplit[0] == "h" or vsplit[0] == "p": msg[vsplit[0]] = int(vsplit[1].rstrip())/100 elif vsplit[0] == "v": msg[vsplit[0]] = int(vsplit[1].rstrip())/1000 else: msg[vsplit[0]] = int(vsplit[1].rstrip()) else: bdata = self._rawbytes(data) msg['t'] = int.from_bytes(bdata[0:3], byteorder='little', signed=True)/100 msg['p'] = int.from_bytes(bdata[4:7], byteorder='little', signed=True)/100 msg['h'] = int.from_bytes(bdata[8:11], byteorder='little', signed=True)/100 msg['v'] = int.from_bytes(bdata[12:15], byteorder='little', signed=True)/1000 for observer in self.__observers: observer.notify(msg) def attach_observer(self, obs): """ Add an Object to the List of Known Observers """ self.__observers.append(obs) def clear_observers(self): """ Delete all Known Observers """ self.__observers.clear() def run(self): """ Start the Receiving Loop """ self.__running = True while self.__running: self.__rfm.receiveBegin() while not self.__rfm.receiveDone(): time.sleep(.1) sid = self.__rfm.SENDERID rssi = self.__rfm.RSSI data = "" for char in self.__rfm.DATA: data += chr(char) if self.__rfm.ACKRequested(): self.__rfm.sendACK() if rssi != 0: self._process(sid, data, rssi) def stop(self): """ Stop the Receiving Loop """ self.__running = False class LogConsole(object): """ This is an Example Observer Class That Logs received Sensor Data to STDOUT """ def __init__(self): """ NOOP, does nothing """ pass @staticmethod def notify(msg): """ Pretty-Print the received Data """ print('[' + time.strftime('%H:%M:%S %d %b %Y') + '] Message Received: ', end='') pprint(msg)