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