def check_date(self): """ Checks recursively if the message on the bottom of the stack is within a month """ buffer_line = self.lora_buffer.read( read_tail=True) # read the tail of the lora_buffer buffer_lst = buffer_line.split( ',') # convert string to a list of strings time_now = time.gmtime() # get current date # get year, month and minutes of the month now year_now, month_now, minutes_now = time_now[0], time_now[ 1], minutes_of_the_month() # get year, month and minutes of the month of the last message in the lora_buffer year_then, month_then, minutes_then = int(buffer_lst[0]) + 2000, int( buffer_lst[1]), int(buffer_lst[4]) # logic to decide if message is older than a month if year_then < year_now or month_then < month_now: if (month_then + 1 == month_now) or (month_then == 12 and month_now == 1 and year_then + 1 == year_now): if minutes_then < minutes_now + 24 * 60: self.lora_buffer.remove_tail() # remove message self.check_date() # call recursively else: self.lora_buffer.remove_tail() # remove message self.check_date() # call recursively
def get_sensor_averages(logger, lora): """ Gets averages for specific columns of defined sensor data, loads them into a line and appends it to the file which the LoRa thread sends data from. A sensor is defined if it is ticked in the configuration and has data to be sent (has a current.csv file). :type logger: LoggerFactory object (status_logger) :param is_def: Stores which sensors are defined in the form "sensor_name" : True/False :type is_def: dict """ logger.debug("Calculating averages") # get a dictionary of sensors and their status sensors = get_sensors() fmt = get_format(sensors) version = str(config.get_config("version")) timestamp = s.csv_timestamp_template.format( *time.gmtime()) # get current time in desired format minutes = str(minutes_of_the_month()) # get minutes past last midnight try: sensor_averages = {} for sensor_name in [s.TEMP, s.PM1, s.PM2]: if sensors[sensor_name]: sensor_averages.update(calculate_average(sensor_name, logger)) # Append averages to the line to be sent over LoRa according to which sensors are defined. line_to_log = '{}' + fmt + ',' + version + ',' + minutes for sensor_name in [s.TEMP, s.PM1, s.PM2]: if sensors[sensor_name]: line_to_log += ',' + str( config.get_config(sensor_name + "_id")) + ',' + ','.join( sensor_averages[sensor_name + "_avg"]) + ',' + str( sensor_averages[sensor_name + "_count"]) line_to_log += '\n' # Logs line_to_log to archive and places copies into relevant to_send folders log_averages(line_to_log.format(timestamp + ',')) if config.get_config("LORA") == "ON": year_month = timestamp[2:4] + "," + timestamp[5:7] + ',' lora.lora_buffer.write(line_to_log.format(year_month)) # If raw data was processed, saved and dumped, processing files can be deleted path = s.processing_path for sensor_name in [s.TEMP, s.PM1, s.PM2]: if sensors[sensor_name]: filename = sensor_name + '.csv' try: os.remove(path + filename) except Exception as e: logger.exception("Failed to remove " + filename + " in " + path) except Exception as e: logger.exception("Failed to flash averages") blink_led((0x550000, 0.4, True))
def get_sensor_averages(logger, lora): """ Takes the averages of sensor readings and constructs a line to log to the SD card, terminal and lora buffer :param logger: status logger :type logger: LoggerFactory object :param lora: LoRaWAN object, False if lora is not enabled :type lora: LoRaWAN object """ logger.debug("Calculating averages") # get a dictionary of sensors and their status sensors = get_sensors() fmt = get_format(sensors) version = str(config.get_config("fmt_version")) timestamp = s.csv_timestamp_template.format( *time.gmtime()) # get current time in desired format minutes = str(minutes_of_the_month()) # get minutes past last midnight try: sensor_averages = {} for sensor_name in [s.TEMP, s.PM1, s.PM2]: if sensors[sensor_name]: sensor_averages.update(calculate_average(sensor_name, logger)) # Append averages to the line to be sent over LoRa according to which sensors are defined. line_to_log = '{}' + fmt + ',' + version + ',' + minutes for sensor_name in [s.TEMP, s.PM1, s.PM2]: if sensors[sensor_name]: line_to_log += ',' + str( config.get_config(sensor_name + "_id")) + ',' + ','.join( sensor_averages[sensor_name + "_avg"]) + ',' + str( sensor_averages[sensor_name + "_count"]) line_to_log += '\n' # Logs line_to_log to archive and places copies into relevant to_send folders log_averages(line_to_log.format(timestamp + ',')) if lora is not False: year_month = timestamp[2:4] + "," + timestamp[5:7] + ',' lora.lora_buffer.write(line_to_log.format(year_month)) # If raw data was processed, saved and dumped, processing files can be deleted path = s.processing_path for sensor_name in [s.TEMP, s.PM1, s.PM2]: if sensors[sensor_name]: filename = sensor_name + '.csv' try: os.remove(path + filename) except Exception as e: pass except Exception as e: logger.exception("Failed to flash averages") blink_led((0x550000, 0.4, True))
def get_position(logger, lora): if gps_lock.locked(): logger.debug("Waiting for other gps thread to finish") with gps_lock: logger.info("Getting position via GPS") serial, chrono, indicator_led = gps_init(logger) com_counter = int(chrono.read()) # counter for checking whether gps is connected message = False while True: # data_in = '$GPGGA,085259.000,5056.1384,N,00123.1522,W,1,8,1.17,25.1,M,47.6,M,,*7D\r\n' data_in = (str(serial.readline()))[1:] if (int(chrono.read()) - com_counter) >= 10: gps_deinit(serial, logger, message, indicator_led) logger.error("GPS enabled, but not connected") return False if data_in[1:4] != "$GP": time.sleep(1) else: for char in data_in: sentence = gps.update(char) if sentence == "GPGGA": com_counter = int(chrono.read()) # set aim for the quality of the signal based on the time elapsed elapsed = chrono.read() / int(config.get_config("GPS_timeout")) hdop_aim = [1, 1.2, 1.5, 1.8, 2, 2.5, 3, 4, 5, 6, 7] time_limit = [0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9] for index in range(len(time_limit)): if elapsed < time_limit[index]: break # Process data only if quality of signal is great if 0 < gps.hdop <= hdop_aim[index] and gps.satellites_in_use >= 3: latitude = gps.latitude[0] + gps.latitude[1]/60 if gps.latitude[2] == 'S': latitude = -latitude longitude = gps.longitude[0] + gps.longitude[1]/60 if gps.longitude[2] == 'W': longitude = -longitude message = """Successfully acquired location from GPS Satellites used: {} HDOP: {} Latitude: {} Longitude: {} Altitude: {}""".format(gps.satellites_in_use, gps.hdop, latitude, longitude, gps.altitude) # Process GPS location timestamp = s.csv_timestamp_template.format(*time.gmtime()) # get current time in desired format lst_to_log = [timestamp, latitude, longitude, gps.altitude] str_lst_to_log = list(map(str, lst_to_log)) # cast to string line_to_log = ','.join(str_lst_to_log) + '\n' # Print to terminal and log to archive sys.stdout.write(s.GPS + " - " + line_to_log) with open(s.archive_path + s.GPS + '.csv', 'a') as f_archive: f_archive.write(line_to_log) if config.get_config("LORA") == "ON": # get year and month from timestamp year_month = timestamp[2:4] + "," + timestamp[5:7] + ',' # get minutes since start of the month minutes = str(minutes_of_the_month()) # Construct LoRa message line_to_log = year_month + 'G,' + str(config.get_config("version")) + ',' + minutes + ',' \ + str(config.get_config("GPS_id")) + ',' + ','.join(str_lst_to_log[1:]) + '\n' # Logs line_to_log to be sent over lora lora.lora_buffer.write(line_to_log) gps_deinit(serial, logger, message, indicator_led) return True # If timeout elapsed exit function or thread if chrono.read() >= int(config.get_config("GPS_timeout")): gps_deinit(serial, logger, message, indicator_led) logger.error("""GPS timeout Check if GPS module is connected Place device under clear sky Increase GPS timeout in configurations""") return False