Skip to content

Instantly share code, notes, and snippets.

@My-Random-Thoughts
Last active November 12, 2024 21:46
Show Gist options
  • Save My-Random-Thoughts/f25651d85a35367a7290a7502b9eb80a to your computer and use it in GitHub Desktop.
Save My-Random-Thoughts/f25651d85a35367a7290a7502b9eb80a to your computer and use it in GitHub Desktop.
Node-RED SubFlow to Get LibreLinkUp API Data
[
{
"id": "99c028b90d557c84",
"type": "group",
"z": "c07b047ac4d1031c",
"name": "Blood Glucose Data",
"style": {
"label": true
},
"nodes": [
"7eac23037bb2cb6e",
"0fc4e3f21fb3c353",
"39ba2ede2e620cf7",
"ff92dd37eadf0d91",
"1e062653f6408f1b"
],
"x": 154,
"y": 179,
"w": 652,
"h": 122
},
{
"id": "971815d09245e7d0",
"type": "subflow",
"name": "llu-api",
"info": "",
"category": "",
"in": [
{
"x": 40,
"y": 40,
"wires": [
{
"id": "173b49ec74fa2d74"
}
]
}
],
"out": [
{
"x": 1140,
"y": 240,
"wires": [
{
"id": "98d4be588da5dd41",
"port": 0
},
{
"id": "6b3ae50153996dd0",
"port": 0
}
]
}
],
"env": [
{
"name": "baseUrl",
"type": "str",
"value": "https://api-eu.libreview.io/",
"ui": {
"icon": "font-awesome/fa-link",
"label": {
"en-US": "Base URL"
},
"type": "input",
"opts": {
"types": [
"str"
]
}
}
},
{
"name": "username",
"type": "str",
"value": "",
"ui": {
"icon": "font-awesome/fa-address-card-o",
"label": {
"en-US": "Username"
},
"type": "input",
"opts": {
"types": [
"str"
]
}
}
},
{
"name": "password",
"type": "cred",
"ui": {
"icon": "font-awesome/fa-lock",
"label": {
"en-US": "Password"
}
}
},
{
"name": "returnGraphDataOnly",
"type": "bool",
"value": "true",
"ui": {
"label": {
"en-US": "Return just graph data"
},
"type": "checkbox"
}
}
],
"meta": {},
"color": "#FDF0C2",
"icon": "font-awesome/fa-eyedropper",
"status": {
"x": 340,
"y": 100,
"wires": [
{
"id": "173b49ec74fa2d74",
"port": 0
},
{
"id": "06a1a2a78d10ecf6",
"port": 0
}
]
}
},
{
"id": "173b49ec74fa2d74",
"type": "function",
"z": "971815d09245e7d0",
"name": "Check Data",
"func": "// Checks to see if there is a token and that it has not expired.\n// If the token is valie, it then checks to see if there is a PatientId/\n//\n// Data is stored in a flow context data with the fllowing format:\n// \n// llu-data: {\n// baseUrl: \"...\" <-- Base URL\n// expiry: \"...\" <-- expiry date for token\n// token: \"...\" <-- auth token\n// patient: \"...\" <-- patient id for connections\n// }\n\nvar status = \"\";\nvar llu_data = (global.get(\"llu-data\")) || {}\nvar baseUrl = llu_data.baseUrl ? llu_data.baseUrl : env.get(\"baseUrl\");\nif (baseUrl.match(/\\/$/)) { baseUrl = baseUrl.slice(0, -1); }\n\nswitch (true) {\n case (!(llu_data.token)):\n msg.url = `${baseUrl}/llu/auth/login`;\n msg.method = \"POST\";\n status = \"Login...\"; // No Token\n break;\n\n case (!(llu_data.expiry)):\n msg.url = `${baseUrl}/llu/auth/login`;\n msg.method = \"POST\";\n status = \"Login...\"; // No Expiry\n break;\n \n case (llu_data.expiry):\n var expiry = new Date(llu_data.expiry * 1000)\n var date = new Date();\n\n if (expiry.getTime() <= date.getTime()) {\n msg.url = `${baseUrl}/llu/auth/login`; // Expiry date has passed\n msg.method = \"POST\"\n status = \"Login..\"; // Expired\n }\n break;\n\n case (!(llu_data.patient)):\n msg.url = `${baseUrl}/llu/connections`;\n msg.method = \"GET\";\n status = \"Getting Connections...\";\n break;\n\n default:\n msg.url = `${baseUrl}/llu/connections/${llu_data.patient}/graph`;\n msg.method = \"GET\";\n status = \"Getting Data...\";\n}\n\nmsg.headers = {\n \"cache-control\": \"no-cache\",\n \"connection\": \"Keep-Alive\",\n \"content-type\": \"application/json\",\n \"product\": \"llu.android\",\n \"version\": \"4.10\",\n \"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.3\",\n};\n\nif (msg.url.match(\"/auth/login\")) {\n msg.payload = {\n \"email\": env.get(\"username\"),\n \"password\": env.get(\"password\")\n }\n}\nelse {\n msg.headers.authorization = `Bearer ${llu_data.token}`\n}\n\nreturn [\n {payload: {fill: \"blue\", shape: \"dot\", text: status}},\n msg\n];\n",
"outputs": 2,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 190,
"y": 140,
"wires": [
[],
[
"b6781cd7458a3ebf"
]
],
"outputLabels": [
"",
"Status Messages"
]
},
{
"id": "b6781cd7458a3ebf",
"type": "http request",
"z": "971815d09245e7d0",
"name": "HTTP Request",
"method": "use",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 400,
"y": 180,
"wires": [
[
"1684874edacc0c07"
]
]
},
{
"id": "1684874edacc0c07",
"type": "switch",
"z": "971815d09245e7d0",
"name": "Check URL",
"property": "responseUrl",
"propertyType": "msg",
"rules": [
{
"t": "regex",
"v": "/auth/login$",
"vt": "str",
"case": true
},
{
"t": "regex",
"v": "/connections$",
"vt": "str",
"case": true
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 590,
"y": 180,
"wires": [
[
"e826b0b853799d13"
],
[
"baf3265cb8a2f01a"
],
[
"956e732bc92e3d5a",
"0471ecd36f1d7754"
]
]
},
{
"id": "2aac8eeb3ff68f71",
"type": "link in",
"z": "971815d09245e7d0",
"name": "Login Loop",
"links": [
"df3225ef197ddd60"
],
"x": 35,
"y": 140,
"wires": [
[
"173b49ec74fa2d74"
]
],
"icon": "font-awesome/fa-unlock-alt"
},
{
"id": "df3225ef197ddd60",
"type": "link out",
"z": "971815d09245e7d0",
"name": "Login Loop",
"mode": "link",
"links": [
"2aac8eeb3ff68f71"
],
"x": 935,
"y": 140,
"wires": [],
"icon": "font-awesome/fa-unlock-alt"
},
{
"id": "e826b0b853799d13",
"type": "change",
"z": "971815d09245e7d0",
"name": "Set Token",
"rules": [
{
"t": "set",
"p": "llu-data.token",
"pt": "global",
"to": "payload.data.authTicket.token",
"tot": "msg"
},
{
"t": "set",
"p": "llu-data.expiry",
"pt": "global",
"to": "payload.data.authTicket.expires",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 780,
"y": 120,
"wires": [
[
"df3225ef197ddd60"
]
]
},
{
"id": "baf3265cb8a2f01a",
"type": "change",
"z": "971815d09245e7d0",
"name": "Set Patient",
"rules": [
{
"t": "set",
"p": "llu-data.patient",
"pt": "global",
"to": "payload.data[0].patientId",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 790,
"y": 180,
"wires": [
[
"df3225ef197ddd60"
]
]
},
{
"id": "98d4be588da5dd41",
"type": "change",
"z": "971815d09245e7d0",
"name": "Set Payload",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.data.graphData",
"tot": "msg",
"dc": true
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 990,
"y": 260,
"wires": [
[]
]
},
{
"id": "956e732bc92e3d5a",
"type": "switch",
"z": "971815d09245e7d0",
"name": "Return All?",
"property": "returnGraphDataOnly",
"propertyType": "env",
"rules": [
{
"t": "false"
},
{
"t": "true"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 790,
"y": 240,
"wires": [
[
"f1c48b5cb938cde7"
],
[
"98d4be588da5dd41"
]
]
},
{
"id": "7a8ee83ccf83fe36",
"type": "change",
"z": "971815d09245e7d0",
"name": "Clear Status",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 990,
"y": 320,
"wires": [
[
"3e3498f715bb4361"
]
]
},
{
"id": "0471ecd36f1d7754",
"type": "delay",
"z": "971815d09245e7d0",
"name": "1s Delay",
"pauseType": "delay",
"timeout": "1",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 780,
"y": 320,
"wires": [
[
"7a8ee83ccf83fe36"
]
]
},
{
"id": "06a1a2a78d10ecf6",
"type": "link in",
"z": "971815d09245e7d0",
"name": "Clear Status",
"links": [
"3e3498f715bb4361"
],
"x": 235,
"y": 100,
"wires": [
[]
],
"icon": "font-awesome/fa-paint-brush"
},
{
"id": "3e3498f715bb4361",
"type": "link out",
"z": "971815d09245e7d0",
"name": "Clear Status",
"mode": "link",
"links": [
"06a1a2a78d10ecf6"
],
"x": 1135,
"y": 320,
"wires": [],
"icon": "font-awesome/fa-paint-brush"
},
{
"id": "f1c48b5cb938cde7",
"type": "junction",
"z": "971815d09245e7d0",
"x": 920,
"y": 200,
"wires": [
[
"6b3ae50153996dd0"
]
]
},
{
"id": "6b3ae50153996dd0",
"type": "junction",
"z": "971815d09245e7d0",
"x": 1060,
"y": 200,
"wires": [
[]
]
},
{
"id": "7eac23037bb2cb6e",
"type": "subflow:971815d09245e7d0",
"z": "c07b047ac4d1031c",
"g": "99c028b90d557c84",
"name": "",
"env": [
{
"name": "baseUrl",
"value": "https://api-eu2.libreview.io/",
"type": "str"
},
{
"name": "password",
"type": "cred"
}
],
"x": 390,
"y": 240,
"wires": [
[
"ff92dd37eadf0d91",
"1e062653f6408f1b"
]
]
},
{
"id": "0fc4e3f21fb3c353",
"type": "inject",
"z": "c07b047ac4d1031c",
"g": "99c028b90d557c84",
"name": "Inject",
"props": [],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 250,
"y": 240,
"wires": [
[
"7eac23037bb2cb6e"
]
]
},
{
"id": "39ba2ede2e620cf7",
"type": "ui_chart",
"z": "c07b047ac4d1031c",
"g": "99c028b90d557c84",
"name": "",
"group": "0fc25052abbbacd2",
"order": 1,
"width": "12",
"height": "7",
"label": "Chart",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "0",
"ymax": "20",
"removeOlder": 1,
"removeOlderPoints": "90",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"outputs": 1,
"useDifferentColor": false,
"className": "",
"x": 730,
"y": 220,
"wires": [
[]
]
},
{
"id": "ff92dd37eadf0d91",
"type": "function",
"z": "c07b047ac4d1031c",
"g": "99c028b90d557c84",
"name": "Format Data",
"func": "var msgNew = {\n topic: \"Blood Glucose Data\",\n payload: [{\n \"series\": [\"Blood Glucose Data\"],\n \"data\": [[]],\n \"labels\": [\"Blood Glucose Data\"]\n }]\n};\n\nmsg.payload.forEach(item => {\n msgNew.payload[0].data[0].push({\n x: item.Timestamp,\n y: item.Value\n })\n})\n\nreturn msgNew;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 570,
"y": 220,
"wires": [
[
"39ba2ede2e620cf7"
]
]
},
{
"id": "1e062653f6408f1b",
"type": "debug",
"z": "c07b047ac4d1031c",
"g": "99c028b90d557c84",
"name": "Data Output",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 570,
"y": 260,
"wires": []
},
{
"id": "0fc25052abbbacd2",
"type": "ui_group",
"name": "Chart",
"tab": "70ad754f34f21b44",
"order": 1,
"disp": true,
"width": "12",
"collapse": false,
"className": ""
},
{
"id": "70ad754f34f21b44",
"type": "ui_tab",
"name": "Blood Glucose Data",
"icon": "dashboard",
"order": 11,
"disabled": false,
"hidden": false
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment