cutiepi-io / cutiepi-shell

A mobile shell for Raspberry Pi OS
https://cutiepi.io
GNU General Public License v3.0
232 stars 25 forks source link

[Enhancement] Battery % Display in 1% increments #27

Open r3wt opened 2 years ago

r3wt commented 2 years ago

So i started out simply trying to shave cycles out of onBatteryChanged., mainly by avoiding loops and conversion between number -> string -> number, and ended up completely rewriting it instead to show 101 points of precision in 1% increments, from 0% to 100%. I followed the voltage range "clamps", and wrote a script which calculates the voltage range for each percentage, then generates the code to be placed in onBatteryChanged.

I do not have a cutiepi yet to test this on, so i was hoping the dev team might be willing to test it on a device and ensure it works properly. It should, based on everything i read about QT javascript support

Pros:

Cons:

Wanted to create a jsbench test suite, but the code exceeds the maximum allowed size for a test case. image

Here's the script i used to generate the code:

const fs = require('fs');

var batteryVoltages = [
  "3.89",
  "3.88",
  "3.86",
  "3.82",
  "3.80",
  "3.76",
  "3.73",
  "3.69",
  "3.67",
  "3.65",
  "3.63",
  "3.61",
  "3.60",
  "3.59",
  "3.56",
  "3.55",
  "3.53",
  "3.51",
  "3.49",
  "3.48",
  "3.00",
].map(v=>parseFloat(v)*1000);

var batteryPercentages = [
  100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10,
  5, 0,
];

function generateRange(arr,baseVal) {
  let res = [];
  for(let i=arr.length-1;i>0;i--){
    let a = arr[i]+1;
    let b = arr[i-1]
    if(i===arr.length-1) {
      a=baseVal;
    }
    res.push([b,a]);
  }
  return res.reverse();
}

function getNums(n,f,tot){
  let x=1;
   const arr=[...new Array(n)]
    .map(c=>x*=f);
   const mul=tot/arr.reduce((a,c)=>a+c);
   return arr.map(v=>mul*v)
}

function expandRanges( pctRanges, voltRanges ) {
  return pctRanges.map((pr,i)=>{
    let n = pr[0]-pr[1]+1;// number of elements
    let prFinal = [];
    for(let i=pr[1];i<=pr[0];i++) {
      prFinal.push(i)
    }
    let vr = voltRanges[i];
    let vrFinal = [];
    let total = vr[0]-vr[1]
    let chunks = getNums(n,1.12359,total).reverse().map(v=>Math.round(v));
    let start = vr[1];
    for(let i=0;i<chunks.length;i++){
      vrFinal.push(start);
      start+=chunks[i];
      if(i==chunks.length-1){
        vrFinal[i]=vr[0];
      }
    }
    return { pct: prFinal.reverse(), voltage: vrFinal.reverse() };
  });
}

const batteryPercentageRanges = generateRange(batteryPercentages,0);
const batteryVoltageRanges = generateRange(batteryVoltages,3000);

console.log(batteryPercentageRanges,batteryVoltageRanges);

const crossMap = expandRanges( batteryPercentageRanges, batteryVoltageRanges );

console.log(crossMap);

const flattenedMap = [
  [],//voltages
  []//percentage
];
crossMap.forEach( item => {
  flattenedMap[0].push(...item.voltage);
  flattenedMap[1].push(...item.pct);
})

console.log(flattenedMap);
console.log(flattenedMap[0].length,flattenedMap[1].length);

let code = [];

code.push(
`
view.queue.push(battery);// there is no need to divide to get value volts, just use raw mv
if (view.queue.length > 15) {
  view.queue.shift();
}
var sum = 0;
var nSum = view.queue.length;
`);
for(let i=0;i<15;i++) {
  code.push(
  `if(view.queue[${i}]!==undefined) {
    sum += view.queue[${i}];
  }`
  );
}

code.push(`var meanVol=~~(sum/nSum);//strip decimal bits (round to integer)`);
code.push('switch(true){');

for(let i=0;i<flattenedMap[0].length;i++){
  if(i===0){
    //special case high voltage
    code.push(`case(meanVol>${flattenedMap[0][i+1]}):
      batteryPercentage=${flattenedMap[1][i]};
    break;
    `);  
  }
  else if(i===flattenedMap[0].length-2) {
    //special case 1%
    code.push(`case(meanVol>${flattenedMap[0][i]}):
      batteryPercentage=${flattenedMap[1][i]};
    break;
    `);  
  }
  else if(i===flattenedMap[0].length-1) {
    //special case low voltage
    code.push(`case(meanVol>${flattenedMap[0][i]}):
      //fall through to default case
    `);  
  }else{
    // all other case
    code.push(`case(meanVol>${flattenedMap[0][i+1]}&&meanVol<=${flattenedMap[0][i]}):
      batteryPercentage=${flattenedMap[1][i]};
    break;
    `);  
  }

}
code.push(`
  default:
    // doesnt seem possible but just in case something weird happened
    batteryPercentage=0;
  break;  
`)
code.push('}');
code.push('view.stableVol=Math.floor((meanVol/1000)*100)/100;');
code.push(`
if (!batteryCharging) { 
  if (view.queue.length < 5) {
    batteryText.text = "Checking..";
  } else {
    batteryText.text = batteryPercentage + "%";
  }
}
`);

const finalGeneratedCode = code.join("\r\n");

fs.writeFileSync('./onBatteryChanged.js',finalGeneratedCode,'utf-8');
penk commented 2 years ago

@r3wt thanks! let me take a look of it.