Skip to content

Commit

Permalink
multi patients management
Browse files Browse the repository at this point in the history
Beta version
  • Loading branch information
gillesvs committed Feb 7, 2024
1 parent 5de87f1 commit 96fcc88
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 127 deletions.
5 changes: 4 additions & 1 deletion custom_components/librelink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@


from .api import LibreLinkApiClient, LibreLinkApiLogin
from .const import DOMAIN
from .const import DOMAIN, BASE_URL
from .coordinator import LibreLinkDataUpdateCoordinator

PLATFORMS: list[Platform] = [
Expand All @@ -31,6 +31,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.data,
entry.data[CONF_USERNAME],
entry.data[CONF_PASSWORD],
entry.data[BASE_URL]
)

hass.data.setdefault(DOMAIN, {})
Expand All @@ -40,6 +41,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
myLibrelinkLogin = LibreLinkApiLogin(
username=entry.data[CONF_USERNAME],
password=entry.data[CONF_PASSWORD],
base_url= entry.data[BASE_URL],
session=async_get_clientsession(hass),
)

Expand All @@ -50,6 +52,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
myLibrelinkClient = LibreLinkApiClient(
sessionToken,
session=async_get_clientsession(hass),
base_url=entry.data[BASE_URL]
)

hass.data[DOMAIN][entry.entry_id] = coordinator = LibreLinkDataUpdateCoordinator(
Expand Down
14 changes: 7 additions & 7 deletions custom_components/librelink/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,18 @@


class LibreLinkApiClient:
def __init__(self, token: str, session: aiohttp.ClientSession) -> None:
def __init__(self, token: str, base_url:str, session: aiohttp.ClientSession) -> None:
"""Sample API Client."""
self._token = token
self._session = session
self.connection_url = base_url + CONNECTION_URL

async def async_get_data(self) -> any:
"""Get data from the API."""
APIreponse = await api_wrapper(
self._session,
method="get",
url=CONNECTION_URL,
url= self.connection_url,
headers={
"product": PRODUCT,
"version": VERSION_APP,
Expand All @@ -55,26 +56,25 @@ async def async_get_data(self) -> any:
return APIreponse


#######################################################################################
# """API launched at start-up to get the Librelink Token.""" #
#######################################################################################



class LibreLinkApiLogin:
def __init__(
self, username: str, password: str, session: aiohttp.ClientSession
self, username: str, password: str, base_url: str, session: aiohttp.ClientSession
) -> None:
"""Sample API Client."""
self._username = username
self._password = password
self.login_url = base_url + LOGIN_URL
self._session = session

async def async_get_token(self) -> any:
"""Get token from the API."""
reponseLogin = await api_wrapper(
self._session,
method="post",
url=LOGIN_URL,
url=self.login_url,
headers={
"product": PRODUCT,
"version": VERSION_APP,
Expand Down
84 changes: 57 additions & 27 deletions custom_components/librelink/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@

from .const import DOMAIN
from .coordinator import LibreLinkDataUpdateCoordinator
from .entity import LibreLinkEntity
from .device import LibreLinkDevice

import logging

_LOGGER = logging.getLogger(__name__)


BinarySensorDescription = (
BinarySensorEntityDescription(
key="isHigh",
name="Is High",
),
BinarySensorEntityDescription(
key="isLow",
name="Is Low",
),
)
# BinarySensorDescription = (
# BinarySensorEntityDescription(
# key="isHigh",
# name="Is High",
# ),
# BinarySensorEntityDescription(
# key="isLow",
# name="Is Low",
# ),
# )


async def async_setup_entry(
Expand All @@ -44,27 +44,38 @@ async def async_setup_entry(

# to manage multiple patients, the API return an array of patients in "data". So we loop in the array
# and create as many devices and sensors as we do have patients.

sensors = []
for index, patients in enumerate(coordinator.data["data"]):
patient = patients["firstName"] + " " + patients["lastName"]
patientId = patients["patientId"]
# print(f"patient : {patient}")

async_add_entities(
# print(f"patient : {patient}")
sensors.extend( [
LibreLinkBinarySensor(
coordinator,
patients,
patientId,
patient,
index,
config_entry.entry_id,
entity_description,
)
for entity_description in BinarySensorDescription
)
key="isHigh",
name= "Is High",
),
LibreLinkBinarySensor(
coordinator,
patients,
patientId,
patient,
index,
config_entry.entry_id,
key="isLow",
name="Is Low",
),
])
async_add_entities(sensors)


class LibreLinkBinarySensor(LibreLinkEntity, BinarySensorEntity):

class LibreLinkBinarySensor(LibreLinkDevice, BinarySensorEntity):
"""librelink binary_sensor class."""

def __init__(
Expand All @@ -75,19 +86,38 @@ def __init__(
patient: str,
index: int,
entry_id,
description: BinarySensorEntityDescription,
key: str,
name: str,
) -> None:
"""Initialize the binary_sensor class."""
super().__init__(coordinator, patientId, patient, entry_id, description.key)
self.entity_description = description
"""Initialize the device class."""
super().__init__(
coordinator, patientId, patient)

self.key = key
self.patients = patients
self.patientId = patientId
self.index = index
self._attr_name = name

@property
def unique_id(self):
# field = self._field
# if self._index != None:
# field = f"{field}_{self._index}"
return f"{self.patientId}_{self.key}_{self.index}"

# @property
# def name(self):
# # field = self._field
# # if self._index != None:
# # field = f"{field}_{self._index}"
# return self.name

# define state based on the entity_description key
@property
def is_on(self) -> bool:
"""Return true if the binary_sensor is on."""
return self.coordinator.data["data"][self.index]["glucoseMeasurement"][
self.entity_description.key
# return self.coordinator.data["data"][self.index]["glucoseMeasurement"][
return self.patients["glucoseMeasurement"][
self.key
]

64 changes: 57 additions & 7 deletions custom_components/librelink/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, CONF_UNIT_OF_MEASUREMENT
from homeassistant.helpers import selector
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, CONF_UNIT_OF_MEASUREMENT, CONF_URL, CONF_COUNTRY
from homeassistant.helpers import selector, config_validation as cv
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from homeassistant.core import callback

Expand All @@ -14,7 +14,7 @@
LibreLinkApiCommunicationError,
LibreLinkApiError,
)
from .const import DOMAIN, LOGGER, MMOL_L, MG_DL
from .const import DOMAIN, LOGGER, MMOL_L, MG_DL, BASE_URL_LIST, BASE_URL_DEFAULT, BASE_URL

import logging

Expand All @@ -38,6 +38,7 @@ async def async_step_user(
await self._test_credentials(
username=user_input[CONF_USERNAME],
password=user_input[CONF_PASSWORD],
base_url=user_input[BASE_URL],
)
except LibreLinkApiAuthenticationError as exception:
LOGGER.warning(exception)
Expand Down Expand Up @@ -71,17 +72,23 @@ async def async_step_user(
type=selector.TextSelectorType.PASSWORD
),
),
# vol.Optional(CONF_UNIT_OF_MEASUREMENT, default=MG_DL): vol.In({MG_DL, MMOL_L}),
}
),

vol.Required(BASE_URL, description = "url by country", default=(BASE_URL_LIST[0])): vol.In(BASE_URL_LIST),


}),

errors=_errors,
)

async def _test_credentials(self, username: str, password: str) -> None:


async def _test_credentials(self, username: str, password: str, base_url: str) -> None:
"""Validate credentials."""
client = LibreLinkApiLogin(
username=username,
password=password,
base_url=base_url,
session=async_create_clientsession(self.hass),
)

Expand Down Expand Up @@ -122,3 +129,46 @@ async def async_step_init(self, user_input=None):
}
)
return self.async_show_form(step_id="init", data_schema=data_schema)


# """Setup sensors from a config entry created in the integrations UI."""
# config = hass.data[DOMAIN][config_entry.entry_id]
# session = async_get_clientsession(hass)
# github = GitHubAPI(session, "requester", oauth_token=config[CONF_ACCESS_TOKEN])
# sensors = [GitHubRepoSensor(github, repo) for repo in config[CONF_REPOS]]

# Grab all configured repos from the entity registry so we can populate the
# multi-select dropdown that will allow a user to remove a repo.
# entity_registry = await async_get_registry(self.hass)
# entries = async_entries_for_config_entry(
# entity_registry, self.config_entry.entry_id
# )
# Default value for our multi-select.


# all_repos = {e.entity_id: e.original_name for e in entries}
# repo_map = {e.entity_id: e for e in entries}

# if user_input is not None:
# # Validation and additional processing logic omitted for brevity.
# # ...
# if not errors:
# # Value of data will be set on the options property of our config_entry
# # instance.
# return self.async_create_entry(
# title="",
# data={CONF_REPOS: updated_repos},
# )

# options_schema = vol.Schema(
# {
# vol.Optional("repos", default=list(all_repos.keys())): cv.multi_select(
# all_repos
# ),
# vol.Optional(CONF_PATH): cv.string,
# vol.Optional(CONF_NAME): cv.string,
# }
# )
# return self.async_show_form(
# step_id="init", data_schema=options_schema, errors=errors
# )
10 changes: 7 additions & 3 deletions custom_components/librelink/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@

NAME = "LibreLink"
DOMAIN = "librelink"
VERSION = "1.1.5"
VERSION = "1.1.6"
ATTRIBUTION = "Data provided by https://libreview.com"
LOGIN_URL = "https://api.libreview.io/llu/auth/login"
CONNECTION_URL = "https://api.libreview.io/llu/connections"
LOGIN_URL = "/llu/auth/login"
CONNECTION_URL = "/llu/connections"
BASE_URL="Base URL"
BASE_URL_LIST = ["https://api.libreview.io","https://api.libreview.ru"]
#BASE_URL_LIST = [{"Global":"https://api.libreview.io"},{"Russia":"https://api.libreview.ru"}]
BASE_URL_DEFAULT = ["https://api.libreview.io"]
PRODUCT = "llu.android"
VERSION_APP = "4.7"
APPLICATION = "application/json"
Expand Down
48 changes: 48 additions & 0 deletions custom_components/librelink/device.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Sensor platform for LibreLink."""
from __future__ import annotations

from homeassistant.helpers.device_registry import DeviceInfo

from .const import ATTRIBUTION, DOMAIN, NAME, VERSION
from .coordinator import LibreLinkDataUpdateCoordinator

from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .coordinator import LibreLinkDataUpdateCoordinator

import logging

# enable logging
_LOGGER = logging.getLogger(__name__)


# This class is called when a device is created.
# A device is created for each patient to regroup patient entities

class LibreLinkDevice(CoordinatorEntity):
"""LibreLinkEntity class."""

_attr_has_entity_name = True
_attr_attribution = ATTRIBUTION

def __init__(
self,
coordinator: LibreLinkDataUpdateCoordinator,
patientId: str,
patient: str,
) -> None:
"""Initialize."""
super().__init__(coordinator)
# Creating unique IDs using for the device based on the Librelink patient Id.
self._attr_unique_id = f"{patientId}"
_LOGGER.debug(
"entity unique id is %s",
self._attr_unique_id,
)
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, patientId)},
name=patient,
model=VERSION,
manufacturer=NAME,
)

2 changes: 1 addition & 1 deletion custom_components/librelink/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"documentation": "https://github.com/gillesvs/librelink",
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/gillesvs/librelink/issues",
"version": "1.1.5"
"version": "1.1.6"
}
Loading

0 comments on commit 96fcc88

Please sign in to comment.