def main_machine(patient_id, peristaltic_pump, flags, DB_FILE): """ :param patient_id: patient identifier to assign the machine to someone else :param peristaltic_pump: peristaltic_pump by the system :param flags: flags defined by the system :return: """ logging.info("thread of the machine starts") # definition button_listener for on/off thread_machine_on = threading.Thread( name='on_off_button', target=power_button.thread_button_pressed, args=(flags.flag_exit, ), daemon=False) # definition request dose for on/off thread_dose_request = threading.Thread( name='request dose button', target=request_button.thread_button_pressed, args=(flag_request_dose, flag_stop_request, flags.flag_exit), daemon=False) # definition glass IR thread_glass = threading.Thread(name='check glass', target=ir_glass.thread_check_object, args=(flags.flag_glass, flags.flag_exit), daemon=False) # definition juice IR thread_juice = threading.Thread(name='check juice box', target=ir_juice.thread_check_object, args=(flags.flag_juice, flags.flag_exit), daemon=False) # no error at the beginning errors = False counter_error = 0 # starting the listener for pressing the exit button thread_machine_on.start() # starting the thread for pressing the dose request thread_dose_request.start() # todo: uncomment the next lines # starting the thread for check the glass thread_glass.start() # starting the thread for check the juice # thread_juice.start() # define the display used for notify data display = Notifier(PORT_DISPLAY) # infinite loop wait for shutdown button while not flags.flag_exit.is_set(): db = Database(DB_FILE) patient = db.pull_patient(patient_id) logging.info(patient) source_cgm = Nightscout(patient) flag_request_dose.clear() flag_stop_request.clear() flags.flag_juice.set() # todo: remove it #flags.flag_glass.set() # todo: remove it try: # retrieve the glucose value -> with management of error cgm = source_cgm.get_cgm( ) # retrieve data from Nightscout (based on patient settings) except urllib.error.HTTPError: logging.warning('HTTP ERROR') errors = True # turn on the flag of errors request_led.turn_off() # turn off the led for dose request flags.flag_dose_may_be_required.clear() display.notify_error_connection( "HTTP ERROR!", True) # display the head of the error except urllib.error.URLError: # this error include content to short logging.warning('URL ERROR') errors = True request_led.turn_off() # turn off the led for dose request flags.flag_dose_may_be_required.clear() display.notify_error_connection( "URL ERROR!", True) # display the head of the error # todo: except the invalid data except Exception as e: logging.warning('Checkout this error', e) errors = True request_led.turn_off() # turn off the led for dose request flags.flag_dose_may_be_required.clear() display.notify_error_connection( "NO DATA!", True) # display the head of the error else: # no errors are detected errors = False # reset any error from previous counter_error = 0 # reset error counter db.push_unique_cgm(cgm) # store the glucose value anomaly = source_cgm.eval_cgm( cgm) # eval data value based on the threshold recent = source_cgm.is_recent( cgm, THRESHOLD.sec_recent) # eval data recent or not last_dose = db.pull_last_dose( patient.id) # retrieve the last dose received from the patient treatment_ingoing = source_cgm.under_treatment( last_dose, cgm, THRESHOLD.sec_dose) cgm_increased = source_cgm.rising_glucose(cgm) # case 1: data recent and hypoglycemia is detected if (not cgm_increased and not treatment_ingoing ) and anomaly == AnomalousSgv.HYPO and recent: request_led.turn_off() # turn off the led for dose request flags.flag_dose_may_be_required.clear() # eval the hypoglycemia (severe = 20 grams, not_severe = 15 grams) last_hour_date_time = datetime.now(tz=None) - timedelta( hours=2) last_hour_date_time = int(last_hour_date_time.timestamp()) other_cgm = db.pull_cgm_from(patient.id, last_hour_date_time) severe_hypo = source_cgm.eval_severe_hypoglycemia( cgm, other_cgm) # try to deliver the juice (if it's possible) result = manager_hypo(db, severe_hypo, patient.id, display, flags, peristaltic_pump) if not result: # the distribution failed # display data and wait another iteration display.notify_value(anomaly, treatment_ingoing, cgm) # todo: verify the feedback flags.flag_exit.wait( THRESHOLD.sec_investigation / 2 ) # in case of not successful distribution display data # case 2: data recent and the patient may ask for a dose elif (not cgm_increased and not treatment_ingoing ) and anomaly == AnomalousSgv.TO_INVESTIGATE and recent: request_led.turn_on() flags.flag_dose_may_be_required.set() display.notify_value(anomaly, treatment_ingoing, cgm) # display data flag_stop_request.wait(THRESHOLD.sec_investigation) # case 2.1 the patient request a dose (he press the button) or use the bot if flag_request_dose.is_set( ) or flags.flag_bot_request_dose.is_set(): request_led.turn_off() flags.flag_dose_may_be_required.clear() severe_hypo = True success = manager_hypo(db, severe_hypo, patient.id, display, flags, peristaltic_pump) # when the bot request a dose, it it early insert into the system if flags.flag_bot_request_dose.is_set() and not success: fail_dose = db.pull_last_dose(patient.id) db.remove_dose(fail_dose) flags.flag_bot_request_dose.clear() # treatment_ingoing = manager_hypo(db, severe_hypo, patient.id, display, flags) # display.notify_value(anomaly, treatment_ingoing, cgm) # case 3: data are recent and into a normal range, no hurry to evaluate them elif anomaly == AnomalousSgv.NORMAL and recent: # todo: add arrow down request_led.turn_off() flags.flag_dose_may_be_required.clear() request_timing = THRESHOLD.sec_fetch if request_timing > 60: refresh = request_timing / 60 count = 1 while count <= refresh: display.notify_value(anomaly, treatment_ingoing, cgm) flags.flag_exit.wait(60) count = count + 1 # case others: display data and update them (no error was detected) else: request_led.turn_off() # turn off the led for dose request flags.flag_dose_may_be_required.clear() display.notify_value(anomaly, treatment_ingoing, cgm) flags.flag_exit.wait(THRESHOLD.sec_investigation) finally: # close the connection with the db in this way the update from the bot may be performed db.close() # something went wrong if errors: counter_error = counter_error + 1 if counter_error <= MAX_TRIES: display.notify_error_connection( "err: " + str(counter_error) + " on " + str(MAX_TRIES), False) flags.flag_exit.wait(THRESHOLD.sec_error) else: logging.warning( 'Too many error the machine will be turned off') display.notify_error('Too many errors!\nMachine OFF') flags.flag_exit.wait( 10) # give the user the possibility to see the message flags.flag_exit.set() # stop the main and kill the machine break # todo add a reminder for glass and juice # out from the loop request_led.turn_off() flags.flag_dose_may_be_required.clear() display.turn_off() logging.info("the thread of the machine arrives at the end")