forked from nightscout/minimed-connect-to-nightscout
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move CL->NS data transformation into its own module
- Loading branch information
Showing
3 changed files
with
112 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/* jshint node: true */ | ||
"use strict"; | ||
|
||
var logger = require('./logger'); | ||
|
||
var STALE_DATA_THRESHOLD_MINUTES = 20; | ||
var PUMP_STATUS_ENTRY_TYPE = 'pump_status'; | ||
var SENSOR_GLUCOSE_ENTRY_TYPE = 'sgv'; | ||
|
||
function parsePumpTime(pumpTimeString, offset) { | ||
return Date.parse(pumpTimeString + ' ' + offset); | ||
} | ||
|
||
function addTimeToEntry(timestamp, entry) { | ||
entry['date'] = timestamp; | ||
entry['dateString'] = new Date(timestamp).toISOString(); | ||
return entry; | ||
} | ||
|
||
var guessPumpOffset = (function() { | ||
var lastGuess; | ||
|
||
// From my observations, sMedicalDeviceTime is advanced by the server even when the app is | ||
// not reporting data or the pump is not connected, so its difference from server time is | ||
// always close to a whole number of hours, and can be used to guess the pump's timezone: | ||
// https://gist.github.com/mddub/f673570e6427c93784bf | ||
return function(data) { | ||
var pumpTimeAsIfUTC = Date.parse(data['sMedicalDeviceTime'] + ' +0'); | ||
var serverTimeUTC = data['currentServerTime']; | ||
var hours = Math.round((pumpTimeAsIfUTC - serverTimeUTC) / (60*60*1000)); | ||
var offset = (hours >= 0 ? '+' : '-') + (Math.abs(hours) < 10 ? '0' : '') + Math.abs(hours) + '00'; | ||
if (offset !== lastGuess) { | ||
logger.log('Guessed pump timezone ' + offset + ' (pump time: "' + data['sMedicalDeviceTime'] + '"; server time: ' + new Date(data['currentServerTime']) + ')'); | ||
} | ||
lastGuess = offset; | ||
return offset; | ||
}; | ||
})(); | ||
|
||
function pumpStatusEntry(data) { | ||
var entry = {'type': PUMP_STATUS_ENTRY_TYPE}; | ||
|
||
[ | ||
'conduitBatteryLevel', | ||
'conduitInRange', | ||
'conduitMedicalDeviceInRange', | ||
'reservoirLevelPercent', | ||
'reservoirAmount', | ||
'medicalDeviceBatteryLevelPercent' | ||
].forEach(function(key) { | ||
if(data[key] !== undefined) { | ||
entry[key] = data[key]; | ||
} | ||
}); | ||
|
||
if(data['activeInsulin'] && data['activeInsulin']['amount'] >= 0) { | ||
entry['activeInsulin'] = data['activeInsulin']['amount']; | ||
} | ||
|
||
return addTimeToEntry(data['lastMedicalDeviceDataUpdateServerTime'], entry); | ||
} | ||
|
||
function sgvEntries(data) { | ||
var offset = guessPumpOffset(data); | ||
|
||
if(data['sgs'] && data['sgs'].length) { | ||
return data['sgs'].filter(function(entry) { | ||
return entry['kind'] === 'SG' && entry['sg'] !== 0; | ||
}).map(function(sgv) { | ||
return addTimeToEntry( | ||
parsePumpTime(sgv['datetime'], offset), | ||
{ | ||
'type': SENSOR_GLUCOSE_ENTRY_TYPE, | ||
'sgv': sgv['sg'], | ||
} | ||
); | ||
}); | ||
} else { | ||
return []; | ||
} | ||
} | ||
|
||
var transform = module.exports = function(data, sgvLimit) { | ||
var recency = (data['currentServerTime'] - data['lastMedicalDeviceDataUpdateServerTime']) / (60 * 1000); | ||
if (recency > STALE_DATA_THRESHOLD_MINUTES) { | ||
logger.log('Stale CareLink data: ' + recency.toFixed(2) + ' minutes old'); | ||
return []; | ||
} | ||
|
||
if (sgvLimit === undefined) { | ||
sgvLimit = Infinity; | ||
} | ||
|
||
var entries = []; | ||
|
||
entries.push(pumpStatusEntry(data)); | ||
|
||
var sgvs = sgvEntries(data); | ||
// TODO: this assumes sgvs are ordered by date ascending | ||
for(var i = Math.max(0, sgvs.length - sgvLimit); i < sgvs.length; i++) { | ||
entries.push(sgvs[i]); | ||
} | ||
|
||
entries.forEach(function(entry) { | ||
entry['device'] = 'MiniMed Connect ' + data['medicalDeviceFamily'] + ' ' + data['medicalDeviceSerialNumber']; | ||
}); | ||
|
||
return entries; | ||
}; |