forked from ultrabug/py3status
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlibrelinkup.py
More file actions
211 lines (174 loc) · 6.75 KB
/
Copy pathlibrelinkup.py
File metadata and controls
211 lines (174 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
r"""
Display glucose readings from LibreLinkUp-connected patients.
LibreLinkUp provides glucose readings every five minutes, allowing
family, friends, and caregivers of LibreLinkUp-connected patients
to easily keep track of their blood glucose levels with ease.
Configuration parameters:
cache_timeout: refresh interval for this module (default 300)
format: display format for this module (default '{format_patient}')
format_datetime: specify strftime characters to format (default {"timestamp": "%-I:%M %p"})
format_patient: display format for LibreLinkUp-connected patients
*(default '{first_name} [\?color=mg_dl {mg_dl} mg/dL {trend_arrow}]'
' [\?color=darkgrey {timestamp}]')*
format_patient_separator: show separator if more than one (default ' ')
password: specify password for the LibreLinkUp account (default None)
thresholds: specify color thresholds to use
*(default {
"mg_dl": [(79, "bad"), (80, "good"), (181, "degraded"), (251, "orange")],
"mmol_l": [(4.4, "bad"), (4.5, "good"), (10.1, "degraded"), (14.0, "orange")],
})*
username: specify username for the LibreLinkUp account (default None)
Format placeholders:
{format_patient} format for LibreLinkUp-connected patients
format_patient placeholders:
{factory_timestamp} glucose reading recorded time as datetime (utc aware)
{first_name} patient first name
{id} patient id
{last_name} patient last name
{mg_dl} blood glucose value in mg/dL, eg 80
{mmol_l} blood glucose value in mmol/L, eg 4.4
{patient_id} patient id
{timestamp} glucose reading recorded time as datetime
{trend} blood glucose trend information, eg 3
{trend_arrow} blood glucose trend as unicode arrow, eg →
{trend_description} blood glucose trend information description, eg Stable
format_datetime placeholders:
key: epoch_placeholder, eg {timestamp}
value: % strftime characters to be translated, eg '%b %d' ----> 'Jan 1'
Color thresholds:
xxx: print a color based on the value of `xxx` placeholder
Requires:
pylibrelinkup: A simple Python API to interact with LibreLinkUp service
Notes:
IF GLUCOSE ALERTS AND CGM READINGS DO NOT MATCH SYMPTOMS OR EXPECTATIONS,
USE A BLOOD GLUCOSE METER TO MAKE DIABETES TREATMENT DECISIONS.
Examples:
```
# compact version
librelinkup {
format_patient = "[\?color=mg_dl {mg_dl}{trend_arrow} ][\?color=darkgrey {timestamp}]"
format_datetime = {"timestamp": "%-I:%M"}
}
```
@author lasers
SAMPLE OUTPUT
[
{'full_text': 'Tom Hanks '},
{'full_text': '80 mg/dL → ', 'color': '#00FF00'},
{'full_text': '7:15 PM', 'color': '#A9A9A9'},
]
"""
from datetime import datetime
from pylibrelinkup import PyLibreLinkUp
MMOL_L_PER_MG_DL = 18.0182
TREND_ARROW_MAP = {
"DOWN_FAST": "⇊",
"DOWN_SLOW": "↓",
"STABLE": "→",
"UP_SLOW": "↑",
"UP_FAST": "⇈",
}
class Py3status:
""" """
# available configuration parameters
cache_timeout = 300
format = "{format_patient}"
format_datetime = {"timestamp": "%-I:%M %p"}
format_patient = (
r"{first_name} [\?color=mg_dl {mg_dl} mg/dL {trend_arrow}]"
r" [\?color=darkgrey {timestamp}]"
)
format_patient_separator = " "
password = None
thresholds = {
"mg_dl": [
(79, "bad"),
(80, "good"),
(181, "degraded"),
(251, "orange"),
],
"mmol_l": [
(4.4, "bad"),
(4.5, "good"),
(10.1, "degraded"),
(14.0, "orange"),
],
}
username = None
class Meta:
update_config = {
"update_placeholder_format": [
{
"placeholder_formats": {
"mg_dl": ":d",
"mmol_l": ":.2f",
},
"format_strings": ["format_patient"],
}
]
}
def post_config_hook(self):
for x in ["username", "password"]:
if not getattr(self, x):
raise Exception(f"missing `{x}`")
self.init = {
"datetimes": [],
"thresholds": self.py3.get_color_names_list(self.format_patient),
}
for x in ["timestamp", "factory_timestamp"]:
if self.py3.format_contains(self.format_patient, x) and x in self.format_datetime:
self.init["datetimes"].append(x)
self.librelinkup_class = PyLibreLinkUp(email=self.username, password=self.password)
self.librelinkup_class.authenticate()
def _consoldiate(self, patient):
# data
model_data = patient.model_dump()
latest_model_data = self.librelinkup_class.latest(patient).model_dump()
data = model_data | latest_model_data
# ids
for key in ("id", "patient_id"):
data[key] = str(data[key])
# units
if "value_in_mg_per_dl" in data:
v = data["value_in_mg_per_dl"]
data["mg_dl"] = v
data["mmol_l"] = v / MMOL_L_PER_MG_DL
elif "value_in_mmol_per_l" in data:
v = data["value_in_mmol_per_l"]
data["mmol_l"] = v
data["mg_dl"] = v * MMOL_L_PER_MG_DL
# trends
trend_name = getattr(data["trend"], "name", str(data["trend"]))
data["trend_arrow"] = TREND_ARROW_MAP.get(trend_name)
data["trend_description"] = trend_name.replace("_", " ").title()
return data
def librelinkup(self):
patients = self.librelinkup_class.get_patients()
new_patient = []
for patient in patients:
patient_data = self._consoldiate(patient)
for x in self.init["datetimes"]:
obj = datetime.fromisoformat(str(patient_data[x]))
date_format = obj.strftime(self.format_datetime[x])
patient_data[x] = self.py3.safe_format(date_format)
for x in self.init["thresholds"]:
if x in patient_data:
self.py3.threshold_get_color(patient_data[x], x)
new_patient.append(self.py3.safe_format(self.format_patient, patient_data))
format_patient_separator = self.py3.safe_format(self.format_patient_separator)
format_patient = self.py3.composite_join(format_patient_separator, new_patient)
return {
"cached_until": self.py3.time_in(self.cache_timeout),
"full_text": self.py3.safe_format(self.format, {"format_patient": format_patient}),
}
if __name__ == "__main__":
"""
Run module in test mode.
"""
from os import getenv
from py3status.module_test import module_test
config = {
"username": getenv("LIBRELINKUP_USERNAME"),
"password": getenv("LIBRELINKUP_PASSWORD"),
}
module_test(Py3status, config)