160 lines
5 KiB
Python
160 lines
5 KiB
Python
"""
|
|
rfm69receiver - A RFM69 433MHz Receiver Using the Observer Pattern
|
|
"""
|
|
|
|
import time
|
|
import struct
|
|
from pprint import pprint, pformat
|
|
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, debug=False):
|
|
""" 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
|
|
self.__debug = debug
|
|
|
|
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 _debug(self, message):
|
|
""" Print Debug Output """
|
|
if self.__debug:
|
|
print('[' + time.strftime('%H:%M:%S %d %b %Y') + '][DBG] ', end='')
|
|
print(message)
|
|
|
|
def _process(self, sid, rdata, 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
|
|
|
|
try:
|
|
data = rdata.decode("ascii")
|
|
except UnicodeDecodeError:
|
|
data = ""
|
|
|
|
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:
|
|
self._debug("Interpreting " + str(len(rdata)) + " Bytes of Binary Data from " + str(sid) + ": " + pformat(rdata))
|
|
if len(rdata) == 9:
|
|
voltage, temp, humidity = struct.unpack('<Bll', rdata)
|
|
msg['v'] = voltage*20/1000
|
|
msg['t'] = temp/100
|
|
msg['h'] = humidity/100
|
|
elif len(rdata) == 13:
|
|
voltage, temp, humidity, pressure = struct.unpack('<Blll', rdata)
|
|
msg['v'] = voltage*20/1000
|
|
msg['t'] = temp/100
|
|
msg['h'] = humidity/100
|
|
msg['p'] = pressure/100
|
|
elif len(rdata) == 16:
|
|
temp, pressure, humidity, voltage = struct.unpack('<llll', rdata)
|
|
msg['t'] = temp/100
|
|
msg['p'] = pressure/100
|
|
msg['h'] = humidity/100
|
|
msg['v'] = voltage/1000
|
|
else:
|
|
self._debug("Unknown data Format, could not decode!")
|
|
|
|
if (msg['v'] < 4 and msg['h'] <= 100):
|
|
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
|
|
rdata = bytes(self.__rfm.DATA)
|
|
|
|
if self.__rfm.ACKRequested():
|
|
self.__rfm.sendACK()
|
|
|
|
if rssi != 0:
|
|
self._process(sid, rdata, 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') + '][NFO] Message Received: ', end='')
|
|
pprint(msg)
|