// ----------------------------------------- // 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] }