Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update auth process and other improvements #68

Merged
merged 1 commit into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "ludeeus/integration_blueprint",
"image": "mcr.microsoft.com/devcontainers/python:3.11-bullseye",
"postCreateCommand": "sudo -E bash scripts/setup",
"forwardPorts": [
8123
],
"portsAttributes": {
"8123": {
"label": "Home Assistant",
"onAutoForward": "notify"
}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"github.vscode-pull-request-github",
"ryanluker.vscode-coverage-gutters",
"ms-python.vscode-pylance"
],
"settings": {
"files.eol": "\n",
"editor.tabSize": 4,
"python.pythonPath": "/usr/bin/python3",
"python.analysis.autoSearchPaths": false,
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true
}
}
},
"remoteUser": "vscode",
"features": {
"ghcr.io/devcontainers/features/rust:1": {}
}
}
43 changes: 0 additions & 43 deletions .devcontainer/README.md

This file was deleted.

11 changes: 0 additions & 11 deletions .devcontainer/configuration.yml

This file was deleted.

43 changes: 0 additions & 43 deletions .devcontainer/devcontainer.json

This file was deleted.

5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,7 @@ cython_debug/
#.idea/

*.DS_Store
cookies.txt
config/**
!config/configuration.yaml
/custom_components/carelink/logindata.json
/utils/logindata.json
22 changes: 2 additions & 20 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,9 @@
"version": "2.0.0",
"tasks": [
{
"label": "Run Home Assistant on port 9123",
"label": "Run Home Assistant on port 8123",
"type": "shell",
"command": "container start",
"problemMatcher": []
},
{
"label": "Run Home Assistant configuration against /config",
"type": "shell",
"command": "container check",
"problemMatcher": []
},
{
"label": "Upgrade Home Assistant to latest dev",
"type": "shell",
"command": "container install",
"problemMatcher": []
},
{
"label": "Install a specific version of Home Assistant",
"type": "shell",
"command": "container set-version",
"command": "sudo bash scripts/develop",
"problemMatcher": []
}
]
Expand Down
41 changes: 36 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,43 @@ Copy the `custom_components/carelink` to your `custom_components` folder. Reboot

## Integration Setup

### Session Token
In order to authenticate to the Carelink server, the Carelink client needs a valid access token. This can be obtained by manually logging into a Carelink follower account via Carelink web page. After successful login, the access token (plus country code) can be shown and copied using the Cookie Quick Manager Firefox plugin as follows:
### Carelink Login Data
The needed information for the authentification process can either be provided as file (=logindata.json), or entered during the initial setup of the integration.
#### Get the data
The Home Assistant Carelink Integration needs the initial login data stored in the `logindata.json` file. This file can be created **by running the login script on a PC with a screen**.
The login script from [@ondrej1024](https://github.com/ondrej1024)'s Carelink Python API, written by @palmarci (Pal Marci), was slightly modified and can be found here ["carelink_carepartner_api_login.py"](https://github.com/sedy89/Home-Assistant-Carelink/blob/json_login/utils/carelink_carepartner_api_login.py).

- With the Carelink web page still active, open Cookie Quick Manger from the extensions menu
- Select option "Search Cookies: carelink.minimed.eu"
- Copy value of auth temp token and use it as Session token for initial setup of the Homeassistant Carelink integration
Simply run:
```
python carelink_carepartner_api_login.py
```

You might need to install the following Python packages to satisfy the script's dependencies:

```
- requests
- OpenSSL (pip install pyOpenSSL)
- seleniumwire (pip install selenium-wire)
```

The script opens a Firefox web browser with the Carelink login page. You have to provide your Carelink patients or follower credentials (recommended) and solve the reCapcha.
On successful completion of the login, the data file will be created with the following structure:

![grafik](https://github.com/sedy89/Home-Assistant-Carelink/assets/65983953/35a60542-03fc-4deb-a14c-c96b0155bdd4)

#### Provide the data
Either the content of the `logindata.json` file can be taken over into the setup of the HA Carelink integration, or the entire file can be uploaded into the custom_componend/carelink folder (recommended).

![grafik](https://github.com/sedy89/Home-Assistant-Carelink/assets/65983953/0a1d8773-7905-4fec-9bff-b3a0f01817b9)

All parameters during setup are optional and a provided file will have a higher priority and overwrite the manual configuration.
If the file was copied to `custom_components/carelink` before the integration setup was started in Home Assistant, all parameters during the setup can stay empty.
With those information, the Home Assistant Carelink Integration will be able to automatically refresh the login data when it expires.
It should be able to do so within one week of the last refresh.

### Scan Interval
The scan interval of the integration can be configured during the integration setup.
User can configure anything between 30 and 300 seconds. Default is 60 seconds.

### Nightscout
To use the Nightscout uploader, it is mandatory to provide the Nightscout URL and the Nightscout API secret.
Expand Down
9 changes: 9 additions & 0 deletions config/configuration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

# Load frontend themes from the themes folder
frontend:
themes: !include_dir_merge_named themes

logger:
default: info
logs:
custom_components.carelink: debug
27 changes: 13 additions & 14 deletions custom_components/carelink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
CLIENT,
UPLOADER,
DOMAIN,
SCAN_INTERVAL,
COORDINATOR,
UNAVAILABLE,
DEVICE_PUMP_MODEL,
Expand Down Expand Up @@ -82,8 +83,6 @@

_LOGGER = logging.getLogger(__name__)

SCAN_INTERVAL = timedelta(seconds=60)


def convert_date_to_isodate(date):
date_iso = re.sub("\.\d{3}Z$", "+00:00", date)
Expand All @@ -97,27 +96,26 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data.setdefault(DOMAIN, {})

config = entry.data
patientId = None

if "patientId" in config:
patientId = config["patientId"]

carelink_client = CarelinkClient(
config["country"],
config["token"],
patientId
config["cl_token"],
config["cl_refresh_token"],
config["cl_client_id"],
config["cl_client_secret"],
config["cl_mag_identifier"],
config["patientId"]
)

hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {CLIENT: carelink_client}

if "nightscout_url" in config and "nightscout_api" in config:
if config["nightscout_url"] and config["nightscout_api"]:
nightscout_uploader = NightscoutUploader(
config["nightscout_url"],
config["nightscout_api"]
)
hass.data.setdefault(DOMAIN, {})[entry.entry_id].update({UPLOADER: nightscout_uploader})

coordinator = CarelinkCoordinator(hass, entry, update_interval=SCAN_INTERVAL)
coordinator = CarelinkCoordinator(hass, entry, update_interval=timedelta(seconds=config[SCAN_INTERVAL]))

await coordinator.async_config_entry_first_refresh()

Expand Down Expand Up @@ -163,9 +161,6 @@ async def _async_update_data(self):
recent_data = await self.client.get_recent_data()
if recent_data is None:
recent_data = dict()
else:
if self.uploader:
await self.uploader.send_recent_data(recent_data)
try:
if recent_data is not None and "clientTimeZoneName" in recent_data:
client_timezone = recent_data["clientTimeZoneName"]
Expand All @@ -188,6 +183,10 @@ async def _async_update_data(self):

_LOGGER.debug("Using timezone %s", DEFAULT_TIME_ZONE)

# nightscout uploader
if self.uploader:
await self.uploader.send_recent_data(recent_data, timezone)

recent_data["sLastSensorTime"] = recent_data.setdefault("sLastSensorTime", "")
recent_data["activeInsulin"] = recent_data.setdefault("activeInsulin", {})
recent_data["basal"] = recent_data.setdefault("basal", {})
Expand Down
Loading
Loading