sensord/sensord/RFM69receiver.py

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)