UNPKG

heatingpro-efficiency

Version:

Utility functions for MonitoringPro efficiency calculations with flexible unit support (GJ, kWh, MWh)

246 lines (208 loc) 7.87 kB
const { hasPropertiesAndNotDash, toFloatWithDot, convertHeatToKwh, } = require("./utils/index.js"); const computeEfficiency = ( row, prevRow, monthlyEffectivityConstant, fieldUnits = {} ) => { // Helper function to convert MWh to GJ if needed const convertValue = (value, fieldName) => { if (fieldUnits[fieldName] === "mwh") { return value * 3.6; // Convert MWh to GJ } return value; }; let sumOfDiffs = 0; let hasNegativeDiff = false; let totalPreviousHeat = 0; for (let i = 1; i <= 8; i++) { const voKey = `VO${i}`; if (hasPropertiesAndNotDash(row, prevRow, voKey)) { const currentVal = toFloatWithDot(row[voKey]); const prevVal = toFloatWithDot(prevRow[voKey]); // Convert values if they are in MWh const convertedCurrentVal = convertValue(currentVal, voKey); const convertedPrevVal = convertValue(prevVal, voKey); const diff = convertedCurrentVal - convertedPrevVal; if (!isNaN(diff)) { if (diff < 0) { hasNegativeDiff = true; } totalPreviousHeat += convertedPrevVal; sumOfDiffs += diff; } } } if (hasPropertiesAndNotDash(row, prevRow, "MT TUV")) { const currentVal = toFloatWithDot(row["MT TUV"]); const prevVal = toFloatWithDot(prevRow["MT TUV"]); // Convert values if they are in MWh const convertedCurrentVal = convertValue(currentVal, "MT TUV"); const convertedPrevVal = convertValue(prevVal, "MT TUV"); const diff = convertedCurrentVal - convertedPrevVal; if (!isNaN(diff)) { if (diff < 0) { hasNegativeDiff = true; } totalPreviousHeat += convertedPrevVal; sumOfDiffs += diff; } } // Detect heat meter reset: negative difference that's significant (> 50% of previous total) // This indicates the meter was reset (current reading < previous reading by a large margin) const isHeatMeterReset = hasNegativeDiff && totalPreviousHeat > 0 && sumOfDiffs < 0 && Math.abs(sumOfDiffs) > totalPreviousHeat * 0.5; const gasDiff = toFloatWithDot(row["Plyn"]) - toFloatWithDot(prevRow["Plyn"]); // Handle gas meter reset: if current reading is significantly less than previous, // it's likely a meter reset. A reset is detected when current < previous AND // the difference is large (> 50% of previous value) const prevGasValue = toFloatWithDot(prevRow["Plyn"]); const isGasMeterReset = gasDiff < 0 && prevGasValue > 0 && Math.abs(gasDiff) > prevGasValue * 0.5; // Convert heat to kWh based on input units (always GJ now since we converted above) const voDiffInKwh = convertHeatToKwh(sumOfDiffs, "GJ"); const gasDiffInKwh = gasDiff * 9.855; // 1 m³ gas = 9.855 kWh (Method 2) let efficiency; // Handle different scenarios for efficiency calculation if (isGasMeterReset || isHeatMeterReset) { // Meter reset detected - cannot calculate efficiency reliably efficiency = "-"; } else if (gasDiff <= 0) { // Negative or zero gas consumption - invalid if (gasDiff < 0) { // Negative gas difference indicates meter reset or data error efficiency = "-"; } else if (sumOfDiffs === 0) { // No consumption at all - no meaningful efficiency efficiency = "-"; } else { // Heat produced without gas consumption - invalid scenario efficiency = "-"; } } else if (sumOfDiffs <= 0) { // Negative or zero heat production if (sumOfDiffs < 0) { // Negative heat difference indicates meter reset or data error efficiency = "-"; } else { // Gas consumed but no heat produced - 0% efficiency efficiency = "0.0000"; } } else if (monthlyEffectivityConstant <= 0 || isNaN(monthlyEffectivityConstant)) { // Invalid effectivity constant efficiency = "-"; } else { // Normal calculation: efficiency = (heat output / (gas input * constant)) // Returns decimal value (e.g., 0.88 for 88%) - will be multiplied by 100 in display code const calculatedEfficiency = voDiffInKwh / (gasDiffInKwh * monthlyEffectivityConstant); // Validate result: efficiency should be reasonable // Check for NaN, Infinity, or negative values // Note: Upper bound removed as efficiency can vary based on effectivityConstant value if (isNaN(calculatedEfficiency) || !isFinite(calculatedEfficiency) || calculatedEfficiency < 0) { efficiency = "-"; } else { efficiency = Number(calculatedEfficiency).toFixed(4); } } // Return heat units value (always in GJ for display) // Make sure we don't return NaN const heatUnitsValue = isNaN(sumOfDiffs) ? 0 : sumOfDiffs; return { ...row, ucinnost: efficiency, heatUnits: heatUnitsValue, }; }; /** * Checks if heat meters are being written off (have valid readings and differences) * @param {Array} valuesData - Array of row data objects * @param {Object} fieldUnits - Mapping of field names to their units * @returns {boolean} - True if meters exist and are being written off, false otherwise */ const areMetersBeingWrittenOff = (valuesData, fieldUnits = {}) => { if (!valuesData || valuesData.length < 2) { return false; } // Helper function to convert MWh to GJ if needed const convertValue = (value, fieldName) => { if (fieldUnits[fieldName] === "mwh") { return value * 3.6; // Convert MWh to GJ } return value; }; // First, check if meters exist (have non-dash values in any row) let metersExist = false; for (const row of valuesData) { // Check VO1-VO8 meters for (let j = 1; j <= 8; j++) { const voKey = `VO${j}`; if ( row.hasOwnProperty(voKey) && row[voKey] !== "-" && row[voKey] !== null && row[voKey] !== undefined && row[voKey] !== "" ) { metersExist = true; break; } } // Check MT TUV meter if ( row.hasOwnProperty("MT TUV") && row["MT TUV"] !== "-" && row["MT TUV"] !== null && row["MT TUV"] !== undefined && row["MT TUV"] !== "" ) { metersExist = true; } if (metersExist) break; } // If meters don't exist, return false if (!metersExist) { return false; } // Check if there are any valid meter readings with differences across rows for (let i = 1; i < valuesData.length; i++) { const row = valuesData[i]; const prevRow = valuesData[i - 1]; let sumOfDiffs = 0; // Check VO1-VO8 meters for (let j = 1; j <= 8; j++) { const voKey = `VO${j}`; if (hasPropertiesAndNotDash(row, prevRow, voKey)) { const currentVal = toFloatWithDot(row[voKey]); const prevVal = toFloatWithDot(prevRow[voKey]); // Convert values if they are in MWh const convertedCurrentVal = convertValue(currentVal, voKey); const convertedPrevVal = convertValue(prevVal, voKey); const diff = convertedCurrentVal - convertedPrevVal; if (!isNaN(diff) && diff !== 0) { sumOfDiffs += Math.abs(diff); } } } // Check MT TUV meter if (hasPropertiesAndNotDash(row, prevRow, "MT TUV")) { const currentVal = toFloatWithDot(row["MT TUV"]); const prevVal = toFloatWithDot(prevRow["MT TUV"]); // Convert values if they are in MWh const convertedCurrentVal = convertValue(currentVal, "MT TUV"); const convertedPrevVal = convertValue(prevVal, "MT TUV"); const diff = convertedCurrentVal - convertedPrevVal; if (!isNaN(diff) && diff !== 0) { sumOfDiffs += Math.abs(diff); } } // If we found any non-zero difference, meters are being written off if (sumOfDiffs > 0) { return true; } } // Meters exist but no differences found (not being written off yet) return false; }; module.exports = { computeEfficiency, areMetersBeingWrittenOff };