treatments synchronization improvement

This commit is contained in:
Milos Kozak 2017-06-07 00:11:33 +02:00
parent 5931abc860
commit 8fab76ee9b
15 changed files with 204 additions and 146 deletions

View file

@ -456,8 +456,6 @@ public class DataService extends IntentService {
public void handleAddChangeTreatmentRecord(JSONObject trJson) throws JSONException {
if (trJson.has("insulin") || trJson.has("carbs")) {
if (Config.logIncommingData)
log.debug("Processing Treatment record: " + trJson.toString());
MainApp.getDbHelper().createTreatmentFromJsonIfNotExists(trJson);
return;
}

View file

@ -28,4 +28,6 @@ public class DetailedBolusInfo {
public JSONObject boluscalc = null; // additional bolus wizard info
public Context context = null; // context for progress dialog
public boolean addToTreatments = true;
public boolean recordFromHistory = false; // true if record is comming from pump history (not a newly created treatment)
public long pumpId = 0; // id of record if comming from pump history (not a newly created treatment)
}

View file

@ -7,6 +7,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Objects;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
@ -133,13 +134,7 @@ public class BgReading implements DataPointWithLabelInterface {
return false;
if (!direction.equals(other.direction))
return false;
if (_id == null && other._id != null)
return false;
else if (_id != null && other._id == null)
return false;
else if (_id == null && other._id == null)
;
else if (!_id.equals(other._id))
if (!Objects.equals(_id, other._id))
return false;
return true;
}

View file

@ -492,28 +492,84 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// -------------------- TREATMENT HANDLING -------------------
private boolean changeAffectingIobCob(Treatment t) {
Treatment existing = findTreatmentByTime(t.date);
if (existing == null)
return true;
if (existing.insulin == t.insulin && existing.carbs == t.carbs)
return false;
return true;
}
public Dao.CreateOrUpdateStatus createOrUpdate(Treatment treatment) {
treatment.date = treatment.date - treatment.date % 1000;
Dao.CreateOrUpdateStatus status = null;
// return true if new record is created
public boolean createOrUpdate(Treatment treatment) {
try {
boolean historyChange = changeAffectingIobCob(treatment);
status = getDaoTreatments().createOrUpdate(treatment);
if (historyChange)
Treatment old;
treatment.date = roundDateToSec(treatment.date);
if (treatment.source == Source.PUMP) {
// check for changed from pump change in NS
QueryBuilder<Treatment, Long> queryBuilder = getDaoTreatments().queryBuilder();
Where where = queryBuilder.where();
where.eq("pumpId", treatment.pumpId);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = getDaoTreatments().query(preparedQuery);
if (trList.size() > 0) {
// do nothing, pump history record cannot be changed
return false;
}
getDaoTreatments().create(treatment);
log.debug("TREATMENT: New record from: " + Source.getString(treatment.source) + " " + treatment.toString());
updateEarliestDataChange(treatment.date);
scheduleTreatmentChange();
return true;
}
if (treatment.source == Source.NIGHTSCOUT) {
old = getDaoTreatments().queryForId(treatment.date);
if (old != null) {
if (!old.isEqual(treatment)) {
boolean historyChange = old.isDataChanging(treatment);
long oldDate = old.date;
getDaoTreatments().delete(old); // need to delete/create because date may change too
old.copyFrom(treatment);
getDaoTreatments().create(old);
log.debug("TREATMENT: Updating record by date from: " + Source.getString(treatment.source) + " " + old.toString());
if (historyChange) {
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
scheduleTreatmentChange();
}
return true;
}
return false;
}
// find by NS _id
if (treatment._id != null) {
QueryBuilder<Treatment, Long> queryBuilder = getDaoTreatments().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", treatment._id);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = getDaoTreatments().query(preparedQuery);
if (trList.size() > 0) {
old = trList.get(0);
if (!old.isEqual(treatment)) {
boolean historyChange = old.isDataChanging(treatment);
long oldDate = old.date;
getDaoTreatments().delete(old); // need to delete/create because date may change too
old.copyFrom(treatment);
getDaoTreatments().create(old);
log.debug("TREATMENT: Updating record by _id from: " + Source.getString(treatment.source) + " " + old.toString());
if (historyChange) {
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
scheduleTreatmentChange();
}
return true;
}
}
}
}
if (treatment.source == Source.USER) {
getDaoTreatments().create(treatment);
updateEarliestDataChange(treatment.date);
scheduleTreatmentChange();
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}
scheduleTreatmentChange();
return status;
return false;
}
public void delete(Treatment treatment) {
@ -529,10 +585,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void deleteTreatmentById(String _id) {
Treatment stored = findTreatmentById(_id);
if (stored != null) {
log.debug("Removing TempTarget record from database: " + stored.log());
log.debug("TREATMENT: Removing Treatment record from database: " + stored.toString());
delete(stored);
} else {
log.debug("Treatment not found database: " + _id);
updateEarliestDataChange(stored.date);
scheduleTreatmentChange();
}
}
@ -559,30 +615,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return null;
}
@Nullable
public Treatment findTreatmentByTime(Long timeIndex) {
try {
QueryBuilder<Treatment, String> qb = null;
Dao<Treatment, Long> daoTreatments = getDaoTreatments();
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
Where where = queryBuilder.where();
where.eq("date", timeIndex);
queryBuilder.limit(10L);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = daoTreatments.query(preparedQuery);
if (trList.size() != 1) {
//log.debug("Treatment findTreatmentByTime query size: " + trList.size());
return null;
} else {
//log.debug("Treatment findTreatmentByTime found: " + trList.get(0).log());
return trList.get(0);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
private void updateEarliestDataChange(long newDate) {
if (earliestDataChange == null) {
earliestDataChange = newDate;
@ -634,30 +666,13 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createTreatmentFromJsonIfNotExists(JSONObject trJson) {
try {
QueryBuilder<Treatment, Long> queryBuilder = null;
queryBuilder = getDaoTreatments().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", trJson.getString("_id")).or().eq("date", trJson.getLong("mills"));
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> list = getDaoTreatments().query(preparedQuery);
Treatment treatment;
if (list.size() == 0) {
treatment = new Treatment();
treatment.source = Source.NIGHTSCOUT;
if (Config.logIncommingData)
log.debug("Adding Treatment record to database: " + trJson.toString());
// Record does not exists. add
} else if (list.size() == 1) {
treatment = list.get(0);
if (Config.logIncommingData)
log.debug("Updating Treatment record in database: " + trJson.toString());
} else {
log.error("Something went wrong");
return;
}
treatment.date = trJson.getLong("mills");
Treatment treatment = new Treatment();
;
treatment.source = Source.NIGHTSCOUT;
treatment.date = roundDateToSec(trJson.getLong("mills"));
treatment.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
treatment.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
treatment.pumpId = trJson.has("pumpId") ? trJson.getLong("pumpId") : 0;
treatment._id = trJson.getString("_id");
if (trJson.has("eventType")) {
treatment.mealBolus = !trJson.get("eventType").equals("Correction Bolus");
@ -672,7 +687,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
treatment.mealBolus = false;
}
createOrUpdate(treatment);
} catch (SQLException | JSONException e) {
} catch (JSONException e) {
e.printStackTrace();
}
}

View file

@ -6,6 +6,19 @@ package info.nightscout.androidaps.db;
public class Source {
public final static int NONE = 0;
public final static int PUMP = 1;
public final static int NIGHTSCOUT = 2;
public final static int PUMP = 1; // Pump history
public final static int NIGHTSCOUT = 2; // created in NS
public final static int USER = 3; // created by user or driver not using history
public static String getString(int source) {
switch (source) {
case PUMP:
return "PUMP";
case NIGHTSCOUT:
return "NIGHTSCOUT";
case USER:
return "USER";
}
return "NONE";
}
}

View file

@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
@ -32,15 +33,18 @@ public class Treatment implements DataPointWithLabelInterface {
@DatabaseField
public boolean isValid = true;
@DatabaseField(index = true)
public long pumpId = 0;
@DatabaseField
public int source = Source.NONE;
@DatabaseField
public String _id;
@DatabaseField
public Double insulin = 0d;
public double insulin = 0d;
@DatabaseField
public Double carbs = 0d;
public double carbs = 0d;
@DatabaseField
public boolean mealBolus = true; // true for meal bolus , false for correction bolus
@ -57,32 +61,60 @@ public class Treatment implements DataPointWithLabelInterface {
dia = insulin.getDia();
}
public void copyFrom(Treatment t) {
this.date = t.date;
this.isValid = t.isValid;
this.source = t.source;
this._id = t._id;
this.insulin = t.insulin;
this.carbs = t.carbs;
this.mealBolus = t.mealBolus;
}
public long getMillisecondsFromStart() {
return new Date().getTime() - date;
}
public String log() {
public String toString() {
return "Treatment{" +
"date= " + date +
", date= " + DateUtil.dateAndTimeString(date) +
", isValid= " + isValid +
", _id= " + _id +
", pumpId= " + pumpId +
", insulin= " + insulin +
", carbs= " + carbs +
", mealBolus= " + mealBolus +
"}";
}
public boolean isDataChanging(Treatment other) {
if (date != other.date) {
return true;
}
if (insulin != other.insulin)
return true;
if (carbs != other.carbs)
return true;
return false;
}
public boolean isEqual(Treatment other) {
if (date != other.date) {
return false;
}
if (insulin != other.insulin)
return false;
if (carbs != other.carbs)
return false;
if (mealBolus != other.mealBolus)
return false;
if (pumpId != other.pumpId)
return false;
if (!Objects.equals(_id, other._id))
return false;
return true;
}
public void copyFrom(Treatment t) {
date = t.date;
_id = t._id;
insulin = t.insulin;
carbs = t.carbs;
mealBolus = t.mealBolus;
pumpId = t.pumpId;
}
// ----------------- DataPointInterface --------------------
@Override
public double getX() {
@ -102,7 +134,7 @@ public class Treatment implements DataPointWithLabelInterface {
String label = "";
if (insulin > 0) label += DecimalFormatter.to2Decimal(insulin) + "U";
if (carbs > 0)
label += (label.equals("") ? "" : " ") + DecimalFormatter.to0Decimal(carbs) + "g";
label += "~" + DecimalFormatter.to0Decimal(carbs) + "g";
return label;
}

View file

@ -51,7 +51,7 @@ public interface TreatmentsInterface {
void addToHistoryExtendedBolusStop(long time);
OverlappingIntervals<ExtendedBolus> getExtendedBolusesFromHistory();
void addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo);
boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo);
TempTarget getTempTargetFromHistory(long time);
OverlappingIntervals<TempTarget> getTempTargetsFromHistory();

View file

@ -934,11 +934,14 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain
}
@Override
public void addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo) {
// return true if new record is created
public boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo) {
if (!detailedBolusInfo.addToTreatments)
return;
activeTreatments.addToHistoryTreatment(detailedBolusInfo);
NSUpload.uploadBolusWizardRecord(detailedBolusInfo);
return false;
boolean newRecordCreated = activeTreatments.addToHistoryTreatment(detailedBolusInfo);
if (newRecordCreated)
NSUpload.uploadBolusWizardRecord(detailedBolusInfo);
return newRecordCreated;
}
@Override

View file

@ -394,6 +394,7 @@ public class NSClientService extends Service {
} else if (treatment.getAction().equals("update")) {
updatedTreatments.put(jsonTreatment);
} else if (treatment.getAction().equals("remove")) {
if (treatment.getMills() != null && treatment.getMills() > new Date().getTime() - 24 * 60 * 60 * 1000L) // handle 1 day old deletions only
removedTreatments.put(jsonTreatment);
}
}

View file

@ -350,14 +350,28 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
}
void drawLabel45(float endX, float endY, E value, Canvas canvas) {
float px = endX;
float py = endY - value.getSize();
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((int) (value.getSize() * 2.5));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
mPaint.setFakeBoldText(true);
canvas.drawText(value.getLabel(), px + value.getSize(), py, mPaint);
canvas.restore();
if (value.getLabel().startsWith("~")) {
float px = endX;
float py = endY + value.getSize();
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((int) (value.getSize() * 2.5));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
mPaint.setFakeBoldText(true);
mPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText(value.getLabel().substring(1), px - value.getSize(), py, mPaint);
mPaint.setTextAlign(Paint.Align.LEFT);
canvas.restore();
} else {
float px = endX;
float py = endY - value.getSize();
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((int) (value.getSize() * 2.5));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
mPaint.setFakeBoldText(true);
canvas.drawText(value.getLabel(), px + value.getSize(), py, mPaint);
canvas.restore();
}
}
}

View file

@ -288,7 +288,7 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, ConstraintsInte
Treatment t = new Treatment(detailedBolusInfo.insulinInterface);
boolean connectionOK = false;
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0)
connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, new Date().getTime() + detailedBolusInfo.carbTime * 60 * 1000, t);
connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, new Date().getTime() + detailedBolusInfo.carbTime * 60 * 1000 + 1000, t); // +1000 to make the record different
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;

View file

@ -9,6 +9,7 @@ import java.util.GregorianCalendar;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
@ -72,15 +73,9 @@ public class MsgHistoryEvents_v2 extends MessageBase {
}
extendedBolus = new ExtendedBolus();
Treatment treatment = MainApp.getDbHelper().findTreatmentByTime(datetime.getTime());
if (treatment != null) {
log.debug("EVENT (" + recordCode + ") " + datetime.toLocaleString() + " Param1: " + param1 + " Param2: " + param2);
log.debug("Existing treatment found. Skipping ...");
if (datetime.getTime() > lastEventTimeLoaded)
lastEventTimeLoaded = datetime.getTime();
return;
}
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.recordFromHistory = true;
detailedBolusInfo.pumpId = datetime.getTime();
switch (recordCode) {
case DanaRPump.TEMPSTART:
@ -92,9 +87,7 @@ public class MsgHistoryEvents_v2 extends MessageBase {
break;
case DanaRPump.TEMPSTOP:
log.debug("EVENT TEMPSTOP (" + recordCode + ") " + datetime.toLocaleString());
temporaryBasal.date = datetime.getTime();
temporaryBasal.durationInMinutes = 0;
MainApp.getConfigBuilder().addToHistoryTempBasalStart(temporaryBasal);
MainApp.getConfigBuilder().addToHistoryTempBasalStop(datetime.getTime());
break;
case DanaRPump.EXTENDEDSTART:
log.debug("EVENT EXTENDEDSTART (" + recordCode + ") " + datetime.toLocaleString() + " Amount: " + (param1 / 100d) + "U Duration: " + param2 + "min");
@ -105,20 +98,20 @@ public class MsgHistoryEvents_v2 extends MessageBase {
break;
case DanaRPump.EXTENDEDSTOP:
log.debug("EVENT EXTENDEDSTOP (" + recordCode + ") " + datetime.toLocaleString() + " Delivered: " + (param1 / 100d) + "U RealDuration: " + param2 + "min");
extendedBolus.date = datetime.getTime();
extendedBolus.durationInMinutes = 0;
MainApp.getConfigBuilder().addToHistoryExtendedBolusStart(extendedBolus);
MainApp.getConfigBuilder().addToHistoryExtendedBolusStop(datetime.getTime());
break;
case DanaRPump.BOLUS:
log.debug("EVENT BOLUS (" + recordCode + ") " + datetime.toLocaleString() + " Bolus: " + (param1 / 100d) + "U Duration: " + param2 + "min");
detailedBolusInfo.date = datetime.getTime();
detailedBolusInfo.insulin = param1 / 100d;
detailedBolusInfo.source = Source.PUMP;
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
break;
case DanaRPump.DUALBOLUS:
log.debug("EVENT DUALBOLUS (" + recordCode + ") " + datetime.toLocaleString() + " Bolus: " + (param1 / 100d) + "U Duration: " + param2 + "min");
detailedBolusInfo.date = datetime.getTime();
detailedBolusInfo.insulin = param1 / 100d;
detailedBolusInfo.source = Source.PUMP;
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
break;
case DanaRPump.DUALEXTENDEDSTART:
@ -130,9 +123,7 @@ public class MsgHistoryEvents_v2 extends MessageBase {
break;
case DanaRPump.DUALEXTENDEDSTOP:
log.debug("EVENT DUALEXTENDEDSTOP (" + recordCode + ") " + datetime.toLocaleString() + " Delivered: " + (param1 / 100d) + "U RealDuration: " + param2 + "min");
extendedBolus.date = datetime.getTime();
extendedBolus.durationInMinutes = 0;
MainApp.getConfigBuilder().addToHistoryExtendedBolusStart(extendedBolus);
MainApp.getConfigBuilder().addToHistoryExtendedBolusStop(datetime.getTime());
break;
case DanaRPump.SUSPENDON:
log.debug("EVENT SUSPENDON (" + recordCode + ") " + datetime.toLocaleString());
@ -153,6 +144,7 @@ public class MsgHistoryEvents_v2 extends MessageBase {
log.debug("EVENT CARBS (" + recordCode + ") " + datetime.toLocaleString() + " Carbs: " + param1 + "g");
detailedBolusInfo.date = datetime.getTime();
detailedBolusInfo.carbs = param1;
detailedBolusInfo.source = Source.PUMP;
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
break;
default:

View file

@ -420,7 +420,7 @@ public class DanaRv2ExecutionService extends Service {
log.debug("Communication stopped");
}
}
waitMsec(300);
waitMsec(1000);
bolusingTreatment = null;
loadEvents();
return true;

View file

@ -24,6 +24,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileIntervals;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
@ -405,24 +406,31 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
}
@Override
public void addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo) {
public boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo) {
Treatment treatment = new Treatment(detailedBolusInfo.insulinInterface);
treatment.date = detailedBolusInfo.date;
treatment.source = detailedBolusInfo.recordFromHistory ? Source.PUMP : Source.USER;
if (detailedBolusInfo.recordFromHistory)
treatment.pumpId = treatment.date;
treatment.insulin = detailedBolusInfo.insulin;
if (detailedBolusInfo.carbTime == 0)
treatment.carbs = detailedBolusInfo.carbs;
treatment.source = detailedBolusInfo.source;
treatment.mealBolus = treatment.carbs > 0;
MainApp.getDbHelper().createOrUpdate(treatment);
log.debug("Adding new Treatment record" + treatment.log());
boolean newRecordCreated = MainApp.getDbHelper().createOrUpdate(treatment);
log.debug("Adding new Treatment record" + treatment.toString());
if (detailedBolusInfo.carbTime != 0) {
Treatment carbsTreatment = new Treatment(detailedBolusInfo.insulinInterface);
carbsTreatment.date = detailedBolusInfo.date + detailedBolusInfo.carbTime * 60 * 1000L;
carbsTreatment.source = detailedBolusInfo.recordFromHistory ? Source.PUMP : Source.USER;
if (detailedBolusInfo.recordFromHistory)
carbsTreatment.pumpId = treatment.date;
carbsTreatment.date = detailedBolusInfo.date + detailedBolusInfo.carbTime * 60 * 1000L + 1000L; // add 1 sec to make them different records
carbsTreatment.carbs = detailedBolusInfo.carbs;
carbsTreatment.source = detailedBolusInfo.source;
MainApp.getDbHelper().createOrUpdate(carbsTreatment);
log.debug("Adding new Treatment record" + carbsTreatment);
}
return newRecordCreated;
}
@Override

View file

@ -175,23 +175,6 @@ public class NSUpload {
}
}
public static void uploadTreatment(Treatment treatment) {
JSONObject data = new JSONObject();
try {
if (treatment.mealBolus)
data.put("eventType", "Meal Bolus");
else
data.put("eventType", "Correction Bolus");
if (treatment.insulin != 0d) data.put("insulin", treatment.insulin);
if (treatment.carbs != 0d) data.put("carbs", treatment.carbs.intValue());
data.put("created_at", DateUtil.toISOString(treatment.date));
data.put("timeIndex", treatment.date);
} catch (JSONException e) {
e.printStackTrace();
}
NSUpload.uploadCareportalEntryToNS(data);
}
public static void uploadDeviceStatus() {
DeviceStatus deviceStatus = new DeviceStatus();
try {
@ -261,6 +244,8 @@ public class NSUpload {
if (detailedBolusInfo.carbs != 0d) data.put("carbs", (int) detailedBolusInfo.carbs);
data.put("created_at", DateUtil.toISOString(detailedBolusInfo.date));
data.put("date", detailedBolusInfo.date);
if (detailedBolusInfo.pumpId != 0)
data.put("pumpId", detailedBolusInfo.pumpId);
if (detailedBolusInfo.glucose != 0d)
data.put("glucose", detailedBolusInfo.glucose);
if (!detailedBolusInfo.glucoseType.equals(""))