Ejemplo n.º 1
0
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")