diff --git a/.gitignore b/.gitignore index 56eb5fd..64e5f50 100644 --- a/.gitignore +++ b/.gitignore @@ -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 + diff --git a/bluesleep.py b/bluesleep.py index e52ccd0..cca2f7e 100755 --- a/bluesleep.py +++ b/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) diff --git a/bluesleep.py.orig b/bluesleep.py.orig new file mode 100755 index 0000000..b41fb30 --- /dev/null +++ b/bluesleep.py.orig @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 + +import time, re, threading +from bluepy.btle import BTLEDisconnectError +from miband import miband +import sleepdata +from vibrate import Vibrate + + + + +auth_key_filename = 'auth_key.txt' +mac_filename = 'mac.txt' + +maximize_graph = False + +vibration_settings = { +<<<<<<< Updated upstream +<<<<<<< Updated upstream +<<<<<<< Updated upstream + 'interval_minutes': 0.1, + 'duration_seconds': 5, + 'type': 'random' +======= +======= +>>>>>>> Stashed changes + 'interval_minutes': 20, + 'duration_seconds': 10, + 'type': 'random', + 'heartrate_alarm_pct': 17 +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes +||||||| constructed merge base + 'interval_minutes': 45, + 'duration_seconds': 5, + 'type': 'random' +======= + 'interval_minutes': 20, + 'duration_seconds': 10, + 'type': 'random', + 'heartrate_alarm_pct': 17 +>>>>>>> Stashed changes + } + +band = None + +#-------------------------------------------------------------------------# + + +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): + try: + with open(filename, "r") as f: + hwaddr_search = re.search(regex_patterns.mac_regex_pattern, f.read().strip()) + if hwaddr_search: + MAC_ADDR = hwaddr_search[0] + else: + print ("No valid MAC address found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("MAC file not found: {}".format(filename)) + exit(1) + return MAC_ADDR + + +def get_auth_key(filename): + try: + with open(filename, "r") as f: + key_search = re.search(regex_patterns.authkey_regex_pattern, f.read().strip()) + if key_search: + AUTH_KEY = bytes.fromhex(key_search[0]) + else: + print ("No valid auth key found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("Auth key file not found: {}".format(filename)) + exit(1) + return AUTH_KEY + + +def average_data(tick_time): + if (tick_time - sleepdata.last_tick_time) >= sleepdata.tick_seconds: + sleepdata.average_raw_data(tick_time) + sleepdata.last_tick_time = time.time() + + +def sleep_monitor_callback(data): + tick_time = time.time() + + if not sleepdata.last_tick_time: + sleepdata.last_tick_time = time.time() + + if data[0] == "GYRO_RAW": + sleepdata.process_gyro_data(data[1], tick_time) + elif data[0] == "HR": + sleepdata.process_heartrate_data(data[1], tick_time) + + 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 + success = False + timeout = 3 + 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) + + while not success: + try: + band = miband(MAC_ADDR, AUTH_KEY, debug=True) + success = band.initialize() + except BTLEDisconnectError: + print(msg.format(timeout)) + time.sleep(timeout) + except KeyboardInterrupt: + print("\nExit.") + exit() + + +def start_data_pull(): + while True: + try: + band.start_heart_and_gyro(sensitivity=1, callback=sleep_monitor_callback) + except BTLEDisconnectError: + band.gyro_started_flag = False + connect() + + +def start_vibration(): + while True: + try: + #vibration.timed_vibration(vibration_settings) + vibration.heartrate_alarm(vibration_settings) + + except BTLEDisconnectError: + print("Vibration thread waiting for band reconnect...") + time.sleep(1) + + +if __name__ == "__main__": + connect() + vibration = Vibrate(band) + threading.Thread(target=start_data_pull).start() + threading.Thread(target=start_vibration).start() + sleepdata.init_graph(maximize=maximize_graph, graph_displaytime_mins=5) + + + +#import simpleaudio as sa +# comfort_wav = 'comfort.wav' +# wave_obj = sa.WaveObject.from_wave_file(comfort_wav) +# comfort_delay = 30 +# comfort_lasttime = time.time() diff --git a/bluesleep_BACKUP_570995.py b/bluesleep_BACKUP_570995.py new file mode 100755 index 0000000..2ca0dff --- /dev/null +++ b/bluesleep_BACKUP_570995.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 + +import time, re, threading +from bluepy.btle import BTLEDisconnectError +from miband import miband +import sleepdata +from vibrate import Vibrate + + + + +auth_key_filename = 'auth_key.txt' +mac_filename = 'mac.txt' + +maximize_graph = False + +vibration_settings = { +<<<<<<< Updated upstream +<<<<<<< Updated upstream + 'interval_minutes': 0.1, + 'duration_seconds': 5, + 'type': 'random' +======= +======= +>>>>>>> Stashed changes + 'interval_minutes': 20, + 'duration_seconds': 10, + 'type': 'random', + 'heartrate_alarm_pct': 17 +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes + } + +band = None + +#-------------------------------------------------------------------------# + + +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): + try: + with open(filename, "r") as f: + hwaddr_search = re.search(regex_patterns.mac_regex_pattern, f.read().strip()) + if hwaddr_search: + MAC_ADDR = hwaddr_search[0] + else: + print ("No valid MAC address found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("MAC file not found: {}".format(filename)) + exit(1) + return MAC_ADDR + + +def get_auth_key(filename): + try: + with open(filename, "r") as f: + key_search = re.search(regex_patterns.authkey_regex_pattern, f.read().strip()) + if key_search: + AUTH_KEY = bytes.fromhex(key_search[0]) + else: + print ("No valid auth key found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("Auth key file not found: {}".format(filename)) + exit(1) + return AUTH_KEY + + +def average_data(tick_time): + if (tick_time - sleepdata.last_tick_time) >= sleepdata.tick_seconds: + sleepdata.average_raw_data(tick_time) + sleepdata.last_tick_time = time.time() + + +def sleep_monitor_callback(data): + tick_time = time.time() + + if not sleepdata.last_tick_time: + sleepdata.last_tick_time = time.time() + + if data[0] == "GYRO_RAW": + sleepdata.process_gyro_data(data[1], tick_time) + elif data[0] == "HR": + sleepdata.process_heartrate_data(data[1], tick_time) + + 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 + success = False + timeout = 3 + 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) + + while not success: + try: + band = miband(MAC_ADDR, AUTH_KEY, debug=True) + success = band.initialize() + except BTLEDisconnectError: + print(msg.format(timeout)) + time.sleep(timeout) + except KeyboardInterrupt: + print("\nExit.") + exit() + + +def start_data_pull(): + while True: + try: + band.start_heart_and_gyro(sensitivity=1, callback=sleep_monitor_callback) + except BTLEDisconnectError: + band.gyro_started_flag = False + connect() + + +def start_vibration(): + while True: + try: + #vibration.timed_vibration(vibration_settings) + vibration.heartrate_alarm(vibration_settings) + + except BTLEDisconnectError: + print("Vibration thread waiting for band reconnect...") + time.sleep(1) + + +if __name__ == "__main__": + connect() + vibration = Vibrate(band) + threading.Thread(target=start_data_pull).start() + threading.Thread(target=start_vibration).start() + sleepdata.init_graph(maximize=maximize_graph, graph_displaytime_mins=5) + + + +#import simpleaudio as sa +# comfort_wav = 'comfort.wav' +# wave_obj = sa.WaveObject.from_wave_file(comfort_wav) +# comfort_delay = 30 +# comfort_lasttime = time.time() diff --git a/bluesleep_BASE_570995.py b/bluesleep_BASE_570995.py new file mode 100644 index 0000000..e196d8c --- /dev/null +++ b/bluesleep_BASE_570995.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 + +import time, re, threading +from bluepy.btle import BTLEDisconnectError +from miband import miband +import sleepdata +from vibrate import Vibrate + + + + +auth_key_filename = 'auth_key.txt' +mac_filename = 'mac.txt' + +maximize_graph = False + +vibration_settings = { + 'interval_minutes': 45, + 'duration_seconds': 5, + 'type': 'random' + } + +band = None + +#-------------------------------------------------------------------------# + + +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): + try: + with open(filename, "r") as f: + hwaddr_search = re.search(regex_patterns.mac_regex_pattern, f.read().strip()) + if hwaddr_search: + MAC_ADDR = hwaddr_search[0] + else: + print ("No valid MAC address found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("MAC file not found: {}".format(filename)) + exit(1) + return MAC_ADDR + + +def get_auth_key(filename): + try: + with open(filename, "r") as f: + key_search = re.search(regex_patterns.authkey_regex_pattern, f.read().strip()) + if key_search: + AUTH_KEY = bytes.fromhex(key_search[0]) + else: + print ("No valid auth key found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("Auth key file not found: {}".format(filename)) + exit(1) + return AUTH_KEY + + +def average_data(tick_time): + if (tick_time - sleepdata.last_tick_time) >= sleepdata.tick_seconds: + sleepdata.average_raw_data(tick_time) + sleepdata.last_tick_time = time.time() + + +def sleep_monitor_callback(data): + tick_time = time.time() + + if not sleepdata.last_tick_time: + sleepdata.last_tick_time = time.time() + + if data[0] == "GYRO_RAW": + sleepdata.process_gyro_data(data[1], tick_time) + elif data[0] == "HR": + sleepdata.process_heartrate_data(data[1], tick_time) + + average_data(tick_time) + + +def connect(): + global band + success = False + timeout = 3 + 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) + + while not success: + try: + band = miband(MAC_ADDR, AUTH_KEY, debug=True) + success = band.initialize() + except BTLEDisconnectError: + print(msg.format(timeout)) + time.sleep(timeout) + except KeyboardInterrupt: + print("\nExit.") + exit() + + +def start_data_pull(): + while True: + try: + band.start_heart_and_gyro(sensitivity=1, callback=sleep_monitor_callback) + except BTLEDisconnectError: + band.gyro_started_flag = False + connect() + + +def start_vibration(): + while True: + try: + vibration.timed_vibration(vibration_settings) + except BTLEDisconnectError: + print("Vibration thread waiting for band reconnect...") + time.sleep(1) + + +if __name__ == "__main__": + connect() + vibration = Vibrate(band) + threading.Thread(target=start_data_pull).start() + threading.Thread(target=start_vibration).start() + sleepdata.init_graph(maximize=maximize_graph, graph_displaytime_mins=5) + + + +#import simpleaudio as sa +# comfort_wav = 'comfort.wav' +# wave_obj = sa.WaveObject.from_wave_file(comfort_wav) +# comfort_delay = 30 +# comfort_lasttime = time.time() diff --git a/bluesleep_LOCAL_570995.py b/bluesleep_LOCAL_570995.py new file mode 100644 index 0000000..836a40c --- /dev/null +++ b/bluesleep_LOCAL_570995.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 + +import time, re, threading +from bluepy.btle import BTLEDisconnectError +from miband import miband +import sleepdata +from vibrate import Vibrate + + + + +auth_key_filename = 'auth_key.txt' +mac_filename = 'mac.txt' + +maximize_graph = False + +vibration_settings = { +<<<<<<< Updated upstream + 'interval_minutes': 0.1, + 'duration_seconds': 5, + 'type': 'random' +======= + 'interval_minutes': 20, + 'duration_seconds': 10, + 'type': 'random', + 'heartrate_alarm_pct': 17 +>>>>>>> Stashed changes + } + +band = None + +#-------------------------------------------------------------------------# + + +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): + try: + with open(filename, "r") as f: + hwaddr_search = re.search(regex_patterns.mac_regex_pattern, f.read().strip()) + if hwaddr_search: + MAC_ADDR = hwaddr_search[0] + else: + print ("No valid MAC address found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("MAC file not found: {}".format(filename)) + exit(1) + return MAC_ADDR + + +def get_auth_key(filename): + try: + with open(filename, "r") as f: + key_search = re.search(regex_patterns.authkey_regex_pattern, f.read().strip()) + if key_search: + AUTH_KEY = bytes.fromhex(key_search[0]) + else: + print ("No valid auth key found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("Auth key file not found: {}".format(filename)) + exit(1) + return AUTH_KEY + + +def average_data(tick_time): + if (tick_time - sleepdata.last_tick_time) >= sleepdata.tick_seconds: + sleepdata.average_raw_data(tick_time) + sleepdata.last_tick_time = time.time() + + +def sleep_monitor_callback(data): + tick_time = time.time() + + if not sleepdata.last_tick_time: + sleepdata.last_tick_time = time.time() + + if data[0] == "GYRO_RAW": + sleepdata.process_gyro_data(data[1], tick_time) + elif data[0] == "HR": + sleepdata.process_heartrate_data(data[1], tick_time) + + 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 + success = False + timeout = 3 + 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) + + while not success: + try: + band = miband(MAC_ADDR, AUTH_KEY, debug=True) + success = band.initialize() + except BTLEDisconnectError: + print(msg.format(timeout)) + time.sleep(timeout) + except KeyboardInterrupt: + print("\nExit.") + exit() + + +def start_data_pull(): + while True: + try: + band.start_heart_and_gyro(sensitivity=1, callback=sleep_monitor_callback) + except BTLEDisconnectError: + band.gyro_started_flag = False + connect() + + +def start_vibration(): + while True: + try: + #vibration.timed_vibration(vibration_settings) + vibration.heartrate_alarm(vibration_settings) + + except BTLEDisconnectError: + print("Vibration thread waiting for band reconnect...") + time.sleep(1) + + +if __name__ == "__main__": + connect() + vibration = Vibrate(band) + threading.Thread(target=start_data_pull).start() + threading.Thread(target=start_vibration).start() + sleepdata.init_graph(maximize=maximize_graph, graph_displaytime_mins=5) + + + +#import simpleaudio as sa +# comfort_wav = 'comfort.wav' +# wave_obj = sa.WaveObject.from_wave_file(comfort_wav) +# comfort_delay = 30 +# comfort_lasttime = time.time() diff --git a/bluesleep_REMOTE_570995.py b/bluesleep_REMOTE_570995.py new file mode 100644 index 0000000..cca2f7e --- /dev/null +++ b/bluesleep_REMOTE_570995.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 + +import time, re, threading +from bluepy.btle import BTLEDisconnectError +from miband import miband +import sleepdata +from vibrate import Vibrate + + + + +auth_key_filename = 'auth_key.txt' +mac_filename = 'mac.txt' + +maximize_graph = False + +vibration_settings = { + 'interval_minutes': 20, + 'duration_seconds': 10, + 'type': 'random', + 'heartrate_alarm_pct': 17 + } + +band = None + +#-------------------------------------------------------------------------# + + +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): + try: + with open(filename, "r") as f: + hwaddr_search = re.search(regex_patterns.mac_regex_pattern, f.read().strip()) + if hwaddr_search: + MAC_ADDR = hwaddr_search[0] + else: + print ("No valid MAC address found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("MAC file not found: {}".format(filename)) + exit(1) + return MAC_ADDR + + +def get_auth_key(filename): + try: + with open(filename, "r") as f: + key_search = re.search(regex_patterns.authkey_regex_pattern, f.read().strip()) + if key_search: + AUTH_KEY = bytes.fromhex(key_search[0]) + else: + print ("No valid auth key found in {}".format(filename)) + exit(1) + except FileNotFoundError: + print ("Auth key file not found: {}".format(filename)) + exit(1) + return AUTH_KEY + + +def average_data(tick_time): + if (tick_time - sleepdata.last_tick_time) >= sleepdata.tick_seconds: + sleepdata.average_raw_data(tick_time) + sleepdata.last_tick_time = time.time() + + +def sleep_monitor_callback(data): + tick_time = time.time() + + if not sleepdata.last_tick_time: + sleepdata.last_tick_time = time.time() + + if data[0] == "GYRO_RAW": + sleepdata.process_gyro_data(data[1], tick_time) + elif data[0] == "HR": + sleepdata.process_heartrate_data(data[1], tick_time) + + 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 + success = False + timeout = 3 + 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) + + while not success: + try: + band = miband(MAC_ADDR, AUTH_KEY, debug=True) + success = band.initialize() + except BTLEDisconnectError: + print(msg.format(timeout)) + time.sleep(timeout) + except KeyboardInterrupt: + print("\nExit.") + exit() + + +def start_data_pull(): + while True: + try: + band.start_heart_and_gyro(sensitivity=1, callback=sleep_monitor_callback) + except BTLEDisconnectError: + band.gyro_started_flag = False + connect() + + +def start_vibration(): + while True: + try: + #vibration.timed_vibration(vibration_settings) + vibration.heartrate_alarm(vibration_settings) + + except BTLEDisconnectError: + print("Vibration thread waiting for band reconnect...") + time.sleep(1) + + +if __name__ == "__main__": + connect() + vibration = Vibrate(band) + threading.Thread(target=start_data_pull).start() + threading.Thread(target=start_vibration).start() + sleepdata.init_graph(maximize=maximize_graph, graph_displaytime_mins=5) + + + +#import simpleaudio as sa +# comfort_wav = 'comfort.wav' +# wave_obj = sa.WaveObject.from_wave_file(comfort_wav) +# comfort_delay = 30 +# comfort_lasttime = time.time() diff --git a/miband.py b/miband.py index b574ebf..976ae71 100644 --- a/miband.py +++ b/miband.py @@ -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 @@ -301,6 +301,16 @@ class miband(Peripheral): self.waitForNotifications(wait) + # def send_gyro_start(self, sensitivity): + # if not self.gyro_started_flag: + # self._log.info("Starting gyro...") + # self.write_req(self._sensor_handle, BYTEPATTERNS.start) + # self.write_req(self._steps_handle, BYTEPATTERNS.start) + # self.write_req(self._hz_handle, BYTEPATTERNS.start) + # self.gyro_started_flag = True + # self.write_cmd(self._char_sensor, BYTEPATTERNS.gyro_start(sensitivity)) + # self.write_req(self._sensor_handle, BYTEPATTERNS.stop) + # self.write_cmd(self._char_sensor, b'\x02') def send_gyro_start(self, sensitivity): if not self.gyro_started_flag: self._log.info("Starting gyro...") @@ -309,9 +319,10 @@ class miband(Peripheral): self.write_req(self._hz_handle, BYTEPATTERNS.start) self.gyro_started_flag = True self.write_cmd(self._char_sensor, BYTEPATTERNS.gyro_start(sensitivity)) + self.write_cmd(self._char_sensor, bytes.fromhex("010100000019")) self.write_req(self._sensor_handle, BYTEPATTERNS.stop) self.write_cmd(self._char_sensor, b'\x02') - + self.write_cmd(self._char_sensor, b'\x03') def send_heart_measure_start(self): self._log.info("Starting heart measure...") diff --git a/sleepdata.py b/sleepdata.py index b7666a4..abc926c 100644 --- a/sleepdata.py +++ b/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: diff --git a/vibrate.py b/vibrate.py index b4a4243..32ee355 100644 --- a/vibrate.py +++ b/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'] + 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 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 type == 'random': + self.vibrate_random(duration_seconds) + elif type == 'pattern': + self.vibrate_pattern(duration_seconds) + elif type == 'rolling': + self.vibrate_rolling(duration_seconds) + elif 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