Moved data handling outside of main script into sleepdata module
This commit is contained in:
parent
8435b2bd69
commit
7bf0e8539d
285
bluesleep.py
285
bluesleep.py
|
@ -4,12 +4,7 @@ from bluepy import btle
|
|||
from bluepy.btle import BTLEDisconnectError
|
||||
|
||||
from miband import miband
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.animation as animation
|
||||
import csv
|
||||
import random
|
||||
from os import path
|
||||
import sleepdata
|
||||
|
||||
import threading
|
||||
import re
|
||||
|
@ -18,69 +13,23 @@ import subprocess
|
|||
import time
|
||||
from datetime import datetime
|
||||
|
||||
sleep_data = {
|
||||
'heartrate': {
|
||||
'value_name': 'bpm',
|
||||
'periods': [2, 5, 10, 15],
|
||||
'raw_data': [],
|
||||
'averaged_data': [],
|
||||
},
|
||||
'movement':{
|
||||
'value_name': 'movement',
|
||||
'periods': [10, 30, 60],
|
||||
'raw_data': [],
|
||||
'averaged_data': [],
|
||||
'workspace': {
|
||||
'gyro_last_x' : 0,
|
||||
'gyro_last_y' : 0,
|
||||
'gyro_last_z' : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auth_key_filename = 'auth_key.txt'
|
||||
mac_filename = 'mac.txt'
|
||||
csv_filename = "sleep_data.csv"
|
||||
|
||||
plt.style.use('dark_background')
|
||||
graph_figure = plt.figure()
|
||||
graph_axes = graph_figure.add_subplot(1, 1, 1)
|
||||
graph_data = {}
|
||||
|
||||
last_heartrate = 0
|
||||
last_tick_time = None
|
||||
tick_seconds = 0.5
|
||||
|
||||
fieldnames = ['time']
|
||||
for data_type in sleep_data:
|
||||
periods = sleep_data[data_type]['periods']
|
||||
for period in periods:
|
||||
fieldnames.append(data_type + str(period))
|
||||
|
||||
band = None
|
||||
|
||||
#-------------------------------------------------------------------------#
|
||||
|
||||
|
||||
def write_csv(data):
|
||||
global fieldnames
|
||||
global csv_filename
|
||||
if not path.exists(csv_filename):
|
||||
with open(csv_filename, 'w', newline='') as csvfile:
|
||||
csv_writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
||||
csv_writer.writeheader()
|
||||
csv_writer.writerow(data)
|
||||
else:
|
||||
with open(csv_filename, 'a', newline='') as csvfile:
|
||||
csv_writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
||||
csv_writer.writerow(data)
|
||||
class regex_patterns():
|
||||
mac_regex_pattern = re.compile(r'([0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5})')
|
||||
authkey_regex_pattern = re.compile(r'([0-9a-fA-F]){32}')
|
||||
|
||||
|
||||
def get_mac_address(filename):
|
||||
mac_regex_pattern = re.compile(r'([0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5})')
|
||||
try:
|
||||
with open(filename, "r") as f:
|
||||
hwaddr_search = re.search(mac_regex_pattern, f.read().strip())
|
||||
|
||||
hwaddr_search = re.search(regex_patterns.mac_regex_pattern, f.read().strip())
|
||||
if hwaddr_search:
|
||||
MAC_ADDR = hwaddr_search[0]
|
||||
else:
|
||||
|
@ -93,10 +42,9 @@ def get_mac_address(filename):
|
|||
|
||||
|
||||
def get_auth_key(filename):
|
||||
authkey_regex_pattern = re.compile(r'([0-9a-fA-F]){32}')
|
||||
try:
|
||||
with open(filename, "r") as f:
|
||||
key_search = re.search(authkey_regex_pattern, f.read().strip())
|
||||
key_search = re.search(regex_patterns.authkey_regex_pattern, f.read().strip())
|
||||
if key_search:
|
||||
AUTH_KEY = bytes.fromhex(key_search[0])
|
||||
else:
|
||||
|
@ -107,210 +55,28 @@ def get_auth_key(filename):
|
|||
exit(1)
|
||||
return AUTH_KEY
|
||||
|
||||
|
||||
def process_heartrate_data(heartrate_data, tick_time):
|
||||
print("BPM: " + str(heartrate_data))
|
||||
if heartrate_data > 0:
|
||||
value_name = sleep_data['heartrate']['value_name']
|
||||
sleep_data['heartrate']['raw_data'].append({
|
||||
'time': tick_time,
|
||||
value_name: heartrate_data
|
||||
} )
|
||||
|
||||
|
||||
def process_gyro_data(gyro_data, tick_time):
|
||||
# Each gyro reading from miband4 comes over as a group of three,
|
||||
# each containing x,y,z values. This function summarizes the
|
||||
# values into a single consolidated movement value.
|
||||
|
||||
global sleep_data
|
||||
|
||||
sleep_move = sleep_data['movement']
|
||||
sleep_workspace = sleep_move['workspace']
|
||||
|
||||
gyro_last_x = sleep_workspace['gyro_last_x']
|
||||
gyro_last_y = sleep_workspace['gyro_last_y']
|
||||
gyro_last_z = sleep_workspace['gyro_last_z']
|
||||
value_name = sleep_move['value_name']
|
||||
gyro_movement = 0
|
||||
for gyro_datum in gyro_data:
|
||||
gyro_delta_x = abs(gyro_datum['x'] - gyro_last_x)
|
||||
gyro_last_x = gyro_datum['x']
|
||||
gyro_delta_y = abs(gyro_datum['y'] - gyro_last_y)
|
||||
gyro_last_y = gyro_datum['y']
|
||||
gyro_delta_z = abs(gyro_datum['z'] - gyro_last_z)
|
||||
gyro_last_z = gyro_datum['z']
|
||||
gyro_delta_sum = gyro_delta_x + gyro_delta_y + gyro_delta_z
|
||||
gyro_movement += gyro_delta_sum
|
||||
|
||||
sleep_workspace['gyro_last_x'] = gyro_last_x
|
||||
sleep_workspace['gyro_last_y'] = gyro_last_y
|
||||
sleep_workspace['gyro_last_z'] = gyro_last_z
|
||||
|
||||
sleep_move['raw_data'].append({
|
||||
'time': tick_time,
|
||||
value_name: gyro_movement
|
||||
})
|
||||
|
||||
|
||||
def flush_old_raw_data(tick_time):
|
||||
global sleep_data
|
||||
|
||||
for data_type in sleep_data:
|
||||
s_data = sleep_data[data_type]
|
||||
periods = s_data['periods']
|
||||
|
||||
cleaned_raw_data = []
|
||||
|
||||
for raw_datum in s_data['raw_data']:
|
||||
datum_age = tick_time - raw_datum['time']
|
||||
if datum_age < max(periods):
|
||||
cleaned_raw_data.append(raw_datum)
|
||||
|
||||
s_data['raw_data'] = cleaned_raw_data
|
||||
|
||||
|
||||
def average_raw_data(tick_time):
|
||||
global sleep_data
|
||||
global last_heartrate
|
||||
timestamp = datetime.fromtimestamp(tick_time)
|
||||
csv_out = {'time': timestamp }
|
||||
|
||||
for data_type in sleep_data:
|
||||
s_data = sleep_data[data_type]
|
||||
period_averages_dict = {'time': timestamp}
|
||||
periods = s_data['periods']
|
||||
value_name = s_data['value_name']
|
||||
|
||||
flush_old_raw_data(tick_time)
|
||||
|
||||
for period_seconds in periods:
|
||||
period_data = []
|
||||
period_averages_dict[period_seconds] = 0
|
||||
for raw_datum in s_data['raw_data']:
|
||||
datum_age_seconds = tick_time - raw_datum['time']
|
||||
if datum_age_seconds < period_seconds:
|
||||
period_data.append(raw_datum[value_name])
|
||||
|
||||
if len(period_data) > 0:
|
||||
period_data_average = sum(period_data) / len(period_data)
|
||||
else:
|
||||
print("({}) Period data empty: {}".format(data_type,
|
||||
period_seconds))
|
||||
if data_type == "heartrate" and period_seconds == min(periods):
|
||||
period_data_average = last_heartrate
|
||||
else:
|
||||
period_data_average = 0
|
||||
|
||||
period_averages_dict[period_seconds] = zero_to_nan(period_data_average)
|
||||
|
||||
csv_out[data_type + str(period_seconds)] = zero_to_nan(period_data_average)
|
||||
|
||||
s_data['averaged_data'].append(period_averages_dict)
|
||||
write_csv(csv_out)
|
||||
|
||||
|
||||
def zero_to_nan(value):
|
||||
if value == 0:
|
||||
return (float('nan'))
|
||||
return int(value)
|
||||
|
||||
def process_data(data, tick_time):
|
||||
if data[0] == "GYRO":
|
||||
sleepdata.process_gyro_data(data[1], tick_time)
|
||||
elif data[0] == "HR":
|
||||
sleepdata.process_heartrate_data(data[1], tick_time)
|
||||
|
||||
def sleep_monitor_callback(data):
|
||||
global sleep_data
|
||||
global last_tick_time
|
||||
|
||||
tick_time = time.time()
|
||||
if not last_tick_time:
|
||||
last_tick_time = time.time()
|
||||
if not sleepdata.last_tick_time:
|
||||
sleepdata.last_tick_time = time.time()
|
||||
|
||||
if data[0] == "GYRO":
|
||||
process_gyro_data(data[1], tick_time)
|
||||
elif data[0] == "HR":
|
||||
process_heartrate_data(data[1], tick_time)
|
||||
process_data(data, tick_time)
|
||||
|
||||
if (tick_time - last_tick_time) >= tick_seconds:
|
||||
average_raw_data(tick_time)
|
||||
last_tick_time = time.time()
|
||||
if (tick_time - sleepdata.last_tick_time) >= sleepdata.tick_seconds:
|
||||
sleepdata.average_raw_data(tick_time)
|
||||
sleepdata.last_tick_time = time.time()
|
||||
|
||||
|
||||
def init_graph_data():
|
||||
for data_type in sleep_data:
|
||||
data_periods = sleep_data[data_type]['periods']
|
||||
graph_data[data_type] = {
|
||||
'time': [],
|
||||
'data': {}
|
||||
}
|
||||
for period in data_periods:
|
||||
graph_data[data_type]['data'][period] = []
|
||||
|
||||
|
||||
def update_graph_data():
|
||||
global sleep_data
|
||||
global graph_data
|
||||
|
||||
for data_type in sleep_data:
|
||||
s_data = sleep_data[data_type] # Re-referenced to shorten name
|
||||
avg_data = s_data['averaged_data']
|
||||
|
||||
if len(avg_data) > 1:
|
||||
|
||||
g_data = graph_data[data_type] # Re-referenced to short name
|
||||
data_periods = s_data['periods']
|
||||
|
||||
starting_index = max([(len(g_data['time']) - 1), 0])
|
||||
ending_index = len(avg_data) - 1
|
||||
|
||||
# Re-referenced to shorten name
|
||||
sleep_data_range = avg_data[starting_index:ending_index]
|
||||
|
||||
for sleep_datum in sleep_data_range:
|
||||
g_data['time'].append(sleep_datum['time'])
|
||||
for period in data_periods:
|
||||
if g_data['data'][period] != 'nan':
|
||||
g_data['data'][period].append(sleep_datum[period])
|
||||
|
||||
|
||||
def graph_animation(i):
|
||||
global sleep_data
|
||||
global graph_axes
|
||||
global graph_data
|
||||
plotflag = False
|
||||
|
||||
if len(graph_data) == 0:
|
||||
init_graph_data()
|
||||
|
||||
update_graph_data()
|
||||
|
||||
for data_type in graph_data:
|
||||
if len(graph_data[data_type]['time']) > 0:
|
||||
graph_axes.clear()
|
||||
break
|
||||
|
||||
for data_type in sleep_data:
|
||||
s_data = sleep_data[data_type]
|
||||
g_data = graph_data[data_type]
|
||||
if len(g_data['time']) > 0:
|
||||
plotflag = True
|
||||
data_periods = sleep_data[data_type]['periods']
|
||||
for period in data_periods:
|
||||
axis_label = "{} {} sec".format(s_data['value_name'], period)
|
||||
graph_axes.plot(g_data['time'],
|
||||
g_data['data'][period],
|
||||
label=axis_label)
|
||||
|
||||
if plotflag:
|
||||
plt.legend()
|
||||
|
||||
|
||||
def connect():
|
||||
def connect(mac_filename, auth_key_filename):
|
||||
global band
|
||||
global mac_filename
|
||||
global auth_key_filename
|
||||
|
||||
success = False
|
||||
timeout = 3
|
||||
msg = 'Connection to the MIBand failed. Trying again in {} seconds'
|
||||
msg = 'Connection to the band failed. Trying again in {} seconds'
|
||||
|
||||
MAC_ADDR = get_mac_address(mac_filename)
|
||||
AUTH_KEY = get_auth_key(auth_key_filename)
|
||||
|
@ -326,10 +92,7 @@ def connect():
|
|||
print("\nExit.")
|
||||
exit()
|
||||
|
||||
|
||||
def start_data_pull():
|
||||
global band
|
||||
|
||||
while True:
|
||||
try:
|
||||
band.start_heart_and_gyro(sensitivity=1, callback=sleep_monitor_callback)
|
||||
|
@ -357,6 +120,7 @@ def vibrate_pattern(duration):
|
|||
time.sleep(vibro_delay)
|
||||
|
||||
def vibrate_rolling():
|
||||
print("Sending rolling vibration...")
|
||||
for x in range(10):
|
||||
for x in range(20, 40, 1):
|
||||
band.vibrate(x)
|
||||
|
@ -364,11 +128,12 @@ def vibrate_rolling():
|
|||
band.vibrate(x)
|
||||
|
||||
if __name__ == "__main__":
|
||||
connect()
|
||||
connect(mac_filename, auth_key_filename)
|
||||
#vibrate_pattern(10)
|
||||
data_gather_thread = threading.Thread(target=start_data_pull)
|
||||
data_gather_thread.start()
|
||||
ani = animation.FuncAnimation(graph_figure, graph_animation, interval=1000)
|
||||
plt.show()
|
||||
sleepdata.init_graph()
|
||||
|
||||
|
||||
|
||||
#import simpleaudio as sa
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
class miband4():
|
||||
|
||||
class bytepatterns():
|
||||
vibration = 'ff{:02x}00000001'
|
||||
gyro_start = '01{:02x}19'
|
||||
start = '0100'
|
||||
stop = '0000'
|
||||
heart_measure_keepalive = '16'
|
||||
stop_heart_measure_continues = '150100'
|
||||
start_heart_measure_continues = '150101'
|
||||
stop_heart_measure_manual = '150200'
|
||||
fetch_begin = '100101'
|
||||
fetch_error = '100104'
|
||||
fetch_continue = '100201'
|
||||
fetch_complete = '100204'
|
||||
auth_ok = '100301'
|
||||
request_random_number = '0200'
|
||||
auth_key_prefix = '0300'
|
||||
|
||||
def vibration(duration):
|
||||
byte_pattern = miband4.bytepatterns.vibration
|
||||
return bytes.fromhex(byte_pattern.format(duration))
|
||||
|
||||
def gyro_start(sensitivity):
|
||||
byte_pattern = miband4.bytepatterns.gyro_start
|
||||
return bytes.fromhex(byte_pattern.format(sensitivity))
|
||||
|
||||
start = bytes.fromhex(bytepatterns.start)
|
||||
stop = bytes.fromhex(bytepatterns.stop)
|
||||
|
||||
heart_measure_keepalive = bytes.fromhex(bytepatterns.heart_measure_keepalive)
|
||||
stop_heart_measure_continues = bytes.fromhex(bytepatterns.stop_heart_measure_continues)
|
||||
start_heart_measure_continues = bytes.fromhex(bytepatterns.start_heart_measure_continues)
|
||||
stop_heart_measure_manual = bytes.fromhex(bytepatterns.stop_heart_measure_manual)
|
||||
|
||||
fetch_begin = bytes.fromhex(bytepatterns.fetch_begin)
|
||||
fetch_error = bytes.fromhex(bytepatterns.fetch_error)
|
||||
fetch_continue = bytes.fromhex(bytepatterns.fetch_continue)
|
||||
fetch_complete = bytes.fromhex(bytepatterns.fetch_complete)
|
||||
|
||||
auth_ok = bytes.fromhex(bytepatterns.auth_ok)
|
||||
request_random_number = bytes.fromhex(bytepatterns.request_random_number)
|
||||
auth_key_prefix = bytes.fromhex(bytepatterns.auth_key_prefix)
|
||||
|
29
miband.py
29
miband.py
|
@ -3,6 +3,8 @@ import logging
|
|||
import struct
|
||||
import binascii
|
||||
|
||||
from bytepatterns import miband4 as bytepattern
|
||||
|
||||
from bluepy.btle import (
|
||||
Peripheral, DefaultDelegate,
|
||||
ADDR_TYPE_RANDOM, ADDR_TYPE_PUBLIC,
|
||||
|
@ -55,34 +57,7 @@ class Delegate(DefaultDelegate):
|
|||
print ("Unhandled handle: " + str(hnd) + " | Data: " + str(data))
|
||||
|
||||
|
||||
class bytepattern():
|
||||
def vibration(duration):
|
||||
byte_pattern = 'ff{:02x}00000001'
|
||||
return bytes.fromhex(byte_pattern.format(duration))
|
||||
|
||||
def gyro_start(sensitivity):
|
||||
byte_pattern = '01{:02x}19'
|
||||
return bytes.fromhex(byte_pattern.format(sensitivity))
|
||||
|
||||
start = bytes.fromhex('0100')
|
||||
stop = bytes.fromhex('0000')
|
||||
|
||||
heart_measure_keepalive = bytes.fromhex('16')
|
||||
stop_heart_measure_continues = bytes.fromhex('150100')
|
||||
start_heart_measure_continues = bytes.fromhex('150101')
|
||||
stop_heart_measure_manual = bytes.fromhex('150200')
|
||||
|
||||
fetch_begin = bytes.fromhex('100101')
|
||||
fetch_error = bytes.fromhex('100104')
|
||||
|
||||
fetch_continue = bytes.fromhex('100201')
|
||||
fetch_complete = bytes.fromhex('100204')
|
||||
|
||||
auth_ok = bytes.fromhex('100301')
|
||||
|
||||
request_random_number = bytes.fromhex('0200')
|
||||
auth_key_prefix = bytes.fromhex('0300')
|
||||
|
||||
|
||||
|
||||
class miband(Peripheral):
|
||||
|
|
256
sleepdata.py
256
sleepdata.py
|
@ -1,24 +1,236 @@
|
|||
class Sleep_Data(object):
|
||||
def __init__(self):
|
||||
print("init")
|
||||
from datetime import datetime
|
||||
from os import path
|
||||
|
||||
import csv
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.animation as animation
|
||||
|
||||
#Todo: separate graph animation from data averaging
|
||||
#Todo: log raw data separately from average data
|
||||
|
||||
|
||||
sleep_data = {
|
||||
'heartrate': {
|
||||
'value_name': 'bpm',
|
||||
'periods': [2, 5, 10, 15],
|
||||
'raw_data': [],
|
||||
'averaged_data': [],
|
||||
},
|
||||
'movement':{
|
||||
'value_name': 'movement',
|
||||
'periods': [10, 30, 60],
|
||||
'raw_data': [],
|
||||
'averaged_data': [],
|
||||
'workspace': {
|
||||
'gyro_last_x' : 0,
|
||||
'gyro_last_y' : 0,
|
||||
'gyro_last_z' : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_heartrate = 0
|
||||
last_tick_time = None
|
||||
tick_seconds = 0.5
|
||||
|
||||
csv_filename = "sleep_data.csv"
|
||||
|
||||
fieldnames = ['time']
|
||||
for data_type in sleep_data:
|
||||
periods = sleep_data[data_type]['periods']
|
||||
for period in periods:
|
||||
fieldnames.append(data_type + str(period))
|
||||
|
||||
|
||||
plt.style.use('dark_background')
|
||||
graph_figure = plt.figure()
|
||||
graph_axes = graph_figure.add_subplot(1, 1, 1)
|
||||
graph_data = {}
|
||||
|
||||
|
||||
def write_csv(data):
|
||||
global fieldnames
|
||||
global csv_filename
|
||||
if not path.exists(csv_filename):
|
||||
with open(csv_filename, 'w', newline='') as csvfile:
|
||||
csv_writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
||||
csv_writer.writeheader()
|
||||
csv_writer.writerow(data)
|
||||
else:
|
||||
with open(csv_filename, 'a', newline='') as csvfile:
|
||||
csv_writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
||||
csv_writer.writerow(data)
|
||||
|
||||
|
||||
def flush_old_raw_data(tick_time):
|
||||
for data_type in sleep_data:
|
||||
s_data = sleep_data[data_type]
|
||||
periods = s_data['periods']
|
||||
|
||||
cleaned_raw_data = []
|
||||
|
||||
sleep_data = {
|
||||
'heartrate': {
|
||||
'value_name': 'bpm',
|
||||
'periods': [2, 5, 10, 15],
|
||||
'raw_data': [],
|
||||
'averaged_data': [],
|
||||
},
|
||||
'movement':{
|
||||
'value_name': 'movement',
|
||||
'periods': [10, 30, 60],
|
||||
'raw_data': [],
|
||||
'averaged_data': [],
|
||||
'workspace': {
|
||||
'gyro_last_x' : 0,
|
||||
'gyro_last_y' : 0,
|
||||
'gyro_last_z' : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
for raw_datum in s_data['raw_data']:
|
||||
datum_age = tick_time - raw_datum['time']
|
||||
if datum_age < max(periods):
|
||||
cleaned_raw_data.append(raw_datum)
|
||||
|
||||
s_data['raw_data'] = cleaned_raw_data
|
||||
|
||||
def write_csv(data):
|
||||
a = ''
|
||||
|
||||
|
||||
def average_raw_data(tick_time):
|
||||
global last_heartrate
|
||||
timestamp = datetime.fromtimestamp(tick_time)
|
||||
csv_out = {'time': timestamp }
|
||||
|
||||
for data_type in sleep_data:
|
||||
s_data = sleep_data[data_type]
|
||||
period_averages_dict = {'time': timestamp}
|
||||
periods = s_data['periods']
|
||||
value_name = s_data['value_name']
|
||||
|
||||
flush_old_raw_data(tick_time)
|
||||
|
||||
for period_seconds in periods:
|
||||
period_data = []
|
||||
period_averages_dict[period_seconds] = 0
|
||||
for raw_datum in s_data['raw_data']:
|
||||
datum_age_seconds = tick_time - raw_datum['time']
|
||||
if datum_age_seconds < period_seconds:
|
||||
period_data.append(raw_datum[value_name])
|
||||
|
||||
if len(period_data) > 0:
|
||||
period_data_average = sum(period_data) / len(period_data)
|
||||
else:
|
||||
print("({}) Period data empty: {}".format(data_type,
|
||||
period_seconds))
|
||||
if data_type == "heartrate" and period_seconds == min(periods):
|
||||
period_data_average = last_heartrate
|
||||
else:
|
||||
period_data_average = 0
|
||||
|
||||
period_averages_dict[period_seconds] = zero_to_nan(period_data_average)
|
||||
|
||||
csv_out[data_type + str(period_seconds)] = zero_to_nan(period_data_average)
|
||||
|
||||
s_data['averaged_data'].append(period_averages_dict)
|
||||
write_csv(csv_out)
|
||||
|
||||
|
||||
|
||||
def process_gyro_data(gyro_data, tick_time):
|
||||
# Each gyro reading from miband4 comes over as a group of three,
|
||||
# each containing x,y,z values. This function summarizes the
|
||||
# values into a single consolidated movement value.
|
||||
|
||||
sleep_move = sleep_data['movement']
|
||||
sleep_workspace = sleep_move['workspace']
|
||||
|
||||
gyro_last_x = sleep_workspace['gyro_last_x']
|
||||
gyro_last_y = sleep_workspace['gyro_last_y']
|
||||
gyro_last_z = sleep_workspace['gyro_last_z']
|
||||
value_name = sleep_move['value_name']
|
||||
gyro_movement = 0
|
||||
for gyro_datum in gyro_data:
|
||||
gyro_delta_x = abs(gyro_datum['x'] - gyro_last_x)
|
||||
gyro_last_x = gyro_datum['x']
|
||||
gyro_delta_y = abs(gyro_datum['y'] - gyro_last_y)
|
||||
gyro_last_y = gyro_datum['y']
|
||||
gyro_delta_z = abs(gyro_datum['z'] - gyro_last_z)
|
||||
gyro_last_z = gyro_datum['z']
|
||||
gyro_delta_sum = gyro_delta_x + gyro_delta_y + gyro_delta_z
|
||||
gyro_movement += gyro_delta_sum
|
||||
|
||||
sleep_workspace['gyro_last_x'] = gyro_last_x
|
||||
sleep_workspace['gyro_last_y'] = gyro_last_y
|
||||
sleep_workspace['gyro_last_z'] = gyro_last_z
|
||||
|
||||
sleep_move['raw_data'].append({
|
||||
'time': tick_time,
|
||||
value_name: gyro_movement
|
||||
})
|
||||
|
||||
|
||||
def process_heartrate_data(heartrate_data, tick_time):
|
||||
print("BPM: " + str(heartrate_data))
|
||||
if heartrate_data > 0:
|
||||
value_name = sleep_data['heartrate']['value_name']
|
||||
sleep_data['heartrate']['raw_data'].append({
|
||||
'time': tick_time,
|
||||
value_name: heartrate_data
|
||||
} )
|
||||
|
||||
def zero_to_nan(value):
|
||||
if value == 0:
|
||||
return (float('nan'))
|
||||
return int(value)
|
||||
|
||||
def update_graph_data():
|
||||
for data_type in sleep_data:
|
||||
s_data = sleep_data[data_type] # Re-referenced to shorten name
|
||||
avg_data = s_data['averaged_data']
|
||||
|
||||
if len(avg_data) > 1:
|
||||
|
||||
g_data = graph_data[data_type] # Re-referenced to short name
|
||||
data_periods = s_data['periods']
|
||||
|
||||
starting_index = max([(len(g_data['time']) - 1), 0])
|
||||
ending_index = len(avg_data) - 1
|
||||
|
||||
# Re-referenced to shorten name
|
||||
sleep_data_range = avg_data[starting_index:ending_index]
|
||||
|
||||
for sleep_datum in sleep_data_range:
|
||||
g_data['time'].append(sleep_datum['time'])
|
||||
for period in data_periods:
|
||||
if g_data['data'][period] != 'nan':
|
||||
g_data['data'][period].append(sleep_datum[period])
|
||||
|
||||
def init_graph_data():
|
||||
for data_type in sleep_data:
|
||||
data_periods = sleep_data[data_type]['periods']
|
||||
graph_data[data_type] = {
|
||||
'time': [],
|
||||
'data': {}
|
||||
}
|
||||
for period in data_periods:
|
||||
graph_data[data_type]['data'][period] = []
|
||||
|
||||
|
||||
def graph_animation(i):
|
||||
global graph_axes
|
||||
global graph_data
|
||||
plotflag = False
|
||||
|
||||
if len(graph_data) == 0:
|
||||
init_graph_data()
|
||||
|
||||
update_graph_data()
|
||||
|
||||
for data_type in graph_data:
|
||||
if len(graph_data[data_type]['time']) > 0:
|
||||
graph_axes.clear()
|
||||
break
|
||||
|
||||
for data_type in sleep_data:
|
||||
s_data = sleep_data[data_type]
|
||||
g_data = graph_data[data_type]
|
||||
if len(g_data['time']) > 0:
|
||||
plotflag = True
|
||||
data_periods = sleep_data[data_type]['periods']
|
||||
for period in data_periods:
|
||||
axis_label = "{} {} sec".format(s_data['value_name'], period)
|
||||
graph_axes.plot(g_data['time'],
|
||||
g_data['data'][period],
|
||||
label=axis_label)
|
||||
|
||||
if plotflag:
|
||||
plt.legend()
|
||||
|
||||
def init_graph():
|
||||
ani = animation.FuncAnimation(graph_figure, graph_animation, interval=1000)
|
||||
plt.show()
|
||||
|
|
Loading…
Reference in New Issue