From 093e7a500699bcc94dfa90af40ca6c6184031baa Mon Sep 17 00:00:00 2001 From: Nate Schoolfield Date: Sun, 31 Jan 2021 15:05:24 -0800 Subject: [PATCH] Made vibration thread-safe, fixed CSV output issue --- bluesleep.py | 3 +-- miband.py | 62 +++++++++++++++++++++++++++++++++++++++------------- sleepdata.py | 6 ----- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/bluesleep.py b/bluesleep.py index bd8e185..ba4daaa 100755 --- a/bluesleep.py +++ b/bluesleep.py @@ -24,7 +24,6 @@ buzz_timer = time.time() buzz_minutes = 45 buzz_delay = buzz_minutes * 60 - #-------------------------------------------------------------------------# class regex_patterns(): @@ -183,7 +182,7 @@ if __name__ == "__main__": connect(mac_filename, auth_key_filename) threading.Thread(target=start_data_pull).start() threading.Thread(target=timed_buzzing, args=([buzz_delay, 15])).start() - sleepdata.init_graph() + #sleepdata.init_graph() diff --git a/miband.py b/miband.py index dc69c97..6164be7 100644 --- a/miband.py +++ b/miband.py @@ -82,6 +82,7 @@ class miband(Peripheral): self.gyro_raw_callback = None self.auth_key = key self.queue = Queue() + self.write_queue = Queue() self.gyro_started_flag = False self.svc_1 = self.getServiceByUUID(UUIDS.SERVICE_MIBAND1) @@ -209,35 +210,66 @@ class miband(Peripheral): return_tuple = ["GYRO", res] return return_tuple + + def process_write_queue(self): + while True: + try: + res = self.write_queue.get(False) + _type = res[0] + _payload = res[1] + if _type == 'write_cmd': + self.write_cmd(_payload[0], _payload[1], response=_payload[2]) + elif _type == 'write_req': + self.write_req(_payload[0], _payload[1], response=_payload[2]) + except Empty: + break + def vibrate(self, ms): vibration_scaler = 0.75 ms = min([round(ms / vibration_scaler), 255]) sent_value = int(ms / 2) vibration_duration = ms / 1000 - self._char_alert.write(bytepattern.vibration(sent_value), withResponse=False) + self.write_cmd(self._char_alert, bytepattern.vibration(sent_value), queued=True) time.sleep(vibration_duration) + def write_cmd(self, characteristic, data, response=False, queued=False): + if queued: + self.write_queue.put(['write_cmd', [characteristic, data, response]]) + else: + characteristic.write(data, withResponse=response) + + def write_req(self, handle, data, response=True, queued=False): + if queued: + self.write_queue.put(['write_req', [handle, data, response]]) + else: + self.writeCharacteristic(handle, data, withResponse=response) + + + def wait_for_notifications_with_queued_writes(self, wait): + self.process_write_queue() + self.waitForNotifications(wait) + def send_gyro_start(self, sensitivity): if not self.gyro_started_flag: self._log.info("Starting gyro...") - self.writeCharacteristic(self._sensor_handle, bytepattern.start, withResponse=True) - self.writeCharacteristic(self._steps_handle, bytepattern.start, withResponse=True) - self.writeCharacteristic(self._hz_handle, bytepattern.start, withResponse=True) + self.write_req(self._sensor_handle, bytepattern.start) + self.write_req(self._steps_handle, bytepattern.start) + self.write_req(self._hz_handle, bytepattern.start) self.gyro_started_flag = True - - self._char_sensor.write(bytepattern.gyro_start(sensitivity), withResponse=False) - self.writeCharacteristic(self._sensor_handle, bytepattern.stop, withResponse=True) - self._char_sensor.write(b'\x02', withResponse=False) + self.write_cmd(self._char_sensor, bytepattern.gyro_start(sensitivity)) + self.write_req(self._sensor_handle, bytepattern.stop) + self.write_cmd(self._char_sensor, b'\x02') def send_heart_measure_start(self): self._log.info("Starting heart measure...") - self._char_heart_ctrl.write(bytepattern.stop_heart_measure_manual, True) - self._char_heart_ctrl.write(bytepattern.stop_heart_measure_continues, True) - self.writeCharacteristic(self._heart_measure_handle, bytepattern.start, withResponse=True) - self._char_heart_ctrl.write(bytepattern.start_heart_measure_continues, True) - + self.write_cmd(self._char_heart_ctrl, bytepattern.stop_heart_measure_manual, response=True) + self.write_cmd(self._char_heart_ctrl, bytepattern.stop_heart_measure_continues, response=True) + self.write_req(self._heart_measure_handle, bytepattern.start) + self.write_cmd(self._char_heart_ctrl, bytepattern.start_heart_measure_continues, response=True) + + def send_heart_measure_keepalive(self): - self._char_heart_ctrl.write(bytepattern.heart_measure_keepalive, True) + self.write_cmd(self._char_heart_ctrl, bytepattern.heart_measure_keepalive, response=True) def start_heart_and_gyro(self, sensitivity, callback): self.heart_measure_callback = callback @@ -248,7 +280,7 @@ class miband(Peripheral): heartbeat_time = time.time() while True: - self.waitForNotifications(0.5) + self.wait_for_notifications_with_queued_writes(0.5) self._parse_queue() if (time.time() - heartbeat_time) >= 12: heartbeat_time = time.time() diff --git a/sleepdata.py b/sleepdata.py index 58f3058..a01f51a 100644 --- a/sleepdata.py +++ b/sleepdata.py @@ -77,10 +77,6 @@ def flush_old_raw_data(tick_time): 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) @@ -119,8 +115,6 @@ def average_raw_data(tick_time): 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