bolus.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. function reduce (treatments) {
  2. var results = [ ];
  3. var state = { };
  4. var previous = [ ];
  5. function in_previous (ev) {
  6. var found = false;
  7. previous.forEach(function (elem) {
  8. if (elem.timestamp === ev.timestamp && ev._type === elem._type) {
  9. found = true;
  10. }
  11. });
  12. return found;
  13. }
  14. function within_minutes_from (origin, tail, minutes) {
  15. var ms = minutes * 1000 * 60;
  16. var ts = Date.parse(origin.timestamp);
  17. return /* candidates */ tail.slice( ).filter(function (elem) {
  18. var dt = Date.parse(elem.timestamp);
  19. return ts - dt <= ms;
  20. });
  21. }
  22. function bolus (ev, remaining) {
  23. if (!ev) { console.error('XXX', ev, remaining); return; }
  24. if (ev._type === 'BolusWizard') {
  25. state.carbs = ev.carb_input.toString( );
  26. state.ratio = ev.carb_ratio.toString( );
  27. if (ev.bg) {
  28. state.bg = ev.bg.toString( );
  29. state.glucose = ev.bg.toString( );
  30. state.glucoseType = ev._type;
  31. }
  32. state.wizard = ev;
  33. state.created_at = state.timestamp = ev.timestamp;
  34. previous.push(ev);
  35. }
  36. if (ev._type === 'Bolus') {
  37. state.duration = ev.duration.toString( );
  38. // if (state.square || state.bolus) { }
  39. // state.insulin = (state.insulin ? state.insulin : 0) + ev.amount;
  40. if (ev.duration && ev.duration > 0) {
  41. state.square = ev;
  42. } else {
  43. if (state.bolus) {
  44. state.bolus.amount = state.bolus.amount + ev.amount;
  45. } else
  46. state.bolus = ev;
  47. }
  48. state.created_at = state.timestamp = ev.timestamp;
  49. previous.push(ev);
  50. }
  51. if (remaining && remaining.length > 0) {
  52. if (state.bolus && state.wizard) {
  53. // skip to end
  54. return bolus({}, []);
  55. }
  56. // keep recursing
  57. return bolus(remaining[0], remaining.slice(1));
  58. } else {
  59. // console.error("state", state);
  60. // console.error("remaining", remaining);
  61. state.eventType = '<none>';
  62. state.insulin = (state.insulin ? state.insulin : 0) + (state.square ? state.square.amount : 0) +
  63. (state.bolus ? state.bolus.amount : 0);
  64. var has_insulin = state.insulin && state.insulin > 0;
  65. var has_carbs = state.carbs && state.carbs > 0;
  66. if (state.square && state.bolus) {
  67. annotate("DualWave bolus for", state.square.duration, "minutes");
  68. } else if (state.square && state.wizard) {
  69. annotate("Square wave bolus for", state.square.duration, "minutes");
  70. } else if (state.square) {
  71. annotate("Solo Square wave bolus for", state.square.duration, "minutes");
  72. annotate("No bolus wizard used.");
  73. } else if (state.bolus && state.wizard) {
  74. annotate("Normal bolus with wizard.");
  75. } else if (state.bolus) {
  76. annotate("Normal bolus (solo, no bolus wizard).");
  77. }
  78. if (has_insulin) {
  79. var iobFile = "./monitor/iob.json";
  80. var fs = require('fs');
  81. if (fs.existsSync(iobFile)) {
  82. var iob = JSON.parse(fs.readFileSync(iobFile));
  83. if (iob && Array.isArray(iob) && iob.length) {
  84. annotate("Calculated IOB:", iob[0].iob);
  85. }
  86. }
  87. }
  88. if (state.bolus) {
  89. annotate("Programmed bolus", state.bolus.programmed);
  90. annotate("Delivered bolus", state.bolus.amount);
  91. annotate("Percent delivered: ", (state.bolus.amount/state.bolus.programmed * 100).toString( ) + '%');
  92. }
  93. if (state.square) {
  94. annotate("Programmed square", state.square.programmed);
  95. annotate("Delivered square", state.square.amount);
  96. annotate("Success: ", (state.square.amount/state.square.programmed * 100).toString( ) + '%');
  97. }
  98. if (state.wizard) {
  99. state.created_at = state.wizard.timestamp;
  100. annotate("Food estimate", state.wizard.food_estimate);
  101. annotate("Correction estimate", state.wizard.correction_estimate);
  102. annotate("Bolus estimate", state.wizard.bolus_estimate);
  103. annotate("Target low", state.wizard.bg_target_low);
  104. annotate("Target high", state.wizard.bg_target_high);
  105. var delta = state.wizard.sensitivity * state.insulin * -1;
  106. annotate("Hypothetical glucose delta", delta);
  107. if (state.bg && state.bg > 0) {
  108. annotate('Glucose was:', state.bg);
  109. // state.glucose = state.bg;
  110. // TODO: annotate prediction
  111. }
  112. }
  113. if (has_carbs && has_insulin) {
  114. state.eventType = 'Meal Bolus';
  115. } else {
  116. if (has_carbs && !has_insulin) {
  117. state.eventType = 'Carb Correction';
  118. }
  119. if (!has_carbs && has_insulin) {
  120. state.eventType = 'Correction Bolus';
  121. }
  122. }
  123. if (state.notes && state.notes.length > 0) {
  124. state.notes = state.notes.join("\n");
  125. }
  126. if (state.insulin) {
  127. state.insulin = state.insulin.toString( );
  128. }
  129. results.push(state);
  130. state = { };
  131. }
  132. }
  133. function annotate (msg) {
  134. var args = [ ].slice.apply(arguments);
  135. msg = args.join(' ');
  136. if (!state.notes) {
  137. state.notes = [ ];
  138. }
  139. state.notes.push(msg);
  140. }
  141. function step (current, index) {
  142. if (in_previous(current)) {
  143. return;
  144. }
  145. switch (current._type) {
  146. case 'Bolus':
  147. case 'BolusWizard':
  148. var tail = within_minutes_from(current, treatments.slice(index+1), 2);
  149. bolus(current, tail);
  150. break;
  151. case 'JournalEntryMealMarker':
  152. current.carbs = current.carb_input;
  153. current.eventType = 'Carb Correction';
  154. results.push(current);
  155. break;
  156. default:
  157. results.push(current);
  158. break;
  159. }
  160. }
  161. treatments.forEach(step);
  162. return results;
  163. }
  164. exports = module.exports = reduce;