Merge pull request #1 from MilosKozak/master

merge in milos master
This commit is contained in:
AdrianLxM 2016-11-02 15:04:14 +01:00 committed by GitHub
commit 7bcdf36ca0
263 changed files with 26193 additions and 280 deletions

View file

@ -3,20 +3,16 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="distributionType" value="LOCAL" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="C:\Program Files\Android\Android Studio\gradle\gradle-2.14.1" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="myModules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>

View file

@ -1,6 +1,7 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AndroidLintLabelFor" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintRtlHardcoded" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintUselessParent" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintValidFragment" enabled="false" level="ERROR" enabled_by_default="false" />

View file

@ -37,26 +37,10 @@
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>1.8</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

6
README.md Normal file
View file

@ -0,0 +1,6 @@
# AndroidAPS
* Check the wiki: https://github.com/MilosKozak/AndroidAPS/wiki
* Everyone whos been looping with AndroidAPS needs to fill out the form after 3 days of looping https://docs.google.com/forms/d/14KcMjlINPMJHVt28MDRupa4sz4DDIooI4SrW0P3HSN8/viewform?c=0&w=1
[![Gitter](https://badges.gitter.im/MilosKozak/AndroidAPS.svg)](https://gitter.im/MilosKozak/AndroidAPS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

View file

@ -1,4 +1,19 @@
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
}
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
repositories {
maven { url 'https://maven.fabric.io/public' }
}
android {
compileSdkVersion 23
@ -8,8 +23,11 @@ android {
applicationId "info.nightscout.androidaps"
minSdkVersion 21
targetSdkVersion 23
versionCode 1
versionName "1.0"
versionCode 1019
versionName "1.0.19"
}
lintOptions {
disable 'MissingTranslation'
}
buildTypes {
release {
@ -17,12 +35,64 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
full {
buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "CLOSEDLOOP", "true"
buildConfigField "int", "MAXBOLUS", "17"
}
fullteenage {
buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "CLOSEDLOOP", "true"
buildConfigField "int", "MAXBOLUS", "10"
}
fullchild {
buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "CLOSEDLOOP", "true"
buildConfigField "int", "MAXBOLUS", "5"
}
danarcontrol {
buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "int", "MAXBOLUS", "17"
}
careportal {
buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "int", "MAXBOLUS", "17"
}
openloop {
buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "int", "MAXBOLUS", "17"
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile('com.crashlytics.sdk.android:crashlytics:2.5.7@aar') {
transitive = true;
}
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:support-v4:23.4.0'
compile 'com.android.support:cardview-v7:23.0.+'
compile 'com.android.support:recyclerview-v7:23.0.+'}
compile 'com.android.support:cardview-v7:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.android.support:gridlayout-v7:23.4.0'
compile 'com.wdullaer:materialdatetimepicker:2.3.0'
compile 'com.squareup:otto:1.3.7'
compile 'com.j256.ormlite:ormlite-core:4.46'
compile 'com.j256.ormlite:ormlite-android:4.46'
compile 'com.github.tony19:logback-android-classic:1.1.1-4'
compile 'org.slf4j:slf4j-api:1.7.12'
compile 'com.jjoe64:graphview:4.0.1'
compile 'com.eclipsesource.j2v8:j2v8:3.1.6@aar'
compile 'com.joanzapata.iconify:android-iconify-fontawesome:2.1.1'
testCompile 'junit:junit:4.12'
}

3
app/fabric.properties Normal file
View file

@ -0,0 +1,3 @@
#Contains API Secret used to validate your application. Commit to internal source control; avoid making secret public.
#Sun Jul 03 14:29:18 CEST 2016
apiSecret=93ce8127162f8349a34eb7cd0756fe123ca8e971c50151906ea06ef38133cc34

View file

@ -15,3 +15,12 @@
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-dontwarn android.support.**
-keep class !android.support.v7.internal.view.menu.**,android.support.** {*;}
-ignorewarnings
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-keep public class * extends android.support.v4.** {*;}
-keep public class * extends android.app.Fragment

View file

@ -2,7 +2,23 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="info.nightscout.androidaps">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.SEND_MMS" />
<!-- To receive data from xdrip. -->
<uses-permission android:name="com.eveningoutpost.dexdrip.permissions.RECEIVE_BG_ESTIMATE" />
<application
android:name=".MainApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@ -13,8 +29,60 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".PreferencesActivity" />
<activity android:name=".AgreementActivity" />
<activity android:name=".plugins.DanaR.History.DanaRHistoryActivity" />
<activity android:name=".plugins.Overview.activities.QuickWizardListActivity">
<intent-filter>
<action android:name="info.nightscout.androidaps.plugins.Overview.activities.QuickWizardListActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver
android:name=".receivers.DataReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<!-- Receiver from NSClient -->
<action android:name="info.nightscout.client.NEW_SGV" />
<action android:name="info.nightscout.client.NEW_TREATMENT" />
<action android:name="info.nightscout.client.CHANGED_TREATMENT" />
<action android:name="info.nightscout.client.REMOVED_TREATMENT" />
<action android:name="info.nightscout.client.NEW_PROFILE" />
<action android:name="info.nightscout.client.NEW_STATUS" />
<action android:name="info.nightscout.client.NEW_MBG" />
<action android:name="info.nightscout.client.NEW_DEVICESTATUS" />
<action android:name="info.nightscout.client.NEW_CAL" />
<!-- Receive new SMS messages -->
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<!-- Receiver from xDrip -->
<action android:name="com.eveningoutpost.dexdrip.BgEstimate" />
<!-- Auto start -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<!-- Receiver keepalive, scheduled every 30 min -->
<receiver android:name=".receivers.KeepAliveReceiver" />
<!-- Service processing incomming data -->
<service
android:name=".Services.DataService"
android:exported="false" />
<!-- Service showing alert on screen -->
<service
android:name=".plugins.DanaR.Services.ExecutionService"
android:enabled="true"
android:exported="false" />
<meta-data
android:name="io.fabric.ApiKey"
android:value="59d462666c664c57b29e1d79ea123e01f8057cfa" />
</application>
</manifest>

View file

@ -0,0 +1,316 @@
/*
Determine Basal
Released under MIT license. See the accompanying LICENSE.txt file for
full terms and conditions
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, offline, meal_data, setTempBasal) {
var rT = { //short for requestedTemp
};
if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') {
rT.error ='Error: could not get current basal rate';
return rT;
}
var bg = glucose_status.glucose;
if (bg < 30) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose
rT.error = "CGM is calibrating or in ??? state";
return rT;
}
var max_iob = profile.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver
// if target_bg is set, great. otherwise, if min and max are set, then set target to their average
var target_bg;
if (typeof profile.target_bg !== 'undefined') {
target_bg = profile.target_bg;
} else {
if (typeof profile.min_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') {
target_bg = (profile.min_bg + profile.max_bg) / 2;
} else {
rT.error ='Error: could not determine target_bg';
return rT;
}
}
if (typeof iob_data === 'undefined' ) {
rT.error ='Error: iob_data undefined';
return rT;
}
if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' || typeof iob_data.activity === 'undefined') {
rT.error ='Error: iob_data missing some property';
return rT;
}
var tick;
if (glucose_status.delta >= 0) {
tick = "+" + glucose_status.delta;
} else {
tick = glucose_status.delta;
}
var minDelta = Math.min(glucose_status.delta, glucose_status.avgdelta);
//var maxDelta = Math.max(glucose_status.delta, glucose_status.avgdelta);
//calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone
var bgi = Math.round(( -iob_data.activity * profile.sens * 5 )*100)/100;
// project positive deviations for 15 minutes
var deviation = Math.round( 15 / 5 * ( glucose_status.avgdelta - bgi ) );
// project negative deviations for 30 minutes
if (deviation < 0) {
deviation = Math.round( 30 / 5 * ( glucose_status.avgdelta - bgi ) );
}
//console.log("Avg.Delta: " + glucose_status.avgdelta.toFixed(1) + ", BGI: " + bgi.toFixed(1) + " 15m activity projection: " + deviation.toFixed(0));
// calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity
var naive_eventualBG = Math.round( bg - (iob_data.iob * profile.sens) );
// and adjust it for the deviation above
var eventualBG = naive_eventualBG + deviation;
// calculate what portion of that is due to bolussnooze
var bolusContrib = iob_data.bolussnooze * profile.sens;
// and add it back in to get snoozeBG, plus another 50% to avoid low-temping at mealtime
var naive_snoozeBG = Math.round( naive_eventualBG + 1.5 * bolusContrib );
// adjust that for deviation like we did eventualBG
var snoozeBG = naive_snoozeBG + deviation;
//console.log("BG: " + bg +"(" + tick + ","+glucose_status.avgdelta.toFixed(1)+")"+ " -> " + eventualBG + "-" + snoozeBG + " (Unadjusted: " + naive_eventualBG + "-" + naive_snoozeBG + "), BGI: " + bgi);
var expectedDelta = Math.round(( bgi + ( target_bg - eventualBG ) / ( profile.dia * 60 / 5 ) )*10)/10;
//console.log("expectedDelta: " + expectedDelta);
if (typeof eventualBG === 'undefined' || isNaN(eventualBG)) {
rT.error ='Error: could not calculate eventualBG';
return rT;
}
// min_bg of 90 -> threshold of 70, 110 -> 80, and 130 -> 90
var threshold = profile.min_bg - 0.5*(profile.min_bg-50);
rT = {
'temp': 'absolute'
, 'bg': bg
, 'tick': tick
, 'eventualBG': eventualBG
, 'snoozeBG': snoozeBG
};
var basaliob;
if (iob_data.basaliob) { basaliob = iob_data.basaliob; }
else { basaliob = iob_data.iob - iob_data.bolussnooze; }
// allow meal assist to run when carbs are just barely covered
if (minDelta > Math.max(3, bgi) && ( (meal_data.carbs > 0 && (1.1 * meal_data.carbs/profile.carb_ratio > meal_data.boluses + basaliob)) || ( deviation > 25 && minDelta > 7 ) ) ) {
// ignore all covered IOB, and just set eventualBG to the current bg
eventualBG = Math.max(bg,eventualBG) + deviation;
rT.eventualBG = eventualBG;
profile.min_bg = 80;
target_bg = (profile.min_bg + profile.max_bg) / 2;
expectedDelta = Math.round(( bgi + ( target_bg - eventualBG ) / ( profile.dia * 60 / 5 ) )*10)/10;
rT.mealAssist = "On: Carbs: " + meal_data.carbs + " Boluses: " + meal_data.boluses + " Target: " + target_bg + " Deviation: " + deviation + " BGI: " + bgi;
} else {
rT.mealAssist = "Off: Carbs: " + meal_data.carbs + " Boluses: " + meal_data.boluses + " Target: " + target_bg + " Deviation: " + deviation + " BGI: " + bgi;
}
if (bg < threshold) { // low glucose suspend mode: BG is < ~80
rT.reason = "BG " + bg + "<" + threshold;
if ((glucose_status.delta <= 0 && glucose_status.avgdelta <= 0) || (glucose_status.delta < expectedDelta && glucose_status.avgdelta < expectedDelta)) {
// BG is still falling / rising slower than predicted
return setTempBasal(0, 30, profile, rT, offline);
}
if (glucose_status.delta > glucose_status.avgdelta) {
rT.reason += ", delta " + glucose_status.delta + ">0";
} else {
rT.reason += ", avg delta " + glucose_status.avgdelta.toFixed(2) + ">0";
}
if (currenttemp.rate > profile.current_basal) { // if a high-temp is running
rT.reason += ", cancel high temp";
return setTempBasal(0, 0, profile, rT, offline); // cancel high temp
} else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB
rT.reason += ", cancel low temp";
return setTempBasal(0, 0, profile, rT, offline); // cancel low temp
}
rT.reason += "; no high-temp to cancel";
return rT;
}
if (eventualBG < profile.min_bg) { // if eventual BG is below target:
if (rT.mealAssist.indexOf("On") == 0) {
rT.reason = "Meal assist: " + meal_data.carbs + "g, " + meal_data.boluses + "U";
} else {
rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg;
// if 5m or 15m avg BG is rising faster than expected delta
if (minDelta > expectedDelta && minDelta > 0) {
if (glucose_status.delta > glucose_status.avgdelta) {
rT.reason += ", but Delta " + tick + " > Exp. Delta " + expectedDelta;
} else {
rT.reason += ", but Avg. Delta " + glucose_status.avgdelta.toFixed(2) + " > Exp. Delta " + expectedDelta;
}
if (currenttemp.duration > 0) { // if there is currently any temp basal running
rT.reason = rT.reason += "; cancel";
return setTempBasal(0, 0, profile, rT, offline); // cancel temp
} else {
rT.reason = rT.reason += "; no temp to cancel";
return rT;
}
}
}
if (eventualBG < profile.min_bg) {
// if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed)
if (snoozeBG > profile.min_bg) { // if adding back in the bolus contribution BG would be above min
// if BG is falling and high-temped, or rising and low-temped, cancel
// compare against zero here, not BGI, because BGI will be highly negative from boluses and no carbs
if (glucose_status.delta < 0 && currenttemp.duration > 0 && currenttemp.rate > profile.current_basal) {
rT.reason += tick + ", and temp " + currenttemp.rate + " > basal " + profile.current_basal;
return setTempBasal(0, 0, profile, rT, offline); // cancel temp
} else if (glucose_status.delta > 0 && currenttemp.duration > 0 && currenttemp.rate < profile.current_basal) {
rT.reason += tick + ", and temp " + currenttemp.rate + " < basal " + profile.current_basal;
return setTempBasal(0, 0, profile, rT, offline); // cancel temp
}
rT.reason += ", bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG;
return rT;
} else {
// calculate 30m low-temp required to get projected BG up to target
// use snoozeBG to more gradually ramp in any counteraction of the user's boluses
// multiply by 2 to low-temp faster for increased hypo safety
var insulinReq = 2 * Math.min(0, (snoozeBG - target_bg) / profile.sens);
if (minDelta < 0 && minDelta > expectedDelta) {
// if we're barely falling, newinsulinReq should be barely negative
rT.reason += ", Snooze BG " + snoozeBG;
var newinsulinReq = Math.round(( insulinReq * (minDelta / expectedDelta) ) * 100)/100;
//console.log("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
insulinReq = newinsulinReq;
}
// rate required to deliver insulinReq less insulin over 30m:
var rate = profile.current_basal + (2 * insulinReq);
rate = Math.round( rate * 1000 ) / 1000;
// if required temp < existing temp basal
var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60;
if (insulinScheduled < insulinReq - 0.2) { // if current temp would deliver >0.2U less than the required insulin, raise the rate
rT.reason = currenttemp.duration + "m@" + (currenttemp.rate - profile.current_basal).toFixed(3) + " = " + insulinScheduled.toFixed(3) + " < req " + insulinReq + "-0.2U";
return setTempBasal(rate, 30, profile, rT, offline);
}
if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 5 && rate > currenttemp.rate - 0.1)) {
rT.reason += ", temp " + currenttemp.rate + " ~< req " + rate + "U/hr";
return rT;
} else {
rT.reason += ", setting " + rate + "U/hr";
return setTempBasal(rate, 30, profile, rT, offline);
}
}
}
}
// if eventual BG is above min but BG is falling faster than expected Delta
if (minDelta < expectedDelta) {
if (glucose_status.delta < glucose_status.avgdelta) {
rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Delta " + tick + " < Exp. Delta " + expectedDelta;
} else {
rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Avg. Delta " + glucose_status.avgdelta.toFixed(2) + " < Exp. Delta " + expectedDelta;
}
if (currenttemp.duration > 0) { // if there is currently any temp basal running
rT.reason = rT.reason += "; cancel";
return setTempBasal(0, 0, profile, rT, offline); // cancel temp
} else {
rT.reason = rT.reason += "; no temp to cancel";
return rT;
}
}
if (eventualBG < profile.max_bg) {
rT.reason = eventualBG + " is in range. No temp required";
if (currenttemp.duration > 0) { // if there is currently any temp basal running
rT.reason = rT.reason += "; cancel";
return setTempBasal(0, 0, profile, rT, offline); // cancel temp
}
if (offline == 'Offline') {
// if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working
if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !rT.duration) {
rT.reason = rT.reason + "; setting current basal of " + profile.current_basal + " as temp";
return setTempBasal(profile.current_basal, 30, profile, rT, offline);
}
}
return rT;
}
if (snoozeBG < profile.max_bg) {
rT.reason = snoozeBG + " < " + profile.max_bg;
if (currenttemp.duration > 0) { // if there is currently any temp basal running
rT.reason = rT.reason += "; cancel";
return setTempBasal(0, 0, profile, rT, offline); // cancel temp
} else {
rT.reason = rT.reason += "; no temp to cancel";
return rT;
}
}
// eventual BG is at/above target:
// if iob is over max, just cancel any temps
var basaliob;
if (iob_data.basaliob) { basaliob = iob_data.basaliob; }
else { basaliob = iob_data.iob - iob_data.bolussnooze; }
rT.reason = "Eventual BG " + eventualBG + ">=" + profile.max_bg + ", ";
if (basaliob > max_iob) {
rT.reason = "basaliob " + basaliob + " > max_iob " + max_iob;
return setTempBasal(0, 0, profile, rT, offline);
} else { // otherwise, calculate 30m high-temp required to get projected BG down to target
// insulinReq is the additional insulin required to get down to max bg:
// if in meal assist mode, check if snoozeBG is lower, as eventualBG is not dependent on IOB
var insulinReq = (Math.min(snoozeBG,eventualBG) - target_bg) / profile.sens;
if (minDelta < 0 && minDelta > expectedDelta) {
var newinsulinReq = Math.round(( insulinReq * (1 - (minDelta / expectedDelta)) ) * 100)/100;
//console.log("Reducing insulinReq from " + insulinReq + " to " + newinsulinReq);
insulinReq = newinsulinReq;
}
// if that would put us over max_iob, then reduce accordingly
if (insulinReq > max_iob-basaliob) {
rT.reason = "max_iob " + max_iob + ", ";
insulinReq = max_iob-basaliob;
}
// rate required to deliver insulinReq more insulin over 30m:
var rate = profile.current_basal + (2 * insulinReq);
rate = Math.round( rate * 1000 ) / 1000;
var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal);
if (rate > maxSafeBasal) {
rT.reason += "adj. req. rate:"+rate.toFixed(1) +" to maxSafeBasal:"+maxSafeBasal.toFixed(1)+", ";
rate = maxSafeBasal;
}
var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60;
if (insulinScheduled > insulinReq + 0.2) { // if current temp would deliver >0.2U more than the required insulin, lower the rate
rT.reason = currenttemp.duration + "m@" + (currenttemp.rate - profile.current_basal).toFixed(3) + " = " + insulinScheduled.toFixed(3) + " > req " + insulinReq + "+0.2U";
return setTempBasal(rate, 30, profile, rT, offline);
}
if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { // no temp is set
rT.reason += "no temp, setting " + rate + "U/hr";
return setTempBasal(rate, 30, profile, rT, offline);
}
if (currenttemp.duration > 5 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal
rT.reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr";
return rT;
}
// required temp > existing temp basal
rT.reason += "temp " + currenttemp.rate + "<" + rate + "U/hr";
return setTempBasal(rate, 30, profile, rT, offline);
}
};
module.exports = determine_basal;

View file

@ -0,0 +1,36 @@
<configuration>
<!-- Create a file appender for a log in the application's data directory -->
<property name="EXT_FILES_DIR" value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/files"/>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${EXT_FILES_DIR}/AndroidAPS.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover. Make sure the path matches the one in the file element or else
the rollover logs are placed in the working directory. -->
<fileNamePattern>${EXT_FILES_DIR}/AndroidAPS._%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- keep 30 days' worth of history -->
<maxHistory>120</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
<tagEncoder>
<pattern>%logger{0}</pattern>
</tagEncoder>
<encoder>
<pattern>[%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Write INFO (and higher-level) messages to the log file -->
<root level="DEBUG">
<appender-ref ref="file" />
<appender-ref ref="logcat" />
</root>
</configuration>

View file

@ -0,0 +1,44 @@
package info.nightscout.androidaps;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
public class AgreementActivity extends Activity {
boolean IUnderstand;
CheckBox agreeCheckBox;
Button saveButton;
SharedPreferences prefs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_agreement);
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
IUnderstand = prefs.getBoolean("I_understand", false);
setContentView(R.layout.activity_agreement);
agreeCheckBox = (CheckBox)findViewById(R.id.agreementCheckBox);
agreeCheckBox.setChecked(IUnderstand);
saveButton = (Button)findViewById(R.id.agreementSaveButton);
addListenerOnButton();
}
public void addListenerOnButton() {
saveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
prefs.edit().putBoolean("I_understand", agreeCheckBox.isChecked()).apply();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
finish();
}
});
}
}

View file

@ -0,0 +1,38 @@
package info.nightscout.androidaps;
/**
* Created by mike on 07.06.2016.
*/
public class Config {
// MAIN FUCTIONALITY
public static final boolean APS = BuildConfig.APS;
// PLUGINS
public static final boolean OPENAPSMAENABLED = APS;
public static final boolean LOOPENABLED = APS;
public static final boolean CAREPORTALENABLED = true;
public static final boolean SMSCOMMUNICATORENABLED = true;
public static final boolean DANAR = true && BuildConfig.PUMPDRIVERS;
public static final boolean MM640G = false && BuildConfig.PUMPDRIVERS;
public static final boolean detailedLog = true;
public static final boolean logFunctionCalls = true;
public static final boolean logIncommingBG = true;
public static final boolean logIncommingData = true;
public static final boolean logAPSResult = true;
public static final boolean logPumpComm = true;
public static final boolean logPrefsChange = true;
public static final boolean logConfigBuilder = true;
public static final boolean logConstraintsChanges = true;
public static final boolean logTempBasalsCut = true;
public static final boolean logNSUpload = true;
public static final boolean logPumpActions = true;
public static final boolean logSMSComm = true;
public static final boolean logCongigBuilderActions = true;
// DanaR specific
public static final boolean logDanaBTComm = true;
public static final boolean logDanaMessageDetail = true;
public static final boolean logDanaSerialEngine = true;
}

View file

@ -0,0 +1,28 @@
package info.nightscout.androidaps;
import com.j256.ormlite.stmt.query.In;
/**
* Created by mike on 07.06.2016.
*/
public class Constants {
public static final String MGDL = "mg/dl"; // This is Nightscout representation
public static final String MMOL = "mmol";
public static final double MMOLL_TO_MGDL = 18; // 18.0182;
public static final double MGDL_TO_MMOLL = 1 / MMOLL_TO_MGDL;
public static final double basalAbsoluteOnlyForCheckLimit = 10101010d;
public static final Integer basalPercentOnlyForCheckLimit = 10101010;
public static final double bolusOnlyForCheckLimit = 10101010d;
public static final Integer carbsOnlyForCheckLimit = 10101010;
public static final Integer notificationID = 556677;
public static final int hoursToKeepInDatabase = 72;
public static final int daysToKeepHistoryInDatabase = 30;
public static final long keepAliveMsecs = 5 * 60 * 1000L;
public static final long remoteBolusMinDistance = 15 * 60 * 1000L;
}

View file

@ -1,40 +1,100 @@
package info.nightscout.androidaps;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import info.nightscout.androidaps.tabs.*;
import info.nightscout.androidaps.plugins.Objectives.ObjectivesFragment;
import info.nightscout.androidaps.plugins.Test.TestFragment;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.fonts.FontAwesomeModule;
import com.squareup.otto.Subscribe;
public class MainActivity extends AppCompatActivity implements ObjectivesFragment.OnFragmentInteractionListener {
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private Toolbar toolbar;
private SlidingTabLayout mTabs;
private ViewPager mPager;
private TabPageAdapter mAdapter;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.DanaR.Services.ExecutionService;
import info.nightscout.androidaps.receivers.KeepAliveReceiver;
import info.nightscout.androidaps.tabs.SlidingTabLayout;
import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.utils.ImportExportPrefs;
import info.nightscout.utils.LocaleHelper;
public class MainActivity extends AppCompatActivity {
private static Logger log = LoggerFactory.getLogger(MainActivity.class);
private static KeepAliveReceiver keepAliveReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Iconify.with(new FontAwesomeModule());
LocaleHelper.onCreate(this, "en");
setContentView(R.layout.activity_main);
checkEula();
if (Config.logFunctionCalls)
log.debug("onCreate");
// Register all tabs in app here
mAdapter = new TabPageAdapter(getSupportFragmentManager());
mAdapter.registerNewFragment("Test", TestFragment.newInstance());
mAdapter.registerNewFragment("Objectives", ObjectivesFragment.newInstance());
toolbar = (Toolbar) findViewById(R.id.toolbar);
// show version in toolbar
try {
setTitle(getString(R.string.app_name) + " " + getPackageManager().getPackageInfo(getPackageName(), 0).versionName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mTabs = (SlidingTabLayout) findViewById(R.id.tabs);
mTabs.setViewPager(mPager);
registerBus();
try {
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setIcon(R.mipmap.ic_launcher);
} catch (NullPointerException e) {
// no action
}
if (keepAliveReceiver == null) {
keepAliveReceiver = new KeepAliveReceiver();
startService(new Intent(this, ExecutionService.class));
keepAliveReceiver.setAlarm(this);
}
setUpTabs(false);
}
@Subscribe
public void onStatusEvent(final EventRefreshGui ev) {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String lang = SP.getString("language", "en");
LocaleHelper.setLocale(getApplicationContext(), lang);
recreate();
try { // activity may be destroyed
setUpTabs(true);
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
private void setUpTabs(boolean switchToLast) {
TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), this);
for (PluginBase p : MainApp.getPluginsList()) {
pageAdapter.registerNewFragment(p);
}
ViewPager mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(pageAdapter);
SlidingTabLayout mTabs = (SlidingTabLayout) findViewById(R.id.tabs);
mTabs.setViewPager(mPager);
if (switchToLast)
mPager.setCurrentItem(pageAdapter.getCount() - 1, false);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
@ -44,13 +104,69 @@ public class MainActivity extends AppCompatActivity implements ObjectivesFragmen
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.nav_preferences:
Intent i = new Intent(getApplicationContext(), PreferencesActivity.class);
startActivity(i);
break;
case R.id.nav_resetdb:
MainApp.getDbHelper().resetDatabases();
break;
case R.id.nav_export:
ImportExportPrefs.verifyStoragePermissions(this);
ImportExportPrefs.exportSharedPreferences(this);
break;
case R.id.nav_import:
ImportExportPrefs.verifyStoragePermissions(this);
ImportExportPrefs.importSharedPreferences(this);
break;
// case R.id.nav_test_alarm:
// final int REQUEST_CODE_ASK_PERMISSIONS = 2355;
// int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.SYSTEM_ALERT_WINDOW);
// if (permission != PackageManager.PERMISSION_GRANTED) {
// // We don't have permission so prompt the user
// // On Android 6 give permission for alarming in Settings -> Apps -> Draw over other apps
// ActivityCompat.requestPermissions(
// this,
// new String[]{Manifest.permission.SYSTEM_ALERT_WINDOW},
// REQUEST_CODE_ASK_PERMISSIONS
// );
// }
// Intent alertServiceIntent = new Intent(getApplicationContext(), AlertService.class);
// alertServiceIntent.putExtra("alertText", getString(R.string.nav_test_alert));
// getApplicationContext().startService(alertServiceIntent);
// break;
case R.id.nav_exit:
log.debug("Exiting");
keepAliveReceiver.cancelAlarm(this);
MainApp.bus().post(new EventAppExit());
MainApp.closeDbHelper();
finish();
System.runFinalization();
System.exit(0);
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onFragmentInteraction(String param) {
private void registerBus() {
try {
MainApp.bus().unregister(this);
} catch (RuntimeException x) {
// Ignore
}
MainApp.bus().register(this);
}
private void checkEula() {
boolean IUnderstand = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getBoolean("I_understand", false);
if (!IUnderstand) {
Intent intent = new Intent(getApplicationContext(), AgreementActivity.class);
startActivity(intent);
finish();
}
}
}

View file

@ -0,0 +1,163 @@
package info.nightscout.androidaps;
import android.app.Application;
import android.content.res.Resources;
import android.support.annotation.Nullable;
import com.crashlytics.android.Crashlytics;
import com.j256.ormlite.android.apptools.OpenHelperManager;
import com.squareup.otto.Bus;
import com.squareup.otto.ThreadEnforcer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.Careportal.CareportalFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.DanaR.DanaRFragment;
import info.nightscout.androidaps.plugins.Loop.LoopFragment;
import info.nightscout.androidaps.plugins.MM640g.MM640gFragment;
import info.nightscout.androidaps.plugins.NSProfileViewer.NSProfileViewerFragment;
import info.nightscout.androidaps.plugins.Objectives.ObjectivesFragment;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAFragment;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.androidaps.plugins.SafetyFragment.SafetyFragment;
import info.nightscout.androidaps.plugins.SimpleProfile.SimpleProfileFragment;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorFragment;
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientFragment;
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripFragment;
import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
import info.nightscout.androidaps.plugins.VirtualPump.VirtualPumpFragment;
import io.fabric.sdk.android.Fabric;
public class MainApp extends Application {
private static Logger log = LoggerFactory.getLogger(MainApp.class);
private static Bus sBus;
private static MainApp sInstance;
public static Resources sResources;
private static DatabaseHelper sDatabaseHelper = null;
private static ConfigBuilderPlugin sConfigBuilder = null;
private static ArrayList<PluginBase> pluginsList = null;
@Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
sBus = new Bus(ThreadEnforcer.ANY);
sInstance = this;
sResources = getResources();
if (pluginsList == null) {
pluginsList = new ArrayList<>();
// Register all tabs in app here
pluginsList.add(OverviewFragment.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRFragment.getPlugin());
if (Config.MM640G) pluginsList.add(MM640gFragment.getPlugin());
if (Config.CAREPORTALENABLED) pluginsList.add(CareportalFragment.getPlugin());
pluginsList.add(VirtualPumpFragment.getPlugin());
if (Config.LOOPENABLED) pluginsList.add(LoopFragment.getPlugin());
if (Config.OPENAPSMAENABLED) pluginsList.add(OpenAPSMAFragment.getPlugin());
pluginsList.add(NSProfileViewerFragment.getPlugin());
pluginsList.add(SimpleProfileFragment.getPlugin());
pluginsList.add(TreatmentsFragment.getPlugin());
pluginsList.add(TempBasalsFragment.getPlugin());
pluginsList.add(SafetyFragment.getPlugin());
if (Config.APS) pluginsList.add(ObjectivesFragment.getPlugin());
pluginsList.add(SourceXdripFragment.getPlugin());
pluginsList.add(SourceNSClientFragment.getPlugin());
if (Config.SMSCOMMUNICATORENABLED)
pluginsList.add(SmsCommunicatorFragment.getPlugin());
pluginsList.add(sConfigBuilder = ConfigBuilderFragment.getPlugin());
MainApp.getConfigBuilder().initialize();
}
}
public static Bus bus() {
return sBus;
}
public static MainApp instance() {
return sInstance;
}
public static DatabaseHelper getDbHelper() {
if (sDatabaseHelper == null) {
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
}
return sDatabaseHelper;
}
public static void closeDbHelper() {
if (sDatabaseHelper != null) {
sDatabaseHelper.close();
sDatabaseHelper = null;
}
}
public static ConfigBuilderPlugin getConfigBuilder() {
return sConfigBuilder;
}
public static ArrayList<PluginBase> getPluginsList() {
return pluginsList;
}
public static ArrayList<PluginBase> getSpecificPluginsList(int type) {
ArrayList<PluginBase> newList = new ArrayList<>();
if (pluginsList != null) {
for (PluginBase p : pluginsList) {
if (p.getType() == type)
newList.add(p);
}
} else {
log.error("pluginsList=null");
}
return newList;
}
public static ArrayList<PluginBase> getSpecificPluginsListByInterface(Class interfaceClass) {
ArrayList<PluginBase> newList = new ArrayList<>();
if (pluginsList != null) {
for (PluginBase p : pluginsList) {
if (p.getClass() != ConfigBuilderPlugin.class && interfaceClass.isAssignableFrom(p.getClass()))
newList.add(p);
}
} else {
log.error("pluginsList=null");
}
return newList;
}
@Nullable
public static PluginBase getSpecificPlugin(Class pluginClass) {
if (pluginsList != null) {
for (PluginBase p : pluginsList) {
if (p.getClass() == pluginClass)
return p;
}
} else {
log.error("pluginsList=null");
}
return null;
}
@Override
public void onTerminate() {
super.onTerminate();
sDatabaseHelper.close();
}
}

View file

@ -0,0 +1,108 @@
package info.nightscout.androidaps;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.MultiSelectListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.DanaR.BluetoothDevicePreference;
import info.nightscout.androidaps.plugins.DanaR.DanaRFragment;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.utils.LocaleHelper;
public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
MyPreferenceFragment myPreferenceFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myPreferenceFragment = new MyPreferenceFragment();
getFragmentManager().beginTransaction().replace(android.R.id.content, myPreferenceFragment).commit();
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
MainApp.bus().post(new EventPreferenceChange());
if (key.equals("language")) {
String lang = sharedPreferences.getString("language", "en");
LocaleHelper.setLocale(getApplicationContext(), lang);
recreate();
MainApp.bus().post(new EventRefreshGui());
}
updatePrefSummary(myPreferenceFragment.getPreference(key));
}
private static void updatePrefSummary(Preference pref) {
if (pref instanceof ListPreference || pref instanceof BluetoothDevicePreference) {
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry());
}
if (pref instanceof EditTextPreference) {
EditTextPreference editTextPref = (EditTextPreference) pref;
if (pref.getTitle().toString().toLowerCase().contains("password"))
{
pref.setSummary("******");
} else if (editTextPref.getText() != null && !editTextPref.getText().equals("")){
pref.setSummary(editTextPref.getText());
}
}
if (pref instanceof MultiSelectListPreference) {
EditTextPreference editTextPref = (EditTextPreference) pref;
pref.setSummary(editTextPref.getText());
}
}
private static void initSummary(Preference p) {
if (p instanceof PreferenceGroup) {
PreferenceGroup pGrp = (PreferenceGroup) p;
for (int i = 0; i < pGrp.getPreferenceCount(); i++) {
initSummary(pGrp.getPreference(i));
}
} else {
updatePrefSummary(p);
}
}
public static class MyPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_quickwizard);
addPreferencesFromResource(R.xml.pref_language);
if (Config.CAREPORTALENABLED)
addPreferencesFromResource(R.xml.pref_careportal);
addPreferencesFromResource(R.xml.pref_treatments);
if (Config.APS)
addPreferencesFromResource(R.xml.pref_closedmode);
if (Config.OPENAPSMAENABLED)
addPreferencesFromResource(R.xml.pref_openapsma);
addPreferencesFromResource(R.xml.pref_nightscout);
if (Config.DANAR) {
DanaRPlugin danaRPlugin = (DanaRPlugin) MainApp.getSpecificPlugin(DanaRPlugin.class);
if (danaRPlugin.isEnabled(PluginBase.PUMP)) {
addPreferencesFromResource(R.xml.pref_danar);
addPreferencesFromResource(R.xml.pref_danarprofile);
}
}
if (Config.MM640G)
addPreferencesFromResource(R.xml.pref_mm640g);
if (Config.SMSCOMMUNICATORENABLED)
addPreferencesFromResource(R.xml.pref_smscommunicator);
initSummary(getPreferenceScreen());
}
public Preference getPreference (String key) {
return findPreference(key);
}
}
}

View file

@ -0,0 +1,569 @@
package info.nightscout.androidaps.Services;
import android.app.IntentService;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.Telephony;
import android.support.annotation.Nullable;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.DanaRHistoryRecord;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.DanaR.History.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.Objectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS;
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin;
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin;
import info.nightscout.androidaps.receivers.DataReceiver;
import info.nightscout.client.data.NSProfile;
import info.nightscout.client.data.NSSgv;
import info.nightscout.utils.ToastUtils;
public class DataService extends IntentService {
private static Logger log = LoggerFactory.getLogger(DataService.class);
boolean xDripEnabled = false;
boolean nsClientEnabled = true;
public DataService() {
super("DataService");
registerBus();
}
@Override
protected void onHandleIntent(final Intent intent) {
if (Config.logFunctionCalls)
log.debug("onHandleIntent " + intent);
if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceXdripPlugin.class)) {
xDripEnabled = true;
nsClientEnabled = false;
}
if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceNSClientPlugin.class)) {
xDripEnabled = false;
nsClientEnabled = true;
}
if (intent != null) {
final String action = intent.getAction();
if (Intents.ACTION_NEW_BG_ESTIMATE.equals(action)) {
if (xDripEnabled)
handleNewDataFromXDrip(intent);
} else if (Intents.ACTION_NEW_PROFILE.equals(action) ||
Intents.ACTION_NEW_TREATMENT.equals(action) ||
Intents.ACTION_CHANGED_TREATMENT.equals(action) ||
Intents.ACTION_REMOVED_TREATMENT.equals(action) ||
Intents.ACTION_NEW_SGV.equals(action) ||
Intents.ACTION_NEW_STATUS.equals(action) ||
Intents.ACTION_NEW_DEVICESTATUS.equals(action) ||
Intents.ACTION_NEW_CAL.equals(action) ||
Intents.ACTION_NEW_MBG.equals(action)
) {
handleNewDataFromNSClient(intent);
} else if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(action)) {
handleNewSMS(intent);
}
}
if (Config.logFunctionCalls)
log.debug("onHandleIntent exit " + intent);
DataReceiver.completeWakefulIntent(intent);
}
/*
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (Config.logFunctionCalls)
log.debug("onStartCommand");
return START_STICKY;
}
*/
@Override
public void onDestroy() {
super.onDestroy();
MainApp.bus().unregister(this);
}
private void registerBus() {
try {
MainApp.bus().unregister(this);
} catch (RuntimeException x) {
// Ignore
}
MainApp.bus().register(this);
}
private void handleNewDataFromXDrip(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;
BgReading bgReading = new BgReading();
bgReading.value = bundle.getDouble(Intents.EXTRA_BG_ESTIMATE);
bgReading.slope = bundle.getDouble(Intents.EXTRA_BG_SLOPE);
bgReading.battery_level = bundle.getInt(Intents.EXTRA_SENSOR_BATTERY);
bgReading.timeIndex = bundle.getLong(Intents.EXTRA_TIMESTAMP);
bgReading.raw = bundle.getDouble(Intents.EXTRA_RAW);
if (bgReading.timeIndex < new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) {
if (Config.logIncommingBG)
log.debug("Ignoring old XDRIPREC BG " + bgReading.toString());
return;
}
if (Config.logIncommingBG)
log.debug("XDRIPREC BG " + bgReading.toString());
try {
MainApp.getDbHelper().getDaoBgReadings().createIfNotExists(bgReading);
} catch (SQLException e) {
e.printStackTrace();
}
MainApp.bus().post(new EventNewBG());
}
private void handleNewDataFromNSClient(Intent intent) {
Bundle bundles = intent.getExtras();
if (bundles == null) return;
if (Config.logIncommingData)
log.debug("Got intent: " + intent.getAction());
if (intent.getAction().equals(Intents.ACTION_NEW_STATUS)) {
if (Config.logIncommingData)
log.debug("Received status: " + bundles);
if (bundles.containsKey("nsclientversioncode")) {
ConfigBuilderPlugin.nightscoutVersionCode = bundles.getInt("nightscoutversioncode"); // for ver 1.2.3 contains 10203
ConfigBuilderPlugin.nightscoutVersionName = bundles.getString("nightscoutversionname");
ConfigBuilderPlugin.nsClientVersionCode = bundles.getInt("nsclientversioncode"); // for ver 1.17 contains 117
ConfigBuilderPlugin.nsClientVersionName = bundles.getString("nsclientversionname");
log.debug("Got versions: NSClient: " + ConfigBuilderPlugin.nsClientVersionName + " Nightscout: " + ConfigBuilderPlugin.nightscoutVersionName);
if (ConfigBuilderPlugin.nsClientVersionCode < 118)
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.unsupportedclientver));
} else {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.unsupportedclientver));
}
if (bundles.containsKey("status")) {
try {
JSONObject statusJson = new JSONObject(bundles.getString("status"));
if (statusJson.has("settings")) {
JSONObject settings = statusJson.getJSONObject("settings");
if (settings.has("thresholds")) {
JSONObject thresholds = settings.getJSONObject("thresholds");
if (thresholds.has("bgTargetTop")) {
OverviewPlugin.bgTargetHigh = thresholds.getDouble("bgTargetTop");
}
if (thresholds.has("bgTargetBottom")) {
OverviewPlugin.bgTargetLow = thresholds.getDouble("bgTargetBottom");
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_DEVICESTATUS)) {
try {
if (bundles.containsKey("devicestatus")) {
String devicestatusesstring = bundles.getString("devicestatus");
JSONObject devicestatusJson = new JSONObject(bundles.getString("devicestatus"));
if (devicestatusJson.has("pump")) {
// Objectives 0
ObjectivesPlugin.pumpStatusIsAvailableInNS = true;
ObjectivesPlugin.saveProgress();
}
}
if (bundles.containsKey("devicestatuses")) {
String devicestatusesstring = bundles.getString("devicestatuses");
JSONArray jsonArray = new JSONArray(devicestatusesstring);
if (jsonArray.length() > 0) {
JSONObject devicestatusJson = jsonArray.getJSONObject(0);
if (devicestatusJson.has("pump")) {
// Objectives 0
ObjectivesPlugin.pumpStatusIsAvailableInNS = true;
ObjectivesPlugin.saveProgress();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Handle profile
if (intent.getAction().equals(Intents.ACTION_NEW_PROFILE)) {
try {
String activeProfile = bundles.getString("activeprofile");
String profile = bundles.getString("profile");
NSProfile nsProfile = new NSProfile(new JSONObject(profile), activeProfile);
if (MainApp.getConfigBuilder() == null) {
log.error("Config builder not ready on receive profile");
return;
}
PumpInterface pump = MainApp.getConfigBuilder();
if (pump != null) {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (SP.getBoolean("syncprofiletopump", false))
pump.setNewBasalProfile(nsProfile);
} else {
log.error("No active pump selected");
}
if (Config.logIncommingData)
log.debug("Received profile: " + activeProfile + " " + profile);
MainApp.bus().post(new EventNewBasalProfile(nsProfile));
} catch (JSONException e) {
e.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_TREATMENT)) {
try {
if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment");
handleAddedTreatment(trstring);
}
if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i);
String trstr = trJson.toString();
handleAddedTreatment(trstr);
}
}
scheduleTreatmentChange();
} catch (Exception e) {
e.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_CHANGED_TREATMENT)) {
try {
if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment");
handleChangedTreatment(trstring);
}
if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i);
String trstr = trJson.toString();
handleChangedTreatment(trstr);
}
}
scheduleTreatmentChange();
} catch (Exception e) {
e.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_REMOVED_TREATMENT)) {
try {
if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment");
JSONObject trJson = new JSONObject(trstring);
String _id = trJson.getString("_id");
removeTreatmentFromDb(_id);
}
if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i);
String _id = trJson.getString("_id");
removeTreatmentFromDb(_id);
}
}
scheduleTreatmentChange();
} catch (Exception e) {
e.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_SGV)) {
if (nsClientEnabled) {
try {
if (bundles.containsKey("sgv")) {
String sgvstring = bundles.getString("sgv");
JSONObject sgvJson = new JSONObject(sgvstring);
NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv);
if (bgReading.timeIndex < new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000l) {
if (Config.logIncommingData)
log.debug("Ignoring old BG: " + bgReading.toString());
return;
}
MainApp.getDbHelper().getDaoBgReadings().createIfNotExists(bgReading);
if (Config.logIncommingData)
log.debug("ADD: Stored new BG: " + bgReading.toString());
}
if (bundles.containsKey("sgvs")) {
String sgvstring = bundles.getString("sgvs");
JSONArray jsonArray = new JSONArray(sgvstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject sgvJson = jsonArray.getJSONObject(i);
NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv);
if (bgReading.timeIndex < new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000l) {
if (Config.logIncommingData)
log.debug("Ignoring old BG: " + bgReading.toString());
} else {
MainApp.getDbHelper().getDaoBgReadings().createIfNotExists(bgReading);
if (Config.logIncommingData)
log.debug("ADD: Stored new BG: " + bgReading.toString());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
MainApp.bus().post(new EventNewBG());
}
// Objectives 0
ObjectivesPlugin.bgIsAvailableInNS = true;
ObjectivesPlugin.saveProgress();
}
if (intent.getAction().equals(Intents.ACTION_NEW_MBG)) {
log.error("Not implemented yet"); // TODO implemeng MBGS
}
}
private void handleAddedTreatment(String trstring) throws JSONException, SQLException {
JSONObject trJson = new JSONObject(trstring);
handleDanaRHistoryRecords(trJson); // update record _id in history
if (!trJson.has("insulin") && !trJson.has("carbs")) {
if (Config.logIncommingData)
log.debug("ADD: Uninterested treatment: " + trstring);
return;
}
Treatment stored = null;
String _id = trJson.getString("_id");
if (trJson.has("timeIndex")) {
if (Config.logIncommingData)
log.debug("ADD: timeIndex found: " + trstring);
stored = findByTimeIndex(trJson.getLong("timeIndex"));
} else {
stored = findById(_id);
}
if (stored != null) {
if (Config.logIncommingData)
log.debug("ADD: Existing treatment: " + trstring);
if (trJson.has("timeIndex")) {
stored._id = _id;
int updated = MainApp.getDbHelper().getDaoTreatments().update(stored);
if (Config.logIncommingData)
log.debug("Records updated: " + updated);
}
} else {
if (Config.logIncommingData)
log.debug("ADD: New treatment: " + trstring);
Treatment treatment = new Treatment();
treatment._id = _id;
treatment.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
treatment.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
treatment.created_at = new Date(trJson.getLong("mills"));
if (trJson.has("eventType")) {
treatment.mealBolus = true;
if (trJson.get("eventType").equals("Correction Bolus")) treatment.mealBolus = false;
if (trJson.get("eventType").equals("Bolus Wizard") && treatment.carbs <= 0) treatment.mealBolus = false;
}
treatment.setTimeIndex(treatment.getTimeIndex());
try {
MainApp.getDbHelper().getDaoTreatments().createOrUpdate(treatment);
if (Config.logIncommingData)
log.debug("ADD: Stored treatment: " + treatment.log());
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private void handleChangedTreatment(String trstring) throws JSONException, SQLException {
JSONObject trJson = new JSONObject(trstring);
handleDanaRHistoryRecords(trJson); // update record _id in history
if (!trJson.has("insulin") && !trJson.has("carbs")) {
if (Config.logIncommingData)
log.debug("CHANGE: Uninterested treatment: " + trstring);
return;
}
String _id = trJson.getString("_id");
Treatment stored;
if (trJson.has("timeIndex")) {
if (Config.logIncommingData)
log.debug("ADD: timeIndex found: " + trstring);
stored = findByTimeIndex(trJson.getLong("timeIndex"));
} else {
stored = findById(_id);
}
if (stored != null) {
if (Config.logIncommingData)
log.debug("CHANGE: Removing old: " + trstring);
removeTreatmentFromDb(_id);
}
if (Config.logIncommingData)
log.debug("CHANGE: Adding new treatment: " + trstring);
Treatment treatment = new Treatment();
treatment._id = _id;
treatment.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
treatment.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
//treatment.created_at = DateUtil.fromISODateString(trJson.getString("created_at"));
treatment.created_at = new Date(trJson.getLong("mills"));
if (trJson.has("eventType")) {
treatment.mealBolus = true;
if (trJson.get("eventType").equals("Correction Bolus")) treatment.mealBolus = false;
if (trJson.get("eventType").equals("Bolus Wizard") && treatment.carbs <= 0) treatment.mealBolus = false;
}
treatment.setTimeIndex(treatment.getTimeIndex());
try {
Dao.CreateOrUpdateStatus status = MainApp.getDbHelper().getDaoTreatments().createOrUpdate(treatment);
if (Config.logIncommingData)
log.debug("Records updated: " + status.getNumLinesChanged());
if (Config.logIncommingData)
log.debug("CHANGE: Stored treatment: " + treatment.log());
} catch (SQLException e) {
e.printStackTrace();
}
}
public void handleDanaRHistoryRecords(JSONObject trJson) throws JSONException, SQLException {
if (trJson.has(DanaRNSHistorySync.DANARSIGNATURE)) {
Dao<DanaRHistoryRecord, String> daoHistoryRecords = MainApp.getDbHelper().getDaoDanaRHistory();
QueryBuilder<DanaRHistoryRecord, String> queryBuilder = daoHistoryRecords.queryBuilder();
Where where = queryBuilder.where();
where.ge("bytes", trJson.get(DanaRNSHistorySync.DANARSIGNATURE));
PreparedQuery<DanaRHistoryRecord> preparedQuery = queryBuilder.prepare();
List<DanaRHistoryRecord> list = daoHistoryRecords.query(preparedQuery);
if (list.size() == 0) {
// Record does not exists. Ignore
} else if (list.size() == 1) {
DanaRHistoryRecord record = list.get(0);
if (record.get_id() == null || record.get_id() != trJson.getString("_id")) {
if (Config.logIncommingData)
log.debug("Updating _id in DanaR history database: " + trJson.getString("_id"));
record.set_id(trJson.getString("_id"));
daoHistoryRecords.update(record);
} else {
// already set
}
}
}
}
@Nullable
public static Treatment findById(String _id) {
try {
Dao<Treatment, Long> daoTreatments = MainApp.getDbHelper().getDaoTreatments();
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
queryBuilder.limit(10);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = daoTreatments.query(preparedQuery);
if (trList.size() != 1) {
//log.debug("Treatment findById query size: " + trList.size());
return null;
} else {
//log.debug("Treatment findById found: " + trList.get(0).log());
return trList.get(0);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Nullable
public static Treatment findByTimeIndex(Long timeIndex) {
try {
QueryBuilder<Treatment, String> qb = null;
Dao<Treatment, Long> daoTreatments = MainApp.getDbHelper().getDaoTreatments();
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
Where where = queryBuilder.where();
where.eq("timeIndex", timeIndex);
queryBuilder.limit(10);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = daoTreatments.query(preparedQuery);
if (trList.size() != 1) {
log.debug("Treatment findByTimeIndex query size: " + trList.size());
return null;
} else {
log.debug("Treatment findByTimeIndex found: " + trList.get(0).log());
return trList.get(0);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
private void removeTreatmentFromDb(String _id) throws SQLException {
Treatment stored = findById(_id);
if (stored != null) {
log.debug("REMOVE: Existing treatment (removing): " + _id);
int removed = MainApp.getDbHelper().getDaoTreatments().delete(stored);
if (Config.logIncommingData)
log.debug("Records removed: " + removed);
scheduleTreatmentChange();
} else {
log.debug("REMOVE: Not stored treatment (ignoring): " + _id);
}
}
private void handleNewSMS(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;
MainApp.bus().post(new EventNewSMS(bundle));
}
public void scheduleTreatmentChange() {
MainApp.bus().post(new EventTreatmentChange());
}
}

View file

@ -0,0 +1,32 @@
package info.nightscout.androidaps.Services;
public interface Intents {
// NSClient -> App
String ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT";
String ACTION_CHANGED_TREATMENT = "info.nightscout.client.CHANGED_TREATMENT";
String ACTION_REMOVED_TREATMENT = "info.nightscout.client.REMOVED_TREATMENT";
String ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE";
String ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV";
String ACTION_NEW_DEVICESTATUS = "info.nightscout.client.NEW_DEVICESTATUS";
String ACTION_NEW_MBG = "info.nightscout.client.NEW_MBG";
String ACTION_NEW_CAL = "info.nightscout.client.NEW_CAL";
String ACTION_NEW_STATUS = "info.nightscout.client.NEW_STATUS";
// App -> NSClient
String ACTION_DATABASE = "info.nightscout.client.DBACCESS";
String ACTION_RESTART = "info.nightscout.client.RESTART";
// xDrip -> App
String RECEIVER_PERMISSION = "com.eveningoutpost.dexdrip.permissions.RECEIVE_BG_ESTIMATE";
String ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate";
String EXTRA_BG_ESTIMATE = "com.eveningoutpost.dexdrip.Extras.BgEstimate";
String EXTRA_BG_SLOPE = "com.eveningoutpost.dexdrip.Extras.BgSlope";
String EXTRA_BG_SLOPE_NAME = "com.eveningoutpost.dexdrip.Extras.BgSlopeName";
String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery";
String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time";
String EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw";
String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData";
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.data;
/**
* Created by mike on 05.06.2016.
*/
public class Iob {
public double iobContrib = 0d;
public double activityContrib = 0d;
public Iob plus(Iob iob) {
iobContrib += iob.iobContrib;
activityContrib += iob.activityContrib;
return this;
}
}

View file

@ -0,0 +1,148 @@
package info.nightscout.androidaps.data;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.Html;
import android.text.Spanned;
import org.json.JSONException;
import org.json.JSONObject;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
public class PumpEnactResult extends Object implements Parcelable {
public boolean success = false; // request was processed successfully (but possible no change was needed)
public boolean enacted = false; // request was processed successfully and change has been made
public String comment = "";
// Result of basal change
public Integer duration = -1; // duration set [minutes]
public Double absolute = -1d; // absolute rate [U/h] , isPercent = false
public Integer percent = -1; // percent of current basal [%] (100% = current basal), isPercent = true
public boolean isPercent = false; // if true percent is used, otherwise absolute
public boolean isTempCancel = false; // if true we are caceling temp basal
// Result of treatment delivery
public Double bolusDelivered = 0d; // real value of delivered insulin
public Integer carbsDelivered = 0; // real value of delivered carbs
public boolean queued = false;
public String log() {
return "Success: " + success + " Enacted: " + enacted + " Comment: " + comment + " Duration: " + duration + " Absolute: " + absolute + " Percent: " + percent + " IsPercent: " + isPercent + " Queued: " + queued;
}
public String toString() {
String ret = MainApp.sResources.getString(R.string.success) + ": " + success;
if (enacted) {
if (isTempCancel) {
ret += "\n" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment + "\n" +
MainApp.sResources.getString(R.string.canceltemp);
} else if (isPercent) {
ret += "\n" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment;
ret += "\n" + MainApp.sResources.getString(R.string.duration) + ": " + duration + " min";
ret += "\n" + MainApp.sResources.getString(R.string.percent) + ": " + percent + "%";
} else {
ret += "\n" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment;
ret += "\n" + MainApp.sResources.getString(R.string.duration) + ": " + duration + " min";
ret += "\n" + MainApp.sResources.getString(R.string.absolute) + ": " + absolute + " U/h";
}
} else {
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment;
}
return ret;
}
public Spanned toSpanned() {
String ret = MainApp.sResources.getString(R.string.success) + ": " + success;
if (queued) {
ret = MainApp.sResources.getString(R.string.waitingforpumpresult);
} else if (enacted) {
if (isTempCancel) {
ret += "<br><b>" + MainApp.sResources.getString(R.string.enacted) + "</b>: " + enacted;
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment +
"<br>" + MainApp.sResources.getString(R.string.canceltemp);
} else if (isPercent) {
ret += "<br><b>" + MainApp.sResources.getString(R.string.enacted) + "</b>: " + enacted;
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment;
ret += "<br><b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + duration + " min";
ret += "<br><b>" + MainApp.sResources.getString(R.string.percent) + "</b>: " + percent + "%";
} else {
ret += "<br><b>" + MainApp.sResources.getString(R.string.enacted) + "</b>: " + enacted;
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment;
ret += "<br><b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + duration + " min";
ret += "<br><b>" + MainApp.sResources.getString(R.string.absolute) + "</b>: " + DecimalFormatter.to2Decimal(absolute) + " U/h";
}
} else {
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment;
}
return Html.fromHtml(ret);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(success ? 1 : 0);
dest.writeInt(enacted ? 1 : 0);
dest.writeInt(isPercent ? 1 : 0);
dest.writeString(comment);
dest.writeInt(duration);
dest.writeDouble(absolute);
dest.writeInt(percent);
}
public final Parcelable.Creator<PumpEnactResult> CREATOR = new Parcelable.Creator<PumpEnactResult>() {
public PumpEnactResult createFromParcel(Parcel in) {
return new PumpEnactResult(in);
}
public PumpEnactResult[] newArray(int size) {
return new PumpEnactResult[size];
}
};
protected PumpEnactResult(Parcel in) {
success = in.readInt() == 1 ? true : false;
enacted = in.readInt() == 1 ? true : false;
isPercent = in.readInt() == 1 ? true : false;
duration = in.readInt();
comment = in.readString();
absolute = in.readDouble();
percent = in.readInt();
}
public PumpEnactResult() {
}
public JSONObject json() {
JSONObject result = new JSONObject();
try {
if (isTempCancel) {
result.put("rate", 0);
result.put("duration", 0);
} else if (isPercent) {
// Nightscout is expecting absolute value
Double abs = Round.roundTo(MainApp.getConfigBuilder().getActiveProfile().getProfile().getBasal(NSProfile.secondsFromMidnight()) * percent / 100, 0.01);
result.put("rate", abs);
result.put("duration", duration);
} else {
result.put("rate", absolute);
result.put("duration", duration);
}
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
}

View file

@ -0,0 +1,87 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import com.jjoe64.graphview.series.DataPointInterface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.Constants;
import info.nightscout.client.data.NSSgv;
import info.nightscout.utils.DecimalFormatter;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS)
public class BgReading implements DataPointInterface {
private static Logger log = LoggerFactory.getLogger(BgReading.class);
public long getTimeIndex() {
return timeIndex;
}
public void setTimeIndex(long timeIndex) {
this.timeIndex = timeIndex;
}
@DatabaseField(id = true, useGetSet = true)
public long timeIndex;
@DatabaseField
public double value;
@DatabaseField
public double slope;
@DatabaseField
public double raw;
@DatabaseField
public int battery_level;
public static String units = Constants.MGDL;
public BgReading() {}
public BgReading(NSSgv sgv) {
timeIndex = sgv.getMills();
value = sgv.getMgdl();
raw = sgv.getFiltered();
}
public Double valueToUnits(String units) {
if (units.equals(Constants.MGDL))
return value;
else
return value * Constants.MGDL_TO_MMOLL;
}
public String valueToUnitsToString(String units) {
if (units.equals(Constants.MGDL)) return DecimalFormatter.to0Decimal(value);
else return DecimalFormatter.to1Decimal(value * Constants.MGDL_TO_MMOLL);
}
@Override
public String toString() {
return "BgReading{" +
"timeIndex=" + timeIndex +
", date=" + new Date(timeIndex) +
", value=" + value +
", slope=" + slope +
", raw=" + raw +
", battery_level=" + battery_level +
'}';
}
@Override
public double getX() {
return timeIndex;
}
@Override
public double getY() {
return valueToUnits(units);
}
}

View file

@ -0,0 +1,171 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import java.util.Date;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_DANARHISTORY)
public class DanaRHistoryRecord {
@DatabaseField(useGetSet = true)
private String _id;
@DatabaseField(useGetSet = true)
private byte recordCode;
@DatabaseField(id = true, useGetSet = true)
private String bytes;
@DatabaseField(useGetSet = true)
private long recordDate;
@DatabaseField(useGetSet = true)
private double recordValue;
@DatabaseField(useGetSet = true)
private String bolusType;
@DatabaseField(useGetSet = true)
private String stringRecordValue;
@DatabaseField(useGetSet = true)
private int recordDuration;
@DatabaseField(useGetSet = true)
private double recordDailyBasal;
@DatabaseField(useGetSet = true)
private double recordDailyBolus;
@DatabaseField(useGetSet = true)
private String recordAlarm;
public DanaRHistoryRecord() {
this.recordDate = 0;
this.recordValue = 0.0;
this.bolusType = "None";
this.recordCode = 0x0F;
this.bytes = new String();
this._id = null;
}
public void setRecordDate(Date dtRecordDate) {
this.recordDate = dtRecordDate.getTime();
}
public long getRecordDate() {
return this.recordDate;
}
public void setRecordDate(long dtRecordDate) {
this.recordDate = dtRecordDate;
}
public double getRecordValue() {
return this.recordValue;
}
public void setRecordValue(double dRecordValue) {
this.recordValue = dRecordValue;
}
public String getBolusType() {
return this.bolusType;
}
public void setBolusType(String strRecordType) {
this.bolusType = strRecordType;
}
public String getStringRecordValue() {
return this.stringRecordValue;
}
public void setStringRecordValue(String strRecordValue) {
this.stringRecordValue = strRecordValue;
}
public byte getRecordCode() {
return this.recordCode;
}
public void setRecordCode(byte cRecordCode) {
this.recordCode = cRecordCode;
}
public int getRecordDuration() {
return this.recordDuration;
}
public void setRecordDuration(int dRecordDuraion) {
this.recordDuration = dRecordDuraion;
}
public double getRecordDailyBasal() {
return this.recordDailyBasal;
}
public void setRecordDailyBasal(double dRecordDailyBasal) {
this.recordDailyBasal = dRecordDailyBasal;
}
public double getRecordDailyBolus() {
return this.recordDailyBolus;
}
public void setRecordDailyBolus(double dRecordDailyBolus) {
this.recordDailyBolus = dRecordDailyBolus;
}
public int getRecordLevel(double dExLow, double dLow, double dHigh, double dExHigh) {
if (this.recordValue < dExLow)
return 0;
if (this.recordValue < dLow)
return 1;
if (this.recordValue < dHigh)
return 2;
return this.recordValue < dExHigh ? 3 : 4;
}
public String getRecordAlarm() {
return this.recordAlarm;
}
public void setRecordAlarm(String strAlarm) {
this.recordAlarm = strAlarm;
}
public String get_id() {
return this._id;
}
public void set_id(String _id) {
this._id = _id;
}
public void setBytes(byte[] raw) {
this.bytes = bytesToHex(raw);
}
public void setBytes(String bytes) {
this.bytes = bytes;
}
public String getBytes() {
return this.bytes;
}
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}

View file

@ -0,0 +1,329 @@
package info.nightscout.androidaps.db;
import android.content.Context;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.text.Html;
import android.text.Spanned;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class);
public static final String DATABASE_NAME = "AndroidAPSDb";
public static final String DATABASE_BGREADINGS = "BgReadings";
public static final String DATABASE_TEMPBASALS = "TempBasals";
public static final String DATABASE_TREATMENTS = "Treatments";
public static final String DATABASE_DANARHISTORY = "DanaRHistory";
private static final int DATABASE_VERSION = 4;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
try {
log.info("onCreate");
TableUtils.createTableIfNotExists(connectionSource, TempBasal.class);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
} catch (SQLException e) {
log.error(DatabaseHelper.class.getName(), "Can't create database", e);
throw new RuntimeException(e);
}
}
@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
try {
log.info(DatabaseHelper.class.getName(), "onUpgrade");
TableUtils.dropTable(connectionSource, TempBasal.class, true);
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
onCreate(database, connectionSource);
} catch (SQLException e) {
log.error(DatabaseHelper.class.getName(), "Can't drop databases", e);
throw new RuntimeException(e);
}
}
/**
* Close the database connections and clear any cached DAOs.
*/
@Override
public void close() {
super.close();
}
public void cleanUpDatabases() {
// TODO: call it somewhere
log.debug("Before BgReadings size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_BGREADINGS));
getWritableDatabase().delete("BgReadings", "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
log.debug("After BgReadings size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_BGREADINGS));
log.debug("Before TempBasals size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPBASALS));
getWritableDatabase().delete("TempBasals", "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
log.debug("After TempBasals size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPBASALS));
log.debug("Before Treatments size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TREATMENTS));
getWritableDatabase().delete("Treatments", "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
log.debug("After Treatments size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TREATMENTS));
log.debug("Before History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), "DanaRHistory"));
getWritableDatabase().delete("History", "recordDate" + " < '" + (new Date().getTime() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), "DanaRHistory"));
}
public void resetDatabases() {
try {
TableUtils.dropTable(connectionSource, TempBasal.class, true);
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.createTableIfNotExists(connectionSource, TempBasal.class);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
// MainApp.bus().post(new EventNewBG());
// MainApp.bus().post(new EventTreatmentChange());
// MainApp.bus().post(new EventTempBasalChange());
} catch (SQLException e) {
e.printStackTrace();
}
}
public void resetTreatments() {
try {
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
} catch (SQLException e) {
e.printStackTrace();
}
}
public Dao<TempBasal, Long> getDaoTempBasals() throws SQLException {
return getDao(TempBasal.class);
}
public Dao<Treatment, Long> getDaoTreatments() throws SQLException {
return getDao(Treatment.class);
}
public Dao<BgReading, Long> getDaoBgReadings() throws SQLException {
return getDao(BgReading.class);
}
public Dao<DanaRHistoryRecord, String> getDaoDanaRHistory() throws SQLException {
return getDao(DanaRHistoryRecord.class);
}
/*
* Return last BgReading from database or null if db is empty
*/
@Nullable
public BgReading lastBg() {
List<BgReading> bgList = null;
try {
Dao<BgReading, Long> daoBgReadings = MainApp.getDbHelper().getDaoBgReadings();
QueryBuilder<BgReading, Long> queryBuilder = daoBgReadings.queryBuilder();
queryBuilder.orderBy("timeIndex", false);
queryBuilder.limit(1L);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgList = daoBgReadings.query(preparedQuery);
} catch (SQLException e) {
log.debug(e.getMessage(), e);
}
if (bgList != null && bgList.size() > 0)
return bgList.get(0);
else
return null;
}
/*
* Return bg reading if not old ( <9 min )
* or null if older
*/
@Nullable
public BgReading actualBg() {
BgReading lastBg = lastBg();
if (lastBg == null)
return null;
if (lastBg.timeIndex > new Date().getTime() - 9 * 60 * 1000)
return lastBg;
return null;
}
public List<BgReading> getDataFromTime(long mills) {
try {
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("timeIndex", true);
Where where = queryBuilder.where();
where.ge("timeIndex", mills);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
} catch (SQLException e) {
e.printStackTrace();
}
return new ArrayList<BgReading>();
}
/*
* Returns glucose_status for openAPS or null if no actual data available
*/
public static class GlucoseStatus implements Parcelable {
public double glucose = 0d;
public double delta = 0d;
public double avgdelta = 0d;
@Override
public String toString() {
return MainApp.sResources.getString(R.string.glucose) + " " + DecimalFormatter.to0Decimal(glucose) + " mg/dl\n" +
MainApp.sResources.getString(R.string.delta) + " " + DecimalFormatter.to0Decimal(delta) + " mg/dl\n" +
MainApp.sResources.getString(R.string.avgdelta) + " " + DecimalFormatter.to2Decimal(avgdelta) + " mg/dl";
}
public Spanned toSpanned() {
return Html.fromHtml("<b>" + MainApp.sResources.getString(R.string.glucose) + "</b>: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.delta) + "</b>: " + DecimalFormatter.to0Decimal(delta) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(avgdelta) + " mg/dl");
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeDouble(avgdelta);
dest.writeDouble(delta);
dest.writeDouble(glucose);
}
public final Parcelable.Creator<GlucoseStatus> CREATOR = new Parcelable.Creator<GlucoseStatus>() {
public GlucoseStatus createFromParcel(Parcel in) {
return new GlucoseStatus(in);
}
public GlucoseStatus[] newArray(int size) {
return new GlucoseStatus[size];
}
};
private GlucoseStatus(Parcel in) {
avgdelta = in.readDouble();
delta = in.readDouble();
glucose = in.readDouble();
}
public GlucoseStatus() {
}
public GlucoseStatus(Double glucose, Double delta, Double avgdelta) {
this.glucose = glucose;
this.delta = delta;
this.avgdelta = avgdelta;
}
public GlucoseStatus round() {
this.glucose = Round.roundTo(this.glucose, 0.1);
this.delta = Round.roundTo(this.delta, 0.01);
this.avgdelta = Round.roundTo(this.avgdelta, 0.01);
return this;
}
}
@Nullable
public GlucoseStatus getGlucoseStatusData() {
GlucoseStatus result = new GlucoseStatus();
try {
Dao<BgReading, Long> daoBgreadings = null;
daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("timeIndex", false);
queryBuilder.limit(4l);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
int sizeRecords = bgReadings.size();
if (sizeRecords < 4 || bgReadings.get(sizeRecords - 4).timeIndex < new Date().getTime() - 7 * 60 * 1000L) {
return null;
}
int minutes = 5;
double change;
double avg;
if (bgReadings.size() > 3) {
BgReading now = bgReadings.get(sizeRecords - 4);
BgReading last = bgReadings.get(sizeRecords - 3);
BgReading last1 = bgReadings.get(sizeRecords - 2);
BgReading last2 = bgReadings.get(sizeRecords - 1);
if (last2.value > 30) {
minutes = 3 * 5;
change = now.value - last2.value;
} else if (last1.value > 30) {
minutes = 2 * 5;
change = now.value - last1.value;
} else if (last.value > 30) {
minutes = 5;
change = now.value - last.value;
} else {
change = 0;
}
//multiply by 5 to get the same unit as delta, i.e. mg/dL/5m
avg = change / minutes * 5;
result.glucose = now.value;
result.delta = now.value - last.value;
result.avgdelta = avg;
}
} catch (SQLException e) {
e.printStackTrace();
return null;
}
result.round();
return result;
}
}

View file

@ -0,0 +1,206 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DecimalFormatter;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TEMPBASALS)
public class TempBasal {
private static Logger log = LoggerFactory.getLogger(TempBasal.class);
public long getTimeIndex() {
return timeStart.getTime();
}
public void setTimeIndex(long timeIndex) {
this.timeIndex = timeIndex;
}
@DatabaseField(id = true, useGetSet = true)
public long timeIndex;
@DatabaseField
public Date timeStart;
@DatabaseField
public Date timeEnd;
@DatabaseField
public int percent; // In % of current basal. 100% == current basal
@DatabaseField
public Double absolute; // Absolute value in U
@DatabaseField
public int duration; // in minutes
@DatabaseField
public boolean isExtended = false; // true if set as extended bolus
@DatabaseField
public boolean isAbsolute = false; // true if if set as absolute value in U
public IobTotal iobCalc(Date time) {
IobTotal result = new IobTotal();
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
if (profile == null)
return result;
int realDuration = getRealDuration();
if (realDuration > 0) {
Double netBasalRate = 0d;
Double basalRate = profile.getBasal(profile.secondsFromMidnight(time));
Double tempBolusSize = 0.05;
if (isExtended) {
netBasalRate = this.absolute;
} else {
if (this.isAbsolute) {
netBasalRate = this.absolute - basalRate;
} else {
netBasalRate = (this.percent - 100) / 100d * basalRate;
}
}
result.netRatio = netBasalRate;
Double netBasalAmount = Math.round(netBasalRate * realDuration * 10 / 6) / 100d;
result.netInsulin = netBasalAmount;
if (netBasalAmount < 0.1) {
tempBolusSize = 0.01;
}
if (netBasalRate < 0) {
tempBolusSize = -tempBolusSize;
}
Long tempBolusCount = Math.round(netBasalAmount / tempBolusSize);
if (tempBolusCount > 0) {
Long tempBolusSpacing = realDuration / tempBolusCount;
for (Long j = 0l; j < tempBolusCount; j++) {
Treatment tempBolusPart = new Treatment();
tempBolusPart.insulin = tempBolusSize;
Long date = this.timeStart.getTime() + j * tempBolusSpacing * 60 * 1000;
tempBolusPart.created_at = new Date(date);
Iob aIOB = tempBolusPart.iobCalc(time, profile.getDia());
result.basaliob += aIOB.iobContrib;
Double dia_ago = time.getTime() - profile.getDia() * 60 * 60 * 1000;
if (date > dia_ago && date <= time.getTime()) {
result.netbasalinsulin += tempBolusPart.insulin;
if (tempBolusPart.insulin > 0) {
result.hightempinsulin += tempBolusPart.insulin;
}
}
}
}
}
return result;
}
// Determine end of basal
public Date getTimeEnd() {
Date tempBasalTimePlannedEnd = getPlannedTimeEnd();
Date now = new Date();
if (timeEnd != null && timeEnd.getTime() < tempBasalTimePlannedEnd.getTime()) {
tempBasalTimePlannedEnd = timeEnd;
}
if (now.getTime() < tempBasalTimePlannedEnd.getTime())
tempBasalTimePlannedEnd = now;
return tempBasalTimePlannedEnd;
}
public Date getPlannedTimeEnd() {
return new Date(timeStart.getTime() + 60 * 1_000 * duration);
}
public int getRealDuration() {
Long msecs = getTimeEnd().getTime() - timeStart.getTime();
return (int) (msecs / 60 / 1000);
}
public long getMillisecondsFromStart() {
return new Date().getTime() - timeStart.getTime();
}
public int getPlannedRemainingMinutes() {
if (timeEnd != null) return 0;
long remainingMin = (getPlannedTimeEnd().getTime() - new Date().getTime()) / 1000 / 60;
return (remainingMin < 0) ? 0 : (int) remainingMin;
}
public boolean isInProgress() {
return isInProgress(new Date());
}
public double tempBasalConvertedToAbsolute(Date time) {
if (isExtended) {
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
double absval = profile.getBasal(NSProfile.secondsFromMidnight(time)) + absolute;
return absval;
} else {
if (isAbsolute) return absolute;
else {
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
double absval = profile.getBasal(NSProfile.secondsFromMidnight(time)) * percent / 100;
return absval;
}
}
}
public boolean isInProgress(Date time) {
if (timeStart.getTime() > time.getTime()) return false; // in the future
if (timeEnd == null) { // open end
if (timeStart.getTime() < time.getTime() && getPlannedTimeEnd().getTime() > time.getTime())
return true; // in interval
return false;
}
// closed end
if (timeStart.getTime() < time.getTime() && timeEnd.getTime() > time.getTime()) return true; // in interval
return false;
}
public String log() {
return "TempBasal{" +
"timeIndex=" + timeIndex +
", timeStart=" + timeStart +
", timeEnd=" + timeEnd +
", percent=" + percent +
", absolute=" + absolute +
", duration=" + duration +
", isAbsolute=" + isAbsolute +
", isExtended=" + isExtended +
'}';
}
public String toString() {
DateFormat formatDateToJustTime = new SimpleDateFormat("HH:mm");
String extended = isExtended ? "E " : "";
if (isAbsolute) {
return extended + DecimalFormatter.to2Decimal(absolute) + "U/h @" +
formatDateToJustTime.format(timeStart) +
" " + getRealDuration() + "/" + duration + "min";
} else { // percent
return percent + "% @" +
formatDateToJustTime.format(timeStart) +
" " + getRealDuration() + "/" + duration + "min";
}
}
}

View file

@ -0,0 +1,153 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.GraphSeriesExtension.DataPointWithLabelInterface;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TREATMENTS)
public class Treatment implements DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(Treatment.class);
public long getTimeIndex() {
return created_at.getTime();
}
public void setTimeIndex(long timeIndex) {
this.timeIndex = timeIndex;
}
@DatabaseField(id = true, useGetSet = true)
public long timeIndex;
@DatabaseField
public String _id;
@DatabaseField
public Date created_at;
@DatabaseField
public Double insulin = 0d;
@DatabaseField
public Double carbs = 0d;
@DatabaseField
public boolean mealBolus = true; // true for meal bolus , false for correction bolus
public void copyFrom(Treatment t) {
this._id = t._id;
this.created_at = t.created_at;
this.insulin = t.insulin;
this.carbs = t.carbs;
this.mealBolus = t.mealBolus;
}
public Iob iobCalc(Date time, Double dia) {
Iob result = new Iob();
Double scaleFactor = 3.0 / dia;
Double peak = 75d;
Double end = 180d;
if (this.insulin != 0d) {
Long bolusTime = this.created_at.getTime();
Double minAgo = scaleFactor * (time.getTime() - bolusTime) / 1000d / 60d;
if (minAgo < peak) {
Double x1 = minAgo / 5d + 1;
result.iobContrib = this.insulin * (1 - 0.001852 * x1 * x1 + 0.001852 * x1);
// units: BG (mg/dL) = (BG/U) * U insulin * scalar
result.activityContrib = this.insulin * (2 / dia / 60 / peak) * minAgo;
} else if (minAgo < end) {
Double x2 = (minAgo - 75) / 5;
result.iobContrib = this.insulin * (0.001323 * x2 * x2 - 0.054233 * x2 + 0.55556);
result.activityContrib = this.insulin * (2 / dia / 60 - (minAgo - peak) * 2 / dia / 60 / (60 * dia - peak));
}
}
return result;
}
public long getMillisecondsFromStart() {
return new Date().getTime() - created_at.getTime();
}
public String log() {
return "Treatment{" +
"timeIndex: " + timeIndex +
", _id: " + _id +
", insulin: " + insulin +
", carbs: " + carbs +
", mealBolus: " + mealBolus +
", created_at: " +
"}";
}
// DataPointInterface
@Override
public double getX() {
return timeIndex;
}
// default when no sgv around available
private double yValue = 0;
@Override
public double getY() {
return yValue;
}
@Override
public String getLabel() {
String label = "";
if (insulin > 0) label += DecimalFormatter.to2Decimal(insulin) + "U";
if (carbs > 0)
label += (label.equals("") ? "" : " ") + DecimalFormatter.to0Decimal(carbs) + "g";
return label;
}
public void setYValue(List<BgReading> bgReadingsArray) {
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
if (profile == null) return;
for (int r = bgReadingsArray.size() - 1; r >= 0; r--) {
BgReading reading = bgReadingsArray.get(r);
if (reading.timeIndex > timeIndex) continue;
yValue = NSProfile.fromMgdlToUnits(reading.value, profile.getUnits());
break;
}
}
public void sendToNSClient() {
JSONObject data = new JSONObject();
try {
if (mealBolus)
data.put("eventType", "Meal Bolus");
else
data.put("eventType", "Correction Bolus");
if (insulin != 0d) data.put("insulin", insulin);
if (carbs != 0d) data.put("carbs", carbs.intValue());
data.put("created_at", DateUtil.toISOString(created_at));
data.put("timeIndex", timeIndex);
} catch (JSONException e) {
e.printStackTrace();
}
ConfigBuilderPlugin.uploadCareportalEntryToNS(data);
}
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 07.07.2016.
*/
public class EventAppExit {
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 05.06.2016.
*/
public class EventNewBG {
}

View file

@ -0,0 +1,14 @@
package info.nightscout.androidaps.events;
import info.nightscout.client.data.NSProfile;
/**
* Created by mike on 04.06.2016.
*/
public class EventNewBasalProfile {
public NSProfile newNSProfile = null;
public EventNewBasalProfile(NSProfile newProfile) {
newNSProfile = newProfile;
}
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 19.06.2016.
*/
public class EventPreferenceChange {
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 13.06.2016.
*/
public class EventRefreshGui {
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 05.06.2016.
*/
public class EventTempBasalChange {
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 04.06.2016.
*/
public class EventTreatmentChange {
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.interfaces;
import java.util.Date;
import info.nightscout.androidaps.plugins.Loop.APSResult;
/**
* Created by mike on 10.06.2016.
*/
public interface APSInterface {
public APSResult getLastAPSResult();
public Date getLastAPSRun();
public void invoke();
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.interfaces;
/**
* Created by mike on 20.06.2016.
*/
public interface BgSourceInterface {
}

View file

@ -0,0 +1,28 @@
package info.nightscout.androidaps.interfaces;
import info.nightscout.androidaps.plugins.Loop.APSResult;
/**
* Created by mike on 15.06.2016.
*/
public interface ConstraintsInterface {
boolean isLoopEnabled();
boolean isClosedModeEnabled();
boolean isAutosensModeEnabled();
boolean isAMAModeEnabled();
Double applyBasalConstraints(Double absoluteRate);
Integer applyBasalConstraints(Integer percentRate);
Double applyBolusConstraints(Double insulin);
Integer applyCarbsConstraints(Integer carbs);
Double applyMaxIOBConstraints(Double maxIob);
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.interfaces;
/**
* Created by mike on 05.08.2016.
*/
public interface FragmentBase {
}

View file

@ -0,0 +1,29 @@
package info.nightscout.androidaps.interfaces;
import java.util.Date;
/**
* Created by mike on 09.06.2016.
*/
public interface PluginBase {
int GENERAL = 1;
int TREATMENT = 2;
int TEMPBASAL = 3;
int PROFILE = 4;
int APS = 5;
int PUMP = 6;
int CONSTRAINTS = 7;
int LOOP = 8;
int BGSOURCE = 9;
int LAST = 10; // keep always highest number
int getType();
String getFragmentClass();
String getName();
boolean isEnabled(int type);
boolean isVisibleInTabs(int type);
boolean canBeHidden(int type);
void setFragmentEnabled(int type, boolean fragmentEnabled);
void setFragmentVisible(int type, boolean fragmentVisible);
}

View file

@ -0,0 +1,13 @@
package info.nightscout.androidaps.interfaces;
import android.support.annotation.Nullable;
import info.nightscout.client.data.NSProfile;
/**
* Created by mike on 14.06.2016.
*/
public interface ProfileInterface {
@Nullable
NSProfile getProfile();
}

View file

@ -0,0 +1,43 @@
package info.nightscout.androidaps.interfaces;
import android.content.Context;
import org.json.JSONObject;
import java.util.Date;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.client.data.NSProfile;
/**
* Created by mike on 04.06.2016.
*/
public interface PumpInterface {
boolean isTempBasalInProgress();
boolean isExtendedBoluslInProgress();
// Upload to pump new basal profile
void setNewBasalProfile(NSProfile profile);
double getBaseBasalRate(); // base basal rate, not temp basal
double getTempBasalAbsoluteRate();
double getTempBasalRemainingMinutes();
TempBasal getTempBasal(Date time);
TempBasal getTempBasal();
TempBasal getExtendedBolus();
PumpEnactResult deliverTreatment(Double insulin, Integer carbs, Context context);
void stopBolusDelivering();
PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes);
PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes);
PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes);
PumpEnactResult cancelTempBasal();
PumpEnactResult cancelExtendedBolus();
// Status to be passed to NS
JSONObject getJSONStatus();
String deviceID();
}

View file

@ -0,0 +1,17 @@
package info.nightscout.androidaps.interfaces;
import java.util.Date;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
/**
* Created by mike on 14.06.2016.
*/
public interface TempBasalsInterface {
void updateTotalIOB();
IobTotal getLastCalculation();
TempBasal getTempBasal (Date time);
TempBasal getExtendedBolus (Date time);
}

View file

@ -0,0 +1,19 @@
package info.nightscout.androidaps.interfaces;
import java.util.List;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
/**
* Created by mike on 14.06.2016.
*/
public interface TreatmentsInterface {
void updateTotalIOB();
IobTotal getLastCalculation();
TreatmentsPlugin.MealData getMealData();
List<Treatment> getTreatments();
}

View file

@ -0,0 +1,175 @@
package info.nightscout.androidaps.plugins.Careportal;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.FragmentBase;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
public class CareportalFragment extends Fragment implements FragmentBase, View.OnClickListener {
static CareportalPlugin careportalPlugin = new CareportalPlugin();
static public CareportalPlugin getPlugin() {
return careportalPlugin;
}
public class OptionsToShow {
public int eventType;
public int eventName;
public boolean bg;
public boolean insulin;
public boolean carbs;
public boolean prebolus;
public boolean duration;
public boolean percent;
public boolean absolute;
public boolean profile;
public boolean split;
public OptionsToShow(int eventType,
int eventName,
boolean bg,
boolean insulin,
boolean carbs,
boolean prebolus,
boolean duration,
boolean percent,
boolean absolute,
boolean profile,
boolean split) {
this.eventType = eventType;
this.eventName = eventName;
this.bg = bg;
this.insulin = insulin;
this.carbs = carbs;
this.prebolus = prebolus;
this.duration = duration;
this.percent = percent;
this.absolute = absolute;
this.profile = profile;
this.split = split;
}
}
// bg,insulin,carbs,prebolus,duration,percent,absolute,profile,split
final OptionsToShow bgcheck = new OptionsToShow(R.id.careportal_bgcheck, R.string.careportal_bgcheck, true, true, true, false, false, false, false, false, false);
final OptionsToShow snackbolus = new OptionsToShow(R.id.careportal_snackbolus, R.string.careportal_snackbolus, true, true, true, true, false, false, false, false, false);
final OptionsToShow mealbolus = new OptionsToShow(R.id.careportal_mealbolus, R.string.careportal_mealbolus, true, true, true, true, false, false, false, false, false);
final OptionsToShow correctionbolus = new OptionsToShow(R.id.careportal_correctionbolus, R.string.careportal_correctionbolus, true, true, true, true, false, false, false, false, false);
final OptionsToShow carbcorrection = new OptionsToShow(R.id.careportal_carbscorrection, R.string.careportal_carbscorrection, true, false, true, false, false, false, false, false, false);
final OptionsToShow combobolus = new OptionsToShow(R.id.careportal_combobolus, R.string.careportal_combobolus, true, true, true, true, true, false, false, false, true);
final OptionsToShow announcement = new OptionsToShow(R.id.careportal_announcement, R.string.careportal_announcement, true, false, false, false, false, false, false, false, false);
final OptionsToShow note = new OptionsToShow(R.id.careportal_note, R.string.careportal_note, true, false, false, false, true, false, false, false, false);
final OptionsToShow question = new OptionsToShow(R.id.careportal_question, R.string.careportal_question, true, false, false, false, false, false, false, false, false);
final OptionsToShow exercise = new OptionsToShow(R.id.careportal_exercise, R.string.careportal_exercise, false, false, false, false, true, false, false, false, false);
final OptionsToShow sitechange = new OptionsToShow(R.id.careportal_pumpsitechange, R.string.careportal_pumpsitechange, true, true, false, false, false, false, false, false, false);
final OptionsToShow sensorstart = new OptionsToShow(R.id.careportal_cgmsensorstart, R.string.careportal_cgmsensorstart, true, false, false, false, false, false, false, false, false);
final OptionsToShow sensorchange = new OptionsToShow(R.id.careportal_cgmsensorinsert, R.string.careportal_cgmsensorinsert, true, false, false, false, false, false, false, false, false);
final OptionsToShow insulinchange = new OptionsToShow(R.id.careportal_insulincartridgechange, R.string.careportal_insulincartridgechange, true, false, false, false, false, false, false, false, false);
final OptionsToShow tempbasalstart = new OptionsToShow(R.id.careportal_tempbasalstart, R.string.careportal_tempbasalstart, true, false, false, false, true, true, true, false, false);
final OptionsToShow tempbasalend = new OptionsToShow(R.id.careportal_tempbasalend, R.string.careportal_tempbasalend, true, false, false, false, false, false, false, false, false);
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false);
final OptionsToShow openapsoffline = new OptionsToShow(R.id.careportal_openapsoffline, R.string.careportal_openapsoffline, false, false, false, false, true, false, false, false, false);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.careportal_fragment, container, false);
view.findViewById(R.id.careportal_bgcheck).setOnClickListener(this);
view.findViewById(R.id.careportal_announcement).setOnClickListener(this);
view.findViewById(R.id.careportal_cgmsensorinsert).setOnClickListener(this);
view.findViewById(R.id.careportal_cgmsensorstart).setOnClickListener(this);
view.findViewById(R.id.careportal_combobolus).setOnClickListener(this);
view.findViewById(R.id.careportal_correctionbolus).setOnClickListener(this);
view.findViewById(R.id.careportal_carbscorrection).setOnClickListener(this);
view.findViewById(R.id.careportal_exercise).setOnClickListener(this);
view.findViewById(R.id.careportal_insulincartridgechange).setOnClickListener(this);
view.findViewById(R.id.careportal_mealbolus).setOnClickListener(this);
view.findViewById(R.id.careportal_note).setOnClickListener(this);
view.findViewById(R.id.careportal_profileswitch).setOnClickListener(this);
view.findViewById(R.id.careportal_pumpsitechange).setOnClickListener(this);
view.findViewById(R.id.careportal_question).setOnClickListener(this);
view.findViewById(R.id.careportal_snackbolus).setOnClickListener(this);
view.findViewById(R.id.careportal_tempbasalend).setOnClickListener(this);
view.findViewById(R.id.careportal_tempbasalstart).setOnClickListener(this);
view.findViewById(R.id.careportal_openapsoffline).setOnClickListener(this);
return view;
}
@Override
public void onClick(View view) {
FragmentManager manager = getFragmentManager();
NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog();
switch (view.getId()) {
case R.id.careportal_bgcheck:
newDialog.setOptions(bgcheck);
break;
case R.id.careportal_announcement:
newDialog.setOptions(announcement);
break;
case R.id.careportal_cgmsensorinsert:
newDialog.setOptions(sensorchange);
break;
case R.id.careportal_cgmsensorstart:
newDialog.setOptions(sensorstart);
break;
case R.id.careportal_combobolus:
newDialog.setOptions(combobolus);
break;
case R.id.careportal_correctionbolus:
newDialog.setOptions(correctionbolus);
break;
case R.id.careportal_carbscorrection:
newDialog.setOptions(carbcorrection);
break;
case R.id.careportal_exercise:
newDialog.setOptions(exercise);
break;
case R.id.careportal_insulincartridgechange:
newDialog.setOptions(insulinchange);
break;
case R.id.careportal_mealbolus:
newDialog.setOptions(mealbolus);
break;
case R.id.careportal_note:
newDialog.setOptions(note);
break;
case R.id.careportal_profileswitch:
newDialog.setOptions(profileswitch);
break;
case R.id.careportal_pumpsitechange:
newDialog.setOptions(sitechange);
break;
case R.id.careportal_question:
newDialog.setOptions(question);
break;
case R.id.careportal_snackbolus:
newDialog.setOptions(snackbolus);
break;
case R.id.careportal_tempbasalstart:
newDialog.setOptions(tempbasalstart);
break;
case R.id.careportal_tempbasalend:
newDialog.setOptions(tempbasalend);
break;
case R.id.careportal_openapsoffline:
newDialog.setOptions(openapsoffline);
break;
default:
newDialog = null;
}
if (newDialog != null)
newDialog.show(manager, "NewNSTreatmentDialog");
}
}

View file

@ -0,0 +1,52 @@
package info.nightscout.androidaps.plugins.Careportal;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase;
public class CareportalPlugin implements PluginBase {
boolean fragmentEnabled = true;
boolean fragmentVisible = true;
@Override
public int getType() {
return PluginBase.GENERAL;
}
@Override
public String getFragmentClass() {
return CareportalFragment.class.getName();
}
@Override
public String getName() {
return MainApp.sResources.getString(R.string.careportal);
}
@Override
public boolean isEnabled(int type) {
return fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
this.fragmentVisible = fragmentVisible;
}
}

View file

@ -0,0 +1,541 @@
package info.nightscout.androidaps.plugins.Careportal.Dialogs;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.TextView;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.plugins.Careportal.CareportalFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.NewExtendedBolusDialog;
import info.nightscout.client.data.DbLogger;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.PlusMinusEditText;
import info.nightscout.utils.SafeParse;
import info.nightscout.utils.ToastUtils;
import info.nightscout.utils.Translator;
public class NewNSTreatmentDialog extends DialogFragment implements View.OnClickListener, DatePickerDialog.OnDateSetListener, TimePickerDialog.OnTimeSetListener {
private static Logger log = LoggerFactory.getLogger(NewNSTreatmentDialog.class);
private FragmentActivity context;
private static CareportalFragment.OptionsToShow options;
NSProfile profile;
String units;
LinearLayout layoutBg;
LinearLayout layoutBgSource;
LinearLayout layoutInsulin;
LinearLayout layoutCarbs;
LinearLayout layoutSplit;
LinearLayout layoutDuration;
LinearLayout layoutPercent;
LinearLayout layoutAbsolute;
LinearLayout layoutCarbTime;
LinearLayout layoutProfile;
Button dateButton;
Button timeButton;
Button okButton;
TextView bgUnitsView;
RadioButton meterRadioButton;
RadioButton sensorRadioButton;
RadioButton otherRadioButton;
EditText notesEdit;
EditText bgInputEdit;
EditText insulinEdit;
EditText carbsEdit;
EditText percentEdit;
EditText absoluteEdit;
EditText durationeEdit;
EditText carbTimeEdit;
EditText splitEdit;
Spinner profileSpinner;
PlusMinusEditText editBg;
PlusMinusEditText editCarbs;
PlusMinusEditText editInsulin;
PlusMinusEditText editSplit;
PlusMinusEditText editDuration;
PlusMinusEditText editPercent;
PlusMinusEditText editAbsolute;
PlusMinusEditText editCarbTime;
Date eventTime;
public void setOptions(CareportalFragment.OptionsToShow options) {
this.options = options;
}
@Override
public void onAttach(Activity activity) {
context = (FragmentActivity) activity;
super.onAttach(activity);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getDialog().setTitle(getString(options.eventName));
View view = inflater.inflate(R.layout.careportal_newnstreatment_dialog, container, false);
layoutBg = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_bg_layout);
layoutBgSource = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_bgsource_layout);
layoutInsulin = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_insulin_layout);
layoutCarbs = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_carbs_layout);
layoutSplit = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_split_layout);
layoutDuration = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_duration_layout);
layoutPercent = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_percent_layout);
layoutAbsolute = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_absolute_layout);
layoutCarbTime = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_carbtime_layout);
layoutProfile = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_profile_layout);
bgUnitsView = (TextView) view.findViewById(R.id.careportal_newnstreatment_bgunits);
meterRadioButton = (RadioButton) view.findViewById(R.id.careportal_newnstreatment_meter);
sensorRadioButton = (RadioButton) view.findViewById(R.id.careportal_newnstreatment_sensor);
otherRadioButton = (RadioButton) view.findViewById(R.id.careportal_newnstreatment_other);
profileSpinner = (Spinner) view.findViewById(R.id.careportal_newnstreatment_profile);
bgInputEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_bginput);
insulinEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_insulininput);
carbsEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_carbsinput);
percentEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_percentinput);
percentEdit.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
layoutPercent.setVisibility(View.VISIBLE);
layoutAbsolute.setVisibility(View.GONE);
}
});
absoluteEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_absoluteinput);
absoluteEdit.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
layoutPercent.setVisibility(View.GONE);
layoutAbsolute.setVisibility(View.VISIBLE);
}
});
durationeEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_durationinput);
carbTimeEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_carbtimeinput);
notesEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_notes);
splitEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_splitinput);
eventTime = new Date();
dateButton = (Button) view.findViewById(R.id.careportal_newnstreatment_eventdate);
timeButton = (Button) view.findViewById(R.id.careportal_newnstreatment_eventtime);
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
DateFormat tf = DateFormat.getTimeInstance(DateFormat.SHORT);
dateButton.setText(df.format(eventTime));
timeButton.setText(tf.format(eventTime));
dateButton.setOnClickListener(this);
timeButton.setOnClickListener(this);
okButton = (Button) view.findViewById(R.id.careportal_newnstreatment_ok);
okButton.setOnClickListener(this);
// BG
profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
ArrayList<CharSequence> profileList;
units = Constants.MGDL;
if (profile == null) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), context.getString(R.string.noprofile));
profileList = new ArrayList<CharSequence>();
} else {
units = profile.getUnits();
profileList = profile.getProfileList();
}
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(),
android.R.layout.simple_spinner_item, profileList);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
profileSpinner.setAdapter(adapter);
if (profile != null) {
// set selected to actual profile
for (int p = 0; p < profileList.size(); p++) {
if (profileList.get(p).equals(profile.getActiveProfile()))
profileSpinner.setSelection(p);
}
}
bgUnitsView.setText(units);
// Set BG if not old
// BgReading lastBg = MainApp.getDbHelper().lastBg();
// Double lastBgValue = 0d;
// if (lastBg != null) {
// lastBgValue = lastBg.valueToUnits(units);
// sensorRadioButton.setChecked(true);
// } else {
// meterRadioButton.setChecked(true);
// }
if (units.equals(Constants.MMOL))
editBg = new PlusMinusEditText(view, R.id.careportal_newnstreatment_bginput, R.id.careportal_newnstreatment_bg_plus, R.id.careportal_newnstreatment_bg_minus, 0d, 0d, 40d, 0.1d, new DecimalFormat("0.0"), false);
else
editBg = new PlusMinusEditText(view, R.id.careportal_newnstreatment_bginput, R.id.careportal_newnstreatment_bg_plus, R.id.careportal_newnstreatment_bg_minus, 0d, 0d, 500d, 1d, new DecimalFormat("0"), false);
Integer maxCarbs = MainApp.getConfigBuilder().applyCarbsConstraints(Constants.carbsOnlyForCheckLimit);
editCarbs = new PlusMinusEditText(view, R.id.careportal_newnstreatment_carbsinput, R.id.careportal_newnstreatment_carbs_plus, R.id.careportal_newnstreatment_carbs_minus, 0d, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false);
Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit);
editInsulin = new PlusMinusEditText(view, R.id.careportal_newnstreatment_insulininput, R.id.careportal_newnstreatment_insulin_plus, R.id.careportal_newnstreatment_insulin_minus, 0d, 0d, maxInsulin, 0.05d, new DecimalFormat("0.00"), false);
editSplit = new PlusMinusEditText(view, R.id.careportal_newnstreatment_splitinput, R.id.careportal_newnstreatment_split_plus, R.id.careportal_newnstreatment_split_minus, 100d, 0d, 100d, 5d, new DecimalFormat("0"), true);
editDuration = new PlusMinusEditText(view, R.id.careportal_newnstreatment_durationinput, R.id.careportal_newnstreatment_duration_plus, R.id.careportal_newnstreatment_duration_minus, 0d, 0d, 24 * 60d, 10d, new DecimalFormat("0"), false);
Integer maxPercent = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalPercentOnlyForCheckLimit);
editPercent = new PlusMinusEditText(view, R.id.careportal_newnstreatment_percentinput, R.id.careportal_newnstreatment_percent_plus, R.id.careportal_newnstreatment_percent_minus, 0d, 0d, (double) maxPercent, 5d, new DecimalFormat("0"), true);
Double maxAbsolute = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalAbsoluteOnlyForCheckLimit);
editAbsolute = new PlusMinusEditText(view, R.id.careportal_newnstreatment_absoluteinput, R.id.careportal_newnstreatment_absolute_plus, R.id.careportal_newnstreatment_absolute_minus, 0d, 0d, maxAbsolute, 0.05d, new DecimalFormat("0.00"), true);
editCarbTime = new PlusMinusEditText(view, R.id.careportal_newnstreatment_carbtimeinput, R.id.careportal_newnstreatment_carbtime_plus, R.id.careportal_newnstreatment_carbtime_minus, 0d, -60d, 60d, 5d, new DecimalFormat("0"), false);
showOrHide(layoutBg, options.bg);
showOrHide(layoutBgSource, options.bg);
showOrHide(layoutInsulin, options.insulin);
showOrHide(layoutCarbs, options.carbs);
showOrHide(layoutSplit, options.split);
showOrHide(layoutDuration, options.duration);
showOrHide(layoutPercent, options.percent);
showOrHide(layoutAbsolute, options.absolute);
showOrHide(layoutCarbTime, options.prebolus);
showOrHide(layoutProfile, options.profile);
return view;
}
@Override
public void onResume() {
super.onResume();
if (getDialog() != null)
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public void onClick(View view) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(eventTime);
switch (view.getId()) {
case R.id.careportal_newnstreatment_eventdate:
DatePickerDialog dpd = DatePickerDialog.newInstance(
this,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
);
dpd.setThemeDark(true);
dpd.dismissOnPause(true);
dpd.show(context.getFragmentManager(), "Datepickerdialog");
break;
case R.id.careportal_newnstreatment_eventtime:
android.text.format.DateFormat df = new android.text.format.DateFormat();
TimePickerDialog tpd = TimePickerDialog.newInstance(
this,
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
df.is24HourFormat(context)
);
tpd.setThemeDark(true);
tpd.dismissOnPause(true);
tpd.show(context.getFragmentManager(), "Timepickerdialog");
break;
case R.id.careportal_newnstreatment_ok:
createNSTreatment();
dismiss();
break;
}
}
private void showOrHide(LinearLayout layout, boolean visible) {
if (visible) layout.setVisibility(View.VISIBLE);
else layout.setVisibility(View.GONE);
}
@Override
public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
eventTime.setYear(year - 1900);
eventTime.setMonth(monthOfYear);
eventTime.setDate(dayOfMonth);
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
dateButton.setText(df.format(eventTime));
}
@Override
public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute, int second) {
eventTime.setHours(hourOfDay);
eventTime.setMinutes(minute);
eventTime.setSeconds(second);
DateFormat tf = DateFormat.getTimeInstance(DateFormat.SHORT);
timeButton.setText(tf.format(eventTime));
}
JSONObject gatherData() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
String enteredBy = SP.getString("careportal_enteredby", "");
JSONObject data = new JSONObject();
try {
data.put("created_at", DateUtil.toISOString(eventTime));
switch (options.eventType) {
case R.id.careportal_bgcheck:
data.put("eventType", "BG Check");
break;
case R.id.careportal_announcement:
data.put("eventType", "Announcement");
data.put("isAnnouncement", true);
break;
case R.id.careportal_cgmsensorinsert:
data.put("eventType", "Sensor Change");
break;
case R.id.careportal_cgmsensorstart:
data.put("eventType", "Sensor Start");
break;
case R.id.careportal_combobolus:
data.put("splitNow", SafeParse.stringToDouble(splitEdit.getText().toString()));
data.put("splitExt", 100 - SafeParse.stringToDouble(splitEdit.getText().toString()));
data.put("eventType", "Combo Bolus");
break;
case R.id.careportal_correctionbolus:
data.put("eventType", "Correction Bolus");
break;
case R.id.careportal_carbscorrection:
data.put("eventType", "Carb Correction");
break;
case R.id.careportal_exercise:
data.put("eventType", "Exercise");
break;
case R.id.careportal_insulincartridgechange:
data.put("eventType", "Insulin Change");
break;
case R.id.careportal_mealbolus:
data.put("eventType", "Meal Bolus");
break;
case R.id.careportal_note:
data.put("eventType", "Note");
break;
case R.id.careportal_profileswitch:
data.put("eventType", "Profile Switch");
break;
case R.id.careportal_pumpsitechange:
data.put("eventType", "Site Change");
break;
case R.id.careportal_question:
data.put("eventType", "Question");
break;
case R.id.careportal_snackbolus:
data.put("eventType", "Snack Bolus");
break;
case R.id.careportal_tempbasalstart:
data.put("eventType", "Temp Basal");
break;
case R.id.careportal_tempbasalend:
data.put("eventType", "Temp Basal");
break;
case R.id.careportal_openapsoffline:
data.put("eventType", "OpenAPS Offline");
break;
}
if (SafeParse.stringToDouble(bgInputEdit.getText().toString()) != 0d) {
data.put("glucose", SafeParse.stringToDouble(bgInputEdit.getText().toString()));
if (meterRadioButton.isChecked()) data.put("glucoseType", "Finger");
if (sensorRadioButton.isChecked()) data.put("glucoseType", "Sensor");
if (otherRadioButton.isChecked()) data.put("glucoseType", "Manual");
}
if (SafeParse.stringToDouble(carbsEdit.getText().toString()) != 0d)
data.put("carbs", SafeParse.stringToDouble(carbsEdit.getText().toString()));
if (SafeParse.stringToDouble(insulinEdit.getText().toString()) != 0d)
data.put("insulin", SafeParse.stringToDouble(insulinEdit.getText().toString()));
if (SafeParse.stringToDouble(durationeEdit.getText().toString()) != 0d)
data.put("duration", SafeParse.stringToDouble(durationeEdit.getText().toString()));
if (layoutPercent.getVisibility() != View.GONE)
data.put("percent", SafeParse.stringToDouble(percentEdit.getText().toString()));
if (layoutAbsolute.getVisibility() != View.GONE)
data.put("absolute", SafeParse.stringToDouble(absoluteEdit.getText().toString()));
if (options.profile && profileSpinner.getSelectedItem() != null)
data.put("profile", profileSpinner.getSelectedItem().toString());
if (SafeParse.stringToDouble(carbTimeEdit.getText().toString()) != 0d)
data.put("preBolus", SafeParse.stringToDouble(carbTimeEdit.getText().toString()));
if (!notesEdit.getText().toString().equals(""))
data.put("notes", notesEdit.getText().toString());
data.put("units", units);
if (!enteredBy.equals("")) data.put("enteredBy", enteredBy);
if (options.eventType == R.id.careportal_combobolus) {
Double enteredInsulin = SafeParse.stringToDouble(insulinEdit.getText().toString());
data.put("enteredinsulin", enteredInsulin);
data.put("insulin", enteredInsulin * SafeParse.stringToDouble(splitEdit.getText().toString()) / 100);
data.put("relative", enteredInsulin * (100 - SafeParse.stringToDouble(splitEdit.getText().toString())) / 100 / SafeParse.stringToDouble(durationeEdit.getText().toString()) * 60);
}
} catch (JSONException e) {
e.printStackTrace();
}
return data;
}
String buildConfirmText(JSONObject data) {
String ret = "";
try {
if (data.has("eventType")) {
ret += getString(R.string.careportal_newnstreatment_eventtype);
ret += ": ";
ret += Translator.translate(data.getString("eventType"));
ret += "\n";
}
if (data.has("glucose")) {
ret += getString(R.string.treatments_wizard_bg_label);
ret += ": ";
ret += data.get("glucose");
ret += " " + units + "\n";
}
if (data.has("glucoseType")) {
ret += getString(R.string.careportal_newnstreatment_glucosetype);
ret += ": ";
ret += Translator.translate(data.getString("glucoseType"));
ret += "\n";
}
if (data.has("carbs")) {
ret += getString(R.string.careportal_newnstreatment_carbs_label);
ret += ": ";
ret += data.get("carbs");
ret += " g\n";
}
if (data.has("insulin")) {
ret += getString(R.string.careportal_newnstreatment_insulin_label);
ret += ": ";
ret += data.get("insulin");
ret += " U\n";
}
if (data.has("duration")) {
ret += getString(R.string.careportal_newnstreatment_duration_label);
ret += ": ";
ret += data.get("duration");
ret += " min\n";
}
if (data.has("percent")) {
ret += getString(R.string.careportal_newnstreatment_percent_label);
ret += ": ";
ret += data.get("percent");
ret += " %\n";
}
if (data.has("absolute")) {
ret += getString(R.string.careportal_newnstreatment_absolute_label);
ret += ": ";
ret += data.get("absolute");
ret += " U/h\n";
}
if (data.has("preBolus")) {
ret += getString(R.string.careportal_newnstreatment_carbtime_label);
ret += ": ";
ret += data.get("preBolus");
ret += " min\n";
}
if (data.has("notes")) {
ret += getString(R.string.careportal_newnstreatment_notes_label);
ret += ": ";
ret += data.get("notes");
ret += "\n";
}
if (data.has("profile")) {
ret += getString(R.string.careportal_newnstreatment_profile_label);
ret += ": ";
ret += data.get("profile");
ret += "\n";
}
if (data.has("created_at")) {
ret += getString(R.string.careportal_newnstreatment_eventtime_label);
ret += ": ";
ret += eventTime.toLocaleString();
ret += "\n";
}
if (data.has("enteredBy")) {
ret += getString(R.string.careportal_newnstreatment_enteredby_title);
ret += ": ";
ret += data.get("enteredBy");
ret += "\n";
}
} catch (JSONException e) {
e.printStackTrace();
}
return ret;
}
void createNSTreatment() {
final JSONObject data = gatherData();
String confirmText = buildConfirmText(data);
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(getContext().getString(R.string.confirmation));
builder.setMessage(confirmText);
builder.setPositiveButton(getContext().getString(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ConfigBuilderPlugin.uploadCareportalEntryToNS(data);
}
});
builder.setNegativeButton(getContext().getString(R.string.cancel), null);
builder.show();
}
}

View file

@ -0,0 +1,306 @@
package info.nightscout.androidaps.plugins.ConfigBuilder;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.FragmentBase;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.TempBasalsInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.plugins.Loop.LoopFragment;
public class ConfigBuilderFragment extends Fragment implements FragmentBase {
static ConfigBuilderPlugin configBuilderPlugin = new ConfigBuilderPlugin();
static public ConfigBuilderPlugin getPlugin() {
return configBuilderPlugin;
}
ListView bgsourceListView;
ListView pumpListView;
ListView loopListView;
TextView loopLabel;
ListView treatmentsListView;
ListView tempsListView;
ListView profileListView;
ListView apsListView;
TextView apsLabel;
ListView constraintsListView;
ListView generalListView;
TextView nsclientVerView;
TextView nightscoutVerView;
PluginCustomAdapter bgsourceDataAdapter = null;
PluginCustomAdapter pumpDataAdapter = null;
PluginCustomAdapter loopDataAdapter = null;
PluginCustomAdapter treatmentsDataAdapter = null;
PluginCustomAdapter tempsDataAdapter = null;
PluginCustomAdapter profileDataAdapter = null;
PluginCustomAdapter apsDataAdapter = null;
PluginCustomAdapter constraintsDataAdapter = null;
PluginCustomAdapter generalDataAdapter = null;
// TODO: sorting
// TODO: Toast and sound when command failed
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.configbuilder_fragment, container, false);
bgsourceListView = (ListView) view.findViewById(R.id.configbuilder_bgsourcelistview);
pumpListView = (ListView) view.findViewById(R.id.configbuilder_pumplistview);
loopListView = (ListView) view.findViewById(R.id.configbuilder_looplistview);
loopLabel = (TextView) view.findViewById(R.id.configbuilder_looplabel);
treatmentsListView = (ListView) view.findViewById(R.id.configbuilder_treatmentslistview);
tempsListView = (ListView) view.findViewById(R.id.configbuilder_tempslistview);
profileListView = (ListView) view.findViewById(R.id.configbuilder_profilelistview);
apsListView = (ListView) view.findViewById(R.id.configbuilder_apslistview);
apsLabel = (TextView) view.findViewById(R.id.configbuilder_apslabel);
constraintsListView = (ListView) view.findViewById(R.id.configbuilder_constraintslistview);
generalListView = (ListView) view.findViewById(R.id.configbuilder_generallistview);
nsclientVerView = (TextView) view.findViewById(R.id.configbuilder_nsclientversion);
nightscoutVerView = (TextView) view.findViewById(R.id.configbuilder_nightscoutversion);
nsclientVerView.setText(ConfigBuilderPlugin.nsClientVersionName);
nightscoutVerView.setText(ConfigBuilderPlugin.nightscoutVersionName);
if (ConfigBuilderPlugin.nsClientVersionCode < 117) nsclientVerView.setTextColor(Color.RED);
if (ConfigBuilderPlugin.nightscoutVersionCode < 900) nightscoutVerView.setTextColor(Color.RED);
setViews();
return view;
}
void setViews() {
bgsourceDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class), PluginBase.BGSOURCE);
bgsourceListView.setAdapter(bgsourceDataAdapter);
setListViewHeightBasedOnChildren(bgsourceListView);
pumpDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsList(PluginBase.PUMP), PluginBase.PUMP);
pumpListView.setAdapter(pumpDataAdapter);
setListViewHeightBasedOnChildren(pumpListView);
loopDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsList(PluginBase.LOOP), PluginBase.LOOP);
loopListView.setAdapter(loopDataAdapter);
setListViewHeightBasedOnChildren(loopListView);
if (MainApp.getSpecificPluginsList(PluginBase.LOOP).size() == 0)
loopLabel.setVisibility(View.GONE);
treatmentsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsList(PluginBase.TREATMENT), PluginBase.TREATMENT);
treatmentsListView.setAdapter(treatmentsDataAdapter);
setListViewHeightBasedOnChildren(treatmentsListView);
tempsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsList(PluginBase.TEMPBASAL), PluginBase.TEMPBASAL);
tempsListView.setAdapter(tempsDataAdapter);
setListViewHeightBasedOnChildren(tempsListView);
profileDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsListByInterface(ProfileInterface.class), PluginBase.PROFILE);
profileListView.setAdapter(profileDataAdapter);
setListViewHeightBasedOnChildren(profileListView);
apsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsList(PluginBase.APS), PluginBase.APS);
apsListView.setAdapter(apsDataAdapter);
setListViewHeightBasedOnChildren(apsListView);
if (MainApp.getSpecificPluginsList(PluginBase.APS).size() == 0)
apsLabel.setVisibility(View.GONE);
constraintsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class), PluginBase.CONSTRAINTS);
constraintsListView.setAdapter(constraintsDataAdapter);
setListViewHeightBasedOnChildren(constraintsListView);
generalDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsList(PluginBase.GENERAL), PluginBase.GENERAL);
generalListView.setAdapter(generalDataAdapter);
setListViewHeightBasedOnChildren(generalListView);
}
/*
* ConfigBuilderFragment code
*/
private class PluginCustomAdapter extends ArrayAdapter<PluginBase> {
private ArrayList<PluginBase> pluginList;
final private int type;
public PluginCustomAdapter(Context context, int textViewResourceId,
ArrayList<PluginBase> pluginList, int type) {
super(context, textViewResourceId, pluginList);
this.pluginList = new ArrayList<PluginBase>();
this.pluginList.addAll(pluginList);
this.type = type;
}
private class PluginViewHolder {
TextView name;
CheckBox checkboxEnabled;
CheckBox checkboxVisible;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
PluginViewHolder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.configbuilder_simpleitem, null);
holder = new PluginViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.configbuilder_simpleitem_name);
holder.checkboxEnabled = (CheckBox) convertView.findViewById(R.id.configbuilder_simpleitem_checkboxenabled);
holder.checkboxVisible = (CheckBox) convertView.findViewById(R.id.configbuilder_simpleitem_checkboxvisible);
convertView.setTag(holder);
holder.checkboxEnabled.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v;
PluginBase plugin = (PluginBase) cb.getTag();
plugin.setFragmentEnabled(type, cb.isChecked());
plugin.setFragmentVisible(type, cb.isChecked());
onEnabledCategoryChanged(plugin, type);
configBuilderPlugin.storeSettings();
MainApp.bus().post(new EventRefreshGui());
}
});
holder.checkboxVisible.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v;
PluginBase plugin = (PluginBase) cb.getTag();
plugin.setFragmentVisible(type, cb.isChecked());
configBuilderPlugin.storeSettings();
MainApp.bus().post(new EventRefreshGui());
}
});
} else {
holder = (PluginViewHolder) convertView.getTag();
}
PluginBase plugin = pluginList.get(position);
holder.name.setText(plugin.getName());
holder.checkboxEnabled.setChecked(plugin.isEnabled(type));
holder.checkboxVisible.setChecked(plugin.isVisibleInTabs(type));
holder.name.setTag(plugin);
holder.checkboxEnabled.setTag(plugin);
holder.checkboxVisible.setTag(plugin);
if (!plugin.canBeHidden(type)) {
holder.checkboxEnabled.setEnabled(false);
holder.checkboxVisible.setEnabled(false);
}
int type = plugin.getType();
// Force enabled if there is only one plugin
if (type == PluginBase.PUMP || type == PluginBase.TREATMENT || type == PluginBase.TEMPBASAL || type == PluginBase.PROFILE)
if (pluginList.size() < 2)
holder.checkboxEnabled.setEnabled(false);
// Constraints cannot be disabled
if (type == PluginBase.CONSTRAINTS)
holder.checkboxEnabled.setEnabled(false);
// Hide disabled profiles by default
if (type == PluginBase.PROFILE) {
if (!plugin.isEnabled(type)) {
holder.checkboxVisible.setEnabled(false);
holder.checkboxVisible.setChecked(false);
} else {
holder.checkboxVisible.setEnabled(true);
}
}
return convertView;
}
}
void onEnabledCategoryChanged(PluginBase changedPlugin, int type) {
int category = changedPlugin.getType();
ArrayList<PluginBase> pluginsInCategory = null;
switch (category) {
// Multiple selection allowed
case PluginBase.GENERAL:
case PluginBase.CONSTRAINTS:
case PluginBase.LOOP:
break;
// Single selection allowed
case PluginBase.APS:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class);
break;
case PluginBase.PROFILE:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class);
break;
case PluginBase.BGSOURCE:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class);
break;
case PluginBase.TEMPBASAL:
case PluginBase.TREATMENT:
case PluginBase.PUMP:
pluginsInCategory = MainApp.getSpecificPluginsList(category);
break;
}
if (pluginsInCategory != null) {
boolean newSelection = changedPlugin.isEnabled(type);
if (newSelection) { // new plugin selected -> disable others
for (PluginBase p : pluginsInCategory) {
if (p.getName().equals(changedPlugin.getName())) {
// this is new selected
} else {
p.setFragmentEnabled(type, false);
p.setFragmentVisible(type, false);
}
}
} else { // enable first plugin in list
pluginsInCategory.get(0).setFragmentEnabled(type, true);
}
setViews();
}
}
/****
* Method for Setting the Height of the ListView dynamically.
* *** Hack to fix the issue of not showing all the items of the ListView
* *** when placed inside a ScrollView
****/
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null)
return;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.UNSPECIFIED);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0)
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, ViewGroup.LayoutParams.WRAP_CONTENT));
view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
}

View file

@ -0,0 +1,903 @@
package info.nightscout.androidaps.plugins.ConfigBuilder;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import com.squareup.otto.Subscribe;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventTempBasalChange;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.TempBasalsInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.androidaps.plugins.Loop.DeviceStatus;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.DetermineBasalResult;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
import info.nightscout.androidaps.plugins.Overview.Dialogs.NewExtendedBolusDialog;
import info.nightscout.client.data.DbLogger;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
/**
* Created by mike on 05.08.2016.
*/
public class ConfigBuilderPlugin implements PluginBase, PumpInterface, ConstraintsInterface {
private static Logger log = LoggerFactory.getLogger(ConfigBuilderPlugin.class);
static BgSourceInterface activeBgSource;
static PumpInterface activePump;
static ProfileInterface activeProfile;
static TreatmentsInterface activeTreatments;
static TempBasalsInterface activeTempBasals;
static APSInterface activeAPS;
static LoopPlugin activeLoop;
static public String nightscoutVersionName = "";
static public Integer nightscoutVersionCode = 0;
static public String nsClientVersionName = "";
static public Integer nsClientVersionCode = 0;
static ArrayList<PluginBase> pluginList;
static Date lastDeviceStatusUpload = new Date(0);
PowerManager.WakeLock mWakeLock;
public ConfigBuilderPlugin() {
MainApp.bus().register(this);
PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "ConfigBuilderPlugin");;
}
@Override
public int getType() {
return PluginBase.GENERAL;
}
@Override
public String getFragmentClass() {
return ConfigBuilderFragment.class.getName();
}
@Override
public String getName() {
return MainApp.instance().getString(R.string.configbuilder);
}
@Override
public boolean isEnabled(int type) {
return true;
}
@Override
public boolean isVisibleInTabs(int type) {
return true;
}
@Override
public boolean canBeHidden(int type) {
return false;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
// Always enabled
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
// Always visible
}
public void initialize() {
pluginList = MainApp.getPluginsList();
loadSettings();
}
public void storeSettings() {
if (pluginList != null) {
if (Config.logPrefsChange)
log.debug("Storing settings");
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
SharedPreferences.Editor editor = settings.edit();
for (int type = 1; type < PluginBase.LAST; type++) {
for (PluginBase p : pluginList) {
String settingEnabled = "ConfigBuilder_" + type + "_" + p.getClass().getSimpleName() + "_Enabled";
String settingVisible = "ConfigBuilder_" + type + "_" + p.getClass().getSimpleName() + "_Visible";
editor.putBoolean(settingEnabled, p.isEnabled(type));
editor.putBoolean(settingVisible, p.isVisibleInTabs(type));
}
}
editor.apply();
verifySelectionInCategories();
}
}
private void loadSettings() {
if (Config.logPrefsChange)
log.debug("Loading stored settings");
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
for (int type = 1; type < PluginBase.LAST; type++) {
for (PluginBase p : pluginList) {
try {
String settingEnabled = "ConfigBuilder_" + type + "_" + p.getClass().getSimpleName() + "_Enabled";
String settingVisible = "ConfigBuilder_" + type + "_" + p.getClass().getSimpleName() + "_Visible";
if (SP.contains(settingEnabled))
p.setFragmentEnabled(type, SP.getBoolean(settingEnabled, true));
if (SP.contains(settingVisible))
p.setFragmentVisible(type, SP.getBoolean(settingVisible, true));
} catch (Exception e) {
e.printStackTrace();
}
}
}
verifySelectionInCategories();
}
public static BgSourceInterface getActiveBgSource() {
return activeBgSource;
}
@Nullable
public static ProfileInterface getActiveProfile() {
return activeProfile;
}
public static TreatmentsInterface getActiveTreatments() {
return activeTreatments;
}
public static TempBasalsInterface getActiveTempBasals() {
return activeTempBasals;
}
public static APSInterface getActiveAPS() {
return activeAPS;
}
public static LoopPlugin getActiveLoop() {
return activeLoop;
}
private void verifySelectionInCategories() {
ArrayList<PluginBase> pluginsInCategory;
// PluginBase.APS
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class);
activeAPS = (APSInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.APS);
if (activeAPS != null) {
if (Config.logConfigBuilder)
log.debug("Selected APS interface: " + ((PluginBase) activeAPS).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeAPS).getName())) {
p.setFragmentVisible(PluginBase.APS, false);
}
}
}
// PluginBase.PROFILE
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class);
activeProfile = (ProfileInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.PROFILE);
if (Config.logConfigBuilder)
log.debug("Selected profile interface: " + ((PluginBase) activeProfile).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeProfile).getName())) {
p.setFragmentVisible(PluginBase.PROFILE, false);
}
}
// PluginBase.BGSOURCE
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class);
activeBgSource = (BgSourceInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.BGSOURCE);
if (Config.logConfigBuilder)
log.debug("Selected bgSource interface: " + ((PluginBase) activeBgSource).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeBgSource).getName())) {
p.setFragmentVisible(PluginBase.BGSOURCE, false);
}
}
// PluginBase.PUMP
pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.PUMP);
activePump = (PumpInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.PUMP);
if (Config.logConfigBuilder)
log.debug("Selected pump interface: " + ((PluginBase) activePump).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activePump).getName())) {
p.setFragmentVisible(PluginBase.PUMP, false);
}
}
// PluginBase.LOOP
pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.LOOP);
activeLoop = (LoopPlugin) getTheOneEnabledInArray(pluginsInCategory, PluginBase.LOOP);
if (activeLoop != null) {
if (Config.logConfigBuilder)
log.debug("Selected loop interface: " + activeLoop.getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(activeLoop.getName())) {
p.setFragmentVisible(PluginBase.LOOP, false);
}
}
}
// PluginBase.TEMPBASAL
pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.TEMPBASAL);
activeTempBasals = (TempBasalsInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.TEMPBASAL);
if (Config.logConfigBuilder)
log.debug("Selected tempbasal interface: " + ((PluginBase) activeTempBasals).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeTempBasals).getName())) {
p.setFragmentVisible(PluginBase.TEMPBASAL, false);
}
}
// PluginBase.TREATMENT
pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.TREATMENT);
activeTreatments = (TreatmentsInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.TREATMENT);
if (Config.logConfigBuilder)
log.debug("Selected treatment interface: " + ((PluginBase) activeTreatments).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeTreatments).getName())) {
p.setFragmentVisible(PluginBase.TREATMENT, false);
}
}
}
@Nullable
private PluginBase getTheOneEnabledInArray(ArrayList<PluginBase> pluginsInCategory, int type) {
PluginBase found = null;
for (PluginBase p : pluginsInCategory) {
if (p.isEnabled(type) && found == null) {
found = p;
} else if (p.isEnabled(type)) {
// set others disabled
p.setFragmentEnabled(type, false);
}
}
// If none enabled, enable first one
if (found == null && pluginsInCategory.size() > 0)
found = pluginsInCategory.get(0);
return found;
}
/*
* Pump interface
*
* Config builder return itself as a pump and check constraints before it passes command to pump driver
*/
@Override
public boolean isTempBasalInProgress() {
return activePump.isTempBasalInProgress();
}
@Override
public boolean isExtendedBoluslInProgress() {
return activePump.isExtendedBoluslInProgress();
}
@Override
public void setNewBasalProfile(NSProfile profile) {
activePump.setNewBasalProfile(profile);
}
@Override
public double getBaseBasalRate() {
return activePump.getBaseBasalRate();
}
@Override
public double getTempBasalAbsoluteRate() {
return activePump.getTempBasalAbsoluteRate();
}
@Override
public double getTempBasalRemainingMinutes() {
return activePump.getTempBasalRemainingMinutes();
}
@Override
public TempBasal getTempBasal(Date time) {
return activePump.getTempBasal(time);
}
@Override
public TempBasal getTempBasal() {
return activePump.getTempBasal();
}
@Override
public TempBasal getExtendedBolus() {
return activePump.getExtendedBolus();
}
public PumpEnactResult deliverTreatmentFromBolusWizard(Context context, Double insulin, Integer carbs, Double glucose, String glucoseType, int carbTime, JSONObject boluscalc) {
mWakeLock.acquire();
insulin = applyBolusConstraints(insulin);
carbs = applyCarbsConstraints(carbs);
BolusProgressDialog bolusProgressDialog = null;
if (context != null) {
bolusProgressDialog = new BolusProgressDialog();
bolusProgressDialog.setInsulin(insulin);
bolusProgressDialog.show(((AppCompatActivity) context).getSupportFragmentManager(), "BolusProgress");
}
PumpEnactResult result = activePump.deliverTreatment(insulin, carbs, context);
BolusProgressDialog.bolusEnded = true;
if (bolusProgressDialog != null && BolusProgressDialog.running) {
try {
bolusProgressDialog.dismiss();
} catch (Exception e) {
e.printStackTrace(); // TODO: handle this better
}
}
if (result.success) {
Treatment t = new Treatment();
t.insulin = result.bolusDelivered;
if (carbTime == 0)
t.carbs = (double) result.carbsDelivered; // with different carbTime record will come back from nightscout
t.created_at = new Date();
t.mealBolus = result.carbsDelivered > 0;
try {
MainApp.getDbHelper().getDaoTreatments().create(t);
} catch (SQLException e) {
e.printStackTrace();
}
t.setTimeIndex(t.getTimeIndex());
t.carbs = (double) result.carbsDelivered;
uploadBolusWizardRecord(t, glucose, glucoseType, carbTime, boluscalc);
MainApp.bus().post(new EventTreatmentChange());
}
mWakeLock.release();
return result;
}
@Override
public PumpEnactResult deliverTreatment(Double insulin, Integer carbs, Context context) {
mWakeLock.acquire();
insulin = applyBolusConstraints(insulin);
carbs = applyCarbsConstraints(carbs);
BolusProgressDialog bolusProgressDialog = null;
if (context != null) {
bolusProgressDialog = new BolusProgressDialog();
bolusProgressDialog.setInsulin(insulin);
bolusProgressDialog.show(((AppCompatActivity) context).getSupportFragmentManager(), "BolusProgress");
}
PumpEnactResult result = activePump.deliverTreatment(insulin, carbs, context);
BolusProgressDialog.bolusEnded = true;
if (bolusProgressDialog != null && BolusProgressDialog.running) {
try {
bolusProgressDialog.dismiss();
} catch (Exception e) {
e.printStackTrace(); // TODO: handle this better
}
}
if (Config.logCongigBuilderActions)
log.debug("deliverTreatment insulin: " + insulin + " carbs: " + carbs + " success: " + result.success + " enacted: " + result.enacted + " bolusDelivered: " + result.bolusDelivered);
if (result.success) {
Treatment t = new Treatment();
t.insulin = result.bolusDelivered;
t.carbs = (double) result.carbsDelivered;
t.created_at = new Date();
t.mealBolus = t.carbs > 0;
try {
MainApp.getDbHelper().getDaoTreatments().create(t);
} catch (SQLException e) {
e.printStackTrace();
}
t.setTimeIndex(t.getTimeIndex());
t.sendToNSClient();
MainApp.bus().post(new EventTreatmentChange());
}
mWakeLock.release();
return result;
}
@Override
public void stopBolusDelivering() {
activePump.stopBolusDelivering();
}
/**
* apply constraints, set temp based on absolute valus and expecting absolute result
*
* @param absoluteRate
* @param durationInMinutes
* @return
*/
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) {
Double rateAfterConstraints = applyBasalConstraints(absoluteRate);
PumpEnactResult result = activePump.setTempBasalAbsolute(rateAfterConstraints, durationInMinutes);
if (Config.logCongigBuilderActions)
log.debug("setTempBasalAbsolute rate: " + rateAfterConstraints + " durationInMinutes: " + durationInMinutes + " success: " + result.success + " enacted: " + result.enacted);
if (result.enacted && result.success) {
if (result.isPercent) {
uploadTempBasalStartPercent(result.percent, result.duration);
} else {
uploadTempBasalStartAbsolute(result.absolute, result.duration);
}
MainApp.bus().post(new EventTempBasalChange());
}
return result;
}
/**
* apply constraints, set temp based on percent and expecting result in percent
*
* @param percent 0 ... 100 ...
* @param durationInMinutes
* @return result
*/
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) {
Integer percentAfterConstraints = applyBasalConstraints(percent);
PumpEnactResult result = activePump.setTempBasalPercent(percentAfterConstraints, durationInMinutes);
if (Config.logCongigBuilderActions)
log.debug("setTempBasalPercent percent: " + percentAfterConstraints + " durationInMinutes: " + durationInMinutes + " success: " + result.success + " enacted: " + result.enacted);
if (result.enacted && result.success) {
uploadTempBasalStartPercent(result.percent, result.duration);
MainApp.bus().post(new EventTempBasalChange());
}
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
Double rateAfterConstraints = applyBolusConstraints(insulin);
PumpEnactResult result = activePump.setExtendedBolus(rateAfterConstraints, durationInMinutes);
if (Config.logCongigBuilderActions)
log.debug("setExtendedBolus rate: " + rateAfterConstraints + " durationInMinutes: " + durationInMinutes + " success: " + result.success + " enacted: " + result.enacted);
if (result.enacted && result.success) {
uploadExtendedBolus(result.bolusDelivered, result.duration);
MainApp.bus().post(new EventTreatmentChange());
}
return result;
}
@Override
public PumpEnactResult cancelTempBasal() {
PumpEnactResult result = activePump.cancelTempBasal();
if (Config.logCongigBuilderActions)
log.debug("cancelTempBasal success: " + result.success + " enacted: " + result.enacted);
if (result.enacted && result.success) {
uploadTempBasalEnd();
MainApp.bus().post(new EventTempBasalChange());
}
return result;
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = activePump.cancelExtendedBolus();
if (Config.logCongigBuilderActions)
log.debug("cancelExtendedBolus success: " + result.success + " enacted: " + result.enacted);
return result;
}
/**
* expect absolute request and allow both absolute and percent response based on pump capabilities
*
* @param request
* @return
*/
public PumpEnactResult applyAPSRequest(APSResult request) {
request.rate = applyBasalConstraints(request.rate);
PumpEnactResult result;
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: " + request.toString());
if ((request.rate == 0 && request.duration == 0) || Math.abs(request.rate - getBaseBasalRate()) < 0.1) {
if (isTempBasalInProgress()) {
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: cancelTempBasal()");
result = cancelTempBasal();
} else {
result = new PumpEnactResult();
result.absolute = request.rate;
result.duration = 0;
result.enacted = false;
result.comment = "Basal set correctly";
result.success = true;
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: Basal set correctly");
}
} else if (isTempBasalInProgress() && Math.abs(request.rate - getTempBasalAbsoluteRate()) < 0.1) {
result = new PumpEnactResult();
result.absolute = getTempBasalAbsoluteRate();
result.duration = activePump.getTempBasal().getPlannedRemainingMinutes();
result.enacted = false;
result.comment = "Temp basal set correctly";
result.success = true;
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: Temp basal set correctly");
} else {
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: setTempBasalAbsolute()");
result = setTempBasalAbsolute(request.rate, request.duration);
}
return result;
}
@Nullable
@Override
public JSONObject getJSONStatus() {
if (activePump != null)
return activePump.getJSONStatus();
else return null;
}
@Override
public String deviceID() {
if (activePump != null)
return activePump.deviceID();
else return "Unknown";
}
/**
* Constraints interface
**/
@Override
public boolean isLoopEnabled() {
boolean result = true;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
result = result && constrain.isLoopEnabled();
}
return result;
}
@Override
public boolean isClosedModeEnabled() {
boolean result = true;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
result = result && constrain.isClosedModeEnabled();
}
return result;
}
@Override
public boolean isAutosensModeEnabled() {
boolean result = true;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
result = result && constrain.isAutosensModeEnabled();
}
return result;
}
@Override
public boolean isAMAModeEnabled() {
boolean result = true;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
result = result && constrain.isAMAModeEnabled();
}
return result;
}
@Override
public Double applyBasalConstraints(Double absoluteRate) {
Double rateAfterConstrain = absoluteRate;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
rateAfterConstrain = Math.min(constrain.applyBasalConstraints(absoluteRate), rateAfterConstrain);
}
return rateAfterConstrain;
}
@Override
public Integer applyBasalConstraints(Integer percentRate) {
Integer rateAfterConstrain = percentRate;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
rateAfterConstrain = Math.min(constrain.applyBasalConstraints(percentRate), rateAfterConstrain);
}
return rateAfterConstrain;
}
@Override
public Double applyBolusConstraints(Double insulin) {
Double insulinAfterConstrain = insulin;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
insulinAfterConstrain = Math.min(constrain.applyBolusConstraints(insulin), insulinAfterConstrain);
}
return insulinAfterConstrain;
}
@Override
public Integer applyCarbsConstraints(Integer carbs) {
Integer carbsAfterConstrain = carbs;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
carbsAfterConstrain = Math.min(constrain.applyCarbsConstraints(carbs), carbsAfterConstrain);
}
return carbsAfterConstrain;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
Double maxIobAfterConstrain = maxIob;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
maxIobAfterConstrain = Math.min(constrain.applyMaxIOBConstraints(maxIob), maxIobAfterConstrain);
}
return maxIobAfterConstrain;
}
@Subscribe
public void onStatusEvent(final EventNewBG ev) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
// Give some time to Loop
try {
Thread.sleep(120 * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
// if status not uploaded, upload pump status only
if (new Date().getTime() - lastDeviceStatusUpload.getTime() > 120 * 1000L) {
uploadDeviceStatus();
}
}
});
t.start();
}
public void uploadTempBasalStartAbsolute(Double absolute, double durationInMinutes) {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", "Temp Basal");
data.put("duration", durationInMinutes);
data.put("absolute", absolute);
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", MainApp.instance().getString(R.string.app_name));
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadTempBasalStartPercent(Integer percent, double durationInMinutes) {
try {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
boolean useAbsolute = SP.getBoolean("ns_sync_use_absolute", false);
if (useAbsolute) {
double absolute = getBaseBasalRate() * percent / 100d;
uploadTempBasalStartAbsolute(absolute, durationInMinutes);
} else {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", "Temp Basal");
data.put("duration", durationInMinutes);
data.put("percent", percent - 100);
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", MainApp.instance().getString(R.string.app_name));
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadTempBasalEnd() {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", "Temp Basal");
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", MainApp.instance().getString(R.string.app_name));
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadExtendedBolus(Double insulin, double durationInMinutes) {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", "Combo Bolus");
data.put("duration", durationInMinutes);
data.put("splitNow", 0);
data.put("splitExt", 100);
data.put("enteredinsulin", insulin);
data.put("relative", insulin);
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", MainApp.instance().getString(R.string.app_name));
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadDeviceStatus() {
DeviceStatus deviceStatus = new DeviceStatus();
try {
LoopPlugin.LastRun lastRun = LoopPlugin.lastRun;
if (lastRun != null && lastRun.lastAPSRun.getTime() > new Date().getTime() - 60 * 1000L) {
// do not send if result is older than 1 min
APSResult apsResult = lastRun.request;
apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.lastAPSRun));
deviceStatus.suggested = apsResult.json();
if (lastRun.request instanceof DetermineBasalResult) {
DetermineBasalResult result = (DetermineBasalResult) lastRun.request;
deviceStatus.iob = result.iob.json();
deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.lastAPSRun));
}
if (lastRun.setByPump != null && lastRun.setByPump.enacted) { // enacted
deviceStatus.enacted = lastRun.request.json();
deviceStatus.enacted.put("rate", lastRun.setByPump.json().get("rate"));
deviceStatus.enacted.put("duration", lastRun.setByPump.json().get("duration"));
deviceStatus.enacted.put("recieved", true);
JSONObject requested = new JSONObject();
requested.put("duration", lastRun.request.duration);
requested.put("rate", lastRun.request.rate);
requested.put("temp", "absolute");
deviceStatus.enacted.put("requested", requested);
}
}
if (activePump != null) {
deviceStatus.device = "openaps://" + deviceID();
deviceStatus.pump = getJSONStatus();
deviceStatus.created_at = DateUtil.toISOString(new Date());
deviceStatus.sendToNSClient();
lastDeviceStatusUpload = new Date();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadBolusWizardRecord(Treatment t, double glucose, String glucoseType, int carbTime, JSONObject boluscalc) {
JSONObject data = new JSONObject();
try {
data.put("eventType", "Bolus Wizard");
if (t.insulin != 0d) data.put("insulin", t.insulin);
if (t.carbs != 0d) data.put("carbs", t.carbs.intValue());
data.put("created_at", DateUtil.toISOString(t.created_at));
data.put("timeIndex", t.timeIndex);
if (glucose != 0d) data.put("glucose", glucose);
data.put("glucoseType", glucoseType);
data.put("boluscalc", boluscalc);
if (carbTime != 0) data.put("preBolus", carbTime);
} catch (JSONException e) {
e.printStackTrace();
}
uploadCareportalEntryToNS(data);
}
public static void uploadCareportalEntryToNS(JSONObject data) {
try {
if (data.has("preBolus") && data.has("carbs")) {
JSONObject prebolus = new JSONObject();
prebolus.put("carbs", data.get("carbs"));
data.remove("carbs");
prebolus.put("eventType", data.get("eventType"));
if (data.has("enteredBy")) prebolus.put("enteredBy", data.get("enteredBy"));
if (data.has("notes")) prebolus.put("notes", data.get("notes"));
long mills = DateUtil.fromISODateString(data.getString("created_at")).getTime();
Date preBolusDate = new Date(mills + data.getInt("preBolus") * 60000L);
prebolus.put("created_at", DateUtil.toISOString(preBolusDate));
uploadCareportalEntryToNS(prebolus);
}
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), NewExtendedBolusDialog.class);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,37 @@
package info.nightscout.androidaps.plugins.DanaR;
import android.bluetooth.*;
import android.content.Context;
import android.preference.ListPreference;
import android.util.AttributeSet;
import java.util.Set;
public class BluetoothDevicePreference extends ListPreference {
public BluetoothDevicePreference(Context context, AttributeSet attrs) {
super(context, attrs);
BluetoothAdapter bta = BluetoothAdapter.getDefaultAdapter();
Integer size = 0;
if (bta != null) {
size += bta.getBondedDevices().size();
}
CharSequence[] entries = new CharSequence[size];
int i = 0;
if (bta != null) {
Set<BluetoothDevice> pairedDevices = bta.getBondedDevices();
for (BluetoothDevice dev : pairedDevices) {
entries[i] = dev.getName();
i++;
}
}
setEntries(entries);
setEntryValues(entries);
}
public BluetoothDevicePreference(Context context) {
this(context, null);
}
}

View file

@ -0,0 +1,234 @@
package info.nightscout.androidaps.plugins.DanaR;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DateFormat;
import java.util.Date;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventTempBasalChange;
import info.nightscout.androidaps.interfaces.FragmentBase;
import info.nightscout.androidaps.plugins.DanaR.Dialogs.ProfileViewDialog;
import info.nightscout.androidaps.plugins.DanaR.History.DanaRHistoryActivity;
import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus;
import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRNewStatus;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SetWarnColor;
public class DanaRFragment extends Fragment implements FragmentBase {
private static Logger log = LoggerFactory.getLogger(DanaRFragment.class);
private static DanaRPlugin danaRPlugin = new DanaRPlugin();
public static DanaRPlugin getPlugin() {
return danaRPlugin;
}
private static Handler sHandler;
private static HandlerThread sHandlerThread;
private Handler loopHandler = new Handler();
private Runnable refreshLoop = null;
TextView lastConnectionView;
TextView btConnectionView;
TextView lastBolusView;
TextView dailyUnitsView;
TextView basaBasalRateView;
TextView tempBasalView;
TextView extendedBolusView;
TextView batteryView;
TextView reservoirView;
TextView iobView;
Button viewProfileButton;
Button historyButton;
public DanaRFragment() {
if (sHandlerThread == null) {
sHandlerThread = new HandlerThread(DanaRFragment.class.getSimpleName());
sHandlerThread.start();
sHandler = new Handler(sHandlerThread.getLooper());
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (refreshLoop == null) {
refreshLoop = new Runnable() {
@Override
public void run() {
updateGUI();
loopHandler.postDelayed(refreshLoop, 60 * 1000L);
}
};
loopHandler.postDelayed(refreshLoop, 60 * 1000L);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.danar_fragment, container, false);
btConnectionView = (TextView) view.findViewById(R.id.danar_btconnection);
lastConnectionView = (TextView) view.findViewById(R.id.danar_lastconnection);
lastBolusView = (TextView) view.findViewById(R.id.danar_lastbolus);
dailyUnitsView = (TextView) view.findViewById(R.id.danar_dailyunits);
basaBasalRateView = (TextView) view.findViewById(R.id.danar_basabasalrate);
tempBasalView = (TextView) view.findViewById(R.id.danar_tempbasal);
extendedBolusView = (TextView) view.findViewById(R.id.danar_extendedbolus);
batteryView = (TextView) view.findViewById(R.id.danar_battery);
reservoirView = (TextView) view.findViewById(R.id.danar_reservoir);
iobView = (TextView) view.findViewById(R.id.danar_iob);
viewProfileButton = (Button) view.findViewById(R.id.danar_viewprofile);
historyButton = (Button) view.findViewById(R.id.danar_history);
viewProfileButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager manager = getFragmentManager();
ProfileViewDialog profileViewDialog = new ProfileViewDialog();
profileViewDialog.show(manager, "ProfileViewDialog");
}
});
historyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getContext(), DanaRHistoryActivity.class));
}
});
btConnectionView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sHandler.post(new Runnable() {
@Override
public void run() {
DanaRPlugin.sExecutionService.connect("Connect request from GUI");
}
}
);
}
});
updateGUI();
return view;
}
@Override
public void onPause() {
super.onPause();
MainApp.bus().unregister(this);
}
@Override
public void onResume() {
super.onResume();
MainApp.bus().register(this);
}
@Subscribe
public void onStatusEvent(final EventDanaRConnectionStatus c) {
Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (c.sStatus == EventDanaRConnectionStatus.CONNECTING)
btConnectionView.setText("{fa-bluetooth-b spin} " + c.sSecondsElapsed + "s");
else if (c.sStatus == EventDanaRConnectionStatus.CONNECTED)
btConnectionView.setText("{fa-bluetooth}");
else
btConnectionView.setText("{fa-bluetooth-b}");
}
}
);
}
}
@Subscribe
public void onStatusEvent(final EventDanaRNewStatus s) {
updateGUI();
}
@Subscribe
public void onStatusEvent(final EventTempBasalChange s) {
updateGUI();
}
@Subscribe
public void onStatusEvent(final EventPreferenceChange s) {
updateGUI();
}
// GUI functions
private void updateGUI() {
final DateFormat formatTime = DateFormat.getTimeInstance(DateFormat.SHORT);
Activity activity = getActivity();
if (activity != null && basaBasalRateView != null)
activity.runOnUiThread(new Runnable() {
@SuppressLint("SetTextI18n")
@Override
public void run() {
if (DanaRPlugin.getDanaRPump().lastConnection.getTime() != 0) {
Long agoMsec = new Date().getTime() - DanaRPlugin.getDanaRPump().lastConnection.getTime();
int agoMin = (int) (agoMsec / 60d / 1000d);
lastConnectionView.setText(formatTime.format(DanaRPlugin.getDanaRPump().lastConnection) + " (" + agoMin + " " + MainApp.sResources.getString(R.string.minago) + ")");
SetWarnColor.setColor(lastConnectionView, agoMin, 16d, 31d);
}
if (DanaRPlugin.getDanaRPump().lastBolusTime.getTime() != 0) {
Long agoMsec = new Date().getTime() - DanaRPlugin.getDanaRPump().lastBolusTime.getTime();
double agoHours = (int) (agoMsec / 60d / 60d / 1000d);
if (agoHours < 6) // max 6h back
lastBolusView.setText(formatTime.format(DanaRPlugin.getDanaRPump().lastBolusTime) + " (" + DecimalFormatter.to1Decimal(agoHours) + " " + getString(R.string.hoursago) + ") " + DecimalFormatter.to2Decimal(danaRPlugin.getDanaRPump().lastBolusAmount) + " U");
else lastBolusView.setText("");
}
dailyUnitsView.setText(DecimalFormatter.to0Decimal(DanaRPlugin.getDanaRPump().dailyTotalUnits) + " / " + DanaRPlugin.getDanaRPump().maxDailyTotalUnits + " U");
SetWarnColor.setColor(dailyUnitsView, DanaRPlugin.getDanaRPump().dailyTotalUnits, DanaRPlugin.getDanaRPump().maxDailyTotalUnits * 0.75d, DanaRPlugin.getDanaRPump().maxDailyTotalUnits * 0.9d);
basaBasalRateView.setText("( " + (DanaRPlugin.getDanaRPump().activeProfile + 1) + " ) " + DecimalFormatter.to2Decimal(danaRPlugin.getBaseBasalRate()) + " U/h");
if (danaRPlugin.isRealTempBasalInProgress()) {
tempBasalView.setText(danaRPlugin.getRealTempBasal().toString());
} else {
tempBasalView.setText("");
}
if (danaRPlugin.isExtendedBoluslInProgress()) {
extendedBolusView.setText(danaRPlugin.getExtendedBolus().toString());
} else {
extendedBolusView.setText("");
}
reservoirView.setText(DecimalFormatter.to0Decimal(DanaRPlugin.getDanaRPump().reservoirRemainingUnits) + " / 300 U");
SetWarnColor.setColorInverse(reservoirView, DanaRPlugin.getDanaRPump().reservoirRemainingUnits, 50d, 20d);
batteryView.setText("{fa-battery-" + (DanaRPlugin.getDanaRPump().batteryRemaining / 25) + "}");
SetWarnColor.setColorInverse(batteryView, DanaRPlugin.getDanaRPump().batteryRemaining, 51d, 26d);
iobView.setText(DanaRPlugin.getDanaRPump().iob + " U");
}
});
}
}

View file

@ -0,0 +1,732 @@
package info.nightscout.androidaps.plugins.DanaR;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import com.squareup.otto.Subscribe;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DateFormat;
import java.util.Date;
import java.util.Objects;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.DanaR.Services.ExecutionService;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
import info.nightscout.utils.ToastUtils;
/**
* Created by mike on 05.08.2016.
*/
public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterface, ProfileInterface {
private static Logger log = LoggerFactory.getLogger(DanaRPlugin.class);
@Override
public String getFragmentClass() {
return DanaRFragment.class.getName();
}
static boolean fragmentPumpEnabled = true;
static boolean fragmentProfileEnabled = true;
static boolean fragmentPumpVisible = true;
public static ExecutionService sExecutionService;
private static DanaRPump sDanaRPump = new DanaRPump();
private static boolean useExtendedBoluses = false;
public static DanaRPump getDanaRPump() {
return sDanaRPump;
}
public DanaRPlugin() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
useExtendedBoluses = sharedPreferences.getBoolean("danar_useextended", false);
Context context = MainApp.instance().getApplicationContext();
Intent intent = new Intent(context, ExecutionService.class);
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
MainApp.bus().register(this);
}
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
log.debug("Service is disconnected");
sExecutionService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
log.debug("Service is connected");
ExecutionService.LocalBinder mLocalBinder = (ExecutionService.LocalBinder) service;
sExecutionService = mLocalBinder.getServiceInstance();
}
};
@SuppressWarnings("UnusedParameters")
@Subscribe
public void onStatusEvent(final EventAppExit e) {
MainApp.instance().getApplicationContext().unbindService(mConnection);
}
@Subscribe
public void onStatusEvent(final EventPreferenceChange s) {
boolean previousValue = useExtendedBoluses;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
useExtendedBoluses = sharedPreferences.getBoolean("danar_useextended", false);
if (useExtendedBoluses != previousValue && isExtendedBoluslInProgress()) {
sExecutionService.extendedBolusStop();
}
}
// Plugin base interface
@Override
public int getType() {
return PluginBase.PUMP;
}
@Override
public String getName() {
return MainApp.instance().getString(R.string.danarpump);
}
@Override
public boolean isEnabled(int type) {
if (type == PluginBase.PROFILE) return fragmentProfileEnabled && fragmentPumpEnabled;
else if (type == PluginBase.PUMP) return fragmentPumpEnabled;
else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled;
return false;
}
@Override
public boolean isVisibleInTabs(int type) {
if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
else if (type == PluginBase.PUMP) return fragmentPumpVisible;
return false;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == PluginBase.PROFILE) this.fragmentProfileEnabled = fragmentEnabled;
else if (type == PluginBase.PUMP) this.fragmentPumpEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == PluginBase.PUMP)
this.fragmentPumpVisible = fragmentVisible;
}
// Pump interface
@Override
public boolean isTempBasalInProgress() {
if (getRealTempBasal() != null) return true;
if (getExtendedBolus() != null && useExtendedBoluses) return true;
return false;
}
public boolean isRealTempBasalInProgress() {
return getRealTempBasal() != null; //TODO: crosscheck here
}
@Override
public boolean isExtendedBoluslInProgress() {
return getExtendedBolus() != null; //TODO: crosscheck here
}
@Override
public void setNewBasalProfile(NSProfile profile) {
if (sExecutionService == null) {
log.error("setNewBasalProfile sExecutionService is null");
return;
}
if (!sExecutionService.updateBasalsInPump(profile))
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.failedupdatebasalprofile));
}
@Override
public double getBaseBasalRate() {
return getDanaRPump().currentBasal;
}
@Override
public double getTempBasalAbsoluteRate() {
if (isRealTempBasalInProgress()) {
if (getRealTempBasal().isAbsolute) {
return getRealTempBasal().absolute;
} else {
Double baseRate = getBaseBasalRate();
Double tempRate = baseRate * (getRealTempBasal().percent / 100d);
return tempRate;
}
}
if (isExtendedBoluslInProgress() && useExtendedBoluses) {
return getBaseBasalRate() + getExtendedBolus().absolute;
}
return 0;
}
@Override
public double getTempBasalRemainingMinutes() {
if (isRealTempBasalInProgress())
return getRealTempBasal().getPlannedRemainingMinutes();
if (isExtendedBoluslInProgress() && useExtendedBoluses)
return getExtendedBolus().getPlannedRemainingMinutes();
return 0;
}
@Override
public TempBasal getTempBasal() {
if (isRealTempBasalInProgress())
return getRealTempBasal();
if (isExtendedBoluslInProgress() && useExtendedBoluses)
return getExtendedBolus();
return null;
}
public TempBasal getTempBasal(Date time) {
TempBasal temp = MainApp.getConfigBuilder().getActiveTempBasals().getTempBasal(time);
if (temp != null) return temp;
if (useExtendedBoluses)
return MainApp.getConfigBuilder().getActiveTempBasals().getExtendedBolus(time);
return null;
}
public TempBasal getRealTempBasal() {
return MainApp.getConfigBuilder().getActiveTempBasals().getTempBasal(new Date());
}
@Override
public TempBasal getExtendedBolus() {
return MainApp.getConfigBuilder().getActiveTempBasals().getExtendedBolus(new Date());
}
@Override
public PumpEnactResult deliverTreatment(Double insulin, Integer carbs, Context context) {
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
insulin = configBuilderPlugin.applyBolusConstraints(insulin);
if (insulin > 0 || carbs > 0) {
Treatment t = new Treatment();
boolean connectionOK = false;
if (insulin > 0 || carbs > 0) connectionOK = sExecutionService.bolus(insulin, carbs, t);
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;
result.carbsDelivered = carbs;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
if (Config.logPumpActions)
log.debug("deliverTreatment: OK. Asked: " + insulin + " Delivered: " + result.bolusDelivered);
return result;
} else {
PumpEnactResult result = new PumpEnactResult();
result.success = false;
result.bolusDelivered = 0d;
result.carbsDelivered = 0;
result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
log.error("deliverTreatment: Invalid input");
return result;
}
}
@Override
public void stopBolusDelivering() {
if (sExecutionService == null) {
log.error("stopBolusDelivering sExecutionService is null");
return;
}
sExecutionService.bolusStop();
}
// This is called from APS
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) {
// Recheck pump status if older than 30 min
if (getDanaRPump().lastConnection.getTime() + 30 * 60 * 1000L < new Date().getTime()) {
doConnect("setTempBasalAbsolute old data");
}
PumpEnactResult result = new PumpEnactResult();
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
absoluteRate = configBuilderPlugin.applyBasalConstraints(absoluteRate);
final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate();
final boolean doHighTemp = absoluteRate > getBaseBasalRate() && !useExtendedBoluses;
final boolean doExtendedTemp = absoluteRate > getBaseBasalRate() && useExtendedBoluses;
if (doTempOff) {
// If extended in progress
if (isExtendedBoluslInProgress() && useExtendedBoluses) {
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Stopping extended bolus (doTempOff)");
return cancelExtendedBolus();
}
// If temp in progress
if (isRealTempBasalInProgress()) {
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Stopping temp basal (doTempOff)");
return cancelRealTempBasal();
}
result.success = true;
result.enacted = false;
result.percent = 100;
result.isPercent = true;
result.isTempCancel = true;
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: doTempOff OK");
return result;
}
if (doLowTemp || doHighTemp) {
Integer percentRate = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue();
if (percentRate < 100) percentRate = Round.ceilTo((double) percentRate, 10d).intValue();
else percentRate = Round.floorTo((double) percentRate, 10d).intValue();
if (percentRate > 200) {
percentRate = 200;
}
// If extended in progress
if (isExtendedBoluslInProgress() && useExtendedBoluses) {
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Stopping extended bolus (doLowTemp || doHighTemp)");
result = cancelExtendedBolus();
if (!result.success) {
log.error("setTempBasalAbsolute: Failed to stop previous extended bolus (doLowTemp || doHighTemp)");
return result;
}
}
// Check if some temp is already in progress
if (isRealTempBasalInProgress()) {
// Correct basal already set ?
if (getRealTempBasal().percent == percentRate) {
result.success = true;
result.percent = percentRate;
result.absolute = getTempBasalAbsoluteRate();
result.enacted = false;
result.duration = ((Double) getTempBasalRemainingMinutes()).intValue();
result.isPercent = true;
result.isTempCancel = false;
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Correct temp basal already set (doLowTemp || doHighTemp)");
return result;
} else {
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Stopping temp basal (doLowTemp || doHighTemp)");
result = cancelRealTempBasal();
// Check for proper result
if (!result.success) {
log.error("setTempBasalAbsolute: Failed to stop previous temp basal (doLowTemp || doHighTemp)");
return result;
}
}
}
// Convert duration from minutes to hours
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)");
return setTempBasalPercent(percentRate, durationInMinutes);
}
if (doExtendedTemp) {
// Check if some temp is already in progress
if (isRealTempBasalInProgress()) {
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Stopping temp basal (doExtendedTemp)");
result = cancelRealTempBasal();
// Check for proper result
if (!result.success) {
log.error("setTempBasalAbsolute: Failed to stop previous temp basal (doExtendedTemp)");
return result;
}
}
// Calculate # of halfHours from minutes
Integer durationInHalfHours = Math.max(durationInMinutes / 30, 1);
// We keep current basal running so need to sub current basal
Double extendedRateToSet = absoluteRate - getBaseBasalRate();
extendedRateToSet = configBuilderPlugin.applyBasalConstraints(extendedRateToSet);
// needs to be rounded to 0.1
extendedRateToSet = Round.roundTo(extendedRateToSet, 0.1d);
// What is current rate of extended bolusing in u/h?
if (Config.logPumpActions) {
log.debug("setTempBasalAbsolute: Extended bolus in progress: " + isExtendedBoluslInProgress() + " rate: " + getDanaRPump().extendedBolusAbsoluteRate + "U/h duration remaining: " + getDanaRPump().extendedBolusRemainingMinutes + "min");
log.debug("setTempBasalAbsolute: Rate to set: " + extendedRateToSet + "U/h");
}
// Compare with extended rate in progress
if (Math.abs(getDanaRPump().extendedBolusAbsoluteRate - extendedRateToSet) < 0.02D) { // Allow some rounding diff
// correct extended already set
result.success = true;
result.absolute = getDanaRPump().extendedBolusAbsoluteRate;
result.enacted = false;
result.duration = getDanaRPump().extendedBolusRemainingMinutes;
result.isPercent = false;
result.isTempCancel = false;
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Correct extended already set");
return result;
}
// Now set new extended, no need to to stop previous (if running) because it's replaced
Double extendedAmount = extendedRateToSet / 2 * durationInHalfHours;
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Setting extended: " + extendedAmount + "U halfhours: " + durationInHalfHours);
result = setExtendedBolus(extendedAmount, durationInMinutes);
if (!result.success) {
log.error("setTempBasalAbsolute: Failed to set extended bolus");
return result;
}
if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Extended bolus set ok");
result.absolute = result.absolute + getBaseBasalRate();
return result;
}
// We should never end here
log.error("setTempBasalAbsolute: Internal error");
result.success = false;
result.comment = "Internal error";
return result;
}
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) {
PumpEnactResult result = new PumpEnactResult();
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
percent = configBuilderPlugin.applyBasalConstraints(percent);
if (percent < 0) {
result.isTempCancel = false;
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
log.error("setTempBasalPercent: Invalid input");
return result;
}
if (percent > 200) percent = 200;
if (getDanaRPump().isTempBasalInProgress && getDanaRPump().tempBasalPercent == percent) {
result.enacted = false;
result.success = true;
result.isTempCancel = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.duration = getDanaRPump().tempBasalRemainingMin;
result.percent = getDanaRPump().tempBasalPercent;
result.isPercent = true;
if (Config.logPumpActions)
log.debug("setTempBasalPercent: Correct value already set");
return result;
}
int durationInHours = Math.max(durationInMinutes / 60, 1);
boolean connectionOK = sExecutionService.tempBasal(percent, durationInHours);
if (connectionOK && getDanaRPump().isTempBasalInProgress && getDanaRPump().tempBasalPercent == percent) {
result.enacted = true;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = false;
result.duration = getDanaRPump().tempBasalRemainingMin;
result.percent = getDanaRPump().tempBasalPercent;
result.isPercent = true;
if (Config.logPumpActions)
log.debug("setTempBasalPercent: OK");
return result;
}
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("setTempBasalPercent: Failed to set temp basal");
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
insulin = configBuilderPlugin.applyBolusConstraints(insulin);
// needs to be rounded to 0.1
insulin = Round.roundTo(insulin, 0.1d);
PumpEnactResult result = new PumpEnactResult();
if (getDanaRPump().isExtendedInProgress && Math.abs(getDanaRPump().extendedBolusAmount - insulin) < 0.1d) {
result.enacted = false;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.duration = getDanaRPump().extendedBolusRemainingMinutes;
result.absolute = getDanaRPump().extendedBolusAbsoluteRate;
result.isPercent = false;
result.isTempCancel = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: Correct extended bolus already set");
return result;
}
int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
if (connectionOK && getDanaRPump().isExtendedInProgress && Math.abs(getDanaRPump().extendedBolusAmount - insulin) < 0.1d) {
result.enacted = true;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = false;
result.duration = getDanaRPump().extendedBolusRemainingMinutes;
result.absolute = getDanaRPump().extendedBolusAbsoluteRate;
result.bolusDelivered = getDanaRPump().extendedBolusAmount;
result.isPercent = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: OK");
return result;
}
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("setExtendedBolus: Failed to extended bolus");
return result;
}
@Override
public PumpEnactResult cancelTempBasal() {
if (isRealTempBasalInProgress())
return cancelRealTempBasal();
if (isExtendedBoluslInProgress())
return cancelExtendedBolus();
PumpEnactResult result = new PumpEnactResult();
result.success = true;
result.enacted = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = true;
return result;
}
public PumpEnactResult cancelRealTempBasal() {
PumpEnactResult result = new PumpEnactResult();
if (getDanaRPump().isTempBasalInProgress) {
sExecutionService.tempBasalStop();
result.enacted = true;
result.isTempCancel = true;
}
if (!getDanaRPump().isTempBasalInProgress) {
result.success = true;
result.isTempCancel = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
if (Config.logPumpActions)
log.debug("cancelRealTempBasal: OK");
return result;
} else {
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
result.isTempCancel = true;
log.error("cancelRealTempBasal: Failed to cancel temp basal");
return result;
}
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
if (getDanaRPump().isExtendedInProgress) {
sExecutionService.extendedBolusStop();
result.enacted = true;
result.isTempCancel = true;
}
if (!getDanaRPump().isExtendedInProgress) {
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
if (Config.logPumpActions)
log.debug("cancelExtendedBolus: OK");
return result;
} else {
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("cancelExtendedBolus: Failed to cancel extended bolus");
return result;
}
}
public static void doConnect(String from) {
if (sExecutionService != null) sExecutionService.connect(from);
}
public static boolean isConnected() {
return sExecutionService != null && sExecutionService.isConnected();
}
public static boolean isConnecting() {
return sExecutionService != null && sExecutionService.isConnecting();
}
@Override
public JSONObject getJSONStatus() {
if (getDanaRPump().lastConnection.getTime() + 5 * 60 * 1000L < new Date().getTime()) {
return null;
}
JSONObject pump = new JSONObject();
JSONObject battery = new JSONObject();
JSONObject status = new JSONObject();
JSONObject extended = new JSONObject();
try {
battery.put("percent", getDanaRPump().batteryRemaining);
status.put("status", "normal");
status.put("timestamp", DateUtil.toISOString(getDanaRPump().lastConnection));
if (isTempBasalInProgress()) {
extended.put("TempBasalAbsoluteRate", getTempBasalAbsoluteRate());
extended.put("TempBasalStart", getTempBasal().timeStart.toLocaleString());
extended.put("TempBasalRemaining", getTempBasal().getPlannedRemainingMinutes());
extended.put("IsExtended", getTempBasal().isExtended);
extended.put("BaseBasalRate", getBaseBasalRate());
try {
extended.put("ActiveProfile", MainApp.getConfigBuilder().getActiveProfile().getProfile().getActiveProfile());
} catch (Exception e) {}
}
extended.put("PumpIOB", getDanaRPump().iob);
extended.put("LastBolus", getDanaRPump().lastBolusTime.toLocaleString());
extended.put("LastBolusAmount", getDanaRPump().lastBolusAmount);
pump.put("battery", battery);
pump.put("status", status);
pump.put("extended", extended);
pump.put("reservoir", (int) getDanaRPump().reservoirRemainingUnits);
pump.put("clock", DateUtil.toISOString(new Date()));
} catch (JSONException e) {
e.printStackTrace();
}
return pump;
}
@Override
public String deviceID() {
return getDanaRPump().serialNumber;
}
/**
* Constraint interface
*/
@Override
public boolean isLoopEnabled() {
return true;
}
@Override
public boolean isClosedModeEnabled() {
return true;
}
@Override
public boolean isAutosensModeEnabled() {
return true;
}
@Override
public boolean isAMAModeEnabled() {
return true;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBasalConstraints(Double absoluteRate) {
double origAbsoluteRate = absoluteRate;
if (getDanaRPump() != null) {
if (absoluteRate > getDanaRPump().maxBasal) {
absoluteRate = getDanaRPump().maxBasal;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
}
}
return absoluteRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Integer applyBasalConstraints(Integer percentRate) {
Integer origPercentRate = percentRate;
if (percentRate < 0) percentRate = 0;
if (percentRate > 200) percentRate = 200;
if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
return percentRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBolusConstraints(Double insulin) {
double origInsulin = insulin;
if (getDanaRPump() != null) {
if (insulin > getDanaRPump().maxBolus) {
insulin = getDanaRPump().maxBolus;
if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
}
}
return insulin;
}
@Override
public Integer applyCarbsConstraints(Integer carbs) {
return carbs;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
return maxIob;
}
@Nullable
@Override
public NSProfile getProfile() {
DanaRPump pump = getDanaRPump();
if (pump.lastSettingsRead.getTime() == 0)
return null; // no info now
return pump.createConvertedProfile();
}
// Reply for sms communicator
public String shortStatus() {
final DateFormat formatTime = DateFormat.getTimeInstance(DateFormat.SHORT);
String ret = "";
if (getDanaRPump().lastConnection.getTime() != 0) {
Long agoMsec = new Date().getTime() - getDanaRPump().lastConnection.getTime();
int agoMin = (int) (agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " minago\n";
}
if (getDanaRPump().lastBolusTime.getTime() != 0) {
ret += "LastBolus: " + DecimalFormatter.to2Decimal(getDanaRPump().lastBolusAmount) + "U @" + formatTime.format(getDanaRPump().lastBolusTime) + "\n";
}
if (isRealTempBasalInProgress()) {
ret += "Temp: " + getRealTempBasal().toString() + "\n";
}
if (isExtendedBoluslInProgress()) {
ret += "Extended: " + getExtendedBolus().toString() + "\n";
}
ret += "IOB: " + getDanaRPump().iob + "U\n";
ret += "Reserv: " + DecimalFormatter.to0Decimal(getDanaRPump().reservoirRemainingUnits) + "U\n";
ret += "Batt: " + getDanaRPump().batteryRemaining + "\n";
return ret;
}
// TODO: daily total constraint
}

View file

@ -0,0 +1,158 @@
package info.nightscout.androidaps.plugins.DanaR;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.DecimalFormat;
import java.util.Date;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.SafeParse;
/**
* Created by mike on 04.07.2016.
*/
public class DanaRPump {
public static final int UNITS_MGDL = 0;
public static final int UNITS_MMOL = 1;
public Date lastConnection = new Date(0);
public Date lastSettingsRead = new Date(0);
// Info
public String serialNumber = "";
public Date shippingDate = new Date(0);
public String shippingCountry = "";
public boolean isNewPump = false;
public int password = -1;
public Date pumpTime = new Date(0);
// Status
public boolean pumpSuspended;
public boolean calculatorEnabled;
public double dailyTotalUnits;
public int maxDailyTotalUnits;
public double iob;
public double reservoirRemainingUnits;
public int batteryRemaining;
public boolean bolusBlocked;
public Date lastBolusTime = new Date(0);
public double lastBolusAmount;
public double currentBasal;
public boolean isTempBasalInProgress;
public int tempBasalPercent;
public int tempBasalRemainingMin;
public int tempBasalTotalSec;
public Date tempBasalStart;
public boolean isExtendedInProgress;
public int extendedBolusMinutes;
public double extendedBolusAmount;
public double extendedBolusAbsoluteRate;
public int extendedBolusSoFarInMinutes;
public Date extendedBolusStart;
public int extendedBolusRemainingMinutes;
// Profile
public int units;
public int easyBasalMode;
public boolean basal48Enable = false;
public int currentCIR;
public double currentCF;
public double currentAI;
public double currentTarget;
public int currentAIDR;
public int morningCIR;
public double morningCF;
public int afternoonCIR;
public double afternoonCF;
public int eveningCIR;
public double eveningCF;
public int nightCIR;
public double nightCF;
public int activeProfile = 0;
public double[][] pumpProfiles = null;
//Limits
public double maxBolus;
public double maxBasal;
public NSProfile createConvertedProfile() {
JSONObject json = new JSONObject();
JSONObject store = new JSONObject();
JSONObject profile = new JSONObject();
// Morning / 6:0010:59
// Afternoon / 11:0016:59
// Evening / 17:0021:59
// Night / 22:005:59
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
double dia = SafeParse.stringToDouble(SP.getString("danarprofile_dia", "3"));
double car = SafeParse.stringToDouble(SP.getString("danarprofile_car", "20"));
try {
json.put("defaultProfile", "" + (activeProfile + 1));
json.put("store", store);
profile.put("dia", dia);
JSONArray carbratios = new JSONArray();
carbratios.put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", nightCF));
carbratios.put(new JSONObject().put("time", "06:00").put("timeAsSeconds", 6 * 3600).put("value", morningCF));
carbratios.put(new JSONObject().put("time", "11:00").put("timeAsSeconds", 11 * 3600).put("value", afternoonCF));
carbratios.put(new JSONObject().put("time", "14:00").put("timeAsSeconds", 17 * 3600).put("value", eveningCF));
carbratios.put(new JSONObject().put("time", "22:00").put("timeAsSeconds", 22 * 3600).put("value", nightCF));
profile.put("carbratio", carbratios);
profile.put("carbs_hr", car);
JSONArray sens = new JSONArray();
sens.put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", nightCIR));
sens.put(new JSONObject().put("time", "06:00").put("timeAsSeconds", 6 * 3600).put("value", morningCIR));
sens.put(new JSONObject().put("time", "11:00").put("timeAsSeconds", 11 * 3600).put("value", afternoonCIR));
sens.put(new JSONObject().put("time", "17:00").put("timeAsSeconds", 17 * 3600).put("value", eveningCIR));
sens.put(new JSONObject().put("time", "22:00").put("timeAsSeconds", 22 * 3600).put("value", nightCIR));
profile.put("sens", sens);
JSONArray basals = new JSONArray();
int basalValues = basal48Enable ? 48 : 24;
int basalIncrement = basal48Enable ? 30 * 60 : 60 * 60;
for (int h = 0; h < basalValues; h++) {
String time;
DecimalFormat df = new DecimalFormat("00");
if (basal48Enable) {
time = df.format((long) h / 2) + ":" + df.format(30 * (h % 2));
} else {
time = df.format(h) + ":00";
}
basals.put(new JSONObject().put("time", time).put("timeAsSeconds", h * basalIncrement).put("value", pumpProfiles[activeProfile][h]));
}
profile.put("basal", basals);
profile.put("target_low", new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", currentTarget)));
profile.put("target_high", new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", currentTarget)));
profile.put("units", units == UNITS_MGDL ? Constants.MGDL : Constants.MMOL);
store.put("" + (activeProfile + 1), profile);
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
return null;
}
return new NSProfile(json, "" + (activeProfile + 1));
}
}

View file

@ -0,0 +1,112 @@
package info.nightscout.androidaps.plugins.DanaR.Dialogs;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.MainActivity;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.DanaR.DanaRFragment;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DecimalFormatter;
/**
* Created by mike on 10.07.2016.
*/
public class ProfileViewDialog extends DialogFragment {
private static Logger log = LoggerFactory.getLogger(ProfileViewDialog.class);
private static TextView noProfile;
private static TextView units;
private static TextView dia;
private static TextView activeProfile;
private static TextView ic;
private static TextView isf;
private static TextView basal;
private static TextView target;
private static Button refreshButton;
Handler mHandler;
static HandlerThread mHandlerThread;
NSProfile profile = null;
public ProfileViewDialog() {
mHandlerThread = new HandlerThread(ProfileViewDialog.class.getSimpleName());
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
profile = ((DanaRPlugin) MainApp.getSpecificPlugin(DanaRPlugin.class)).getProfile();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.nsprofileviewer_fragment, container, false);
noProfile = (TextView) layout.findViewById(R.id.profileview_noprofile);
units = (TextView) layout.findViewById(R.id.profileview_units);
dia = (TextView) layout.findViewById(R.id.profileview_dia);
activeProfile = (TextView) layout.findViewById(R.id.profileview_activeprofile);
ic = (TextView) layout.findViewById(R.id.profileview_ic);
isf = (TextView) layout.findViewById(R.id.profileview_isf);
basal = (TextView) layout.findViewById(R.id.profileview_basal);
target = (TextView) layout.findViewById(R.id.profileview_target);
refreshButton = (Button) layout.findViewById(R.id.profileview_reload);
refreshButton.setVisibility(View.VISIBLE);
refreshButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.post(new Runnable() {
@Override
public void run() {
DanaRPlugin.getDanaRPump().lastSettingsRead = new Date(0);
DanaRPlugin.doConnect("ProfileViewDialog");
}
});
dismiss();
}
});
setContent();
return layout;
}
@Override
public void onResume() {
super.onResume();
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
private void setContent() {
if (profile == null) {
noProfile.setVisibility(View.VISIBLE);
return;
} else {
noProfile.setVisibility(View.GONE);
}
units.setText(profile.getUnits());
dia.setText(DecimalFormatter.to2Decimal(profile.getDia()) + " h");
activeProfile.setText(profile.getActiveProfile());
ic.setText(profile.getIcList());
isf.setText(profile.getIsfList());
basal.setText(profile.getBasalList());
target.setText(profile.getTargetList());
}
}

View file

@ -0,0 +1,451 @@
package info.nightscout.androidaps.plugins.DanaR.History;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.DanaRHistoryRecord;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.DanaR.Services.ExecutionService;
import info.nightscout.androidaps.plugins.DanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus;
import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRSyncStatus;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.ToastUtils;
public class DanaRHistoryActivity extends Activity {
private static Logger log = LoggerFactory.getLogger(DanaRHistoryActivity.class);
private boolean mBounded;
private static ExecutionService mExecutionService;
private Handler mHandler;
private static HandlerThread mHandlerThread;
static NSProfile profile = null;
Spinner historyTypeSpinner;
TextView statusView;
Button reloadButton;
Button syncButton;
RecyclerView recyclerView;
LinearLayoutManager llm;
static byte showingType = RecordTypes.RECORD_TYPE_ALARM;
List<DanaRHistoryRecord> historyList = new ArrayList<>();
public static class TypeList {
public byte type;
String name;
public TypeList(byte type, String name) {
this.type = type;
this.name = name;
}
@Override
public String toString() {
return name;
}
}
public DanaRHistoryActivity() {
super();
mHandlerThread = new HandlerThread(DanaRHistoryActivity.class.getSimpleName());
mHandlerThread.start();
this.mHandler = new Handler(mHandlerThread.getLooper());
}
@Override
public void onStart() {
super.onStart();
Intent intent = new Intent(this, ExecutionService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onResume() {
super.onResume();
MainApp.bus().register(this);
}
@Override
protected void onPause() {
super.onPause();
MainApp.bus().unregister(this);
}
@Override
public void onStop() {
super.onStop();
if (mBounded) {
unbindService(mConnection);
mBounded = false;
}
}
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
log.debug("Service is disconnected");
mBounded = false;
mExecutionService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
log.debug("Service is connected");
mBounded = true;
ExecutionService.LocalBinder mLocalBinder = (ExecutionService.LocalBinder) service;
mExecutionService = mLocalBinder.getServiceInstance();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.danar_historyactivity);
historyTypeSpinner = (Spinner) findViewById(R.id.danar_historytype);
statusView = (TextView) findViewById(R.id.danar_historystatus);
reloadButton = (Button) findViewById(R.id.danar_historyreload);
syncButton = (Button) findViewById(R.id.danar_historysync);
recyclerView = (RecyclerView) findViewById(R.id.danar_history_recyclerview);
recyclerView.setHasFixedSize(true);
llm = new LinearLayoutManager(this);
recyclerView.setLayoutManager(llm);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(historyList);
recyclerView.setAdapter(adapter);
statusView.setVisibility(View.GONE);
// Types
ArrayList<TypeList> typeList = new ArrayList<>();
typeList.add(new TypeList(RecordTypes.RECORD_TYPE_ALARM, getString(R.string.danar_history_alarm)));
typeList.add(new TypeList(RecordTypes.RECORD_TYPE_BASALHOUR, getString(R.string.danar_history_basalhours)));
typeList.add(new TypeList(RecordTypes.RECORD_TYPE_BOLUS, getString(R.string.danar_history_bolus)));
typeList.add(new TypeList(RecordTypes.RECORD_TYPE_CARBO, getString(R.string.danar_history_carbohydrates)));
typeList.add(new TypeList(RecordTypes.RECORD_TYPE_DAILY, getString(R.string.danar_history_dailyinsulin)));
typeList.add(new TypeList(RecordTypes.RECORD_TYPE_ERROR, getString(R.string.danar_history_errors)));
typeList.add(new TypeList(RecordTypes.RECORD_TYPE_GLUCOSE, getString(R.string.danar_history_glucose)));
typeList.add(new TypeList(RecordTypes.RECORD_TYPE_REFILL, getString(R.string.danar_history_refill)));
typeList.add(new TypeList(RecordTypes.RECORD_TYPE_SUSPEND, getString(R.string.danar_history_syspend)));
ArrayAdapter<TypeList> spinnerAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_spinner_item, typeList);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
historyTypeSpinner.setAdapter(spinnerAdapter);
reloadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mExecutionService.isConnected() || mExecutionService.isConnecting()) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), getString(R.string.pumpbusy));
return;
}
mHandler.post(new Runnable() {
@Override
public void run() {
TypeList selected = (TypeList) historyTypeSpinner.getSelectedItem();
runOnUiThread(new Runnable() {
@Override
public void run() {
reloadButton.setVisibility(View.GONE);
syncButton.setVisibility(View.GONE);
statusView.setVisibility(View.VISIBLE);
}
});
clearCardView();
mExecutionService.loadHistory(selected.type);
loadDataFromDB(selected.type);
runOnUiThread(new Runnable() {
@Override
public void run() {
reloadButton.setVisibility(View.VISIBLE);
syncButton.setVisibility(View.VISIBLE);
statusView.setVisibility(View.GONE);
}
});
}
});
}
});
syncButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.post(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
reloadButton.setVisibility(View.GONE);
syncButton.setVisibility(View.GONE);
statusView.setVisibility(View.VISIBLE);
}
});
DanaRNSHistorySync sync = new DanaRNSHistorySync(historyList);
sync.sync(DanaRNSHistorySync.SYNC_ALL);
runOnUiThread(new Runnable() {
@Override
public void run() {
reloadButton.setVisibility(View.VISIBLE);
syncButton.setVisibility(View.VISIBLE);
statusView.setVisibility(View.GONE);
}
});
}
});
}
});
historyTypeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
TypeList selected = (TypeList) historyTypeSpinner.getSelectedItem();
loadDataFromDB(selected.type);
showingType = selected.type;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
clearCardView();
}
});
profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
if (profile == null) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.noprofile));
finish();
}
}
public static class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.HistoryViewHolder> {
List<DanaRHistoryRecord> historyList;
RecyclerViewAdapter(List<DanaRHistoryRecord> historyList) {
this.historyList = historyList;
}
@Override
public HistoryViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.danar_history_item, viewGroup, false);
return new HistoryViewHolder(v);
}
@Override
public void onBindViewHolder(HistoryViewHolder holder, int position) {
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
DanaRHistoryRecord record = historyList.get(position);
holder.time.setText(df.format(new Date(record.getRecordDate())));
holder.value.setText(DecimalFormatter.to2Decimal(record.getRecordValue()));
holder.stringvalue.setText(record.getStringRecordValue());
holder.bolustype.setText(record.getBolusType());
holder.duration.setText(DecimalFormatter.to0Decimal(record.getRecordDuration()));
holder.dailybasal.setText(DecimalFormatter.to2Decimal(record.getRecordDailyBasal()) + "U");
holder.dailybolus.setText(DecimalFormatter.to2Decimal(record.getRecordDailyBolus()) + "U");
holder.alarm.setText(record.getRecordAlarm());
switch (showingType) {
case RecordTypes.RECORD_TYPE_ALARM:
holder.time.setVisibility(View.VISIBLE);
holder.value.setVisibility(View.VISIBLE);
holder.stringvalue.setVisibility(View.GONE);
holder.bolustype.setVisibility(View.GONE);
holder.duration.setVisibility(View.GONE);
holder.dailybasal.setVisibility(View.GONE);
holder.dailybolus.setVisibility(View.GONE);
holder.alarm.setVisibility(View.VISIBLE);
break;
case RecordTypes.RECORD_TYPE_BOLUS:
holder.time.setVisibility(View.VISIBLE);
holder.value.setVisibility(View.VISIBLE);
holder.stringvalue.setVisibility(View.GONE);
holder.bolustype.setVisibility(View.VISIBLE);
holder.duration.setVisibility(View.VISIBLE);
holder.dailybasal.setVisibility(View.GONE);
holder.dailybolus.setVisibility(View.GONE);
holder.alarm.setVisibility(View.GONE);
break;
case RecordTypes.RECORD_TYPE_DAILY:
holder.time.setVisibility(View.VISIBLE);
holder.value.setVisibility(View.GONE);
holder.stringvalue.setVisibility(View.GONE);
holder.bolustype.setVisibility(View.GONE);
holder.duration.setVisibility(View.GONE);
holder.dailybasal.setVisibility(View.VISIBLE);
holder.dailybolus.setVisibility(View.VISIBLE);
holder.alarm.setVisibility(View.GONE);
break;
case RecordTypes.RECORD_TYPE_GLUCOSE:
holder.value.setText(NSProfile.toUnitsString(record.getRecordValue(), record.getRecordValue() * Constants.MGDL_TO_MMOLL, profile.getUnits()));
// rest is the same
case RecordTypes.RECORD_TYPE_CARBO:
case RecordTypes.RECORD_TYPE_BASALHOUR:
case RecordTypes.RECORD_TYPE_ERROR:
case RecordTypes.RECORD_TYPE_PRIME:
case RecordTypes.RECORD_TYPE_REFILL:
case RecordTypes.RECORD_TYPE_TB:
holder.time.setVisibility(View.VISIBLE);
holder.value.setVisibility(View.VISIBLE);
holder.stringvalue.setVisibility(View.GONE);
holder.bolustype.setVisibility(View.GONE);
holder.duration.setVisibility(View.GONE);
holder.dailybasal.setVisibility(View.GONE);
holder.dailybolus.setVisibility(View.GONE);
holder.alarm.setVisibility(View.GONE);
break;
case RecordTypes.RECORD_TYPE_SUSPEND:
holder.time.setVisibility(View.VISIBLE);
holder.value.setVisibility(View.GONE);
holder.stringvalue.setVisibility(View.VISIBLE);
holder.bolustype.setVisibility(View.GONE);
holder.duration.setVisibility(View.GONE);
holder.dailybasal.setVisibility(View.GONE);
holder.dailybolus.setVisibility(View.GONE);
holder.alarm.setVisibility(View.GONE);
break;
}
}
@Override
public int getItemCount() {
return historyList.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public static class HistoryViewHolder extends RecyclerView.ViewHolder {
CardView cv;
TextView time;
TextView value;
TextView bolustype;
TextView stringvalue;
TextView duration;
TextView dailybasal;
TextView dailybolus;
TextView alarm;
HistoryViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.danar_history_cardview);
time = (TextView) itemView.findViewById(R.id.danar_history_time);
value = (TextView) itemView.findViewById(R.id.danar_history_value);
bolustype = (TextView) itemView.findViewById(R.id.danar_history_bolustype);
stringvalue = (TextView) itemView.findViewById(R.id.danar_history_stringvalue);
duration = (TextView) itemView.findViewById(R.id.danar_history_duration);
dailybasal = (TextView) itemView.findViewById(R.id.danar_history_dailybasal);
dailybolus = (TextView) itemView.findViewById(R.id.danar_history_dailybolus);
alarm = (TextView) itemView.findViewById(R.id.danar_history_alarm);
}
}
}
private void loadDataFromDB(byte type) {
try {
Dao<DanaRHistoryRecord, String> dao = MainApp.getDbHelper().getDaoDanaRHistory();
QueryBuilder<DanaRHistoryRecord, String> queryBuilder = dao.queryBuilder();
queryBuilder.orderBy("recordDate", false);
Where where = queryBuilder.where();
where.eq("recordCode", type);
queryBuilder.limit(200L);
PreparedQuery<DanaRHistoryRecord> preparedQuery = queryBuilder.prepare();
historyList = dao.query(preparedQuery);
} catch (SQLException e) {
e.printStackTrace();
historyList = new ArrayList<>();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
recyclerView.swapAdapter(new RecyclerViewAdapter(historyList), false);
}
});
}
private void clearCardView() {
historyList = new ArrayList<>();
runOnUiThread(new Runnable() {
@Override
public void run() {
recyclerView.swapAdapter(new RecyclerViewAdapter(historyList), false);
}
});
}
@Subscribe
public void onStatusEvent(final EventDanaRSyncStatus s) {
log.debug("EventDanaRSyncStatus: " + s.message);
runOnUiThread(
new Runnable() {
@Override
public void run() {
statusView.setText(s.message);
}
});
}
@Subscribe
public void onStatusEvent(final EventDanaRConnectionStatus c) {
runOnUiThread(
new Runnable() {
@Override
public void run() {
if (c.sStatus == EventDanaRConnectionStatus.CONNECTING) {
statusView.setText(String.format(getString(R.string.danar_history_connectingfor), c.sSecondsElapsed));
log.debug("EventDanaRConnectionStatus: " + "Connecting for " + c.sSecondsElapsed + "s");
} else if (c.sStatus == EventDanaRConnectionStatus.CONNECTED) {
statusView.setText(MainApp.sResources.getString(R.string.connected));
log.debug("EventDanaRConnectionStatus: Connected");
} else {
statusView.setText(MainApp.sResources.getString(R.string.disconnected));
log.debug("EventDanaRConnectionStatus: Disconnected");
}
}
}
);
}
}

View file

@ -0,0 +1,230 @@
package info.nightscout.androidaps.plugins.DanaR.History;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.DanaRHistoryRecord;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.DanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRSyncStatus;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.ToastUtils;
/**
* Created by mike on 20.07.2016.
*/
public class DanaRNSHistorySync {
private static Logger log = LoggerFactory.getLogger(DanaRNSHistorySync.class);
private List<DanaRHistoryRecord> historyRecords;
public final static int SYNC_BOLUS = 0b00000001;
public final static int SYNC_ERROR = 0b00000010;
public final static int SYNC_REFILL = 0b00000100;
public final static int SYNC_GLUCOSE = 0b00001000;
public final static int SYNC_CARBO = 0b00010000;
public final static int SYNC_ALARM = 0b00100000;
public final static int SYNC_BASALHOURS = 0b01000000;
public final static int SYNC_ALL = 0b11111111;
public final static String DANARSIGNATURE = "DANARMESSAGE";
public DanaRNSHistorySync(List<DanaRHistoryRecord> historyRecords) {
this.historyRecords = historyRecords;
}
public void sync(int what) {
try {
ConfigBuilderPlugin ConfigBuilderPlugin = MainApp.getConfigBuilder();
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
if (profile == null) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.noprofile));
return;
}
Calendar cal = Calendar.getInstance();
long records = historyRecords.size();
long processing = 0;
long uploaded = 0;
log.debug("Database contains " + records + " records");
EventDanaRSyncStatus ev = new EventDanaRSyncStatus();
for (DanaRHistoryRecord record : historyRecords) {
processing++;
if (record.get_id() != null) continue;
//log.debug(record.getBytes());
JSONObject nsrec = new JSONObject();
ev.message = MainApp.sResources.getString(R.string.uploading) + " " + processing + "/" + records + " "; // TODO: translations
switch (record.getRecordCode()) {
case RecordTypes.RECORD_TYPE_BOLUS:
if ((what & SYNC_BOLUS) == 0) break;
switch (record.getBolusType()) {
case "S":
log.debug("Syncing standard bolus record " + record.getRecordValue() + "U " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "Meal Bolus");
nsrec.put("insulin", record.getRecordValue());
nsrec.put("created_at", DateUtil.toISOString(record.getRecordDate()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_sbolus);
break;
case "E":
if (record.getRecordDuration() > 0) {
log.debug("Syncing extended bolus record " + record.getRecordValue() + "U " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "Combo Bolus");
nsrec.put("insulin", 0);
nsrec.put("duration", record.getRecordDuration());
nsrec.put("relative", record.getRecordValue() / record.getRecordDuration() * 60);
nsrec.put("splitNow", 0);
nsrec.put("splitExt", 100);
cal.setTimeInMillis(record.getRecordDate());
cal.add(Calendar.MINUTE, -1 * record.getRecordDuration());
nsrec.put("created_at", DateUtil.toISOString(cal.getTime()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_ebolus);
} else {
log.debug("NOT Syncing extended bolus record " + record.getRecordValue() + "U " + DateUtil.toISOString(record.getRecordDate()) + " zero duration");
}
break;
case "DS":
log.debug("Syncing dual(S) bolus record " + record.getRecordValue() + "U " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "Combo Bolus");
nsrec.put("insulin", record.getRecordValue());
nsrec.put("splitNow", 100);
nsrec.put("splitExt", 0);
nsrec.put("created_at", DateUtil.toISOString(record.getRecordDate()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_dsbolus);
break;
case "DE":
log.debug("Syncing dual(E) bolus record " + record.getRecordValue() + "U " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "Combo Bolus");
nsrec.put("duration", record.getRecordDuration());
nsrec.put("relative", record.getRecordValue() / record.getRecordDuration() * 60);
nsrec.put("splitNow", 0);
nsrec.put("splitExt", 100);
cal.setTimeInMillis(record.getRecordDate());
cal.add(Calendar.MINUTE, -1 * record.getRecordDuration());
nsrec.put("created_at", DateUtil.toISOString(cal.getTime()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_debolus);
break;
default:
log.debug("Unknown bolus record");
break;
}
break;
case RecordTypes.RECORD_TYPE_ERROR:
if ((what & SYNC_ERROR) == 0) break;
log.debug("Syncing error record " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "Note");
nsrec.put("notes", "Error");
nsrec.put("created_at", DateUtil.toISOString(record.getRecordDate()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_error);
break;
case RecordTypes.RECORD_TYPE_REFILL:
if ((what & SYNC_REFILL) == 0) break;
log.debug("Syncing refill record " + record.getRecordValue() + " " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "Insulin Change");
nsrec.put("notes", "Refill " + record.getRecordValue() + "U");
nsrec.put("created_at", DateUtil.toISOString(record.getRecordDate()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_refill);
break;
case RecordTypes.RECORD_TYPE_BASALHOUR:
if ((what & SYNC_BASALHOURS) == 0) break;
log.debug("Syncing basal hour record " + record.getRecordValue() + " " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "Temp Basal");
nsrec.put("absolute", record.getRecordValue());
nsrec.put("duration", 60);
nsrec.put("created_at", DateUtil.toISOString(record.getRecordDate()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_basalhour);
break;
case RecordTypes.RECORD_TYPE_TB:
//log.debug("Ignoring TB record " + record.getBytes() + " " + DateUtil.toISOString(record.getRecordDate()));
break;
case RecordTypes.RECORD_TYPE_GLUCOSE:
if ((what & SYNC_GLUCOSE) == 0) break;
log.debug("Syncing glucose record " + record.getRecordValue() + " " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "BG Check");
nsrec.put("glucose", NSProfile.fromMgdlToUnits(record.getRecordValue(), profile.getUnits()));
nsrec.put("glucoseType", "Finger");
nsrec.put("created_at", DateUtil.toISOString(record.getRecordDate()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_glucose);
break;
case RecordTypes.RECORD_TYPE_CARBO:
if ((what & SYNC_CARBO) == 0) break;
log.debug("Syncing carbo record " + record.getRecordValue() + "g " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "Meal Bolus");
nsrec.put("carbs", record.getRecordValue());
nsrec.put("created_at", DateUtil.toISOString(record.getRecordDate()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_carbohydrate);
break;
case RecordTypes.RECORD_TYPE_ALARM:
if ((what & SYNC_ALARM) == 0) break;
log.debug("Syncing alarm record " + record.getRecordAlarm() + " " + DateUtil.toISOString(record.getRecordDate()));
nsrec.put(DANARSIGNATURE, record.getBytes());
nsrec.put("eventType", "Note");
nsrec.put("notes", "Alarm: " + record.getRecordAlarm());
nsrec.put("created_at", DateUtil.toISOString(record.getRecordDate()));
nsrec.put("enteredBy", MainApp.sResources.getString(R.string.app_name));
ConfigBuilderPlugin.uploadCareportalEntryToNS(nsrec);
uploaded++;
ev.message += MainApp.sResources.getString(R.string.danar_alarm);
break;
case RecordTypes.RECORD_TYPE_SUSPEND: // TODO: this too
case RecordTypes.RECORD_TYPE_DAILY:
case RecordTypes.RECORD_TYPE_PRIME:
// Ignore
break;
default:
log.error("Unknown record type");
break;
}
MainApp.bus().post(ev);
}
ev.message = String.format(MainApp.sResources.getString(R.string.danar_totaluploaded), uploaded);
MainApp.bus().post(ev);
} catch (JSONException e) {
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,224 @@
package info.nightscout.androidaps.plugins.DanaR;
import android.bluetooth.BluetoothSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.DanaR.comm.MessageHashTable;
import info.nightscout.utils.CRC;
/**
* Created by mike on 17.07.2016.
*/
public class SerialIOThread extends Thread {
private static Logger log = LoggerFactory.getLogger(SerialIOThread.class);
private InputStream mInputStream = null;
private OutputStream mOutputStream = null;
private BluetoothSocket mRfCommSocket;
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledDisconnection = null;
private boolean mKeepRunning = true;
private byte[] mReadBuff = new byte[0];
MessageBase processedMessage;
public SerialIOThread(BluetoothSocket rfcommSocket) {
super(SerialIOThread.class.toString());
mRfCommSocket = rfcommSocket;
try {
mOutputStream = mRfCommSocket.getOutputStream();
mInputStream = mRfCommSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
this.start();
}
@Override
public final void run() {
try {
while (mKeepRunning) {
int availableBytes = mInputStream.available();
// Ask for 1024 byte (or more if available)
byte[] newData = new byte[Math.max(1024, availableBytes)];
int gotBytes = mInputStream.read(newData);
// When we are here there is some new data available
appendToBuffer(newData, gotBytes);
// process all messages we already got
while (mReadBuff.length > 3) { // 3rd byte is packet size. continue only if we an determine packet size
byte[] extractedBuff = cutMessageFromBuffer();
if (extractedBuff == null) break; // message is not complete in buffer (wrong packet calls disconnection)
int command = (extractedBuff[5] & 0xFF) | ((extractedBuff[4] << 8) & 0xFF00);
MessageBase message;
if (processedMessage != null && processedMessage.getCommand() == command) {
message = processedMessage;
} else {
// get it from hash table
message = MessageHashTable.findMessage(command);
}
if (Config.logDanaMessageDetail)
log.debug("<<<<< " + message.getMessageName() + " " + message.toHexString(extractedBuff));
// process the message content
message.received = true;
message.handleMessage(extractedBuff);
synchronized (message) {
message.notify();
}
scheduleDisconnection();
}
}
} catch (Exception e) {
if (Config.logDanaSerialEngine && e.getMessage().indexOf("bt socket closed") < 0)
log.error("Thread exception: ", e);
mKeepRunning = false;
}
disconnect("EndOfLoop");
}
void appendToBuffer(byte[] newData, int gotBytes) {
// add newData to mReadBuff
byte[] newReadBuff = new byte[mReadBuff.length + gotBytes];
System.arraycopy(mReadBuff, 0, newReadBuff, 0, mReadBuff.length);
System.arraycopy(newData, 0, newReadBuff, mReadBuff.length, gotBytes);
mReadBuff = newReadBuff;
}
byte[] cutMessageFromBuffer() {
if (mReadBuff[0] == (byte) 0x7E && mReadBuff[1] == (byte) 0x7E) {
int length = (mReadBuff[2] & 0xFF) + 7;
// Check if we have enough data
if (mReadBuff.length < length) {
return null;
}
if (mReadBuff[length - 2] != (byte) 0x2E || mReadBuff[length - 1] != (byte) 0x2E) {
log.error("wrong packet lenght=" + length + " data " + MessageBase.toHexString(mReadBuff));
disconnect("wrong packet");
return null;
}
short crc = CRC.getCrc16(mReadBuff, 3, length - 7);
byte crcByte0 = (byte) (crc >> 8 & 0xFF);
byte crcByte1 = (byte) (crc & 0xFF);
byte crcByte0received = mReadBuff[length - 4];
byte crcByte1received = mReadBuff[length - 3];
if (crcByte0 != crcByte0received || crcByte1 != crcByte1received) {
log.error("CRC Error" + String.format("%02x ", crcByte0) + String.format("%02x ", crcByte1) + String.format("%02x ", crcByte0received) + String.format("%02x ", crcByte1received));
disconnect("crc error");
return null;
}
// Packet is verified here. extract data
byte[] extractedBuff = new byte[length];
System.arraycopy(mReadBuff, 0, extractedBuff, 0, length);
// remove extracted data from read buffer
byte[] unprocessedData = new byte[mReadBuff.length - length];
System.arraycopy(mReadBuff, length, unprocessedData, 0, unprocessedData.length);
mReadBuff = unprocessedData;
return extractedBuff;
} else {
log.error("Wrong beginning of packet len=" + mReadBuff.length + " " + MessageBase.toHexString(mReadBuff));
disconnect("Wrong beginning of packet");
return null;
}
}
public synchronized void sendMessage(MessageBase message) {
if (!mRfCommSocket.isConnected()) {
log.error("Socket not connected on sendMessage");
return;
}
processedMessage = message;
byte[] messageBytes = message.getRawMessageBytes();
if (Config.logDanaSerialEngine)
log.debug(">>>>> " + message.getMessageName() + " " + message.toHexString(messageBytes));
try {
mOutputStream.write(messageBytes);
} catch (Exception e) {
log.error("sendMessage write exception: ", e);
e.printStackTrace();
}
synchronized (message) {
try {
message.wait(5000);
} catch (InterruptedException e) {
log.error("sendMessage InterruptedException", e);
e.printStackTrace();
}
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
if (!message.received) {
log.warn("Reply not received " + message.getMessageName());
}
scheduleDisconnection();
}
public void scheduleDisconnection() {
class DisconnectRunnable implements Runnable {
public void run() {
disconnect("scheduleDisconnection");
scheduledDisconnection = null;
}
}
// prepare task for execution in 5 sec
// cancel waiting task to prevent sending multiple disconnections
if (scheduledDisconnection != null)
scheduledDisconnection.cancel(false);
Runnable task = new DisconnectRunnable();
final int sec = 5;
scheduledDisconnection = worker.schedule(task, sec, TimeUnit.SECONDS);
}
public void disconnect(String reason) {
mKeepRunning = false;
try {
mInputStream.close();
} catch (Exception e) {
if (Config.logDanaSerialEngine) log.debug(e.getMessage());
}
try {
mOutputStream.close();
} catch (Exception e) {
if (Config.logDanaSerialEngine) log.debug(e.getMessage());
}
try {
mRfCommSocket.close();
} catch (Exception e) {
if (Config.logDanaSerialEngine) log.debug(e.getMessage());
}
try {
System.runFinalization();
} catch (Exception e) {
if (Config.logDanaSerialEngine) log.debug(e.getMessage());
}
if (Config.logDanaSerialEngine) log.debug("Disconnected: " + reason);
}
}

View file

@ -0,0 +1,491 @@
package info.nightscout.androidaps.plugins.DanaR.Services;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Binder;
import android.os.IBinder;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
import info.nightscout.androidaps.plugins.DanaR.SerialIOThread;
import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgBolusProgress;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgBolusStart;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgBolusStop;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgCheckValue;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryAlarm;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryBasalHour;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryBolus;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryCarbo;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryDailyInsulin;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryDone;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryError;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryGlucose;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryRefill;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistorySuspend;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgPCCommStart;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgPCCommStop;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetActivateBasalProfile;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetBasalProfile;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetCarbsEntry;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetExtendedBolusStart;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetExtendedBolusStop;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTempBasalStart;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTempBasalStop;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingActiveProfile;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingBasal;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingGlucose;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingMaxValues;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingProfileRatios;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingProfileRatiosAll;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingPumpTime;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingShippingInfo;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgStatus;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgStatusBasic;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgStatusBolusExtended;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgStatusTempBasal;
import info.nightscout.androidaps.plugins.DanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRBolusStart;
import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus;
import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRNewStatus;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.SafeParse;
import info.nightscout.utils.ToastUtils;
public class ExecutionService extends Service {
private static Logger log = LoggerFactory.getLogger(ExecutionService.class);
private SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
private String devName;
private SerialIOThread mSerialIOThread;
private BluetoothSocket mRfcommSocket;
private BluetoothDevice mBTDevice;
private PowerManager.WakeLock mWakeLock;
private IBinder mBinder = new LocalBinder();
private DanaRPump danaRPump;
private Treatment bolusingTreatment = null;
private static Boolean connectionInProgress = false;
private static final Object connectionLock = new Object();
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
log.debug("Device has disconnected " + device.getName());//Device has disconnected
if (mBTDevice != null && mBTDevice.getName().equals(device.getName())) {
if (mSerialIOThread != null) {
mSerialIOThread.disconnect("BT disconnection broadcast");
}
MainApp.bus().post(new EventDanaRConnectionStatus(EventDanaRConnectionStatus.DISCONNECTED, 0));
}
}
}
};
public ExecutionService() {
registerBus();
MainApp.instance().getApplicationContext().registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
danaRPump = DanaRPlugin.getDanaRPump();
PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExecutionService");
}
public class LocalBinder extends Binder {
public ExecutionService getServiceInstance() {
return ExecutionService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
private void registerBus() {
try {
MainApp.bus().unregister(this);
} catch (RuntimeException x) {
// Ignore
}
MainApp.bus().register(this);
}
@Subscribe
public void onStatusEvent(EventAppExit event) {
if (Config.logFunctionCalls)
log.debug("EventAppExit received");
if (mSerialIOThread != null)
mSerialIOThread.disconnect("Application exit");
MainApp.instance().getApplicationContext().unregisterReceiver(receiver);
stopSelf();
if (Config.logFunctionCalls)
log.debug("EventAppExit finished");
}
public boolean isConnected() {
return mRfcommSocket != null && mRfcommSocket.isConnected();
}
public boolean isConnecting() {
return connectionInProgress;
}
public void connect(String from) {
if (danaRPump.password != -1 && danaRPump.password != SafeParse.stringToInt(SP.getString("danar_password", "-1"))) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumppassword), R.raw.error);
return;
}
while (isConnected() || isConnecting()) {
if (Config.logDanaBTComm)
log.debug("already connected/connecting from: " + from);
waitMsec(3000);
}
final long maxConnectionTime = 5 * 60 * 1000L; // 5 min
synchronized (connectionLock) {
//log.debug("entering connection while loop");
connectionInProgress = true;
mWakeLock.acquire();
getBTSocketForSelectedPump();
if (mRfcommSocket == null || mBTDevice == null)
return; // Device not found
long startTime = new Date().getTime();
while (!isConnected() && startTime + maxConnectionTime >= new Date().getTime()) {
long secondsElapsed = (new Date().getTime() - startTime) / 1000L;
MainApp.bus().post(new EventDanaRConnectionStatus(EventDanaRConnectionStatus.CONNECTING, (int) secondsElapsed));
if (Config.logDanaBTComm)
log.debug("connect waiting " + secondsElapsed + "sec from: " + from);
try {
mRfcommSocket.connect();
} catch (IOException e) {
//e.printStackTrace();
if (e.getMessage().contains("socket closed")) {
e.printStackTrace();
break;
}
}
waitMsec(1000);
if (isConnected()) {
if (mSerialIOThread != null) {
mSerialIOThread.disconnect("Recreate SerialIOThread");
}
mSerialIOThread = new SerialIOThread(mRfcommSocket);
MainApp.bus().post(new EventDanaRConnectionStatus(EventDanaRConnectionStatus.CONNECTED, 0));
if (!getPumpStatus()) {
mSerialIOThread.disconnect("getPumpStatus failed");
waitMsec(3000);
}
}
}
if (!isConnected()) {
MainApp.bus().post(new EventDanaRConnectionStatus(EventDanaRConnectionStatus.DISCONNECTED, 0));
log.error("Pump connection timed out");
}
connectionInProgress = false;
mWakeLock.release();
}
}
private void getBTSocketForSelectedPump() {
devName = SP.getString("danar_bt_name", "");
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : bondedDevices) {
if (devName.equals(device.getName())) {
mBTDevice = device;
try {
mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
log.error("Error creating socket: ", e);
}
break;
}
}
} else {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
}
if (mBTDevice == null) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
}
}
@Subscribe
public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
mSerialIOThread.disconnect("EventPreferenceChange");
}
private boolean getPumpStatus() {
try {
MsgStatus statusMsg = new MsgStatus();
MsgStatusBasic statusBasicMsg = new MsgStatusBasic();
MsgStatusTempBasal tempStatusMsg = new MsgStatusTempBasal();
MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended();
mSerialIOThread.sendMessage(tempStatusMsg); // do this before statusBasic because here is temp duration
mSerialIOThread.sendMessage(exStatusMsg);
mSerialIOThread.sendMessage(statusMsg);
mSerialIOThread.sendMessage(statusBasicMsg);
mSerialIOThread.sendMessage(new MsgSettingShippingInfo()); // TODO: show it somewhere
if (danaRPump.isNewPump) {
mSerialIOThread.sendMessage(new MsgCheckValue());
}
if (!statusMsg.received) {
mSerialIOThread.sendMessage(statusMsg);
}
if (!statusBasicMsg.received) {
mSerialIOThread.sendMessage(statusBasicMsg);
}
if (!tempStatusMsg.received) {
// Load of status of current basal rate failed, give one more try
mSerialIOThread.sendMessage(tempStatusMsg);
}
if (!exStatusMsg.received) {
// Load of status of current extended bolus failed, give one more try
mSerialIOThread.sendMessage(exStatusMsg);
}
// Check we have really current status of pump
if (!statusMsg.received || !statusBasicMsg.received || !tempStatusMsg.received || !exStatusMsg.received) {
waitMsec(10 * 1000);
log.debug("getPumpStatus failed");
return false;
}
Date now = new Date();
if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime()) {
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
//0x3203
mSerialIOThread.sendMessage(new MsgSettingBasal());
//0x3201
mSerialIOThread.sendMessage(new MsgSettingMaxValues());
mSerialIOThread.sendMessage(new MsgSettingGlucose());
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
mSerialIOThread.sendMessage(new MsgSettingProfileRatios());
mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll());
danaRPump.lastSettingsRead = now;
}
danaRPump.lastConnection = now;
MainApp.bus().post(new EventDanaRNewStatus());
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
public boolean tempBasal(int percent, int durationInHours) {
connect("tempBasal");
if (!isConnected()) return false;
mSerialIOThread.sendMessage(new MsgSetTempBasalStart(percent, durationInHours));
mSerialIOThread.sendMessage(new MsgStatusTempBasal());
return true;
}
public boolean tempBasalStop() {
connect("tempBasalStop");
if (!isConnected()) return false;
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
mSerialIOThread.sendMessage(new MsgStatusTempBasal());
return true;
}
public boolean extendedBolus(double insulin, int durationInHalfHours) {
connect("extendedBolus");
if (!isConnected()) return false;
mSerialIOThread.sendMessage(new MsgSetExtendedBolusStart(insulin, (byte) (durationInHalfHours & 0xFF)));
mSerialIOThread.sendMessage(new MsgStatusBolusExtended());
return true;
}
public boolean extendedBolusStop() {
connect("extendedBolusStop");
if (!isConnected()) return false;
mSerialIOThread.sendMessage(new MsgSetExtendedBolusStop());
mSerialIOThread.sendMessage(new MsgStatusBolusExtended());
return true;
}
public boolean bolus(Double amount, int carbs, Treatment t) {
bolusingTreatment = t;
MsgBolusStart start = new MsgBolusStart(amount);
MsgBolusProgress progress = new MsgBolusProgress(MainApp.bus(), amount, t);
MsgBolusStop stop = new MsgBolusStop(MainApp.bus(), amount, t);
connect("bolus");
if (!isConnected()) return false;
if (carbs > 0) {
Calendar time = Calendar.getInstance();
mSerialIOThread.sendMessage(new MsgSetCarbsEntry(time, carbs));
}
MainApp.bus().post(new EventDanaRBolusStart());
if (!stop.stopped) {
mSerialIOThread.sendMessage(start);
} else {
t.insulin = 0d;
return false;
}
while (!stop.stopped && !start.failed) {
waitMsec(100);
}
waitMsec(300);
bolusingTreatment = null;
getPumpStatus();
return true;
}
public void bolusStop() {
if (Config.logDanaBTComm)
log.debug("bolusStop >>>>> @ " + (bolusingTreatment == null ? "" : bolusingTreatment.insulin));
MsgBolusStop stop = new MsgBolusStop();
stop.forced = true;
if (isConnected()) {
mSerialIOThread.sendMessage(stop);
while (!stop.stopped) {
mSerialIOThread.sendMessage(stop);
waitMsec(200);
}
} else {
stop.stopped = true;
}
}
public boolean carbsEntry(int amount) {
connect("carbsEntry");
if (!isConnected()) return false;
Calendar time = Calendar.getInstance();
MsgSetCarbsEntry msg = new MsgSetCarbsEntry(time, amount);
mSerialIOThread.sendMessage(msg);
return true;
}
public boolean loadHistory(byte type) {
connect("loadHistory");
if (!isConnected()) return false;
MessageBase msg = null;
switch (type) {
case RecordTypes.RECORD_TYPE_ALARM:
msg = new MsgHistoryAlarm();
break;
case RecordTypes.RECORD_TYPE_BASALHOUR:
msg = new MsgHistoryBasalHour();
break;
case RecordTypes.RECORD_TYPE_BOLUS:
msg = new MsgHistoryBolus();
break;
case RecordTypes.RECORD_TYPE_CARBO:
msg = new MsgHistoryCarbo();
break;
case RecordTypes.RECORD_TYPE_DAILY:
msg = new MsgHistoryDailyInsulin();
break;
case RecordTypes.RECORD_TYPE_ERROR:
msg = new MsgHistoryError();
break;
case RecordTypes.RECORD_TYPE_GLUCOSE:
msg = new MsgHistoryGlucose();
break;
case RecordTypes.RECORD_TYPE_REFILL:
msg = new MsgHistoryRefill();
break;
case RecordTypes.RECORD_TYPE_SUSPEND:
msg = new MsgHistorySuspend();
break;
}
MsgHistoryDone done = new MsgHistoryDone();
mSerialIOThread.sendMessage(new MsgPCCommStart());
waitMsec(400);
mSerialIOThread.sendMessage(msg);
while (!done.received && mRfcommSocket.isConnected()) {
waitMsec(100);
}
waitMsec(200);
mSerialIOThread.sendMessage(new MsgPCCommStop());
return true;
}
public boolean updateBasalsInPump(final NSProfile profile) {
connect("updateBasalsInPump");
if (!isConnected()) return false;
double[] basal = buildDanaRProfileRecord(profile);
MsgSetBasalProfile msgSet = new MsgSetBasalProfile((byte) 0, basal);
mSerialIOThread.sendMessage(msgSet);
MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0);
mSerialIOThread.sendMessage(msgActivate);
getPumpStatus();
return true;
}
private double[] buildDanaRProfileRecord(NSProfile nsProfile) {
double[] record = new double[24];
for (Integer hour = 0; hour < 24; hour++) {
double value = nsProfile.getBasal(hour * 60 * 60);
if (Config.logDanaMessageDetail)
log.debug("NS basal value for " + hour + ":00 is " + value);
record[hour] = value;
}
return record;
}
private void waitMsec(long msecs) {
try {
Thread.sleep(msecs);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,173 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import android.annotation.TargetApi;
import android.os.Build;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import info.nightscout.androidaps.Config;
import info.nightscout.utils.CRC;
/*
* 00 01 02 03 04 05 06
*
* 7E 7E len F1 CMD SUB data CRC CRC 2E 2E
*/
public class MessageBase {
private static Logger log = LoggerFactory.getLogger(MessageBase.class);
private byte[] buffer = new byte[512];
private int position = 6;
public boolean received = false;
public boolean failed = false;
public void SetCommand(int cmd) {
this.buffer[4] = (byte) (cmd >> 8 & 0xFF);
this.buffer[5] = (byte) (cmd & 0xFF);
}
public void AddParamByte(byte data) {
this.buffer[this.position++] = data;
}
public void AddParamInt(int data) {
this.buffer[this.position++] = (byte) (data >> 8 & 0xFF);
this.buffer[this.position++] = (byte) (data & 0xFF);
}
public void AddParamDate(GregorianCalendar date) {
AddParamByte((byte) (date.get(Calendar.YEAR) - 1900 - 100));
AddParamByte((byte) (date.get(Calendar.MONTH) + 1));
AddParamByte((byte) (date.get(Calendar.DAY_OF_MONTH)));
AddParamByte((byte) (date.get(Calendar.HOUR)));
AddParamByte((byte) (date.get(Calendar.MINUTE)));
}
public byte[] getRawMessageBytes() {
this.buffer[0] = (byte) 0x7E;
this.buffer[1] = (byte) 0x7E;
int length = this.position - 3;
this.buffer[2] = (byte) length;
this.buffer[3] = (byte) 0xF1;
this.AddParamInt(CRC.getCrc16(this.buffer, 3, length));
this.buffer[length + 5] = (byte) 0x2E;
this.buffer[length + 6] = (byte) 0x2E;
return Arrays.copyOf(buffer, length + 7);
}
public String getMessageName() {
return MessageOriginalNames.getName(getCommand());
}
public void handleMessage(byte[] bytes) {
if (Config.logDanaMessageDetail) {
if (bytes.length > 6) {
int command = (bytes[5] & 0xFF) | ((bytes[4] << 8) & 0xFF00);
log.debug("UNPROCESSED MSG: " + getMessageName() + " Command: " + String.format("%04X", command) + " Data: " + toHexString(bytes));
} else {
log.debug("MISFORMATTED MSG: " + toHexString(bytes));
}
}
}
public int getCommand() {
int command = byteFromRawBuff(buffer, 5) | (byteFromRawBuff(buffer, 4) << 8);
return command;
}
public static int byteFromRawBuff(byte[] buff, int offset) {
return buff[offset] & 0xFF;
}
public static int intFromBuff(byte[] buff, int offset, int length) {
offset += 6;
switch (length) {
case 1:
return byteFromRawBuff(buff, offset);
case 2:
return (byteFromRawBuff(buff, offset) << 8) + byteFromRawBuff(buff, offset + 1);
case 3:
return (byteFromRawBuff(buff, offset + 2) << 16) + (byteFromRawBuff(buff, offset + 1) << 8) + byteFromRawBuff(buff, offset);
case 4:
return (byteFromRawBuff(buff, offset + 3) << 24) + (byteFromRawBuff(buff, offset + 2) << 16) + (byteFromRawBuff(buff, offset + 1) << 8) + byteFromRawBuff(buff, offset);
}
return 0;
}
public static Date dateTimeFromBuff(byte[] buff, int offset) {
Date date =
new Date(
100 + intFromBuff(buff, offset, 1),
intFromBuff(buff, offset + 1, 1) - 1,
intFromBuff(buff, offset + 2, 1),
intFromBuff(buff, offset + 3, 1),
intFromBuff(buff, offset + 4, 1),
0
);
return date;
}
public static Date dateTimeSecFromBuff(byte[] buff, int offset) {
Date date =
new Date(
100 + intFromBuff(buff, offset, 1),
intFromBuff(buff, offset + 1, 1) - 1,
intFromBuff(buff, offset + 2, 1),
intFromBuff(buff, offset + 3, 1),
intFromBuff(buff, offset + 4, 1),
intFromBuff(buff, offset + 5, 1)
);
return date;
}
public static Date dateFromBuff(byte[] buff, int offset) {
Date date =
new Date(
100 + intFromBuff(buff, offset, 1),
intFromBuff(buff, offset + 1, 1) - 1,
intFromBuff(buff, offset + 2, 1)
);
return date;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String stringFromBuff(byte[] buff, int offset, int length) {
byte[] strbuff = new byte[length];
System.arraycopy(buff, offset + 6, strbuff, 0, length);
return new String(strbuff, StandardCharsets.UTF_8);
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String asciiStringFromBuff(byte[] buff, int offset, int length) {
byte[] strbuff = new byte[length];
System.arraycopy(buff, offset + 6, strbuff, 0, length);
for (int pos = 0; pos < length; pos++)
strbuff[pos] += 65; // "A"
return new String(strbuff, StandardCharsets.UTF_8);
}
public static String toHexString(byte[] buff) {
StringBuffer sb = new StringBuffer();
int count = 0;
for (byte element : buff) {
sb.append(String.format("%02x ", element));
if (++count % 4 == 0) sb.append(" ");
}
return sb.toString();
}
}

View file

@ -0,0 +1,83 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
/**
* Created by mike on 28.05.2016.
*/
public class MessageHashTable {
private static Logger log = LoggerFactory.getLogger(MessageHashTable.class);
public static HashMap<Integer, MessageBase> messages = null;
static {
if (messages == null) {
messages = new HashMap<Integer, MessageBase>();
put(new MsgBolusStop()); // 0x0101 CMD_MEALINS_STOP
put(new MsgBolusStart()); // 0x0102 CMD_MEALINS_START_DATA
put(new MsgBolusProgress()); // 0x0202 CMD_PUMP_THIS_REMAINDER_MEAL_INS
put(new MsgStatusProfile()); // 0x0204 CMD_PUMP_CALCULATION_SETTING
put(new MsgStatusTempBasal()); // 0x0205 CMD_PUMP_EXERCISE_MODE
put(new MsgStatusBolusExtended()); // 0x0207 CMD_PUMP_EXPANS_INS_I
put(new MsgStatusBasic()); // 0x020A CMD_PUMP_INITVIEW_I
put(new MsgStatus()); // 0x020B CMD_PUMP_STATUS
put(new MsgInitConnStatusTime()); // 0x0301 CMD_PUMPINIT_TIME_INFO
put(new MsgInitConnStatusBolus()); // 0x0302 CMD_PUMPINIT_BOLUS_INFO
put(new MsgInitConnStatusBasic()); // 0x0303 CMD_PUMPINIT_INIT_INFO
put(new MsgInitConnStatusOption()); // 0x0304 CMD_PUMPINIT_OPTION
put(new MsgSetTempBasalStart()); // 0x0401 CMD_PUMPSET_EXERCISE_S
put(new MsgSetCarbsEntry()); // 0x0402 CMD_PUMPSET_HIS_S
put(new MsgSetTempBasalStop()); // 0x0403 CMD_PUMPSET_EXERCISE_STOP
put(new MsgSetExtendedBolusStop()); // 0x0406 CMD_PUMPSET_EXPANS_INS_STOP
put(new MsgSetExtendedBolusStart()); // 0x0407 CMD_PUMPSET_EXPANS_INS_S
put(new MsgOcclusion()); // 0x0601 CMD_PUMPOWAY_SYSTEM_STATUS
put(new MsgPCCommStart()); // 0x3001 CMD_CONNECT
put(new MsgPCCommStop()); // 0x3002 CMD_DISCONNECT
put(new MsgHistoryBolus()); // 0x3101 CMD_HISTORY_MEAL_INS
put(new MsgHistoryDailyInsulin()); // 0x3102 CMD_HISTORY_DAY_INS
put(new MsgHistoryGlucose()); // 0x3104 CMD_HISTORY_GLUCOSE
put(new MsgHistoryAlarm()); // 0x3105 CMD_HISTORY_ALARM
put(new MsgHistoryError()); // 0x3106 CMD_HISTORY_ERROR
put(new MsgHistoryCarbo()); // 0x3107 CMD_HISTORY_CARBOHY
put(new MsgHistoryRefill()); // 0x3108 CMD_HISTORY_REFILL
put(new MsgHistorySuspend()); // 0x3109 CMD_HISTORY_SUSPEND
put(new MsgHistoryBasalHour()); // 0x310A CMD_HISTORY_BASAL_HOUR
put(new MsgHistoryDone()); // 0x31F1 CMD_HISTORY_DONT_USED
put(new MsgSettingBasal()); // 0x3202 CMD_SETTING_V_BASAL_INS_I
put(new MsgSettingProfileRatios()); // 0x3204 CMD_SETTING_V_CCC_I
put(new MsgSettingMaxValues()); // 0x3205 CMD_SETTING_V_MAX_VALUE_I
put(new MsgSettingBasalProfileAll()); // 0x3206 CMD_SETTING_V_BASAL_PROFILE_ALL
put(new MsgSettingShippingInfo()); // 0x3207 CMD_SETTING_V_SHIPPING_I
put(new MsgSettingGlucose()); // 0x3209 CMD_SETTING_V_GLUCOSEandEASY
put(new MsgSettingPumpTime()); // 0x320A CMD_SETTING_V_TIME_I
put(new MsgSettingUserOptions()); // 0x320B CMD_SETTING_V_USER_OPTIONS
put(new MsgSettingActiveProfile()); // 0x320C CMD_SETTING_V_PROFILE_NUMBER
put(new MsgSettingProfileRatiosAll()); // 0x320D CMD_SETTING_V_CIR_CF_VALUE
put(new MsgSetBasalProfile()); // 0x3306 CMD_SETTING_BASAL_PROFILE_S
put(new MsgSetActivateBasalProfile()); // 0x330C CMD_SETTING_PROFILE_NUMBER_S
put(new MsgHistoryAllDone()); // 0x41F1 CMD_HISTORY_ALL_DONE
put(new MsgHistoryAll()); // 0x41F2 CMD_HISTORY_ALL
put(new MsgHistoryNewDone()); // 0x42F1 CMD_HISTORY_NEW_DONE
put(new MsgHistoryNew()); // 0x42F2 CMD_HISTORY_NEW
put(new MsgCheckValue()); // 0xF0F1 CMD_PUMP_CHECK_VALUE
}
}
public static void put(MessageBase message) {
int command = message.getCommand();
//String name = MessageOriginalNames.getName(command);
messages.put(command, message);
//log.debug(String.format("%04x ", command) + " " + name);
}
public static MessageBase findMessage(Integer command) {
if (messages.containsKey(command)) {
return messages.get(command);
} else {
return new MessageBase();
}
}
}

View file

@ -0,0 +1,163 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
/**
* Created by mike on 28.05.2016.
*/
public class MessageOriginalNames {
private static Logger log = LoggerFactory.getLogger(MessageOriginalNames.class);
public static HashMap<Integer,String> messageNames;
static {
messageNames = new HashMap<Integer,String>();
messageNames.put(0x3001, "CMD_CONNECT");
messageNames.put(0x3002, "CMD_DISCONNECT");
messageNames.put(0x3101, "CMD_HISTORY_MEAL_INS");
messageNames.put(0x3102, "CMD_HISTORY_DAY_INS");
messageNames.put(0x3103, "CMD_HISTORY_AIR_SUB");
messageNames.put(0x3104, "CMD_HISTORY_GLUCOSE");
messageNames.put(0x3105, "CMD_HISTORY_ALARM");
messageNames.put(0x3106, "CMD_HISTORY_ERROR");
messageNames.put(0x3107, "CMD_HISTORY_CARBOHY");
messageNames.put(0x3108, "CMD_HISTORY_REFILL");
messageNames.put(0x3109, "CMD_HISTORY_SUSPEND");
messageNames.put(0x310a, "CMD_HISTORY_BASAL_HOUR");
messageNames.put(0x310b, "CMD_HISTORY_TB");
messageNames.put(0x31f1, "CMD_HISTORY_STOP");
messageNames.put(0x31f2, "CMD_HISTORY_LAST_T_R");
messageNames.put(0x31f3, "CMD_HISTORY_LAST_T_S");
messageNames.put(0x0501, "CMD_HISPAGE_MEAL_INS");
messageNames.put(0x0502, "CMD_HISPAGE_DAY_INS");
messageNames.put(0x0503, "CMD_HISPAGE_AIR_SUB");
messageNames.put(0x0504, "CMD_HISPAGE_GLUCOSE");
messageNames.put(0x0505, "CMD_HISPAGE_ALARM");
messageNames.put(0x0506, "CMD_HISPAGE_ERROR");
messageNames.put(0x0507, "CMD_HISPAGE_CARBOHY");
messageNames.put(0x0508, "CMD_HISPAGE_REFILL");
messageNames.put(0x050a, "CMD_HISPAGE_DAILTY_PRE_DATA");
messageNames.put(0x050b, "CMD_HISPAGE_BOLUS_AVG");
messageNames.put(0x050c, "CMD_HISPAGE_BASAL_RECORD");
messageNames.put(0x050d, "CMD_HISPAGE_TB");
messageNames.put(0x3201, "CMD_SETTING_V_MEAL_INS_I");
messageNames.put(0x3202, "CMD_SETTING_V_BASAL_INS_I");
messageNames.put(0x3203, "CMD_SETTING_V_MEAL_SETTING_I");
messageNames.put(0x3204, "CMD_SETTING_V_CCC_I");
messageNames.put(0x3205, "CMD_SETTING_V_MAX_VALUE_I");
messageNames.put(0x3206, "CMD_SETTING_V_BASAL_PROFILE_ALL");
messageNames.put(0x3207, "CMD_SETTING_V_SHIPPING_I");
messageNames.put(0x3208, "CMD_SETTING_V_CLOGGIN_SENS_I");
messageNames.put(0x3209, "CMD_SETTING_V_GLUCOSEandEASY");
messageNames.put(0x320a, "CMD_SETTING_V_TIME_I");
messageNames.put(0x320b, "CMD_SETTING_V_USER_OPTIONS");
messageNames.put(0x320c, "CMD_SETTING_V_PROFILE_NUMBER");
messageNames.put(0x320d, "CMD_SETTING_V_CIR_CF_VALUE");
messageNames.put(0x3301, "CMD_SETTING_MEAL_INS_S");
messageNames.put(0x3302, "CMD_SETTING_Based_INS_S");
messageNames.put(0x3303, "CMD_SETTING_MEAL_SETTING_S");
messageNames.put(0x3304, "CMD_SETTING_CCC_S");
messageNames.put(0x3305, "CMD_SETTING_MAX_VALUE_S");
messageNames.put(0x3306, "CMD_SETTING_BASAL_PROFILE_S");
messageNames.put(0x3307, "CMD_SETTING_SHIPPING_S");
messageNames.put(0x3308, "CMD_SETTING_CLOGGIN_SENS_S");
messageNames.put(0x3309, "CMD_SETTING_GLUCOSEandEASY_S");
messageNames.put(0x330a, "CMD_SETTING_TIME_S");
messageNames.put(0x330b, "CMD_SETTING_USER_OPTIONS_S");
messageNames.put(0x330c, "CMD_SETTING_PROFILE_NUMBER_S");
messageNames.put(0x330d, "CMD_SETTING_CIR_CF_VALUE_S");
messageNames.put(0x0101, "CMD_MEALINS_STOP");
messageNames.put(0x0102, "CMD_MEALINS_START_DATA");
messageNames.put(0x0103, "CMD_MEALINS_START_NODATA");
messageNames.put(0x0104, "CMD_MEALINS_START_DATA_SPEED");
messageNames.put(0x0105, "CMD_MEALINS_START_NODATA_SPEED");
messageNames.put(0x0201, "CMD_PUMP_ACT_INS_VALUE");
messageNames.put(0x0202, "CMD_PUMP_THIS_REMAINDER_MEAL_INS");
messageNames.put(0x0203, "CMD_PUMP_BASE_SET");
messageNames.put(0x0204, "CMD_PUMP_CALCULATION_SETTING");
messageNames.put(0x0205, "CMD_PUMP_EXERCISE_MODE");
messageNames.put(0x0206, "CMD_PUMP_MEAL_INS_I");
messageNames.put(0x0207, "CMD_PUMP_EXPANS_INS_I");
messageNames.put(0x0208, "CMD_PUMP_EXPANS_INS_RQ");
messageNames.put(0x0209, "CMD_PUMP_DUAL_INS_RQ");
messageNames.put(0x020a, "CMD_PUMP_INITVIEW_I");
messageNames.put(0x020b, "CMD_PUMP_STATUS");
messageNames.put(0x020c, "CMD_PUMP_CAR_N_CIR");
messageNames.put(0x0301, "CMD_PUMPINIT_TIME_INFO");
messageNames.put(0x0302, "CMD_PUMPINIT_BOLUS_INFO");
messageNames.put(0x0303, "CMD_PUMPINIT_INIT_INFO");
messageNames.put(0x0304, "CMD_PUMPINIT_OPTION");
messageNames.put(0x0401, "CMD_PUMPSET_EXERCISE_S");
messageNames.put(0x0402, "CMD_PUMPSET_HIS_S");
messageNames.put(0x0403, "CMD_PUMPSET_EXERCISE_STOP");
messageNames.put(0x0404, "CMD_PUMPSET_PAUSE");
messageNames.put(0x0405, "CMD_PUMPSET_PAUSE_STOP");
messageNames.put(0x0406, "CMD_PUMPSET_EXPANS_INS_STOP");
messageNames.put(0x0407, "CMD_PUMPSET_EXPANS_INS_S");
messageNames.put(0x0408, "CMD_PUMPSET_DUAL_S");
messageNames.put(0x0409, "CMD_PUMPSET_EASY_OFF");
messageNames.put(0x0601, "CMD_PUMPOWAY_SYSTEM_STATUS");
messageNames.put(0x0602, "CMD_PUMPOWAY_GLUCOSE_ALARM");
messageNames.put(0x0603, "CMD_PUMPOWAY_LOW_INSULIN_ALARM");
messageNames.put(0x0610, "CMD_PUMP_ALARM_TIEOUT");
messageNames.put(0x0701, "CMD_MSGRECEP_TAKE_SUGAR");
messageNames.put(0x0702, "CMD_MSGRECEP_GO_TO_DOCTOR");
messageNames.put(0x0703, "CMD_MSGRECEP_CALL_TO_CAREGIVER");
messageNames.put(0x0704, "CMD_MSGRECEP_CHECK_GLUCOSE_AGAIN");
messageNames.put(0x0705, "CMD_MSGRECEP_CALL_TO_HOME");
messageNames.put(0x0706, "CMD_MSGRECEP_DO_DELIVER");
messageNames.put(0x0801, "CMD_MSGSEND_YES_I_DO");
messageNames.put(0x0802, "CMD_MSGSEND_NO_I_CANNOT");
messageNames.put(0x0803, "CMD_MSGSEND_CALL_TO_ME_MOM");
messageNames.put(0x0804, "CMD_MSGSEND_DO_NOT_INFUSE");
messageNames.put(0x0901, "CMD_FILL_REFILL_COUNT");
messageNames.put(0x0902, "CMD_FILL_PRIME_CHECK");
messageNames.put(0x0903, "CMD_FILL_PRIME_END");
messageNames.put(0x0904, "CMD_FILL_PRIME_STOP");
messageNames.put(0x0905, "CMD_FILL_PRIME_PAUSE");
messageNames.put(0x0906, "CMD_FILL_PRIME_RATE");
messageNames.put(0x41f2, "CMD_HISTORY_ALL");
messageNames.put(0x42f2, "CMD_HISTORY_NEW");
messageNames.put(0x41f1, "CMD_HISTORY_ALL_DONE");
messageNames.put(0x42f1, "CMD_HISTORY_NEW_DONE");
messageNames.put(0xF0F1, "CMD_PUMP_CHECK_VALUE");
messageNames.put(0xF0F2, "CMD_PUMP_TIMECHANGE_CHECK");
messageNames.put(0xF0F3, "CMD_PUMP_TIMECHANGE_CLEAR");
messageNames.put(0x43F2, "CMD_HISTORY_DATEOVER_ALL");
messageNames.put(0x4300, "CMD_HISTORY_DATEOVER_DONE");
}
public static String getName(Integer command) {
if (messageNames.containsKey(command))
return messageNames.get(command);
else {
log.debug("Unknown command: " + String.format("%04X", command));
return "UNKNOWN_COMMAND";
}
}
}

View file

@ -0,0 +1,50 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import com.squareup.otto.Bus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
public class MsgBolusProgress extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgBolusProgress.class);
private static Bus bus = null;
private static Treatment t;
private static double amount;
public int progress = -1;
public MsgBolusProgress() {
SetCommand(0x0202);
}
public MsgBolusProgress(Bus bus, double amount, Treatment t) {
this();
this.amount = amount;
this.t = t;
this.bus = bus;
}
@Override
public void handleMessage(byte[] bytes) {
progress = intFromBuff(bytes, 0, 2);
Double done = (amount * 100 - progress) / 100d;
t.insulin = done;
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
bolusingEvent.status = String.format(MainApp.sResources.getString(R.string.bolusdelivering), done);
bolusingEvent.t = t;
bolusingEvent.percent = Math.min((int) (done / amount * 100), 100);
if (Config.logDanaMessageDetail) {
log.debug("Bolus remaining: " + progress + " delivered: " + done);
}
bus.post(bolusingEvent);
}
}

View file

@ -0,0 +1,39 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
public class MsgBolusStart extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgBolusStart.class);
public MsgBolusStart() {
SetCommand(0x0102);
}
public MsgBolusStart(double amount) {
this();
// HARDCODED LIMIT
amount = MainApp.getConfigBuilder().applyBolusConstraints(amount);
if (amount < 0) amount = 0d;
if (amount > BuildConfig.MAXBOLUS) amount = BuildConfig.MAXBOLUS;
AddParamInt((int) (amount * 100));
}
@Override
public void handleMessage(byte[] bytes) {
int result = intFromBuff(bytes, 0, 1);
if (result != 2) {
failed = true;
log.debug("Messsage response: " + result + " FAILED!!");
} else {
if (Config.logDanaMessageDetail)
log.debug("Messsage response: " + result);
}
}
}

View file

@ -0,0 +1,48 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import com.squareup.otto.Bus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
public class MsgBolusStop extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgBolusStop.class);
private static Treatment t;
private static Double amount;
private static Bus bus = null;
public static boolean stopped = false;
public static boolean forced = false;
public MsgBolusStop() {
SetCommand(0x0101);
stopped = false;
}
public MsgBolusStop(Bus bus, Double amount, Treatment t) {
this();
this.bus = bus;
this.t = t;
this.amount = amount;
forced = false;
}
@Override
public void handleMessage(byte[] bytes) {
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
stopped = true;
if (!forced) {
t.insulin = amount;
bolusingEvent.status = MainApp.sResources.getString(R.string.overview_bolusprogress_delivered);
bolusingEvent.percent = 100;
} else {
bolusingEvent.status = MainApp.sResources.getString(R.string.overview_bolusprogress_stoped);
}
bus.post(bolusingEvent);
}
}

View file

@ -0,0 +1,31 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
/**
* Created by mike on 30.06.2016.
*/
public class MsgCheckValue extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgCheckValue.class);
public MsgCheckValue() {
SetCommand(0xF0F1);
}
@Override
public void handleMessage(byte[] bytes) {
int a = intFromBuff(bytes, 0, 1);
int b = intFromBuff(bytes, 1, 1);
if (a != 3 || b <= 0) {
// another message will follow
} else {
}
if (Config.logDanaMessageDetail)
log.debug("Response: " + String.format("%02X ", a) + String.format("%02X ", b));
}
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryAlarm extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistoryAlarm.class);
public MsgHistoryAlarm() {
SetCommand(0x3105);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,160 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import com.j256.ormlite.dao.Dao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.Date;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.db.DanaRHistoryRecord;
import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRSyncStatus;
public class MsgHistoryAll extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgHistoryAll.class);
public MsgHistoryAll() {
SetCommand(0x41F2);
}
@Override
public void handleMessage(byte[] bytes) {
byte recordCode = (byte) intFromBuff(bytes, 0, 1);
Date date = dateFromBuff(bytes, 1); // 3 bytes
Date datetime = dateTimeFromBuff(bytes, 1); // 5 bytes
Date datetimewihtsec = dateTimeSecFromBuff(bytes, 1); // 6 bytes
double dailyBasal = intFromBuff(bytes, 4, 2) * 0.01d;
double dailyBolus = intFromBuff(bytes, 6, 2) * 0.01d;
byte paramByte5 = (byte) intFromBuff(bytes, 4, 1);
byte paramByte6 = (byte) intFromBuff(bytes, 5, 1);
byte paramByte7 = (byte) intFromBuff(bytes, 6, 1);
byte paramByte8 = (byte) intFromBuff(bytes, 7, 1);
double value = (double) intFromBuff(bytes, 8, 2);
EventDanaRSyncStatus ev = new EventDanaRSyncStatus();
DanaRHistoryRecord danaRHistoryRecord = new DanaRHistoryRecord();
danaRHistoryRecord.setRecordCode(recordCode);
danaRHistoryRecord.setBytes(bytes);
String messageType = "";
switch (recordCode) {
case RecordTypes.RECORD_TYPE_BOLUS:
danaRHistoryRecord.setRecordDate(datetime);
switch (0xF0 & paramByte8) {
case 0xA0:
danaRHistoryRecord.setBolusType("DS");
messageType += "DS bolus";
break;
case 0xC0:
danaRHistoryRecord.setBolusType("E");
messageType += "E bolus";
break;
case 0x80:
danaRHistoryRecord.setBolusType("S");
messageType += "S bolus";
break;
case 0x90:
danaRHistoryRecord.setBolusType("DE");
messageType += "DE bolus";
break;
default:
danaRHistoryRecord.setBolusType("None");
break;
}
danaRHistoryRecord.setRecordDuration(((int) paramByte8 & 0x0F) * 60 + (int) paramByte7);
danaRHistoryRecord.setRecordValue(value * 0.01);
break;
case RecordTypes.RECORD_TYPE_DAILY:
messageType += "dailyinsulin";
danaRHistoryRecord.setRecordDate(date);
danaRHistoryRecord.setRecordDailyBasal(dailyBasal);
danaRHistoryRecord.setRecordDailyBolus(dailyBolus);
break;
case RecordTypes.RECORD_TYPE_PRIME:
messageType += "prime";
danaRHistoryRecord.setRecordDate(datetimewihtsec);
danaRHistoryRecord.setRecordValue(value * 0.01);
break;
case RecordTypes.RECORD_TYPE_ERROR:
messageType += "error";
danaRHistoryRecord.setRecordDate(datetimewihtsec);
danaRHistoryRecord.setRecordValue(value * 0.01);
break;
case RecordTypes.RECORD_TYPE_REFILL:
messageType += "refill";
danaRHistoryRecord.setRecordDate(datetimewihtsec);
danaRHistoryRecord.setRecordValue(value * 0.01);
break;
case RecordTypes.RECORD_TYPE_BASALHOUR:
messageType += "basal hour";
danaRHistoryRecord.setRecordDate(datetimewihtsec);
danaRHistoryRecord.setRecordValue(value * 0.01);
break;
case RecordTypes.RECORD_TYPE_TB:
messageType += "tb";
danaRHistoryRecord.setRecordDate(datetimewihtsec);
danaRHistoryRecord.setRecordValue(value * 0.01);
break;
case RecordTypes.RECORD_TYPE_GLUCOSE:
messageType += "glucose";
danaRHistoryRecord.setRecordDate(datetimewihtsec);
danaRHistoryRecord.setRecordValue(value);
break;
case RecordTypes.RECORD_TYPE_CARBO:
messageType += "carbo";
danaRHistoryRecord.setRecordDate(datetimewihtsec);
danaRHistoryRecord.setRecordValue(value);
break;
case RecordTypes.RECORD_TYPE_ALARM:
messageType += "alarm";
danaRHistoryRecord.setRecordDate(datetimewihtsec);
String strAlarm = "None";
switch ((int) paramByte8) {
case 67:
strAlarm = "Check";
break;
case 79:
strAlarm = "Occlusion";
break;
case 66:
strAlarm = "Low Battery";
break;
case 83:
strAlarm = "Shutdown";
break;
}
danaRHistoryRecord.setRecordAlarm(strAlarm);
danaRHistoryRecord.setRecordValue(value * 0.01);
break;
case RecordTypes.RECORD_TYPE_SUSPEND:
messageType += "suspend";
danaRHistoryRecord.setRecordDate(datetimewihtsec);
String strRecordValue = "Off";
if ((int) paramByte8 == 79)
strRecordValue = "On";
danaRHistoryRecord.setStringRecordValue(strRecordValue);
break;
}
try {
Dao<DanaRHistoryRecord, String> daoHistoryRecords = MainApp.getDbHelper().getDaoDanaRHistory();
daoHistoryRecords.createIfNotExists(danaRHistoryRecord);
} catch (SQLException e) {
log.error(e.getMessage(), e);
}
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
ev.message = df.format(new Date(danaRHistoryRecord.getRecordDate()));
ev.message += " " + messageType;
MainApp.bus().post(ev);
return;
}
}

View file

@ -0,0 +1,23 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
public class MsgHistoryAllDone extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgHistoryAllDone.class);
public static boolean received = false;
public MsgHistoryAllDone() {
SetCommand(0x41F1);
received = false;
}
@Override
public void handleMessage(byte[] bytes) {
received = true;
if (Config.logDanaMessageDetail)
log.debug("History all done received");
}
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryBasalHour extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistoryBasalHour.class);
public MsgHistoryBasalHour() {
SetCommand(0x310A);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryBolus extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistoryBolus.class);
public MsgHistoryBolus() {
SetCommand(0x3101);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryCarbo extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistoryCarbo.class);
public MsgHistoryCarbo() {
SetCommand(0x3107);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryDailyInsulin extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistoryDailyInsulin.class);
public MsgHistoryDailyInsulin() {
SetCommand(0x3102);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,27 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryDone extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgHistoryDone.class);
public static boolean received = false;
public MsgHistoryDone() {
SetCommand(0x31F1);
received = false;
}
@Override
public void handleMessage(byte[] bytes) {
received = true;
if (Config.logDanaMessageDetail)
log.debug("History done received");
}
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryError extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistoryError.class);
public MsgHistoryError() {
SetCommand(0x3106);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryGlucose extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistoryGlucose.class);
public MsgHistoryGlucose() {
SetCommand(0x3104);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryNew extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistoryNew.class);
public MsgHistoryNew() {
SetCommand(0x42F2);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,26 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryNewDone extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgHistoryNewDone.class);
public static boolean received = false;
public MsgHistoryNewDone() {
SetCommand(0x42F1);
received = false;
}
@Override
public void handleMessage(byte[] bytes) {
received = true;
if (Config.logDanaMessageDetail)
log.debug("History new done received");
}
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistoryRefill extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistoryRefill.class);
public MsgHistoryRefill() {
SetCommand(0x3108);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 20.07.2016.
*/
public class MsgHistorySuspend extends MsgHistoryAll {
private static Logger log = LoggerFactory.getLogger(MsgHistorySuspend.class);
public MsgHistorySuspend() {
SetCommand(0x3109);
}
// Handle message taken from MsgHistoryAll
}

View file

@ -0,0 +1,36 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MsgInitConnStatusBasic extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgInitConnStatusBasic.class);
public MsgInitConnStatusBasic() {
SetCommand(0x0303);
}
@Override
public void handleMessage(byte[] bytes) {
int a = intFromBuff(bytes, 0, 1);
int b = intFromBuff(bytes, 1, 1);
int c = intFromBuff(bytes, 2, 1);
int d = intFromBuff(bytes, 3, 1);
int e = intFromBuff(bytes, 4, 1);
int f = intFromBuff(bytes, 5, 1);
int g = intFromBuff(bytes, 6, 1);
int h = intFromBuff(bytes, 7, 1);
int i = intFromBuff(bytes, 8, 1);
int j = intFromBuff(bytes, 9, 1);
int k = intFromBuff(bytes, 10, 1);
int l = intFromBuff(bytes, 11, 1);
int m = intFromBuff(bytes, 12, 1);
int n = intFromBuff(bytes, 13, 1);
int o;
try {
o = intFromBuff(bytes, 21, 1);
} catch (Exception ex) {
o = 0;
}
}
}

View file

@ -0,0 +1,24 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 28.05.2016.
*/
public class MsgInitConnStatusBolus extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgInitConnStatusBolus.class);
public MsgInitConnStatusBolus() {
SetCommand(0x0302);
}
@Override
public void handleMessage(byte[] bytes) {
int a1 = intFromBuff(bytes, 0, 1);
int a2 = intFromBuff(bytes, 1, 1);
int c = intFromBuff(bytes, 8, 2);
int d = c / 100;
int e = intFromBuff(bytes, 10, 2);
}
}

View file

@ -0,0 +1,37 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
/**
* Created by mike on 28.05.2016.
*/
public class MsgInitConnStatusOption extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgInitConnStatusOption.class);
public MsgInitConnStatusOption() {
SetCommand(0x0304);
}
@Override
public void handleMessage(byte[] bytes) {
int a = intFromBuff(bytes, 0, 1);
int b = intFromBuff(bytes, 1, 1);
int c = intFromBuff(bytes, 2, 1);
int d = intFromBuff(bytes, 3, 1);
int e = intFromBuff(bytes, 4, 1);
int f = intFromBuff(bytes, 5, 1);
int g = intFromBuff(bytes, 6, 1);
int h = intFromBuff(bytes, 7, 1);
int i = intFromBuff(bytes, 8, 1);
if (bytes.length >= 21) {
DanaRPlugin.getDanaRPump().password = intFromBuff(bytes, 9, 2) ^ 0x3463;
if (Config.logDanaMessageDetail)
log.debug("Pump password: " + DanaRPlugin.getDanaRPump().password);
}
}
}

View file

@ -0,0 +1,24 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.Config;
public class MsgInitConnStatusTime extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgInitConnStatusTime.class);
public MsgInitConnStatusTime() {
SetCommand(0x0301);
}
@Override
public void handleMessage(byte[] bytes) {
Date time = dateTimeSecFromBuff(bytes, 0);
if (Config.logDanaMessageDetail)
log.debug("Pump time: " + time);
}
}

View file

@ -0,0 +1,61 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
import info.nightscout.client.data.DbLogger;
import info.nightscout.utils.DateUtil;
public class MsgOcclusion extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgOcclusion.class);
public MsgOcclusion() {
SetCommand(0x0601);
}
@Override
public void handleMessage(byte[] bytes) {
if (Config.logDanaMessageDetail)
log.debug("Oclusion detected");
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
MsgBolusStop.stopped = true;
bolusingEvent.status = MainApp.sResources.getString(R.string.overview_bolusiprogress_occlusion);
MainApp.bus().post(bolusingEvent);
sendToNSClient();
}
public void sendToNSClient() {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
JSONObject data = new JSONObject();
try {
data.put("eventType", "Announcement");
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("notes", MainApp.sResources.getString(R.string.overview_bolusiprogress_occlusion));
data.put("isAnnouncement", true);
} catch (JSONException e) {
e.printStackTrace();
}
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), MsgOcclusion.class);
}
}

View file

@ -0,0 +1,19 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
public class MsgPCCommStart extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgPCCommStart.class);
public MsgPCCommStart() {
SetCommand(0x3001);
}
@Override
public void handleMessage(byte[] bytes) {
if (Config.logDanaMessageDetail)
log.debug("PC comm start received");
}
}

View file

@ -0,0 +1,19 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
public class MsgPCCommStop extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgPCCommStop.class);
public MsgPCCommStop() {
SetCommand(0x3002);
}
@Override
public void handleMessage(byte[] bytes) {
if (Config.logDanaMessageDetail)
log.debug("PC comm stop received");
}
}

View file

@ -0,0 +1,34 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
public class MsgSetActivateBasalProfile extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSetActivateBasalProfile.class);
public MsgSetActivateBasalProfile() {
SetCommand(0x330C);
}
// index 0-3
public MsgSetActivateBasalProfile(byte index) {
this();
AddParamByte(index);
if (Config.logDanaMessageDetail)
log.debug("Activate basal profile: " + index);
}
@Override
public void handleMessage(byte[] bytes) {
int result = intFromBuff(bytes, 0, 1);
if (result != 1) {
failed = true;
log.debug("Activate basal profile result: " + result + " FAILED!!!");
} else {
if (Config.logDanaMessageDetail)
log.debug("Activate basal profile result: " + result);
}
}
}

View file

@ -0,0 +1,39 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
public class MsgSetBasalProfile extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSetBasalProfile.class);
public MsgSetBasalProfile() {
SetCommand(0x3306);
}
// index 0-3
public MsgSetBasalProfile(byte index, double[] values) {
this();
AddParamByte(index);
for (Integer i = 0; i < 24; i++) {
AddParamInt((int) (values[i] * 100));
}
if (Config.logDanaMessageDetail)
log.debug("Set basal profile: " + index);
}
@Override
public void handleMessage(byte[] bytes) {
int result = intFromBuff(bytes, 0, 1);
if (result != 1) {
failed = true;
log.debug("Set basal profile result: " + result + " FAILED!!!");
} else {
if (Config.logDanaMessageDetail)
log.debug("Set basal profile result: " + result);
}
}
}

View file

@ -0,0 +1,44 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import info.nightscout.androidaps.Config;
public class MsgSetCarbsEntry extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSetCarbsEntry.class);
public MsgSetCarbsEntry() {
SetCommand(0x0402);
}
public MsgSetCarbsEntry(Calendar time, int amount) {
this();
AddParamByte((byte) RecordTypes.RECORD_TYPE_CARBO);
AddParamByte((byte) (time.get(Calendar.YEAR) % 100));
AddParamByte((byte) (time.get(Calendar.MONTH) + 1));
AddParamByte((byte) (time.get(Calendar.DAY_OF_MONTH)));
AddParamByte((byte) (time.get(Calendar.HOUR_OF_DAY)));
AddParamByte((byte) (time.get(Calendar.MINUTE)));
AddParamByte((byte) (time.get(Calendar.SECOND)));
AddParamByte((byte) 0x43); //??
AddParamInt(amount);
if (Config.logDanaMessageDetail)
log.debug("Set carb entry: " + amount + " date " + time.toString());
}
@Override
public void handleMessage(byte[] bytes) {
int result = intFromBuff(bytes, 0, 1);
if (result != 1) {
failed = true;
log.debug("Set carb entry result: " + result + " FAILED!!!");
} else {
if (Config.logDanaMessageDetail)
log.debug("Set carb entry result: " + result);
}
}
}

View file

@ -0,0 +1,43 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
public class MsgSetExtendedBolusStart extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSetExtendedBolusStart.class);
public MsgSetExtendedBolusStart() {
SetCommand(0x0407);
}
public MsgSetExtendedBolusStart(double amount, byte halfhours) {
this();
// HARDCODED LIMITS
if (halfhours < 1) halfhours = 1;
if (halfhours > 16) halfhours = 16;
amount = MainApp.getConfigBuilder().applyBolusConstraints(amount);
if (amount < 0d) amount = 0d;
if (amount > 10d) amount = 10d;
AddParamInt((int) (amount * 100));
AddParamByte(halfhours);
if (Config.logDanaMessageDetail)
log.debug("Set extended bolus start: " + (((int) (amount * 100)) / 100d) + "U halfhours: " + (int) halfhours);
}
@Override
public void handleMessage(byte[] bytes) {
int result = intFromBuff(bytes, 0, 1);
if (result != 1) {
failed = true;
log.debug("Set extended bolus start result: " + result + " FAILED!!!");
} else {
if (Config.logDanaMessageDetail)
log.debug("Set extended bolus start result: " + result);
}
}
}

View file

@ -0,0 +1,30 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
public class MsgSetExtendedBolusStop extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSetExtendedBolusStop.class);
public MsgSetExtendedBolusStop() {
SetCommand(0x0406);
if (Config.logDanaMessageDetail)
log.debug("Set extended bolus stop");
}
@Override
public void handleMessage(byte[] bytes) {
int result = intFromBuff(bytes, 0, 1);
if (result != 1) {
failed = true;
log.debug("Set extended bolus stop result: " + result + " FAILED!!!");
} else {
if (Config.logDanaMessageDetail)
log.debug("Set extended bolus stop result: " + result);
}
}
}

View file

@ -0,0 +1,43 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
public class MsgSetTempBasalStart extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSetTempBasalStart.class);
public MsgSetTempBasalStart() {
SetCommand(0x0401);
}
public MsgSetTempBasalStart(int percent, int durationInHours) {
this();
//HARDCODED LIMITS
if (percent < 0) percent = 0;
if (percent > 200) percent = 200;
if (durationInHours < 1) durationInHours = 1;
if (durationInHours > 24) durationInHours = 24;
AddParamByte((byte) (percent & 255));
AddParamByte((byte) (durationInHours & 255));
if (Config.logDanaMessageDetail)
log.debug("Temp basal start percent: " + percent + " duration hours: " + durationInHours);
}
public void handleMessage(byte[] bytes) {
int result = intFromBuff(bytes, 0, 1);
if (result != 1) {
failed = true;
log.debug("Set temp basal start result: " + result + " FAILED!!!");
} else {
if (Config.logDanaMessageDetail)
log.debug("Set temp basal start result: " + result);
}
}
}

View file

@ -0,0 +1,29 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
public class MsgSetTempBasalStop extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSetTempBasalStop.class);
public MsgSetTempBasalStop() {
SetCommand(0x0403);
if (Config.logDanaMessageDetail)
log.debug("Temp basal stop");
}
public void handleMessage(byte[] bytes) {
int result = intFromBuff(bytes, 0, 1);
if (result != 1) {
failed = true;
log.debug("Set temp basal stop result: " + result + " FAILED!!!");
} else {
if (Config.logDanaMessageDetail)
log.debug("Set temp basal stop result: " + result);
}
}
}

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
/**
* Created by mike on 05.07.2016.
*/
public class MsgSettingActiveProfile extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingBasal.class);
public MsgSettingActiveProfile() {
SetCommand(0x320C);
}
public void handleMessage(byte[] bytes) {
DanaRPlugin.getDanaRPump().activeProfile = intFromBuff(bytes, 0, 1);
if (Config.logDanaMessageDetail)
log.debug("Active profile number: " + DanaRPlugin.getDanaRPump().activeProfile);
}
}

View file

@ -0,0 +1,35 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
/**
* Created by mike on 05.07.2016.
*/
public class MsgSettingBasal extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingBasal.class);
public MsgSettingBasal() {
SetCommand(0x3202);
}
public void handleMessage(byte[] bytes) {
DanaRPump pump = DanaRPlugin.getDanaRPump();
if (pump.pumpProfiles == null) pump.pumpProfiles = new double[4][];
pump.pumpProfiles[pump.activeProfile] = new double[24];
for (int index = 0; index < 24; index++) {
int basal = intFromBuff(bytes, 2 * index, 2);
if (basal < 10) basal = 0;
pump.pumpProfiles[pump.activeProfile][index] = basal / 100d;
}
if (Config.logDanaMessageDetail)
for (int index = 0; index < 24; index++) {
log.debug("Basal " + String.format("%02d", index) + "h: " + DanaRPlugin.getDanaRPump().pumpProfiles[DanaRPlugin.getDanaRPump().activeProfile][index]);
}
}
}

View file

@ -0,0 +1,72 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
/**
* Created by mike on 05.07.2016.
* <p/>
* <p/>
* THIS IS BROKEN IN PUMP... SENDING ONLY 1 PROFILE
*/
public class MsgSettingBasalProfileAll extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingBasalProfileAll.class);
public MsgSettingBasalProfileAll() {
SetCommand(0x3206);
}
public void handleMessage(byte[] bytes) {
DanaRPump pump = DanaRPlugin.getDanaRPump();
if (DanaRPlugin.getDanaRPump().basal48Enable) {
pump.pumpProfiles = new double[4][];
for (int profile = 0; profile < 4; profile++) {
int position = intFromBuff(bytes, 107 * profile, 1);
pump.pumpProfiles[position] = new double[48];
for (int index = 0; index < 48; index++) {
int basal = intFromBuff(bytes, 107 * profile + 2 * index + 1, 2);
if (basal < 10) basal = 0;
pump.pumpProfiles[position][index] = basal / 100d;
}
}
} else {
pump.pumpProfiles = new double[4][];
for (int profile = 0; profile < 4; profile++) {
int position = intFromBuff(bytes, 49 * profile, 1);
log.debug("position " + position);
pump.pumpProfiles[position] = new double[24];
for (int index = 0; index < 24; index++) {
int basal = intFromBuff(bytes, 59 * profile + 2 * index + 1, 2);
if (basal < 10) basal = 0;
log.debug("position " + position + " index " + index);
pump.pumpProfiles[position][index] = basal / 100d;
}
}
}
if (Config.logDanaMessageDetail) {
if (DanaRPlugin.getDanaRPump().basal48Enable) {
for (int profile = 0; profile < 4; profile++) {
for (int index = 0; index < 24; index++) {
log.debug("Basal profile " + profile + ": " + String.format("%02d", index) + "h: " + DanaRPlugin.getDanaRPump().pumpProfiles[profile][index]);
}
}
} else {
for (int profile = 0; profile < 4; profile++) {
for (int index = 0; index < 48; index++) {
log.debug("Basal profile " + profile + ": " +
String.format("%02d", (index / 2)) +
":" + String.format("%02d", (index % 2) * 30) + " : " +
DanaRPlugin.getDanaRPump().pumpProfiles[profile][index]);
}
}
}
}
}
}

View file

@ -0,0 +1,29 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
/**
* Created by mike on 05.07.2016.
*/
public class MsgSettingGlucose extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingGlucose.class);
public MsgSettingGlucose() {
SetCommand(0x3209);
}
public void handleMessage(byte[] bytes) {
DanaRPlugin.getDanaRPump().units = intFromBuff(bytes, 0, 1);
DanaRPlugin.getDanaRPump().easyBasalMode = intFromBuff(bytes, 1, 1);
if (Config.logDanaMessageDetail) {
log.debug("Pump units: " + (DanaRPlugin.getDanaRPump().units == DanaRPump.UNITS_MGDL ? "MGDL" : "MMOL"));
log.debug("Easy basal mode: " + DanaRPlugin.getDanaRPump().easyBasalMode);
}
}
}

View file

@ -0,0 +1,32 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
/**
* Created by mike on 05.07.2016.
*/
public class MsgSettingMaxValues extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingMaxValues.class);
public MsgSettingMaxValues() {
SetCommand(0x3205);
}
public void handleMessage(byte[] bytes) {
DanaRPlugin.getDanaRPump().maxBolus = intFromBuff(bytes, 0, 2) / 100d;
DanaRPlugin.getDanaRPump().maxBasal = intFromBuff(bytes, 2, 2) / 100d;
DanaRPlugin.getDanaRPump().maxDailyTotalUnits = intFromBuff(bytes, 4, 2) / 100;
if (Config.logDanaMessageDetail) {
log.debug("Max bolus: " + DanaRPlugin.getDanaRPump().maxBolus);
log.debug("Max basal: " + DanaRPlugin.getDanaRPump().maxBasal);
log.debug("Total daily max units: " + DanaRPlugin.getDanaRPump().maxDailyTotalUnits);
}
}
}

View file

@ -0,0 +1,44 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
/**
* Created by mike on 05.07.2016.
*/
public class MsgSettingProfileRatios extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingProfileRatios.class);
public MsgSettingProfileRatios() {
SetCommand(0x3204);
}
public void handleMessage(byte[] bytes) {
if (DanaRPlugin.getDanaRPump().units == DanaRPump.UNITS_MGDL) {
DanaRPlugin.getDanaRPump().currentCIR = intFromBuff(bytes, 0, 2);
DanaRPlugin.getDanaRPump().currentCF = intFromBuff(bytes, 2, 2);
DanaRPlugin.getDanaRPump().currentAI = intFromBuff(bytes, 4, 2) / 100d;
DanaRPlugin.getDanaRPump().currentTarget = intFromBuff(bytes, 6, 2);
DanaRPlugin.getDanaRPump().currentAIDR = intFromBuff(bytes, 8, 1);
} else {
DanaRPlugin.getDanaRPump().currentCIR = intFromBuff(bytes, 0, 2);
DanaRPlugin.getDanaRPump().currentCF = intFromBuff(bytes, 2, 2) / 100d;
DanaRPlugin.getDanaRPump().currentAI = intFromBuff(bytes, 4, 2) / 100d;
DanaRPlugin.getDanaRPump().currentTarget = intFromBuff(bytes, 6, 2) / 100d;
DanaRPlugin.getDanaRPump().currentAIDR = intFromBuff(bytes, 8, 1);
}
if (Config.logDanaMessageDetail) {
log.debug("Pump units (saved): " + (DanaRPlugin.getDanaRPump().units == DanaRPump.UNITS_MGDL ? "MGDL" : "MMOL"));
log.debug("Current pump CIR: " + DanaRPlugin.getDanaRPump().currentCIR);
log.debug("Current pump CF: " + DanaRPlugin.getDanaRPump().currentCF);
log.debug("Current pump AI: " + DanaRPlugin.getDanaRPump().currentAI);
log.debug("Current pump target: " + DanaRPlugin.getDanaRPump().currentTarget);
log.debug("Current pump AIDR: " + DanaRPlugin.getDanaRPump().currentAIDR);
}
}
}

View file

@ -0,0 +1,55 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
/**
* Created by mike on 05.07.2016.
*/
public class MsgSettingProfileRatiosAll extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingProfileRatiosAll.class);
public MsgSettingProfileRatiosAll() {
SetCommand(0x320D);
}
public void handleMessage(byte[] bytes) {
if (DanaRPlugin.getDanaRPump().units == DanaRPump.UNITS_MGDL) {
DanaRPlugin.getDanaRPump().morningCIR = intFromBuff(bytes, 0, 2);
DanaRPlugin.getDanaRPump().morningCF = intFromBuff(bytes, 2, 2);
DanaRPlugin.getDanaRPump().afternoonCIR = intFromBuff(bytes, 4, 2);
DanaRPlugin.getDanaRPump().afternoonCF = intFromBuff(bytes, 6, 2);
DanaRPlugin.getDanaRPump().eveningCIR = intFromBuff(bytes, 8, 2);
DanaRPlugin.getDanaRPump().eveningCF = intFromBuff(bytes, 10, 2);
DanaRPlugin.getDanaRPump().nightCIR = intFromBuff(bytes, 12, 2);
DanaRPlugin.getDanaRPump().nightCF = intFromBuff(bytes, 14, 2);
} else {
DanaRPlugin.getDanaRPump().morningCIR = intFromBuff(bytes, 0, 2);
DanaRPlugin.getDanaRPump().morningCF = intFromBuff(bytes, 2, 2) / 100d;
DanaRPlugin.getDanaRPump().afternoonCIR = intFromBuff(bytes, 4, 2);
DanaRPlugin.getDanaRPump().afternoonCF = intFromBuff(bytes, 6, 2) / 100d;
DanaRPlugin.getDanaRPump().eveningCIR = intFromBuff(bytes, 8, 2);
DanaRPlugin.getDanaRPump().eveningCF = intFromBuff(bytes, 10, 2) / 100d;
DanaRPlugin.getDanaRPump().nightCIR = intFromBuff(bytes, 12, 2);
DanaRPlugin.getDanaRPump().nightCF = intFromBuff(bytes, 14, 2) / 100d;
}
if (Config.logDanaMessageDetail) {
log.debug("Pump units: " + (DanaRPlugin.getDanaRPump().units == DanaRPump.UNITS_MGDL ? "MGDL" : "MMOL"));
log.debug("Current pump morning CIR: " + DanaRPlugin.getDanaRPump().morningCIR);
log.debug("Current pump morning CF: " + DanaRPlugin.getDanaRPump().morningCF);
log.debug("Current pump afternoon CIR: " + DanaRPlugin.getDanaRPump().afternoonCIR);
log.debug("Current pump afternoon CF: " + DanaRPlugin.getDanaRPump().afternoonCF);
log.debug("Current pump evening CIR: " + DanaRPlugin.getDanaRPump().eveningCIR);
log.debug("Current pump evening CF: " + DanaRPlugin.getDanaRPump().eveningCF);
log.debug("Current pump night CIR: " + DanaRPlugin.getDanaRPump().nightCIR);
log.debug("Current pump night CF: " + DanaRPlugin.getDanaRPump().nightCF);
}
DanaRPlugin.getDanaRPump().createConvertedProfile();
}
}

View file

@ -0,0 +1,34 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
public class MsgSettingPumpTime extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingPumpTime.class);
public MsgSettingPumpTime() {
SetCommand(0x320A);
}
public void handleMessage(byte[] bytes) {
Date time =
new Date(
100 + intFromBuff(bytes, 5, 1),
intFromBuff(bytes, 4, 1) - 1,
intFromBuff(bytes, 3, 1),
intFromBuff(bytes, 2, 1),
intFromBuff(bytes, 1, 1),
intFromBuff(bytes, 0, 1)
);
if (Config.logDanaMessageDetail)
log.debug("Pump time: " + time);
DanaRPlugin.getDanaRPump().pumpTime = time;
}
}

View file

@ -0,0 +1,36 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
/**
* Created by mike on 05.07.2016.
*/
public class MsgSettingShippingInfo extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingShippingInfo.class);
public MsgSettingShippingInfo() {
SetCommand(0x3207);
}
public void handleMessage(byte[] bytes) {
DanaRPlugin.getDanaRPump().serialNumber = stringFromBuff(bytes, 0, 10);
DanaRPlugin.getDanaRPump().shippingDate = dateFromBuff(bytes, 10);
DanaRPlugin.getDanaRPump().shippingCountry = asciiStringFromBuff(bytes, 13, 3);
if (DanaRPlugin.getDanaRPump().shippingDate.getTime() > new Date(116, 4, 1).getTime()) {
DanaRPlugin.getDanaRPump().isNewPump = true;
} else
DanaRPlugin.getDanaRPump().isNewPump = false;
if (Config.logDanaMessageDetail) {
log.debug("Serial number: " + DanaRPlugin.getDanaRPump().serialNumber);
log.debug("Shipping date: " + DanaRPlugin.getDanaRPump().shippingDate);
log.debug("Shipping country: " + DanaRPlugin.getDanaRPump().shippingCountry);
}
}
}

View file

@ -0,0 +1,20 @@
package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by mike on 05.07.2016.
*/
public class MsgSettingUserOptions extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSettingShippingInfo.class);
public MsgSettingUserOptions() {
SetCommand(0x320B);
}
public void handleMessage(byte[] bytes) {
}
}

Some files were not shown because too many files have changed in this diff Show more