pydexcom

PyPI Python versions Pre-commit Tests Docs

A simple Python API to interact with Dexcom Share service. Used to get real-time Dexcom CGM sensor data.

Quickstart

  1. Download the Dexcom G6 / G5 / G4 mobile app and enable the Share service.

The Dexcom Share service requires setup of at least one follower to enable the share service, but pydexcom will use your credentials, not the follower's

  1. Install the pydexcom package.

    pip3 install pydexcom

  2. Profit.

>>> from pydexcom import Dexcom
>>> dexcom = Dexcom("username", "password") # `ous=True` if outside of US
>>> glucose_reading = dexcom.get_current_glucose_reading()
>>> print(glucose_reading)
85

>>> glucose_reading.value
85

>>> glucose_reading.mmol_l
4.7

>>> glucose_reading.trend
4

>>> glucose_reading.trend_direction
'Flat'

>>> glucose_reading.trend_description
'steady'

>>> glucose_reading.trend_arrow
'→'

>>> print(bg.datetime)
2023-08-07 20:40:58

>>> glucose_reading.json
{'WT': 'Date(1691455258000)', 'ST': 'Date(1691455258000)', 'DT': 'Date(1691455258000-0400)', 'Value': 85, 'Trend': 'Flat'}

Documentation

https://gagebenne.github.io/pydexcom/pydexcom.html

Frequently Asked Questions

Why is my password not working?

The Dexcom Share API understandably reports limited information during account validation. If anything is incorrect, the API simply reports back invalid password (pydexcom.errors.AccountErrorEnum). However, there could be many reasons you are getting this error:

  1. Use the correct Dexcom Share API instance.

If you are located outside of the United States, be sure to set ous=True when intializing Dexcom.

  1. Use your Dexcom Share credentials, not the follower's credentials.

Use the same credentials used to login to the Dexcom mobile application publishing the glucose readings.

  1. Ensure you have at least one follower on Dexcom Share.

The Dexcom Share service requires setup of at least one follower to enable the service, as does this package.

  1. Check whether your account credentials involve usernames or emails.

There are two account types the Dexcom Share API uses: legacy username-based accounts, and newer email-based accounts. Be sure to use the correct authentication method.

  1. Use alpha-numeric passwords.

Some individuals have had problems with connecting when their Dexcom Share passwords are entirely numeric. If you have connection issues, try changing your password to something with a mix of numbers and letters.

  1. Report it!

The Dexcom Share API sometimes changes. If you believe there is an issue with pydexcom , feel free to create an issue if one has not been created yet already.

Why not use the official Dexcom Developer API?

The official Dexcom API is a great tool to view trends, statistics, and day-by-day data, but is not suitable for real time fetching of glucose readings as it is a retrospective API.

How can I let you know of suggestions or issues?

By all means submit a pull request if you have a feature you would like to see in the next release. Alternatively, you may create an issue if you have a suggestion or bug you'd like to report.

Where is this package being used?

Primarily this package is used in the Home Assistant Dexcom integration, but it's fantastic to see community projects involving pydexcom:

  1"""
  2.. include:: ../README.md
  3"""
  4import logging
  5import re
  6from datetime import datetime
  7from typing import Any, Dict, List, Optional
  8
  9import requests
 10
 11from .const import (
 12    DEFAULT_UUID,
 13    DEXCOM_APPLICATION_ID,
 14    DEXCOM_AUTHENTICATE_ENDPOINT,
 15    DEXCOM_BASE_URL,
 16    DEXCOM_BASE_URL_OUS,
 17    DEXCOM_GLUCOSE_READINGS_ENDPOINT,
 18    DEXCOM_LOGIN_ID_ENDPOINT,
 19    DEXCOM_TREND_DIRECTIONS,
 20    MAX_MAX_COUNT,
 21    MAX_MINUTES,
 22    MMOL_L_CONVERSION_FACTOR,
 23    TREND_ARROWS,
 24    TREND_DESCRIPTIONS,
 25)
 26from .errors import (
 27    AccountError,
 28    AccountErrorEnum,
 29    ArgumentError,
 30    ArgumentErrorEnum,
 31    DexcomError,
 32    SessionError,
 33    SessionErrorEnum,
 34)
 35
 36_LOGGER = logging.getLogger("pydexcom")
 37
 38
 39class GlucoseReading:
 40    """Class for parsing glucose reading from Dexcom Share API."""
 41
 42    def __init__(self, json_glucose_reading: Dict[str, Any]):
 43        """Initialize `GlucoseReading` with JSON glucose reading from Dexcom Share API.
 44
 45        :param json_glucose_reading: JSON glucose reading from Dexcom Share API
 46        """
 47        self._json = json_glucose_reading
 48        try:
 49            self._value = int(json_glucose_reading["Value"])
 50            self._trend_direction: str = json_glucose_reading["Trend"]
 51            # Dexcom Share API returns `str` direction now, previously `int` trend
 52            self._trend: int = DEXCOM_TREND_DIRECTIONS[self._trend_direction]
 53            self._datetime = datetime.fromtimestamp(
 54                int(re.sub("[^0-9]", "", json_glucose_reading["WT"])) / 1000.0
 55            )
 56        except (KeyError, TypeError, ValueError):
 57            raise ArgumentError(ArgumentErrorEnum.GLUCOSE_READING_INVALID)
 58
 59    @property
 60    def value(self) -> int:
 61        """Blood glucose value in mg/dL."""
 62        return self._value
 63
 64    @property
 65    def mg_dl(self) -> int:
 66        """Blood glucose value in mg/dL."""
 67        return self._value
 68
 69    @property
 70    def mmol_l(self) -> float:
 71        """Blood glucose value in mmol/L."""
 72        return round(self.value * MMOL_L_CONVERSION_FACTOR, 1)
 73
 74    @property
 75    def trend(self) -> int:
 76        """Blood glucose trend information
 77        (value of `pydexcom.const.DEXCOM_TREND_DIRECTIONS`)."""
 78        return self._trend
 79
 80    @property
 81    def trend_direction(self) -> str:
 82        """Blood glucose trend direction
 83        (key of `pydexcom.const.DEXCOM_TREND_DIRECTIONS`)."""
 84        return self._trend_direction
 85
 86    @property
 87    def trend_description(self) -> Optional[str]:
 88        """Blood glucose trend information description
 89        (`pydexcom.const.TREND_DESCRIPTIONS`).
 90        """
 91        return TREND_DESCRIPTIONS[self._trend]
 92
 93    @property
 94    def trend_arrow(self) -> str:
 95        """Blood glucose trend as unicode arrow (`pydexcom.const.TREND_ARROWS`)."""
 96        return TREND_ARROWS[self._trend]
 97
 98    @property
 99    def datetime(self) -> datetime:
100        """Glucose reading recorded time as datetime."""
101        return self._datetime
102
103    @property
104    def json(self) -> Dict[str, Any]:
105        """JSON glucose reading from Dexcom Share API."""
106        return self._json
107
108    def __str__(self) -> str:
109        return str(self._value)
110
111
112class Dexcom:
113    """Class for communicating with Dexcom Share API."""
114
115    def __init__(self, username: str, password: str, ous: bool = False):
116        """
117        Initialize `Dexcom` with Dexcom Share credentials.
118
119        :param username: username for the Dexcom Share user, *not follower*.
120        :param password: password for the Dexcom Share user.
121        :param ous: whether the Dexcom Share user is outside of the US.
122        """
123        self._base_url = DEXCOM_BASE_URL_OUS if ous else DEXCOM_BASE_URL
124        self._username = username
125        self._password = password
126        self._account_id: Optional[str] = None
127        self._session_id: Optional[str] = None
128        self.__session = requests.Session()
129        self._session()
130
131    def _post(
132        self,
133        endpoint: str,
134        params: Optional[Dict[str, Any]] = None,
135        json: Optional[Dict[str, Any]] = None,
136    ) -> Any:
137        """Send post request to Dexcom Share API.
138
139        :param endpoint: URL of the post request
140        :param params: `dict` to send in the query string of the post request
141        :param json: JSON to send in the body of the post request
142        """
143        response = self.__session.post(
144            f"{self._base_url}/{endpoint}",
145            headers={"Accept-Encoding": "application/json"},
146            params=params,
147            json={} if json is None else json,
148        )
149
150        try:
151            response.raise_for_status()
152            return response.json()
153        except requests.HTTPError as http_error:
154            error = self._handle_response(response)
155            if error:
156                raise error from http_error
157            _LOGGER.error("%s", response.text)
158            raise http_error
159
160    def _handle_response(self, response: requests.Response) -> Optional[DexcomError]:
161        error: Optional[DexcomError] = None
162        """
163        Parse `requests.Response` for `pydexcom.errors.DexcomError`.
164
165        :param response: `requests.Response` to parse
166        """
167        if response.json():
168            _LOGGER.debug("%s", response.json())
169            code = response.json().get("Code", None)
170            message = response.json().get("Message", None)
171            if code == "SessionIdNotFound":
172                error = SessionError(SessionErrorEnum.NOT_FOUND)
173            elif code == "SessionNotValid":
174                error = SessionError(SessionErrorEnum.INVALID)
175            elif code == "AccountPasswordInvalid":
176                error = AccountError(AccountErrorEnum.PASSWORD_INVALID)
177            elif code == "SSO_AuthenticateMaxAttemptsExceeed":
178                error = AccountError(AccountErrorEnum.MAX_ATTEMPTS)
179            elif code == "InvalidArgument":
180                if message and "accountName" in message:
181                    error = ArgumentError(ArgumentErrorEnum.USERNAME_INVALID)
182                elif message and "password" in message:
183                    error = ArgumentError(ArgumentErrorEnum.PASSWORD_INVALID)
184                elif message and "UUID" in message:
185                    error = ArgumentError(ArgumentErrorEnum.ACCOUNT_ID_INVALID)
186            elif code and message:
187                _LOGGER.debug("%s: %s", code, message)
188        return error
189
190    def _validate_session_id(self) -> None:
191        """Validate session ID."""
192        if any([not isinstance(self._session_id, str), not self._session_id]):
193            raise ArgumentError(ArgumentErrorEnum.SESSION_ID_INVALID)
194        if self._session_id == DEFAULT_UUID:
195            raise ArgumentError(ArgumentErrorEnum.SESSION_ID_DEFAULT)
196
197    def _validate_credentials(self) -> None:
198        """Validate credentials."""
199        if any([not isinstance(self._username, str), not self._username]):
200            raise ArgumentError(ArgumentErrorEnum.USERNAME_INVALID)
201        if any([not isinstance(self._password, str), not self._password]):
202            raise ArgumentError(ArgumentErrorEnum.PASSWORD_INVALID)
203
204    def _validate_account_id(self) -> None:
205        """Validate account ID."""
206        if any([not isinstance(self._account_id, str), not self._account_id]):
207            raise ArgumentError(ArgumentErrorEnum.ACCOUNT_ID_INVALID)
208        if self._account_id == DEFAULT_UUID:
209            raise ArgumentError(ArgumentErrorEnum.ACCOUNT_ID_DEFAULT)
210
211    def _get_account_id(self) -> str:
212        """Retrieve account ID from the authentication endpoint
213        (`pydexcom.const.DEXCOM_AUTHENTICATE_ENDPOINT`)."""
214        _LOGGER.debug("Retrieve account ID from the authentication endpoint")
215        return self._post(
216            DEXCOM_AUTHENTICATE_ENDPOINT,
217            json={
218                "accountName": self._username,
219                "password": self._password,
220                "applicationId": DEXCOM_APPLICATION_ID,
221            },
222        )
223
224    def _get_session_id(self) -> str:
225        """Retrieve session ID from the login endpoint
226        (`pydexcom.const.DEXCOM_LOGIN_ID_ENDPOINT`)."""
227        _LOGGER.debug("Retrieve session ID from the login endpoint")
228        return self._post(
229            DEXCOM_LOGIN_ID_ENDPOINT,
230            json={
231                "accountId": self._account_id,
232                "password": self._password,
233                "applicationId": DEXCOM_APPLICATION_ID,
234            },
235        )
236
237    def _session(self) -> None:
238        """Create Dexcom Share API session."""
239        self._validate_credentials()
240
241        if self._account_id is None:
242            self._account_id = self._get_account_id()
243            self._validate_account_id()
244
245        self._session_id = self._get_session_id()
246        self._validate_session_id()
247
248    def _get_glucose_readings(
249        self, minutes: int = MAX_MINUTES, max_count: int = MAX_MAX_COUNT
250    ) -> List[Dict[str, Any]]:
251        """Retrieve glucose readings from the glucose readings endpoint
252        (`pydexcom.const.DEXCOM_GLUCOSE_READINGS_ENDPOINT`)."""
253        if not isinstance(minutes, int) or any([minutes < 0, minutes > MAX_MINUTES]):
254            raise ArgumentError(ArgumentErrorEnum.MINUTES_INVALID)
255        if not isinstance(max_count, int) or any(
256            [max_count < 0, max_count > MAX_MAX_COUNT]
257        ):
258            raise ArgumentError(ArgumentErrorEnum.MAX_COUNT_INVALID)
259
260        _LOGGER.debug("Retrieve glucose readings from the glucose readings endpoint")
261        return self._post(
262            DEXCOM_GLUCOSE_READINGS_ENDPOINT,
263            params={
264                "sessionId": self._session_id,
265                "minutes": minutes,
266                "maxCount": max_count,
267            },
268        )
269
270    def get_glucose_readings(
271        self, minutes: int = MAX_MINUTES, max_count: int = MAX_MAX_COUNT
272    ) -> List[GlucoseReading]:
273        """Get `max_count` glucose readings within specified number of `minutes`.
274
275        Catches one instance of a thrown `pydexcom.errors.SessionError` if session ID
276        expired, attempts to get a new session ID and retries.
277
278        :param minutes: Number of minutes to retrieve glucose readings from (1-1440)
279        :param max_count: Maximum number of glucose readings to retrieve (1-288)
280        """
281
282        json_glucose_readings: List[Dict[str, Any]] = []
283
284        try:
285            # Requesting glucose reading with DEFAULT_UUID returns non-JSON empty string
286            self._validate_session_id()
287
288            json_glucose_readings = self._get_glucose_readings(minutes, max_count)
289        except SessionError:
290            # Attempt to update expired session ID
291            self._session()
292
293            json_glucose_readings = self._get_glucose_readings(minutes, max_count)
294
295        return [GlucoseReading(json_reading) for json_reading in json_glucose_readings]
296
297    def get_latest_glucose_reading(self) -> Optional[GlucoseReading]:
298        """Get latest available glucose reading, within the last 24 hours."""
299        glucose_readings = self.get_glucose_readings(max_count=1)
300        return glucose_readings[0] if glucose_readings else None
301
302    def get_current_glucose_reading(self) -> Optional[GlucoseReading]:
303        """Get current available glucose reading, within the last 10 minutes."""
304        glucose_readings = self.get_glucose_readings(minutes=10, max_count=1)
305        return glucose_readings[0] if glucose_readings else None
class GlucoseReading:
 40class GlucoseReading:
 41    """Class for parsing glucose reading from Dexcom Share API."""
 42
 43    def __init__(self, json_glucose_reading: Dict[str, Any]):
 44        """Initialize `GlucoseReading` with JSON glucose reading from Dexcom Share API.
 45
 46        :param json_glucose_reading: JSON glucose reading from Dexcom Share API
 47        """
 48        self._json = json_glucose_reading
 49        try:
 50            self._value = int(json_glucose_reading["Value"])
 51            self._trend_direction: str = json_glucose_reading["Trend"]
 52            # Dexcom Share API returns `str` direction now, previously `int` trend
 53            self._trend: int = DEXCOM_TREND_DIRECTIONS[self._trend_direction]
 54            self._datetime = datetime.fromtimestamp(
 55                int(re.sub("[^0-9]", "", json_glucose_reading["WT"])) / 1000.0
 56            )
 57        except (KeyError, TypeError, ValueError):
 58            raise ArgumentError(ArgumentErrorEnum.GLUCOSE_READING_INVALID)
 59
 60    @property
 61    def value(self) -> int:
 62        """Blood glucose value in mg/dL."""
 63        return self._value
 64
 65    @property
 66    def mg_dl(self) -> int:
 67        """Blood glucose value in mg/dL."""
 68        return self._value
 69
 70    @property
 71    def mmol_l(self) -> float:
 72        """Blood glucose value in mmol/L."""
 73        return round(self.value * MMOL_L_CONVERSION_FACTOR, 1)
 74
 75    @property
 76    def trend(self) -> int:
 77        """Blood glucose trend information
 78        (value of `pydexcom.const.DEXCOM_TREND_DIRECTIONS`)."""
 79        return self._trend
 80
 81    @property
 82    def trend_direction(self) -> str:
 83        """Blood glucose trend direction
 84        (key of `pydexcom.const.DEXCOM_TREND_DIRECTIONS`)."""
 85        return self._trend_direction
 86
 87    @property
 88    def trend_description(self) -> Optional[str]:
 89        """Blood glucose trend information description
 90        (`pydexcom.const.TREND_DESCRIPTIONS`).
 91        """
 92        return TREND_DESCRIPTIONS[self._trend]
 93
 94    @property
 95    def trend_arrow(self) -> str:
 96        """Blood glucose trend as unicode arrow (`pydexcom.const.TREND_ARROWS`)."""
 97        return TREND_ARROWS[self._trend]
 98
 99    @property
100    def datetime(self) -> datetime:
101        """Glucose reading recorded time as datetime."""
102        return self._datetime
103
104    @property
105    def json(self) -> Dict[str, Any]:
106        """JSON glucose reading from Dexcom Share API."""
107        return self._json
108
109    def __str__(self) -> str:
110        return str(self._value)

Class for parsing glucose reading from Dexcom Share API.

GlucoseReading(json_glucose_reading: Dict[str, Any])
43    def __init__(self, json_glucose_reading: Dict[str, Any]):
44        """Initialize `GlucoseReading` with JSON glucose reading from Dexcom Share API.
45
46        :param json_glucose_reading: JSON glucose reading from Dexcom Share API
47        """
48        self._json = json_glucose_reading
49        try:
50            self._value = int(json_glucose_reading["Value"])
51            self._trend_direction: str = json_glucose_reading["Trend"]
52            # Dexcom Share API returns `str` direction now, previously `int` trend
53            self._trend: int = DEXCOM_TREND_DIRECTIONS[self._trend_direction]
54            self._datetime = datetime.fromtimestamp(
55                int(re.sub("[^0-9]", "", json_glucose_reading["WT"])) / 1000.0
56            )
57        except (KeyError, TypeError, ValueError):
58            raise ArgumentError(ArgumentErrorEnum.GLUCOSE_READING_INVALID)

Initialize GlucoseReading with JSON glucose reading from Dexcom Share API.

Parameters
  • json_glucose_reading: JSON glucose reading from Dexcom Share API
value: int

Blood glucose value in mg/dL.

mg_dl: int

Blood glucose value in mg/dL.

mmol_l: float

Blood glucose value in mmol/L.

trend: int

Blood glucose trend information (value of pydexcom.const.DEXCOM_TREND_DIRECTIONS).

trend_direction: str

Blood glucose trend direction (key of pydexcom.const.DEXCOM_TREND_DIRECTIONS).

trend_description: Optional[str]

Blood glucose trend information description (pydexcom.const.TREND_DESCRIPTIONS).

trend_arrow: str

Blood glucose trend as unicode arrow (pydexcom.const.TREND_ARROWS).

datetime: datetime.datetime

Glucose reading recorded time as datetime.

json: Dict[str, Any]

JSON glucose reading from Dexcom Share API.

class Dexcom:
113class Dexcom:
114    """Class for communicating with Dexcom Share API."""
115
116    def __init__(self, username: str, password: str, ous: bool = False):
117        """
118        Initialize `Dexcom` with Dexcom Share credentials.
119
120        :param username: username for the Dexcom Share user, *not follower*.
121        :param password: password for the Dexcom Share user.
122        :param ous: whether the Dexcom Share user is outside of the US.
123        """
124        self._base_url = DEXCOM_BASE_URL_OUS if ous else DEXCOM_BASE_URL
125        self._username = username
126        self._password = password
127        self._account_id: Optional[str] = None
128        self._session_id: Optional[str] = None
129        self.__session = requests.Session()
130        self._session()
131
132    def _post(
133        self,
134        endpoint: str,
135        params: Optional[Dict[str, Any]] = None,
136        json: Optional[Dict[str, Any]] = None,
137    ) -> Any:
138        """Send post request to Dexcom Share API.
139
140        :param endpoint: URL of the post request
141        :param params: `dict` to send in the query string of the post request
142        :param json: JSON to send in the body of the post request
143        """
144        response = self.__session.post(
145            f"{self._base_url}/{endpoint}",
146            headers={"Accept-Encoding": "application/json"},
147            params=params,
148            json={} if json is None else json,
149        )
150
151        try:
152            response.raise_for_status()
153            return response.json()
154        except requests.HTTPError as http_error:
155            error = self._handle_response(response)
156            if error:
157                raise error from http_error
158            _LOGGER.error("%s", response.text)
159            raise http_error
160
161    def _handle_response(self, response: requests.Response) -> Optional[DexcomError]:
162        error: Optional[DexcomError] = None
163        """
164        Parse `requests.Response` for `pydexcom.errors.DexcomError`.
165
166        :param response: `requests.Response` to parse
167        """
168        if response.json():
169            _LOGGER.debug("%s", response.json())
170            code = response.json().get("Code", None)
171            message = response.json().get("Message", None)
172            if code == "SessionIdNotFound":
173                error = SessionError(SessionErrorEnum.NOT_FOUND)
174            elif code == "SessionNotValid":
175                error = SessionError(SessionErrorEnum.INVALID)
176            elif code == "AccountPasswordInvalid":
177                error = AccountError(AccountErrorEnum.PASSWORD_INVALID)
178            elif code == "SSO_AuthenticateMaxAttemptsExceeed":
179                error = AccountError(AccountErrorEnum.MAX_ATTEMPTS)
180            elif code == "InvalidArgument":
181                if message and "accountName" in message:
182                    error = ArgumentError(ArgumentErrorEnum.USERNAME_INVALID)
183                elif message and "password" in message:
184                    error = ArgumentError(ArgumentErrorEnum.PASSWORD_INVALID)
185                elif message and "UUID" in message:
186                    error = ArgumentError(ArgumentErrorEnum.ACCOUNT_ID_INVALID)
187            elif code and message:
188                _LOGGER.debug("%s: %s", code, message)
189        return error
190
191    def _validate_session_id(self) -> None:
192        """Validate session ID."""
193        if any([not isinstance(self._session_id, str), not self._session_id]):
194            raise ArgumentError(ArgumentErrorEnum.SESSION_ID_INVALID)
195        if self._session_id == DEFAULT_UUID:
196            raise ArgumentError(ArgumentErrorEnum.SESSION_ID_DEFAULT)
197
198    def _validate_credentials(self) -> None:
199        """Validate credentials."""
200        if any([not isinstance(self._username, str), not self._username]):
201            raise ArgumentError(ArgumentErrorEnum.USERNAME_INVALID)
202        if any([not isinstance(self._password, str), not self._password]):
203            raise ArgumentError(ArgumentErrorEnum.PASSWORD_INVALID)
204
205    def _validate_account_id(self) -> None:
206        """Validate account ID."""
207        if any([not isinstance(self._account_id, str), not self._account_id]):
208            raise ArgumentError(ArgumentErrorEnum.ACCOUNT_ID_INVALID)
209        if self._account_id == DEFAULT_UUID:
210            raise ArgumentError(ArgumentErrorEnum.ACCOUNT_ID_DEFAULT)
211
212    def _get_account_id(self) -> str:
213        """Retrieve account ID from the authentication endpoint
214        (`pydexcom.const.DEXCOM_AUTHENTICATE_ENDPOINT`)."""
215        _LOGGER.debug("Retrieve account ID from the authentication endpoint")
216        return self._post(
217            DEXCOM_AUTHENTICATE_ENDPOINT,
218            json={
219                "accountName": self._username,
220                "password": self._password,
221                "applicationId": DEXCOM_APPLICATION_ID,
222            },
223        )
224
225    def _get_session_id(self) -> str:
226        """Retrieve session ID from the login endpoint
227        (`pydexcom.const.DEXCOM_LOGIN_ID_ENDPOINT`)."""
228        _LOGGER.debug("Retrieve session ID from the login endpoint")
229        return self._post(
230            DEXCOM_LOGIN_ID_ENDPOINT,
231            json={
232                "accountId": self._account_id,
233                "password": self._password,
234                "applicationId": DEXCOM_APPLICATION_ID,
235            },
236        )
237
238    def _session(self) -> None:
239        """Create Dexcom Share API session."""
240        self._validate_credentials()
241
242        if self._account_id is None:
243            self._account_id = self._get_account_id()
244            self._validate_account_id()
245
246        self._session_id = self._get_session_id()
247        self._validate_session_id()
248
249    def _get_glucose_readings(
250        self, minutes: int = MAX_MINUTES, max_count: int = MAX_MAX_COUNT
251    ) -> List[Dict[str, Any]]:
252        """Retrieve glucose readings from the glucose readings endpoint
253        (`pydexcom.const.DEXCOM_GLUCOSE_READINGS_ENDPOINT`)."""
254        if not isinstance(minutes, int) or any([minutes < 0, minutes > MAX_MINUTES]):
255            raise ArgumentError(ArgumentErrorEnum.MINUTES_INVALID)
256        if not isinstance(max_count, int) or any(
257            [max_count < 0, max_count > MAX_MAX_COUNT]
258        ):
259            raise ArgumentError(ArgumentErrorEnum.MAX_COUNT_INVALID)
260
261        _LOGGER.debug("Retrieve glucose readings from the glucose readings endpoint")
262        return self._post(
263            DEXCOM_GLUCOSE_READINGS_ENDPOINT,
264            params={
265                "sessionId": self._session_id,
266                "minutes": minutes,
267                "maxCount": max_count,
268            },
269        )
270
271    def get_glucose_readings(
272        self, minutes: int = MAX_MINUTES, max_count: int = MAX_MAX_COUNT
273    ) -> List[GlucoseReading]:
274        """Get `max_count` glucose readings within specified number of `minutes`.
275
276        Catches one instance of a thrown `pydexcom.errors.SessionError` if session ID
277        expired, attempts to get a new session ID and retries.
278
279        :param minutes: Number of minutes to retrieve glucose readings from (1-1440)
280        :param max_count: Maximum number of glucose readings to retrieve (1-288)
281        """
282
283        json_glucose_readings: List[Dict[str, Any]] = []
284
285        try:
286            # Requesting glucose reading with DEFAULT_UUID returns non-JSON empty string
287            self._validate_session_id()
288
289            json_glucose_readings = self._get_glucose_readings(minutes, max_count)
290        except SessionError:
291            # Attempt to update expired session ID
292            self._session()
293
294            json_glucose_readings = self._get_glucose_readings(minutes, max_count)
295
296        return [GlucoseReading(json_reading) for json_reading in json_glucose_readings]
297
298    def get_latest_glucose_reading(self) -> Optional[GlucoseReading]:
299        """Get latest available glucose reading, within the last 24 hours."""
300        glucose_readings = self.get_glucose_readings(max_count=1)
301        return glucose_readings[0] if glucose_readings else None
302
303    def get_current_glucose_reading(self) -> Optional[GlucoseReading]:
304        """Get current available glucose reading, within the last 10 minutes."""
305        glucose_readings = self.get_glucose_readings(minutes=10, max_count=1)
306        return glucose_readings[0] if glucose_readings else None

Class for communicating with Dexcom Share API.

Dexcom(username: str, password: str, ous: bool = False)
116    def __init__(self, username: str, password: str, ous: bool = False):
117        """
118        Initialize `Dexcom` with Dexcom Share credentials.
119
120        :param username: username for the Dexcom Share user, *not follower*.
121        :param password: password for the Dexcom Share user.
122        :param ous: whether the Dexcom Share user is outside of the US.
123        """
124        self._base_url = DEXCOM_BASE_URL_OUS if ous else DEXCOM_BASE_URL
125        self._username = username
126        self._password = password
127        self._account_id: Optional[str] = None
128        self._session_id: Optional[str] = None
129        self.__session = requests.Session()
130        self._session()

Initialize Dexcom with Dexcom Share credentials.

Parameters
  • username: username for the Dexcom Share user, not follower.
  • password: password for the Dexcom Share user.
  • ous: whether the Dexcom Share user is outside of the US.
def get_glucose_readings( self, minutes: int = 1440, max_count: int = 288) -> List[GlucoseReading]:
271    def get_glucose_readings(
272        self, minutes: int = MAX_MINUTES, max_count: int = MAX_MAX_COUNT
273    ) -> List[GlucoseReading]:
274        """Get `max_count` glucose readings within specified number of `minutes`.
275
276        Catches one instance of a thrown `pydexcom.errors.SessionError` if session ID
277        expired, attempts to get a new session ID and retries.
278
279        :param minutes: Number of minutes to retrieve glucose readings from (1-1440)
280        :param max_count: Maximum number of glucose readings to retrieve (1-288)
281        """
282
283        json_glucose_readings: List[Dict[str, Any]] = []
284
285        try:
286            # Requesting glucose reading with DEFAULT_UUID returns non-JSON empty string
287            self._validate_session_id()
288
289            json_glucose_readings = self._get_glucose_readings(minutes, max_count)
290        except SessionError:
291            # Attempt to update expired session ID
292            self._session()
293
294            json_glucose_readings = self._get_glucose_readings(minutes, max_count)
295
296        return [GlucoseReading(json_reading) for json_reading in json_glucose_readings]

Get max_count glucose readings within specified number of minutes.

Catches one instance of a thrown pydexcom.errors.SessionError if session ID expired, attempts to get a new session ID and retries.

Parameters
  • minutes: Number of minutes to retrieve glucose readings from (1-1440)
  • max_count: Maximum number of glucose readings to retrieve (1-288)
def get_latest_glucose_reading(self) -> Optional[GlucoseReading]:
298    def get_latest_glucose_reading(self) -> Optional[GlucoseReading]:
299        """Get latest available glucose reading, within the last 24 hours."""
300        glucose_readings = self.get_glucose_readings(max_count=1)
301        return glucose_readings[0] if glucose_readings else None

Get latest available glucose reading, within the last 24 hours.

def get_current_glucose_reading(self) -> Optional[GlucoseReading]:
303    def get_current_glucose_reading(self) -> Optional[GlucoseReading]:
304        """Get current available glucose reading, within the last 10 minutes."""
305        glucose_readings = self.get_glucose_readings(minutes=10, max_count=1)
306        return glucose_readings[0] if glucose_readings else None

Get current available glucose reading, within the last 10 minutes.