class BaseLogger(object): """ BaseLogger class receives sensor messages and writes them to the database. """ def __init__(self, bif=None, dbfile=DBFILE): """ create a new BaseLogger and connect it to the sensor source (bif) and the database (dbfile). """ self.engine = create_engine(dbfile, echo=False) init_model(self.engine) self.metadata = Base.metadata if bif is None: self.bif = BaseIF("sf@localhost:9002") else: self.bif = bif def create_tables(self): """ create any missing tables using sqlalchemy """ self.metadata.create_all(self.engine) # TODO: follow the instructions at url: # https://alembic.readthedocs.org/en/latest/tutorial.html#building-an-up-to-date-database-from-scratch # to write an alembic version string session = Session() if session.query(SensorType).get(0) is None: raise Exception("SensorType must be populated by alembic " + "before starting BaseLogger") session.close() def send_ack(self, seq=None, dest=None): """ send acknowledgement message """ ack_msg = AckMsg() ack_msg.set_seq(seq) ack_msg.set_node_id(dest) self.bif.sendMsg(ack_msg, dest) LOGGER.debug("Sending Ack %s to %s" % (seq, dest)) def store_state(self, msg): """ receive and process a message object from the base station """ # get the last source if msg.get_special() != Packets.SPECIAL: raise Exception("Corrupted packet - special is %02x not %02x" % (msg.get_special(), Packets.SPECIAL)) try: session = Session() current_time = datetime.utcnow() node_id = msg.getAddr() parent_id = msg.get_ctp_parent_id() seq = msg.get_seq() node = session.query(Node).get(node_id) loc_id = None if node is None: add_node(session, node_id) else: loc_id = node.locationId pack_state = PackState.from_message(msg) if duplicate_packet(session=session, receipt_time=current_time, node_id=node_id, localtime=msg.get_timestamp()): LOGGER.info( "duplicate packet %d->%d, %d %s" % (node_id, parent_id, msg.get_timestamp(), str(msg))) #send acknowledgement to base station to fwd to node self.send_ack(seq=seq, dest=node_id) return # write a node state row node_state = NodeState(time=current_time, nodeId=node_id, parent=parent_id, localtime=msg.get_timestamp(), seq_num=seq) session.add(node_state) for i, value in pack_state.d.iteritems(): if (msg.get_amType() == Packets.AM_BNMSG and i not in [Packets.SC_VOLTAGE]): type_id = i + BN_OFFSET # TODO: ideally should be a flag in datbase or something else: type_id = i session.add( Reading(time=current_time, nodeId=node_id, typeId=type_id, locationId=loc_id, value=value)) session.commit() #send acknowledgement to base station to fwd to node self.send_ack(seq=seq, dest=node_id) LOGGER.debug("reading: %s, %s" % (node_state, pack_state)) except Exception as exc: session.rollback() LOGGER.exception("during storing: " + str(exc)) finally: session.close() def run(self): """ run - main loop At the moment this is just receiving from the sensor message queue and processing the message. """ try: while True: # wait up to 30 seconds for a message try: msg = self.bif.queue.get(True, 30) self.store_state(msg) except Empty: pass except Exception as exc: LOGGER.exception("during receiving or storing msg: " + str(exc)) except KeyboardInterrupt: self.bif.finishAll()
class BaseLogger(object): """ BaseLogger class receives sensor messages and writes them to the database. """ def __init__(self, bif=None, dbfile=DBFILE): """ create a new BaseLogger and connect it to the sensor source (bif) and the database (dbfile). """ self.engine = create_engine(dbfile, echo=False) init_model(self.engine) self.metadata = Base.metadata if bif is None: self.bif = BaseIF("sf@localhost:9002") else: self.bif = bif def create_tables(self): """ create any missing tables using sqlalchemy """ self.metadata.create_all(self.engine) # TODO: follow the instructions at url: # https://alembic.readthedocs.org/en/latest/tutorial.html#building-an-up-to-date-database-from-scratch # to write an alembic version string session = Session() if session.query(SensorType).get(0) is None: raise Exception("SensorType must be populated by alembic " + "before starting BaseLogger") session.close() def send_ack(self, seq=None, dest=None): """ send acknowledgement message """ ack_msg = AckMsg() ack_msg.set_seq(seq) ack_msg.set_node_id(dest) self.bif.sendMsg(ack_msg, dest) LOGGER.debug("Sending Ack %s to %s" % (seq, dest)) def store_state(self, msg): """ receive and process a message object from the base station """ # get the last source if msg.get_special() != Packets.SPECIAL: raise Exception("Corrupted packet - special is %02x not %02x" % (msg.get_special(), Packets.SPECIAL)) try: session = Session() current_time = datetime.utcnow() node_id = msg.getAddr() parent_id = msg.get_ctp_parent_id() seq = msg.get_seq() node = session.query(Node).get(node_id) loc_id = None if node is None: add_node(session, node_id) else: loc_id = node.locationId pack_state = PackState.from_message(msg) if duplicate_packet(session=session, receipt_time=current_time, node_id=node_id, localtime=msg.get_timestamp()): LOGGER.info("duplicate packet %d->%d, %d %s" % (node_id, parent_id, msg.get_timestamp(), str(msg))) #send acknowledgement to base station to fwd to node self.send_ack(seq=seq, dest=node_id) return # write a node state row node_state = NodeState(time=current_time, nodeId=node_id, parent=parent_id, localtime=msg.get_timestamp(), seq_num=seq) session.add(node_state) for i, value in pack_state.d.iteritems(): if (msg.get_amType() == Packets.AM_BNMSG and i not in [Packets.SC_VOLTAGE]): type_id = i + BN_OFFSET # TODO: ideally should be a flag in datbase or something else: type_id = i session.add(Reading(time=current_time, nodeId=node_id, typeId=type_id, locationId=loc_id, value=value)) session.commit() #send acknowledgement to base station to fwd to node self.send_ack(seq=seq, dest=node_id) LOGGER.debug("reading: %s, %s" % (node_state, pack_state)) except Exception as exc: session.rollback() LOGGER.exception("during storing: " + str(exc)) finally: session.close() def run(self): """ run - main loop At the moment this is just receiving from the sensor message queue and processing the message. """ try: while True: # wait up to 30 seconds for a message try: msg = self.bif.queue.get(True, 30) self.store_state(msg) except Empty: pass except Exception as exc: LOGGER.exception("during receiving or storing msg: " + str(exc)) except KeyboardInterrupt: self.bif.finishAll()
class BaseLogger(object): """ BaseLogger class receives sensor messages and writes them to the database. """ def __init__(self, bif=None, dbfile=DBFILE): """ create a new BaseLogger and connect it to the sensor source (bif) and the database (dbfile). """ self.engine = create_engine(dbfile, echo=False) #init_model(self.engine) models.initialise_sql(self.engine) #self.metadata = Base.metadata if bif is None: self.bif = BaseIF("sf@localhost:9002") else: self.bif = bif self.log = logging.getLogger("baselogger") self.running = True def create_tables(self): """ create any missing tables using sqlalchemy """ #self.metadata.create_all(self.engine) # TODO: follow the instructions at url: # https://alembic.readthedocs.org/en/latest/tutorial.html#building-an-up-to-date-database-from-scratch # to write an alembic version string session = meta.Session() models.populateData.init_data(session) if session.query(SensorType).get(0) is None: raise Exception("SensorType must be populated by alembic " + "before starting BaseLogger") session.close() def send_ack(self, seq=None, dest=None): """ send acknowledgement message """ ack_msg = AckMsg() ack_msg.set_seq(seq) ack_msg.set_node_id(dest) self.bif.sendMsg(ack_msg, dest) self.log.debug("Sending Ack %s to %s" % (seq, dest)) def booted_node(self, msg): """Receieve and process a boot message object from the base station """ if msg.get_special() != Packets.SPECIAL: raise Exception("Corrupted packet - special is %02x not %02x" % (msg.get_special(), Packets.SPECIAL)) try: session = Session() current_time = datetime.utcnow() node_id = msg.getAddr() clustered = msg.get_clustered() version = msg.get_version() version = "".join([chr(i) for i in version]) node = session.query(Node).get(node_id) if node is None: add_node(session, node_id) b = NodeBoot(time=current_time, nodeId=node_id, clustered=clustered, version=version) session.add(b) session.flush() self.log.debug("boot: %s %s, %s, %s" % (current_time, node_id, clustered, version)) session.commit() except Exception as exc: session.rollback() self.log.exception("error during storing (boot): " + str(exc)) finally: session.close() return True def store_state(self, msg): """ receive and process a message object from the base station """ if msg.get_special() != Packets.SPECIAL: raise Exception("Corrupted packet - special is %02x not %02x" % (msg.get_special(), Packets.SPECIAL)) try: session = Session() current_time = datetime.utcnow() node_id = msg.getAddr() parent_id = msg.get_ctp_parent_id() seq = msg.get_seq() rssi_val = msg.get_rssi() node = session.query(Node).get(node_id) loc_id = None if node is None: add_node(session, node_id) else: loc_id = node.locationId pack_state = PackState.from_message(msg) if duplicate_packet(session=session, receipt_time=current_time, node_id=node_id, localtime=msg.get_timestamp()): LOGGER.info("duplicate packet %d->%d, %d %s" % (node_id, parent_id, msg.get_timestamp(), str(msg))) return False # write a node state row node_state = NodeState(time=current_time, nodeId=node_id, parent=parent_id, localtime=msg.get_timestamp(), seq_num=seq, rssi = rssi_val) session.add(node_state) for i, value in pack_state.d.iteritems(): type_id = i if math.isinf(value) or math.isnan(value): value = None r = Reading(time=current_time, nodeId=node_id, typeId=type_id, locationId=loc_id, value=value) try: session.add(r) session.flush() except sqlalchemy.exc.IntegrityError, e: self.log.error("Unable to store reading, checking if node type exists") self.log.error(e) session.rollback() s = session.query(SensorType).filter_by(id=i).first() if s is None: s = SensorType(id=type_id,name="UNKNOWN") session.add(s) self.log.info("Adding new sensortype") session.flush() session.add(r) session.flush() else: self.log.error("Sensor type exists") self.log.debug("reading: %s, %s" % (node_state, pack_state)) session.commit() #send acknowledgement to base station to fwd to node self.send_ack(seq=seq, dest=node_id) except Exception as exc: session.rollback() self.log.exception("error during storing (reading): " + str(exc))