FreeStyle Libre 2

Hello. I have a small challenge for you and for me as a HA user an amazing facilitation. I have diabetes and I have a FreeStyle Libre 2 sensor. I miss the ability to read data from this sensor. Optionally, I use the Xdrip+ app.

I think this can be done independently from the sensors version and model by tapping into LibreLinkUp
https://www.librelinkup.com/

https://xdrip.readthedocs.io/en/latest/install/webfollower/

could serve as a starter here

1 Like

Hello,

In the past week, I started looking at the Libre Link since the recent update of no requirements of needing to scan anymore.

I’m not a programmer, but here’s what I’ve put together so far.

I’ve taken 2 separate approaches on getting the Libre Link data. 1-PowerShell and 2-NodeRed

It would be awesome if someone made a proper LibreLink integration.

1: PowerShell
Here’s a simple PowerShell script to get the LibreLink Data

#Libre Link Region and Credentials
$Region = "au"
$Username = "[email protected]"
$Password = "YourPassword"

# Get Auth Token
$AuthToken = $null
$Authheaders = $null
$Authheaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$Authheaders.Add("Pragma", "no-cache")
$Authheaders.Add("Version", "4.7.0")
$Authheaders.Add("product", "llu.ios")
$Authheaders.Add("Cache-Control", "no-cache")
$Authheaders.Add("Accept-Language", "en-AU,en;q=0.9")
$Authheaders.Add("Content-Type", "application/json")
$AuthBody = @"
{
    `"email`": `"$Username`",
    `"password`": `"$Password`"
}
"@
$AuthURI = "https://api-$Region.libreview.io/llu/auth/login"
$tresponse = Invoke-RestMethod $AuthURI -Method 'POST' -Headers $Authheaders -Body $AuthBody
$AuthToken = $tresponse.data.authTicket.token
#$AuthToken

# Get Libre Link Data
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Pragma", "no-cache")
$headers.Add("Version", "4.7.0")
$headers.Add("product", "llu.ios")
$headers.Add("Cache-Control", "no-cache")
$headers.Add("Accept-Language", "en-AU,en;q=0.9")
$headers.Add("Content-Type", "application/json")
$headers.Add("Authorization", "Bearer $AuthToken")
$response = $null
$response = Invoke-RestMethod 'https://api-au.libreview.io/llu/connections' -Method 'GET' -Headers $headers
$headers = $null
#$response | ConvertTo-Json
$timestamp = $response.data.glucoseMeasurement.Timestamp
$level = $response.data.glucoseMeasurement.Value
$TrendArrow = $response.data.glucoseMeasurement.TrendArrow
$MeasurementColor = $response.data.glucoseMeasurement.MeasurementColor
$SensorSerialNumber = $response.data.sensor.sn
$SensorStartUnixTimeStamp = $response.data.sensor.a

# Convert the Unix timestamp to a DateTime object
$SensorStartDateTime = [System.DateTimeOffset]::FromUnixTimeSeconds($SensorStartUnixTimeStamp).DateTime
# Add 14 days to the DateTime object
$SensorEndDateTime = $SensorStartDateTime.AddDays(14)
$SensorStartDateTimeLong = $SensorStartDateTime.ToString("dddd, d MMMM yyyy h:mm:ss tt")
$SensorEndDateTimeLong = $SensorEndDateTime.ToString("dddd, d MMMM yyyy h:mm:ss tt")

Write-Output "==================================================="
Write-Output "As of $timestamp"
Write-Output "Glucose Level $level mmol/L"
Write-Output "Trend Arrow = $TrendArrow"
Write-Output "Measurement Colour = $MeasurementColor"
Write-Output "Sensor Serial Number $SensorSerialNumber"
Write-Output "Sensor Start Date $SensorStartDateTimeLong"
Write-Output "Sensor End Date $SensorEndDateTimeLong"
Write-Output "==================================================="

2 - NodeRed

This is how I’m getting the LibreLink data into Home Assistant.

[{"id":"1d53e8e8cb49d6ee","type":"tab","label":"Libre","disabled":false,"info":"","env":[]},{"id":"3f93eda1ef013b57","type":"http request","z":"1d53e8e8cb49d6ee","name":"Libre Link Auth API Call","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://api-au.libreview.io/llu/auth/login","tls":"5f0b28b1aaa052cb","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"Pragma","valueType":"other","valueValue":"no-cache"},{"keyType":"other","keyValue":"Version","valueType":"other","valueValue":"4.7.0"},{"keyType":"other","keyValue":"product","valueType":"other","valueValue":"llu.ios"},{"keyType":"other","keyValue":"Cache-Control","valueType":"other","valueValue":"no-cache"},{"keyType":"other","keyValue":"Accept-Language","valueType":"other","valueValue":"en-AU,en;q=0.9"},{"keyType":"other","keyValue":"Content-Type","valueType":"other","valueValue":"application/json"}],"x":690,"y":40,"wires":[["6e74824d3048d6c2"]]},{"id":"d682318c.36823","type":"debug","z":"1d53e8e8cb49d6ee","name":"Connection Debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":570,"y":200,"wires":[]},{"id":"ef169e174831491a","type":"http request","z":"1d53e8e8cb49d6ee","name":"Libre Link Connections API Call","method":"GET","ret":"obj","paytoqs":"query","url":"https://api-au.libreview.io/llu/connections","tls":"5f0b28b1aaa052cb","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"Pragma","valueType":"other","valueValue":"no-cache"},{"keyType":"other","keyValue":"Version","valueType":"other","valueValue":"4.7.0"},{"keyType":"other","keyValue":"product","valueType":"other","valueValue":"llu.ios"},{"keyType":"other","keyValue":"Cache-Control","valueType":"other","valueValue":"no-cache"},{"keyType":"other","keyValue":"Accept-Language","valueType":"other","valueValue":"en-AU,en;q=0.9"},{"keyType":"other","keyValue":"Content-Type","valueType":"other","valueValue":"application/json"},{"keyType":"other","keyValue":"Authorization","valueType":"msg","valueValue":"token"}],"x":210,"y":200,"wires":[["d682318c.36823","4af54317f78a2c03","0641052c53bdd52a","3c263e5bfcb22e4a"]]},{"id":"6e74824d3048d6c2","type":"function","z":"1d53e8e8cb49d6ee","name":"Convert Token to Bearer token","func":"\n// Assuming you have a variable named 'token'\nvar token = msg.payload.data.authTicket.token; // Replace 'msg.payload.token' with the actual path to your token variable\n\n// Prepend 'Bearer ' to the token\nvar bearerToken = 'Bearer ' + token;\n\n// Update the message payload with the new bearer token\nmsg.token = bearerToken;\n\n// Return the modified message object\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":120,"wires":[["ef169e174831491a"]]},{"id":"b84131edd60d5143","type":"api-call-service","z":"1d53e8e8cb49d6ee","name":"Update Name BGL","server":"f5d6c7d4.360698","version":5,"debugenabled":false,"domain":"input_number","service":"set_value","areaId":[],"deviceId":[],"entityId":["input_number.Name_bgl"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":810,"y":260,"wires":[[]]},{"id":"4af54317f78a2c03","type":"function","z":"1d53e8e8cb49d6ee","name":"Convert BGL Payload","func":"// Check if msg.payload.data[0] and msg.payload.data[0].glucoseMeasurement exist\nif (\n    msg.payload &&\n    msg.payload.data &&\n    msg.payload.data[0] &&\n    msg.payload.data[0].glucoseMeasurement\n) {\n    // Access the Value property\n    var bgl = msg.payload.data[0].glucoseMeasurement.Value;\n\n    // Assign the value to msg.bgl\n//    msg.payload.bgl = bgl;\n//    msg.payload = '';\n    msg.payload.data.shift();\n    msg.payload.data.value = bgl;\n} else {\n    // Handle the case where the necessary properties are not present\n    console.error(\n        \"Missing properties in msg.payload.data. Unable to set msg.bgl.\"\n    );\n}\n\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":260,"wires":[["b84131edd60d5143"]]},{"id":"0df0514713297b08","type":"inject","z":"1d53e8e8cb49d6ee","name":"Start","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":90,"y":120,"wires":[["0730b4d04dd91244"]]},{"id":"95e0a95020a138f1","type":"cron","z":"1d53e8e8cb49d6ee","name":"Start Every 5 Mins","crontab":"*/5 * * * *","x":130,"y":40,"wires":[["0730b4d04dd91244"]]},{"id":"381d6fd4e0855b9b","type":"api-call-service","z":"1d53e8e8cb49d6ee","name":"Update Name BGL Trend Arrow","server":"f5d6c7d4.360698","version":5,"debugenabled":false,"domain":"input_number","service":"set_value","areaId":[],"deviceId":[],"entityId":["input_number.Name_bgl_trend_arrow"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":850,"y":320,"wires":[[]]},{"id":"0641052c53bdd52a","type":"function","z":"1d53e8e8cb49d6ee","name":"Convert BGL Payload","func":"// Check if msg.payload.data[0] and msg.payload.data[0].glucoseMeasurement exist\nif (\n    msg.payload &&\n    msg.payload.data &&\n    msg.payload.data[0] &&\n    msg.payload.data[0].glucoseMeasurement\n) {\n    // Access the Value property\n    var trendarrow = msg.payload.data[0].glucoseMeasurement.TrendArrow;\n    msg.payload.data.shift();\n    msg.payload.data.value = trendarrow;\n} else {\n    // Handle the case where the necessary properties are not present\n    console.error(\n        \"Missing properties in msg.payload.data. Unable to set msg.payload.\"\n    );\n}\n\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":320,"wires":[["381d6fd4e0855b9b"]]},{"id":"e1a1c0781889539f","type":"api-call-service","z":"1d53e8e8cb49d6ee","name":"Update Name Sensor Serial Number","server":"f5d6c7d4.360698","version":5,"debugenabled":false,"domain":"input_text","service":"set_value","areaId":[],"deviceId":[],"entityId":["input_text.Name_libre_sensor_serial_number"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":860,"y":380,"wires":[[]]},{"id":"3c263e5bfcb22e4a","type":"function","z":"1d53e8e8cb49d6ee","name":"Convert Sensor Serial Number","func":"// Check if msg.payload.data[0] and msg.payload.data[0].glucoseMeasurement exist\nif (\n    msg.payload &&\n    msg.payload.data &&\n    msg.payload.data[0] &&\n    msg.payload.data[0].glucoseMeasurement\n) {\n    // Access the Value property\n    var sensorsn = msg.payload.data[0].sensor.sn;\n    msg.payload.data.shift();\n    msg.payload.data.value = sensorsn;\n} else {\n    // Handle the case where the necessary properties are not present\n    console.error(\n        \"Missing properties in msg.payload.data. Unable to set msg.payload.\"\n    );\n}\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":380,"wires":[["e1a1c0781889539f"]]},{"id":"0730b4d04dd91244","type":"function","z":"1d53e8e8cb49d6ee","name":"Get Libre Link Credentials","func":"var libreuser = global.get('libre_link_user');\nvar librepass = global.get('libre_link_pass');\n// Create or modify the JSON body\nvar jsonBody = {\n    email: libreuser,\n    password: librepass\n};\n\n// Set the modified JSON as the output\nmsg.payload = jsonBody;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":40,"wires":[["3f93eda1ef013b57"]]},{"id":"5f0b28b1aaa052cb","type":"tls-config","name":"TLS","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","servername":"","verifyservercert":false,"alpnprotocol":""},{"id":"f5d6c7d4.360698","type":"server","name":"Home Assistant HA1","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

Hi, I love the fact that you did make the node red flow to get the values, but I can’t get it working, could you please elaborate a bit more on how to do it? The Powershell one doesn’t seem to work either. In the node red flow I did change the api adress to api-eu… but I get expired JWT error now…

Would be marvelous if you could help! TIA! <3

Connection debug gives:
{“message”:“invalid or expired jwt”}

just in case anyone has troubles setting up.

  1. you need to have an account with librelinkup - just get the app on store, invite yourself to watch your glucose.
  2. in the node red flow, edit these:

var libreuser = “[email protected]”;
var librepass = “your_password”;

it’s the “get credentials” node
3) now you have to figure which api your data is on…as I’m in Europe mine are api-eu. Adjust the connection nodes accordingly.

and bang :slight_smile: done

Also here’s my wear os template to display the glucose including the trend arrow (you have to setup your entities accordingly to the node red flow)

<H1 style="text-align: center;">🩸
{% set glucose_value = states('input_number.Name_bgl') | float(default=0) %}
{% set trend_arrow = states('input_number.name_bgl_trend_arrow') | int(default=3) %}

{% if glucose_value < 3.9 %}
  <font color='red'>{{ glucose_value }} mmol/l</font>
{% elif 4.0 <= glucose_value <= 10.0 %}
  <font color='green'>{{ glucose_value }} mmol/l</font>
{% elif 10.1 <= glucose_value <= 13.0 %}
  <font color='yellow'>{{ glucose_value }} mmol/l</font>
{% else %}
  <font color='red'>{{ glucose_value }} mmol/l</font>
{% endif %}

{% if trend_arrow == 1 %}
  <font color='red'>⇊</font>
{% elif trend_arrow == 2 %}
  <font color='orange'>⇊</font>
{% elif trend_arrow == 3 %}
  <font color='green'>→</font>
{% elif trend_arrow == 4 %}
  <font color='green'>⇈</font>
{% elif trend_arrow == 5 %}
  <font color='red'>⇈</font>
{% endif %}
</H1>

You can add more sensors from your home after the H1 tag… mine are for example the outside temperature and solar yield / home load :slight_smile:

Hi, I am new in this. Can you please help?
I am getting the error: (I am in UK and gb is not supported when I tried, so with eu, I am getting this error)
Invoke-RestMethod : {“message”:“missing or malformed jwt”}
At line:37 char:13

Looks like the error I experienced a ton of times. Your data is probably not in api-eu, I would try api-uk but that’s guess work. Hope it works.

Googled and found this :

API Url
The global api url is https://api.libreview.io. If you are placed in europe you can use https://api-eu.libreview.io instead

So you might just need to remove ve the -eu in the API address (do it for all nodes where you see it.)

I’m not sure, but it seems the api has now changed and this way of retrieving data no longer works.

EDIT after a well spent night:
I’ve been up till midnight to figure out a new way and finally I did, the structure of the reply from the api has now changed, so the two functions needed rewriting. Here’s a revised flow:

[{"id":"13a17eac4b567d27","type":"http request","z":"1d53e8e8cb49d6ee","name":"Libre Link Auth API Call","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://api-eu.libreview.io/llu/auth/login","tls":"5f0b28b1aaa052cb","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"Pragma","valueType":"other","valueValue":"no-cache"},{"keyType":"other","keyValue":"Version","valueType":"other","valueValue":"4.7.0"},{"keyType":"other","keyValue":"product","valueType":"other","valueValue":"llu.ios"},{"keyType":"other","keyValue":"Cache-Control","valueType":"other","valueValue":"no-cache"},{"keyType":"other","keyValue":"Accept-Language","valueType":"other","valueValue":"en-AU,en;q=0.9"},{"keyType":"other","keyValue":"Content-Type","valueType":"other","valueValue":"application/json"}],"x":728,"y":78,"wires":[["4377e64f5ec990ac"]]},{"id":"db776d2cd0c7ab15","type":"debug","z":"1d53e8e8cb49d6ee","name":"Connection Debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":608,"y":238,"wires":[]},{"id":"f2705d682ff07157","type":"http request","z":"1d53e8e8cb49d6ee","name":"Libre Link Connections API Call","method":"GET","ret":"obj","paytoqs":"query","url":"https://api-eu.libreview.io/llu/connections","tls":"5f0b28b1aaa052cb","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"Pragma","valueType":"other","valueValue":"no-cache"},{"keyType":"other","keyValue":"Version","valueType":"other","valueValue":"4.7.0"},{"keyType":"other","keyValue":"product","valueType":"other","valueValue":"llu.ios"},{"keyType":"other","keyValue":"Cache-Control","valueType":"other","valueValue":"no-cache"},{"keyType":"other","keyValue":"Accept-Language","valueType":"other","valueValue":"en-AU,en;q=0.9"},{"keyType":"other","keyValue":"Content-Type","valueType":"other","valueValue":"application/json"},{"keyType":"other","keyValue":"Authorization","valueType":"msg","valueValue":"token"}],"x":250,"y":240,"wires":[["db776d2cd0c7ab15","c02b3a48f9ca8fb7","379e4560decb35cf"]]},{"id":"4377e64f5ec990ac","type":"function","z":"1d53e8e8cb49d6ee","name":"Convert Token to Bearer token","func":"\n// Assuming you have a variable named 'token'\nvar token = msg.payload.data.authTicket.token; // Replace 'msg.payload.token' with the actual path to your token variable\n\n// Prepend 'Bearer ' to the token\nvar bearerToken = 'Bearer ' + token;\n\n// Update the message payload with the new bearer token\nmsg.token = bearerToken;\n\n// Return the modified message object\nreturn msg;\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":508,"y":158,"wires":[["f2705d682ff07157"]]},{"id":"2390d7dfd72410f8","type":"inject","z":"1d53e8e8cb49d6ee","name":"Start","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":248,"y":78,"wires":[["286fc53b54724853"]]},{"id":"286fc53b54724853","type":"function","z":"1d53e8e8cb49d6ee","name":"Get Libre Link Credentials","func":"var libreuser = \"[email protected]\";\nvar librepass = \"yourpassword\";\n// Create or modify the JSON body\nvar jsonBody = {\n    email: libreuser,\n    password: librepass\n};\n\n// Set the modified JSON as the output\nmsg.payload = jsonBody;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":448,"y":78,"wires":[["13a17eac4b567d27"]]},{"id":"ed3532566a642df5","type":"api-call-service","z":"1d53e8e8cb49d6ee","name":"Update Name BGL Trend Arrow","server":"bc76673d.54eb28","version":5,"debugenabled":false,"domain":"input_number","service":"set_value","areaId":[],"deviceId":[],"entityId":["input_number.Name_bgl_trend_arrow"],"data":"{   \"value\": {{payload}} }","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":870,"y":360,"wires":[[]]},{"id":"c02b3a48f9ca8fb7","type":"function","z":"1d53e8e8cb49d6ee","name":"bgl new","func":"// Assuming msg.payload is the object returned from the API\nvar apiResponse = msg.payload;\n\n// Check if the necessary nested properties exist in the response\nif (apiResponse && apiResponse.data && Array.isArray(apiResponse.data) && apiResponse.data.length > 0) {\n    var glucoseMeasurement = apiResponse.data[0].glucoseMeasurement;\n\n    // Check if the \"Value\" property exists in the glucoseMeasurement object\n    if (glucoseMeasurement && glucoseMeasurement.Value !== undefined) {\n        // Extract the glucose value\n        var glucoseValue = glucoseMeasurement.Value;\n\n        // Put the glucose value in the payload\n        msg.payload = glucoseValue;\n\n        // Continue with the message\n        return msg;\n    } else {\n        // Handle the case where the \"Value\" property is not found in glucoseMeasurement\n        node.warn(\"Glucose value not found in the API response\");\n        return null; // or return msg; depending on your use case\n    }\n} else {\n    // Handle the case where the necessary nested properties are not found in the response\n    node.warn(\"Nested properties not found in the API response\");\n    return null; // or return msg; depending on your use case\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":560,"y":320,"wires":[["ea384b0a28f22f26"]]},{"id":"ea384b0a28f22f26","type":"api-call-service","z":"1d53e8e8cb49d6ee","name":"Update Name BGL","server":"bc76673d.54eb28","version":5,"debugenabled":false,"domain":"input_number","service":"set_value","areaId":[],"deviceId":[],"entityId":["input_number.Name_bgl"],"data":"{   \"value\": {{payload}} }","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1050,"y":300,"wires":[[]]},{"id":"379e4560decb35cf","type":"function","z":"1d53e8e8cb49d6ee","name":"bgl trend","func":"// Assuming msg.payload is the object returned from the API\nvar apiResponse = msg.payload;\n\n// Check if the necessary nested properties exist in the response\nif (apiResponse && apiResponse.data && Array.isArray(apiResponse.data) && apiResponse.data.length > 0) {\n    var glucoseMeasurement = apiResponse.data[0].glucoseMeasurement;\n\n    // Check if the \"Value\" property exists in the glucoseMeasurement object\n    if (glucoseMeasurement && glucoseMeasurement.TrendArrow !== undefined) {\n        // Extract the glucose value\n        var glucoseValue = glucoseMeasurement.TrendArrow;\n\n        // Put the glucose value in the payload\n        msg.payload = glucoseValue;\n\n        // Continue with the message\n        return msg;\n    } else {\n        // Handle the case where the \"Value\" property is not found in glucoseMeasurement\n        node.warn(\"Glucose value not found in the API response\");\n        return null; // or return msg; depending on your use case\n    }\n} else {\n    // Handle the case where the necessary nested properties are not found in the response\n    node.warn(\"Nested properties not found in the API response\");\n    return null; // or return msg; depending on your use case\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":360,"wires":[["ed3532566a642df5"]]},{"id":"5f0b28b1aaa052cb","type":"tls-config","name":"TLS","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","servername":"","verifyservercert":false,"alpnprotocol":""},{"id":"bc76673d.54eb28","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

If you have customized the flow and don’t want to lose any changes here’s the function that converts glucose value:

// Assuming msg.payload is the object returned from the API
var apiResponse = msg.payload;

// Check if the necessary nested properties exist in the response
if (apiResponse && apiResponse.data && Array.isArray(apiResponse.data) && apiResponse.data.length > 0) {
    var glucoseMeasurement = apiResponse.data[0].glucoseMeasurement;

    // Check if the "Value" property exists in the glucoseMeasurement object
    if (glucoseMeasurement && glucoseMeasurement.Value !== undefined) {
        // Extract the glucose value
        var glucoseValue = glucoseMeasurement.Value;

        // Put the glucose value in the payload
        msg.payload = glucoseValue;

        // Continue with the message
        return msg;
    } else {
        // Handle the case where the "Value" property is not found in glucoseMeasurement
        node.warn("Glucose value not found in the API response");
        return null; // or return msg; depending on your use case
    }
} else {
    // Handle the case where the necessary nested properties are not found in the response
    node.warn("Nested properties not found in the API response");
    return null; // or return msg; depending on your use case
}

and here’s the one for the trend arrow:

// Assuming msg.payload is the object returned from the API
var apiResponse = msg.payload;

// Check if the necessary nested properties exist in the response
if (apiResponse && apiResponse.data && Array.isArray(apiResponse.data) && apiResponse.data.length > 0) {
    var glucoseMeasurement = apiResponse.data[0].glucoseMeasurement;

    // Check if the "Value" property exists in the glucoseMeasurement object
    if (glucoseMeasurement && glucoseMeasurement.TrendArrow !== undefined) {
        // Extract the glucose value
        var glucoseValue = glucoseMeasurement.TrendArrow;

        // Put the glucose value in the payload
        msg.payload = glucoseValue;

        // Continue with the message
        return msg;
    } else {
        // Handle the case where the "Value" property is not found in glucoseMeasurement
        node.warn("Glucose value not found in the API response");
        return null; // or return msg; depending on your use case
    }
} else {
    // Handle the case where the necessary nested properties are not found in the response
    node.warn("Nested properties not found in the API response");
    return null; // or return msg; depending on your use case
}

yeah, one last thing, but very important as well - if you used same e-mail to sign up for librelinkup (to make the api available), don’t EVER delete your account, becuase it’s associated with your libreview one and you’ll lose all your history and stuff…

Thanks for the response on this, but I am so new in the Home Assistant but I was testing out with PowerShell and never use node red. Can you please give me more idea how I can configure this in Home assistant dashboard. if you don’t mind.

Sorry, I only know node red. First of all you’d need to install that. In node red you can just click import and paste the flow code.

Then you need to check the first node and add your credentials (get a linkup account and invite it to monitor your libreview).

After that you need to configure the helper entities accordingly to the last two nodes in the flow. To can then display those in your dashboard or you can use them for automations, display in wear os…

Sounds frightening, but it’s quite easy in the end. I’m sure you can get it working… :upside_down_face:

It’s very worth it.

Felt like adding more:

  1. after you have installed node red, you should click fmenu import:

  2. paste the flow (as in the thread here)

  3. this is what’s it going to look like after you do it. Double click the “credentials” node:

  4. you need to put your credentials here:

  5. double click the api call node (and the second one later) and check the api adress - mine is on api-eu, yours could be just api.librelink.io or whatever just look and see
    image

  6. open hte update name bgl node, here you can see what is the name of the entity and type that you have to create in helpers.

image

  1. once you got this you can add this and the trend entity to your dashboard in any card you like :

sorry if it’s messy, I don’t know bbcode or whatever the forum uses for formatting. Hope this helps!

Thanks for this. I am almost there.
Actually entities are not coming up in the card.

Update: helper created but output is 0.

Well another update: It’s working now. thank you so much for that. But still says 0 when I am using other one with trend. I have already create the helper etc but don’t know what’s wrong.


16-Jan/Update: Here you go:


And another screenshot here: image hosted at ImgBB — ImgBB (only 1 image allowed for new user)

Also, its not updating the value. Still the same as yesterday.


16-Jan/Update2: here you go: image hosted at ImgBB — ImgBB (it’s the same as yesterday 7.2, didn’t change.
And trend one is giving a value 0.

I am not able to make replies on this thread because of new user only reply for 3 times in a thread. Is there any other way to connect?


(Sorry, I am a new user so I have to update my reply each time, I can’t more then 3 reply on this thread)

It seems to me you skipped the step of creating the entity:

You have to go to settings:
image
then helpers:
image
then create helper:
image
and create the entity:

same for the other one for trend arrow (if you want the up/down arrows as well).
But you can skip that if you like.

If it’s something different please send a screenshot of the flow.

You cannot reply 3 times in a row, you should be fine when I reply.

Please take a screenshot of the flow in node red.
Then double click the first gray node and screenshot that. We’ll get there!

The trend arrow actually displays a number for corresponding trend. But you’ll have to figure that by watching and comparing to the official app. Weirdly it works differently now than before.

I Will check your screenshots in the morning and we’ll figure it out.

Did you create both entities?

The flow should run every minute (that’s the hosted screenshot, that’s an inject node, which starts the flow every minute).

Do you actually get any values? Do you get the glucose value at all?

If you observe the flow, you should see it sort of “blink” the nodes every minute, does it?

From the screenshots it all looks ok.

also, please do me a favour and actually reply.
It doesn’t work if you do 3 replies in a row,but if there’s my reply in-between, it should be fine.

Well, ignore the last edit. As new user restrictions have been lifted

here you go:

(it’s the same as yesterday 7.2, didn’t change.
And trend one is giving a value 0.

and that’s my helper:

That is very weird. Try clicking the square on the first node, that will trigger the flow manually. See if it changes value.

I assume you do have an active sensor now?

I am getting this in debug after the manual trigger.
image
Yes, the libre2 sensor is active right now.

Sorry I’m stumped…no idea.

It works for me. :pensive:

Did it work before? Was the value correct for that time? The 7.2 as in screenshot?

Is your linkup account ok?

I have no idea, but the error would indicate the object returned from API doesn’t have the properties that it does for me. That would be weird.