glucoglance 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- glucoglance-0.3.0/LICENSE +21 -0
- glucoglance-0.3.0/PKG-INFO +327 -0
- glucoglance-0.3.0/README.md +295 -0
- glucoglance-0.3.0/pyproject.toml +77 -0
- glucoglance-0.3.0/setup.cfg +4 -0
- glucoglance-0.3.0/src/glucoglance/__init__.py +11 -0
- glucoglance-0.3.0/src/glucoglance/alerts/__init__.py +1 -0
- glucoglance-0.3.0/src/glucoglance/alerts/base.py +7 -0
- glucoglance-0.3.0/src/glucoglance/assets/icon.png +0 -0
- glucoglance-0.3.0/src/glucoglance/client/__init__.py +1 -0
- glucoglance-0.3.0/src/glucoglance/client/errors.py +28 -0
- glucoglance-0.3.0/src/glucoglance/client/librelinkup.py +275 -0
- glucoglance-0.3.0/src/glucoglance/config/__init__.py +1 -0
- glucoglance-0.3.0/src/glucoglance/config/autostart.py +64 -0
- glucoglance-0.3.0/src/glucoglance/config/credentials.py +27 -0
- glucoglance-0.3.0/src/glucoglance/config/settings.py +102 -0
- glucoglance-0.3.0/src/glucoglance/domain/__init__.py +1 -0
- glucoglance-0.3.0/src/glucoglance/domain/range.py +38 -0
- glucoglance-0.3.0/src/glucoglance/domain/reading.py +29 -0
- glucoglance-0.3.0/src/glucoglance/domain/trend.py +41 -0
- glucoglance-0.3.0/src/glucoglance/domain/units.py +29 -0
- glucoglance-0.3.0/src/glucoglance/main.py +205 -0
- glucoglance-0.3.0/src/glucoglance/poller/__init__.py +1 -0
- glucoglance-0.3.0/src/glucoglance/poller/poller.py +136 -0
- glucoglance-0.3.0/src/glucoglance/ui/__init__.py +1 -0
- glucoglance-0.3.0/src/glucoglance/ui/about_dialog.py +49 -0
- glucoglance-0.3.0/src/glucoglance/ui/app_icon.py +17 -0
- glucoglance-0.3.0/src/glucoglance/ui/credential_prompt.py +80 -0
- glucoglance-0.3.0/src/glucoglance/ui/disclaimer.py +14 -0
- glucoglance-0.3.0/src/glucoglance/ui/display.py +33 -0
- glucoglance-0.3.0/src/glucoglance/ui/icon_renderer.py +87 -0
- glucoglance-0.3.0/src/glucoglance/ui/tray.py +243 -0
- glucoglance-0.3.0/src/glucoglance.egg-info/PKG-INFO +327 -0
- glucoglance-0.3.0/src/glucoglance.egg-info/SOURCES.txt +46 -0
- glucoglance-0.3.0/src/glucoglance.egg-info/dependency_links.txt +1 -0
- glucoglance-0.3.0/src/glucoglance.egg-info/entry_points.txt +2 -0
- glucoglance-0.3.0/src/glucoglance.egg-info/requires.txt +12 -0
- glucoglance-0.3.0/src/glucoglance.egg-info/top_level.txt +1 -0
- glucoglance-0.3.0/tests/test_about_dialog.py +16 -0
- glucoglance-0.3.0/tests/test_app_icon.py +9 -0
- glucoglance-0.3.0/tests/test_autostart.py +60 -0
- glucoglance-0.3.0/tests/test_client_parsing.py +79 -0
- glucoglance-0.3.0/tests/test_icon_renderer.py +37 -0
- glucoglance-0.3.0/tests/test_poller.py +116 -0
- glucoglance-0.3.0/tests/test_range.py +29 -0
- glucoglance-0.3.0/tests/test_settings.py +52 -0
- glucoglance-0.3.0/tests/test_trend.py +18 -0
- glucoglance-0.3.0/tests/test_units.py +18 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Angel Blanco
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: glucoglance
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Ubuntu-only tray widget showing live FreeStyle Libre glucose readings (requires a LibreLinkUp account)
|
|
5
|
+
Author-email: Angel Blanco <toabm@yahoo.es>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/toabm/glucoglance-ubuntu
|
|
8
|
+
Project-URL: Issues, https://github.com/toabm/glucoglance-ubuntu/issues
|
|
9
|
+
Keywords: glucose,freestyle-libre,librelinkup,cgm,tray,gnome,ubuntu
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: X11 Applications :: GTK
|
|
12
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Utilities
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: requests>=2.31
|
|
22
|
+
Requires-Dist: keyring>=24
|
|
23
|
+
Requires-Dist: tomli-w>=1.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
26
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
27
|
+
Requires-Dist: responses>=0.25; extra == "dev"
|
|
28
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
29
|
+
Provides-Extra: ide
|
|
30
|
+
Requires-Dist: PyGObject-stubs>=2.10; extra == "ide"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# GlucoGlance for Ubuntu
|
|
34
|
+
|
|
35
|
+
[](https://github.com/toabm/glucoglance-ubuntu/actions/workflows/ci.yml)
|
|
36
|
+
|
|
37
|
+
A tray widget that shows your current glucose reading (from a FreeStyle
|
|
38
|
+
Libre sensor, via LibreLinkUp) in the Ubuntu top bar. Phase 1: just the
|
|
39
|
+
number and trend arrow, refreshed roughly every minute. Threshold alarms are
|
|
40
|
+
planned as a phase 2.
|
|
41
|
+
|
|
42
|
+
> **Compatibility - please check before installing.** GlucoGlance only
|
|
43
|
+
> works with:
|
|
44
|
+
>
|
|
45
|
+
> - **Ubuntu** (developed and tested on Ubuntu 24.04 with GNOME Shell 46).
|
|
46
|
+
> Windows, macOS, and other Linux distributions/desktops are not
|
|
47
|
+
> supported.
|
|
48
|
+
> - **FreeStyle Libre sensors** whose readings are shared through
|
|
49
|
+
> **LibreLinkUp**. Other CGMs (Dexcom, Medtronic, Eversense, etc.) are
|
|
50
|
+
> not supported.
|
|
51
|
+
> - A **LibreLinkUp account** - see Requirements below.
|
|
52
|
+
|
|
53
|
+
## ⚠️ Disclaimer
|
|
54
|
+
|
|
55
|
+
**GlucoGlance is not a medical device.** It has not been reviewed or
|
|
56
|
+
approved by the FDA, the EMA, or any other regulator.
|
|
57
|
+
|
|
58
|
+
- It is an **unofficial, independent** project. It is not affiliated
|
|
59
|
+
with, endorsed by, or supported by Abbott. FreeStyle Libre and
|
|
60
|
+
LibreLinkUp are trademarks of Abbott, used here only to describe what
|
|
61
|
+
the app works with.
|
|
62
|
+
- Readings may be **delayed, missing or wrong**. **Do not use this app to
|
|
63
|
+
make treatment decisions** (e.g. insulin dosing). Always confirm with
|
|
64
|
+
your sensor's official app or a fingerstick blood glucose meter.
|
|
65
|
+
- It relies on an **undocumented LibreLinkUp API** that Abbott can change
|
|
66
|
+
or block at any time, so the app may stop working without warning.
|
|
67
|
+
- It is provided "as is", without warranty of any kind (see
|
|
68
|
+
[LICENSE](https://github.com/toabm/glucoglance-ubuntu/blob/master/LICENSE)). **Use it at your own risk.**
|
|
69
|
+
|
|
70
|
+
## Requirements
|
|
71
|
+
|
|
72
|
+
- **Ubuntu** with the default GNOME desktop (see Compatibility above).
|
|
73
|
+
- A **FreeStyle Libre sensor** whose wearer shares their readings to
|
|
74
|
+
**LibreLinkUp** from the official Libre app.
|
|
75
|
+
- A LibreLinkUp **follower** account that has accepted that share: you
|
|
76
|
+
log in here with the follower account's email and password.
|
|
77
|
+
|
|
78
|
+
This app cannot talk to the sensor directly - it only reads what the
|
|
79
|
+
official Libre app has already uploaded to LibreLinkUp.
|
|
80
|
+
|
|
81
|
+
## Installing on Ubuntu
|
|
82
|
+
|
|
83
|
+
### Quick install (from PyPI, with pipx)
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
sudo apt install pipx python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1
|
|
87
|
+
pipx ensurepath
|
|
88
|
+
pipx install --system-site-packages glucoglance
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`--system-site-packages` is required: it lets the app reuse the GTK
|
|
92
|
+
bindings installed by `apt`, which PyPI doesn't distribute. Open a new
|
|
93
|
+
terminal (so `pipx ensurepath` takes effect) and run `glucoglance` - then
|
|
94
|
+
skip to "Running it for the first time" below. Upgrade later with
|
|
95
|
+
`pipx upgrade glucoglance`.
|
|
96
|
+
|
|
97
|
+
### From source
|
|
98
|
+
|
|
99
|
+
These steps assume a fresh Ubuntu machine with nothing set up yet - if
|
|
100
|
+
you've already done part of this, skip ahead.
|
|
101
|
+
|
|
102
|
+
**1. Get the code:**
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
git clone https://github.com/toabm/glucoglance-ubuntu.git
|
|
106
|
+
cd glucoglance-ubuntu
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**2. Install the system packages** the tray icon needs (these come from
|
|
110
|
+
`apt`, not `pip` - they're GTK/AppIndicator bindings that Python's package
|
|
111
|
+
index doesn't distribute):
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
sudo apt install python3-venv python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
(If your Ubuntu/distro version ships classic `AppIndicator3` instead of
|
|
118
|
+
the Ayatana fork, install `gir1.2-appindicator3-0.1` instead - the app
|
|
119
|
+
tries Ayatana first and falls back automatically, so either works.)
|
|
120
|
+
|
|
121
|
+
**3. Create a Python virtual environment and install the app into it.**
|
|
122
|
+
`--system-site-packages` is required here - it lets the venv reuse the
|
|
123
|
+
`python3-gi` bindings you just installed with `apt`, instead of trying
|
|
124
|
+
(and failing) to build them from PyPI:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
python3 -m venv --system-site-packages .venv
|
|
128
|
+
source .venv/bin/activate
|
|
129
|
+
pip install .
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
That's the whole install. The `glucoglance` command now exists at
|
|
133
|
+
`.venv/bin/glucoglance` (and on your `PATH` while the venv is
|
|
134
|
+
activated).
|
|
135
|
+
|
|
136
|
+
## Running it for the first time
|
|
137
|
+
|
|
138
|
+
With the venv activated (`source .venv/bin/activate`, if you're in a new
|
|
139
|
+
terminal):
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
glucoglance
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
A small dialog pops up asking for your LibreLinkUp email and password (see
|
|
146
|
+
Requirements above). Enter them and press OK. The email is saved to
|
|
147
|
+
`~/.config/glucoglance/config.toml`; the password is stored in your
|
|
148
|
+
system keyring (GNOME Keyring), never in plaintext. A number should then
|
|
149
|
+
appear in your top bar within a few seconds - that's your current glucose
|
|
150
|
+
reading.
|
|
151
|
+
|
|
152
|
+
You won't need to repeat this - the credentials are remembered, and (see
|
|
153
|
+
below) the app is set to start automatically at every login by default.
|
|
154
|
+
|
|
155
|
+
Right-click the tray icon for:
|
|
156
|
+
- **Start at login** - checkbox, on by default (see "Running automatically
|
|
157
|
+
at login" below).
|
|
158
|
+
- **Restart** - reloads the app, e.g. after editing `config.toml`.
|
|
159
|
+
- **Quit**.
|
|
160
|
+
|
|
161
|
+
## Adding it to your Applications menu
|
|
162
|
+
|
|
163
|
+
This is separate from "start at login" below: this makes GlucoGlance
|
|
164
|
+
show up as a proper icon in GNOME's Activities overview and app search
|
|
165
|
+
(so you can launch it manually, or pin it to the Dock), rather than only
|
|
166
|
+
starting silently in the background. Run this once, from the repo
|
|
167
|
+
directory, with the venv already created as above:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
test -x .venv/bin/glucoglance || { echo "Run this from the glucoglance-ubuntu directory (the venv wasn't found here)"; exit 1; }
|
|
171
|
+
ICON_PATH=$(.venv/bin/python3 -c "from glucoglance.ui.app_icon import app_icon_path; print(app_icon_path())")
|
|
172
|
+
mkdir -p ~/.local/share/applications
|
|
173
|
+
cat > ~/.local/share/applications/glucoglance.desktop <<EOF
|
|
174
|
+
[Desktop Entry]
|
|
175
|
+
Type=Application
|
|
176
|
+
Name=GlucoGlance
|
|
177
|
+
Exec=$(pwd)/.venv/bin/glucoglance
|
|
178
|
+
Icon=$ICON_PATH
|
|
179
|
+
Comment=Shows current blood glucose reading in the top bar
|
|
180
|
+
Terminal=false
|
|
181
|
+
Categories=Utility;
|
|
182
|
+
EOF
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
It should now appear if you search for "GlucoGlance" in GNOME's
|
|
186
|
+
Activities overview (press the Super/Windows key and start typing). From
|
|
187
|
+
there you can drag it onto the Dock to pin it.
|
|
188
|
+
|
|
189
|
+
(This installs into `~/.local/share/applications`, the standard location
|
|
190
|
+
for manually-installed apps - not `/usr/share/applications`, which is
|
|
191
|
+
where apt/snap-installed apps land since that directory is shared across
|
|
192
|
+
all users on the machine. GNOME scans both identically, so this works the
|
|
193
|
+
same either way; no need to move it.)
|
|
194
|
+
|
|
195
|
+
(The `Exec=` line uses an absolute path to the venv you just created,
|
|
196
|
+
rather than the bare `glucoglance` command, since a graphical launcher
|
|
197
|
+
doesn't necessarily have your venv on its `PATH`. If you ever move the
|
|
198
|
+
`glucoglance-ubuntu` folder, re-run the command above to update it.)
|
|
199
|
+
|
|
200
|
+
## Configuration
|
|
201
|
+
|
|
202
|
+
Settings live at `~/.config/glucoglance/config.toml` (created with
|
|
203
|
+
defaults on first run). Notable options:
|
|
204
|
+
|
|
205
|
+
```toml
|
|
206
|
+
interval_seconds = 60 # how often to poll, in seconds
|
|
207
|
+
unit = "mgdl" # "mgdl" or "mmol"
|
|
208
|
+
low_threshold_mgdl = 80 # below this, the icon turns red
|
|
209
|
+
high_threshold_mgdl = 180 # above this, the icon turns yellow (green in between)
|
|
210
|
+
color_low = "#ED4343"
|
|
211
|
+
color_normal = "#4DCC66"
|
|
212
|
+
color_high = "#F5D334"
|
|
213
|
+
autostart_enabled = true # start automatically at login (see below)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Edit the file and restart `glucoglance` for changes to take effect.
|
|
217
|
+
|
|
218
|
+
## Running automatically at login
|
|
219
|
+
|
|
220
|
+
Enabled by default - on every startup the app installs (or removes) a
|
|
221
|
+
`~/.config/autostart/glucoglance.desktop` entry to match the
|
|
222
|
+
`autostart_enabled` setting. That path is the standard XDG autostart
|
|
223
|
+
location on Ubuntu (and GNOME/most other Linux desktops generally), but
|
|
224
|
+
this project is only built and tested against Ubuntu - see "Installing on
|
|
225
|
+
Ubuntu" above. Toggle it anytime from the tray icon's right-click menu
|
|
226
|
+
("Start at login"), or by editing `autostart_enabled` in `config.toml` and
|
|
227
|
+
restarting.
|
|
228
|
+
|
|
229
|
+
That autostart entry always waits 6 seconds before actually launching the
|
|
230
|
+
app (only on this path - running from a terminal or the Applications-menu
|
|
231
|
+
icon starts immediately). This isn't configurable, and it's not about
|
|
232
|
+
sensor timing: it exists purely to influence where the icon lands in the
|
|
233
|
+
top bar. GNOME Shell's AppIndicator extension inserts each new tray icon
|
|
234
|
+
at a fixed position rather than appending, so indicators that register
|
|
235
|
+
*later* tend to end up ahead of ones that registered earlier. The delay
|
|
236
|
+
gives your other autostart tray apps a head start, with the goal of
|
|
237
|
+
landing this icon at the left edge of the right-side icon group (i.e.
|
|
238
|
+
immediately after the clock, ahead of things like wifi/bluetooth/volume) -
|
|
239
|
+
though the exact result depends on how many other apps you have and how
|
|
240
|
+
long they take to start, so it may need tuning (edit
|
|
241
|
+
`_STARTUP_DELAY_SECONDS` in `config/autostart.py`) to get exactly there.
|
|
242
|
+
|
|
243
|
+
## Tests & linting
|
|
244
|
+
|
|
245
|
+
Tests and linting need the extra dev dependencies, which the regular
|
|
246
|
+
install above skips:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
pip install -e ".[dev]"
|
|
250
|
+
ruff check . # lint
|
|
251
|
+
pytest --cov=glucoglance --cov-report=term-missing # tests + coverage
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Overall coverage sits around 49% by design, not by accident: GTK/keyring-
|
|
255
|
+
dependent code (`main.py`, `ui/tray.py`, `ui/credential_prompt.py`,
|
|
256
|
+
`ui/display.py`, `config/credentials.py`) is deliberately manual-only -
|
|
257
|
+
see CLAUDE.md's "Testing philosophy" section.
|
|
258
|
+
|
|
259
|
+
Coverage includes branches (`[tool.coverage.run] branch = true` in
|
|
260
|
+
`pyproject.toml`, applied automatically - no extra flag needed), not
|
|
261
|
+
just lines: a line can show as "covered" while one of its branches
|
|
262
|
+
(e.g. one side of an `if`) was never actually exercised, so branch
|
|
263
|
+
coverage catches real gaps line coverage hides.
|
|
264
|
+
|
|
265
|
+
If your IDE flags `gi.repository` symbols (e.g. `GLib`, `Gtk`) as
|
|
266
|
+
unresolved, that's expected - PyGObject generates those modules
|
|
267
|
+
dynamically from typelibs at runtime, not from real `.py` files, so
|
|
268
|
+
static analyzers can't see them without type stubs. Install those
|
|
269
|
+
separately from `dev` (pip otherwise tries to rebuild the real
|
|
270
|
+
PyGObject/pycairo from source to satisfy this package's declared
|
|
271
|
+
dependency, and fails without cairo/girepository dev headers):
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
pip install --no-deps PyGObject-stubs
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Continuous integration
|
|
278
|
+
|
|
279
|
+
Every push to `develop`/`master` and every pull request runs `ruff` and
|
|
280
|
+
the full test suite (`.github/workflows/ci.yml`), publishing a test
|
|
281
|
+
report and a coverage summary (including diff/patch coverage on PRs) as
|
|
282
|
+
a PR comment. `master` is protected: it only accepts changes through a
|
|
283
|
+
pull request, and the "Lint & Test" check must pass before merging.
|
|
284
|
+
|
|
285
|
+
For PRs opened from a fork, the test/coverage report job is skipped -
|
|
286
|
+
GitHub gives fork PRs a read-only token, so it couldn't post its comment
|
|
287
|
+
anyway. "Lint & Test" still runs, and its log shows the full results.
|
|
288
|
+
|
|
289
|
+
## Project layout
|
|
290
|
+
|
|
291
|
+
- `client/` - talks to the LibreLinkUp API.
|
|
292
|
+
- `domain/` - plain data types (readings, trend, unit conversion), no I/O.
|
|
293
|
+
- `poller/` - background polling loop; publishes events on an `EventBus`.
|
|
294
|
+
- `alerts/` - placeholder for phase 2 threshold alarms.
|
|
295
|
+
- `ui/` - the tray display, built behind a small `Display` interface so
|
|
296
|
+
other frontends (e.g. a floating window) can be added later.
|
|
297
|
+
- `config/` - settings (TOML) and credentials (system keyring).
|
|
298
|
+
|
|
299
|
+
## Why the number is drawn as an icon, not a tray label
|
|
300
|
+
|
|
301
|
+
AppIndicator has a built-in feature for showing text next to the tray icon
|
|
302
|
+
(a "label"). On this project's target environment (GNOME Shell 46 +
|
|
303
|
+
`ubuntu-appindicators`), that feature silently doesn't render anything,
|
|
304
|
+
even though the app publishes it correctly - a Shell-extension bug, not
|
|
305
|
+
something fixable from the app side. Instead, `ui/icon_renderer.py` draws
|
|
306
|
+
the reading as a small bitmap and that image becomes the tray icon itself,
|
|
307
|
+
which does render reliably. If a future Shell/extension update fixes label
|
|
308
|
+
rendering, this could be simplified back to `set_label()`.
|
|
309
|
+
|
|
310
|
+
## Privacy
|
|
311
|
+
|
|
312
|
+
- Your LibreLinkUp password is stored only in your system keyring
|
|
313
|
+
(GNOME Keyring), never in a plain file. Your email is stored in
|
|
314
|
+
`~/.config/glucoglance/config.toml`.
|
|
315
|
+
- The app talks only to Abbott's LibreLinkUp servers. It has no server of
|
|
316
|
+
its own, no analytics and no telemetry, so your readings and credentials
|
|
317
|
+
never go anywhere else.
|
|
318
|
+
- Tray menu → **Log out** deletes the stored password and email.
|
|
319
|
+
|
|
320
|
+
## Contributing
|
|
321
|
+
|
|
322
|
+
Bug reports and pull requests are welcome - see
|
|
323
|
+
[CONTRIBUTING.md](https://github.com/toabm/glucoglance-ubuntu/blob/master/CONTRIBUTING.md).
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
MIT - see [LICENSE](https://github.com/toabm/glucoglance-ubuntu/blob/master/LICENSE).
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# GlucoGlance for Ubuntu
|
|
2
|
+
|
|
3
|
+
[](https://github.com/toabm/glucoglance-ubuntu/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
A tray widget that shows your current glucose reading (from a FreeStyle
|
|
6
|
+
Libre sensor, via LibreLinkUp) in the Ubuntu top bar. Phase 1: just the
|
|
7
|
+
number and trend arrow, refreshed roughly every minute. Threshold alarms are
|
|
8
|
+
planned as a phase 2.
|
|
9
|
+
|
|
10
|
+
> **Compatibility - please check before installing.** GlucoGlance only
|
|
11
|
+
> works with:
|
|
12
|
+
>
|
|
13
|
+
> - **Ubuntu** (developed and tested on Ubuntu 24.04 with GNOME Shell 46).
|
|
14
|
+
> Windows, macOS, and other Linux distributions/desktops are not
|
|
15
|
+
> supported.
|
|
16
|
+
> - **FreeStyle Libre sensors** whose readings are shared through
|
|
17
|
+
> **LibreLinkUp**. Other CGMs (Dexcom, Medtronic, Eversense, etc.) are
|
|
18
|
+
> not supported.
|
|
19
|
+
> - A **LibreLinkUp account** - see Requirements below.
|
|
20
|
+
|
|
21
|
+
## ⚠️ Disclaimer
|
|
22
|
+
|
|
23
|
+
**GlucoGlance is not a medical device.** It has not been reviewed or
|
|
24
|
+
approved by the FDA, the EMA, or any other regulator.
|
|
25
|
+
|
|
26
|
+
- It is an **unofficial, independent** project. It is not affiliated
|
|
27
|
+
with, endorsed by, or supported by Abbott. FreeStyle Libre and
|
|
28
|
+
LibreLinkUp are trademarks of Abbott, used here only to describe what
|
|
29
|
+
the app works with.
|
|
30
|
+
- Readings may be **delayed, missing or wrong**. **Do not use this app to
|
|
31
|
+
make treatment decisions** (e.g. insulin dosing). Always confirm with
|
|
32
|
+
your sensor's official app or a fingerstick blood glucose meter.
|
|
33
|
+
- It relies on an **undocumented LibreLinkUp API** that Abbott can change
|
|
34
|
+
or block at any time, so the app may stop working without warning.
|
|
35
|
+
- It is provided "as is", without warranty of any kind (see
|
|
36
|
+
[LICENSE](https://github.com/toabm/glucoglance-ubuntu/blob/master/LICENSE)). **Use it at your own risk.**
|
|
37
|
+
|
|
38
|
+
## Requirements
|
|
39
|
+
|
|
40
|
+
- **Ubuntu** with the default GNOME desktop (see Compatibility above).
|
|
41
|
+
- A **FreeStyle Libre sensor** whose wearer shares their readings to
|
|
42
|
+
**LibreLinkUp** from the official Libre app.
|
|
43
|
+
- A LibreLinkUp **follower** account that has accepted that share: you
|
|
44
|
+
log in here with the follower account's email and password.
|
|
45
|
+
|
|
46
|
+
This app cannot talk to the sensor directly - it only reads what the
|
|
47
|
+
official Libre app has already uploaded to LibreLinkUp.
|
|
48
|
+
|
|
49
|
+
## Installing on Ubuntu
|
|
50
|
+
|
|
51
|
+
### Quick install (from PyPI, with pipx)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
sudo apt install pipx python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1
|
|
55
|
+
pipx ensurepath
|
|
56
|
+
pipx install --system-site-packages glucoglance
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`--system-site-packages` is required: it lets the app reuse the GTK
|
|
60
|
+
bindings installed by `apt`, which PyPI doesn't distribute. Open a new
|
|
61
|
+
terminal (so `pipx ensurepath` takes effect) and run `glucoglance` - then
|
|
62
|
+
skip to "Running it for the first time" below. Upgrade later with
|
|
63
|
+
`pipx upgrade glucoglance`.
|
|
64
|
+
|
|
65
|
+
### From source
|
|
66
|
+
|
|
67
|
+
These steps assume a fresh Ubuntu machine with nothing set up yet - if
|
|
68
|
+
you've already done part of this, skip ahead.
|
|
69
|
+
|
|
70
|
+
**1. Get the code:**
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/toabm/glucoglance-ubuntu.git
|
|
74
|
+
cd glucoglance-ubuntu
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**2. Install the system packages** the tray icon needs (these come from
|
|
78
|
+
`apt`, not `pip` - they're GTK/AppIndicator bindings that Python's package
|
|
79
|
+
index doesn't distribute):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
sudo apt install python3-venv python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
(If your Ubuntu/distro version ships classic `AppIndicator3` instead of
|
|
86
|
+
the Ayatana fork, install `gir1.2-appindicator3-0.1` instead - the app
|
|
87
|
+
tries Ayatana first and falls back automatically, so either works.)
|
|
88
|
+
|
|
89
|
+
**3. Create a Python virtual environment and install the app into it.**
|
|
90
|
+
`--system-site-packages` is required here - it lets the venv reuse the
|
|
91
|
+
`python3-gi` bindings you just installed with `apt`, instead of trying
|
|
92
|
+
(and failing) to build them from PyPI:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
python3 -m venv --system-site-packages .venv
|
|
96
|
+
source .venv/bin/activate
|
|
97
|
+
pip install .
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
That's the whole install. The `glucoglance` command now exists at
|
|
101
|
+
`.venv/bin/glucoglance` (and on your `PATH` while the venv is
|
|
102
|
+
activated).
|
|
103
|
+
|
|
104
|
+
## Running it for the first time
|
|
105
|
+
|
|
106
|
+
With the venv activated (`source .venv/bin/activate`, if you're in a new
|
|
107
|
+
terminal):
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
glucoglance
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
A small dialog pops up asking for your LibreLinkUp email and password (see
|
|
114
|
+
Requirements above). Enter them and press OK. The email is saved to
|
|
115
|
+
`~/.config/glucoglance/config.toml`; the password is stored in your
|
|
116
|
+
system keyring (GNOME Keyring), never in plaintext. A number should then
|
|
117
|
+
appear in your top bar within a few seconds - that's your current glucose
|
|
118
|
+
reading.
|
|
119
|
+
|
|
120
|
+
You won't need to repeat this - the credentials are remembered, and (see
|
|
121
|
+
below) the app is set to start automatically at every login by default.
|
|
122
|
+
|
|
123
|
+
Right-click the tray icon for:
|
|
124
|
+
- **Start at login** - checkbox, on by default (see "Running automatically
|
|
125
|
+
at login" below).
|
|
126
|
+
- **Restart** - reloads the app, e.g. after editing `config.toml`.
|
|
127
|
+
- **Quit**.
|
|
128
|
+
|
|
129
|
+
## Adding it to your Applications menu
|
|
130
|
+
|
|
131
|
+
This is separate from "start at login" below: this makes GlucoGlance
|
|
132
|
+
show up as a proper icon in GNOME's Activities overview and app search
|
|
133
|
+
(so you can launch it manually, or pin it to the Dock), rather than only
|
|
134
|
+
starting silently in the background. Run this once, from the repo
|
|
135
|
+
directory, with the venv already created as above:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
test -x .venv/bin/glucoglance || { echo "Run this from the glucoglance-ubuntu directory (the venv wasn't found here)"; exit 1; }
|
|
139
|
+
ICON_PATH=$(.venv/bin/python3 -c "from glucoglance.ui.app_icon import app_icon_path; print(app_icon_path())")
|
|
140
|
+
mkdir -p ~/.local/share/applications
|
|
141
|
+
cat > ~/.local/share/applications/glucoglance.desktop <<EOF
|
|
142
|
+
[Desktop Entry]
|
|
143
|
+
Type=Application
|
|
144
|
+
Name=GlucoGlance
|
|
145
|
+
Exec=$(pwd)/.venv/bin/glucoglance
|
|
146
|
+
Icon=$ICON_PATH
|
|
147
|
+
Comment=Shows current blood glucose reading in the top bar
|
|
148
|
+
Terminal=false
|
|
149
|
+
Categories=Utility;
|
|
150
|
+
EOF
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
It should now appear if you search for "GlucoGlance" in GNOME's
|
|
154
|
+
Activities overview (press the Super/Windows key and start typing). From
|
|
155
|
+
there you can drag it onto the Dock to pin it.
|
|
156
|
+
|
|
157
|
+
(This installs into `~/.local/share/applications`, the standard location
|
|
158
|
+
for manually-installed apps - not `/usr/share/applications`, which is
|
|
159
|
+
where apt/snap-installed apps land since that directory is shared across
|
|
160
|
+
all users on the machine. GNOME scans both identically, so this works the
|
|
161
|
+
same either way; no need to move it.)
|
|
162
|
+
|
|
163
|
+
(The `Exec=` line uses an absolute path to the venv you just created,
|
|
164
|
+
rather than the bare `glucoglance` command, since a graphical launcher
|
|
165
|
+
doesn't necessarily have your venv on its `PATH`. If you ever move the
|
|
166
|
+
`glucoglance-ubuntu` folder, re-run the command above to update it.)
|
|
167
|
+
|
|
168
|
+
## Configuration
|
|
169
|
+
|
|
170
|
+
Settings live at `~/.config/glucoglance/config.toml` (created with
|
|
171
|
+
defaults on first run). Notable options:
|
|
172
|
+
|
|
173
|
+
```toml
|
|
174
|
+
interval_seconds = 60 # how often to poll, in seconds
|
|
175
|
+
unit = "mgdl" # "mgdl" or "mmol"
|
|
176
|
+
low_threshold_mgdl = 80 # below this, the icon turns red
|
|
177
|
+
high_threshold_mgdl = 180 # above this, the icon turns yellow (green in between)
|
|
178
|
+
color_low = "#ED4343"
|
|
179
|
+
color_normal = "#4DCC66"
|
|
180
|
+
color_high = "#F5D334"
|
|
181
|
+
autostart_enabled = true # start automatically at login (see below)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Edit the file and restart `glucoglance` for changes to take effect.
|
|
185
|
+
|
|
186
|
+
## Running automatically at login
|
|
187
|
+
|
|
188
|
+
Enabled by default - on every startup the app installs (or removes) a
|
|
189
|
+
`~/.config/autostart/glucoglance.desktop` entry to match the
|
|
190
|
+
`autostart_enabled` setting. That path is the standard XDG autostart
|
|
191
|
+
location on Ubuntu (and GNOME/most other Linux desktops generally), but
|
|
192
|
+
this project is only built and tested against Ubuntu - see "Installing on
|
|
193
|
+
Ubuntu" above. Toggle it anytime from the tray icon's right-click menu
|
|
194
|
+
("Start at login"), or by editing `autostart_enabled` in `config.toml` and
|
|
195
|
+
restarting.
|
|
196
|
+
|
|
197
|
+
That autostart entry always waits 6 seconds before actually launching the
|
|
198
|
+
app (only on this path - running from a terminal or the Applications-menu
|
|
199
|
+
icon starts immediately). This isn't configurable, and it's not about
|
|
200
|
+
sensor timing: it exists purely to influence where the icon lands in the
|
|
201
|
+
top bar. GNOME Shell's AppIndicator extension inserts each new tray icon
|
|
202
|
+
at a fixed position rather than appending, so indicators that register
|
|
203
|
+
*later* tend to end up ahead of ones that registered earlier. The delay
|
|
204
|
+
gives your other autostart tray apps a head start, with the goal of
|
|
205
|
+
landing this icon at the left edge of the right-side icon group (i.e.
|
|
206
|
+
immediately after the clock, ahead of things like wifi/bluetooth/volume) -
|
|
207
|
+
though the exact result depends on how many other apps you have and how
|
|
208
|
+
long they take to start, so it may need tuning (edit
|
|
209
|
+
`_STARTUP_DELAY_SECONDS` in `config/autostart.py`) to get exactly there.
|
|
210
|
+
|
|
211
|
+
## Tests & linting
|
|
212
|
+
|
|
213
|
+
Tests and linting need the extra dev dependencies, which the regular
|
|
214
|
+
install above skips:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pip install -e ".[dev]"
|
|
218
|
+
ruff check . # lint
|
|
219
|
+
pytest --cov=glucoglance --cov-report=term-missing # tests + coverage
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Overall coverage sits around 49% by design, not by accident: GTK/keyring-
|
|
223
|
+
dependent code (`main.py`, `ui/tray.py`, `ui/credential_prompt.py`,
|
|
224
|
+
`ui/display.py`, `config/credentials.py`) is deliberately manual-only -
|
|
225
|
+
see CLAUDE.md's "Testing philosophy" section.
|
|
226
|
+
|
|
227
|
+
Coverage includes branches (`[tool.coverage.run] branch = true` in
|
|
228
|
+
`pyproject.toml`, applied automatically - no extra flag needed), not
|
|
229
|
+
just lines: a line can show as "covered" while one of its branches
|
|
230
|
+
(e.g. one side of an `if`) was never actually exercised, so branch
|
|
231
|
+
coverage catches real gaps line coverage hides.
|
|
232
|
+
|
|
233
|
+
If your IDE flags `gi.repository` symbols (e.g. `GLib`, `Gtk`) as
|
|
234
|
+
unresolved, that's expected - PyGObject generates those modules
|
|
235
|
+
dynamically from typelibs at runtime, not from real `.py` files, so
|
|
236
|
+
static analyzers can't see them without type stubs. Install those
|
|
237
|
+
separately from `dev` (pip otherwise tries to rebuild the real
|
|
238
|
+
PyGObject/pycairo from source to satisfy this package's declared
|
|
239
|
+
dependency, and fails without cairo/girepository dev headers):
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
pip install --no-deps PyGObject-stubs
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Continuous integration
|
|
246
|
+
|
|
247
|
+
Every push to `develop`/`master` and every pull request runs `ruff` and
|
|
248
|
+
the full test suite (`.github/workflows/ci.yml`), publishing a test
|
|
249
|
+
report and a coverage summary (including diff/patch coverage on PRs) as
|
|
250
|
+
a PR comment. `master` is protected: it only accepts changes through a
|
|
251
|
+
pull request, and the "Lint & Test" check must pass before merging.
|
|
252
|
+
|
|
253
|
+
For PRs opened from a fork, the test/coverage report job is skipped -
|
|
254
|
+
GitHub gives fork PRs a read-only token, so it couldn't post its comment
|
|
255
|
+
anyway. "Lint & Test" still runs, and its log shows the full results.
|
|
256
|
+
|
|
257
|
+
## Project layout
|
|
258
|
+
|
|
259
|
+
- `client/` - talks to the LibreLinkUp API.
|
|
260
|
+
- `domain/` - plain data types (readings, trend, unit conversion), no I/O.
|
|
261
|
+
- `poller/` - background polling loop; publishes events on an `EventBus`.
|
|
262
|
+
- `alerts/` - placeholder for phase 2 threshold alarms.
|
|
263
|
+
- `ui/` - the tray display, built behind a small `Display` interface so
|
|
264
|
+
other frontends (e.g. a floating window) can be added later.
|
|
265
|
+
- `config/` - settings (TOML) and credentials (system keyring).
|
|
266
|
+
|
|
267
|
+
## Why the number is drawn as an icon, not a tray label
|
|
268
|
+
|
|
269
|
+
AppIndicator has a built-in feature for showing text next to the tray icon
|
|
270
|
+
(a "label"). On this project's target environment (GNOME Shell 46 +
|
|
271
|
+
`ubuntu-appindicators`), that feature silently doesn't render anything,
|
|
272
|
+
even though the app publishes it correctly - a Shell-extension bug, not
|
|
273
|
+
something fixable from the app side. Instead, `ui/icon_renderer.py` draws
|
|
274
|
+
the reading as a small bitmap and that image becomes the tray icon itself,
|
|
275
|
+
which does render reliably. If a future Shell/extension update fixes label
|
|
276
|
+
rendering, this could be simplified back to `set_label()`.
|
|
277
|
+
|
|
278
|
+
## Privacy
|
|
279
|
+
|
|
280
|
+
- Your LibreLinkUp password is stored only in your system keyring
|
|
281
|
+
(GNOME Keyring), never in a plain file. Your email is stored in
|
|
282
|
+
`~/.config/glucoglance/config.toml`.
|
|
283
|
+
- The app talks only to Abbott's LibreLinkUp servers. It has no server of
|
|
284
|
+
its own, no analytics and no telemetry, so your readings and credentials
|
|
285
|
+
never go anywhere else.
|
|
286
|
+
- Tray menu → **Log out** deletes the stored password and email.
|
|
287
|
+
|
|
288
|
+
## Contributing
|
|
289
|
+
|
|
290
|
+
Bug reports and pull requests are welcome - see
|
|
291
|
+
[CONTRIBUTING.md](https://github.com/toabm/glucoglance-ubuntu/blob/master/CONTRIBUTING.md).
|
|
292
|
+
|
|
293
|
+
## License
|
|
294
|
+
|
|
295
|
+
MIT - see [LICENSE](https://github.com/toabm/glucoglance-ubuntu/blob/master/LICENSE).
|