const GraphXZero = 40; const GraphYZero = 180; const GraphY100 = 80; const GraphMarkerOffset = 5; const MaxValueCount = 144; const GraphXMax = GraphXZero + MaxValueCount; const GraphLcdY = GraphYZero + 10; const GraphCompassY = GraphYZero + 16; const GraphBluetoothY = GraphYZero + 22; const GraphGpsY = GraphYZero + 28; const GraphHrmY = GraphYZero + 34; const Storage = require("Storage"); function renderCoordinateSystem() { g.setFont("6x8", 1); // Left Y axis (Battery) g.setColor(1, 1, 0); g.drawLine(GraphXZero, GraphYZero + GraphMarkerOffset, GraphXZero, GraphY100); g.drawString("%", 39, GraphY100 - 10); g.setFontAlign(1, -1, 0); g.drawString("100", 30, GraphY100 - GraphMarkerOffset); g.drawLine(GraphXZero - GraphMarkerOffset, GraphY100, GraphXZero, GraphY100); g.drawString("50", 30, GraphYZero - 50 - GraphMarkerOffset); g.drawLine(GraphXZero - GraphMarkerOffset, 130, GraphXZero, 130); g.drawString("0", 30, GraphYZero - GraphMarkerOffset); g.setColor(1,1,1); g.setFontAlign(1, -1, 0); g.drawLine(GraphXZero - GraphMarkerOffset, GraphYZero, GraphXMax + GraphMarkerOffset, GraphYZero); // Right Y axis (Temperature) g.setColor(0.4, 0.4, 1); g.drawLine(GraphXMax, GraphYZero + GraphMarkerOffset, GraphXMax, GraphY100); g.drawString("°C", GraphXMax + GraphMarkerOffset, GraphY100 - 10); g.setFontAlign(-1, -1, 0); g.drawString("20", GraphXMax + 2 * GraphMarkerOffset, GraphYZero - GraphMarkerOffset); g.drawLine(GraphXMax + GraphMarkerOffset, 130, GraphXMax, 130); g.drawString("30", GraphXMax + 2 * GraphMarkerOffset, GraphYZero - 50 - GraphMarkerOffset); g.drawLine(GraphXMax + GraphMarkerOffset, 80, GraphXMax, 80); g.drawString("40", GraphXMax + 2 * GraphMarkerOffset, GraphY100 - GraphMarkerOffset); g.setColor(1,1,1); } function decrementDay(dayToDecrement) { return dayToDecrement === 0 ? 6 : dayToDecrement-1; } function loadData() { const startingDay = new Date().getDay(); // Load data for the current day let logFileName = "bclog" + startingDay; let dataLines = loadLinesFromFile(MaxValueCount, logFileName); // Top up to MaxValueCount from previous days as required let previousDay = decrementDay(startingDay); while (dataLines.length < MaxValueCount && previousDay !== startingDay) { let topUpLogFileName = "bclog" + previousDay; let remainingLines = MaxValueCount - dataLines.length; let topUpLines = loadLinesFromFile(remainingLines, topUpLogFileName); if(topUpLines) { dataLines = topUpLines.concat(dataLines); } previousDay = decrementDay(previousDay); } return dataLines; } function loadLinesFromFile(requestedLineCount, fileName) { let allLines = []; let returnLines = []; var readFile = Storage.open(fileName, "r"); while ((nextLine = readFile.readLine())) { if(nextLine) { allLines.push(nextLine); } } readFile = null; if (allLines.length <= 0) return; let linesToReadCount = Math.min(requestedLineCount, allLines.length); let startingLineIndex = Math.max(0, allLines.length - requestedLineCount - 1); for (let i = startingLineIndex; i < linesToReadCount + startingLineIndex; i++) { if(allLines[i]) { returnLines.push(allLines[i]); } } allLines = null; return returnLines; } function renderData(dataArray) { const switchableConsumers = { none: 0, lcd: 1, compass: 2, bluetooth: 4, gps: 8, hrm: 16 }; //const timestampIndex = 0; const batteryIndex = 1; const temperatureIndex = 2; const switchabelsIndex = 3; const minTemperature = 20; const maxTemparature = 40; const belowMinIndicatorValue = minTemperature - 1; const aboveMaxIndicatorValue = maxTemparature + 1; var allConsumers = switchableConsumers.none | switchableConsumers.lcd | switchableConsumers.compass | switchableConsumers.bluetooth | switchableConsumers.gps | switchableConsumers.hrm; for (let i = 0; i < dataArray.length; i++) { const element = dataArray[i]; var dataInfo = element.split(","); // Battery percentage g.setColor(1, 1, 0); g.setPixel(GraphXZero + i, GraphYZero - parseInt(dataInfo[batteryIndex])); // Temperature g.setColor(0.4, 0.4, 1); let datapointTemp = parseFloat(dataInfo[temperatureIndex]); if (datapointTemp < minTemperature) { datapointTemp = belowMinIndicatorValue; } if (datapointTemp > maxTemparature) { datapointTemp = aboveMaxIndicatorValue; } // Scale down the range of 20 - 40°C to a 100px y-axis, where 1px = .25° let scaledTemp = Math.floor(((datapointTemp * 100) - 2000) / 20) + ((((datapointTemp * 100) - 2000) % 100) / 25); g.setPixel(GraphXZero + i, GraphYZero - scaledTemp); // LCD state if (parseInt(dataInfo[switchabelsIndex]) & switchableConsumers.lcd) { g.setColor(1, 1, 1); g.setFontAlign(1, -1, 0); g.drawString("LCD", GraphXZero - GraphMarkerOffset, GraphLcdY - 2, true); g.drawLine(GraphXZero + i, GraphLcdY, GraphXZero + i, GraphLcdY + 1); } // Compass state if (parseInt(dataInfo[switchabelsIndex]) & switchableConsumers.compass) { g.setColor(0, 1, 0); g.setFontAlign(-1, -1, 0); g.drawString("Compass", GraphXMax + GraphMarkerOffset, GraphCompassY - 2, true); g.drawLine(GraphXZero + i, GraphCompassY, GraphXZero + i, GraphCompassY + 1); } // Bluetooth state if (parseInt(dataInfo[switchabelsIndex]) & switchableConsumers.bluetooth) { g.setColor(0, 0, 1); g.setFontAlign(1, -1, 0); g.drawString("BLE", GraphXZero - GraphMarkerOffset, GraphBluetoothY - 2, true); g.drawLine(GraphXZero + i, GraphBluetoothY, GraphXZero + i, GraphBluetoothY + 1); } // Gps state if (parseInt(dataInfo[switchabelsIndex]) & switchableConsumers.gps) { g.setColor(0.8, 0.5, 0.24); g.setFontAlign(-1, -1, 0); g.drawString("GPS", GraphXMax + GraphMarkerOffset, GraphGpsY - 2, true); g.drawLine(GraphXZero + i, GraphGpsY, GraphXZero + i, GraphGpsY + 1); } // Hrm state if (parseInt(dataInfo[switchabelsIndex]) & switchableConsumers.hrm) { g.setColor(1, 0, 0); g.setFontAlign(1, -1, 0); g.drawString("HRM", GraphXZero - GraphMarkerOffset, GraphHrmY - 2, true); g.drawLine(GraphXZero + i, GraphHrmY, GraphXZero + i, GraphHrmY + 1); } } dataArray = null; } function renderHomeIcon() { //Home for Btn2 g.setColor(1, 1, 1); g.drawLine(220, 118, 227, 110); g.drawLine(227, 110, 234, 118); g.drawPoly([222,117,222,125,232,125,232,117], false); g.drawRect(226,120,229,125); } function renderBatteryChart() { renderCoordinateSystem(); let data = loadData(); renderData(data); data = null; } // Show launcher when middle button pressed function switchOffApp(){ Bangle.showLauncher(); } // special function to handle display switch on Bangle.on('lcdPower', (on) => { if (on) { g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); renderBatteryChart(); } }); setWatch(switchOffApp, BTN2, {edge:"falling", debounce:50, repeat:true}); g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); renderHomeIcon(); renderBatteryChart();