UPS Status Monitor applet
Almquist Shell Script written for POSIX systems like OpenWRT, Linux and WSL2/WSLg

---------------------------------------
Dependencies
---------------------------------------
This depends on NUT (Network UPS Tools), specifically its upsc excutable.  I have my copy configured to detect my UPS via the instruction "upsc CP685AVR@localhost", for my CyberPower CP685AVR unit.  This is otherwise entirely browser-instigated.  No cron tasks needed!

Just OpenWRT or any POSIX system like OpenWRT, Linux and WSL2/WSLg.  If you can run ash prompt scripts or bash (Bourne Again Shell) scripts, you can run this!

---------------------------------------
Installation
---------------------------------------
The files are to be mounted as follows:
├── readme.txt (this very file)
├── <the code goes into your html file>
└── cgi-bin
    └── upsstatus.sh

Just remeber to chmod +x upsstatus.sh before running it!
```

---------------------------------------
What is it?
---------------------------------------
I wrote this program to help me monitor the UPS that my router is connected to.  I wrote a custom landing page in place of the usual OpenWRT LuCI page at index.html (with the LuCI page being moved to admin.html) and needed a way to see how my UPS was going, that was similar to NUT but embedded within index.html.


SO!  I wrote up upsstatus.sh and then embedded it with this code:

```
    <div style="font-weight: bold; font-size: 1.2em; margin-bottom: 4px;">
      &#x1F50B; UPS Battery Status
    </div>
    <div id="ups-box" style="padding: 8px; font-size: 1.1em; font-weight: bold; transition: color 0.3s ease;">
      Loading UPS status&#x2026;
    </div>

<script>
async function updateUPS() {
    try {
        const res = await fetch('/cgi-bin/upsstatus.sh');
        const data = await res.json();

        const charge = parseInt(data.charge) || 0;
        const status = data.status;
        const load = parseInt(data.load) || 0;
        const runtime = parseInt(data.runtime) || 0;

        // Determine color
        let color = 'black';
        if (status === 'OL') color = '#3399FF';
        else if (charge >= 76) color = '#008000';
        else if (charge >= 51) color = '#FFD700';
        else if (charge >= 26) color = '#FFA500';
        else color = '#FF0000';

        // Emoji battery bar (HTML escapes)
        let bar = '';
        if (charge >= 76) bar = '&#x1F7E9;&#x1F7E9;&#x1F7E9;&#x1F7E9;&#x1F7E9;';
        else if (charge >= 51) bar = '&#x1F7E9;&#x1F7E9;&#x1F7E9;&#x1F7E9;&#x2B1C;';
        else if (charge >= 26) bar = '&#x1F7E7;&#x1F7E7;&#x1F7E7;&#x2B1C;&#x2B1C;';
        else bar = '&#x1F7E5;&#x1F7E5;&#x2B1C;&#x2B1C;&#x2B1C;';

        // Status text
        let text = '';
        if (status === 'OL') text = `Mains Power (${charge}%)`;
        else if (status === 'OB') text = `On Battery (${charge}%)`;
        else if (status === 'LB') text = `Low Battery (${charge}%)`;
        else text = `Status: ${status} (${charge}%)`;

        // Runtime countdown (convert seconds → H:MM:SS)
        function fmt(sec) {
            const h = Math.floor(sec / 3600);
            const m = Math.floor((sec % 3600) / 60);
            const s = sec % 60;
            return `${h}:${m.toString().padStart(2,'0')}:${s.toString().padStart(2,'0')}`;
        }

        const runtimeText = fmt(runtime);

        document.getElementById('ups-box').innerHTML =
            `<span style="color:${color}">${text} ${bar}</span><br>
             <span style="font-size:0.9em;">UPS Load: ${load}%</span><br>
             <span style="font-size:0.9em;">Remaining Runtime: ${runtimeText}</span>`;
    } catch (e) {
        document.getElementById('ups-box').innerText = 'UPS status unavailable';
    }
}

setInterval(updateUPS, 5000);
updateUPS();
</script>

  </div>
```

Any further comments, questions or suggestions can be forwarded to the developer at slycooper1986@yahoo.ca
