|
| 1 | +var fs = require('fs'); |
| 2 | +var font = require('oled-font-5x7'); |
| 3 | + |
| 4 | +// Rounds value to 'digits' decimal places |
| 5 | +function round(value, digits) |
| 6 | +{ |
| 7 | + if (! digits) { digits = 0; } |
| 8 | + var scale = Math.pow(10, digits); |
| 9 | + return Math.round(value * scale) / scale; |
| 10 | +} |
| 11 | + |
| 12 | +function convert_bg(value, profile) |
| 13 | +{ |
| 14 | + if (profile != null && profile.out_units == "mmol/L") |
| 15 | + { |
| 16 | + return round(value / 18, 1).toFixed(1); |
| 17 | + } |
| 18 | + else |
| 19 | + { |
| 20 | + return Math.round(value); |
| 21 | + } |
| 22 | +} |
| 23 | + |
| 24 | +function stripLeadingZero(value) |
| 25 | +{ |
| 26 | + var re = /^(-)?0+(?=[\.\d])/; |
| 27 | + return value.toString().replace( re, '$1'); |
| 28 | +} |
| 29 | + |
| 30 | +module.exports = radiofruitStatus; |
| 31 | + |
| 32 | +// |
| 33 | +//Start of status display function |
| 34 | +// |
| 35 | + |
| 36 | +function radiofruitStatus(display, openapsDir) { |
| 37 | + |
| 38 | +display.oled.clearDisplay(true); //clear display buffer |
| 39 | + |
| 40 | +//Parse all the .json files we need |
| 41 | +try { |
| 42 | + var profile = JSON.parse(fs.readFileSync(openapsDir+"/settings/profile.json")); |
| 43 | +} catch (e) { |
| 44 | + console.error("Status screen display error: could not parse profile.json: ", e); |
| 45 | +} |
| 46 | +try { |
| 47 | + var status = JSON.parse(fs.readFileSync(openapsDir+"/monitor/status.json")); |
| 48 | +} catch (e) { |
| 49 | + console.error("Status screen display error: could not parse status.json: ", e); |
| 50 | +} |
| 51 | +try { |
| 52 | + var suggested = JSON.parse(fs.readFileSync(openapsDir+"/enact/suggested.json")); |
| 53 | +} catch (e) { |
| 54 | + console.error("Status screen display error: could not parse suggested.json: ", e); |
| 55 | +} |
| 56 | +try { |
| 57 | + var bg = JSON.parse(fs.readFileSync(openapsDir+"/monitor/glucose.json")); |
| 58 | +} catch (e) { |
| 59 | + console.error("Status screen display error: could not parse glucose.json: ", e); |
| 60 | +} |
| 61 | +try { |
| 62 | + var temp = JSON.parse(fs.readFileSync(openapsDir+"/monitor/last_temp_basal.json")); |
| 63 | + var statusStats = fs.statSync(openapsDir+"/monitor/last_temp_basal.json"); |
| 64 | +} catch (e) { |
| 65 | + console.error("Status screen display error: could not parse last_temp_basal.json: ", e); |
| 66 | +} |
| 67 | +try { |
| 68 | + var iob = JSON.parse(fs.readFileSync(openapsDir+"/monitor/iob.json")); |
| 69 | +} catch (e) { |
| 70 | + console.error("Status screen display error: could not parse iob.json: ", e); |
| 71 | +} |
| 72 | +try { |
| 73 | + var cob = JSON.parse(fs.readFileSync(openapsDir+"/monitor/meal.json")); |
| 74 | +} catch (e) { |
| 75 | + console.error("Status screen display error: could not parse meal.json: ", e); |
| 76 | +} |
| 77 | +try { |
| 78 | + var pumpbattery = JSON.parse(fs.readFileSync(openapsDir+"/monitor/battery.json")); |
| 79 | +} catch (e) { |
| 80 | + console.error("Status screen display error: could not parse battery.json: ", e); |
| 81 | +} |
| 82 | + |
| 83 | +//display warning messages |
| 84 | +if (status && suggested && pumpbattery) { |
| 85 | + var notLoopingReason = suggested.reason; |
| 86 | + display.oled.setCursor(0,16); |
| 87 | + if (pumpbattery.voltage <= 1.25) { |
| 88 | + display.oled.writeString(font, 1, "LOW PUMP BATT.", 1, false, 0, false); |
| 89 | + yOffset = 3; |
| 90 | + } |
| 91 | + else if (status.suspended == true) { |
| 92 | + display.oled.writeString(font, 1, "PUMP SUSPENDED", 1, false, 0, false); |
| 93 | + yOffset = 3; |
| 94 | + } |
| 95 | + else if (status.bolusing == true) { |
| 96 | + display.oled.writeString(font, 1, "PUMP BOLUSING", 1, false, 0, false); |
| 97 | + yOffset = 3; |
| 98 | + } |
| 99 | + else if (notLoopingReason.includes("CGM is calibrating")) { |
| 100 | + display.oled.writeString(font, 1, "CGM calib./???/noisy", 1, false, 0, false); |
| 101 | + yOffset = 3; |
| 102 | + } |
| 103 | + else if (notLoopingReason.includes("CGM data is unchanged")) { |
| 104 | + display.oled.writeString(font, 1, "CGM data unchanged", 1, false, 0, false); |
| 105 | + yOffset = 3; |
| 106 | + } |
| 107 | + else if (notLoopingReason.includes("BG data is too old")) { |
| 108 | + display.oled.writeString(font, 1, "BG data too old", 1, false, 0, false); |
| 109 | + yOffset = 3; |
| 110 | + } |
| 111 | + else if (notLoopingReason.includes("currenttemp rate")) { |
| 112 | + display.oled.writeString(font, 1, "Temp. mismatch", 1, false, 0, false); |
| 113 | + yOffset = 3; |
| 114 | + } |
| 115 | + else if (suggested.carbsReq) { |
| 116 | + display.oled.writeString(font, 1, "Carbs Requiredd: "+suggested.carbsReq+'g', 1, false, 0, false); |
| 117 | + yOffset = 3; |
| 118 | + } |
| 119 | +//add more on-screen warnings/messages, maybe some special ones for xdrip-js users? |
| 120 | +} |
| 121 | + |
| 122 | +//calculate timeago for BG |
| 123 | +var startDate = new Date(bg[0].date); |
| 124 | +var endDate = new Date(); |
| 125 | +var minutes = Math.round(( (endDate.getTime() - startDate.getTime()) / 1000) / 60); |
| 126 | +if (bg[0].delta) { |
| 127 | + var delta = Math.round(bg[0].delta); |
| 128 | +} else if (bg[1] && bg[0].date - bg[1].date > 200000 ) { |
| 129 | + var delta = Math.round(bg[0].glucose - bg[1].glucose); |
| 130 | +} else if (bg[2] && bg[0].date - bg[2].date > 200000 ) { |
| 131 | + var delta = Math.round(bg[0].glucose - bg[2].glucose); |
| 132 | +} else if (bg[3] && bg[0].date - bg[3].date > 200000 ) { |
| 133 | + var delta = Math.round(bg[0].glucose - bg[3].glucose); |
| 134 | +} else { |
| 135 | + var delta = 0; |
| 136 | +} |
| 137 | +//display BG number and timeago, add plus sign if delta is positive |
| 138 | +display.oled.setCursor(0,24); |
| 139 | +if (delta >= 0) { |
| 140 | + display.oled.writeString(font, 1, "BG:"+convert_bg(bg[0].glucose, profile)+"+"+stripLeadingZero(convert_bg(delta, profile))+" "+minutes+"m", 1, false, 0, false); |
| 141 | +} else { |
| 142 | + display.oled.writeString(font, 1, "BG:"+convert_bg(bg[0].glucose, profile)+""+stripLeadingZero(convert_bg(delta, profile))+" "+minutes+"m", 1, false, 0, false); |
| 143 | +} |
| 144 | + |
| 145 | +//display current temp basal and how long ago it was set, on the first line of the screen |
| 146 | +if (statusStats && temp) { |
| 147 | + startDate = new Date(statusStats.mtime); |
| 148 | + endDate = new Date(); |
| 149 | + var minutesAgo = Math.round(( (endDate.getTime() - startDate.getTime()) / 1000) / 60); |
| 150 | + //display current temp basal |
| 151 | + display.oled.setCursor(0,0); |
| 152 | + var tempRate = Math.round(temp.rate*10)/10; |
| 153 | + display.oled.writeString(font, 1, "TB: "+temp.duration+'m '+tempRate+'U/h '+'('+minutesAgo+'m ago)', 1, false, 0, false); |
| 154 | +} |
| 155 | + |
| 156 | +//display current COB and IOB, on the second line of the screen |
| 157 | +if (iob && cob) { |
| 158 | + display.oled.setCursor(0,8); |
| 159 | + display.oled.writeString(font, 1, "COB: "+cob.mealCOB+"g IOB: "+iob[0].iob+'U', 1, false, 0, false); |
| 160 | +} |
| 161 | + |
| 162 | +//render clock |
| 163 | +var clockDate = new Date(); |
| 164 | +var clockHour = clockDate.getHours(); |
| 165 | +clockHour = (clockHour < 10 ? "0" : "") + clockHour; |
| 166 | +var clockMin = clockDate.getMinutes(); |
| 167 | +clockMin = (clockMin < 10 ? "0" : "") + clockMin; |
| 168 | +display.oled.setCursor(97, 24); |
| 169 | +display.oled.writeString(font, 1, clockHour+":"+clockMin, 1, false, 0, false); |
| 170 | + |
| 171 | +display.oled.dimDisplay(true); //dim the display |
| 172 | +display.oled.update(); //write buffer to the screen |
| 173 | + |
| 174 | +fs.readFile(openapsDir+"/preferences.json", function (err, data) { |
| 175 | + if (err) throw err; |
| 176 | + preferences = JSON.parse(data); |
| 177 | + if (preferences.wearOLEDevenly && preferences.wearOLEDevenly.includes("off")) { |
| 178 | + display.oled.invertDisplay(false); |
| 179 | + } |
| 180 | + else if (preferences.wearOLEDevenly && preferences.wearOLEDevenly.includes("nightandday") && (clockHour >= 20 || clockHour <= 8)) { |
| 181 | + display.oled.invertDisplay(false); |
| 182 | + } |
| 183 | + else if (preferences.wearOLEDevenly && preferences.wearOLEDevenly.includes("nightandday") && (clockHour <= 20 && clockHour >= 8)) { |
| 184 | + display.oled.invertDisplay(true); |
| 185 | + } |
| 186 | + else { |
| 187 | + display.oled.invertDisplay((endDate % 2 == 1)); |
| 188 | + } |
| 189 | +}); |
| 190 | + |
| 191 | + // |
| 192 | +}//End of status display function |
| 193 | + // |
0 commit comments