def birdseye_read(kiwi, downsample_N): config = kiwi.get_config(use_cached=True) sample_count = kiwi.get_sample_count() #if sample_count <= 0: # return None,None number_to_read = min(downsample_N, sample_count) STRIDE = int(sample_count // number_to_read) m = '{:,} in steps of {:,}'.format(number_to_read, STRIDE) if STRIDE > 1 else 'everything' print(' {:,} sample{} in memory.'.format(sample_count, 's' if sample_count > 1 else '')) print('Requested {:,} sample{}; will read {}.'.format( downsample_N, 's' if downsample_N > 1 else '', m)) print('First sample taken at {} ({} UTC).'.format( ts2dt(config['start'], utc=False), ts2dt(config['start'], utc=True))) print('Sampling interval: {:.3f} second'.format(config['interval_ms'] * 1e-3)) # - - - D = [] current_page_index = None current_page = None sample_indices = list(range(0, sample_count, STRIDE)) addr = [kiwi.sampleindex2flashaddress(i) for i in sample_indices] print('Reading', end='', flush=True) for sample_index, (page_i, byte_i) in zip(sample_indices, addr): #print(sample_index, page_i, byte_i) try: if 0 == (sample_index // STRIDE) % math.ceil( sample_count // STRIDE / 10): print('.', end='', flush=True) if current_page_index != page_i: logging.debug('Reading logger...') begin = page_i * Kiwi.SPI_FLASH_PAGE_SIZE_BYTE end = (page_i + 1) * Kiwi.SPI_FLASH_PAGE_SIZE_BYTE - 1 current_page = kiwi.read_range_core(begin, end) if len(current_page) != end - begin + 1: logging.warning( 'Invalid response length. Skipping sample {}'.format( sample_index)) continue current_page_index = page_i else: logging.debug('reuse') d = struct.unpack( kiwi.sample_struct_fmt, current_page[byte_i:byte_i + kiwi.SAMPLE_SIZE_BYTE]) D.append([sample_index, *d]) except KeyboardInterrupt: print(' User interrupted.') break return D, STRIDE
def read_clock(ent): logging.debug('read_clock') with Serial(PORT, 115200, timeout=1) as ser: kiwi = Kiwi(ser) ent.config(state='normal') ent.delete(0, tk.END) ent.insert(0, '{}'.format(ts2dt(kiwi.read_rtc()))) ent.config(state='readonly')
def bin2csv(fn_bin, fn_csv, config): logging.debug('Reading and parsing binary file...') D = [] with open(fn_bin, 'rb') as fin: while True: page = fin.read(Kiwi.SPI_FLASH_PAGE_SIZE_BYTE) if len(page) < Kiwi.SPI_FLASH_PAGE_SIZE_BYTE: break L = list( range( 0, Kiwi.SPI_FLASH_PAGE_SIZE_BYTE, 4 + 4 + 2 + 2 + 2 + 2 + 2 + 2 if config['use_light'] else 4 + 4)) for a, b in list(zip(L[::], L[1::])): d = struct.unpack('ffHHHHHH' if config['use_light'] else 'ff', page[a:b]) if any([math.isnan(dd) for dd in d]): break D.append(d) logging.debug('Reconstructing time axis...') if 'logging_start_time' in config and 'logging_interval_code' in config: ts = construct_timestamp( config['logging_start_time'], len(D), SAMPLE_INTERVAL_CODE_MAP[config['logging_interval_code']]) else: ts = construct_timestamp(config['start'], len(D), config['interval_ms'] * 1e-3) dt = [ts2dt(tmp) for tmp in ts] tmp = list(zip(*D)) tmp.insert(0, ts) tmp.insert(0, dt) D = zip(*tmp) logging.debug('Writing to {}...'.format(fn_csv)) with open(fn_csv, 'w', newline='') as fout: writer = csv.writer(fout, delimiter=',') if config['use_light']: fs = [ str, str, lambda x: '{:.4f}'.format(x), lambda x: '{:.3f}'.format(x), str, str, str, str, str, str ] writer.writerow([ 'UTC_datetime', 'posix_timestamp', 'T_DegC', 'P_kPa', 'ambient_light_hdr', 'white_light_hdr', 'red', 'green', 'blue', 'white' ]) else: fs = [ str, str, lambda x: '{:.4f}'.format(x), lambda x: '{:.3f}'.format(x) ] writer.writerow( ['UTC_datetime', 'posix_timestamp', 'T_DegC', 'P_kPa']) for d in D: #writer.writerow([str(x) for x in d]) writer.writerow([f(x) for f, x in zip(fs, d)])
good = False break D.append(d) except KeyboardInterrupt: break # reconstruct time axis using logging start time and sample interval print('Reading config {}'.format(configfilename)) config = json.loads(open(configfilename).read()) logging_start_time = config['logging_start_time'] logging_stop_time = config.get('logging_stop_time', None) if logging_stop_time is not None and logging_stop_time > logging_start_time: print('{} samples from {} to {} spanning {}'.format( len(D), ts2dt(logging_start_time), ts2dt(logging_stop_time), ts2dt(logging_stop_time) - ts2dt(logging_start_time))) print( 'Effective sample rate {:.3f} sample/second or an average interval of {:.3f} second' .format( len(D) / (logging_stop_time - logging_start_time), (logging_stop_time - logging_start_time) / len(D))) else: logging.warning( 'No record of logging_stop_time. Are the batteries good? Did someone remove power without stopping logging first?' ) logging_interval_code = config['logging_interval_code'] print('Reconstructing time axis...') ts = np.linspace(0, len(D) - 1, num=len(D))
logging.basicConfig(level=logging.WARNING) #fn = UNIQUE_ID + '.csv' #fn = input('Path to the CSV file: ').strip() d = find('data/*', dironly=True) fn = find(join(d, '*.csv'), fileonly=True, default='last') if fn is None: print('No CSV file found. Have you run bin2csv.py? Terminating.') sys.exit() logger_name = get_logger_name(fn) ts, t, p, als, white, r, g, b, w = read_and_parse_data(fn) begin, end = ts2dt(min(ts)), ts2dt(max(ts)) if len(ts) <= 1: print('Only less than two measurements are available. ABORT.') print( '{} samples from {} to {} spanning {}, average interval {:.3}s'.format( len(ts), begin, end, end - begin, ts[1] - ts[0])) # - - - #print(describe(p)) # also PSD... TODO '''print('Calculating Temperature statistics...') plt.figure(figsize=(16, 9))
def birdseye_plot(D, STRIDE, config, sample_count, use_utc): D = list(zip(*D)) D[0] = [ ts2dt(i * config['interval_ms'] * 1e-3 + config['start'], utc=use_utc) for i in D[0] ] print(' plotting... ', end='', flush=True) fig, ax = plt.subplots(4 if config['use_light'] else 2, 1, figsize=(16, 9), sharex=True) for tmp in ax[:-1]: plt.setp(tmp.get_xticklabels(), visible=False) ax[-1].set_xlabel('UTC Time' if use_utc else 'Local Time') if STRIDE > 1: ax[0].set_title( 'Memory Overview (plotting one out of every {:,})'.format( STRIDE, sample_count)) else: ax[0].set_title('Memory Overview (plotting everything)') # add caption span = max(D[0]) - min(D[0]) if span > timedelta(days=2): span = '{:.1f} days'.format(span.total_seconds() / 3600 / 24) else: span = '{:.1f} hours'.format(span.total_seconds() / 3600) s = 'Logger "{}" (ID={})'.format(config['name'], config['id']) s += '\n{:,} samples from {} to {} spanning ~{}'.format( sample_count, min(D[0]).isoformat()[:19].replace('T', ' '), max(D[0]).isoformat()[:19].replace('T', ' '), span, ) s += '\nSample interval={:.3f} second{}'.format( config['interval_ms'] * 1e-3, 's' if config['interval_ms'] > 1000 else '') if STRIDE > 1: s += '\n{:,} out of {:,} samples plotted (in steps of {:,})'.format( len(D[0]), sample_count, STRIDE) else: s += '\nAll samples plotted' plt.figtext(0.99, 0.01, s, horizontalalignment='right', color='k', alpha=0.5) ax[0].plot_date(D[0], D[1], 'r.:', label='℃') ax[0].legend(loc=2) ax[0].grid(True) ax[1].plot_date(D[0], D[2], '.:', label='kPa') ax[1].legend(loc=2) ax[1].grid(True) if config['use_light']: ax[2].plot_date(D[0], D[3], '.:', label='HDR_ALS', alpha=0.5) ax[2].plot_date(D[0], D[4], '.:', label='HDR_W', alpha=0.5) ax[2].legend(loc=2) ax[2].grid(True) ax[3].plot_date(D[0], D[5], 'r.:', label='R', alpha=0.5) ax[3].plot_date(D[0], D[6], 'g.:', label='G', alpha=0.5) ax[3].plot_date(D[0], D[7], 'b.:', label='B', alpha=0.5) ax[3].plot_date(D[0], D[8], 'k.:', label='W', alpha=0.2) ax[3].legend(loc=2) ax[3].grid(True) ax[-1].xaxis.set_major_formatter(DateFormatter('%b %d %H:%M:%S')) plt.tight_layout() plt.gcf().autofmt_xdate() #print('Saving plot to disk...') #plt.savefig(fn.split('.')[0] + '.png', dpi=300) print('voila!') plt.show()
assert not kiwi.is_logging() # Turn off LEDs ser.write(b'red_led_off green_led_off blue_led_off' if 0 == kiwi._version else b'roffgoffboff') if 0 == kiwi._version: # Set RTC to current UTC time print('Synchronizing clock to UTC...', flush=True) for i in range(MAX_RETRY): device_time = kiwi.set_rtc_aligned() if abs(device_time - time.time()) <= 2: break else: print('Cannot set logger clock. Terminating.') sys.exit() print('Logger time: {} ({} UTC)'.format(ts2dt(device_time, utc=False), ts2dt(device_time, utc=True))) if 0 == kiwi._version: use_light_sensors = True else: while True: r = input('Use light sensors? (yes/no; default=yes)').strip().lower() if r in ['', 'yes', 'no']: use_light_sensors = r not in ['no'] break for i in range(MAX_RETRY): ser.write(b'enable_light_sensors' if use_light_sensors else b'disable_light_sensors') if 'OK' == ser.readline().strip(): break