PC Dashboard using NETIO Power Cables

How power-hungry is your PC?

I always wondered how much power my desktop computer draws. The 750W PSU can draw a lot in theory, but for most of the time, the PC is idling at 20% CPU use. There is more than one reason for using NETIO Power Cable 101x for that, unlike Sonoff POWR2, the unit already comes with C-14 (PSU cable), it’s sturdy, and there is no need to flash custom software.

NETIO Power Cables

NETIO products come in many shapes, but I got the PC cable for 2 reasons:

  • toggling power ON|OFF
  • monitoring power use

You could achieve this with a Sonoff POW R2, but NETIO power cables come with a protected button toggle, which is hard to toggle accidentally. You need a pin, and 3 presses to change the state. The company clearly wants to reduce the danger of that to zero.

I picked the NETIO Power Cable REST 101x as I wanted to submit the data to my NodeRED server via HTTP requests. The API is well documented and it’s very easy to work with.

NETIO power cables come with a basic GUI hosted at port 80, but for the most part, you will interact with the cable via API. I took a couple of screenshots to show you what’s available.

The data can be transferred via JSON, XML and URL. I’m dealing with NodeRED, JSON would be the perfect fit. Here is the data structure:

NETIO JSON
{
     "Agent": {
         "Model": "101x",
         "DeviceName": "Computer",
         "MAC": "24:A4:2x:xx:xx:xx",
         "JSONVer": "2.0",
         "Time": "2019-12-04T11:07:26+00:00",
         "Uptime": 54111,
         "Version": "2.2.4",
         "OemID": "5",
         "VendorID": "0",
         "NumOutputs": 1
     },
     "GlobalMeasure": {
         "Voltage": 240,
         "TotalLoad": 52,
         "TotalEnergy": 12596,
         "OverallPowerFactor": 0.63,
         "Frequency": 50.0,
         "EnergyStart": "2019-08-09T05:45:47+00:00"
     },
     "Outputs": [
         {
             "ID": 1,
             "Name": "Computer",
             "State": 1,
             "Action": 6,
             "Delay": 2000,
             "Current": 344,
             "PowerFactor": 0.63,
             "Energy": 12596,
             "Load": 52
         }
     ]
 }

PC Dashboard

Data not factual due to testing

You will notice that my PC dashboard displays more details than what’s available via NETIO Power Cables. I took advantage of my previous projects (Washing Machine Notifications & Mobile Notifications for 3D Printers) to calculate the power used by my computer and the costs associated with it.

By default, I pull the data every 10 seconds, but the script is modified to support custom refresh rates. Make sure to preserve the NodeRED variables so the values wouldn’t be lost on NodeRED restart.

Not my PC, my case would not fit here!

Every 10 seconds

An HTTP GET request is sent to NETIO Power Cable. To make my life easier, I decided to store all values in flow variables. Based on the current load TotalLoad I update the main button on my dashboard (more about it here) and push correct values to display the data in the chart. (more about it here).

Then, a function node Calculate All takes care of all the values for me. These are split into three categories:

FUNCTION NODE: Every 24h
//get values
var totalload =  flow.get("TotalLoad");
var totalenergy = flow.get("TotalEnergy");
var refresh = flow.get("refresh_rate");
var totalusebyday = flow.get("TotalUseByDay");
var totalusebyhour = flow.get("TotalUseByHour");
var timetotal = flow.get("TimeTotal");
var timeday = flow.get("TimeDay");
var cost = global.get("PowerCost");
var averageuseperhour = flow.get("AverageUsePerHour");

//ERROR HANDLING









// functions
function calcTimeHM(hh){
    var hours = ("0"+Math.floor((hh%86400)/3600)).slice(-2);
    var minutes = ("0"+Math.floor((hh%3600)/60)).slice(-2);
    return hours + "h " + minutes +"min";
}

function calcTimeDHM(hh){
    var days = ("0"+Math.floor(hh/86400)).slice(-2);
    var hours = ("0"+Math.floor((hh%86400)/3600)).slice(-2);
    var minutes = ("0"+Math.floor((hh%3600)/60)).slice(-2);
    return days+"d " +hours + "h " + minutes +"min";
}

function add(accumulator, a) {
            return accumulator + a}

//WATTAGE

//total kWh
var kw = totalenergy/1000;
//today so far W
var todayw1 = totalusebyhour[0];
if(todayw1 === 0){
    var todayw = averageuseperhour.toFixed(2);
}
if(todayw1 !== 0){
   todayw = (totalusebyhour.reduce(add) + averageuseperhour).toFixed(2);
}

// Watts used in X sec (W per h)
var houruse = ((totalload/3600)*refresh);
var currentuse = averageuseperhour +  houruse;  


//COST

//calculate the day cost per used kWh
var daycost1 = totalusebyhour[0];
if(daycost1 === 0 || undefined){
    var daycost = (averageuseperhour/1000 * cost).toFixed(2);
}
if(daycost1 !== 0){
    daycost = ((totalusebyhour.reduce(add))/1000 * cost).toFixed(2);
}
//calculate the day cost per used kWh
var totalcost = (totalenergy/1000*cost).toFixed(2);


//TIME

//calculate uptime
if(totalload => 5){
    //total uptime
    var timeT = timetotal + 10;    
    var timeTdisplay = calcTimeDHM(timeT);
    //daily so far uptime
    var timeD = timeday + 10;    
    var timeDdisplay = calcTimeHM(timeD);
}
if(totalload < 5){
    //total uptime
    timeT = timetotal;    
    timeTdisplay = calcTimeDHM(timeT);
    //daily so far uptime
    timeD = timeday;    
    timeDdisplay = calcTimeHM(timeD);
}
     
//update values
flow.set("TimeTotal", timeT);
flow.set("TimeDay", timeD);
flow.set("AverageUsePerHour", currentuse);




//final payload

msg.payload = {
    "kwh"         : kw,
    "todayw"      : todayw,
    "daycost"     : daycost,
    "totalcost"   : totalcost,
    "currentuse"  : currentuse,
    "timeT"       : timeT,
    "timeTdisplay": timeTdisplay,
    "timeD"       : timeD,
    "timeDdisplay": timeDdisplay,
    "totalload"   : totalload,
    "totalenergy" : totalenergy
};


return msg;

Watts

Total Watts used are taken directly from the NETIO Power Cable (TotalEnergy). To get a daily breakdown, I could save the value every 24h and do some easy maths, but I wanted the power use per day to be available constantly.

I split this into 3 measurements:

  • per hour (Watts used in 10-sec increments)
  • per day (Watts from each hour and the current hour)
  • per week (Watts saved after each 24h period)

This way the correct power will be displayed on your dashboard. To calculate how much power had been used, simply use: var houruse = ((totalload/3600)*refresh);

Uptime

Calculating uptime was actually very simple, for every 10 seconds passed (update) I would add +10 to both arrays TimeTotal & TimeDay.

The daily value would be reset every 24h. To display the value in a more human format I used the scripts to calculate Seconds to DD:HH:MM:SS, it's a very good reddit collaboration where we came up with neat solutions to leading zeros and other problems.

Cost

Since I know how much I pay for kWh, I can estimate the cost of running my PC. Both calculations are simple once you have the total energy used. If you have 2 power tariffs, you will need to take a look at the Mobile Notifications for 3D printers to introduce multiple tariffs into your schedule.

Bear in mind that I'm using my credential system to store the important values in global variables and distribute them to other devices.

Every 1h

Every hour, NodeRED collects the power used in the last hour and pushes that data to the TotalUseByHour array. The AverageUsePerHour is cleared and ready to collect new power information.

FUNCTION NODE: Every Hour
var total = flow.get("TotalUseByHour");

if(total === undefined){
    total = [0];
    flow.set("TotalUseByHour", total);
}

if(!total || !total.length || total === undefined){
        total = [0];
    }

//push element to an array 1st postition


var value = flow.get("AverageUsePerHour");
total.unshift(value);
flow.set("TotalUseByHour", total);
flow.set("AverageUsePerHour", 0);

Every 24h

Every 24h values stored in the TotalUseByHour array are added together and pushed to the TotalUseByDay array. This array will hold the last 7 days of data so I could display it on the dashboard chart as well.

The hour details are cleared at midnight, and the 8th day is removed from the array so the chart consists of the weekly breakdown only.

FUNCTION NODE: Every 24h
var totalD = flow.get("TotalUseByHour");
var weektotal = flow.get("TotalUseByDay");
flow.set("TimeDay", 0);

if(!totalD || !totalD.length || totalD === undefined){
        totalD = [0];
        return msg;
    }


function add(accumulator, a) {
            return accumulator + a}
        

//Watts per 24h
var usedperday = totalD.reduce(add);

weektotal.unshift(usedperday);
flow.set("TotalUseByDay", weektotal);
totalD.splice(0,totalD.length);
totalD = [0];
flow.set("TotalUseByHour",totalD);



var totalW = flow.get("TotalUseByDay");

if(!totalW || !totalW.length || totalW === undefined){
        totalW = [0];
        return msg;
    }



//keep x number of elements in an array

var position = 7;

if(totalW[position] === undefined) {
    //do nothing if array empty
}
else {
    totalW.splice(position, 7); //remove 1 element from position
    flow.set("TotalUseByDay", totalW);
    
}

Dashboard extras

Interactive button

Instead of multiple buttons, I opted out for a single one which changes ist behaviour based on the power use. The button can:

  • put PC to sleep
  • wake PC up
  • power cycle NETIO Power Cable

I already have the WOL setup in NodeRED so implementation was very easy. All I had to do is to issue an HTTP request to reset the NETIO power cable and protect this action with 2FA (two-factor authentication tutorial) to prevent the accidental use.

The button has 3 states that are stored as a flow variable Power_function. The value sleep|reset|wol decides what action is taken once the button is pressed.

Protected button

There is one more way to invoke a safe power cycle. I used a switch in the dashboard to enable|disable the reset button. Now I can power cycle my PC anytime without the risk of doing it by mistake.

To force the PC to start-up after power loss, visit BIOS settings. You will need to enable that function. Check the power options and look for PC behaviour after the power loss.

Better Charts

Initially, I had my charts displaying the data after 24h. Waiting a full day (or more) to see the results wasn't fun so I decided to add a couple of conditions.

Improved charts will display the present-day only if there are no other values, and current hour by hour use as well. To achieve this, I used a couple of IF statements to check the array values before the graph is updated.

FUNCTION NODE: Update Chart
var arrayD = flow.get("TotalUseByDay");
var arrayH= flow.get("TotalUseByHour");
var averageperhour = flow.get("AverageUsePerHour");

//if array doen't exist
if(arrayD === undefined){
    arrayD = [0];
    flow.set("TotalUseByDay", arrayD);
}
if(arrayH === undefined){
    arrayH = [0];
    flow.set("TotalUseByHour", arrayH);
}

//function
function add(accumulator, a) {
            return accumulator + a}


//set data, label and series for the chart

var m = {};
var count = arrayD.length;

if(count === undefined || count < 2){
    
    m.labels = ["Today"];
    m.data = [[]];
    m.series = [];
    
    
    if(arrayH[0] === 0){
        m.data[0].push(averageperhour.toFixed(2));
        m.series.push("Watts/24h");
    }
    if(arrayH[0] > 0){    
        var usedperday = arrayH.reduce(add);
        m.data[0].push(usedperday.toFixed(2));
        m.series.push("Watts/24h");
    }
    
    
    
    return {payload:[m],topic:msg.topic};
}

else{
    
    m.labels = ["Today","Yesterday","Day3","Da4","Day5","Day6", "Day7"];
    m.data = [[]];
    m.series = [];
    if(arrayH[0] === 0){
        m.data[0].push(averageperhour.toFixed(2));
        m.series.push("Watts/24h");
    }
    if(arrayH[0] > 0){    
        usedperday = arrayH.reduce(add);
        m.data[0].push(usedperday.toFixed(2));
        m.series.push("Watts/24h");
    }m.series.push("Watts/24h");

for (i=0; i
Sonoff POW R2
Support NotEnoughTech
Buy Sonoff POW R2
Control a power outlet and monitor the power use at the same time

Conclusion

Disclaimer
NETIO Power Cables has been set to me for the purpose of this write-up free of charge.

To answer my question: How much actual power my 750W PSU is using? Turns out, not that much! The desktop PC uses 50-60W an hour, with peaks 270W while the machine is rendering videos. Running this beast (i7 + GTX2080) daily costs less than £0.30 which is OK.

There is one elephant in the room that I should address. NETIO Power Cables are expensive. Right now you can get one for €99 + VAT. Clearly the cables are designed for specific industry use cases with business customers in mind. It's going to be very hard to beat DIY Sonoff POWR2 approach where the same could be achieved for much less (with not as pretty effect). I'd hope to see NETIO Power Cables going down in price. At what price point would you try it out? Let me know in this Reddit thread.

Support NotEnoughTech
A lot of time and effort goes into keeping NotEnoughTech alive! If my work helped you out, consider buying me a coffee or check out exclusive rewards available to Patreon supporters.
SHARE