Last active
December 12, 2022 12:12
-
-
Save alisterburt/15280eae3d03ccb28e45713c3e10aeed to your computer and use it in GitHub Desktop.
xbar nightscout plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/Users/alisterburt/mambaforge/envs/py/bin/python | |
from datetime import datetime | |
import requests | |
import timeago | |
from pydantic import BaseModel, validator | |
from pytz import timezone | |
NIGHTSCOUT_URL = "https://ab-nightscout.undo.cl/" | |
ENDPOINT = "api/v1/entries" | |
TIMEZONE = 'Europe/London' | |
ARROWS = { | |
'Flat': '→', | |
'SingleUp': '↑', | |
'FortyFiveUp': '↗', | |
'FortyFiveDown': '↘', | |
'SingleDown': '↓', | |
} | |
request_url = NIGHTSCOUT_URL + ENDPOINT | |
response = requests.get(request_url, timeout=5) | |
if not response.ok: | |
print('bad request') | |
exit(0) | |
class NightscoutEntry(BaseModel): | |
time: datetime | |
blood_glucose: float | |
trend: str | |
source: str | |
@validator('trend', 'source') | |
def remove_quotes(cls, value): | |
return value.strip('"') | |
@property | |
def trend_arrow(self): | |
return ARROWS.get(self.trend, self.trend) | |
@property | |
def value_trend_string(self): | |
return f'{self.blood_glucose} {self.trend_arrow}' | |
@property | |
def local_time(self): | |
return self.time.astimezone(tz=timezone(TIMEZONE)) | |
@property | |
def local_time_string(self): | |
return self.local_time.strftime('%H:%M') | |
@property | |
def time_ago_string(self): | |
now = datetime.now(tz=timezone('UTC')) | |
return timeago.format(self.time, now) | |
@property | |
def summary(self): | |
bg = self.blood_glucose | |
entry_time = self.local_time_string | |
time_ago = self.time_ago_string | |
return f'{bg} @ {entry_time} ({time_ago})' | |
@classmethod | |
def from_item(cls, item: str): | |
_, time, blood_glucose, trend, source = item.split('\t') | |
return cls( | |
time=time, blood_glucose=blood_glucose, trend=trend, source=source | |
) | |
entries = [ | |
NightscoutEntry.from_item(item) | |
for item | |
in response.text.split('\n') | |
] | |
# entries = list(filter(lambda entry: 'xDrip' in entry.source, entries)) | |
# xbar section | |
nightscout_link = f'View on Nightscout | href={NIGHTSCOUT_URL}' | |
# is the last entry up to date? | |
current_entry = entries[0] | |
last_entry = entries[1] | |
now = datetime.now().astimezone(tz=timezone(TIMEZONE)) | |
time_since_last_entry = now - current_entry.time | |
seconds_since_last_entry = time_since_last_entry.total_seconds() | |
seconds_since_last_entry_threshold = 15 * 60 | |
entry_is_outdated = seconds_since_last_entry > seconds_since_last_entry_threshold | |
# calculate rate of change | |
d_bg = current_entry.blood_glucose - last_entry.blood_glucose | |
dt = current_entry.time - last_entry.time | |
dt_minutes = dt.total_seconds() / 60 | |
delta_bg_mg_dl_per_minute = d_bg / dt_minutes | |
delta_str = f'(Δ{delta_bg_mg_dl_per_minute:.1f})' | |
if -1 < delta_bg_mg_dl_per_minute < 1: | |
trend = ARROWS['Flat'] | |
elif 1 <= delta_bg_mg_dl_per_minute < 2: | |
trend = ARROWS['FortyFiveUp'] | |
elif delta_bg_mg_dl_per_minute >= 2: | |
trend = ARROWS['SingleUp'] | |
elif -2 < delta_bg_mg_dl_per_minute <= -1: | |
trend = ARROWS['FortyFiveDown'] | |
elif delta_bg_mg_dl_per_minute <= -2: | |
trend = ARROWS['SingleDown'] | |
else: | |
trend = delta_str | |
if entry_is_outdated: | |
main_item = current_entry.summary | |
else: | |
main_item = f'{current_entry.blood_glucose:.0f} {trend} {delta_str}' | |
summaries = '\n'.join(entry.summary for entry in entries) | |
xbar_string = f"""{main_item} | |
--- | |
{summaries} | |
{nightscout_link}""" | |
print(xbar_string) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment