@measurequick/measurequick-report-generator 1.5.222 → 1.5.224
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -254,18 +254,69 @@ export async function getReport(payload, _test) {
|
|
|
254
254
|
return isFinite(n) ? n : NaN;
|
|
255
255
|
}
|
|
256
256
|
var coAmbRaw = toNum(data && data.co_ambient);
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
257
|
+
var coRetRaw = toNum(data && data.co_return);
|
|
258
|
+
var coSupRaw = toNum(data && data.co_supply);
|
|
259
|
+
|
|
260
|
+
// CO level helper function
|
|
261
|
+
// Normal: 0-8 ppm, Elevated: 9-35 ppm, Dangerous: 36-69 ppm, Emergency: 70+ ppm
|
|
262
|
+
function getCOLevel(ppm) {
|
|
263
|
+
if (!isFinite(ppm) || ppm <= 8) return "Normal";
|
|
264
|
+
if (ppm >= 9 && ppm <= 35) return "Elevated";
|
|
265
|
+
if (ppm >= 36 && ppm <= 69) return "Dangerous";
|
|
266
|
+
return "Emergency";
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
var reasons = [];
|
|
270
|
+
if (isFinite(coAmbRaw) && coAmbRaw > 8) reasons.push({ type: "Ambient", value: coAmbRaw, level: getCOLevel(coAmbRaw) });
|
|
271
|
+
if (isFinite(coRetRaw) && coRetRaw > 8) reasons.push({ type: "Return", value: coRetRaw, level: getCOLevel(coRetRaw) });
|
|
272
|
+
if (isFinite(coSupRaw) && coSupRaw > 8) reasons.push({ type: "Supply", value: coSupRaw, level: getCOLevel(coSupRaw) });
|
|
273
|
+
var coHigh = reasons.length > 0;
|
|
274
|
+
|
|
275
|
+
if (coHigh) {
|
|
276
|
+
// Find the highest severity level and the ambient CO reading
|
|
277
|
+
var highestLevel = "Elevated";
|
|
278
|
+
var ambientReading = null;
|
|
279
|
+
for (var r = 0; r < reasons.length; r++) {
|
|
280
|
+
if (reasons[r].type === "Ambient") ambientReading = reasons[r];
|
|
281
|
+
if (reasons[r].level === "Emergency") highestLevel = "Emergency";
|
|
282
|
+
else if (reasons[r].level === "Dangerous" && highestLevel !== "Emergency") highestLevel = "Dangerous";
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Build warning message focused on ambient CO
|
|
286
|
+
var warningMsg, warningMsg2;
|
|
287
|
+
if (ambientReading) {
|
|
288
|
+
warningMsg = "WARNING: " + ambientReading.level + " Ambient CO " + Math.round(ambientReading.value) + " ppm\nVentilate the area and investigate source.";
|
|
289
|
+
warningMsg2 = "WARNING: " + ambientReading.level + " Ambient CO " + Math.round(ambientReading.value) + " ppm. Ventilate the area and investigate source.";
|
|
290
|
+
} else {
|
|
291
|
+
// Fallback if no ambient reading (use first reading)
|
|
292
|
+
var firstReading = reasons[0];
|
|
293
|
+
warningMsg = "WARNING: " + firstReading.level + " " + firstReading.type + " CO " + Math.round(firstReading.value) + " ppm\nVentilate the area and investigate source.";
|
|
294
|
+
warningMsg2 = "WARNING: " + firstReading.level + " " + firstReading.type + " CO " + Math.round(firstReading.value) + " ppm. Ventilate the area and investigate source.";
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Set text with color based on severity level
|
|
298
|
+
// Orange for Elevated, Red for Dangerous, Dark Red for Emergency
|
|
299
|
+
var warningColor;
|
|
300
|
+
if (highestLevel === "Emergency") {
|
|
301
|
+
warningColor = rgb(0.72, 0.11, 0.11); // Dark red (#b71c1c)
|
|
302
|
+
} else if (highestLevel === "Dangerous") {
|
|
303
|
+
warningColor = rgb(0.96, 0.26, 0.21); // Red (#f44336)
|
|
304
|
+
} else {
|
|
305
|
+
warningColor = rgb(1, 0.6, 0); // Orange (#ff9800)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
var tf1 = form.getTextField("COWarning");
|
|
310
|
+
tf1.setText(warningMsg);
|
|
311
|
+
tf1.setTextColor(warningColor);
|
|
312
|
+
} catch (e) {}
|
|
313
|
+
try {
|
|
314
|
+
var tf2 = form.getTextField("COWarning2");
|
|
315
|
+
tf2.setText(warningMsg2);
|
|
316
|
+
tf2.setTextColor(warningColor);
|
|
317
|
+
} catch (e) {}
|
|
268
318
|
} else {
|
|
319
|
+
// clear warnings if not applicable
|
|
269
320
|
safeSetText(form, "COWarning", "");
|
|
270
321
|
safeSetText(form, "COWarning2", "");
|
|
271
322
|
}
|
|
@@ -511,16 +562,57 @@ export async function getReport(payload, _test) {
|
|
|
511
562
|
passFails.splice(3, 1);
|
|
512
563
|
pfLabels.splice(3, 1);
|
|
513
564
|
}
|
|
565
|
+
|
|
566
|
+
// CO threshold color helpers
|
|
567
|
+
function getCOIcon(coValue) {
|
|
568
|
+
if (coValue === null || coValue === undefined || isNaN(coValue)) {
|
|
569
|
+
return iconRangeGreen;
|
|
570
|
+
}
|
|
571
|
+
if (coValue <= 9) {
|
|
572
|
+
return iconRangeGreen;
|
|
573
|
+
} else if (coValue > 9 && coValue <= 35) {
|
|
574
|
+
return iconRangeYellow;
|
|
575
|
+
} else {
|
|
576
|
+
return iconRangeRed;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
function getCOTextColor(coValue) {
|
|
581
|
+
if (coValue === null || coValue === undefined || isNaN(coValue)) {
|
|
582
|
+
return rgb(0, 0, 0);
|
|
583
|
+
}
|
|
584
|
+
if (coValue <= 9) {
|
|
585
|
+
return rgb(0, 0, 0); // black - OK
|
|
586
|
+
} else if (coValue > 9 && coValue <= 35) {
|
|
587
|
+
return rgb(1, 0.6, 0); // orange - Elevated
|
|
588
|
+
} else {
|
|
589
|
+
return rgb(0.96, 0.26, 0.21); // red - Dangerous
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function getCOStatus(coValue) {
|
|
594
|
+
if (coValue === null || coValue === undefined || isNaN(coValue)) {
|
|
595
|
+
return "";
|
|
596
|
+
}
|
|
597
|
+
if (coValue <= 9) {
|
|
598
|
+
return "OK";
|
|
599
|
+
} else {
|
|
600
|
+
return "Elevated";
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Collect valid items first (no gaps)
|
|
605
|
+
let validItems = [];
|
|
606
|
+
|
|
514
607
|
for (let i = 0; i < passFails.length; i++) {
|
|
515
608
|
const meas = test.testInfo[passFails[i]];
|
|
516
609
|
|
|
517
|
-
//
|
|
610
|
+
// Skip items with no value
|
|
518
611
|
if (meas === undefined || meas === null || meas === "") {
|
|
519
|
-
safeSetText(form, `SSR${i + 1}`, "");
|
|
520
612
|
continue;
|
|
521
613
|
}
|
|
522
614
|
|
|
523
|
-
//
|
|
615
|
+
// Determine icon based on value
|
|
524
616
|
let icon;
|
|
525
617
|
if (meas === "Caution") {
|
|
526
618
|
icon = iconRangeYellow;
|
|
@@ -529,53 +621,85 @@ export async function getReport(payload, _test) {
|
|
|
529
621
|
} else {
|
|
530
622
|
icon = iconRangeRed;
|
|
531
623
|
}
|
|
532
|
-
if (passFails[i] === "heating_efficiency_pass_fail")
|
|
624
|
+
if (passFails[i] === "heating_efficiency_pass_fail") {
|
|
533
625
|
icon = iconRangeGreen;
|
|
534
|
-
|
|
535
|
-
// Set the icon as before
|
|
536
|
-
safeSetImage(form, `ImageSubsystem${i + 1}_af_image`, icon);
|
|
626
|
+
}
|
|
537
627
|
|
|
538
628
|
const suffix = test.testInfo[passFails[i] + "_override"] ? " *" : "";
|
|
539
|
-
const fieldName = `SSR${i + 1}`;
|
|
540
|
-
|
|
541
|
-
// Default label for non-special cases
|
|
542
629
|
let label = pfLabels[i] + suffix;
|
|
630
|
+
let textColor = rgb(0, 0, 0); // default black
|
|
543
631
|
|
|
544
|
-
// Special handling
|
|
632
|
+
// Special handling for Ambient CO - show actual values
|
|
545
633
|
if (passFails[i] === "ambient_pass_fail") {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
)
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
tf.setText(label);
|
|
566
|
-
tf.setTextColor(rgb(0, 0, 0)); // black
|
|
567
|
-
} catch (e) {}
|
|
568
|
-
continue;
|
|
634
|
+
// Calculate CO delta
|
|
635
|
+
const coDelta = (isFinite(coSupRaw) && isFinite(coRetRaw)) ? (coSupRaw - coRetRaw) : null;
|
|
636
|
+
const hasCODeltaWarning = test.testInfo.ambient_pass_fail_co_delta_warning || (coDelta !== null && coDelta >= 1);
|
|
637
|
+
|
|
638
|
+
// Add CO Ambient with value
|
|
639
|
+
if (isFinite(coAmbRaw)) {
|
|
640
|
+
const coAmbIcon = getCOIcon(coAmbRaw);
|
|
641
|
+
const coAmbColor = getCOTextColor(coAmbRaw);
|
|
642
|
+
const coAmbStatus = getCOStatus(coAmbRaw);
|
|
643
|
+
const coAmbLabel = "CO Ambient: " + Math.round(coAmbRaw) + " ppm (" + coAmbStatus + ")" + suffix;
|
|
644
|
+
validItems.push({ label: coAmbLabel, icon: coAmbIcon, textColor: coAmbColor });
|
|
645
|
+
} else if (meas) {
|
|
646
|
+
// No CO value but has pass/fail - show generic
|
|
647
|
+
const isFail = !(meas === "Pass" || meas === "High" || meas === "Mid" || meas === "Caution");
|
|
648
|
+
if (isFail) {
|
|
649
|
+
validItems.push({ label: "CO Ambient: Elevated" + suffix, icon: iconRangeYellow, textColor: rgb(1, 0.6, 0) });
|
|
650
|
+
} else {
|
|
651
|
+
validItems.push({ label: "CO Ambient: OK" + suffix, icon: iconRangeGreen, textColor: rgb(0, 0, 0) });
|
|
652
|
+
}
|
|
569
653
|
}
|
|
654
|
+
|
|
655
|
+
// Add CO Return with value (if available and not boiler)
|
|
656
|
+
if (isFinite(coRetRaw) && !payload.meta.boiler_type) {
|
|
657
|
+
const coRetIcon = getCOIcon(coRetRaw);
|
|
658
|
+
const coRetColor = getCOTextColor(coRetRaw);
|
|
659
|
+
const coRetStatus = getCOStatus(coRetRaw);
|
|
660
|
+
const coRetLabel = "CO Return: " + Math.round(coRetRaw) + " ppm (" + coRetStatus + ")";
|
|
661
|
+
validItems.push({ label: coRetLabel, icon: coRetIcon, textColor: coRetColor });
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Add CO Supply with value (if available and not boiler)
|
|
665
|
+
if (isFinite(coSupRaw) && !payload.meta.boiler_type) {
|
|
666
|
+
const coSupIcon = getCOIcon(coSupRaw);
|
|
667
|
+
const coSupColor = getCOTextColor(coSupRaw);
|
|
668
|
+
const coSupStatus = getCOStatus(coSupRaw);
|
|
669
|
+
const coSupLabel = "CO Supply: " + Math.round(coSupRaw) + " ppm (" + coSupStatus + ")";
|
|
670
|
+
validItems.push({ label: coSupLabel, icon: coSupIcon, textColor: coSupColor });
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Add CO Delta (if both return and supply available and not boiler)
|
|
674
|
+
if (coDelta !== null && !payload.meta.boiler_type) {
|
|
675
|
+
const deltaIcon = hasCODeltaWarning ? iconRangeRed : iconRangeGreen;
|
|
676
|
+
const deltaColor = hasCODeltaWarning ? rgb(0.96, 0.26, 0.21) : rgb(0, 0, 0);
|
|
677
|
+
const deltaStatus = hasCODeltaWarning ? "Investigate Heat Exchanger" : "OK";
|
|
678
|
+
const deltaLabel = "CO Delta: " + Math.round(coDelta) + " ppm (" + deltaStatus + ")";
|
|
679
|
+
validItems.push({ label: deltaLabel, icon: deltaIcon, textColor: deltaColor });
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
continue; // Skip adding the default ambient_pass_fail item
|
|
570
683
|
}
|
|
571
684
|
|
|
572
|
-
|
|
685
|
+
validItems.push({ label, icon, textColor });
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Fill fields sequentially with valid items (no gaps)
|
|
689
|
+
for (let i = 0; i < validItems.length; i++) {
|
|
690
|
+
const item = validItems[i];
|
|
691
|
+
safeSetImage(form, `ImageSubsystem${i + 1}_af_image`, item.icon);
|
|
573
692
|
try {
|
|
574
|
-
const tf = form.getTextField(
|
|
575
|
-
tf.setText(label);
|
|
576
|
-
tf.setTextColor(
|
|
693
|
+
const tf = form.getTextField(`SSR${i + 1}`);
|
|
694
|
+
tf.setText(item.label);
|
|
695
|
+
tf.setTextColor(item.textColor);
|
|
577
696
|
} catch (e) {}
|
|
578
697
|
}
|
|
698
|
+
|
|
699
|
+
// Clear any remaining unused fields
|
|
700
|
+
for (let i = validItems.length; i < passFails.length + 3; i++) {
|
|
701
|
+
safeSetText(form, `SSR${i + 1}`, "");
|
|
702
|
+
}
|
|
579
703
|
} else safeSetText(form, `SSR1`, "Not yet reviewed");
|
|
580
704
|
|
|
581
705
|
if (payload.meta.report_type != "FullReport") {
|
|
@@ -672,13 +672,23 @@ export async function getReport(payload, _test) {
|
|
|
672
672
|
// Use coAmbRaw which is already defined and validated earlier in the function
|
|
673
673
|
const coValue = isFinite(coAmbRaw) ? coAmbRaw : null;
|
|
674
674
|
|
|
675
|
+
// Check for CO delta warning (Supply - Return >= 1 ppm)
|
|
676
|
+
const coDelta = (isFinite(coSupRaw) && isFinite(coRetRaw)) ? (coSupRaw - coRetRaw) : null;
|
|
677
|
+
const hasCODeltaWarning = test.testInfo.ambient_pass_fail_co_delta_warning || (coDelta !== null && coDelta >= 1);
|
|
678
|
+
|
|
675
679
|
// Use CO-specific icon based on actual value
|
|
676
680
|
if (coValue !== null) {
|
|
677
681
|
icon = getCOIcon(coValue);
|
|
678
682
|
const stateText = getCOStateText(coValue);
|
|
679
683
|
|
|
680
|
-
// Format label based on CO level
|
|
681
|
-
if (
|
|
684
|
+
// Format label based on CO level and delta warning
|
|
685
|
+
if (hasCODeltaWarning) {
|
|
686
|
+
// CO delta detected - recommend heat exchanger investigation
|
|
687
|
+
icon = iconRangeRed;
|
|
688
|
+
textColor = rgb(0.96, 0.26, 0.21); // Red
|
|
689
|
+
const deltaValue = coDelta !== null ? Math.round(coDelta) : "";
|
|
690
|
+
label = "CO Delta " + deltaValue + " ppm: Investigate heat exchanger" + suffix;
|
|
691
|
+
} else if (coValue <= 8) {
|
|
682
692
|
// Normal - just show value
|
|
683
693
|
label = "Ambient CO: " + Math.round(coValue) + " ppm" + suffix;
|
|
684
694
|
} else {
|
|
@@ -686,15 +696,23 @@ export async function getReport(payload, _test) {
|
|
|
686
696
|
label = "CO Ambient " + stateText + " " + Math.round(coValue) + " ppm, Investigate!" + suffix;
|
|
687
697
|
}
|
|
688
698
|
|
|
689
|
-
// Set text color based on CO level
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
699
|
+
// Set text color based on CO level (if not already set by delta warning)
|
|
700
|
+
if (!hasCODeltaWarning) {
|
|
701
|
+
// Orange for Elevated, Red for Dangerous, Dark Red for Emergency
|
|
702
|
+
if (coValue >= 70) {
|
|
703
|
+
textColor = rgb(0.72, 0.11, 0.11); // Dark red for Emergency
|
|
704
|
+
} else if (coValue >= 36) {
|
|
705
|
+
textColor = rgb(0.96, 0.26, 0.21); // Red for Dangerous
|
|
706
|
+
} else if (coValue >= 9) {
|
|
707
|
+
textColor = rgb(1, 0.6, 0); // Orange for Elevated
|
|
708
|
+
}
|
|
697
709
|
}
|
|
710
|
+
} else if (hasCODeltaWarning) {
|
|
711
|
+
// No ambient CO value but delta warning detected
|
|
712
|
+
icon = iconRangeRed;
|
|
713
|
+
textColor = rgb(0.96, 0.26, 0.21); // Red
|
|
714
|
+
const deltaValue = coDelta !== null ? Math.round(coDelta) : "";
|
|
715
|
+
label = "CO Delta " + deltaValue + " ppm: Investigate heat exchanger" + suffix;
|
|
698
716
|
} else {
|
|
699
717
|
// No CO value, use pass/fail status
|
|
700
718
|
const isFail = !(meas === "Pass" || meas === "High" || meas === "Mid" || meas === "Caution");
|