summaryrefslogblamecommitdiffstats
path: root/glucometerutils/common.py
blob: 8b413202947de428c34f9b57b32d085270c825a9 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       

                              

                                              
               
           
               
 
    
                                         
                   

        

           
                      

                     
 
                                
                      


                          
 
                              
                                   

                                               
                 
 
 
                                                    
                                        
                                                              
 



                                                                   
 




                                                              
 

                            
 

                                     

                                 
 

                     
 

                                               
                   


                                                               

                                               

                                                         
                                      

                                    
                               







                                                                    
                             



                                                                              
 

                    
 


                                               
                                      
 


                                                                              
 
                                          
                                                                             
                         
 
       






                                                          
                                      








                                                                         
                









                                                                                


                                                          
                          


                                                                






                                                       
                                          







                                                                          





                                                                   
# -*- coding: utf-8 -*-
#
# SPDX-License-Identifier: MIT
"""Common routines for data in glucometers."""

import datetime
import enum
import textwrap

try:
    from typing import Optional, Sequence
except ImportError:
    pass

import attr

class Unit(enum.Enum):
    MG_DL = 'mg/dL'
    MMOL_L = 'mmol/L'

# Constants for meal information
class Meal(enum.Enum):
    NONE = ''
    BEFORE = 'Before Meal'
    AFTER = 'After Meal'

# Constants for measure method
class MeasurementMethod(enum.Enum):
    BLOOD_SAMPLE = 'blood sample'
    CGM = 'CGM' # Continuous Glucose Monitoring
    TIME = 'time'


def convert_glucose_unit(value, from_unit, to_unit):
    # type: (float, Unit, Unit) -> float
    """Convert the given value of glucose level between units.

    Args:
      value: The value of glucose in the current unit
      from_unit: The unit value is currently expressed in
      to_unit: The unit to conver the value to: the other if empty.

    Returns:
      The converted representation of the blood glucose level.
    """
    from_unit = Unit(from_unit)
    to_unit = Unit(to_unit)

    if from_unit == to_unit:
        return value

    if from_unit == Unit.MG_DL:
        return round(value / 18.0, 2)

    return round(value * 18.0, 0)

@attr.s
class GlucoseReading:

    timestamp = attr.ib(type=datetime.datetime)
    value = attr.ib(type=float)
    meal = attr.ib(
        default=Meal.NONE, validator=attr.validators.in_(Meal),
        type=Meal)
    comment = attr.ib(default='', type=str)
    measure_method = attr.ib(
        default=MeasurementMethod.BLOOD_SAMPLE,
        validator=attr.validators.in_(MeasurementMethod),
        type=MeasurementMethod)
    extra_data = attr.ib(factory=dict)

    def get_value_as(self, to_unit):
        # type: (Unit) -> float
        """Returns the reading value as the given unit.

        Args:
          to_unit: (Unit) The unit to return the value to.
        """
        return convert_glucose_unit(self.value, Unit.MG_DL, to_unit)

    def as_csv(self, unit):
        # type: (Unit) -> str
        """Returns the reading as a formatted comma-separated value string."""
        return '"%s","%.2f","%s","%s","%s"' % (
            self.timestamp, self.get_value_as(unit), self.meal.value,
            self.measure_method.value, self.comment)

@attr.s
class KetoneReading:

    timestamp = attr.ib(type=datetime.datetime)
    value = attr.ib(type=float)
    comment = attr.ib(default='', type=str)
    extra_data = attr.ib(factory=dict)

    def as_csv(self, unit):
        """Returns the reading as a formatted comma-separated value string."""
        del unit  # Unused for Ketone readings.

        return '"%s","%.2f","%s","%s"' % (
            self.timestamp, self.value, MeasurementMethod.BLOOD_SAMPLE.value,
            self.comment)

@attr.s
class TimeAdjustment:
    timestamp = attr.ib()  # type: datetime.datetime
    old_timestamp = attr.ib()  # type: datetime.datetime
    measure_method = attr.ib(
        default=MeasurementMethod.TIME,
        validator=attr.validators.in_(
            MeasurementMethod))  # type: MeasurementMethod
    extra_data = attr.ib(factory=dict)

    def as_csv(self, unit):
        del unit
        return '"%s","","%s","%s"' % (
            self.timestamp, self.measure_method.value, self.old_timestamp
        )


@attr.s
class MeterInfo:
    """General information about the meter.

    Attributes:
      model: Human readable model name, chosen by the driver.
      serial_number: Serial number identified for the reader (or N/A if not
        available in the protocol.)
      version_info: List of strings with any version information available about
        the device. It can include hardware and software version.
      native_unit: One of the Unit values to identify the meter native unit.
    """
    model = attr.ib(type=str)
    serial_number = attr.ib(default='N/A', type=str)
    version_info = attr.ib(default=(), type=Sequence[str])
    native_unit = attr.ib(
        default=Unit.MG_DL, validator=attr.validators.in_(Unit),
        type=Unit)
    patient_name = attr.ib(default=None, type=Optional[str])

    def __str__(self):
        version_information_string = 'N/A'
        if self.version_info:
            version_information_string = '\n    '.join(
                self.version_info).strip()

        base_output = textwrap.dedent("""\
            {model}
            Serial Number: {serial_number}
            Version Information:
                {version_information_string}
            Native Unit: {native_unit}
        """).format(model=self.model, serial_number=self.serial_number,
                    version_information_string=version_information_string,
                    native_unit=self.native_unit.value)

        if self.patient_name != None:
            base_output += 'Patient Name: {patient_name}\n'.format(
                patient_name=self.patient_name)

        return base_output