Dexcom + Alexa + Node Red

UPDATE: the logic in the js function is not quite right yet. I will post the correct version after further testing. I’ve messed up something in the if else if statement.

I wanted to have Alexa announce Dexcom G6 Blood Glucose level on-demand and when high or low.

The on-demand announcement does not require a Skill and uses only the node-red-contrib-amazon-echo pallette.

Make a “fake” light and discover it in the Alexa app. Create a routine to invoke the on function of the light. I suppose one could say: “Alexa, turn on Dexcom”. But “Alexa, what’s my blood sugar?” sounds better.

The fake light sends the “on” message to retrieve the current bg value and sends that to the notify Alexa. There is also a delay to send the light off command back to Alexa, so she doesn’t think that the light is already on, or always on.

That was the easy part.

Having Alexa announce on HA-State Change node got a bit more complicated.

There are essentially 5 combinations: normal, first high, sustained high, first low, and sustained low.

Normal bg values are ignored.

The difference between first and sustained is based on bg value being high/low and for a duration (2 hours high / 20 minutes low). The timer is invaluable to suppress further announcements AFTER the first announcement. I don’t need to know every 5 minutes that I’ve got a blood glucose event! Just a reminder to check again after taking corrective action(s).

Obviously, after a correction, a duration of time passes before desiring to know current bg value.

The other conditional is home vs not_home for my person in HA. No need to announce anything if I’m not home to hear.

I’m sure this isn’t finished yet, and I will continue to tweak as necessary.

But I wanted to share, because I hadn’t found anything quite like this when I was searching.

[{"id":"c4bca5dce2cfa066","type":"subflow","name":"Glucose Logic","info":"","category":"","in":[{"x":60,"y":90,"wires":[{"id":"fe09567a3d979fdb"}]}],"out":[{"x":540,"y":90,"wires":[{"id":"60516074ad6d4c12","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"fe09567a3d979fdb","type":"api-current-state","z":"c4bca5dce2cfa066","name":"Glucose Value","server":"19e06289.dada3d","version":2,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.dexcom_glucose_value","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":210,"y":90,"wires":[["60516074ad6d4c12"]]},{"id":"60516074ad6d4c12","type":"function","z":"c4bca5dce2cfa066","name":"high or low?","func":"var bg = msg.data.state;\n\nif (bg < 5.0) {\n    msg.bg = {\n        \"bg_state\" : \"low\",\n        \"bg\" : bg\n    }\n    return msg;\n}\n\nif (bg >= 11.0) {\n    msg.bg = {\n        \"bg_state\" : \"high\",\n        \"bg\" : bg\n    }\n    return msg;\n}\n\nif (bg >= 5.0 && bg < 11.0) {\n    msg.bg = {\n        \"bg_state\" : \"normal\",\n        \"bg\" : bg\n    }\n    return msg;\n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":90,"wires":[[]]},{"id":"a2c98a6ea52a48d9","type":"tab","label":"Dexcom","disabled":false,"info":""},{"id":"5604e44f3e298273","type":"group","z":"a2c98a6ea52a48d9","name":"Announce BG Events","style":{"fill":"#bfc7d7","label":true,"color":"#ff0000"},"nodes":["f90b6cc0512181a7","0e4a27e861732290","b273b80afdf1c009","dbd7b0bec2dd3fde","494e60774fa68223","90282257ae7a7348","21e755caad8eeffe"],"x":64,"y":394,"w":982,"h":247},{"id":"ed8b2cf5deecfb75","type":"group","z":"a2c98a6ea52a48d9","name":"Alexa Dexcom Light Routine","style":{"fill":"#bfdbef","label":true,"color":"#3f93cf"},"nodes":["9b7f264716a21ec1","a6e38bab64360584","75d3404140239634","71a7b969e91fa6b4","28187768adc0889c","763e40bed6358cc1","c48a65c2e37fa9c0","b5c5dec1ccaf0f3a"],"x":64,"y":49,"w":1212,"h":172},{"id":"aaa4a57205bd6a61","type":"api-call-service","z":"a2c98a6ea52a48d9","name":"Alexa Announce","server":"19e06289.dada3d","version":3,"debugenabled":false,"service_domain":"notify","service":"alexa_media_kitchen","entityId":"","data":"{\"data\":{\"type\":\"announce\"},\"message\":\"Michael's blood glucose is {{bg.bg}}, which is {{bg.bg_state}}. {{bg.message}}\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":470,"y":300,"wires":[[]]},{"id":"a6e38bab64360584","type":"amazon-echo-device","z":"a2c98a6ea52a48d9","g":"ed8b2cf5deecfb75","name":"Dexcom","topic":"","x":350,"y":90,"wires":[["75d3404140239634"]]},{"id":"9b7f264716a21ec1","type":"link in","z":"a2c98a6ea52a48d9","g":"ed8b2cf5deecfb75","name":"Alexa talks to HAL","links":["be564bd7.ec5368"],"x":180,"y":90,"wires":[["a6e38bab64360584"]],"l":true},{"id":"75d3404140239634","type":"switch","z":"a2c98a6ea52a48d9","g":"ed8b2cf5deecfb75","name":"retrieve bg value","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":550,"y":90,"wires":[["71a7b969e91fa6b4","28187768adc0889c"]]},{"id":"71a7b969e91fa6b4","type":"delay","z":"a2c98a6ea52a48d9","g":"ed8b2cf5deecfb75","name":"turn off in Alexa","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"x":550,"y":180,"wires":[["763e40bed6358cc1"]]},{"id":"763e40bed6358cc1","type":"function","z":"a2c98a6ea52a48d9","g":"ed8b2cf5deecfb75","name":"Dexcom Alexa NodeID","func":"msg.nodeid=\"a6e38bab64360584\";\n\nvar alexa_id = msg.nodeid;\n\nmsg.payload = {\n    on: false,\n    nodeid: alexa_id\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":810,"y":180,"wires":[["b5c5dec1ccaf0f3a"]]},{"id":"c48a65c2e37fa9c0","type":"link out","z":"a2c98a6ea52a48d9","g":"ed8b2cf5deecfb75","name":"Dexcom Announce","links":["ca36204d9e4fe957"],"x":1160,"y":90,"wires":[],"l":true},{"id":"ca36204d9e4fe957","type":"link in","z":"a2c98a6ea52a48d9","name":"Dexcom Announce","links":["c48a65c2e37fa9c0","95463530d5b57b3e","21e755caad8eeffe"],"x":210,"y":300,"wires":[["aaa4a57205bd6a61"]],"l":true},{"id":"b5c5dec1ccaf0f3a","type":"link out","z":"a2c98a6ea52a48d9","g":"ed8b2cf5deecfb75","name":"Dexcom \"light\" OFF to Alexa","links":["6728bba2.6521c4"],"x":1130,"y":180,"wires":[],"l":true},{"id":"f90b6cc0512181a7","type":"trigger-state","z":"a2c98a6ea52a48d9","g":"5604e44f3e298273","name":"Dexcom State","server":"19e06289.dada3d","version":0,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"sensor.dexcom_glucose_value","entityidfiltertype":"exact","debugenabled":false,"constraints":[{"targetType":"entity_id","targetValue":"person.michael","propertyType":"current_state","comparatorType":"is","comparatorValueDatatype":"str","comparatorValue":"home","propertyValue":"new_state.state"}],"outputs":4,"customoutputs":[{"messageType":"payload","messageValue":"on","messageValueType":"str","comparatorPropertyType":"current_state","comparatorType":">","comparatorValue":"11.0","comparatorValueDataType":"num","comparatorPropertyValue":"new_state.state"},{"messageType":"payload","messageValue":"on","messageValueType":"str","comparatorPropertyType":"current_state","comparatorType":"<","comparatorValue":"5","comparatorValueDataType":"num","comparatorPropertyValue":"new_state.state"}],"outputinitially":true,"state_type":"str","x":170,"y":450,"wires":[[],[],["0e4a27e861732290","b273b80afdf1c009"],["0e4a27e861732290","dbd7b0bec2dd3fde"]],"outputLabels":["at home","","high bg","low bg"]},{"id":"494e60774fa68223","type":"function","z":"a2c98a6ea52a48d9","g":"5604e44f3e298273","name":"first high or low?","func":"var old_state = msg.data.event.old_state.state;\nvar new_state = msg.data.event.new_state.state;\nvar bg = new_state;\n\nvar high_timer = flow.get(\"high_timer\");\nvar low_timer = flow.get(\"low_timer\");\n\nmsg.high_timer_status = high_timer;\nmsg.low_timer_status = low_timer;\n\n\nif ((old_state < 11) && (new_state >= 11) && (high_timer == \"on\")){\n    msg.bg = {\n        \"bg\" : bg,\n        \"bg_state\" : \"high\",\n        \"message\" : \"This is a new high event.\"\n    }\n    return msg;\n}\n\nelse if ((old_state >= 11) && (new_state >= 11) && (high_timer == \"off\")){\n    msg.bg = {\n        \"bg\" : bg,\n        \"bg_state\" : \"high\",\n        \"message\" : \"This is a sustained high event.\"\n    }\n    return msg;\n}\n\nelse if ((old_state >= 5) && (new_state < 5) && (low_timer == \"on\")){\n    msg.bg = {\n        \"bg\" : bg,\n        \"bg_state\" : \"low\",\n        \"message\" : \"This is a new low event.\"\n    }\n    return msg;\n}\n\nelse if ((old_state < 5) && (new_state < 5) && (low_timer == \"off\")){\n    msg.bg = {\n        \"bg\" : bg,\n        \"bg_state\" : \"low\",\n        \"message\" : \"This is a sustained low event.\"\n    }\n    return msg;\n}\n\nelse {\n    msg.bg = {\n        \"bg\" : bg,\n        \"bg_state\" : \"normal\",\n        \"message\" : \"Blood glucose is normal.\"\n    }\n    return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":690,"y":600,"wires":[["21e755caad8eeffe"]],"outputLabels":["high bg"]},{"id":"95463530d5b57b3e","type":"link out","z":"a2c98a6ea52a48d9","name":"Dexcom Announce","links":["ca36204d9e4fe957"],"x":780,"y":960,"wires":[],"l":true},{"id":"28187768adc0889c","type":"subflow:c4bca5dce2cfa066","z":"a2c98a6ea52a48d9","g":"ed8b2cf5deecfb75","name":"Glucose Logic","env":[],"x":820,"y":90,"wires":[["c48a65c2e37fa9c0"]]},{"id":"21e755caad8eeffe","type":"link out","z":"a2c98a6ea52a48d9","g":"5604e44f3e298273","name":"Dexcom Announce","links":["ca36204d9e4fe957"],"x":930,"y":600,"wires":[],"l":true},{"id":"b273b80afdf1c009","type":"eztimer","z":"a2c98a6ea52a48d9","g":"5604e44f3e298273","name":"high_bg","debug":false,"autoname":" + 02:00:00","tag":"bg_timer","topic":"high_timer","suspended":false,"sendEventsOnSuspend":false,"latLongSource":"haZone","latLongHaZone":"zone.home","lat":"your_lat_here","lon":"your_long_here","timerType":"1","startupMessage":false,"ontype":"9","ontimesun":"dawn","ontimetod":"17:00","onpropertytype":"msg","onproperty":"payload","onvaluetype":"num","onvalue":1,"onoffset":0,"onrandomoffset":0,"onsuppressrepeats":true,"offtype":"3","offtimesun":"dusk","offtimetod":"dusk","offduration":"02:00:00","offpropertytype":"msg","offproperty":"payload","offvaluetype":"num","offvalue":0,"offoffset":0,"offrandomoffset":0,"offsuppressrepeats":false,"resend":false,"resendInterval":"0s","mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"sat":true,"sun":true,"x":450,"y":450,"wires":[["90282257ae7a7348"]]},{"id":"dbd7b0bec2dd3fde","type":"eztimer","z":"a2c98a6ea52a48d9","g":"5604e44f3e298273","name":"low_bg","debug":false,"autoname":" + 00:20:00","tag":"low_bg","topic":"low_timer","suspended":false,"sendEventsOnSuspend":false,"latLongSource":"haZone","latLongHaZone":"zone.home","lat":"your_lat_here","lon":"your_lon_here","timerType":"1","startupMessage":false,"ontype":"9","ontimesun":"dawn","ontimetod":"17:00","onpropertytype":"msg","onproperty":"payload","onvaluetype":"num","onvalue":1,"onoffset":0,"onrandomoffset":0,"onsuppressrepeats":true,"offtype":"3","offtimesun":"dusk","offtimetod":"dusk","offduration":"00:20:00","offpropertytype":"msg","offproperty":"payload","offvaluetype":"num","offvalue":0,"offoffset":0,"offrandomoffset":0,"offsuppressrepeats":false,"resend":false,"resendInterval":"0s","mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"sat":true,"sun":true,"x":450,"y":510,"wires":[["90282257ae7a7348"]]},{"id":"35d709d445182dce","type":"debug","z":"a2c98a6ea52a48d9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":560,"y":810,"wires":[]},{"id":"edc649f6362ab85e","type":"function","z":"a2c98a6ea52a48d9","name":"testing timer flow set","func":"var high_timer_status = flow.get(\"high_timer\");\nvar low_timer_status = flow.get(\"low_timer\");\n\nmsg.high_timer_status = high_timer_status;\nmsg.low_timer_status = low_timer_status;\n\n    return msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":810,"wires":[["35d709d445182dce"]]},{"id":"54c03a01cd72bfd8","type":"inject","z":"a2c98a6ea52a48d9","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":810,"wires":[["edc649f6362ab85e"]]},{"id":"90282257ae7a7348","type":"function","z":"a2c98a6ea52a48d9","g":"5604e44f3e298273","name":"set bg_timer status","func":"var topic = msg.topic;\nvar timer = msg.payload;\n\nif ((topic == \"high_timer\") && (timer == 1)){\n    flow.set(\"high_timer\",\"on\");\n    \n    msg = {\n     \"timer\" : \"high bg timer on\",\n     \"_payload\" : \"on\"\n    }\n    \n    return msg;\n}\n\nelse if ((topic == \"high_timer\") && (timer == 0)){\n    flow.set(\"high_timer\",\"off\");\n    \n    msg = {\n     \"timer\" : \"high bg timer off\",\n     \"_payload\" : \"off\"\n    }\n\n    \n    return msg;\n}\n\nelse if ((topic == \"low_timer\") && (timer == 1)){\n    flow.set(\"low_timer\",\"on\");\n    \n    msg = {\n     \"timer\" : \"low bg timer on\",\n     \"_payload\" : \"on\"\n    }\n    \n    return msg;\n}\n\nelse if ((topic == \"low_timer\") && (timer == 0)){\n    flow.set(\"low_timer\",\"off\");\n    \n    msg = {\n     \"timer\" : \"low bg timer on\",\n     \"_payload\" : \"off\"\n    }\n    \n    return msg;\n}","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\n\nflow.set(\"high_timer\",\"off\");\nflow.set(\"low_timer\",\"off\");","finalize":"","libs":[],"x":690,"y":480,"wires":[[]]},{"id":"0e4a27e861732290","type":"delay","z":"a2c98a6ea52a48d9","g":"5604e44f3e298273","name":"delay 3s","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"x":450,"y":600,"wires":[["494e60774fa68223"]]},{"id":"19e06289.dada3d","type":"server","name":"Home Assistant","version":1,"legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]
3 Likes

Holy shit that’s amazing. I’m very envious with my Medtronic pump :wink:

I just stopped using my Medtronic 630G, and switched to Dexcom G6 & Ypsomed.

Which Medtronic do you use? CGM? There may be a way to modify this and make it work with Medtronic.

I’m on 640g (so, shitty Enlite sensors) rn but I’m probably getting a 780g soon. I know Dexcom has an official HA integration and I highly doubt something like that is available for Medtronic but I’ll look around. Your post is an inspiration :slight_smile:

Does that system have any type of App or cloud share? If so, there must be a method of http get on the api to obtain a bg value. ?? Don’t necessarily need a pre-fab HA integration. Just an http query to Medtronic cloud.

Just a thought.

Yeah, I use Tidepool to upload and see data, so 3rd-party stuff is definitely possible. But I’m not a developer at all, the bes I can do is modify and maybe link together someone else’s scripts. Thanks!

Does your Medtronic + Enlite have real time sharing?

I don’t think so :-/ Maybe, I have to look into it.

i was using sugarmate to grab json info but since they are back up, they are no longer providing json data. i then was using home assistant to pull the data and now that is broke. I then resorted to using xdrip to upload data to a influxDB however it does not always upload the data and then the cycle time for the upload is slow. I am looking for a better way so i can get my alert system going again. idk what else to do.

I am also pissed at Sugarmate for taking the JSON API away. I am letting them know that this makes Sugarmate almost useless for me.

The Dexcom integration may be up again soon:

Ont thing I am doing is to explore making a BLE receiver to scrape the data directly from the sensor/transmitter. This would have the potential of eliminating all third party reliances. But BLE is a new technology for me to develop anything. If you or anyone interested in this subject wants to help, I am planning to use the HC-05 BLE module on Arduino.

The issue with the Dexcom integration is that Dexcom, unannounced, modified their API and broke the responses all the apps were expecting. This appears to have only affected non-USA accounts.

Check out this thread:

There is a solution near the bottom, for those who use HASS OS.

Do I need to be using an xdrip pump to do this?

yeah, that is what i did. now the HA integration is working again in the lastest update but need to find something that was just as good as the json data from sugarmate was. nothing is as reliable as that was. HA integration updates 2 minutes after dexcom actually updates. I put in a feature request to poll the data more often. like 30 seconds to a minute. i know that dex updates every 5 but if HA polls data 2 or 3 minutes after dexcom, it is useless at certain times.

https://community.home-assistant.io/t/dexcom-how-often-it-updates

This is my feature request that I put. if it would poll every 30 seconds that would be way more helpfull

Unclear- do I need to be using the xdrip pump to get my BG data?

Right now i am using home assistant to populate the data in node-red.

the other option is to use xdrip to put data into a influxDB and then use node-red to pull that data. either way is not perfect. the influxDB sometimes does not update the trending arrow and I am unsure why it does that. the HA way, just doesn’t poll the data as often as i would like.

OK, let me ask the question another way. How are you using Xdrip to get your BG data from Dexcom?

i selected dexcom share as the source. i put the login and password and it grabs the info from dexcom. I am using one of the nightlies. the one i am using is from the 8th of december. I actually have it running in a android emulator on one of my pcs that run 24/7

ok, i now have dexcom on my home assistant install doing a scan interval ever 30 seconds instead of the 180seconds that were originally set on the home assistant integration/

I do want to find a way to pull the data directly from dexcom and not rely on home assistant to do it but for now. i am happy with how this works. (i hope)