Compare commits
6 Commits
miband5_de
...
master
Author | SHA1 | Date |
---|---|---|
NateSchoolfield | 5849fc5b6d | |
NateSchoolfield | bfb2e81ec1 | |
NateSchoolfield | fc23f1f3c9 | |
NateSchoolfield | 6e3ddc2045 | |
NateSchoolfield | e6732d62df | |
NateSchoolfield | c3bc050593 |
|
@ -1,5 +1,6 @@
|
|||
mac.txt
|
||||
auth_key.txt
|
||||
mac*.txt
|
||||
auth_key*.txt
|
||||
*.sh
|
||||
*.pyc
|
||||
/__pycache__
|
||||
*.swp
|
||||
|
@ -8,3 +9,6 @@ auth_key.txt
|
|||
*.code-workspace
|
||||
/.vscode
|
||||
/data
|
||||
datafilter.py
|
||||
crymonitor.py
|
||||
|
||||
|
|
11
README
11
README
|
@ -10,10 +10,8 @@ You will need to create two .txt files in the base directory:
|
|||
|
||||
|
||||
CURRENT STATUS:
|
||||
Right now the project does not yet fulfill its primary purpose (responding to biometrics).
|
||||
If executed now, it will:
|
||||
* Log raw and averaged biometric data to disk
|
||||
* Vibrate in a random pattern every 30 minutes (adjustable)
|
||||
The project now supports basic "heartrate alarming". Currently it's configured to send a 10-second random vibration pattern if the heartrate increase percentage goes above 17% of the lowest HR value for the last 10 readings, with a 20-minute delay between vibrations. This was tested on the Miband5, which has a better HR sensor, though I've not yet fully figured out the gyroscope data. Right now only HR and vibration are supported on the Miband5.
|
||||
|
||||
|
||||
GOALS:
|
||||
* Publish statistics to Google Sheets or other easy-to-use target. I'd like to make this usable by non-technical folks, so S3 buckets and CloudWatch are out of scope.
|
||||
|
@ -24,7 +22,4 @@ GOALS:
|
|||
|
||||
|
||||
DISCLAIMER:
|
||||
None of the statements on this web site have been evaluated by the FDA.
|
||||
Furthermore, none of the statements herein should be construed as dispensing medical advice, or making claims regarding the cure or treatment of diseases.
|
||||
These statements have not been evaluated by the Food and Drug Administration.
|
||||
These project is not intended to diagnose, treat, cure, or prevent any diseases.
|
||||
None of the statements on this web site have been evaluated by the FDA. Furthermore, none of the statements herein should be construed as dispensing medical advice, or making claims regarding the cure or treatment of diseases. These statements have not been evaluated by the Food and Drug Administration. This project is not intended to diagnose, treat, cure, or prevent any diseases.
|
||||
|
|
16
bluesleep.py
16
bluesleep.py
|
@ -15,9 +15,10 @@ mac_filename = 'mac.txt'
|
|||
maximize_graph = False
|
||||
|
||||
vibration_settings = {
|
||||
'interval_minutes': 0.1,
|
||||
'duration_seconds': 5,
|
||||
'type': 'random'
|
||||
'interval_minutes': 20,
|
||||
'duration_seconds': 10,
|
||||
'type': 'random',
|
||||
'heartrate_alarm_pct': 17
|
||||
}
|
||||
|
||||
band = None
|
||||
|
@ -65,7 +66,7 @@ def average_data(tick_time):
|
|||
sleepdata.average_raw_data(tick_time)
|
||||
sleepdata.last_tick_time = time.time()
|
||||
|
||||
|
||||
|
||||
def sleep_monitor_callback(data):
|
||||
tick_time = time.time()
|
||||
|
||||
|
@ -79,6 +80,9 @@ def sleep_monitor_callback(data):
|
|||
|
||||
average_data(tick_time)
|
||||
|
||||
vibration.heartrate_increase_pct = sleepdata.analyze_heartrate(10)
|
||||
print("HR increase percent: {}".format(vibration.heartrate_increase_pct))
|
||||
|
||||
|
||||
def connect():
|
||||
global band
|
||||
|
@ -113,7 +117,9 @@ def start_data_pull():
|
|||
def start_vibration():
|
||||
while True:
|
||||
try:
|
||||
vibration.timed_vibration(vibration_settings)
|
||||
#vibration.timed_vibration(vibration_settings)
|
||||
vibration.heartrate_alarm(vibration_settings)
|
||||
|
||||
except BTLEDisconnectError:
|
||||
print("Vibration thread waiting for band reconnect...")
|
||||
time.sleep(1)
|
||||
|
|
|
@ -231,7 +231,7 @@ class miband(Peripheral):
|
|||
def _parse_heart_measure(self, bytes):
|
||||
res = struct.unpack('bb', bytes)[1]
|
||||
return_tuple = ["HR", res]
|
||||
print("BPM: {}".format(res))
|
||||
#print("BPM: {}".format(res))
|
||||
return return_tuple
|
||||
|
||||
|
||||
|
|
17
sleepdata.py
17
sleepdata.py
|
@ -12,6 +12,7 @@ sleep_data = {
|
|||
'periods': [2, 5, 10, 15],
|
||||
'raw_data': [],
|
||||
'averaged_data': [],
|
||||
'last_hr': []
|
||||
},
|
||||
'movement':{
|
||||
'value_name': 'movement',
|
||||
|
@ -173,6 +174,7 @@ def process_gyro_data(gyro_data, tick_time):
|
|||
|
||||
|
||||
def process_heartrate_data(heartrate_data, tick_time):
|
||||
last_heartrate_count = 20
|
||||
print("BPM: " + str(heartrate_data))
|
||||
if heartrate_data > 0:
|
||||
value_name = sleep_data['heartrate']['value_name']
|
||||
|
@ -181,6 +183,21 @@ def process_heartrate_data(heartrate_data, tick_time):
|
|||
value_name: heartrate_data
|
||||
} )
|
||||
|
||||
if len(sleep_data['heartrate']['last_hr']) > last_heartrate_count:
|
||||
sleep_data['heartrate']['last_hr'].pop(0)
|
||||
sleep_data['heartrate']['last_hr'].append(heartrate_data)
|
||||
|
||||
|
||||
def analyze_heartrate(hr_count):
|
||||
# Finds the pct change between the lowest HR in the last $hr_count samples and the current HR
|
||||
pct_heartrate_increase = 0
|
||||
if len(sleep_data['heartrate']['last_hr']) >= hr_count:
|
||||
last_heartrate_list = sleep_data['heartrate']['last_hr'][-hr_count:]
|
||||
last_heartrate_min = min(last_heartrate_list)
|
||||
current_heartrate = last_heartrate_list[-1]
|
||||
pct_heartrate_increase = int((current_heartrate - last_heartrate_min)/last_heartrate_min*100)
|
||||
return pct_heartrate_increase
|
||||
|
||||
|
||||
def zero_to_nan(value):
|
||||
if value == 0:
|
||||
|
|
45
vibrate.py
45
vibrate.py
|
@ -12,6 +12,8 @@ import logging
|
|||
class Vibrate():
|
||||
vibrate_band = None
|
||||
vibration_log = None
|
||||
heartrate_increase_pct = 0
|
||||
|
||||
|
||||
def __init__(self, band):
|
||||
self.vibrate_band = band
|
||||
|
@ -22,12 +24,53 @@ class Vibrate():
|
|||
self.vibration_log = logging.getLogger(__name__)
|
||||
self.vibration_log.setLevel(vibration_log_level)
|
||||
|
||||
|
||||
def heartrate_alarm(self, settings):
|
||||
interval_minutes = settings['interval_minutes']
|
||||
duration_seconds = settings['duration_seconds']
|
||||
vibration_type = settings['type']
|
||||
heartrate_alarm_pct = settings['heartrate_alarm_pct']
|
||||
|
||||
tick_time = time.time()
|
||||
buzz_delay = interval_minutes * 60
|
||||
buzz_timer = tick_time - buzz_delay
|
||||
|
||||
|
||||
self.vibration_log.info("Starting heartrate alarm timer, alarming at {} percent for {} seconds with a {} minute interval".format(
|
||||
heartrate_alarm_pct,
|
||||
duration_seconds,
|
||||
interval_minutes))
|
||||
if vibration_type not in ['random', 'pattern', 'rolling', 'continuous']:
|
||||
self.vibration_log.warn("Invalid or no vibration type specified: {}".format(type))
|
||||
self.vibration_log.warn("Must be one of these: random, pattern, rolling, continuous")
|
||||
return
|
||||
|
||||
while True:
|
||||
elapsed_time = tick_time - buzz_timer
|
||||
if elapsed_time >= buzz_delay and self.heartrate_increase_pct >= heartrate_alarm_pct:
|
||||
self.vibration_log.info("Heartrate alarm triggered at {} percent, buzzing".format(self.heartrate_increase_pct))
|
||||
if vibration_type == 'random':
|
||||
self.vibrate_random(duration_seconds)
|
||||
elif vibration_type == 'pattern':
|
||||
self.vibrate_pattern(duration_seconds)
|
||||
elif vibration_type == 'rolling':
|
||||
self.vibrate_rolling(duration_seconds)
|
||||
elif vibration_type == 'continuous':
|
||||
self.vibrate_continuous(duration_seconds)
|
||||
buzz_timer = tick_time
|
||||
elif not elapsed_time >= buzz_delay and self.heartrate_increase_pct >= heartrate_alarm_pct:
|
||||
self.vibration_log.info("Heartrate alarm threshold reached ({} percent) but timout not expired".format(self.heartrate_increase_pct))
|
||||
else:
|
||||
tick_time = time.time()
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
def timed_vibration(self, settings):
|
||||
interval_minutes = settings['interval_minutes']
|
||||
duration_seconds = settings['duration_seconds']
|
||||
type = settings['type']
|
||||
|
||||
buzz_timer = time.time()
|
||||
buzz_timer = time.time()
|
||||
tick_time = time.time()
|
||||
buzz_delay = interval_minutes * 60
|
||||
|
||||
|
|
Loading…
Reference in New Issue