diff --git a/mainloop-function.js b/mainloop-function.js new file mode 100644 index 0000000..680d4ef --- /dev/null +++ b/mainloop-function.js @@ -0,0 +1,197 @@ +// ----------------------------------------- +// Notify and store power use and cost for an appliance +// MAIN LOOP +// Full loop to calculate power average of appliance and +// work out when it is operating. When operational +// fill arrays with power used, and cost of power calculated. +// ----------------------------------------- +// 2021-04-12 V1.3 - zorruno +// - Fixed loop not detecting Finished-> Standby +// - Moved some flow variables to context +// - Changed csv filename to reflect appliance +// ----------------------------------------- + +// The input message must be the current power in Watts +var power = msg.payload; + +// Get flow user settings variables into local variables +var res = flow.get("resolution"); +var tariff = flow.get("tariff"); +var metricsf = flow.get("metricFrequency"); +var standby = flow.get("standbyPower"); +var opPowerMin = flow.get("operatingPowerMinium"); +var currentCycle = flow.get("currentApplianceCycle"); + +// Get flow variables into local variables +var operation = context.get("operation") || "Off"; +var recentPowerArray = flow.get("recentPowerArray") || [0]; +var cycleCostArray = flow.get("cycleCostArray") || [0]; +var cyclePowerArray = flow.get("cyclePowerArray") || [0]; + +// Get date, seconds and hours +var date = new Date(); +var dateS = date.getTime()/1000; +var hour = date.getHours(); + +// ----------------------------------------- +// Fill power array, and calculate average +// power. Do this on every loop. +// ----------------------------------------- + +// Function add for reduce array +function add(accumulator, a) { + return accumulator + a; +} +// Push power into TotalPower array for average +recentPowerArray.unshift(power); +// Remove X element to get total resolution for average calc +if(recentPowerArray[res] === undefined) { + flow.set("recentPowerArray", recentPowerArray); +} +else { + recentPowerArray.splice(res, 1); + flow.set("recentPowerArray", recentPowerArray); +} +// Calculate average power from array +var sum = recentPowerArray; +var average = (sum.reduce(add)/recentPowerArray.length); // Average the array + + +// ----------------------------------------- +// Fill cycle power array, and calculate average power. +// Only do this when cycle is occurring. +// Note this method doesn't capture EVERY data point - +// we'll miss the first few as we are calculating an +// average. We could capture more, but that is less efficient. +// ----------------------------------------- +if(operation === "Operating"){ + // Push watthours into cyclePowerArray for cycle + var wattHoursNow = power / ( 60 * ( 60 / metricsf )); + cyclePowerArray.push(wattHoursNow); + flow.set("cyclePowerArray", cyclePowerArray); + + // Calculate the cost of power + var price; + if( hour >= tariff.start && hour < tariff.end ){ + price = tariff.costDay; // Apply day tariff + } + if( hour < tariff.start || hour >= tariff.end ){ + price = tariff.costNight; // Apply night tariff + } + + // Fill cycleCostArray + var costPerMinute = power/1000 * price / (60* (60/metricsf)); + cycleCostArray.push(costPerMinute); + flow.set("cycleCostArray", cycleCostArray); // Add to cost array +} + +// ----------------------------------------- +// Appliance is off +// ----------------------------------------- +//if(average === 0){ +if(average < standby){ + context.set("operation", "Off"); +} + +// ----------------------------------------- +// Appliance has gone into Standby from Off +// ----------------------------------------- +if(average >= standby && operation === "Off"){ + context.set("operation", "Standby"); +} + +// ----------------------------------------- +// Appliance has gone into Standby from Finished +// ----------------------------------------- +if(average >= standby && operation === "Finished"){ + context.set("operation", "Standby"); +} + +// ----------------------------------------- +// Appliance has started its Operating cycle +// from Standby or Off +// ----------------------------------------- +if((average > opPowerMin && operation === "Standby") || (average > opPowerMin && operation === "Off")){ + context.set("operation", "Operating"); + currentCycle.cycleTimeStart = dateS; + cycleCostArray = [0]; // Clear array to start cycle + flow.set("cycleCostArray",cycleCostArray); + cyclePowerArray = [0]; // Clear array to start cycle + flow.set("cyclePowerArray",cyclePowerArray); +} + +// ----------------------------------------- +// Appliance was in Operating cycle, +// but now has Finished +// ----------------------------------------- +if(average < opPowerMin && operation === "Operating"){ + context.set("operation", "Finished"); + currentCycle.cycleTimeStop = dateS; + + // Calculate & format total cost of the entire cycle + var sumCost = flow.get("cycleCostArray"); + var costOfPower = sumCost.reduce(add); + currentCycle.totalCycleCostDollars = costOfPower; + + // Format as $ or cents + if ( costOfPower < 0.01 ){ + costOfPower = '<1c'; + } else if ( costOfPower < 1){ + costOfPower = costOfPower * 100; + costOfPower = Math.round(costOfPower); + costOfPower = costOfPower.toString() + 'c'; + } else { + costOfPower = costOfPower.toFixed(2); + costOfPower = '$' + costOfPower.toString(); + } + currentCycle.totalCycleCostFormatted = costOfPower ; + + // Calculate & format total power use of the entire cycle + var sumPower = flow.get("cyclePowerArray"); + var sumOfPower = sumPower.reduce(add); + currentCycle.totalCyclePowerWattHours = sumOfPower; + + // Format as wH or kWh + if ( sumOfPower >= 1000 ){ + sumOfPower = sumOfPower / 1000; + sumOfPower = sumOfPower.toFixed(1); // 1 decimal place + sumOfPower = sumOfPower.toString() + 'kWh'; + } else if ( costOfPower < 1){ + costOfPower = '<1Wh'; + } else { + sumOfPower = sumOfPower.toFixed(1); // 1 decimal place + sumOfPower = sumOfPower.toString() + 'Wh'; + } + + currentCycle.totalCyclePowerFormatted = sumOfPower ; + + msg.payload = context.get("operation") ; + return [msg,msg] +} + + +// ----------------------------------------- +// Output debug stuff on each loop +// ----------------------------------------- +if(flow.get("debugFlow") === true){ + + flow.set("debugAverage",average) ; + + // Calculate total cost of the entire cycle so far + var costSoFar = flow.get("cycleCostArray").reduce(add); + flow.set("debugCostSoFar",costSoFar) ; + + // Calculate total power use of the entire cycle so far + var powerSoFar = flow.get("cyclePowerArray").reduce(add); + flow.set("debugPowerSoFar",powerSoFar) ; + + flow.set("debugCyclePowerArray",cyclePowerArray) ; + flow.set("debugCycleCostArray",cycleCostArray) ; + flow.set("debugRecentPowerArray",recentPowerArray) ; + + msg.payload = context.get("operation") ; + return [null,msg] +} + + +