diff --git a/README.md b/README.md index 30564fd9..38e0829c 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Generate your metrics that you can embed everywhere, including your GitHub profi @@ -100,7 +100,7 @@ Generate your metrics that you can embed everywhere, including your GitHub profi - + + + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - + @@ -574,6 +578,7 @@ https://my-personal-domain.com/my-github-user?base=0&base.repositories=1 + @@ -597,6 +602,7 @@ https://my-personal-domain.com/my-github-user?base=0&base.repositories=1 + @@ -620,6 +626,7 @@ https://my-personal-domain.com/my-github-user?base=0&base.repositories=1 + @@ -659,6 +666,7 @@ See their respective documentation for more informations about how to setup them * [đŸˆˇī¸ Most used languages](/source/plugins/languages/README.md) * [👨‍đŸ’ģ Lines of code changed](/source/plugins/lines/README.md) * [đŸŽŧ Music plugin](/source/plugins/music/README.md) +* [💉 Nightscout](/source/plugins/nightscout/README.md) * [âąī¸ Website performances](/source/plugins/pagespeed/README.md) * [🧑‍🤝‍🧑 People plugin](/source/plugins/people/README.md) * [âœ’ī¸ Recent posts](/source/plugins/posts/README.md) diff --git a/action.yml b/action.yml index 57138ab6..2b5ce47f 100644 --- a/action.yml +++ b/action.yml @@ -365,6 +365,44 @@ inputs: description: Music provider username default: .user.login + # ==================================================================================== + # 💉 Nightscout + + # Enable or disable plugin + plugin_nightscout: + description: Displays Blood Glucose + default: no + + # Nightscout site URL + plugin_nightscout_url: + description: Your Nightscout site URL + default: https://example.herokuapp.com + + # Controls how big the graph is + plugin_nightscout_datapoints: + description: How many datapoints to show on the graph. 0 and 1 disable the graph. + default: 12 + + # Low value used for colors and text alerts + plugin_nightscout_lowalert: + description: When the blood sugar is considered low + default: 80 + + # High value used for colors and text alerts + plugin_nightscout_highalert: + description: When the blood sugar is considered high + default: 180 + + # Urgent low value used for colors and text alerts + plugin_nightscout_urgentlowalert: + description: When the blood sugar is considered urgently low + default: 50 + + # Urgent high value used for colors and text alerts + plugin_nightscout_urgenthighalert: + description: When the blood sugar is considered urgently high + default: 250 + # ==================================================================================== # âąī¸ Website performances diff --git a/settings.example.json b/settings.example.json index ececa048..333cf511 100644 --- a/settings.example.json +++ b/settings.example.json @@ -49,6 +49,9 @@ "token": null, "//":"Music provider personal token", "enabled": false, "//": "Display your music tracks" }, + "nightscout":{ + "enabled": false, "//": "Displays Blood Glucose" + }, "pagespeed":{ "token": null, "//":"PageSpeed token", "enabled": false, "//": "Display a website Google PageSpeed metrics" diff --git a/source/app/mocks/api/axios/get/nightscout.mjs b/source/app/mocks/api/axios/get/nightscout.mjs new file mode 100644 index 00000000..1662408d --- /dev/null +++ b/source/app/mocks/api/axios/get/nightscout.mjs @@ -0,0 +1,31 @@ +/**Mocked data */ +export default function({faker, url}) { + //Last.fm api + if (/^https:..testapp.herokuapp.com.*$/.test(url)) { + //Get Nightscout Data + console.debug(`metrics/compute/mocks > mocking nightscout api result > ${url}`) + const lastInterval = Math.floor(new Date() / 300000) * 300000 + const directionArray = ["SingleUp", "DoubleUp", "FortyFiveUp", "Flat", "FortyFiveDown", "SingleDown", "DoubleDown"] + return ({ + status:200, + data:{ + data:[{ + _id:faker.git.commitSha().substring(0, 23), + device:"xDrip-DexcomG5", + date:lastInterval, + dateString:new Date(lastInterval).toISOString(), + sgv:faker.random.number({min:40, max:400}), + delta:faker.random.number({min:-10, max:10}), + direction:directionArray[Math.floor(Math.random() * directionArray.length)], + type:"sgv", + filtered:0, + unfiltered:0, + rssi:100, + noise:1, + sysTime:new Date(lastInterval).toISOString(), + utcOffset:faker.random.number({min:-12, max:14})*60, + }], + }, + }) + } + } \ No newline at end of file diff --git a/source/app/web/statics/app.placeholder.js b/source/app/web/statics/app.placeholder.js index 2d21f03c..5c41ba10 100644 --- a/source/app/web/statics/app.placeholder.js +++ b/source/app/web/statics/app.placeholder.js @@ -257,6 +257,17 @@ })) } }) : null), + //Nightscout + ...(set.plugins.enabled.nightscout ? ({ + nightscout:{ + url: options["nightscout.url"] != null && options["nightscout.url"] != "https://example.herokuapp.com" ? options["nightscout.url"]: "https://testapp.herokuapp.com/", + datapoints: faker.random.number({min: 8, max: 12}), + lowalert: faker.random.number({min: 60, max: 90}), + highalert: faker.random.number({min: 150, max: 200}), + urgentlowalert: faker.random.number({min: 40, max: 59}), + urgenthighalert: faker.random.number({min: 201, max: 300}) + } + }) : null), //Pagespeed ...(set.plugins.enabled.pagespeed ? ({ pagespeed:{ diff --git a/source/plugins/README.md b/source/plugins/README.md index dc642e6d..c3e0d64a 100644 --- a/source/plugins/README.md +++ b/source/plugins/README.md @@ -14,6 +14,7 @@ See their respective documentation for more informations about how to setup them * [đŸˆˇī¸ Most used languages](/source/plugins/languages/README.md) * [👨‍đŸ’ģ Lines of code changed](/source/plugins/lines/README.md) * [đŸŽŧ Music plugin](/source/plugins/music/README.md) +* [💉 Nightscout](/source/plugins/nightscout/README.md) * [âąī¸ Website performances](/source/plugins/pagespeed/README.md) * [🧑‍🤝‍🧑 People plugin](/source/plugins/people/README.md) * [âœ’ī¸ Recent posts](/source/plugins/posts/README.md) diff --git a/source/plugins/nightscout/README.md b/source/plugins/nightscout/README.md new file mode 100644 index 00000000..3fda4bf0 --- /dev/null +++ b/source/plugins/nightscout/README.md @@ -0,0 +1,34 @@ +### 💉 Nightscout + +The *Nightscout* plugin lets you display blood sugar values from a [Nightscout](http://nightscout.info) site. + +
- 🧩 19 plugins + 🧩 20 plugins
đŸŽŧ Music pluginâąī¸ Website performances💉 Nightscout
@@ -112,6 +112,16 @@ Generate your metrics that you can embed everywhere, including your GitHub profi + + +
âąī¸ Website performances🧑‍🤝‍🧑 People plugin
Detailed version @@ -122,12 +132,6 @@ Generate your metrics that you can embed everywhere, including your GitHub profi
🧑‍🤝‍🧑 People pluginâœ’ī¸ Recent posts
Followed people version @@ -141,34 +145,40 @@ Generate your metrics that you can embed everywhere, including your GitHub profi
âœ’ī¸ Recent postsđŸ—‚ī¸ Projects
đŸ—‚ī¸ Projects✨ Stargazers over last weeks
✨ Stargazers over last weeks🌟 Recently starred repositories
🌟 Recently starred repositories📌 Starred topics
📌 Starred topics🧮 Repositories traffic
Mastered and known technologies version @@ -176,30 +186,23 @@ Generate your metrics that you can embed everywhere, including your GitHub profi
🧮 Repositories traffic🐤 Latest tweets
🐤 Latest tweets⏰ WakaTime plugin
⏰ WakaTime plugin
@@ -551,6 +554,7 @@ https://my-personal-domain.com/my-github-user?base=0&base.repositories=1 đŸˆˇī¸ 👨‍đŸ’ģ đŸŽŧ💉 âąī¸ 🧑‍🤝‍🧑 âœ’ī¸âœ”ī¸ âœ”ī¸ âœ”ī¸âœ”ī¸ âœ”ī¸ âœ”ī¸ âœ”ī¸âœ”ī¸ âœ”ī¸ ❌❌ âœ”ī¸ âœ”ī¸ âŒâœ”ī¸ âœ”ī¸ ❌❌ âœ”ī¸ ❌ ❌
+ +
+ + +
+ +
+đŸ’Ŧ Setting up a nightscout site + +The [nightscout website](http://www.nightscout.info/) details how to self-host a nightscout site. Check out the instructions there. + +
+ +#### â„šī¸ Examples workflows + +[âžĄī¸ Available options for this plugin](metadata.yml) + +```yaml +- uses: lowlighter/metrics@master + with: + # ... other options + plugin_nightscout: yes + plugin_nightscout_url: ${{ secrets.NIGHTSCOUT_URL }} # Use the github actions "NIGHTSCOUT_URL" secret as your nightscout site + plugin_nightscout_datapoints: 12 # Use the latest 12 blood sugar datapoints to create a graph + plugin_nightscout_lowalert: 80 # Blood sugars below 80 will be considered low + plugin_nightscout_highalert: 180 # Blood sugars above 180 will be considered high + plugin_nightscout_urgentlowalert: 50 # Blood sugars below 50 will be considered urgently low + plugin_nightscout_urgenthighalert: 250 # Blood sugars above 250 will be considered urgently high +``` \ No newline at end of file diff --git a/source/plugins/nightscout/index.mjs b/source/plugins/nightscout/index.mjs new file mode 100644 index 00000000..803edb79 --- /dev/null +++ b/source/plugins/nightscout/index.mjs @@ -0,0 +1,83 @@ +//Setup + export default async function({q, imports, data, account}, {enabled = false} = {}) { + //Plugin execution + try { + //Check if plugin is enabled and requirements are met + if ((!enabled)||(!q.nightscout)) + return null + + //Load inputs + let {url, datapoints, lowalert, highalert, urgentlowalert, urgenthighalert} = imports.metadata.plugins.nightscout.inputs({data, account, q}) + + if (!url || url === "https://example.herokuapp.com") throw "Nightscout site URL isn't set!" + if (url.substring(url.length - 1) !== "/") url += "/" + if (url.substring(0, 7) === "http://") url = `https://${url.substring(7)}` + if (url.substring(0, 8) !== "https://") url = `https://${url}` + if (datapoints <= 0) datapoints = 1 + //Get nightscout data from axios + const resp = await imports.axios.get(`${url}api/v1/entries.json?count=${datapoints}`) + for (let i = 0; i < resp.data.length; i++){ + const {sgv} = resp.data[i] + //Add human readable timestamps and arrows + const date = new Date(resp.data[i].dateString) + resp.data[i].arrowHumanReadable = directionArrow(resp.data[i].direction) + resp.data[i].timeUTCHumanReadable = `${addZero(date.getUTCHours())}:${addZero(date.getUTCMinutes())}` + /* + * Add colors and alert names + * TODO: Maybe make colors better themed instead of just the "github style" - red and yellow could fit better than darker shades of green + */ + let color = "#40c463" + let alertName = "Normal" + if (sgv >= urgenthighalert || sgv <= urgentlowalert){ + color = "#216e39" + alertName = sgv >= urgenthighalert ? "Urgent High" : "Urgent Low" + } + else if (sgv >= highalert || sgv <= lowalert){ + color = "#30a14e" + alertName = sgv >= highalert ? "High" : "Low" + } + resp.data[i].color = color + resp.data[i].alert = alertName + } + return {data:resp.data.reverse()} + } + //Handle errors + catch (error) { + throw {error:{message:"An error occured", instance:error}} + } + } + +function addZero(i) { + if (i < 10) + i = `0${i}` + + return i +} + +function directionArrow(direction) { + const dir = direction.toUpperCase() + switch (dir) { + case "NONE": + return "" + case "DOUBLEUP": + return "↑↑" + case "SINGLEUP": + return "↑" + case "FORTYFIVEUP": + return "↗" + case "FLAT": + return "→" + case "FORTYFIVEDOWN": + return "↘" + case "SINGLEDOWN": + return "↓" + case "DOUBLEDOWN": + return "↓↓" + case "NOT COMPUTABLE": + return "" + case "RATE OUT OF RANGE": + return "" + default: + return "" + } +} diff --git a/source/plugins/nightscout/metadata.yml b/source/plugins/nightscout/metadata.yml new file mode 100644 index 00000000..8d066288 --- /dev/null +++ b/source/plugins/nightscout/metadata.yml @@ -0,0 +1,53 @@ +name: "💉 Nightscout" +cost: N/A +supports: + - user + - organization +inputs: + + # Enable or disable plugin + plugin_nightscout: + description: Displays Blood Glucose + type: boolean + default: no + + # Nightscout site URL + plugin_nightscout_url: + description: Your Nightscout site URL + type: string + default: https://example.herokuapp.com + + # Controls how big the graph is + plugin_nightscout_datapoints: + description: How many datapoints to show on the graph. 0 and 1 disable the graph. + type: number + default: 12 + min: 0 + + # Low value used for colors and text alerts + plugin_nightscout_lowalert: + description: When the blood sugar is considered low + type: number + default: 80 + min: 0 + + # High value used for colors and text alerts + plugin_nightscout_highalert: + description: When the blood sugar is considered high + type: number + default: 180 + min: 0 + + # Urgent low value used for colors and text alerts + plugin_nightscout_urgentlowalert: + description: When the blood sugar is considered urgently low + type: number + default: 50 + min: 0 + + # Urgent high value used for colors and text alerts + plugin_nightscout_urgenthighalert: + description: When the blood sugar is considered urgently high + type: number + default: 250 + min: 0 diff --git a/source/plugins/nightscout/tests.yml b/source/plugins/nightscout/tests.yml new file mode 100644 index 00000000..7f7d2894 --- /dev/null +++ b/source/plugins/nightscout/tests.yml @@ -0,0 +1,14 @@ +- name: Nightscout plugin (default) + uses: lowlighter/metrics@master + with: + token: NOT_NEEDED + plugin_nightscout: yes + plugin_nightscout_url: https://testapp.herokuapp.com/ + +- name: Nightscout plugin (without graph) + uses: lowlighter/metrics@master + with: + token: NOT_NEEDED + plugin_nightscout: yes + plugin_nightscout_url: https://testapp.herokuapp.com/ + plugin_nightscout_datapoints: 0 \ No newline at end of file diff --git a/source/templates/classic/partials/_.json b/source/templates/classic/partials/_.json index 8a6bc5f9..9671fd96 100644 --- a/source/templates/classic/partials/_.json +++ b/source/templates/classic/partials/_.json @@ -10,6 +10,7 @@ "habits", "topics", "music", + "nightscout", "posts", "tweets", "isocalendar", diff --git a/source/templates/classic/partials/nightscout.ejs b/source/templates/classic/partials/nightscout.ejs new file mode 100644 index 00000000..4672e2da --- /dev/null +++ b/source/templates/classic/partials/nightscout.ejs @@ -0,0 +1,42 @@ +<% if (plugins.nightscout) { %> +
+
+ <% if (plugins.nightscout.error) { %> +
+
+ + <%= plugins.nightscout.error.message %> +
+
+ <% } else { %> +
+

+ + Blood Sugar: <%= `${plugins.nightscout.data[plugins.nightscout.data.length-1].sgv}${plugins.nightscout.data[plugins.nightscout.data.length-1].arrowHumanReadable} (${plugins.nightscout.data[plugins.nightscout.data.length-1].alert})`%> +

+ <% if (plugins.nightscout.data.length > 1) { %> +
+
+
+ <% { let previous = null; for (const dataObject of Object.values(plugins.nightscout.data)) { const p = dataObject.sgv/Math.max.apply(Math, Object.values(plugins.nightscout.data).map(function(o) { return o.sgv; })); %> +
+ <%= dataObject.sgv != 0 ? f(dataObject.sgv, {sign:false}) : "" %> +
+
+ <%= dataObject.timeUTCHumanReadable %> +
+
+ <% previous = dataObject.sgv } } %> +
+
+
All times are in UTC.
+ +
+ <%# Do stuff in there -%> +
+ <% } %> + <% } %> +
+
+ <% } %> + \ No newline at end of file