myio-js-library 0.1.549 → 0.1.550

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
@@ -899,7 +899,7 @@ module.exports = __toCommonJS(src_exports);
899
899
  // package.json
900
900
  var package_default = {
901
901
  name: "myio-js-library",
902
- version: "0.1.549",
902
+ version: "0.1.550",
903
903
  description: "A clean, standalone JS SDK for MYIO projects",
904
904
  license: "MIT",
905
905
  repository: "github:gh-myio/myio-js-library",
@@ -35502,7 +35502,8 @@ var DeviceReportModal = class {
35502
35502
  baseUrl: this.params.api.dataApiBaseUrl || "https://api.data.apps.myio-bas.com",
35503
35503
  ingestionId: this.params.ingestionId,
35504
35504
  startISO,
35505
- endISO
35505
+ endISO,
35506
+ granularity: this.granularity
35506
35507
  });
35507
35508
  this.data = this.processApiResponse(apiResponse, dateRange);
35508
35509
  this.renderSummary();
@@ -35532,10 +35533,25 @@ var DeviceReportModal = class {
35532
35533
  if (!Array.isArray(dataArray) || dataArray.length === 0) {
35533
35534
  console.warn("[DeviceReportModal] API returned empty or invalid response, zero-filling date range");
35534
35535
  if (isHourly) return [];
35535
- return dateRange.map((date) => ({ date, consumption: 0 }));
35536
+ const noData = this.domainConfig.summaryType === "average";
35537
+ return dateRange.map((date) => ({ date, consumption: 0, ...noData ? { noData: true } : {} }));
35536
35538
  }
35537
35539
  const deviceData = dataArray[0];
35538
35540
  const consumption = deviceData.consumption || [];
35541
+ if (!isHourly && this.domainConfig.summaryType === "average") {
35542
+ const acc = {};
35543
+ consumption.forEach((item) => {
35544
+ if (item.timestamp && item.value != null && Number.isFinite(Number(item.value))) {
35545
+ const date = String(item.timestamp).slice(0, 10);
35546
+ const a = acc[date] || (acc[date] = { sum: 0, n: 0 });
35547
+ a.sum += Number(item.value);
35548
+ a.n += 1;
35549
+ }
35550
+ });
35551
+ return dateRange.map(
35552
+ (date) => acc[date] ? { date, consumption: acc[date].sum / acc[date].n } : { date, consumption: 0, noData: true }
35553
+ );
35554
+ }
35539
35555
  if (isHourly) {
35540
35556
  return consumption.filter((item) => item.timestamp && item.value != null).map((item) => ({
35541
35557
  date: item.timestamp,
@@ -35597,14 +35613,15 @@ var DeviceReportModal = class {
35597
35613
  const isHourly = this.granularity === "1h";
35598
35614
  const isTemperature = this.domainConfig.summaryType === "average";
35599
35615
  const total = this.calculateTotal();
35600
- const summaryValue = isTemperature ? this.data.length > 0 ? total / this.data.length : 0 : total;
35601
- const dayKeys = new Set(this.data.map((r) => r.date.slice(0, 10)));
35616
+ const rows = this.validRows;
35617
+ const summaryValue = isTemperature ? rows.length > 0 ? total / rows.length : 0 : total;
35618
+ const dayKeys = new Set(rows.map((r) => r.date.slice(0, 10)));
35602
35619
  const dayCount = Math.max(1, dayKeys.size);
35603
- const maxRow = this.data.reduce(
35620
+ const maxRow = rows.reduce(
35604
35621
  (best, r) => !best || r.consumption > best.consumption ? r : best,
35605
35622
  null
35606
35623
  );
35607
- const minPool = isTemperature ? this.data : this.data.filter((r) => r.consumption > 0);
35624
+ const minPool = isTemperature ? rows : rows.filter((r) => r.consumption > 0);
35608
35625
  const minRow = minPool.reduce(
35609
35626
  (best, r) => !best || r.consumption < best.consumption ? r : best,
35610
35627
  null
@@ -35616,7 +35633,7 @@ var DeviceReportModal = class {
35616
35633
  { value: fmt2(total / dayCount), label: `M\xE9dia por Dia (${unit})` }
35617
35634
  ];
35618
35635
  if (isHourly) {
35619
- kpis.push({ value: fmt2(total / this.data.length), label: `M\xE9dia por Hora (${unit})` });
35636
+ kpis.push({ value: fmt2(rows.length ? total / rows.length : 0), label: `M\xE9dia por Hora (${unit})` });
35620
35637
  }
35621
35638
  kpis.push(
35622
35639
  {
@@ -35632,6 +35649,9 @@ var DeviceReportModal = class {
35632
35649
  );
35633
35650
  if (!isTemperature) {
35634
35651
  kpis.push({ value: String(zeroCount), label: isHourly ? "Horas sem Consumo" : "Dias sem Consumo" });
35652
+ } else {
35653
+ const noData = this.data.length - rows.length;
35654
+ if (noData > 0) kpis.push({ value: String(noData), label: isHourly ? "Horas sem Leitura" : "Dias sem Leitura" });
35635
35655
  }
35636
35656
  return kpis;
35637
35657
  }
@@ -35717,7 +35737,7 @@ var DeviceReportModal = class {
35717
35737
  ${this.data.map((row) => `
35718
35738
  <tr>
35719
35739
  <td>${this.formatDate(row.date)}</td>
35720
- <td style="text-align: right;">${this.domainConfig.formatter(row.consumption)}</td>
35740
+ <td style="text-align: right;${row.noData ? " color: var(--myio-text-muted);" : ""}">${row.noData ? "Sem leitura" : this.domainConfig.formatter(row.consumption)}</td>
35721
35741
  </tr>
35722
35742
  `).join("")}
35723
35743
  </tbody>
@@ -35748,13 +35768,18 @@ var DeviceReportModal = class {
35748
35768
  if (key === "date") {
35749
35769
  comparison = new Date(a.date).getTime() - new Date(b.date).getTime();
35750
35770
  } else {
35771
+ if (!!a.noData !== !!b.noData) return a.noData ? 1 : -1;
35751
35772
  comparison = a.consumption - b.consumption;
35752
35773
  }
35753
35774
  return this.sortState.direction === "desc" ? -comparison : comparison;
35754
35775
  });
35755
35776
  }
35777
+ // Linhas com leitura (temperatura: dia sem leitura fica fora de totais/médias/KPIs)
35778
+ get validRows() {
35779
+ return this.data.filter((r) => !r.noData);
35780
+ }
35756
35781
  calculateTotal() {
35757
- return this.data.reduce((sum2, row) => sum2 + row.consumption, 0);
35782
+ return this.validRows.reduce((sum2, row) => sum2 + row.consumption, 0);
35758
35783
  }
35759
35784
  formatDate(dateStr) {
35760
35785
  if (!dateStr) return "";
@@ -35767,7 +35792,8 @@ var DeviceReportModal = class {
35767
35792
  }
35768
35793
  exportCSV() {
35769
35794
  const total = this.calculateTotal();
35770
- const summaryValue = this.domainConfig.summaryType === "average" ? this.data.length > 0 ? total / this.data.length : 0 : total;
35795
+ const valid = this.validRows.length;
35796
+ const summaryValue = this.domainConfig.summaryType === "average" ? valid > 0 ? total / valid : 0 : total;
35771
35797
  const now = /* @__PURE__ */ new Date();
35772
35798
  const timestamp = now.toLocaleDateString("pt-BR") + " - " + now.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" });
35773
35799
  const csvData = [
@@ -35775,7 +35801,7 @@ var DeviceReportModal = class {
35775
35801
  ["DATA EMISS\xC3O", timestamp, ""],
35776
35802
  [this.domainConfig.summaryLabel, this.domainConfig.formatter(summaryValue), this.domainConfig.unit],
35777
35803
  [this.granularity === "1h" ? "Data/Hora" : "Data", this.domainConfig.label, ""],
35778
- ...this.data.map((row) => [this.formatDate(row.date), this.domainConfig.formatter(row.consumption)])
35804
+ ...this.data.map((row) => [this.formatDate(row.date), row.noData ? "Sem leitura" : this.domainConfig.formatter(row.consumption)])
35779
35805
  ];
35780
35806
  const csvContent = toCsv(csvData);
35781
35807
  const granSuffix = this.granularity === "1h" ? "-1h" : "";
@@ -35806,7 +35832,7 @@ var DeviceReportModal = class {
35806
35832
  return this.data.map((row) => ({
35807
35833
  labelOrName: this.formatDate(row.date),
35808
35834
  name: this.formatDate(row.date),
35809
- val: row.consumption,
35835
+ val: row.noData ? null : row.consumption,
35810
35836
  ...isTemperature || total <= 0 ? {} : { perc: row.consumption / total * 100 }
35811
35837
  }));
35812
35838
  }
@@ -39003,10 +39029,12 @@ var AllReportModal = class {
39003
39029
  // em total_value (in-place). Sensores sem série ficam com o 0 original.
39004
39030
  async enrichTemperatureAverages(data, startISO, endISO, token, baseUrl) {
39005
39031
  const rows = Array.isArray(data?.data) ? data.data : [];
39006
- let tempRows = rows.filter((d) => String(d?.deviceType || "").toLowerCase() === "temperature");
39032
+ let tempRows;
39007
39033
  if (this.params.itemsList) {
39008
39034
  const ids = new Set(this.params.itemsList.map((i) => String(i.id)));
39009
- tempRows = tempRows.filter((d) => ids.has(String(d?.id)));
39035
+ tempRows = rows.filter((d) => ids.has(String(d?.id)));
39036
+ } else {
39037
+ tempRows = rows.filter((d) => String(d?.deviceType || "").toLowerCase() === "temperature");
39010
39038
  }
39011
39039
  if (!tempRows.length) return;
39012
39040
  const startTime = encodeURIComponent(startISO);
package/dist/index.d.cts CHANGED
@@ -5639,6 +5639,8 @@ type EnergyFetcher = (args: {
5639
5639
  ingestionId: string;
5640
5640
  startISO: string;
5641
5641
  endISO: string;
5642
+ /** Granularidade selecionada na modal (fetchers customizados podem honrar 1h/1d). */
5643
+ granularity?: '1d' | '1h';
5642
5644
  }) => Promise<any>;
5643
5645
  interface OpenDeviceReportParams {
5644
5646
  ingestionId: string;
package/dist/index.d.ts CHANGED
@@ -5639,6 +5639,8 @@ type EnergyFetcher = (args: {
5639
5639
  ingestionId: string;
5640
5640
  startISO: string;
5641
5641
  endISO: string;
5642
+ /** Granularidade selecionada na modal (fetchers customizados podem honrar 1h/1d). */
5643
+ granularity?: '1d' | '1h';
5642
5644
  }) => Promise<any>;
5643
5645
  interface OpenDeviceReportParams {
5644
5646
  ingestionId: string;
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  // package.json
11
11
  var package_default = {
12
12
  name: "myio-js-library",
13
- version: "0.1.549",
13
+ version: "0.1.550",
14
14
  description: "A clean, standalone JS SDK for MYIO projects",
15
15
  license: "MIT",
16
16
  repository: "github:gh-myio/myio-js-library",
@@ -33888,7 +33888,8 @@ var DeviceReportModal = class {
33888
33888
  baseUrl: this.params.api.dataApiBaseUrl || "https://api.data.apps.myio-bas.com",
33889
33889
  ingestionId: this.params.ingestionId,
33890
33890
  startISO,
33891
- endISO
33891
+ endISO,
33892
+ granularity: this.granularity
33892
33893
  });
33893
33894
  this.data = this.processApiResponse(apiResponse, dateRange);
33894
33895
  this.renderSummary();
@@ -33918,10 +33919,25 @@ var DeviceReportModal = class {
33918
33919
  if (!Array.isArray(dataArray) || dataArray.length === 0) {
33919
33920
  console.warn("[DeviceReportModal] API returned empty or invalid response, zero-filling date range");
33920
33921
  if (isHourly) return [];
33921
- return dateRange.map((date) => ({ date, consumption: 0 }));
33922
+ const noData = this.domainConfig.summaryType === "average";
33923
+ return dateRange.map((date) => ({ date, consumption: 0, ...noData ? { noData: true } : {} }));
33922
33924
  }
33923
33925
  const deviceData = dataArray[0];
33924
33926
  const consumption = deviceData.consumption || [];
33927
+ if (!isHourly && this.domainConfig.summaryType === "average") {
33928
+ const acc = {};
33929
+ consumption.forEach((item) => {
33930
+ if (item.timestamp && item.value != null && Number.isFinite(Number(item.value))) {
33931
+ const date = String(item.timestamp).slice(0, 10);
33932
+ const a = acc[date] || (acc[date] = { sum: 0, n: 0 });
33933
+ a.sum += Number(item.value);
33934
+ a.n += 1;
33935
+ }
33936
+ });
33937
+ return dateRange.map(
33938
+ (date) => acc[date] ? { date, consumption: acc[date].sum / acc[date].n } : { date, consumption: 0, noData: true }
33939
+ );
33940
+ }
33925
33941
  if (isHourly) {
33926
33942
  return consumption.filter((item) => item.timestamp && item.value != null).map((item) => ({
33927
33943
  date: item.timestamp,
@@ -33983,14 +33999,15 @@ var DeviceReportModal = class {
33983
33999
  const isHourly = this.granularity === "1h";
33984
34000
  const isTemperature = this.domainConfig.summaryType === "average";
33985
34001
  const total = this.calculateTotal();
33986
- const summaryValue = isTemperature ? this.data.length > 0 ? total / this.data.length : 0 : total;
33987
- const dayKeys = new Set(this.data.map((r) => r.date.slice(0, 10)));
34002
+ const rows = this.validRows;
34003
+ const summaryValue = isTemperature ? rows.length > 0 ? total / rows.length : 0 : total;
34004
+ const dayKeys = new Set(rows.map((r) => r.date.slice(0, 10)));
33988
34005
  const dayCount = Math.max(1, dayKeys.size);
33989
- const maxRow = this.data.reduce(
34006
+ const maxRow = rows.reduce(
33990
34007
  (best, r) => !best || r.consumption > best.consumption ? r : best,
33991
34008
  null
33992
34009
  );
33993
- const minPool = isTemperature ? this.data : this.data.filter((r) => r.consumption > 0);
34010
+ const minPool = isTemperature ? rows : rows.filter((r) => r.consumption > 0);
33994
34011
  const minRow = minPool.reduce(
33995
34012
  (best, r) => !best || r.consumption < best.consumption ? r : best,
33996
34013
  null
@@ -34002,7 +34019,7 @@ var DeviceReportModal = class {
34002
34019
  { value: fmt2(total / dayCount), label: `M\xE9dia por Dia (${unit})` }
34003
34020
  ];
34004
34021
  if (isHourly) {
34005
- kpis.push({ value: fmt2(total / this.data.length), label: `M\xE9dia por Hora (${unit})` });
34022
+ kpis.push({ value: fmt2(rows.length ? total / rows.length : 0), label: `M\xE9dia por Hora (${unit})` });
34006
34023
  }
34007
34024
  kpis.push(
34008
34025
  {
@@ -34018,6 +34035,9 @@ var DeviceReportModal = class {
34018
34035
  );
34019
34036
  if (!isTemperature) {
34020
34037
  kpis.push({ value: String(zeroCount), label: isHourly ? "Horas sem Consumo" : "Dias sem Consumo" });
34038
+ } else {
34039
+ const noData = this.data.length - rows.length;
34040
+ if (noData > 0) kpis.push({ value: String(noData), label: isHourly ? "Horas sem Leitura" : "Dias sem Leitura" });
34021
34041
  }
34022
34042
  return kpis;
34023
34043
  }
@@ -34103,7 +34123,7 @@ var DeviceReportModal = class {
34103
34123
  ${this.data.map((row) => `
34104
34124
  <tr>
34105
34125
  <td>${this.formatDate(row.date)}</td>
34106
- <td style="text-align: right;">${this.domainConfig.formatter(row.consumption)}</td>
34126
+ <td style="text-align: right;${row.noData ? " color: var(--myio-text-muted);" : ""}">${row.noData ? "Sem leitura" : this.domainConfig.formatter(row.consumption)}</td>
34107
34127
  </tr>
34108
34128
  `).join("")}
34109
34129
  </tbody>
@@ -34134,13 +34154,18 @@ var DeviceReportModal = class {
34134
34154
  if (key === "date") {
34135
34155
  comparison = new Date(a.date).getTime() - new Date(b.date).getTime();
34136
34156
  } else {
34157
+ if (!!a.noData !== !!b.noData) return a.noData ? 1 : -1;
34137
34158
  comparison = a.consumption - b.consumption;
34138
34159
  }
34139
34160
  return this.sortState.direction === "desc" ? -comparison : comparison;
34140
34161
  });
34141
34162
  }
34163
+ // Linhas com leitura (temperatura: dia sem leitura fica fora de totais/médias/KPIs)
34164
+ get validRows() {
34165
+ return this.data.filter((r) => !r.noData);
34166
+ }
34142
34167
  calculateTotal() {
34143
- return this.data.reduce((sum2, row) => sum2 + row.consumption, 0);
34168
+ return this.validRows.reduce((sum2, row) => sum2 + row.consumption, 0);
34144
34169
  }
34145
34170
  formatDate(dateStr) {
34146
34171
  if (!dateStr) return "";
@@ -34153,7 +34178,8 @@ var DeviceReportModal = class {
34153
34178
  }
34154
34179
  exportCSV() {
34155
34180
  const total = this.calculateTotal();
34156
- const summaryValue = this.domainConfig.summaryType === "average" ? this.data.length > 0 ? total / this.data.length : 0 : total;
34181
+ const valid = this.validRows.length;
34182
+ const summaryValue = this.domainConfig.summaryType === "average" ? valid > 0 ? total / valid : 0 : total;
34157
34183
  const now = /* @__PURE__ */ new Date();
34158
34184
  const timestamp = now.toLocaleDateString("pt-BR") + " - " + now.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" });
34159
34185
  const csvData = [
@@ -34161,7 +34187,7 @@ var DeviceReportModal = class {
34161
34187
  ["DATA EMISS\xC3O", timestamp, ""],
34162
34188
  [this.domainConfig.summaryLabel, this.domainConfig.formatter(summaryValue), this.domainConfig.unit],
34163
34189
  [this.granularity === "1h" ? "Data/Hora" : "Data", this.domainConfig.label, ""],
34164
- ...this.data.map((row) => [this.formatDate(row.date), this.domainConfig.formatter(row.consumption)])
34190
+ ...this.data.map((row) => [this.formatDate(row.date), row.noData ? "Sem leitura" : this.domainConfig.formatter(row.consumption)])
34165
34191
  ];
34166
34192
  const csvContent = toCsv(csvData);
34167
34193
  const granSuffix = this.granularity === "1h" ? "-1h" : "";
@@ -34192,7 +34218,7 @@ var DeviceReportModal = class {
34192
34218
  return this.data.map((row) => ({
34193
34219
  labelOrName: this.formatDate(row.date),
34194
34220
  name: this.formatDate(row.date),
34195
- val: row.consumption,
34221
+ val: row.noData ? null : row.consumption,
34196
34222
  ...isTemperature || total <= 0 ? {} : { perc: row.consumption / total * 100 }
34197
34223
  }));
34198
34224
  }
@@ -37389,10 +37415,12 @@ var AllReportModal = class {
37389
37415
  // em total_value (in-place). Sensores sem série ficam com o 0 original.
37390
37416
  async enrichTemperatureAverages(data, startISO, endISO, token, baseUrl) {
37391
37417
  const rows = Array.isArray(data?.data) ? data.data : [];
37392
- let tempRows = rows.filter((d) => String(d?.deviceType || "").toLowerCase() === "temperature");
37418
+ let tempRows;
37393
37419
  if (this.params.itemsList) {
37394
37420
  const ids = new Set(this.params.itemsList.map((i) => String(i.id)));
37395
- tempRows = tempRows.filter((d) => ids.has(String(d?.id)));
37421
+ tempRows = rows.filter((d) => ids.has(String(d?.id)));
37422
+ } else {
37423
+ tempRows = rows.filter((d) => String(d?.deviceType || "").toLowerCase() === "temperature");
37396
37424
  }
37397
37425
  if (!tempRows.length) return;
37398
37426
  const startTime = encodeURIComponent(startISO);
@@ -5455,7 +5455,7 @@
5455
5455
 
5456
5456
  // package.json
5457
5457
  var package_default = {
5458
- version: "0.1.549"};
5458
+ version: "0.1.550"};
5459
5459
 
5460
5460
  // src/utils/format/energy.ts
5461
5461
  function formatPower(value, decimals = 2) {
@@ -39211,7 +39211,8 @@
39211
39211
  baseUrl: this.params.api.dataApiBaseUrl || "https://api.data.apps.myio-bas.com",
39212
39212
  ingestionId: this.params.ingestionId,
39213
39213
  startISO,
39214
- endISO
39214
+ endISO,
39215
+ granularity: this.granularity
39215
39216
  });
39216
39217
  this.data = this.processApiResponse(apiResponse, dateRange);
39217
39218
  this.renderSummary();
@@ -39241,10 +39242,25 @@
39241
39242
  if (!Array.isArray(dataArray) || dataArray.length === 0) {
39242
39243
  console.warn("[DeviceReportModal] API returned empty or invalid response, zero-filling date range");
39243
39244
  if (isHourly) return [];
39244
- return dateRange.map((date) => ({ date, consumption: 0 }));
39245
+ const noData = this.domainConfig.summaryType === "average";
39246
+ return dateRange.map((date) => ({ date, consumption: 0, ...noData ? { noData: true } : {} }));
39245
39247
  }
39246
39248
  const deviceData = dataArray[0];
39247
39249
  const consumption = deviceData.consumption || [];
39250
+ if (!isHourly && this.domainConfig.summaryType === "average") {
39251
+ const acc = {};
39252
+ consumption.forEach((item) => {
39253
+ if (item.timestamp && item.value != null && Number.isFinite(Number(item.value))) {
39254
+ const date = String(item.timestamp).slice(0, 10);
39255
+ const a = acc[date] || (acc[date] = { sum: 0, n: 0 });
39256
+ a.sum += Number(item.value);
39257
+ a.n += 1;
39258
+ }
39259
+ });
39260
+ return dateRange.map(
39261
+ (date) => acc[date] ? { date, consumption: acc[date].sum / acc[date].n } : { date, consumption: 0, noData: true }
39262
+ );
39263
+ }
39248
39264
  if (isHourly) {
39249
39265
  return consumption.filter((item) => item.timestamp && item.value != null).map((item) => ({
39250
39266
  date: item.timestamp,
@@ -39306,14 +39322,15 @@
39306
39322
  const isHourly = this.granularity === "1h";
39307
39323
  const isTemperature = this.domainConfig.summaryType === "average";
39308
39324
  const total = this.calculateTotal();
39309
- const summaryValue = isTemperature ? this.data.length > 0 ? total / this.data.length : 0 : total;
39310
- const dayKeys = new Set(this.data.map((r) => r.date.slice(0, 10)));
39325
+ const rows = this.validRows;
39326
+ const summaryValue = isTemperature ? rows.length > 0 ? total / rows.length : 0 : total;
39327
+ const dayKeys = new Set(rows.map((r) => r.date.slice(0, 10)));
39311
39328
  const dayCount = Math.max(1, dayKeys.size);
39312
- const maxRow = this.data.reduce(
39329
+ const maxRow = rows.reduce(
39313
39330
  (best, r) => !best || r.consumption > best.consumption ? r : best,
39314
39331
  null
39315
39332
  );
39316
- const minPool = isTemperature ? this.data : this.data.filter((r) => r.consumption > 0);
39333
+ const minPool = isTemperature ? rows : rows.filter((r) => r.consumption > 0);
39317
39334
  const minRow = minPool.reduce(
39318
39335
  (best, r) => !best || r.consumption < best.consumption ? r : best,
39319
39336
  null
@@ -39325,7 +39342,7 @@
39325
39342
  { value: fmt2(total / dayCount), label: `M\xE9dia por Dia (${unit})` }
39326
39343
  ];
39327
39344
  if (isHourly) {
39328
- kpis.push({ value: fmt2(total / this.data.length), label: `M\xE9dia por Hora (${unit})` });
39345
+ kpis.push({ value: fmt2(rows.length ? total / rows.length : 0), label: `M\xE9dia por Hora (${unit})` });
39329
39346
  }
39330
39347
  kpis.push(
39331
39348
  {
@@ -39341,6 +39358,9 @@
39341
39358
  );
39342
39359
  if (!isTemperature) {
39343
39360
  kpis.push({ value: String(zeroCount), label: isHourly ? "Horas sem Consumo" : "Dias sem Consumo" });
39361
+ } else {
39362
+ const noData = this.data.length - rows.length;
39363
+ if (noData > 0) kpis.push({ value: String(noData), label: isHourly ? "Horas sem Leitura" : "Dias sem Leitura" });
39344
39364
  }
39345
39365
  return kpis;
39346
39366
  }
@@ -39426,7 +39446,7 @@
39426
39446
  ${this.data.map((row) => `
39427
39447
  <tr>
39428
39448
  <td>${this.formatDate(row.date)}</td>
39429
- <td style="text-align: right;">${this.domainConfig.formatter(row.consumption)}</td>
39449
+ <td style="text-align: right;${row.noData ? " color: var(--myio-text-muted);" : ""}">${row.noData ? "Sem leitura" : this.domainConfig.formatter(row.consumption)}</td>
39430
39450
  </tr>
39431
39451
  `).join("")}
39432
39452
  </tbody>
@@ -39457,13 +39477,18 @@
39457
39477
  if (key === "date") {
39458
39478
  comparison = new Date(a.date).getTime() - new Date(b.date).getTime();
39459
39479
  } else {
39480
+ if (!!a.noData !== !!b.noData) return a.noData ? 1 : -1;
39460
39481
  comparison = a.consumption - b.consumption;
39461
39482
  }
39462
39483
  return this.sortState.direction === "desc" ? -comparison : comparison;
39463
39484
  });
39464
39485
  }
39486
+ // Linhas com leitura (temperatura: dia sem leitura fica fora de totais/médias/KPIs)
39487
+ get validRows() {
39488
+ return this.data.filter((r) => !r.noData);
39489
+ }
39465
39490
  calculateTotal() {
39466
- return this.data.reduce((sum2, row) => sum2 + row.consumption, 0);
39491
+ return this.validRows.reduce((sum2, row) => sum2 + row.consumption, 0);
39467
39492
  }
39468
39493
  formatDate(dateStr) {
39469
39494
  if (!dateStr) return "";
@@ -39476,7 +39501,8 @@
39476
39501
  }
39477
39502
  exportCSV() {
39478
39503
  const total = this.calculateTotal();
39479
- const summaryValue = this.domainConfig.summaryType === "average" ? this.data.length > 0 ? total / this.data.length : 0 : total;
39504
+ const valid = this.validRows.length;
39505
+ const summaryValue = this.domainConfig.summaryType === "average" ? valid > 0 ? total / valid : 0 : total;
39480
39506
  const now = /* @__PURE__ */ new Date();
39481
39507
  const timestamp = now.toLocaleDateString("pt-BR") + " - " + now.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" });
39482
39508
  const csvData = [
@@ -39484,7 +39510,7 @@
39484
39510
  ["DATA EMISS\xC3O", timestamp, ""],
39485
39511
  [this.domainConfig.summaryLabel, this.domainConfig.formatter(summaryValue), this.domainConfig.unit],
39486
39512
  [this.granularity === "1h" ? "Data/Hora" : "Data", this.domainConfig.label, ""],
39487
- ...this.data.map((row) => [this.formatDate(row.date), this.domainConfig.formatter(row.consumption)])
39513
+ ...this.data.map((row) => [this.formatDate(row.date), row.noData ? "Sem leitura" : this.domainConfig.formatter(row.consumption)])
39488
39514
  ];
39489
39515
  const csvContent = toCsv(csvData);
39490
39516
  const granSuffix = this.granularity === "1h" ? "-1h" : "";
@@ -39515,7 +39541,7 @@
39515
39541
  return this.data.map((row) => ({
39516
39542
  labelOrName: this.formatDate(row.date),
39517
39543
  name: this.formatDate(row.date),
39518
- val: row.consumption,
39544
+ val: row.noData ? null : row.consumption,
39519
39545
  ...isTemperature || total <= 0 ? {} : { perc: row.consumption / total * 100 }
39520
39546
  }));
39521
39547
  }
@@ -42712,10 +42738,12 @@
42712
42738
  // em total_value (in-place). Sensores sem série ficam com o 0 original.
42713
42739
  async enrichTemperatureAverages(data, startISO, endISO, token, baseUrl) {
42714
42740
  const rows = Array.isArray(data?.data) ? data.data : [];
42715
- let tempRows = rows.filter((d) => String(d?.deviceType || "").toLowerCase() === "temperature");
42741
+ let tempRows;
42716
42742
  if (this.params.itemsList) {
42717
42743
  const ids = new Set(this.params.itemsList.map((i) => String(i.id)));
42718
- tempRows = tempRows.filter((d) => ids.has(String(d?.id)));
42744
+ tempRows = rows.filter((d) => ids.has(String(d?.id)));
42745
+ } else {
42746
+ tempRows = rows.filter((d) => String(d?.deviceType || "").toLowerCase() === "temperature");
42719
42747
  }
42720
42748
  if (!tempRows.length) return;
42721
42749
  const startTime = encodeURIComponent(startISO);