-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Question re this Dexcom API #7
Comments
Hey there! This is private API (same API the Dexcom shareous app uses). The reason why this isn't using the currently documented official API that Dexcom provides is there's a delay of 3 hours on fetching estimated glucose value (EVG) data. See these docs, which is sort of a nonstarter if you want to be notified quickly. With that said, because it is unofficial there's no uptime/breaking change guarantees, I've never had a problem with that (yet) though. As for the application_id, if I recall I found this after looking how other apps use it. I did some inspection of network requests last year and I believe this was the "blessed" application_id the Dexcom shareous app uses. So, basically we're spoofing the requests as if we're the real Dexcom app. This also may be useful: nightscout/share2nightscout-bridge#15 |
Thanks for the pointers. I'll check them out! |
@rajid Btw, I recently extracted this API into a library if you're still looking for a way to access this: https://github.com/aud/dexcom-share-api |
Yes, I think I can use this! I'll give it a try with my wife's Dexcom account and see how it goes. It would be good to allow my Fitbit CGM watchfaces the ability to read CGM data directly from Dexcom and thus not require Nightscout, for those using a Dexcom CGM. I'll let you know how it goes. Thanks a lot! |
I downloaded this library and have tried to figure out how to use it, but can't seem to make anything work. I'm sure it's just because I'm not familiar enough with npm, npx, javascript libraries, or package.json files. I've done a lot of Fitbit app/watchface development, but that's a whole environment already setup. Anyway, I was able to read through the code, see what calls you're doing, and make that method work for me as well, so I now have all of the knowledge I need to add direct dexcom BG information to my watchfaces, so Nightscout won't be needed. I'm sure this will help a large number of people who use Dexcom and don't have a Nightscout site, so I'm happy to add it. Thanks for the pointers to how to use the API, even I'm still struggling with how to make use of libraries! |
No problem! It should be easy as installing the library, or adding to the package.json of your project as a dependency, and importing. An example using a package manager is: package.json {
"devDependencies": {
"dexcom-share-api": "latest"
}
} main.js const {DexcomClient} = require("dexcom-share-api")
// server "eu" if outside of US, otherwise "us"
const client = new DexcomClient({username: "username", password: "password", server: "eu"})
async function main() {
const data = await client.getEstimatedGlucoseValues();
console.log(data);
}
main(); Usage: $ yarn && node main.js
yarn install v1.22.17
warning package.json: No license field
warning No license field
[1/4] 🔍 Resolving packages...
success Already up-to-date.
✨ Done in 0.03s.
[
{
mmol: 11.11,
mgdl: 200,
trend: 'singledown',
timestamp: 1641855251000
}
] Or, if you don't want to use a package manager you could always just source the script directly. For example: dexcom-share.js (this is a UMD bundle that is browser compatible) (function(o,a){typeof exports=="object"&&typeof module!="undefined"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(o=typeof globalThis!="undefined"?globalThis:o||self,a(o.DexcomApi={}))})(this,function(o){"use strict";function a(t){const e=t.match(/\d+/g);return e?parseInt(e[0]):null}function w(t){return+(t/18).toFixed(2)}var c;(function(t){t[t.DoubleUp=0]="DoubleUp",t[t.SingleUp=1]="SingleUp",t[t.FortyFiveUp=2]="FortyFiveUp",t[t.Flat=3]="Flat",t[t.FortyFiveDown=4]="FortyFiveDown",t[t.SingleDown=5]="SingleDown",t[t.DoubleDown=6]="DoubleDown"})(c||(c={}));const d=typeof window!="undefined"?window.fetch:require("isomorphic-fetch");class i{constructor({username:e,password:r,server:s}){if(Object.defineProperty(this,"username",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"password",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"server",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),typeof e=="undefined")throw new Error("Must provide username");if(typeof r=="undefined")throw new Error("Must provide password");if(typeof s=="undefined")throw new Error("Must provide server");if(!i.DEXCOM_SERVERS.includes(s))throw new Error(`Invalid server. Valid servers: ${i.DEXCOM_SERVERS.join(", ")}`);this.username=e,this.password=r,this.server=s}static get APPLICATION_ID(){return"d8665ade-9673-4e27-9ff6-92db4ce13d13"}static get DEXCOM_SERVERS(){return["eu","us"]}async getAccountId(){try{const e=await d(this.apiUrl("General/AuthenticatePublisherAccount"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({applicationId:i.APPLICATION_ID,accountName:this.username,password:this.password})}),r=await e.json();if(e.status!==200)throw new Error(`Dexcom server responded with status: ${e.status}, data: ${JSON.stringify(r)}`);return r}catch(e){throw new Error(`Request failed with error: ${e}`)}}async getSessionId(){try{const e=await this.getAccountId(),r=await d(this.apiUrl("General/LoginPublisherAccountById"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({applicationId:i.APPLICATION_ID,accountId:e,password:this.password})}),s=await r.json();if(r.status!==200)throw new Error(`Dexcom server responded with status: ${r.status}, data: ${JSON.stringify(s)}`);return s}catch(e){throw new Error(`Request failed with error: ${e}`)}}async getEstimatedGlucoseValues({minutes:e,maxCount:r}={minutes:1440,maxCount:1}){try{const s=await this.getSessionId(),l=await d(this.apiUrl("Publisher/ReadPublisherLatestGlucoseValues"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({maxCount:r,minutes:e,sessionId:s})}),h=await l.json();if(l.status!==200)throw new Error(`Dexcom server responded with status: ${l.status}, data: ${JSON.stringify(h)}`);return h.map(n=>{let u=n.Trend;return typeof u=="number"&&(u=c[u-1]),{mmol:w(n.Value),mgdl:n.Value,trend:u.toLowerCase(),timestamp:new Date(a(n.WT)).getTime()}})}catch(s){throw new Error(`Request failed with error: ${s}`)}}apiUrl(e){let r;switch(this.server){case"us":r="share2.dexcom.com";break;case"eu":r="shareous1.dexcom.com";break}return`https://${r}/ShareWebServices/Services/${e}`}}o.DexcomClient=i,Object.defineProperty(o,"__esModule",{value:!0}),o[Symbol.toStringTag]="Module"}); Usage: async function main() {
const client = new DexcomApi.DexcomClient({username: "username", password: "password", server: "eu"});
const data = await client.getEstimatedGlucoseValues();
console.log(data);
}
main(); In any case, I'm glad this has been helpful so far. I know the experience with Nightscout so I'm happy this is helping simplify things. |
I have a question, I hope you don't mind. I've been looking at adding dexcom reading to some of my Fitbit watchfaces, which currently read from Nightscout. Looking at their current API documents, I don't see anything like the API you're using here. The currently documented one uses oauth2 and quite a bit more complicated, requiring a "redirect_uri" where the authorization_code is passed there after the user logs into a Dexcom originated login page. Then, the authorization_code has to be exchanged for a session token within 60 seconds. The only way to really support this would be to have a server which handles all of the tokens, etc. I would rather use the API you're using, which is far less complicated and easier to implement to, for a watch/phone client.
Does the API you're using still exist and is currently supported? Can you point me to some documentation? Really, I think your code is easily followed, but I don't know where you're getting the "Application_id". The new oauth2 API doesn't have anything like this.
Thanks for any pointers you can provide!
The text was updated successfully, but these errors were encountered: