myio-js-library 0.1.169 → 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.
@@ -1324,7 +1324,8 @@
1324
1324
  FAILURE: "failure",
1325
1325
  MAINTENANCE: "maintenance",
1326
1326
  NO_INFO: "no_info",
1327
- NOT_INSTALLED: "not_installed"
1327
+ NOT_INSTALLED: "not_installed",
1328
+ OFFLINE: "offline"
1328
1329
  };
1329
1330
  var ConnectionStatusType = {
1330
1331
  CONNECTED: "connected",
@@ -1333,39 +1334,42 @@
1333
1334
  var deviceStatusIcons = {
1334
1335
  [DeviceStatusType.POWER_ON]: "\u26A1",
1335
1336
  [DeviceStatusType.STANDBY]: "\u{1F50C}",
1336
- [DeviceStatusType.POWER_OFF]: "\u{1F534}",
1337
+ [DeviceStatusType.POWER_OFF]: "\u26AB",
1337
1338
  [DeviceStatusType.WARNING]: "\u26A0\uFE0F",
1338
1339
  [DeviceStatusType.FAILURE]: "\u{1F6A8}",
1339
1340
  [DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
1340
1341
  [DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
1341
- [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
1342
+ [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
1343
+ [DeviceStatusType.OFFLINE]: "\u{1F534}"
1342
1344
  };
1343
1345
  var waterDeviceStatusIcons = {
1344
1346
  [DeviceStatusType.POWER_ON]: "\u{1F4A7}",
1345
1347
  [DeviceStatusType.STANDBY]: "\u{1F6B0}",
1346
- [DeviceStatusType.POWER_OFF]: "\u{1F534}",
1348
+ [DeviceStatusType.POWER_OFF]: "\u26AB",
1347
1349
  [DeviceStatusType.WARNING]: "\u26A0\uFE0F",
1348
1350
  [DeviceStatusType.FAILURE]: "\u{1F6A8}",
1349
1351
  [DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
1350
1352
  [DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
1351
- [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
1353
+ [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
1354
+ [DeviceStatusType.OFFLINE]: "\u{1F534}"
1352
1355
  };
1353
1356
  var temperatureDeviceStatusIcons = {
1354
1357
  [DeviceStatusType.POWER_ON]: "\u{1F321}\uFE0F",
1355
1358
  [DeviceStatusType.STANDBY]: "\u{1F321}\uFE0F",
1356
- [DeviceStatusType.POWER_OFF]: "\u{1F534}",
1359
+ [DeviceStatusType.POWER_OFF]: "\u26AB",
1357
1360
  [DeviceStatusType.WARNING]: "\u26A0\uFE0F",
1358
1361
  [DeviceStatusType.FAILURE]: "\u{1F6A8}",
1359
1362
  [DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
1360
1363
  [DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
1361
- [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
1364
+ [DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
1365
+ [DeviceStatusType.OFFLINE]: "\u{1F534}"
1362
1366
  };
1363
1367
  var connectionStatusIcons = {
1364
1368
  [ConnectionStatusType.CONNECTED]: "\u{1F7E2}",
1365
1369
  [ConnectionStatusType.OFFLINE]: "\u{1F6AB}"
1366
1370
  };
1367
1371
  function mapDeviceToConnectionStatus(deviceStatus) {
1368
- if (deviceStatus === DeviceStatusType.NO_INFO) {
1372
+ if (deviceStatus === DeviceStatusType.NO_INFO || deviceStatus === DeviceStatusType.OFFLINE) {
1369
1373
  return ConnectionStatusType.OFFLINE;
1370
1374
  }
1371
1375
  return ConnectionStatusType.CONNECTED;
@@ -1389,15 +1393,16 @@
1389
1393
  [DeviceStatusType.FAILURE]: "fail",
1390
1394
  [DeviceStatusType.MAINTENANCE]: "alert",
1391
1395
  [DeviceStatusType.NO_INFO]: "unknown",
1392
- [DeviceStatusType.NOT_INSTALLED]: "not_installed"
1396
+ [DeviceStatusType.NOT_INSTALLED]: "not_installed",
1397
+ [DeviceStatusType.OFFLINE]: "offline"
1393
1398
  };
1394
1399
  return statusMap[deviceStatus] || "unknown";
1395
1400
  }
1396
1401
  function shouldFlashIcon(deviceStatus) {
1397
- return deviceStatus === DeviceStatusType.POWER_OFF || deviceStatus === DeviceStatusType.WARNING || deviceStatus === DeviceStatusType.FAILURE || deviceStatus === DeviceStatusType.MAINTENANCE;
1402
+ return deviceStatus === DeviceStatusType.POWER_OFF || deviceStatus === DeviceStatusType.WARNING || deviceStatus === DeviceStatusType.FAILURE || deviceStatus === DeviceStatusType.MAINTENANCE || deviceStatus === DeviceStatusType.OFFLINE;
1398
1403
  }
1399
1404
  function isDeviceOffline(deviceStatus) {
1400
- return deviceStatus === DeviceStatusType.NO_INFO;
1405
+ return deviceStatus === DeviceStatusType.NO_INFO || deviceStatus === DeviceStatusType.OFFLINE;
1401
1406
  }
1402
1407
  function getDeviceStatusIcon(deviceStatus, deviceType = null) {
1403
1408
  const normalizedType = deviceType?.toUpperCase() || "";
@@ -3953,15 +3958,30 @@
3953
3958
  --myio-chip-alert-fg: #b45309;
3954
3959
  --myio-border-alert: rgba(245, 158, 11, 0.5);
3955
3960
 
3956
- /* Status colors - Failure (red) */
3961
+ /* Status colors - Failure (dark red) */
3957
3962
  --myio-chip-failure-bg: #fee2e2;
3958
3963
  --myio-chip-failure-fg: #b91c1c;
3959
- --myio-border-failure: rgba(239, 68, 68, 0.5);
3964
+ --myio-border-failure: rgba(153, 27, 27, 0.6);
3965
+
3966
+ /* Status colors - Power Off (light red) */
3967
+ --myio-chip-power-off-bg: #fecaca;
3968
+ --myio-chip-power-off-fg: #dc2626;
3969
+ --myio-border-power-off: rgba(239, 68, 68, 0.5);
3970
+
3971
+ /* Status colors - Offline (dark gray) */
3972
+ --myio-chip-offline-bg: #e2e8f0;
3973
+ --myio-chip-offline-fg: #475569;
3974
+ --myio-border-offline: rgba(71, 85, 105, 0.6);
3975
+
3976
+ /* Status colors - No Info (dark orange) */
3977
+ --myio-chip-no-info-bg: #fed7aa;
3978
+ --myio-chip-no-info-fg: #c2410c;
3979
+ --myio-border-no-info: rgba(194, 65, 12, 0.5);
3960
3980
 
3961
- /* Status colors - Offline (gray) */
3962
- --myio-chip-offline-bg: #f1f5f9;
3963
- --myio-chip-offline-fg: #64748b;
3964
- --myio-border-offline: rgba(100, 116, 139, 0.4);
3981
+ /* Status colors - Not Installed (purple) */
3982
+ --myio-chip-not-installed-bg: #e9d5ff;
3983
+ --myio-chip-not-installed-fg: #7c3aed;
3984
+ --myio-border-not-installed: rgba(124, 58, 237, 0.5);
3965
3985
 
3966
3986
  --myio-text-1: #0f172a;
3967
3987
  --myio-text-2: #4b5563;
@@ -4017,26 +4037,55 @@
4017
4037
  }
4018
4038
 
4019
4039
  /* Card border states based on device status */
4020
- .myio-ho-card.is-ok {
4040
+
4041
+ /* POWER_ON - Blue */
4042
+ .myio-ho-card.is-power-on {
4021
4043
  border-color: var(--myio-border-ok);
4022
4044
  box-shadow: 0 0 0 2px var(--myio-border-ok), var(--myio-card-shadow);
4023
4045
  }
4024
4046
 
4047
+ /* STANDBY - Green */
4025
4048
  .myio-ho-card.is-standby {
4026
4049
  border-color: var(--myio-border-standby);
4027
4050
  box-shadow: 0 0 0 2px var(--myio-border-standby), var(--myio-card-shadow);
4028
4051
  }
4029
4052
 
4030
- .myio-ho-card.is-alert {
4053
+ /* WARNING - Yellow */
4054
+ .myio-ho-card.is-warning {
4031
4055
  border-color: var(--myio-border-alert);
4032
4056
  box-shadow: 0 0 0 2px var(--myio-border-alert), var(--myio-card-shadow);
4033
4057
  }
4034
4058
 
4059
+ /* MAINTENANCE - Yellow */
4060
+ .myio-ho-card.is-maintenance {
4061
+ border-color: var(--myio-border-alert);
4062
+ box-shadow: 0 0 0 2px var(--myio-border-alert), var(--myio-card-shadow);
4063
+ }
4064
+
4065
+ /* FAILURE - Dark Red */
4035
4066
  .myio-ho-card.is-failure {
4036
4067
  border-color: var(--myio-border-failure);
4037
4068
  box-shadow: 0 0 0 2px var(--myio-border-failure), var(--myio-card-shadow);
4038
4069
  }
4039
4070
 
4071
+ /* POWER_OFF - Light Red */
4072
+ .myio-ho-card.is-power-off {
4073
+ border-color: var(--myio-border-power-off);
4074
+ box-shadow: 0 0 0 2px var(--myio-border-power-off), var(--myio-card-shadow);
4075
+ }
4076
+
4077
+ /* NO_INFO - Dark Orange */
4078
+ .myio-ho-card.is-no-info {
4079
+ border-color: var(--myio-border-no-info);
4080
+ box-shadow: 0 0 0 2px var(--myio-border-no-info), var(--myio-card-shadow);
4081
+ }
4082
+
4083
+ /* NOT_INSTALLED - Purple */
4084
+ .myio-ho-card.is-not-installed {
4085
+ border-color: var(--myio-border-not-installed);
4086
+ box-shadow: 0 0 0 2px var(--myio-border-not-installed), var(--myio-card-shadow);
4087
+ }
4088
+
4040
4089
  /* Header section */
4041
4090
  .myio-ho-card__header {
4042
4091
  display: flex;
@@ -4054,7 +4103,9 @@
4054
4103
  margin-top: 2px;
4055
4104
  }
4056
4105
 
4057
- .myio-ho-card.is-alert .myio-ho-card__icon {
4106
+ /* Icon colors based on status */
4107
+ .myio-ho-card.is-warning .myio-ho-card__icon,
4108
+ .myio-ho-card.is-maintenance .myio-ho-card__icon {
4058
4109
  color: var(--myio-chip-alert-fg);
4059
4110
  }
4060
4111
 
@@ -4062,14 +4113,28 @@
4062
4113
  color: var(--myio-chip-failure-fg);
4063
4114
  }
4064
4115
 
4116
+ .myio-ho-card.is-power-off .myio-ho-card__icon {
4117
+ color: var(--myio-chip-power-off-fg);
4118
+ }
4119
+
4120
+ .myio-ho-card.is-offline .myio-ho-card__icon {
4121
+ color: var(--myio-chip-offline-fg);
4122
+ }
4123
+
4124
+ .myio-ho-card.is-no-info .myio-ho-card__icon {
4125
+ color: var(--myio-chip-no-info-fg);
4126
+ }
4127
+
4128
+ .myio-ho-card.is-not-installed .myio-ho-card__icon {
4129
+ color: var(--myio-chip-not-installed-fg);
4130
+ }
4131
+
4065
4132
  .myio-ho-card__title {
4066
4133
  flex: 1;
4067
4134
  min-width: 0;
4068
4135
  }
4069
4136
 
4070
- /* Adicione estas duas novas regras ao seu CSS_STRING */
4071
-
4072
- /* Estado Offline - borda cinza */
4137
+ /* OFFLINE - Dark Gray */
4073
4138
  .myio-ho-card.is-offline {
4074
4139
  border-color: var(--myio-border-offline);
4075
4140
  box-shadow: 0 0 0 2px var(--myio-border-offline), var(--myio-card-shadow);
@@ -4464,6 +4529,37 @@
4464
4529
  color: var(--myio-chip-offline-fg);
4465
4530
  }
4466
4531
 
4532
+ /* New chip classes aligned with getCardStateClass */
4533
+ .chip--power-on {
4534
+ background: var(--myio-chip-ok-bg);
4535
+ color: var(--myio-chip-ok-fg);
4536
+ }
4537
+
4538
+ .chip--warning {
4539
+ background: var(--myio-chip-alert-bg);
4540
+ color: var(--myio-chip-alert-fg);
4541
+ }
4542
+
4543
+ .chip--maintenance {
4544
+ background: var(--myio-chip-alert-bg);
4545
+ color: var(--myio-chip-alert-fg);
4546
+ }
4547
+
4548
+ .chip--power-off {
4549
+ background: var(--myio-chip-power-off-bg);
4550
+ color: var(--myio-chip-power-off-fg);
4551
+ }
4552
+
4553
+ .chip--no-info {
4554
+ background: var(--myio-chip-no-info-bg);
4555
+ color: var(--myio-chip-no-info-fg);
4556
+ }
4557
+
4558
+ .chip--not-installed {
4559
+ background: var(--myio-chip-not-installed-bg);
4560
+ color: var(--myio-chip-not-installed-fg);
4561
+ }
4562
+
4467
4563
  /* Status indicator dot for power metric */
4468
4564
  .status-dot {
4469
4565
  width: 8px;
@@ -4497,6 +4593,31 @@
4497
4593
  background: var(--myio-muted);
4498
4594
  }
4499
4595
 
4596
+ /* New dot classes aligned with getCardStateClass */
4597
+ .status-dot.dot--power-on {
4598
+ background: var(--myio-chip-ok-fg);
4599
+ }
4600
+
4601
+ .status-dot.dot--warning {
4602
+ background: var(--myio-chip-alert-fg);
4603
+ }
4604
+
4605
+ .status-dot.dot--maintenance {
4606
+ background: var(--myio-chip-alert-fg);
4607
+ }
4608
+
4609
+ .status-dot.dot--power-off {
4610
+ background: var(--myio-chip-power-off-fg);
4611
+ }
4612
+
4613
+ .status-dot.dot--no-info {
4614
+ background: var(--myio-chip-no-info-fg);
4615
+ }
4616
+
4617
+ .status-dot.dot--not-installed {
4618
+ background: var(--myio-chip-not-installed-fg);
4619
+ }
4620
+
4500
4621
  /* Primary metric */
4501
4622
  .myio-ho-card__primary {
4502
4623
  margin-bottom: 14px;
@@ -4679,6 +4800,215 @@
4679
4800
  transition: none;
4680
4801
  }
4681
4802
  }
4803
+
4804
+ /* ============================================
4805
+ DEBUG TOOLTIP STYLES (Premium)
4806
+ ============================================ */
4807
+
4808
+ .has-debug-tooltip {
4809
+ cursor: help !important;
4810
+ }
4811
+
4812
+ .has-debug-tooltip::after {
4813
+ content: '\u{1F41B}';
4814
+ position: absolute;
4815
+ top: -4px;
4816
+ right: -4px;
4817
+ font-size: 10px;
4818
+ z-index: 1;
4819
+ }
4820
+
4821
+ .debug-tooltip-container {
4822
+ position: absolute;
4823
+ bottom: calc(100% + 8px);
4824
+ left: 50%;
4825
+ transform: translateX(-50%);
4826
+ z-index: 10000;
4827
+ pointer-events: none;
4828
+ opacity: 0;
4829
+ transition: opacity 0.2s ease, transform 0.2s ease;
4830
+ }
4831
+
4832
+ .has-debug-tooltip:hover .debug-tooltip-container {
4833
+ opacity: 1;
4834
+ pointer-events: auto;
4835
+ }
4836
+
4837
+ .debug-tooltip {
4838
+ background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
4839
+ border: 1px solid rgba(99, 102, 241, 0.3);
4840
+ border-radius: 12px;
4841
+ box-shadow:
4842
+ 0 20px 40px rgba(0, 0, 0, 0.4),
4843
+ 0 0 0 1px rgba(255, 255, 255, 0.05),
4844
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
4845
+ min-width: 340px;
4846
+ max-width: 420px;
4847
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
4848
+ font-size: 12px;
4849
+ color: #e2e8f0;
4850
+ overflow: hidden;
4851
+ }
4852
+
4853
+ .debug-tooltip__header {
4854
+ display: flex;
4855
+ align-items: center;
4856
+ gap: 8px;
4857
+ padding: 12px 16px;
4858
+ background: linear-gradient(90deg, rgba(99, 102, 241, 0.2) 0%, rgba(139, 92, 246, 0.1) 100%);
4859
+ border-bottom: 1px solid rgba(99, 102, 241, 0.2);
4860
+ }
4861
+
4862
+ .debug-tooltip__icon {
4863
+ font-size: 16px;
4864
+ }
4865
+
4866
+ .debug-tooltip__title {
4867
+ font-weight: 700;
4868
+ font-size: 13px;
4869
+ color: #f1f5f9;
4870
+ letter-spacing: 0.5px;
4871
+ text-transform: uppercase;
4872
+ }
4873
+
4874
+ .debug-tooltip__content {
4875
+ padding: 12px 16px;
4876
+ max-height: 400px;
4877
+ overflow-y: auto;
4878
+ }
4879
+
4880
+ .debug-tooltip__section {
4881
+ margin-bottom: 14px;
4882
+ padding-bottom: 12px;
4883
+ border-bottom: 1px solid rgba(148, 163, 184, 0.1);
4884
+ }
4885
+
4886
+ .debug-tooltip__section:last-child {
4887
+ margin-bottom: 0;
4888
+ padding-bottom: 0;
4889
+ border-bottom: none;
4890
+ }
4891
+
4892
+ .debug-tooltip__section-title {
4893
+ font-size: 11px;
4894
+ font-weight: 600;
4895
+ color: #94a3b8;
4896
+ text-transform: uppercase;
4897
+ letter-spacing: 0.8px;
4898
+ margin-bottom: 10px;
4899
+ display: flex;
4900
+ align-items: center;
4901
+ gap: 6px;
4902
+ }
4903
+
4904
+ .debug-tooltip__row {
4905
+ display: flex;
4906
+ justify-content: space-between;
4907
+ align-items: flex-start;
4908
+ padding: 4px 0;
4909
+ gap: 12px;
4910
+ }
4911
+
4912
+ .debug-tooltip__row--full {
4913
+ flex-direction: column;
4914
+ gap: 4px;
4915
+ }
4916
+
4917
+ .debug-tooltip__label {
4918
+ color: #94a3b8;
4919
+ font-size: 11px;
4920
+ flex-shrink: 0;
4921
+ }
4922
+
4923
+ .debug-tooltip__value {
4924
+ color: #f1f5f9;
4925
+ font-weight: 500;
4926
+ text-align: right;
4927
+ word-break: break-all;
4928
+ }
4929
+
4930
+ .debug-tooltip__row--full .debug-tooltip__value {
4931
+ text-align: left;
4932
+ background: rgba(0, 0, 0, 0.3);
4933
+ padding: 6px 10px;
4934
+ border-radius: 6px;
4935
+ font-size: 11px;
4936
+ width: 100%;
4937
+ box-sizing: border-box;
4938
+ }
4939
+
4940
+ .debug-tooltip__value--mono {
4941
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
4942
+ font-size: 11px;
4943
+ background: rgba(0, 0, 0, 0.3);
4944
+ padding: 2px 6px;
4945
+ border-radius: 4px;
4946
+ }
4947
+
4948
+ .debug-tooltip__value--highlight {
4949
+ color: #a5b4fc;
4950
+ font-style: italic;
4951
+ }
4952
+
4953
+ .debug-tooltip__badge {
4954
+ display: inline-block;
4955
+ padding: 2px 8px;
4956
+ border-radius: 4px;
4957
+ font-size: 10px;
4958
+ font-weight: 600;
4959
+ text-transform: uppercase;
4960
+ letter-spacing: 0.5px;
4961
+ background: rgba(99, 102, 241, 0.3);
4962
+ color: #a5b4fc;
4963
+ }
4964
+
4965
+ .debug-tooltip__badge--energy {
4966
+ background: rgba(59, 130, 246, 0.3);
4967
+ color: #93c5fd;
4968
+ }
4969
+
4970
+ .debug-tooltip__badge--water {
4971
+ background: rgba(6, 182, 212, 0.3);
4972
+ color: #67e8f9;
4973
+ }
4974
+
4975
+ .debug-tooltip__badge--temperature {
4976
+ background: rgba(249, 115, 22, 0.3);
4977
+ color: #fdba74;
4978
+ }
4979
+
4980
+ /* Tooltip arrow */
4981
+ .debug-tooltip::after {
4982
+ content: '';
4983
+ position: absolute;
4984
+ bottom: -6px;
4985
+ left: 50%;
4986
+ transform: translateX(-50%) rotate(45deg);
4987
+ width: 12px;
4988
+ height: 12px;
4989
+ background: #0f172a;
4990
+ border-right: 1px solid rgba(99, 102, 241, 0.3);
4991
+ border-bottom: 1px solid rgba(99, 102, 241, 0.3);
4992
+ }
4993
+
4994
+ /* Scrollbar styling for tooltip content */
4995
+ .debug-tooltip__content::-webkit-scrollbar {
4996
+ width: 6px;
4997
+ }
4998
+
4999
+ .debug-tooltip__content::-webkit-scrollbar-track {
5000
+ background: rgba(0, 0, 0, 0.2);
5001
+ border-radius: 3px;
5002
+ }
5003
+
5004
+ .debug-tooltip__content::-webkit-scrollbar-thumb {
5005
+ background: rgba(99, 102, 241, 0.4);
5006
+ border-radius: 3px;
5007
+ }
5008
+
5009
+ .debug-tooltip__content::-webkit-scrollbar-thumb:hover {
5010
+ background: rgba(99, 102, 241, 0.6);
5011
+ }
4682
5012
  `;
4683
5013
 
4684
5014
  // src/thingsboard/main-dashboard-shopping/v-4.0.0/head-office/card-head-office.icons.ts
@@ -4819,7 +5149,245 @@
4819
5149
  menu_settings: "Configura\xE7\xF5es"
4820
5150
  };
4821
5151
 
5152
+ // src/components/temperature/utils.ts
5153
+ var DAY_PERIODS = [
5154
+ { id: "madrugada", label: "Madrugada (00h-06h)", startHour: 0, endHour: 6 },
5155
+ { id: "manha", label: "Manh\xE3 (06h-12h)", startHour: 6, endHour: 12 },
5156
+ { id: "tarde", label: "Tarde (12h-18h)", startHour: 12, endHour: 18 },
5157
+ { id: "noite", label: "Noite (18h-24h)", startHour: 18, endHour: 24 }
5158
+ ];
5159
+ var DEFAULT_CLAMP_RANGE = { min: 15, max: 40 };
5160
+ function getTodaySoFar() {
5161
+ const now = /* @__PURE__ */ new Date();
5162
+ const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
5163
+ return {
5164
+ startTs: startOfDay.getTime(),
5165
+ endTs: now.getTime()
5166
+ };
5167
+ }
5168
+ var CHART_COLORS = [
5169
+ "#1976d2",
5170
+ // Blue
5171
+ "#FF6B6B",
5172
+ // Red
5173
+ "#4CAF50",
5174
+ // Green
5175
+ "#FF9800",
5176
+ // Orange
5177
+ "#9C27B0",
5178
+ // Purple
5179
+ "#00BCD4",
5180
+ // Cyan
5181
+ "#E91E63",
5182
+ // Pink
5183
+ "#795548"
5184
+ // Brown
5185
+ ];
5186
+ async function fetchTemperatureData(token, deviceId, startTs, endTs) {
5187
+ const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=temperature&startTs=${encodeURIComponent(startTs)}&endTs=${encodeURIComponent(endTs)}&limit=50000&agg=NONE`;
5188
+ const response = await fetch(url, {
5189
+ headers: {
5190
+ "X-Authorization": `Bearer ${token}`,
5191
+ "Content-Type": "application/json"
5192
+ }
5193
+ });
5194
+ if (!response.ok) {
5195
+ throw new Error(`Failed to fetch temperature data: ${response.status}`);
5196
+ }
5197
+ const data = await response.json();
5198
+ return data?.temperature || [];
5199
+ }
5200
+ function clampTemperature(value, range = DEFAULT_CLAMP_RANGE) {
5201
+ const num = Number(value || 0);
5202
+ if (num < range.min) return range.min;
5203
+ if (num > range.max) return range.max;
5204
+ return num;
5205
+ }
5206
+ function calculateStats(data, clampRange = DEFAULT_CLAMP_RANGE) {
5207
+ if (data.length === 0) {
5208
+ return { avg: 0, min: 0, max: 0, count: 0 };
5209
+ }
5210
+ const values = data.map((item) => clampTemperature(item.value, clampRange));
5211
+ const sum = values.reduce((acc, v) => acc + v, 0);
5212
+ return {
5213
+ avg: sum / values.length,
5214
+ min: Math.min(...values),
5215
+ max: Math.max(...values),
5216
+ count: values.length
5217
+ };
5218
+ }
5219
+ function interpolateTemperature(data, options) {
5220
+ const { intervalMinutes, startTs, endTs, clampRange = DEFAULT_CLAMP_RANGE } = options;
5221
+ const intervalMs = intervalMinutes * 60 * 1e3;
5222
+ if (data.length === 0) {
5223
+ return [];
5224
+ }
5225
+ const sortedData = [...data].sort((a, b) => a.ts - b.ts);
5226
+ const result = [];
5227
+ let lastKnownValue = clampTemperature(sortedData[0].value, clampRange);
5228
+ let dataIndex = 0;
5229
+ for (let ts = startTs; ts <= endTs; ts += intervalMs) {
5230
+ while (dataIndex < sortedData.length - 1 && sortedData[dataIndex + 1].ts <= ts) {
5231
+ dataIndex++;
5232
+ }
5233
+ const currentData = sortedData[dataIndex];
5234
+ if (currentData && Math.abs(currentData.ts - ts) < intervalMs) {
5235
+ lastKnownValue = clampTemperature(currentData.value, clampRange);
5236
+ }
5237
+ result.push({
5238
+ ts,
5239
+ value: lastKnownValue
5240
+ });
5241
+ }
5242
+ return result;
5243
+ }
5244
+ function aggregateByDay(data, clampRange = DEFAULT_CLAMP_RANGE) {
5245
+ if (data.length === 0) {
5246
+ return [];
5247
+ }
5248
+ const dayMap = /* @__PURE__ */ new Map();
5249
+ data.forEach((item) => {
5250
+ const date = new Date(item.ts);
5251
+ const dateKey = date.toISOString().split("T")[0];
5252
+ if (!dayMap.has(dateKey)) {
5253
+ dayMap.set(dateKey, []);
5254
+ }
5255
+ dayMap.get(dateKey).push(item);
5256
+ });
5257
+ const result = [];
5258
+ dayMap.forEach((dayData, dateKey) => {
5259
+ const values = dayData.map((item) => clampTemperature(item.value, clampRange));
5260
+ const sum = values.reduce((acc, v) => acc + v, 0);
5261
+ result.push({
5262
+ date: dateKey,
5263
+ dateTs: new Date(dateKey).getTime(),
5264
+ avg: sum / values.length,
5265
+ min: Math.min(...values),
5266
+ max: Math.max(...values),
5267
+ count: values.length
5268
+ });
5269
+ });
5270
+ return result.sort((a, b) => a.dateTs - b.dateTs);
5271
+ }
5272
+ function filterByDayPeriods(data, selectedPeriods) {
5273
+ if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
5274
+ return data;
5275
+ }
5276
+ return data.filter((item) => {
5277
+ const date = new Date(item.ts);
5278
+ const hour = date.getHours();
5279
+ return selectedPeriods.some((periodId) => {
5280
+ const period = DAY_PERIODS.find((p) => p.id === periodId);
5281
+ if (!period) return false;
5282
+ return hour >= period.startHour && hour < period.endHour;
5283
+ });
5284
+ });
5285
+ }
5286
+ function getSelectedPeriodsLabel(selectedPeriods) {
5287
+ if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
5288
+ return "Todos os per\xEDodos";
5289
+ }
5290
+ if (selectedPeriods.length === 1) {
5291
+ const period = DAY_PERIODS.find((p) => p.id === selectedPeriods[0]);
5292
+ return period?.label || "";
5293
+ }
5294
+ return `${selectedPeriods.length} per\xEDodos selecionados`;
5295
+ }
5296
+ function formatTemperature(value, decimals = 1) {
5297
+ if (value === null || value === void 0 || isNaN(value)) {
5298
+ return "\u2014";
5299
+ }
5300
+ return `${value.toFixed(decimals)}\xB0C`;
5301
+ }
5302
+ function exportTemperatureCSV(data, deviceLabel, stats, startDate, endDate) {
5303
+ if (data.length === 0) {
5304
+ console.warn("No data to export");
5305
+ return;
5306
+ }
5307
+ const BOM = "\uFEFF";
5308
+ let csvContent = BOM;
5309
+ csvContent += `Relat\xF3rio de Temperatura - ${deviceLabel}
5310
+ `;
5311
+ csvContent += `Per\xEDodo: ${startDate} at\xE9 ${endDate}
5312
+ `;
5313
+ csvContent += `M\xE9dia: ${formatTemperature(stats.avg)}
5314
+ `;
5315
+ csvContent += `M\xEDnima: ${formatTemperature(stats.min)}
5316
+ `;
5317
+ csvContent += `M\xE1xima: ${formatTemperature(stats.max)}
5318
+ `;
5319
+ csvContent += `Total de leituras: ${stats.count}
5320
+ `;
5321
+ csvContent += "\n";
5322
+ csvContent += "Data/Hora,Temperatura (\xB0C)\n";
5323
+ data.forEach((item) => {
5324
+ const date = new Date(item.ts).toLocaleString("pt-BR");
5325
+ const temp = Number(item.value).toFixed(2);
5326
+ csvContent += `"${date}",${temp}
5327
+ `;
5328
+ });
5329
+ const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
5330
+ const url = URL.createObjectURL(blob);
5331
+ const link = document.createElement("a");
5332
+ link.href = url;
5333
+ link.download = `temperatura_${deviceLabel.replace(/\s+/g, "_")}_${startDate}_${endDate}.csv`;
5334
+ document.body.appendChild(link);
5335
+ link.click();
5336
+ document.body.removeChild(link);
5337
+ URL.revokeObjectURL(url);
5338
+ }
5339
+ var DARK_THEME = {
5340
+ background: "rgba(0, 0, 0, 0.85)",
5341
+ surface: "#1a1f28",
5342
+ text: "#ffffff",
5343
+ textMuted: "rgba(255, 255, 255, 0.7)",
5344
+ border: "rgba(255, 255, 255, 0.1)",
5345
+ primary: "#1976d2",
5346
+ success: "#4CAF50",
5347
+ warning: "#FF9800",
5348
+ danger: "#f44336",
5349
+ chartLine: "#1976d2",
5350
+ chartGrid: "rgba(255, 255, 255, 0.1)"
5351
+ };
5352
+ var LIGHT_THEME = {
5353
+ background: "rgba(0, 0, 0, 0.6)",
5354
+ surface: "#ffffff",
5355
+ text: "#333333",
5356
+ textMuted: "#666666",
5357
+ border: "#e0e0e0",
5358
+ primary: "#1976d2",
5359
+ success: "#4CAF50",
5360
+ warning: "#FF9800",
5361
+ danger: "#f44336",
5362
+ chartLine: "#1976d2",
5363
+ chartGrid: "#e0e0e0"
5364
+ };
5365
+ function getThemeColors(theme) {
5366
+ return theme === "dark" ? DARK_THEME : LIGHT_THEME;
5367
+ }
5368
+
5369
+ // src/utils/logHelper.js
5370
+ function createLogHelper(debugActive = false) {
5371
+ return {
5372
+ log: function(...args) {
5373
+ if (debugActive) {
5374
+ console.log(...args);
5375
+ }
5376
+ },
5377
+ warn: function(...args) {
5378
+ if (debugActive) {
5379
+ console.warn(...args);
5380
+ }
5381
+ },
5382
+ error: function(...args) {
5383
+ console.error(...args);
5384
+ }
5385
+ };
5386
+ }
5387
+
4822
5388
  // src/thingsboard/main-dashboard-shopping/v-4.0.0/card/head-office/card-head-office.js
5389
+ var LABEL_CHAR_LIMIT = 18;
5390
+ var DEFAUL_DELAY_TIME_CONNECTION_IN_MINS = 1440;
4823
5391
  var CSS_TAG = "head-office-card-v1";
4824
5392
  function ensureCss() {
4825
5393
  if (!document.querySelector(`style[data-myio-css="${CSS_TAG}"]`)) {
@@ -4833,11 +5401,17 @@
4833
5401
  if (!params || !params.entityObject) {
4834
5402
  throw new Error("renderCardCompenteHeadOffice: entityObject is required");
4835
5403
  }
5404
+ const LogHelper2 = createLogHelper(params.debugActive ?? false);
4836
5405
  const entityObject = params.entityObject;
4837
5406
  if (!entityObject.entityId) {
4838
- console.warn("renderCardCompenteHeadOffice: entityId is missing, generating temporary ID");
5407
+ LogHelper2.warn("[CardHeadOffice] entityId is missing, generating temporary ID");
4839
5408
  entityObject.entityId = `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
4840
5409
  }
5410
+ if (!params.delayTimeConnectionInMins) {
5411
+ LogHelper2.warn(
5412
+ `[CardHeadOffice] delayTimeConnectionInMins is missing, defaulting to ${DEFAUL_DELAY_TIME_CONNECTION_IN_MINS} mins`
5413
+ );
5414
+ }
4841
5415
  return {
4842
5416
  entityObject,
4843
5417
  i18n: { ...DEFAULT_I18N, ...params.i18n || {} },
@@ -4845,7 +5419,12 @@
4845
5419
  enableDragDrop: Boolean(params.enableDragDrop),
4846
5420
  useNewComponents: Boolean(params.useNewComponents),
4847
5421
  // RFC-0091: Configurable delay time for connection status check (default 15 minutes)
4848
- delayTimeConnectionInMins: params.delayTimeConnectionInMins ?? 15,
5422
+ delayTimeConnectionInMins: params.delayTimeConnectionInMins ?? DEFAUL_DELAY_TIME_CONNECTION_IN_MINS,
5423
+ // Debug options
5424
+ debugActive: params.debugActive ?? false,
5425
+ activeTooltipDebug: params.activeTooltipDebug ?? false,
5426
+ // LogHelper instance for this card
5427
+ LogHelper: LogHelper2,
4849
5428
  callbacks: {
4850
5429
  handleActionDashboard: params.handleActionDashboard,
4851
5430
  handleActionReport: params.handleActionReport,
@@ -4883,16 +5462,10 @@
4883
5462
  return formatWaterVolumeM3(value);
4884
5463
  }
4885
5464
  if (domain === "temperature") {
4886
- return formatTemperature(value);
5465
+ return formatTemperature(value, 0);
4887
5466
  }
4888
5467
  return formatEnergy(value);
4889
5468
  }
4890
- function formatTemperature(temp) {
4891
- if (temp === null || temp === void 0 || isNaN(temp)) {
4892
- return "\u2014";
4893
- }
4894
- return `${temp.toFixed(0)}\xB0C`;
4895
- }
4896
5469
  function calculateConsumptionPercentage(target, consumption) {
4897
5470
  const numericTarget = Number(target);
4898
5471
  const numericConsumption = Number(consumption);
@@ -4907,32 +5480,32 @@
4907
5480
  // --- Novos Status de Temperatura ---
4908
5481
  case "normal":
4909
5482
  return { chipClass: "chip--ok", label: "Normal" };
4910
- // Verde/Azul
4911
5483
  case "cold":
4912
5484
  return { chipClass: "chip--standby", label: "Frio" };
4913
- // Azul claro/Ciano
4914
5485
  case "hot":
4915
5486
  return { chipClass: "chip--alert", label: "Quente" };
4916
- // Laranja/Amarelo
4917
- // --- Status Existentes ---
5487
+ // --- Status Existentes (aligned with getCardStateClass) ---
4918
5488
  case DeviceStatusType.POWER_ON:
4919
5489
  if (domain === "water") {
4920
- return { chipClass: "chip--ok", label: i18n.in_operation_water };
5490
+ return { chipClass: "chip--power-on", label: i18n.in_operation_water };
4921
5491
  }
4922
- return { chipClass: "chip--ok", label: i18n.in_operation };
5492
+ return { chipClass: "chip--power-on", label: i18n.in_operation };
4923
5493
  case DeviceStatusType.STANDBY:
4924
5494
  return { chipClass: "chip--standby", label: i18n.standby };
4925
5495
  case DeviceStatusType.WARNING:
4926
- return { chipClass: "chip--alert", label: i18n.alert };
5496
+ return { chipClass: "chip--warning", label: i18n.alert };
5497
+ case DeviceStatusType.MAINTENANCE:
5498
+ return { chipClass: "chip--maintenance", label: i18n.maintenance };
4927
5499
  case DeviceStatusType.FAILURE:
4928
- case DeviceStatusType.POWER_OFF:
4929
5500
  return { chipClass: "chip--failure", label: i18n.failure };
4930
- case DeviceStatusType.MAINTENANCE:
4931
- return { chipClass: "chip--alert", label: i18n.maintenance };
4932
- case DeviceStatusType.NOT_INSTALLED:
4933
- return { chipClass: "chip--offline", label: i18n.not_installed };
4934
- // Default (Cai aqui se não achar 'normal', 'hot' etc)
5501
+ case DeviceStatusType.POWER_OFF:
5502
+ return { chipClass: "chip--power-off", label: i18n.power_off || i18n.failure };
5503
+ case DeviceStatusType.OFFLINE:
5504
+ return { chipClass: "chip--offline", label: i18n.offline };
4935
5505
  case DeviceStatusType.NO_INFO:
5506
+ return { chipClass: "chip--no-info", label: i18n.no_info || i18n.offline };
5507
+ case DeviceStatusType.NOT_INSTALLED:
5508
+ return { chipClass: "chip--not-installed", label: i18n.not_installed };
4936
5509
  default:
4937
5510
  return { chipClass: "chip--offline", label: i18n.offline };
4938
5511
  }
@@ -4940,23 +5513,32 @@
4940
5513
  function getCardStateClass(deviceStatus) {
4941
5514
  switch (deviceStatus) {
4942
5515
  case DeviceStatusType.POWER_ON:
4943
- return "is-ok";
5516
+ return "is-power-on";
4944
5517
  // Blue border
4945
5518
  case DeviceStatusType.STANDBY:
4946
5519
  return "is-standby";
4947
5520
  // Green border
4948
5521
  case DeviceStatusType.WARNING:
5522
+ return "is-warning";
5523
+ // Yellow border
4949
5524
  case DeviceStatusType.MAINTENANCE:
4950
- return "is-alert";
5525
+ return "is-maintenance";
4951
5526
  // Yellow border
4952
5527
  case DeviceStatusType.FAILURE:
4953
- case DeviceStatusType.POWER_OFF:
4954
5528
  return "is-failure";
4955
- // Red border
5529
+ // Dark Red border
5530
+ case DeviceStatusType.POWER_OFF:
5531
+ return "is-power-off";
5532
+ // Light Red border
5533
+ case DeviceStatusType.OFFLINE:
5534
+ return "is-offline";
5535
+ // Dark Gray border
4956
5536
  case DeviceStatusType.NO_INFO:
5537
+ return "is-no-info";
5538
+ // Dark Orange border
4957
5539
  case DeviceStatusType.NOT_INSTALLED:
4958
- return "is-offline";
4959
- // Gray border
5540
+ return "is-not-installed";
5541
+ // Purple border
4960
5542
  default:
4961
5543
  return "";
4962
5544
  }
@@ -4970,17 +5552,25 @@
4970
5552
  return "dot--standby";
4971
5553
  case "hot":
4972
5554
  return "dot--alert";
4973
- // --- Status Existentes ---
5555
+ // --- Status Existentes (aligned with getCardStateClass) ---
4974
5556
  case DeviceStatusType.POWER_ON:
4975
- return "dot--ok";
5557
+ return "dot--power-on";
4976
5558
  case DeviceStatusType.STANDBY:
4977
5559
  return "dot--standby";
4978
5560
  case DeviceStatusType.WARNING:
5561
+ return "dot--warning";
4979
5562
  case DeviceStatusType.MAINTENANCE:
4980
- return "dot--alert";
5563
+ return "dot--maintenance";
4981
5564
  case DeviceStatusType.FAILURE:
4982
- case DeviceStatusType.POWER_OFF:
4983
5565
  return "dot--failure";
5566
+ case DeviceStatusType.POWER_OFF:
5567
+ return "dot--power-off";
5568
+ case DeviceStatusType.OFFLINE:
5569
+ return "dot--offline";
5570
+ case DeviceStatusType.NO_INFO:
5571
+ return "dot--no-info";
5572
+ case DeviceStatusType.NOT_INSTALLED:
5573
+ return "dot--not-installed";
4984
5574
  default:
4985
5575
  return "dot--offline";
4986
5576
  }
@@ -5004,7 +5594,13 @@
5004
5594
  titleSection.className = "myio-ho-card__title";
5005
5595
  const nameEl = document.createElement("div");
5006
5596
  nameEl.className = "myio-ho-card__name";
5007
- nameEl.textContent = entityObject.labelOrName || "Unknown Device";
5597
+ const fullName = entityObject.labelOrName || "Unknown Device";
5598
+ if (fullName.length > LABEL_CHAR_LIMIT) {
5599
+ nameEl.textContent = fullName.slice(0, LABEL_CHAR_LIMIT) + "\u2026";
5600
+ nameEl.title = fullName;
5601
+ } else {
5602
+ nameEl.textContent = fullName;
5603
+ }
5008
5604
  titleSection.appendChild(nameEl);
5009
5605
  if (entityObject.deviceIdentifier) {
5010
5606
  const codeEl = document.createElement("div");
@@ -5133,29 +5729,207 @@
5133
5729
  root.appendChild(footer);
5134
5730
  return root;
5135
5731
  }
5136
- function verifyOfflineStatus(entityObject, delayTimeInMins = 15) {
5732
+ function buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins) {
5733
+ const formatTimestamp = (ts) => {
5734
+ if (!ts) return "N/A";
5735
+ const d = new Date(ts);
5736
+ return d.toLocaleString("pt-BR", {
5737
+ day: "2-digit",
5738
+ month: "2-digit",
5739
+ year: "numeric",
5740
+ hour: "2-digit",
5741
+ minute: "2-digit",
5742
+ second: "2-digit"
5743
+ });
5744
+ };
5745
+ return {
5746
+ // Entity identification
5747
+ entityId: entityObject.entityId || "N/A",
5748
+ name: entityObject.name || entityObject.nameEl || "N/A",
5749
+ domain: entityObject.domain || "energy",
5750
+ // Status decision chain
5751
+ originalDeviceStatus: entityObject._originalDeviceStatus || entityObject.deviceStatus,
5752
+ finalDeviceStatus: entityObject.deviceStatus,
5753
+ connectionStatus: entityObject.connectionStatus || "N/A",
5754
+ statusDecisionSource,
5755
+ // Visual output
5756
+ stateClass,
5757
+ chipClass: statusInfo.chipClass,
5758
+ chipLabel: statusInfo.label,
5759
+ // Connection timestamps
5760
+ lastConnectTime: formatTimestamp(entityObject.lastConnectTime),
5761
+ lastDisconnectTime: formatTimestamp(entityObject.lastDisconnectTime),
5762
+ delayTimeConnectionInMins,
5763
+ // Raw values
5764
+ val: entityObject.val,
5765
+ consumptionTargetValue: entityObject.consumptionTargetValue,
5766
+ deviceType: entityObject.deviceType || "N/A"
5767
+ };
5768
+ }
5769
+ function attachDebugTooltip(element, debugInfo) {
5770
+ const existingTooltip = element.querySelector(".debug-tooltip-container");
5771
+ if (existingTooltip) {
5772
+ existingTooltip.remove();
5773
+ }
5774
+ const tooltipContainer = document.createElement("div");
5775
+ tooltipContainer.className = "debug-tooltip-container";
5776
+ const tooltip = document.createElement("div");
5777
+ tooltip.className = "debug-tooltip";
5778
+ tooltip.innerHTML = `
5779
+ <div class="debug-tooltip__header">
5780
+ <span class="debug-tooltip__icon">\u{1F50D}</span>
5781
+ <span class="debug-tooltip__title">Debug Info</span>
5782
+ </div>
5783
+ <div class="debug-tooltip__content">
5784
+ <div class="debug-tooltip__section">
5785
+ <div class="debug-tooltip__section-title">\u{1F4CB} Identifica\xE7\xE3o</div>
5786
+ <div class="debug-tooltip__row">
5787
+ <span class="debug-tooltip__label">Entity ID:</span>
5788
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.entityId}</span>
5789
+ </div>
5790
+ <div class="debug-tooltip__row">
5791
+ <span class="debug-tooltip__label">Nome:</span>
5792
+ <span class="debug-tooltip__value">${debugInfo.name}</span>
5793
+ </div>
5794
+ <div class="debug-tooltip__row">
5795
+ <span class="debug-tooltip__label">Dom\xEDnio:</span>
5796
+ <span class="debug-tooltip__value debug-tooltip__badge debug-tooltip__badge--${debugInfo.domain}">${debugInfo.domain}</span>
5797
+ </div>
5798
+ </div>
5799
+
5800
+ <div class="debug-tooltip__section">
5801
+ <div class="debug-tooltip__section-title">\u26A1 Decis\xE3o de Status</div>
5802
+ <div class="debug-tooltip__row">
5803
+ <span class="debug-tooltip__label">connectionStatus:</span>
5804
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.connectionStatus}</span>
5805
+ </div>
5806
+ <div class="debug-tooltip__row">
5807
+ <span class="debug-tooltip__label">deviceStatus (final):</span>
5808
+ <span class="debug-tooltip__value debug-tooltip__badge">${debugInfo.finalDeviceStatus}</span>
5809
+ </div>
5810
+ <div class="debug-tooltip__row debug-tooltip__row--full">
5811
+ <span class="debug-tooltip__label">Fonte da decis\xE3o:</span>
5812
+ <span class="debug-tooltip__value debug-tooltip__value--highlight">${debugInfo.statusDecisionSource}</span>
5813
+ </div>
5814
+ </div>
5815
+
5816
+ <div class="debug-tooltip__section">
5817
+ <div class="debug-tooltip__section-title">\u{1F3A8} Output Visual</div>
5818
+ <div class="debug-tooltip__row">
5819
+ <span class="debug-tooltip__label">stateClass:</span>
5820
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.stateClass}</span>
5821
+ </div>
5822
+ <div class="debug-tooltip__row">
5823
+ <span class="debug-tooltip__label">chipClass:</span>
5824
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.chipClass}</span>
5825
+ </div>
5826
+ <div class="debug-tooltip__row">
5827
+ <span class="debug-tooltip__label">chipLabel:</span>
5828
+ <span class="debug-tooltip__value">${debugInfo.chipLabel}</span>
5829
+ </div>
5830
+ </div>
5831
+
5832
+ <div class="debug-tooltip__section">
5833
+ <div class="debug-tooltip__section-title">\u{1F550} Timestamps de Conex\xE3o</div>
5834
+ <div class="debug-tooltip__row">
5835
+ <span class="debug-tooltip__label">lastConnectTime:</span>
5836
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.lastConnectTime}</span>
5837
+ </div>
5838
+ <div class="debug-tooltip__row">
5839
+ <span class="debug-tooltip__label">lastDisconnectTime:</span>
5840
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.lastDisconnectTime}</span>
5841
+ </div>
5842
+ <div class="debug-tooltip__row">
5843
+ <span class="debug-tooltip__label">delayTime:</span>
5844
+ <span class="debug-tooltip__value">${debugInfo.delayTimeConnectionInMins} mins</span>
5845
+ </div>
5846
+ </div>
5847
+
5848
+ <div class="debug-tooltip__section">
5849
+ <div class="debug-tooltip__section-title">\u{1F4CA} Valores</div>
5850
+ <div class="debug-tooltip__row">
5851
+ <span class="debug-tooltip__label">val (consumo):</span>
5852
+ <span class="debug-tooltip__value">${debugInfo.val ?? "N/A"}</span>
5853
+ </div>
5854
+ <div class="debug-tooltip__row">
5855
+ <span class="debug-tooltip__label">target (meta):</span>
5856
+ <span class="debug-tooltip__value">${debugInfo.consumptionTargetValue ?? "N/A"}</span>
5857
+ </div>
5858
+ <div class="debug-tooltip__row">
5859
+ <span class="debug-tooltip__label">deviceType:</span>
5860
+ <span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.deviceType}</span>
5861
+ </div>
5862
+ </div>
5863
+ </div>
5864
+ `;
5865
+ tooltipContainer.appendChild(tooltip);
5866
+ element.style.position = "relative";
5867
+ element.style.cursor = "help";
5868
+ element.appendChild(tooltipContainer);
5869
+ element.classList.add("has-debug-tooltip");
5870
+ }
5871
+ function verifyOfflineStatus(entityObject, delayTimeInMins = 15, LogHelper2) {
5137
5872
  const lastConnectionTime = new Date(entityObject.lastConnectTime || 0);
5138
5873
  const lastDisconnectTime = new Date(entityObject.lastDisconnectTime || 0);
5139
5874
  const now = /* @__PURE__ */ new Date();
5140
5875
  const delayTimeInMs = delayTimeInMins * 60 * 1e3;
5141
5876
  const timeSinceConnection = now.getTime() - lastConnectionTime.getTime();
5877
+ let isOffline = false;
5142
5878
  if (lastDisconnectTime.getTime() > lastConnectionTime.getTime()) {
5143
- return false;
5144
- }
5145
- if (timeSinceConnection < delayTimeInMs) {
5146
- return false;
5879
+ isOffline = true;
5880
+ LogHelper2.log(
5881
+ "[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastDisconnectTime is more recent than lastConnectTime",
5882
+ entityObject.nameEl
5883
+ );
5884
+ } else if (timeSinceConnection > delayTimeInMs) {
5885
+ isOffline = true;
5886
+ LogHelper2.log(
5887
+ "[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastConnectTime is older than configured delayTimeConnectionInMins:",
5888
+ delayTimeInMins,
5889
+ "for device",
5890
+ entityObject.nameEl
5891
+ );
5892
+ } else {
5893
+ isOffline = false;
5894
+ LogHelper2.log(
5895
+ "[CardHeadOffice][ConnectionStatus Verify] Device is ONLINE because lastConnectTime is within configured delayTimeConnectionInMins:",
5896
+ delayTimeInMins,
5897
+ "for device",
5898
+ entityObject.nameEl
5899
+ );
5147
5900
  }
5148
- return true;
5901
+ return isOffline;
5149
5902
  }
5150
5903
  function paint(root, state) {
5151
- const { entityObject, i18n, delayTimeConnectionInMins, isSelected } = state;
5904
+ const { entityObject, i18n, delayTimeConnectionInMins, isSelected, LogHelper: LogHelper2, activeTooltipDebug } = state;
5905
+ let statusDecisionSource = "unknown";
5152
5906
  if (entityObject.connectionStatus) {
5153
5907
  if (entityObject.connectionStatus === "offline") {
5154
- entityObject.deviceStatus = DeviceStatusType.NO_INFO;
5908
+ LogHelper2.log(
5909
+ "[CardHeadOffice][ConnectionStatus Verify 01] Setting deviceStatus to OFFLINE based on connectionStatus"
5910
+ );
5911
+ entityObject.deviceStatus = DeviceStatusType.OFFLINE;
5912
+ statusDecisionSource = 'connectionStatus === "offline"';
5913
+ } else {
5914
+ LogHelper2.log(
5915
+ "[CardHeadOffice] Device is ONLINE or WAITING based on connectionStatus for device",
5916
+ entityObject.nameEl
5917
+ );
5918
+ statusDecisionSource = `connectionStatus === "${entityObject.connectionStatus}" (kept original deviceStatus)`;
5155
5919
  }
5156
5920
  } else {
5157
- if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins) === false) {
5158
- entityObject.deviceStatus = DeviceStatusType.NO_INFO;
5921
+ if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins, LogHelper2) === false) {
5922
+ LogHelper2.log(
5923
+ "[CardHeadOffice][ConnectionStatus Verify 02] Setting deviceStatus to OFFLINE based on timestamp verification by verifyOfflineStatus METHOD with delayTimeConnectionInMins:",
5924
+ delayTimeConnectionInMins
5925
+ );
5926
+ entityObject.deviceStatus = DeviceStatusType.OFFLINE;
5927
+ statusDecisionSource = `verifyOfflineStatus() returned false (delay: ${delayTimeConnectionInMins} mins)`;
5928
+ } else {
5929
+ LogHelper2.log(
5930
+ `[CardHeadOffice][ConnectionStatus Verify 03] Device is ONLINE with deviceStatus = ${entityObject.deviceStatus} based on timestamp verification for device ${entityObject.nameEl}`
5931
+ );
5932
+ statusDecisionSource = `verifyOfflineStatus() returned true (delay: ${delayTimeConnectionInMins} mins)`;
5159
5933
  }
5160
5934
  }
5161
5935
  const stateClass = getCardStateClass(entityObject.deviceStatus);
@@ -5164,6 +5938,10 @@
5164
5938
  const chip = root.querySelector(".chip");
5165
5939
  chip.className = `chip ${statusInfo.chipClass}`;
5166
5940
  chip.innerHTML = statusInfo.label;
5941
+ if (activeTooltipDebug) {
5942
+ const debugInfo = buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins);
5943
+ attachDebugTooltip(chip, debugInfo);
5944
+ }
5167
5945
  const primaryValue = formatValueByDomain(entityObject.val, entityObject.domain);
5168
5946
  const numSpan = root.querySelector(".myio-ho-card__value .num");
5169
5947
  root.querySelector(".myio-ho-card__value .unit");
@@ -5376,6 +6154,7 @@
5376
6154
  }
5377
6155
 
5378
6156
  // src/thingsboard/main-dashboard-shopping/v-5.2.0/card/template-card-v5.js
6157
+ var LABEL_CHAR_LIMIT2 = 18;
5379
6158
  function renderCardComponentV5({
5380
6159
  entityObject,
5381
6160
  handleActionDashboard,
@@ -5892,7 +6671,7 @@ ${rangeText}`;
5892
6671
 
5893
6672
  <div class="device-title-row" style="flex-direction: column; min-height: 38px; text-align: center; width: 100%;">
5894
6673
  <span class="device-title" title="${cardEntity.name}">
5895
- ${cardEntity.name.length > 18 ? cardEntity.name.slice(0, 18) + "\u2026" : cardEntity.name}
6674
+ ${cardEntity.name.length > LABEL_CHAR_LIMIT2 ? cardEntity.name.slice(0, LABEL_CHAR_LIMIT2) + "\u2026" : cardEntity.name}
5896
6675
  </span>
5897
6676
  ${deviceIdentifier ? `
5898
6677
  <span class="device-subtitle" title="${deviceIdentifier}">
@@ -20045,220 +20824,6 @@ ${rangeText}`;
20045
20824
  }
20046
20825
  }
20047
20826
 
20048
- // src/components/temperature/utils.ts
20049
- var DAY_PERIODS = [
20050
- { id: "madrugada", label: "Madrugada (00h-06h)", startHour: 0, endHour: 6 },
20051
- { id: "manha", label: "Manh\xE3 (06h-12h)", startHour: 6, endHour: 12 },
20052
- { id: "tarde", label: "Tarde (12h-18h)", startHour: 12, endHour: 18 },
20053
- { id: "noite", label: "Noite (18h-24h)", startHour: 18, endHour: 24 }
20054
- ];
20055
- var DEFAULT_CLAMP_RANGE = { min: 15, max: 40 };
20056
- function getTodaySoFar() {
20057
- const now = /* @__PURE__ */ new Date();
20058
- const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
20059
- return {
20060
- startTs: startOfDay.getTime(),
20061
- endTs: now.getTime()
20062
- };
20063
- }
20064
- var CHART_COLORS = [
20065
- "#1976d2",
20066
- // Blue
20067
- "#FF6B6B",
20068
- // Red
20069
- "#4CAF50",
20070
- // Green
20071
- "#FF9800",
20072
- // Orange
20073
- "#9C27B0",
20074
- // Purple
20075
- "#00BCD4",
20076
- // Cyan
20077
- "#E91E63",
20078
- // Pink
20079
- "#795548"
20080
- // Brown
20081
- ];
20082
- async function fetchTemperatureData(token, deviceId, startTs, endTs) {
20083
- const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=temperature&startTs=${encodeURIComponent(startTs)}&endTs=${encodeURIComponent(endTs)}&limit=50000&agg=NONE`;
20084
- const response = await fetch(url, {
20085
- headers: {
20086
- "X-Authorization": `Bearer ${token}`,
20087
- "Content-Type": "application/json"
20088
- }
20089
- });
20090
- if (!response.ok) {
20091
- throw new Error(`Failed to fetch temperature data: ${response.status}`);
20092
- }
20093
- const data = await response.json();
20094
- return data?.temperature || [];
20095
- }
20096
- function clampTemperature(value, range = DEFAULT_CLAMP_RANGE) {
20097
- const num = Number(value || 0);
20098
- if (num < range.min) return range.min;
20099
- if (num > range.max) return range.max;
20100
- return num;
20101
- }
20102
- function calculateStats(data, clampRange = DEFAULT_CLAMP_RANGE) {
20103
- if (data.length === 0) {
20104
- return { avg: 0, min: 0, max: 0, count: 0 };
20105
- }
20106
- const values = data.map((item) => clampTemperature(item.value, clampRange));
20107
- const sum = values.reduce((acc, v) => acc + v, 0);
20108
- return {
20109
- avg: sum / values.length,
20110
- min: Math.min(...values),
20111
- max: Math.max(...values),
20112
- count: values.length
20113
- };
20114
- }
20115
- function interpolateTemperature(data, options) {
20116
- const { intervalMinutes, startTs, endTs, clampRange = DEFAULT_CLAMP_RANGE } = options;
20117
- const intervalMs = intervalMinutes * 60 * 1e3;
20118
- if (data.length === 0) {
20119
- return [];
20120
- }
20121
- const sortedData = [...data].sort((a, b) => a.ts - b.ts);
20122
- const result = [];
20123
- let lastKnownValue = clampTemperature(sortedData[0].value, clampRange);
20124
- let dataIndex = 0;
20125
- for (let ts = startTs; ts <= endTs; ts += intervalMs) {
20126
- while (dataIndex < sortedData.length - 1 && sortedData[dataIndex + 1].ts <= ts) {
20127
- dataIndex++;
20128
- }
20129
- const currentData = sortedData[dataIndex];
20130
- if (currentData && Math.abs(currentData.ts - ts) < intervalMs) {
20131
- lastKnownValue = clampTemperature(currentData.value, clampRange);
20132
- }
20133
- result.push({
20134
- ts,
20135
- value: lastKnownValue
20136
- });
20137
- }
20138
- return result;
20139
- }
20140
- function aggregateByDay(data, clampRange = DEFAULT_CLAMP_RANGE) {
20141
- if (data.length === 0) {
20142
- return [];
20143
- }
20144
- const dayMap = /* @__PURE__ */ new Map();
20145
- data.forEach((item) => {
20146
- const date = new Date(item.ts);
20147
- const dateKey = date.toISOString().split("T")[0];
20148
- if (!dayMap.has(dateKey)) {
20149
- dayMap.set(dateKey, []);
20150
- }
20151
- dayMap.get(dateKey).push(item);
20152
- });
20153
- const result = [];
20154
- dayMap.forEach((dayData, dateKey) => {
20155
- const values = dayData.map((item) => clampTemperature(item.value, clampRange));
20156
- const sum = values.reduce((acc, v) => acc + v, 0);
20157
- result.push({
20158
- date: dateKey,
20159
- dateTs: new Date(dateKey).getTime(),
20160
- avg: sum / values.length,
20161
- min: Math.min(...values),
20162
- max: Math.max(...values),
20163
- count: values.length
20164
- });
20165
- });
20166
- return result.sort((a, b) => a.dateTs - b.dateTs);
20167
- }
20168
- function filterByDayPeriods(data, selectedPeriods) {
20169
- if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
20170
- return data;
20171
- }
20172
- return data.filter((item) => {
20173
- const date = new Date(item.ts);
20174
- const hour = date.getHours();
20175
- return selectedPeriods.some((periodId) => {
20176
- const period = DAY_PERIODS.find((p) => p.id === periodId);
20177
- if (!period) return false;
20178
- return hour >= period.startHour && hour < period.endHour;
20179
- });
20180
- });
20181
- }
20182
- function getSelectedPeriodsLabel(selectedPeriods) {
20183
- if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
20184
- return "Todos os per\xEDodos";
20185
- }
20186
- if (selectedPeriods.length === 1) {
20187
- const period = DAY_PERIODS.find((p) => p.id === selectedPeriods[0]);
20188
- return period?.label || "";
20189
- }
20190
- return `${selectedPeriods.length} per\xEDodos selecionados`;
20191
- }
20192
- function formatTemperature2(value, decimals = 1) {
20193
- return `${value.toFixed(decimals)}\xB0C`;
20194
- }
20195
- function exportTemperatureCSV(data, deviceLabel, stats, startDate, endDate) {
20196
- if (data.length === 0) {
20197
- console.warn("No data to export");
20198
- return;
20199
- }
20200
- const BOM = "\uFEFF";
20201
- let csvContent = BOM;
20202
- csvContent += `Relat\xF3rio de Temperatura - ${deviceLabel}
20203
- `;
20204
- csvContent += `Per\xEDodo: ${startDate} at\xE9 ${endDate}
20205
- `;
20206
- csvContent += `M\xE9dia: ${formatTemperature2(stats.avg)}
20207
- `;
20208
- csvContent += `M\xEDnima: ${formatTemperature2(stats.min)}
20209
- `;
20210
- csvContent += `M\xE1xima: ${formatTemperature2(stats.max)}
20211
- `;
20212
- csvContent += `Total de leituras: ${stats.count}
20213
- `;
20214
- csvContent += "\n";
20215
- csvContent += "Data/Hora,Temperatura (\xB0C)\n";
20216
- data.forEach((item) => {
20217
- const date = new Date(item.ts).toLocaleString("pt-BR");
20218
- const temp = Number(item.value).toFixed(2);
20219
- csvContent += `"${date}",${temp}
20220
- `;
20221
- });
20222
- const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
20223
- const url = URL.createObjectURL(blob);
20224
- const link = document.createElement("a");
20225
- link.href = url;
20226
- link.download = `temperatura_${deviceLabel.replace(/\s+/g, "_")}_${startDate}_${endDate}.csv`;
20227
- document.body.appendChild(link);
20228
- link.click();
20229
- document.body.removeChild(link);
20230
- URL.revokeObjectURL(url);
20231
- }
20232
- var DARK_THEME = {
20233
- background: "rgba(0, 0, 0, 0.85)",
20234
- surface: "#1a1f28",
20235
- text: "#ffffff",
20236
- textMuted: "rgba(255, 255, 255, 0.7)",
20237
- border: "rgba(255, 255, 255, 0.1)",
20238
- primary: "#1976d2",
20239
- success: "#4CAF50",
20240
- warning: "#FF9800",
20241
- danger: "#f44336",
20242
- chartLine: "#1976d2",
20243
- chartGrid: "rgba(255, 255, 255, 0.1)"
20244
- };
20245
- var LIGHT_THEME = {
20246
- background: "rgba(0, 0, 0, 0.6)",
20247
- surface: "#ffffff",
20248
- text: "#333333",
20249
- textMuted: "#666666",
20250
- border: "#e0e0e0",
20251
- primary: "#1976d2",
20252
- success: "#4CAF50",
20253
- warning: "#FF9800",
20254
- danger: "#f44336",
20255
- chartLine: "#1976d2",
20256
- chartGrid: "#e0e0e0"
20257
- };
20258
- function getThemeColors(theme) {
20259
- return theme === "dark" ? DARK_THEME : LIGHT_THEME;
20260
- }
20261
-
20262
20827
  // src/components/temperature/TemperatureModal.ts
20263
20828
  async function openTemperatureModal(params) {
20264
20829
  const modalId = `myio-temp-modal-${Date.now()}`;
@@ -20498,7 +21063,7 @@ ${rangeText}`;
20498
21063
  ">
20499
21064
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Temperatura Atual</span>
20500
21065
  <div style="font-weight: 700; font-size: 24px; color: ${statusColor}; margin-top: 4px;">
20501
- ${state.currentTemperature !== null ? formatTemperature2(state.currentTemperature) : "N/A"}
21066
+ ${state.currentTemperature !== null ? formatTemperature(state.currentTemperature) : "N/A"}
20502
21067
  </div>
20503
21068
  <div style="font-size: 11px; color: ${statusColor}; margin-top: 2px;">${statusText}</div>
20504
21069
  </div>
@@ -20509,7 +21074,7 @@ ${rangeText}`;
20509
21074
  ">
20510
21075
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">M\xE9dia do Per\xEDodo</span>
20511
21076
  <div id="${modalId}-avg" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
20512
- ${state.stats.count > 0 ? formatTemperature2(state.stats.avg) : "N/A"}
21077
+ ${state.stats.count > 0 ? formatTemperature(state.stats.avg) : "N/A"}
20513
21078
  </div>
20514
21079
  <div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${startDateStr} - ${endDateStr}</div>
20515
21080
  </div>
@@ -20520,7 +21085,7 @@ ${rangeText}`;
20520
21085
  ">
20521
21086
  <span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Min / Max</span>
20522
21087
  <div id="${modalId}-minmax" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
20523
- ${state.stats.count > 0 ? `${formatTemperature2(state.stats.min)} / ${formatTemperature2(state.stats.max)}` : "N/A"}
21088
+ ${state.stats.count > 0 ? `${formatTemperature(state.stats.min)} / ${formatTemperature(state.stats.max)}` : "N/A"}
20524
21089
  </div>
20525
21090
  <div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${state.stats.count} leituras</div>
20526
21091
  </div>
@@ -20836,7 +21401,7 @@ ${rangeText}`;
20836
21401
  }
20837
21402
  tooltip.innerHTML = `
20838
21403
  <div style="font-weight: 600; margin-bottom: 6px; color: ${colors.primary};">
20839
- ${formatTemperature2(point.y)}
21404
+ ${formatTemperature(point.y)}
20840
21405
  </div>
20841
21406
  <div style="font-size: 11px; color: ${colors.textMuted};">
20842
21407
  \u{1F4C5} ${dateStr}
@@ -21099,7 +21664,7 @@ ${rangeText}`;
21099
21664
  <span style="width: 12px; height: 12px; border-radius: 50%; background: ${dd.color};"></span>
21100
21665
  <span style="color: ${colors.text}; font-size: 13px;">${dd.device.label}</span>
21101
21666
  <span style="color: ${colors.textMuted}; font-size: 11px; margin-left: auto;">
21102
- ${dd.stats.count > 0 ? formatTemperature2(dd.stats.avg) : "N/A"}
21667
+ ${dd.stats.count > 0 ? formatTemperature(dd.stats.avg) : "N/A"}
21103
21668
  </span>
21104
21669
  </div>
21105
21670
  `).join("");
@@ -21115,15 +21680,15 @@ ${rangeText}`;
21115
21680
  <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 4px; font-size: 11px;">
21116
21681
  <span style="color: ${colors.textMuted};">M\xE9dia:</span>
21117
21682
  <span style="color: ${colors.text}; font-weight: 500;">
21118
- ${dd.stats.count > 0 ? formatTemperature2(dd.stats.avg) : "N/A"}
21683
+ ${dd.stats.count > 0 ? formatTemperature(dd.stats.avg) : "N/A"}
21119
21684
  </span>
21120
21685
  <span style="color: ${colors.textMuted};">Min:</span>
21121
21686
  <span style="color: ${colors.text};">
21122
- ${dd.stats.count > 0 ? formatTemperature2(dd.stats.min) : "N/A"}
21687
+ ${dd.stats.count > 0 ? formatTemperature(dd.stats.min) : "N/A"}
21123
21688
  </span>
21124
21689
  <span style="color: ${colors.textMuted};">Max:</span>
21125
21690
  <span style="color: ${colors.text};">
21126
- ${dd.stats.count > 0 ? formatTemperature2(dd.stats.max) : "N/A"}
21691
+ ${dd.stats.count > 0 ? formatTemperature(dd.stats.max) : "N/A"}
21127
21692
  </span>
21128
21693
  <span style="color: ${colors.textMuted};">Leituras:</span>
21129
21694
  <span style="color: ${colors.text};">${dd.stats.count}</span>
@@ -21659,7 +22224,7 @@ ${rangeText}`;
21659
22224
  <span style="font-weight: 600;">${point.deviceLabel}</span>
21660
22225
  </div>
21661
22226
  <div style="font-weight: 600; font-size: 16px; color: ${point.deviceColor}; margin-bottom: 4px;">
21662
- ${formatTemperature2(point.y)}
22227
+ ${formatTemperature(point.y)}
21663
22228
  </div>
21664
22229
  <div style="font-size: 11px; color: ${colors.textMuted};">
21665
22230
  \u{1F4C5} ${dateStr}
@@ -26205,7 +26770,7 @@ ${rangeText}`;
26205
26770
  exports.formatNumberReadable = formatNumberReadable;
26206
26771
  exports.formatRelativeTime = formatRelativeTime;
26207
26772
  exports.formatTankHeadFromCm = formatTankHeadFromCm;
26208
- exports.formatTemperature = formatTemperature2;
26773
+ exports.formatTemperature = formatTemperature;
26209
26774
  exports.formatWater = formatWater;
26210
26775
  exports.formatWaterByGroup = formatWaterByGroup;
26211
26776
  exports.formatWaterVolumeM3 = formatWaterVolumeM3;