myio-js-library 0.1.168 → 0.1.172

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/dist/index.cjs CHANGED
@@ -642,7 +642,7 @@ __export(index_exports, {
642
642
  formatNumberReadable: () => formatNumberReadable,
643
643
  formatRelativeTime: () => formatRelativeTime,
644
644
  formatTankHeadFromCm: () => formatTankHeadFromCm,
645
- formatTemperature: () => formatTemperature2,
645
+ formatTemperature: () => formatTemperature,
646
646
  formatWater: () => formatWater,
647
647
  formatWaterByGroup: () => formatWaterByGroup,
648
648
  formatWaterVolumeM3: () => formatWaterVolumeM3,
@@ -1459,7 +1459,8 @@ var DeviceStatusType = {
1459
1459
  FAILURE: "failure",
1460
1460
  MAINTENANCE: "maintenance",
1461
1461
  NO_INFO: "no_info",
1462
- NOT_INSTALLED: "not_installed"
1462
+ NOT_INSTALLED: "not_installed",
1463
+ OFFLINE: "offline"
1463
1464
  };
1464
1465
  var ConnectionStatusType = {
1465
1466
  CONNECTED: "connected",
@@ -1468,39 +1469,42 @@ var ConnectionStatusType = {
1468
1469
  var deviceStatusIcons = {
1469
1470
  [DeviceStatusType.POWER_ON]: "\u26A1",
1470
1471
  [DeviceStatusType.STANDBY]: "\u{1F50C}",
1471
- [DeviceStatusType.POWER_OFF]: "\u{1F534}",
1472
+ [DeviceStatusType.POWER_OFF]: "\u26AB",
1472
1473
  [DeviceStatusType.WARNING]: "\u26A0\uFE0F",
1473
1474
  [DeviceStatusType.FAILURE]: "\u{1F6A8}",
1474
1475
  [DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
1475
1476
  [DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
1476
- [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
1477
+ [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
1478
+ [DeviceStatusType.OFFLINE]: "\u{1F534}"
1477
1479
  };
1478
1480
  var waterDeviceStatusIcons = {
1479
1481
  [DeviceStatusType.POWER_ON]: "\u{1F4A7}",
1480
1482
  [DeviceStatusType.STANDBY]: "\u{1F6B0}",
1481
- [DeviceStatusType.POWER_OFF]: "\u{1F534}",
1483
+ [DeviceStatusType.POWER_OFF]: "\u26AB",
1482
1484
  [DeviceStatusType.WARNING]: "\u26A0\uFE0F",
1483
1485
  [DeviceStatusType.FAILURE]: "\u{1F6A8}",
1484
1486
  [DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
1485
1487
  [DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
1486
- [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
1488
+ [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
1489
+ [DeviceStatusType.OFFLINE]: "\u{1F534}"
1487
1490
  };
1488
1491
  var temperatureDeviceStatusIcons = {
1489
1492
  [DeviceStatusType.POWER_ON]: "\u{1F321}\uFE0F",
1490
1493
  [DeviceStatusType.STANDBY]: "\u{1F321}\uFE0F",
1491
- [DeviceStatusType.POWER_OFF]: "\u{1F534}",
1494
+ [DeviceStatusType.POWER_OFF]: "\u26AB",
1492
1495
  [DeviceStatusType.WARNING]: "\u26A0\uFE0F",
1493
1496
  [DeviceStatusType.FAILURE]: "\u{1F6A8}",
1494
1497
  [DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
1495
1498
  [DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
1496
- [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
1499
+ [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
1500
+ [DeviceStatusType.OFFLINE]: "\u{1F534}"
1497
1501
  };
1498
1502
  var connectionStatusIcons = {
1499
1503
  [ConnectionStatusType.CONNECTED]: "\u{1F7E2}",
1500
1504
  [ConnectionStatusType.OFFLINE]: "\u{1F6AB}"
1501
1505
  };
1502
1506
  function mapDeviceToConnectionStatus(deviceStatus) {
1503
- if (deviceStatus === DeviceStatusType.NO_INFO) {
1507
+ if (deviceStatus === DeviceStatusType.NO_INFO || deviceStatus === DeviceStatusType.OFFLINE) {
1504
1508
  return ConnectionStatusType.OFFLINE;
1505
1509
  }
1506
1510
  return ConnectionStatusType.CONNECTED;
@@ -1524,15 +1528,16 @@ function mapDeviceStatusToCardStatus(deviceStatus) {
1524
1528
  [DeviceStatusType.FAILURE]: "fail",
1525
1529
  [DeviceStatusType.MAINTENANCE]: "alert",
1526
1530
  [DeviceStatusType.NO_INFO]: "unknown",
1527
- [DeviceStatusType.NOT_INSTALLED]: "not_installed"
1531
+ [DeviceStatusType.NOT_INSTALLED]: "not_installed",
1532
+ [DeviceStatusType.OFFLINE]: "offline"
1528
1533
  };
1529
1534
  return statusMap[deviceStatus] || "unknown";
1530
1535
  }
1531
1536
  function shouldFlashIcon(deviceStatus) {
1532
- return deviceStatus === DeviceStatusType.POWER_OFF || deviceStatus === DeviceStatusType.WARNING || deviceStatus === DeviceStatusType.FAILURE || deviceStatus === DeviceStatusType.MAINTENANCE;
1537
+ return deviceStatus === DeviceStatusType.POWER_OFF || deviceStatus === DeviceStatusType.WARNING || deviceStatus === DeviceStatusType.FAILURE || deviceStatus === DeviceStatusType.MAINTENANCE || deviceStatus === DeviceStatusType.OFFLINE;
1533
1538
  }
1534
1539
  function isDeviceOffline(deviceStatus) {
1535
- return deviceStatus === DeviceStatusType.NO_INFO;
1540
+ return deviceStatus === DeviceStatusType.NO_INFO || deviceStatus === DeviceStatusType.OFFLINE;
1536
1541
  }
1537
1542
  function getDeviceStatusIcon(deviceStatus, deviceType = null) {
1538
1543
  const normalizedType = deviceType?.toUpperCase() || "";
@@ -4088,15 +4093,30 @@ var CSS_STRING = `
4088
4093
  --myio-chip-alert-fg: #b45309;
4089
4094
  --myio-border-alert: rgba(245, 158, 11, 0.5);
4090
4095
 
4091
- /* Status colors - Failure (red) */
4096
+ /* Status colors - Failure (dark red) */
4092
4097
  --myio-chip-failure-bg: #fee2e2;
4093
4098
  --myio-chip-failure-fg: #b91c1c;
4094
- --myio-border-failure: rgba(239, 68, 68, 0.5);
4099
+ --myio-border-failure: rgba(153, 27, 27, 0.6);
4100
+
4101
+ /* Status colors - Power Off (light red) */
4102
+ --myio-chip-power-off-bg: #fecaca;
4103
+ --myio-chip-power-off-fg: #dc2626;
4104
+ --myio-border-power-off: rgba(239, 68, 68, 0.5);
4105
+
4106
+ /* Status colors - Offline (dark gray) */
4107
+ --myio-chip-offline-bg: #e2e8f0;
4108
+ --myio-chip-offline-fg: #475569;
4109
+ --myio-border-offline: rgba(71, 85, 105, 0.6);
4110
+
4111
+ /* Status colors - No Info (dark orange) */
4112
+ --myio-chip-no-info-bg: #fed7aa;
4113
+ --myio-chip-no-info-fg: #c2410c;
4114
+ --myio-border-no-info: rgba(194, 65, 12, 0.5);
4095
4115
 
4096
- /* Status colors - Offline (gray) */
4097
- --myio-chip-offline-bg: #f1f5f9;
4098
- --myio-chip-offline-fg: #64748b;
4099
- --myio-border-offline: rgba(100, 116, 139, 0.4);
4116
+ /* Status colors - Not Installed (purple) */
4117
+ --myio-chip-not-installed-bg: #e9d5ff;
4118
+ --myio-chip-not-installed-fg: #7c3aed;
4119
+ --myio-border-not-installed: rgba(124, 58, 237, 0.5);
4100
4120
 
4101
4121
  --myio-text-1: #0f172a;
4102
4122
  --myio-text-2: #4b5563;
@@ -4152,26 +4172,55 @@ var CSS_STRING = `
4152
4172
  }
4153
4173
 
4154
4174
  /* Card border states based on device status */
4155
- .myio-ho-card.is-ok {
4175
+
4176
+ /* POWER_ON - Blue */
4177
+ .myio-ho-card.is-power-on {
4156
4178
  border-color: var(--myio-border-ok);
4157
4179
  box-shadow: 0 0 0 2px var(--myio-border-ok), var(--myio-card-shadow);
4158
4180
  }
4159
4181
 
4182
+ /* STANDBY - Green */
4160
4183
  .myio-ho-card.is-standby {
4161
4184
  border-color: var(--myio-border-standby);
4162
4185
  box-shadow: 0 0 0 2px var(--myio-border-standby), var(--myio-card-shadow);
4163
4186
  }
4164
4187
 
4165
- .myio-ho-card.is-alert {
4188
+ /* WARNING - Yellow */
4189
+ .myio-ho-card.is-warning {
4190
+ border-color: var(--myio-border-alert);
4191
+ box-shadow: 0 0 0 2px var(--myio-border-alert), var(--myio-card-shadow);
4192
+ }
4193
+
4194
+ /* MAINTENANCE - Yellow */
4195
+ .myio-ho-card.is-maintenance {
4166
4196
  border-color: var(--myio-border-alert);
4167
4197
  box-shadow: 0 0 0 2px var(--myio-border-alert), var(--myio-card-shadow);
4168
4198
  }
4169
4199
 
4200
+ /* FAILURE - Dark Red */
4170
4201
  .myio-ho-card.is-failure {
4171
4202
  border-color: var(--myio-border-failure);
4172
4203
  box-shadow: 0 0 0 2px var(--myio-border-failure), var(--myio-card-shadow);
4173
4204
  }
4174
4205
 
4206
+ /* POWER_OFF - Light Red */
4207
+ .myio-ho-card.is-power-off {
4208
+ border-color: var(--myio-border-power-off);
4209
+ box-shadow: 0 0 0 2px var(--myio-border-power-off), var(--myio-card-shadow);
4210
+ }
4211
+
4212
+ /* NO_INFO - Dark Orange */
4213
+ .myio-ho-card.is-no-info {
4214
+ border-color: var(--myio-border-no-info);
4215
+ box-shadow: 0 0 0 2px var(--myio-border-no-info), var(--myio-card-shadow);
4216
+ }
4217
+
4218
+ /* NOT_INSTALLED - Purple */
4219
+ .myio-ho-card.is-not-installed {
4220
+ border-color: var(--myio-border-not-installed);
4221
+ box-shadow: 0 0 0 2px var(--myio-border-not-installed), var(--myio-card-shadow);
4222
+ }
4223
+
4175
4224
  /* Header section */
4176
4225
  .myio-ho-card__header {
4177
4226
  display: flex;
@@ -4189,7 +4238,9 @@ var CSS_STRING = `
4189
4238
  margin-top: 2px;
4190
4239
  }
4191
4240
 
4192
- .myio-ho-card.is-alert .myio-ho-card__icon {
4241
+ /* Icon colors based on status */
4242
+ .myio-ho-card.is-warning .myio-ho-card__icon,
4243
+ .myio-ho-card.is-maintenance .myio-ho-card__icon {
4193
4244
  color: var(--myio-chip-alert-fg);
4194
4245
  }
4195
4246
 
@@ -4197,14 +4248,28 @@ var CSS_STRING = `
4197
4248
  color: var(--myio-chip-failure-fg);
4198
4249
  }
4199
4250
 
4251
+ .myio-ho-card.is-power-off .myio-ho-card__icon {
4252
+ color: var(--myio-chip-power-off-fg);
4253
+ }
4254
+
4255
+ .myio-ho-card.is-offline .myio-ho-card__icon {
4256
+ color: var(--myio-chip-offline-fg);
4257
+ }
4258
+
4259
+ .myio-ho-card.is-no-info .myio-ho-card__icon {
4260
+ color: var(--myio-chip-no-info-fg);
4261
+ }
4262
+
4263
+ .myio-ho-card.is-not-installed .myio-ho-card__icon {
4264
+ color: var(--myio-chip-not-installed-fg);
4265
+ }
4266
+
4200
4267
  .myio-ho-card__title {
4201
4268
  flex: 1;
4202
4269
  min-width: 0;
4203
4270
  }
4204
4271
 
4205
- /* Adicione estas duas novas regras ao seu CSS_STRING */
4206
-
4207
- /* Estado Offline - borda cinza */
4272
+ /* OFFLINE - Dark Gray */
4208
4273
  .myio-ho-card.is-offline {
4209
4274
  border-color: var(--myio-border-offline);
4210
4275
  box-shadow: 0 0 0 2px var(--myio-border-offline), var(--myio-card-shadow);
@@ -4599,6 +4664,37 @@ var CSS_STRING = `
4599
4664
  color: var(--myio-chip-offline-fg);
4600
4665
  }
4601
4666
 
4667
+ /* New chip classes aligned with getCardStateClass */
4668
+ .chip--power-on {
4669
+ background: var(--myio-chip-ok-bg);
4670
+ color: var(--myio-chip-ok-fg);
4671
+ }
4672
+
4673
+ .chip--warning {
4674
+ background: var(--myio-chip-alert-bg);
4675
+ color: var(--myio-chip-alert-fg);
4676
+ }
4677
+
4678
+ .chip--maintenance {
4679
+ background: var(--myio-chip-alert-bg);
4680
+ color: var(--myio-chip-alert-fg);
4681
+ }
4682
+
4683
+ .chip--power-off {
4684
+ background: var(--myio-chip-power-off-bg);
4685
+ color: var(--myio-chip-power-off-fg);
4686
+ }
4687
+
4688
+ .chip--no-info {
4689
+ background: var(--myio-chip-no-info-bg);
4690
+ color: var(--myio-chip-no-info-fg);
4691
+ }
4692
+
4693
+ .chip--not-installed {
4694
+ background: var(--myio-chip-not-installed-bg);
4695
+ color: var(--myio-chip-not-installed-fg);
4696
+ }
4697
+
4602
4698
  /* Status indicator dot for power metric */
4603
4699
  .status-dot {
4604
4700
  width: 8px;
@@ -4632,6 +4728,31 @@ var CSS_STRING = `
4632
4728
  background: var(--myio-muted);
4633
4729
  }
4634
4730
 
4731
+ /* New dot classes aligned with getCardStateClass */
4732
+ .status-dot.dot--power-on {
4733
+ background: var(--myio-chip-ok-fg);
4734
+ }
4735
+
4736
+ .status-dot.dot--warning {
4737
+ background: var(--myio-chip-alert-fg);
4738
+ }
4739
+
4740
+ .status-dot.dot--maintenance {
4741
+ background: var(--myio-chip-alert-fg);
4742
+ }
4743
+
4744
+ .status-dot.dot--power-off {
4745
+ background: var(--myio-chip-power-off-fg);
4746
+ }
4747
+
4748
+ .status-dot.dot--no-info {
4749
+ background: var(--myio-chip-no-info-fg);
4750
+ }
4751
+
4752
+ .status-dot.dot--not-installed {
4753
+ background: var(--myio-chip-not-installed-fg);
4754
+ }
4755
+
4635
4756
  /* Primary metric */
4636
4757
  .myio-ho-card__primary {
4637
4758
  margin-bottom: 14px;
@@ -4814,6 +4935,215 @@ var CSS_STRING = `
4814
4935
  transition: none;
4815
4936
  }
4816
4937
  }
4938
+
4939
+ /* ============================================
4940
+ DEBUG TOOLTIP STYLES (Premium)
4941
+ ============================================ */
4942
+
4943
+ .has-debug-tooltip {
4944
+ cursor: help !important;
4945
+ }
4946
+
4947
+ .has-debug-tooltip::after {
4948
+ content: '\u{1F41B}';
4949
+ position: absolute;
4950
+ top: -4px;
4951
+ right: -4px;
4952
+ font-size: 10px;
4953
+ z-index: 1;
4954
+ }
4955
+
4956
+ .debug-tooltip-container {
4957
+ position: absolute;
4958
+ bottom: calc(100% + 8px);
4959
+ left: 50%;
4960
+ transform: translateX(-50%);
4961
+ z-index: 10000;
4962
+ pointer-events: none;
4963
+ opacity: 0;
4964
+ transition: opacity 0.2s ease, transform 0.2s ease;
4965
+ }
4966
+
4967
+ .has-debug-tooltip:hover .debug-tooltip-container {
4968
+ opacity: 1;
4969
+ pointer-events: auto;
4970
+ }
4971
+
4972
+ .debug-tooltip {
4973
+ background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
4974
+ border: 1px solid rgba(99, 102, 241, 0.3);
4975
+ border-radius: 12px;
4976
+ box-shadow:
4977
+ 0 20px 40px rgba(0, 0, 0, 0.4),
4978
+ 0 0 0 1px rgba(255, 255, 255, 0.05),
4979
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
4980
+ min-width: 340px;
4981
+ max-width: 420px;
4982
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
4983
+ font-size: 12px;
4984
+ color: #e2e8f0;
4985
+ overflow: hidden;
4986
+ }
4987
+
4988
+ .debug-tooltip__header {
4989
+ display: flex;
4990
+ align-items: center;
4991
+ gap: 8px;
4992
+ padding: 12px 16px;
4993
+ background: linear-gradient(90deg, rgba(99, 102, 241, 0.2) 0%, rgba(139, 92, 246, 0.1) 100%);
4994
+ border-bottom: 1px solid rgba(99, 102, 241, 0.2);
4995
+ }
4996
+
4997
+ .debug-tooltip__icon {
4998
+ font-size: 16px;
4999
+ }
5000
+
5001
+ .debug-tooltip__title {
5002
+ font-weight: 700;
5003
+ font-size: 13px;
5004
+ color: #f1f5f9;
5005
+ letter-spacing: 0.5px;
5006
+ text-transform: uppercase;
5007
+ }
5008
+
5009
+ .debug-tooltip__content {
5010
+ padding: 12px 16px;
5011
+ max-height: 400px;
5012
+ overflow-y: auto;
5013
+ }
5014
+
5015
+ .debug-tooltip__section {
5016
+ margin-bottom: 14px;
5017
+ padding-bottom: 12px;
5018
+ border-bottom: 1px solid rgba(148, 163, 184, 0.1);
5019
+ }
5020
+
5021
+ .debug-tooltip__section:last-child {
5022
+ margin-bottom: 0;
5023
+ padding-bottom: 0;
5024
+ border-bottom: none;
5025
+ }
5026
+
5027
+ .debug-tooltip__section-title {
5028
+ font-size: 11px;
5029
+ font-weight: 600;
5030
+ color: #94a3b8;
5031
+ text-transform: uppercase;
5032
+ letter-spacing: 0.8px;
5033
+ margin-bottom: 10px;
5034
+ display: flex;
5035
+ align-items: center;
5036
+ gap: 6px;
5037
+ }
5038
+
5039
+ .debug-tooltip__row {
5040
+ display: flex;
5041
+ justify-content: space-between;
5042
+ align-items: flex-start;
5043
+ padding: 4px 0;
5044
+ gap: 12px;
5045
+ }
5046
+
5047
+ .debug-tooltip__row--full {
5048
+ flex-direction: column;
5049
+ gap: 4px;
5050
+ }
5051
+
5052
+ .debug-tooltip__label {
5053
+ color: #94a3b8;
5054
+ font-size: 11px;
5055
+ flex-shrink: 0;
5056
+ }
5057
+
5058
+ .debug-tooltip__value {
5059
+ color: #f1f5f9;
5060
+ font-weight: 500;
5061
+ text-align: right;
5062
+ word-break: break-all;
5063
+ }
5064
+
5065
+ .debug-tooltip__row--full .debug-tooltip__value {
5066
+ text-align: left;
5067
+ background: rgba(0, 0, 0, 0.3);
5068
+ padding: 6px 10px;
5069
+ border-radius: 6px;
5070
+ font-size: 11px;
5071
+ width: 100%;
5072
+ box-sizing: border-box;
5073
+ }
5074
+
5075
+ .debug-tooltip__value--mono {
5076
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
5077
+ font-size: 11px;
5078
+ background: rgba(0, 0, 0, 0.3);
5079
+ padding: 2px 6px;
5080
+ border-radius: 4px;
5081
+ }
5082
+
5083
+ .debug-tooltip__value--highlight {
5084
+ color: #a5b4fc;
5085
+ font-style: italic;
5086
+ }
5087
+
5088
+ .debug-tooltip__badge {
5089
+ display: inline-block;
5090
+ padding: 2px 8px;
5091
+ border-radius: 4px;
5092
+ font-size: 10px;
5093
+ font-weight: 600;
5094
+ text-transform: uppercase;
5095
+ letter-spacing: 0.5px;
5096
+ background: rgba(99, 102, 241, 0.3);
5097
+ color: #a5b4fc;
5098
+ }
5099
+
5100
+ .debug-tooltip__badge--energy {
5101
+ background: rgba(59, 130, 246, 0.3);
5102
+ color: #93c5fd;
5103
+ }
5104
+
5105
+ .debug-tooltip__badge--water {
5106
+ background: rgba(6, 182, 212, 0.3);
5107
+ color: #67e8f9;
5108
+ }
5109
+
5110
+ .debug-tooltip__badge--temperature {
5111
+ background: rgba(249, 115, 22, 0.3);
5112
+ color: #fdba74;
5113
+ }
5114
+
5115
+ /* Tooltip arrow */
5116
+ .debug-tooltip::after {
5117
+ content: '';
5118
+ position: absolute;
5119
+ bottom: -6px;
5120
+ left: 50%;
5121
+ transform: translateX(-50%) rotate(45deg);
5122
+ width: 12px;
5123
+ height: 12px;
5124
+ background: #0f172a;
5125
+ border-right: 1px solid rgba(99, 102, 241, 0.3);
5126
+ border-bottom: 1px solid rgba(99, 102, 241, 0.3);
5127
+ }
5128
+
5129
+ /* Scrollbar styling for tooltip content */
5130
+ .debug-tooltip__content::-webkit-scrollbar {
5131
+ width: 6px;
5132
+ }
5133
+
5134
+ .debug-tooltip__content::-webkit-scrollbar-track {
5135
+ background: rgba(0, 0, 0, 0.2);
5136
+ border-radius: 3px;
5137
+ }
5138
+
5139
+ .debug-tooltip__content::-webkit-scrollbar-thumb {
5140
+ background: rgba(99, 102, 241, 0.4);
5141
+ border-radius: 3px;
5142
+ }
5143
+
5144
+ .debug-tooltip__content::-webkit-scrollbar-thumb:hover {
5145
+ background: rgba(99, 102, 241, 0.6);
5146
+ }
4817
5147
  `;
4818
5148
 
4819
5149
  // src/thingsboard/main-dashboard-shopping/v-4.0.0/head-office/card-head-office.icons.ts
@@ -4968,7 +5298,246 @@ var DEFAULT_I18N = {
4968
5298
  menu_settings: "Configura\xE7\xF5es"
4969
5299
  };
4970
5300
 
5301
+ // src/components/temperature/utils.ts
5302
+ var DAY_PERIODS = [
5303
+ { id: "madrugada", label: "Madrugada (00h-06h)", startHour: 0, endHour: 6 },
5304
+ { id: "manha", label: "Manh\xE3 (06h-12h)", startHour: 6, endHour: 12 },
5305
+ { id: "tarde", label: "Tarde (12h-18h)", startHour: 12, endHour: 18 },
5306
+ { id: "noite", label: "Noite (18h-24h)", startHour: 18, endHour: 24 }
5307
+ ];
5308
+ var DEFAULT_CLAMP_RANGE = { min: 15, max: 40 };
5309
+ function getTodaySoFar() {
5310
+ const now = /* @__PURE__ */ new Date();
5311
+ const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
5312
+ return {
5313
+ startTs: startOfDay.getTime(),
5314
+ endTs: now.getTime()
5315
+ };
5316
+ }
5317
+ var CHART_COLORS = [
5318
+ "#1976d2",
5319
+ // Blue
5320
+ "#FF6B6B",
5321
+ // Red
5322
+ "#4CAF50",
5323
+ // Green
5324
+ "#FF9800",
5325
+ // Orange
5326
+ "#9C27B0",
5327
+ // Purple
5328
+ "#00BCD4",
5329
+ // Cyan
5330
+ "#E91E63",
5331
+ // Pink
5332
+ "#795548"
5333
+ // Brown
5334
+ ];
5335
+ async function fetchTemperatureData(token, deviceId, startTs, endTs) {
5336
+ const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=temperature&startTs=${encodeURIComponent(startTs)}&endTs=${encodeURIComponent(endTs)}&limit=50000&agg=NONE`;
5337
+ const response = await fetch(url, {
5338
+ headers: {
5339
+ "X-Authorization": `Bearer ${token}`,
5340
+ "Content-Type": "application/json"
5341
+ }
5342
+ });
5343
+ if (!response.ok) {
5344
+ throw new Error(`Failed to fetch temperature data: ${response.status}`);
5345
+ }
5346
+ const data = await response.json();
5347
+ return data?.temperature || [];
5348
+ }
5349
+ function clampTemperature(value, range = DEFAULT_CLAMP_RANGE) {
5350
+ const num = Number(value || 0);
5351
+ if (num < range.min) return range.min;
5352
+ if (num > range.max) return range.max;
5353
+ return num;
5354
+ }
5355
+ function calculateStats(data, clampRange = DEFAULT_CLAMP_RANGE) {
5356
+ if (data.length === 0) {
5357
+ return { avg: 0, min: 0, max: 0, count: 0 };
5358
+ }
5359
+ const values = data.map((item) => clampTemperature(item.value, clampRange));
5360
+ const sum = values.reduce((acc, v) => acc + v, 0);
5361
+ return {
5362
+ avg: sum / values.length,
5363
+ min: Math.min(...values),
5364
+ max: Math.max(...values),
5365
+ count: values.length
5366
+ };
5367
+ }
5368
+ function interpolateTemperature(data, options) {
5369
+ const { intervalMinutes, startTs, endTs, clampRange = DEFAULT_CLAMP_RANGE } = options;
5370
+ const intervalMs = intervalMinutes * 60 * 1e3;
5371
+ if (data.length === 0) {
5372
+ return [];
5373
+ }
5374
+ const sortedData = [...data].sort((a, b) => a.ts - b.ts);
5375
+ const result = [];
5376
+ let lastKnownValue = clampTemperature(sortedData[0].value, clampRange);
5377
+ let dataIndex = 0;
5378
+ for (let ts = startTs; ts <= endTs; ts += intervalMs) {
5379
+ while (dataIndex < sortedData.length - 1 && sortedData[dataIndex + 1].ts <= ts) {
5380
+ dataIndex++;
5381
+ }
5382
+ const currentData = sortedData[dataIndex];
5383
+ if (currentData && Math.abs(currentData.ts - ts) < intervalMs) {
5384
+ lastKnownValue = clampTemperature(currentData.value, clampRange);
5385
+ }
5386
+ result.push({
5387
+ ts,
5388
+ value: lastKnownValue
5389
+ });
5390
+ }
5391
+ return result;
5392
+ }
5393
+ function aggregateByDay(data, clampRange = DEFAULT_CLAMP_RANGE) {
5394
+ if (data.length === 0) {
5395
+ return [];
5396
+ }
5397
+ const dayMap = /* @__PURE__ */ new Map();
5398
+ data.forEach((item) => {
5399
+ const date = new Date(item.ts);
5400
+ const dateKey = date.toISOString().split("T")[0];
5401
+ if (!dayMap.has(dateKey)) {
5402
+ dayMap.set(dateKey, []);
5403
+ }
5404
+ dayMap.get(dateKey).push(item);
5405
+ });
5406
+ const result = [];
5407
+ dayMap.forEach((dayData, dateKey) => {
5408
+ const values = dayData.map((item) => clampTemperature(item.value, clampRange));
5409
+ const sum = values.reduce((acc, v) => acc + v, 0);
5410
+ result.push({
5411
+ date: dateKey,
5412
+ dateTs: new Date(dateKey).getTime(),
5413
+ avg: sum / values.length,
5414
+ min: Math.min(...values),
5415
+ max: Math.max(...values),
5416
+ count: values.length
5417
+ });
5418
+ });
5419
+ return result.sort((a, b) => a.dateTs - b.dateTs);
5420
+ }
5421
+ function filterByDayPeriods(data, selectedPeriods) {
5422
+ if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
5423
+ return data;
5424
+ }
5425
+ return data.filter((item) => {
5426
+ const date = new Date(item.ts);
5427
+ const hour = date.getHours();
5428
+ return selectedPeriods.some((periodId) => {
5429
+ const period = DAY_PERIODS.find((p) => p.id === periodId);
5430
+ if (!period) return false;
5431
+ return hour >= period.startHour && hour < period.endHour;
5432
+ });
5433
+ });
5434
+ }
5435
+ function getSelectedPeriodsLabel(selectedPeriods) {
5436
+ if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
5437
+ return "Todos os per\xEDodos";
5438
+ }
5439
+ if (selectedPeriods.length === 1) {
5440
+ const period = DAY_PERIODS.find((p) => p.id === selectedPeriods[0]);
5441
+ return period?.label || "";
5442
+ }
5443
+ return `${selectedPeriods.length} per\xEDodos selecionados`;
5444
+ }
5445
+ function formatTemperature(value, decimals = 1) {
5446
+ if (value === null || value === void 0 || isNaN(value)) {
5447
+ return "\u2014";
5448
+ }
5449
+ return `${value.toFixed(decimals)}\xB0C`;
5450
+ }
5451
+ function exportTemperatureCSV(data, deviceLabel, stats, startDate, endDate) {
5452
+ if (data.length === 0) {
5453
+ console.warn("No data to export");
5454
+ return;
5455
+ }
5456
+ const BOM = "\uFEFF";
5457
+ let csvContent = BOM;
5458
+ csvContent += `Relat\xF3rio de Temperatura - ${deviceLabel}
5459
+ `;
5460
+ csvContent += `Per\xEDodo: ${startDate} at\xE9 ${endDate}
5461
+ `;
5462
+ csvContent += `M\xE9dia: ${formatTemperature(stats.avg)}
5463
+ `;
5464
+ csvContent += `M\xEDnima: ${formatTemperature(stats.min)}
5465
+ `;
5466
+ csvContent += `M\xE1xima: ${formatTemperature(stats.max)}
5467
+ `;
5468
+ csvContent += `Total de leituras: ${stats.count}
5469
+ `;
5470
+ csvContent += "\n";
5471
+ csvContent += "Data/Hora,Temperatura (\xB0C)\n";
5472
+ data.forEach((item) => {
5473
+ const date = new Date(item.ts).toLocaleString("pt-BR");
5474
+ const temp = Number(item.value).toFixed(2);
5475
+ csvContent += `"${date}",${temp}
5476
+ `;
5477
+ });
5478
+ const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
5479
+ const url = URL.createObjectURL(blob);
5480
+ const link = document.createElement("a");
5481
+ link.href = url;
5482
+ link.download = `temperatura_${deviceLabel.replace(/\s+/g, "_")}_${startDate}_${endDate}.csv`;
5483
+ document.body.appendChild(link);
5484
+ link.click();
5485
+ document.body.removeChild(link);
5486
+ URL.revokeObjectURL(url);
5487
+ }
5488
+ var DARK_THEME = {
5489
+ background: "rgba(0, 0, 0, 0.85)",
5490
+ surface: "#1a1f28",
5491
+ text: "#ffffff",
5492
+ textMuted: "rgba(255, 255, 255, 0.7)",
5493
+ border: "rgba(255, 255, 255, 0.1)",
5494
+ primary: "#1976d2",
5495
+ success: "#4CAF50",
5496
+ warning: "#FF9800",
5497
+ danger: "#f44336",
5498
+ chartLine: "#1976d2",
5499
+ chartGrid: "rgba(255, 255, 255, 0.1)"
5500
+ };
5501
+ var LIGHT_THEME = {
5502
+ background: "rgba(0, 0, 0, 0.6)",
5503
+ surface: "#ffffff",
5504
+ text: "#333333",
5505
+ textMuted: "#666666",
5506
+ border: "#e0e0e0",
5507
+ primary: "#1976d2",
5508
+ success: "#4CAF50",
5509
+ warning: "#FF9800",
5510
+ danger: "#f44336",
5511
+ chartLine: "#1976d2",
5512
+ chartGrid: "#e0e0e0"
5513
+ };
5514
+ function getThemeColors(theme) {
5515
+ return theme === "dark" ? DARK_THEME : LIGHT_THEME;
5516
+ }
5517
+
5518
+ // src/utils/logHelper.js
5519
+ function createLogHelper(debugActive = false) {
5520
+ return {
5521
+ log: function(...args) {
5522
+ if (debugActive) {
5523
+ console.log(...args);
5524
+ }
5525
+ },
5526
+ warn: function(...args) {
5527
+ if (debugActive) {
5528
+ console.warn(...args);
5529
+ }
5530
+ },
5531
+ error: function(...args) {
5532
+ console.error(...args);
5533
+ }
5534
+ };
5535
+ }
5536
+ var LogHelper = createLogHelper(false);
5537
+
4971
5538
  // src/thingsboard/main-dashboard-shopping/v-4.0.0/card/head-office/card-head-office.js
5539
+ var LABEL_CHAR_LIMIT = 18;
5540
+ var DEFAUL_DELAY_TIME_CONNECTION_IN_MINS = 1440;
4972
5541
  var CSS_TAG = "head-office-card-v1";
4973
5542
  function ensureCss() {
4974
5543
  if (!document.querySelector(`style[data-myio-css="${CSS_TAG}"]`)) {
@@ -4982,11 +5551,17 @@ function normalizeParams(params) {
4982
5551
  if (!params || !params.entityObject) {
4983
5552
  throw new Error("renderCardCompenteHeadOffice: entityObject is required");
4984
5553
  }
5554
+ const LogHelper2 = createLogHelper(params.debugActive ?? false);
4985
5555
  const entityObject = params.entityObject;
4986
5556
  if (!entityObject.entityId) {
4987
- console.warn("renderCardCompenteHeadOffice: entityId is missing, generating temporary ID");
5557
+ LogHelper2.warn("[CardHeadOffice] entityId is missing, generating temporary ID");
4988
5558
  entityObject.entityId = `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
4989
5559
  }
5560
+ if (!params.delayTimeConnectionInMins) {
5561
+ LogHelper2.warn(
5562
+ `[CardHeadOffice] delayTimeConnectionInMins is missing, defaulting to ${DEFAUL_DELAY_TIME_CONNECTION_IN_MINS} mins`
5563
+ );
5564
+ }
4990
5565
  return {
4991
5566
  entityObject,
4992
5567
  i18n: { ...DEFAULT_I18N, ...params.i18n || {} },
@@ -4994,7 +5569,12 @@ function normalizeParams(params) {
4994
5569
  enableDragDrop: Boolean(params.enableDragDrop),
4995
5570
  useNewComponents: Boolean(params.useNewComponents),
4996
5571
  // RFC-0091: Configurable delay time for connection status check (default 15 minutes)
4997
- delayTimeConnectionInMins: params.delayTimeConnectionInMins ?? 15,
5572
+ delayTimeConnectionInMins: params.delayTimeConnectionInMins ?? DEFAUL_DELAY_TIME_CONNECTION_IN_MINS,
5573
+ // Debug options
5574
+ debugActive: params.debugActive ?? false,
5575
+ activeTooltipDebug: params.activeTooltipDebug ?? false,
5576
+ // LogHelper instance for this card
5577
+ LogHelper: LogHelper2,
4998
5578
  callbacks: {
4999
5579
  handleActionDashboard: params.handleActionDashboard,
5000
5580
  handleActionReport: params.handleActionReport,
@@ -5032,16 +5612,10 @@ function formatValueByDomain(value, domain) {
5032
5612
  return formatWaterVolumeM3(value);
5033
5613
  }
5034
5614
  if (domain === "temperature") {
5035
- return formatTemperature(value);
5615
+ return formatTemperature(value, 0);
5036
5616
  }
5037
5617
  return formatEnergy(value);
5038
5618
  }
5039
- function formatTemperature(temp) {
5040
- if (temp === null || temp === void 0 || isNaN(temp)) {
5041
- return "\u2014";
5042
- }
5043
- return `${temp.toFixed(0)}\xB0C`;
5044
- }
5045
5619
  function calculateConsumptionPercentage(target, consumption) {
5046
5620
  const numericTarget = Number(target);
5047
5621
  const numericConsumption = Number(consumption);
@@ -5056,32 +5630,32 @@ function getStatusInfo(deviceStatus, i18n, domain) {
5056
5630
  // --- Novos Status de Temperatura ---
5057
5631
  case "normal":
5058
5632
  return { chipClass: "chip--ok", label: "Normal" };
5059
- // Verde/Azul
5060
5633
  case "cold":
5061
5634
  return { chipClass: "chip--standby", label: "Frio" };
5062
- // Azul claro/Ciano
5063
5635
  case "hot":
5064
5636
  return { chipClass: "chip--alert", label: "Quente" };
5065
- // Laranja/Amarelo
5066
- // --- Status Existentes ---
5637
+ // --- Status Existentes (aligned with getCardStateClass) ---
5067
5638
  case DeviceStatusType.POWER_ON:
5068
5639
  if (domain === "water") {
5069
- return { chipClass: "chip--ok", label: i18n.in_operation_water };
5640
+ return { chipClass: "chip--power-on", label: i18n.in_operation_water };
5070
5641
  }
5071
- return { chipClass: "chip--ok", label: i18n.in_operation };
5642
+ return { chipClass: "chip--power-on", label: i18n.in_operation };
5072
5643
  case DeviceStatusType.STANDBY:
5073
5644
  return { chipClass: "chip--standby", label: i18n.standby };
5074
5645
  case DeviceStatusType.WARNING:
5075
- return { chipClass: "chip--alert", label: i18n.alert };
5646
+ return { chipClass: "chip--warning", label: i18n.alert };
5647
+ case DeviceStatusType.MAINTENANCE:
5648
+ return { chipClass: "chip--maintenance", label: i18n.maintenance };
5076
5649
  case DeviceStatusType.FAILURE:
5077
- case DeviceStatusType.POWER_OFF:
5078
5650
  return { chipClass: "chip--failure", label: i18n.failure };
5079
- case DeviceStatusType.MAINTENANCE:
5080
- return { chipClass: "chip--alert", label: i18n.maintenance };
5081
- case DeviceStatusType.NOT_INSTALLED:
5082
- return { chipClass: "chip--offline", label: i18n.not_installed };
5083
- // Default (Cai aqui se não achar 'normal', 'hot' etc)
5651
+ case DeviceStatusType.POWER_OFF:
5652
+ return { chipClass: "chip--power-off", label: i18n.power_off || i18n.failure };
5653
+ case DeviceStatusType.OFFLINE:
5654
+ return { chipClass: "chip--offline", label: i18n.offline };
5084
5655
  case DeviceStatusType.NO_INFO:
5656
+ return { chipClass: "chip--no-info", label: i18n.no_info || i18n.offline };
5657
+ case DeviceStatusType.NOT_INSTALLED:
5658
+ return { chipClass: "chip--not-installed", label: i18n.not_installed };
5085
5659
  default:
5086
5660
  return { chipClass: "chip--offline", label: i18n.offline };
5087
5661
  }
@@ -5089,23 +5663,32 @@ function getStatusInfo(deviceStatus, i18n, domain) {
5089
5663
  function getCardStateClass(deviceStatus) {
5090
5664
  switch (deviceStatus) {
5091
5665
  case DeviceStatusType.POWER_ON:
5092
- return "is-ok";
5666
+ return "is-power-on";
5093
5667
  // Blue border
5094
5668
  case DeviceStatusType.STANDBY:
5095
5669
  return "is-standby";
5096
5670
  // Green border
5097
5671
  case DeviceStatusType.WARNING:
5672
+ return "is-warning";
5673
+ // Yellow border
5098
5674
  case DeviceStatusType.MAINTENANCE:
5099
- return "is-alert";
5675
+ return "is-maintenance";
5100
5676
  // Yellow border
5101
5677
  case DeviceStatusType.FAILURE:
5102
- case DeviceStatusType.POWER_OFF:
5103
5678
  return "is-failure";
5104
- // Red border
5679
+ // Dark Red border
5680
+ case DeviceStatusType.POWER_OFF:
5681
+ return "is-power-off";
5682
+ // Light Red border
5683
+ case DeviceStatusType.OFFLINE:
5684
+ return "is-offline";
5685
+ // Dark Gray border
5105
5686
  case DeviceStatusType.NO_INFO:
5687
+ return "is-no-info";
5688
+ // Dark Orange border
5106
5689
  case DeviceStatusType.NOT_INSTALLED:
5107
- return "is-offline";
5108
- // Gray border
5690
+ return "is-not-installed";
5691
+ // Purple border
5109
5692
  default:
5110
5693
  return "";
5111
5694
  }
@@ -5119,17 +5702,25 @@ function getStatusDotClass(deviceStatus) {
5119
5702
  return "dot--standby";
5120
5703
  case "hot":
5121
5704
  return "dot--alert";
5122
- // --- Status Existentes ---
5705
+ // --- Status Existentes (aligned with getCardStateClass) ---
5123
5706
  case DeviceStatusType.POWER_ON:
5124
- return "dot--ok";
5707
+ return "dot--power-on";
5125
5708
  case DeviceStatusType.STANDBY:
5126
5709
  return "dot--standby";
5127
5710
  case DeviceStatusType.WARNING:
5711
+ return "dot--warning";
5128
5712
  case DeviceStatusType.MAINTENANCE:
5129
- return "dot--alert";
5713
+ return "dot--maintenance";
5130
5714
  case DeviceStatusType.FAILURE:
5131
- case DeviceStatusType.POWER_OFF:
5132
5715
  return "dot--failure";
5716
+ case DeviceStatusType.POWER_OFF:
5717
+ return "dot--power-off";
5718
+ case DeviceStatusType.OFFLINE:
5719
+ return "dot--offline";
5720
+ case DeviceStatusType.NO_INFO:
5721
+ return "dot--no-info";
5722
+ case DeviceStatusType.NOT_INSTALLED:
5723
+ return "dot--not-installed";
5133
5724
  default:
5134
5725
  return "dot--offline";
5135
5726
  }
@@ -5153,7 +5744,13 @@ function buildDOM(state) {
5153
5744
  titleSection.className = "myio-ho-card__title";
5154
5745
  const nameEl = document.createElement("div");
5155
5746
  nameEl.className = "myio-ho-card__name";
5156
- nameEl.textContent = entityObject.labelOrName || "Unknown Device";
5747
+ const fullName = entityObject.labelOrName || "Unknown Device";
5748
+ if (fullName.length > LABEL_CHAR_LIMIT) {
5749
+ nameEl.textContent = fullName.slice(0, LABEL_CHAR_LIMIT) + "\u2026";
5750
+ nameEl.title = fullName;
5751
+ } else {
5752
+ nameEl.textContent = fullName;
5753
+ }
5157
5754
  titleSection.appendChild(nameEl);
5158
5755
  if (entityObject.deviceIdentifier) {
5159
5756
  const codeEl = document.createElement("div");
@@ -5282,29 +5879,207 @@ function buildDOM(state) {
5282
5879
  root.appendChild(footer);
5283
5880
  return root;
5284
5881
  }
5285
- function verifyOfflineStatus(entityObject, delayTimeInMins = 15) {
5882
+ function buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins) {
5883
+ const formatTimestamp = (ts) => {
5884
+ if (!ts) return "N/A";
5885
+ const d = new Date(ts);
5886
+ return d.toLocaleString("pt-BR", {
5887
+ day: "2-digit",
5888
+ month: "2-digit",
5889
+ year: "numeric",
5890
+ hour: "2-digit",
5891
+ minute: "2-digit",
5892
+ second: "2-digit"
5893
+ });
5894
+ };
5895
+ return {
5896
+ // Entity identification
5897
+ entityId: entityObject.entityId || "N/A",
5898
+ name: entityObject.name || entityObject.nameEl || "N/A",
5899
+ domain: entityObject.domain || "energy",
5900
+ // Status decision chain
5901
+ originalDeviceStatus: entityObject._originalDeviceStatus || entityObject.deviceStatus,
5902
+ finalDeviceStatus: entityObject.deviceStatus,
5903
+ connectionStatus: entityObject.connectionStatus || "N/A",
5904
+ statusDecisionSource,
5905
+ // Visual output
5906
+ stateClass,
5907
+ chipClass: statusInfo.chipClass,
5908
+ chipLabel: statusInfo.label,
5909
+ // Connection timestamps
5910
+ lastConnectTime: formatTimestamp(entityObject.lastConnectTime),
5911
+ lastDisconnectTime: formatTimestamp(entityObject.lastDisconnectTime),
5912
+ delayTimeConnectionInMins,
5913
+ // Raw values
5914
+ val: entityObject.val,
5915
+ consumptionTargetValue: entityObject.consumptionTargetValue,
5916
+ deviceType: entityObject.deviceType || "N/A"
5917
+ };
5918
+ }
5919
+ function attachDebugTooltip(element, debugInfo) {
5920
+ const existingTooltip = element.querySelector(".debug-tooltip-container");
5921
+ if (existingTooltip) {
5922
+ existingTooltip.remove();
5923
+ }
5924
+ const tooltipContainer = document.createElement("div");
5925
+ tooltipContainer.className = "debug-tooltip-container";
5926
+ const tooltip = document.createElement("div");
5927
+ tooltip.className = "debug-tooltip";
5928
+ tooltip.innerHTML = `
5929
+ <div class="debug-tooltip__header">
5930
+ <span class="debug-tooltip__icon">\u{1F50D}</span>
5931
+ <span class="debug-tooltip__title">Debug Info</span>
5932
+ </div>
5933
+ <div class="debug-tooltip__content">
5934
+ <div class="debug-tooltip__section">
5935
+ <div class="debug-tooltip__section-title">\u{1F4CB} Identifica\xE7\xE3o</div>
5936
+ <div class="debug-tooltip__row">
5937
+ <span class="debug-tooltip__label">Entity ID:</span>
5938
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.entityId}</span>
5939
+ </div>
5940
+ <div class="debug-tooltip__row">
5941
+ <span class="debug-tooltip__label">Nome:</span>
5942
+ <span class="debug-tooltip__value">${debugInfo.name}</span>
5943
+ </div>
5944
+ <div class="debug-tooltip__row">
5945
+ <span class="debug-tooltip__label">Dom\xEDnio:</span>
5946
+ <span class="debug-tooltip__value debug-tooltip__badge debug-tooltip__badge--${debugInfo.domain}">${debugInfo.domain}</span>
5947
+ </div>
5948
+ </div>
5949
+
5950
+ <div class="debug-tooltip__section">
5951
+ <div class="debug-tooltip__section-title">\u26A1 Decis\xE3o de Status</div>
5952
+ <div class="debug-tooltip__row">
5953
+ <span class="debug-tooltip__label">connectionStatus:</span>
5954
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.connectionStatus}</span>
5955
+ </div>
5956
+ <div class="debug-tooltip__row">
5957
+ <span class="debug-tooltip__label">deviceStatus (final):</span>
5958
+ <span class="debug-tooltip__value debug-tooltip__badge">${debugInfo.finalDeviceStatus}</span>
5959
+ </div>
5960
+ <div class="debug-tooltip__row debug-tooltip__row--full">
5961
+ <span class="debug-tooltip__label">Fonte da decis\xE3o:</span>
5962
+ <span class="debug-tooltip__value debug-tooltip__value--highlight">${debugInfo.statusDecisionSource}</span>
5963
+ </div>
5964
+ </div>
5965
+
5966
+ <div class="debug-tooltip__section">
5967
+ <div class="debug-tooltip__section-title">\u{1F3A8} Output Visual</div>
5968
+ <div class="debug-tooltip__row">
5969
+ <span class="debug-tooltip__label">stateClass:</span>
5970
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.stateClass}</span>
5971
+ </div>
5972
+ <div class="debug-tooltip__row">
5973
+ <span class="debug-tooltip__label">chipClass:</span>
5974
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.chipClass}</span>
5975
+ </div>
5976
+ <div class="debug-tooltip__row">
5977
+ <span class="debug-tooltip__label">chipLabel:</span>
5978
+ <span class="debug-tooltip__value">${debugInfo.chipLabel}</span>
5979
+ </div>
5980
+ </div>
5981
+
5982
+ <div class="debug-tooltip__section">
5983
+ <div class="debug-tooltip__section-title">\u{1F550} Timestamps de Conex\xE3o</div>
5984
+ <div class="debug-tooltip__row">
5985
+ <span class="debug-tooltip__label">lastConnectTime:</span>
5986
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.lastConnectTime}</span>
5987
+ </div>
5988
+ <div class="debug-tooltip__row">
5989
+ <span class="debug-tooltip__label">lastDisconnectTime:</span>
5990
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.lastDisconnectTime}</span>
5991
+ </div>
5992
+ <div class="debug-tooltip__row">
5993
+ <span class="debug-tooltip__label">delayTime:</span>
5994
+ <span class="debug-tooltip__value">${debugInfo.delayTimeConnectionInMins} mins</span>
5995
+ </div>
5996
+ </div>
5997
+
5998
+ <div class="debug-tooltip__section">
5999
+ <div class="debug-tooltip__section-title">\u{1F4CA} Valores</div>
6000
+ <div class="debug-tooltip__row">
6001
+ <span class="debug-tooltip__label">val (consumo):</span>
6002
+ <span class="debug-tooltip__value">${debugInfo.val ?? "N/A"}</span>
6003
+ </div>
6004
+ <div class="debug-tooltip__row">
6005
+ <span class="debug-tooltip__label">target (meta):</span>
6006
+ <span class="debug-tooltip__value">${debugInfo.consumptionTargetValue ?? "N/A"}</span>
6007
+ </div>
6008
+ <div class="debug-tooltip__row">
6009
+ <span class="debug-tooltip__label">deviceType:</span>
6010
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.deviceType}</span>
6011
+ </div>
6012
+ </div>
6013
+ </div>
6014
+ `;
6015
+ tooltipContainer.appendChild(tooltip);
6016
+ element.style.position = "relative";
6017
+ element.style.cursor = "help";
6018
+ element.appendChild(tooltipContainer);
6019
+ element.classList.add("has-debug-tooltip");
6020
+ }
6021
+ function verifyOfflineStatus(entityObject, delayTimeInMins = 15, LogHelper2) {
5286
6022
  const lastConnectionTime = new Date(entityObject.lastConnectTime || 0);
5287
6023
  const lastDisconnectTime = new Date(entityObject.lastDisconnectTime || 0);
5288
6024
  const now = /* @__PURE__ */ new Date();
5289
6025
  const delayTimeInMs = delayTimeInMins * 60 * 1e3;
5290
6026
  const timeSinceConnection = now.getTime() - lastConnectionTime.getTime();
6027
+ let isOffline = false;
5291
6028
  if (lastDisconnectTime.getTime() > lastConnectionTime.getTime()) {
5292
- return false;
5293
- }
5294
- if (timeSinceConnection < delayTimeInMs) {
5295
- return false;
6029
+ isOffline = true;
6030
+ LogHelper2.log(
6031
+ "[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastDisconnectTime is more recent than lastConnectTime",
6032
+ entityObject.nameEl
6033
+ );
6034
+ } else if (timeSinceConnection > delayTimeInMs) {
6035
+ isOffline = true;
6036
+ LogHelper2.log(
6037
+ "[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastConnectTime is older than configured delayTimeConnectionInMins:",
6038
+ delayTimeInMins,
6039
+ "for device",
6040
+ entityObject.nameEl
6041
+ );
6042
+ } else {
6043
+ isOffline = false;
6044
+ LogHelper2.log(
6045
+ "[CardHeadOffice][ConnectionStatus Verify] Device is ONLINE because lastConnectTime is within configured delayTimeConnectionInMins:",
6046
+ delayTimeInMins,
6047
+ "for device",
6048
+ entityObject.nameEl
6049
+ );
5296
6050
  }
5297
- return true;
6051
+ return isOffline;
5298
6052
  }
5299
6053
  function paint(root, state) {
5300
- const { entityObject, i18n, delayTimeConnectionInMins, isSelected } = state;
6054
+ const { entityObject, i18n, delayTimeConnectionInMins, isSelected, LogHelper: LogHelper2, activeTooltipDebug } = state;
6055
+ let statusDecisionSource = "unknown";
5301
6056
  if (entityObject.connectionStatus) {
5302
6057
  if (entityObject.connectionStatus === "offline") {
5303
- entityObject.deviceStatus = DeviceStatusType.NO_INFO;
6058
+ LogHelper2.log(
6059
+ "[CardHeadOffice][ConnectionStatus Verify 01] Setting deviceStatus to OFFLINE based on connectionStatus"
6060
+ );
6061
+ entityObject.deviceStatus = DeviceStatusType.OFFLINE;
6062
+ statusDecisionSource = 'connectionStatus === "offline"';
6063
+ } else {
6064
+ LogHelper2.log(
6065
+ "[CardHeadOffice] Device is ONLINE or WAITING based on connectionStatus for device",
6066
+ entityObject.nameEl
6067
+ );
6068
+ statusDecisionSource = `connectionStatus === "${entityObject.connectionStatus}" (kept original deviceStatus)`;
5304
6069
  }
5305
6070
  } else {
5306
- if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins) === false) {
5307
- entityObject.deviceStatus = DeviceStatusType.NO_INFO;
6071
+ if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins, LogHelper2) === false) {
6072
+ LogHelper2.log(
6073
+ "[CardHeadOffice][ConnectionStatus Verify 02] Setting deviceStatus to OFFLINE based on timestamp verification by verifyOfflineStatus METHOD with delayTimeConnectionInMins:",
6074
+ delayTimeConnectionInMins
6075
+ );
6076
+ entityObject.deviceStatus = DeviceStatusType.OFFLINE;
6077
+ statusDecisionSource = `verifyOfflineStatus() returned false (delay: ${delayTimeConnectionInMins} mins)`;
6078
+ } else {
6079
+ LogHelper2.log(
6080
+ `[CardHeadOffice][ConnectionStatus Verify 03] Device is ONLINE with deviceStatus = ${entityObject.deviceStatus} based on timestamp verification for device ${entityObject.nameEl}`
6081
+ );
6082
+ statusDecisionSource = `verifyOfflineStatus() returned true (delay: ${delayTimeConnectionInMins} mins)`;
5308
6083
  }
5309
6084
  }
5310
6085
  const stateClass = getCardStateClass(entityObject.deviceStatus);
@@ -5313,6 +6088,10 @@ function paint(root, state) {
5313
6088
  const chip = root.querySelector(".chip");
5314
6089
  chip.className = `chip ${statusInfo.chipClass}`;
5315
6090
  chip.innerHTML = statusInfo.label;
6091
+ if (activeTooltipDebug) {
6092
+ const debugInfo = buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins);
6093
+ attachDebugTooltip(chip, debugInfo);
6094
+ }
5316
6095
  const primaryValue = formatValueByDomain(entityObject.val, entityObject.domain);
5317
6096
  const numSpan = root.querySelector(".myio-ho-card__value .num");
5318
6097
  const unitSpan = root.querySelector(".myio-ho-card__value .unit");
@@ -5525,6 +6304,7 @@ function renderCardComponentHeadOffice(containerEl, params) {
5525
6304
  }
5526
6305
 
5527
6306
  // src/thingsboard/main-dashboard-shopping/v-5.2.0/card/template-card-v5.js
6307
+ var LABEL_CHAR_LIMIT2 = 18;
5528
6308
  function renderCardComponentV5({
5529
6309
  entityObject,
5530
6310
  handleActionDashboard,
@@ -6041,7 +6821,7 @@ ${rangeText}`;
6041
6821
 
6042
6822
  <div class="device-title-row" style="flex-direction: column; min-height: 38px; text-align: center; width: 100%;">
6043
6823
  <span class="device-title" title="${cardEntity.name}">
6044
- ${cardEntity.name.length > 18 ? cardEntity.name.slice(0, 18) + "\u2026" : cardEntity.name}
6824
+ ${cardEntity.name.length > LABEL_CHAR_LIMIT2 ? cardEntity.name.slice(0, LABEL_CHAR_LIMIT2) + "\u2026" : cardEntity.name}
6045
6825
  </span>
6046
6826
  ${deviceIdentifier ? `
6047
6827
  <span class="device-subtitle" title="${deviceIdentifier}">
@@ -20368,220 +21148,6 @@ function openGoalsPanel(params) {
20368
21148
  }
20369
21149
  }
20370
21150
 
20371
- // src/components/temperature/utils.ts
20372
- var DAY_PERIODS = [
20373
- { id: "madrugada", label: "Madrugada (00h-06h)", startHour: 0, endHour: 6 },
20374
- { id: "manha", label: "Manh\xE3 (06h-12h)", startHour: 6, endHour: 12 },
20375
- { id: "tarde", label: "Tarde (12h-18h)", startHour: 12, endHour: 18 },
20376
- { id: "noite", label: "Noite (18h-24h)", startHour: 18, endHour: 24 }
20377
- ];
20378
- var DEFAULT_CLAMP_RANGE = { min: 15, max: 40 };
20379
- function getTodaySoFar() {
20380
- const now = /* @__PURE__ */ new Date();
20381
- const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
20382
- return {
20383
- startTs: startOfDay.getTime(),
20384
- endTs: now.getTime()
20385
- };
20386
- }
20387
- var CHART_COLORS = [
20388
- "#1976d2",
20389
- // Blue
20390
- "#FF6B6B",
20391
- // Red
20392
- "#4CAF50",
20393
- // Green
20394
- "#FF9800",
20395
- // Orange
20396
- "#9C27B0",
20397
- // Purple
20398
- "#00BCD4",
20399
- // Cyan
20400
- "#E91E63",
20401
- // Pink
20402
- "#795548"
20403
- // Brown
20404
- ];
20405
- async function fetchTemperatureData(token, deviceId, startTs, endTs) {
20406
- const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=temperature&startTs=${encodeURIComponent(startTs)}&endTs=${encodeURIComponent(endTs)}&limit=50000&agg=NONE`;
20407
- const response = await fetch(url, {
20408
- headers: {
20409
- "X-Authorization": `Bearer ${token}`,
20410
- "Content-Type": "application/json"
20411
- }
20412
- });
20413
- if (!response.ok) {
20414
- throw new Error(`Failed to fetch temperature data: ${response.status}`);
20415
- }
20416
- const data = await response.json();
20417
- return data?.temperature || [];
20418
- }
20419
- function clampTemperature(value, range = DEFAULT_CLAMP_RANGE) {
20420
- const num = Number(value || 0);
20421
- if (num < range.min) return range.min;
20422
- if (num > range.max) return range.max;
20423
- return num;
20424
- }
20425
- function calculateStats(data, clampRange = DEFAULT_CLAMP_RANGE) {
20426
- if (data.length === 0) {
20427
- return { avg: 0, min: 0, max: 0, count: 0 };
20428
- }
20429
- const values = data.map((item) => clampTemperature(item.value, clampRange));
20430
- const sum = values.reduce((acc, v) => acc + v, 0);
20431
- return {
20432
- avg: sum / values.length,
20433
- min: Math.min(...values),
20434
- max: Math.max(...values),
20435
- count: values.length
20436
- };
20437
- }
20438
- function interpolateTemperature(data, options) {
20439
- const { intervalMinutes, startTs, endTs, clampRange = DEFAULT_CLAMP_RANGE } = options;
20440
- const intervalMs = intervalMinutes * 60 * 1e3;
20441
- if (data.length === 0) {
20442
- return [];
20443
- }
20444
- const sortedData = [...data].sort((a, b) => a.ts - b.ts);
20445
- const result = [];
20446
- let lastKnownValue = clampTemperature(sortedData[0].value, clampRange);
20447
- let dataIndex = 0;
20448
- for (let ts = startTs; ts <= endTs; ts += intervalMs) {
20449
- while (dataIndex < sortedData.length - 1 && sortedData[dataIndex + 1].ts <= ts) {
20450
- dataIndex++;
20451
- }
20452
- const currentData = sortedData[dataIndex];
20453
- if (currentData && Math.abs(currentData.ts - ts) < intervalMs) {
20454
- lastKnownValue = clampTemperature(currentData.value, clampRange);
20455
- }
20456
- result.push({
20457
- ts,
20458
- value: lastKnownValue
20459
- });
20460
- }
20461
- return result;
20462
- }
20463
- function aggregateByDay(data, clampRange = DEFAULT_CLAMP_RANGE) {
20464
- if (data.length === 0) {
20465
- return [];
20466
- }
20467
- const dayMap = /* @__PURE__ */ new Map();
20468
- data.forEach((item) => {
20469
- const date = new Date(item.ts);
20470
- const dateKey = date.toISOString().split("T")[0];
20471
- if (!dayMap.has(dateKey)) {
20472
- dayMap.set(dateKey, []);
20473
- }
20474
- dayMap.get(dateKey).push(item);
20475
- });
20476
- const result = [];
20477
- dayMap.forEach((dayData, dateKey) => {
20478
- const values = dayData.map((item) => clampTemperature(item.value, clampRange));
20479
- const sum = values.reduce((acc, v) => acc + v, 0);
20480
- result.push({
20481
- date: dateKey,
20482
- dateTs: new Date(dateKey).getTime(),
20483
- avg: sum / values.length,
20484
- min: Math.min(...values),
20485
- max: Math.max(...values),
20486
- count: values.length
20487
- });
20488
- });
20489
- return result.sort((a, b) => a.dateTs - b.dateTs);
20490
- }
20491
- function filterByDayPeriods(data, selectedPeriods) {
20492
- if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
20493
- return data;
20494
- }
20495
- return data.filter((item) => {
20496
- const date = new Date(item.ts);
20497
- const hour = date.getHours();
20498
- return selectedPeriods.some((periodId) => {
20499
- const period = DAY_PERIODS.find((p) => p.id === periodId);
20500
- if (!period) return false;
20501
- return hour >= period.startHour && hour < period.endHour;
20502
- });
20503
- });
20504
- }
20505
- function getSelectedPeriodsLabel(selectedPeriods) {
20506
- if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
20507
- return "Todos os per\xEDodos";
20508
- }
20509
- if (selectedPeriods.length === 1) {
20510
- const period = DAY_PERIODS.find((p) => p.id === selectedPeriods[0]);
20511
- return period?.label || "";
20512
- }
20513
- return `${selectedPeriods.length} per\xEDodos selecionados`;
20514
- }
20515
- function formatTemperature2(value, decimals = 1) {
20516
- return `${value.toFixed(decimals)}\xB0C`;
20517
- }
20518
- function exportTemperatureCSV(data, deviceLabel, stats, startDate, endDate) {
20519
- if (data.length === 0) {
20520
- console.warn("No data to export");
20521
- return;
20522
- }
20523
- const BOM = "\uFEFF";
20524
- let csvContent = BOM;
20525
- csvContent += `Relat\xF3rio de Temperatura - ${deviceLabel}
20526
- `;
20527
- csvContent += `Per\xEDodo: ${startDate} at\xE9 ${endDate}
20528
- `;
20529
- csvContent += `M\xE9dia: ${formatTemperature2(stats.avg)}
20530
- `;
20531
- csvContent += `M\xEDnima: ${formatTemperature2(stats.min)}
20532
- `;
20533
- csvContent += `M\xE1xima: ${formatTemperature2(stats.max)}
20534
- `;
20535
- csvContent += `Total de leituras: ${stats.count}
20536
- `;
20537
- csvContent += "\n";
20538
- csvContent += "Data/Hora,Temperatura (\xB0C)\n";
20539
- data.forEach((item) => {
20540
- const date = new Date(item.ts).toLocaleString("pt-BR");
20541
- const temp = Number(item.value).toFixed(2);
20542
- csvContent += `"${date}",${temp}
20543
- `;
20544
- });
20545
- const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
20546
- const url = URL.createObjectURL(blob);
20547
- const link = document.createElement("a");
20548
- link.href = url;
20549
- link.download = `temperatura_${deviceLabel.replace(/\s+/g, "_")}_${startDate}_${endDate}.csv`;
20550
- document.body.appendChild(link);
20551
- link.click();
20552
- document.body.removeChild(link);
20553
- URL.revokeObjectURL(url);
20554
- }
20555
- var DARK_THEME = {
20556
- background: "rgba(0, 0, 0, 0.85)",
20557
- surface: "#1a1f28",
20558
- text: "#ffffff",
20559
- textMuted: "rgba(255, 255, 255, 0.7)",
20560
- border: "rgba(255, 255, 255, 0.1)",
20561
- primary: "#1976d2",
20562
- success: "#4CAF50",
20563
- warning: "#FF9800",
20564
- danger: "#f44336",
20565
- chartLine: "#1976d2",
20566
- chartGrid: "rgba(255, 255, 255, 0.1)"
20567
- };
20568
- var LIGHT_THEME = {
20569
- background: "rgba(0, 0, 0, 0.6)",
20570
- surface: "#ffffff",
20571
- text: "#333333",
20572
- textMuted: "#666666",
20573
- border: "#e0e0e0",
20574
- primary: "#1976d2",
20575
- success: "#4CAF50",
20576
- warning: "#FF9800",
20577
- danger: "#f44336",
20578
- chartLine: "#1976d2",
20579
- chartGrid: "#e0e0e0"
20580
- };
20581
- function getThemeColors(theme) {
20582
- return theme === "dark" ? DARK_THEME : LIGHT_THEME;
20583
- }
20584
-
20585
21151
  // src/components/temperature/TemperatureModal.ts
20586
21152
  async function openTemperatureModal(params) {
20587
21153
  const modalId = `myio-temp-modal-${Date.now()}`;
@@ -20821,7 +21387,7 @@ function renderModal(container, state, modalId, error) {
20821
21387
  ">
20822
21388
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Temperatura Atual</span>
20823
21389
  <div style="font-weight: 700; font-size: 24px; color: ${statusColor}; margin-top: 4px;">
20824
- ${state.currentTemperature !== null ? formatTemperature2(state.currentTemperature) : "N/A"}
21390
+ ${state.currentTemperature !== null ? formatTemperature(state.currentTemperature) : "N/A"}
20825
21391
  </div>
20826
21392
  <div style="font-size: 11px; color: ${statusColor}; margin-top: 2px;">${statusText}</div>
20827
21393
  </div>
@@ -20832,7 +21398,7 @@ function renderModal(container, state, modalId, error) {
20832
21398
  ">
20833
21399
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">M\xE9dia do Per\xEDodo</span>
20834
21400
  <div id="${modalId}-avg" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
20835
- ${state.stats.count > 0 ? formatTemperature2(state.stats.avg) : "N/A"}
21401
+ ${state.stats.count > 0 ? formatTemperature(state.stats.avg) : "N/A"}
20836
21402
  </div>
20837
21403
  <div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${startDateStr} - ${endDateStr}</div>
20838
21404
  </div>
@@ -20843,7 +21409,7 @@ function renderModal(container, state, modalId, error) {
20843
21409
  ">
20844
21410
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Min / Max</span>
20845
21411
  <div id="${modalId}-minmax" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
20846
- ${state.stats.count > 0 ? `${formatTemperature2(state.stats.min)} / ${formatTemperature2(state.stats.max)}` : "N/A"}
21412
+ ${state.stats.count > 0 ? `${formatTemperature(state.stats.min)} / ${formatTemperature(state.stats.max)}` : "N/A"}
20847
21413
  </div>
20848
21414
  <div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${state.stats.count} leituras</div>
20849
21415
  </div>
@@ -21159,7 +21725,7 @@ function setupChartTooltip(canvas, container, chartData, state, colors) {
21159
21725
  }
21160
21726
  tooltip.innerHTML = `
21161
21727
  <div style="font-weight: 600; margin-bottom: 6px; color: ${colors.primary};">
21162
- ${formatTemperature2(point.y)}
21728
+ ${formatTemperature(point.y)}
21163
21729
  </div>
21164
21730
  <div style="font-size: 11px; color: ${colors.textMuted};">
21165
21731
  \u{1F4C5} ${dateStr}
@@ -21422,7 +21988,7 @@ function renderModal2(container, state, modalId) {
21422
21988
  <span style="width: 12px; height: 12px; border-radius: 50%; background: ${dd.color};"></span>
21423
21989
  <span style="color: ${colors.text}; font-size: 13px;">${dd.device.label}</span>
21424
21990
  <span style="color: ${colors.textMuted}; font-size: 11px; margin-left: auto;">
21425
- ${dd.stats.count > 0 ? formatTemperature2(dd.stats.avg) : "N/A"}
21991
+ ${dd.stats.count > 0 ? formatTemperature(dd.stats.avg) : "N/A"}
21426
21992
  </span>
21427
21993
  </div>
21428
21994
  `).join("");
@@ -21438,15 +22004,15 @@ function renderModal2(container, state, modalId) {
21438
22004
  <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 4px; font-size: 11px;">
21439
22005
  <span style="color: ${colors.textMuted};">M\xE9dia:</span>
21440
22006
  <span style="color: ${colors.text}; font-weight: 500;">
21441
- ${dd.stats.count > 0 ? formatTemperature2(dd.stats.avg) : "N/A"}
22007
+ ${dd.stats.count > 0 ? formatTemperature(dd.stats.avg) : "N/A"}
21442
22008
  </span>
21443
22009
  <span style="color: ${colors.textMuted};">Min:</span>
21444
22010
  <span style="color: ${colors.text};">
21445
- ${dd.stats.count > 0 ? formatTemperature2(dd.stats.min) : "N/A"}
22011
+ ${dd.stats.count > 0 ? formatTemperature(dd.stats.min) : "N/A"}
21446
22012
  </span>
21447
22013
  <span style="color: ${colors.textMuted};">Max:</span>
21448
22014
  <span style="color: ${colors.text};">
21449
- ${dd.stats.count > 0 ? formatTemperature2(dd.stats.max) : "N/A"}
22015
+ ${dd.stats.count > 0 ? formatTemperature(dd.stats.max) : "N/A"}
21450
22016
  </span>
21451
22017
  <span style="color: ${colors.textMuted};">Leituras:</span>
21452
22018
  <span style="color: ${colors.text};">${dd.stats.count}</span>
@@ -21982,7 +22548,7 @@ function setupComparisonChartTooltip(canvas, container, chartData, state, colors
21982
22548
  <span style="font-weight: 600;">${point.deviceLabel}</span>
21983
22549
  </div>
21984
22550
  <div style="font-weight: 600; font-size: 16px; color: ${point.deviceColor}; margin-bottom: 4px;">
21985
- ${formatTemperature2(point.y)}
22551
+ ${formatTemperature(point.y)}
21986
22552
  </div>
21987
22553
  <div style="font-size: 11px; color: ${colors.textMuted};">
21988
22554
  \u{1F4C5} ${dateStr}
@@ -23737,7 +24303,7 @@ function createConsumptionModal(config) {
23737
24303
  let currentTheme = config.theme ?? "light";
23738
24304
  let currentChartType = config.defaultChartType ?? "line";
23739
24305
  let currentVizMode = config.defaultVizMode ?? "total";
23740
- let isMaximized = false;
24306
+ const isMaximized = true;
23741
24307
  const domainCfg = DOMAIN_CONFIG3[config.domain] || { name: config.domain, icon: "\u{1F4CA}" };
23742
24308
  const title = config.title || `${domainCfg.name} - Hist\xF3rico de Consumo`;
23743
24309
  function getThemeColors3() {
@@ -23756,7 +24322,10 @@ function createConsumptionModal(config) {
23756
24322
  title,
23757
24323
  icon: domainCfg.icon,
23758
24324
  theme: currentTheme,
23759
- isMaximized,
24325
+ isMaximized: true,
24326
+ // Modal is always fullscreen
24327
+ showMaximize: false,
24328
+ // Hide maximize button - modal is already fullscreen
23760
24329
  exportFormats,
23761
24330
  onExport: (format) => {
23762
24331
  if (config.onExport) {
@@ -23774,10 +24343,6 @@ function createConsumptionModal(config) {
23774
24343
  chartInstance?.setTheme(currentTheme);
23775
24344
  updateModal();
23776
24345
  },
23777
- onMaximize: (maximized) => {
23778
- isMaximized = maximized;
23779
- updateModal();
23780
- },
23781
24346
  onClose: () => {
23782
24347
  instance.close();
23783
24348
  }
@@ -23985,7 +24550,7 @@ function createConsumptionModal(config) {
23985
24550
  typeBarBtn.style.color = currentChartType === "bar" ? "white" : colors.text;
23986
24551
  }
23987
24552
  }
23988
- function updateModal() {
24553
+ async function updateModal() {
23989
24554
  if (!modalElement) return;
23990
24555
  const cachedData = chartInstance?.getCachedData();
23991
24556
  headerInstance?.destroy();
@@ -23998,9 +24563,11 @@ function createConsumptionModal(config) {
23998
24563
  containerId: `${modalId}-chart`,
23999
24564
  theme: currentTheme,
24000
24565
  defaultChartType: currentChartType,
24001
- defaultVizMode: currentVizMode
24566
+ defaultVizMode: currentVizMode,
24567
+ initialData: cachedData
24568
+ // RFC-0098: Use initialData for instant re-render
24002
24569
  });
24003
- chartInstance.update(cachedData);
24570
+ await chartInstance.render();
24004
24571
  }
24005
24572
  }
24006
24573
  const instance = {