sensord/sensord/RFM69receiver.py
2019-10-07 18:58:28 +02:00

150 lines
4.7 KiB
Python

"""
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)