myio-js-library 0.1.136 → 0.1.139

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.
@@ -6983,8 +6983,8 @@ ${rangeText}`;
6983
6983
  total_current: { label: "Corrente Total", unit: "A", icon: "\u{1F50C}", decimals: 2 },
6984
6984
  current: { label: "Corrente", unit: "A", icon: "\u{1F50C}", decimals: 2 },
6985
6985
  // Power and Energy
6986
- consumption: { label: "Consumo", unit: "kW", icon: "\u2699\uFE0F", decimals: 2 },
6987
- power: { label: "Pot\xEAncia", unit: "kW", icon: "\u2699\uFE0F", decimals: 2 },
6986
+ consumption: { label: "Pot\xEAncia", unit: "W", icon: "\u2699\uFE0F", decimals: 0 },
6987
+ power: { label: "Pot\xEAncia", unit: "W", icon: "\u2699\uFE0F", decimals: 0 },
6988
6988
  energy: { label: "Energia", unit: "kWh", icon: "\u{1F4CA}", decimals: 1 },
6989
6989
  activePower: { label: "Pot\xEAncia Ativa", unit: "kW", icon: "\u2699\uFE0F", decimals: 2 },
6990
6990
  reactivePower: { label: "Pot\xEAncia Reativa", unit: "kVAr", icon: "\u{1F504}", decimals: 2 },
@@ -7040,7 +7040,9 @@ ${rangeText}`;
7040
7040
  let refreshIntervalId = null;
7041
7041
  let isPaused = false;
7042
7042
  let telemetryHistory = /* @__PURE__ */ new Map();
7043
+ let lastKnownValues = /* @__PURE__ */ new Map();
7043
7044
  let chart = null;
7045
+ let selectedChartKey = "consumption";
7044
7046
  const overlay = document.createElement("div");
7045
7047
  overlay.className = "myio-realtime-telemetry-overlay";
7046
7048
  overlay.innerHTML = `
@@ -7191,6 +7193,8 @@ ${rangeText}`;
7191
7193
  padding: 20px;
7192
7194
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
7193
7195
  margin-bottom: 20px;
7196
+ max-height: 520px;
7197
+ overflow: hidden;
7194
7198
  }
7195
7199
 
7196
7200
  .myio-telemetry-chart-title {
@@ -7201,7 +7205,29 @@ ${rangeText}`;
7201
7205
  }
7202
7206
 
7203
7207
  .myio-telemetry-chart {
7204
- height: 200px;
7208
+ height: 300px;
7209
+ max-height: 450px;
7210
+ width: 100%;
7211
+ }
7212
+
7213
+ .myio-telemetry-selector {
7214
+ padding: 8px 12px;
7215
+ border: 1px solid #ddd;
7216
+ border-radius: 6px;
7217
+ font-size: 14px;
7218
+ background: white;
7219
+ cursor: pointer;
7220
+ transition: border-color 0.2s;
7221
+ }
7222
+
7223
+ .myio-telemetry-selector:hover {
7224
+ border-color: #667eea;
7225
+ }
7226
+
7227
+ .myio-telemetry-selector:focus {
7228
+ outline: none;
7229
+ border-color: #667eea;
7230
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
7205
7231
  }
7206
7232
 
7207
7233
  .myio-realtime-telemetry-footer {
@@ -7311,7 +7337,16 @@ ${rangeText}`;
7311
7337
  <div class="myio-telemetry-cards-grid" id="telemetry-cards"></div>
7312
7338
 
7313
7339
  <div class="myio-telemetry-chart-container" id="chart-container" style="display: none;">
7314
- <h3 class="myio-telemetry-chart-title" id="chart-title">Pot\xEAncia (\xFAltimos 5 min)</h3>
7340
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
7341
+ <h3 class="myio-telemetry-chart-title" id="chart-title" style="margin: 0;">Hist\xF3rico de Telemetria</h3>
7342
+ <select id="chart-key-selector" class="myio-telemetry-selector">
7343
+ <option value="consumption">Pot\xEAncia</option>
7344
+ <option value="total_current">Corrente Total</option>
7345
+ <option value="voltage_a">Tens\xE3o Fase A</option>
7346
+ <option value="voltage_b">Tens\xE3o Fase B</option>
7347
+ <option value="voltage_c">Tens\xE3o Fase C</option>
7348
+ </select>
7349
+ </div>
7315
7350
  <canvas class="myio-telemetry-chart" id="telemetry-chart"></canvas>
7316
7351
  </div>
7317
7352
  </div>
@@ -7342,20 +7377,21 @@ ${rangeText}`;
7342
7377
  </div>
7343
7378
  `;
7344
7379
  document.body.appendChild(overlay);
7345
- const closeBtn = document.getElementById("close-btn");
7346
- const pauseBtn = document.getElementById("pause-btn");
7347
- const pauseBtnIcon = document.getElementById("pause-btn-icon");
7348
- const pauseBtnText = document.getElementById("pause-btn-text");
7349
- const exportBtn = document.getElementById("export-btn");
7350
- const loadingState = document.getElementById("loading-state");
7351
- const telemetryContent = document.getElementById("telemetry-content");
7352
- const errorState = document.getElementById("error-state");
7353
- const telemetryCards = document.getElementById("telemetry-cards");
7354
- const chartContainer = document.getElementById("chart-container");
7355
- const chartCanvas = document.getElementById("telemetry-chart");
7356
- const statusIndicator = document.getElementById("status-indicator");
7357
- const statusText = document.getElementById("status-text");
7358
- const lastUpdateText = document.getElementById("last-update-text");
7380
+ const closeBtn = overlay.querySelector("#close-btn");
7381
+ const pauseBtn = overlay.querySelector("#pause-btn");
7382
+ const pauseBtnIcon = overlay.querySelector("#pause-btn-icon");
7383
+ const pauseBtnText = overlay.querySelector("#pause-btn-text");
7384
+ const exportBtn = overlay.querySelector("#export-btn");
7385
+ const loadingState = overlay.querySelector("#loading-state");
7386
+ const telemetryContent = overlay.querySelector("#telemetry-content");
7387
+ const errorState = overlay.querySelector("#error-state");
7388
+ const telemetryCards = overlay.querySelector("#telemetry-cards");
7389
+ const chartContainer = overlay.querySelector("#chart-container");
7390
+ const chartCanvas = overlay.querySelector("#telemetry-chart");
7391
+ const chartKeySelector = overlay.querySelector("#chart-key-selector");
7392
+ const statusIndicator = overlay.querySelector("#status-indicator");
7393
+ const statusText = overlay.querySelector("#status-text");
7394
+ const lastUpdateText = overlay.querySelector("#last-update-text");
7359
7395
  function closeModal() {
7360
7396
  if (refreshIntervalId) {
7361
7397
  clearInterval(refreshIntervalId);
@@ -7444,16 +7480,42 @@ ${rangeText}`;
7444
7480
  }
7445
7481
  const history = telemetryHistory.get(tel.key);
7446
7482
  history.push({ x: now, y: tel.value });
7483
+ lastKnownValues.set(tel.key, tel.value);
7447
7484
  if (history.length > historyPoints) {
7448
7485
  history.shift();
7449
7486
  }
7450
7487
  }
7451
- if (telemetryHistory.has("power") && chart) {
7452
- const powerHistory = telemetryHistory.get("power");
7453
- chart.data.datasets[0].data = powerHistory;
7488
+ for (const key of telemetryKeys) {
7489
+ const receivedKeys = values.map((v) => v.key);
7490
+ if (!receivedKeys.includes(key) && lastKnownValues.has(key)) {
7491
+ if (!telemetryHistory.has(key)) {
7492
+ telemetryHistory.set(key, []);
7493
+ }
7494
+ const history = telemetryHistory.get(key);
7495
+ const lastValue = lastKnownValues.get(key);
7496
+ history.push({ x: now, y: lastValue });
7497
+ if (history.length > historyPoints) {
7498
+ history.shift();
7499
+ }
7500
+ }
7501
+ }
7502
+ if (telemetryHistory.has(selectedChartKey) && chart) {
7503
+ const selectedHistory = telemetryHistory.get(selectedChartKey);
7504
+ chart.data.datasets[0].data = selectedHistory;
7454
7505
  chart.update("none");
7455
7506
  }
7456
7507
  }
7508
+ function getFormattedValue(key, value) {
7509
+ const config = TELEMETRY_CONFIG[key];
7510
+ if (!config) return value.toFixed(2);
7511
+ if (key === "consumption" || key === "power") {
7512
+ if (value >= 1e3) {
7513
+ return `${(value / 1e3).toFixed(2)} kW`;
7514
+ }
7515
+ return `${value.toFixed(0)} W`;
7516
+ }
7517
+ return `${value.toFixed(config.decimals)} ${config.unit}`;
7518
+ }
7457
7519
  function initializeChart() {
7458
7520
  const Chart = window.Chart;
7459
7521
  if (!Chart) {
@@ -7461,23 +7523,26 @@ ${rangeText}`;
7461
7523
  return;
7462
7524
  }
7463
7525
  chartContainer.style.display = "block";
7526
+ const config = TELEMETRY_CONFIG[selectedChartKey] || { label: selectedChartKey, unit: "" };
7464
7527
  chart = new Chart(chartCanvas, {
7465
7528
  type: "line",
7466
7529
  data: {
7467
7530
  datasets: [{
7468
- label: "Pot\xEAncia",
7531
+ label: config.label,
7469
7532
  data: [],
7470
7533
  borderColor: "#667eea",
7471
7534
  backgroundColor: "rgba(102, 126, 234, 0.1)",
7472
7535
  borderWidth: 2,
7473
7536
  fill: true,
7474
7537
  tension: 0.4,
7475
- pointRadius: 0
7538
+ pointRadius: 3,
7539
+ pointHoverRadius: 5
7476
7540
  }]
7477
7541
  },
7478
7542
  options: {
7479
7543
  responsive: true,
7480
7544
  maintainAspectRatio: false,
7545
+ animation: false,
7481
7546
  plugins: {
7482
7547
  legend: { display: false },
7483
7548
  tooltip: {
@@ -7485,10 +7550,18 @@ ${rangeText}`;
7485
7550
  title: function(context) {
7486
7551
  const timestamp = context[0].parsed.x;
7487
7552
  const date = new Date(timestamp);
7488
- return date.toLocaleTimeString(locale);
7553
+ return date.toLocaleString(locale, {
7554
+ day: "2-digit",
7555
+ month: "2-digit",
7556
+ year: "numeric",
7557
+ hour: "2-digit",
7558
+ minute: "2-digit",
7559
+ second: "2-digit"
7560
+ });
7489
7561
  },
7490
7562
  label: function(context) {
7491
- return `${context.parsed.y.toFixed(2)} kW`;
7563
+ const value = context.parsed.y;
7564
+ return getFormattedValue(selectedChartKey, value);
7492
7565
  }
7493
7566
  }
7494
7567
  }
@@ -7497,23 +7570,57 @@ ${rangeText}`;
7497
7570
  x: {
7498
7571
  type: "linear",
7499
7572
  ticks: {
7573
+ maxRotation: 45,
7574
+ minRotation: 0,
7500
7575
  callback: function(value) {
7501
7576
  const date = new Date(value);
7502
- return date.toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" });
7577
+ return date.toLocaleTimeString(locale, {
7578
+ hour: "2-digit",
7579
+ minute: "2-digit",
7580
+ second: "2-digit"
7581
+ });
7503
7582
  }
7583
+ },
7584
+ title: {
7585
+ display: true,
7586
+ text: "Hora"
7504
7587
  }
7505
7588
  },
7506
7589
  y: {
7507
7590
  beginAtZero: true,
7591
+ ticks: {
7592
+ callback: function(value) {
7593
+ if (selectedChartKey === "consumption" || selectedChartKey === "power") {
7594
+ if (value >= 1e3) {
7595
+ return `${(value / 1e3).toFixed(1)} kW`;
7596
+ }
7597
+ return `${value} W`;
7598
+ }
7599
+ return `${value} ${config.unit}`;
7600
+ }
7601
+ },
7508
7602
  title: {
7509
7603
  display: true,
7510
- text: "kW"
7604
+ text: selectedChartKey === "consumption" || selectedChartKey === "power" ? "W" : config.unit
7511
7605
  }
7512
7606
  }
7513
7607
  }
7514
7608
  }
7515
7609
  });
7516
7610
  }
7611
+ function updateChartKey(newKey) {
7612
+ selectedChartKey = newKey;
7613
+ if (chart) {
7614
+ chart.destroy();
7615
+ chart = null;
7616
+ }
7617
+ initializeChart();
7618
+ if (telemetryHistory.has(selectedChartKey)) {
7619
+ const selectedHistory = telemetryHistory.get(selectedChartKey);
7620
+ chart.data.datasets[0].data = selectedHistory;
7621
+ chart.update("none");
7622
+ }
7623
+ }
7517
7624
  async function refreshData() {
7518
7625
  try {
7519
7626
  const data = await fetchLatestTelemetry();
@@ -7525,9 +7632,7 @@ ${rangeText}`;
7525
7632
  if (loadingState.style.display !== "none") {
7526
7633
  loadingState.style.display = "none";
7527
7634
  telemetryContent.style.display = "block";
7528
- if (telemetryKeys.includes("power")) {
7529
- initializeChart();
7530
- }
7635
+ initializeChart();
7531
7636
  }
7532
7637
  } catch (error) {
7533
7638
  console.error("[RealTimeTelemetry] Error fetching data:", error);
@@ -7595,6 +7700,10 @@ ${rangeText}`;
7595
7700
  closeBtn.addEventListener("click", closeModal);
7596
7701
  pauseBtn.addEventListener("click", togglePause);
7597
7702
  exportBtn.addEventListener("click", exportToCSV2);
7703
+ chartKeySelector.addEventListener("change", (e) => {
7704
+ const newKey = e.target.value;
7705
+ updateChartKey(newKey);
7706
+ });
7598
7707
  overlay.addEventListener("click", (e) => {
7599
7708
  if (e.target === overlay) {
7600
7709
  closeModal();
@@ -8717,18 +8826,20 @@ ${rangeText}`;
8717
8826
  "/assets/vendor/moment.min.js",
8718
8827
  "/assets/vendor/daterangepicker.min.js"
8719
8828
  ];
8720
- var PT_BR_LOCALE = {
8721
- format: "DD/MM/YY HH:mm",
8722
- separator: " at\xE9 ",
8723
- applyLabel: "Aplicar",
8724
- cancelLabel: "Cancelar",
8725
- fromLabel: "De",
8726
- toLabel: "At\xE9",
8727
- customRangeLabel: "Personalizado",
8728
- daysOfWeek: ["Do", "Se", "Te", "Qa", "Qi", "Se", "Sa"],
8729
- monthNames: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"],
8730
- firstDay: 1
8731
- };
8829
+ function getLocaleConfig(includeTime = false) {
8830
+ return {
8831
+ format: includeTime ? "DD/MM/YY HH:mm" : "DD/MM/YYYY",
8832
+ separator: " at\xE9 ",
8833
+ applyLabel: "Aplicar",
8834
+ cancelLabel: "Cancelar",
8835
+ fromLabel: "De",
8836
+ toLabel: "At\xE9",
8837
+ customRangeLabel: "Personalizado",
8838
+ daysOfWeek: ["Do", "Se", "Te", "Qa", "Qi", "Se", "Sa"],
8839
+ monthNames: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"],
8840
+ firstDay: 1
8841
+ };
8842
+ }
8732
8843
  var CDNLoader = class {
8733
8844
  static jQueryInstance = null;
8734
8845
  static loadingPromise = null;
@@ -8849,14 +8960,46 @@ ${rangeText}`;
8849
8960
  helpText.style.display = "flex";
8850
8961
  helpText.style.alignItems = "center";
8851
8962
  input.parentNode?.appendChild(helpText);
8963
+ const includeTime = opts.includeTime === true;
8964
+ const timePrecision = opts.timePrecision || "minute";
8965
+ const localeConfig = getLocaleConfig(includeTime);
8852
8966
  const moment = window.moment;
8853
- const startDate = opts.presetStart ? moment(opts.presetStart).startOf("day") : moment().startOf("month");
8854
- const endDate = opts.presetEnd ? moment(opts.presetEnd).endOf("day") : moment().endOf("day");
8967
+ let startDate, endDate;
8968
+ if (includeTime) {
8969
+ startDate = opts.presetStart ? moment(opts.presetStart) : moment().startOf("day");
8970
+ endDate = opts.presetEnd ? moment(opts.presetEnd) : moment();
8971
+ } else {
8972
+ startDate = opts.presetStart ? moment(opts.presetStart).startOf("day") : moment().startOf("month");
8973
+ endDate = opts.presetEnd ? moment(opts.presetEnd).endOf("day") : moment().endOf("day");
8974
+ }
8975
+ let ranges;
8976
+ if (includeTime) {
8977
+ const now = moment();
8978
+ ranges = {
8979
+ "\xDAltima hora": [moment().subtract(1, "hours"), now.clone()],
8980
+ "\xDAltimas 6 horas": [moment().subtract(6, "hours"), now.clone()],
8981
+ "\xDAltimas 12 horas": [moment().subtract(12, "hours"), now.clone()],
8982
+ "\xDAltimas 24 horas": [moment().subtract(24, "hours"), now.clone()],
8983
+ "Hoje": [moment().startOf("day"), now.clone()],
8984
+ "Ontem": [moment().subtract(1, "day").startOf("day"), moment().subtract(1, "day").endOf("day")],
8985
+ "\xDAltimos 7 dias": [moment().subtract(6, "days").startOf("day"), now.clone()],
8986
+ "Este m\xEAs": [moment().startOf("month"), now.clone()]
8987
+ };
8988
+ } else {
8989
+ ranges = {
8990
+ "Hoje": [moment().startOf("day"), moment().endOf("day")],
8991
+ "\xDAltimos 7 dias": [moment().subtract(6, "days").startOf("day"), moment().endOf("day")],
8992
+ "\xDAltimos 30 dias": [moment().subtract(29, "days").startOf("day"), moment().endOf("day")],
8993
+ "M\xEAs Anterior": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")]
8994
+ };
8995
+ }
8855
8996
  $input.daterangepicker({
8856
8997
  parentEl: opts.parentEl || document.body,
8857
- timePicker: true,
8998
+ timePicker: includeTime,
8999
+ // RFC-0086: Conditional time picker
8858
9000
  timePicker24Hour: true,
8859
- timePickerIncrement: 1,
9001
+ timePickerIncrement: timePrecision === "hour" ? 60 : 1,
9002
+ // RFC-0086: Hour vs minute precision
8860
9003
  autoApply: true,
8861
9004
  autoUpdateInput: true,
8862
9005
  linkedCalendars: true,
@@ -8867,15 +9010,12 @@ ${rangeText}`;
8867
9010
  endDate,
8868
9011
  opens: "right",
8869
9012
  drops: "down",
8870
- locale: PT_BR_LOCALE,
9013
+ locale: localeConfig,
9014
+ // RFC-0086: Dynamic locale format
8871
9015
  applyButtonClasses: "btn btn-primary",
8872
9016
  cancelClass: "btn btn-muted",
8873
- ranges: {
8874
- "Hoje": [moment().startOf("day"), moment().endOf("day")],
8875
- "\xDAltimos 7 dias": [moment().subtract(6, "days").startOf("day"), moment().endOf("day")],
8876
- "\xDAltimos 30 dias": [moment().subtract(29, "days").startOf("day"), moment().endOf("day")],
8877
- "M\xEAs Anterior": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")]
8878
- }
9017
+ ranges
9018
+ // RFC-0086: Dynamic ranges
8879
9019
  });
8880
9020
  updateInputDisplay();
8881
9021
  $input.on("apply.daterangepicker.myio", () => {
@@ -8894,7 +9034,7 @@ ${rangeText}`;
8894
9034
  function updateInputDisplay() {
8895
9035
  const picker = $input.data("daterangepicker");
8896
9036
  if (picker) {
8897
- const formatted = `${picker.startDate.format(PT_BR_LOCALE.format)}${PT_BR_LOCALE.separator}${picker.endDate.format(PT_BR_LOCALE.format)}`;
9037
+ const formatted = `${picker.startDate.format(localeConfig.format)}${localeConfig.separator}${picker.endDate.format(localeConfig.format)}`;
8898
9038
  $input.val(formatted);
8899
9039
  }
8900
9040
  }
@@ -8902,8 +9042,8 @@ ${rangeText}`;
8902
9042
  const picker = $input.data("daterangepicker");
8903
9043
  const startISO = picker.startDate.format("YYYY-MM-DD[T]HH:mm:ssZ");
8904
9044
  const endISO = picker.endDate.format("YYYY-MM-DD[T]HH:mm:ssZ");
8905
- const startLabel = picker.startDate.format(PT_BR_LOCALE.format);
8906
- const endLabel = picker.endDate.format(PT_BR_LOCALE.format);
9045
+ const startLabel = picker.startDate.format(localeConfig.format);
9046
+ const endLabel = picker.endDate.format(localeConfig.format);
8907
9047
  return { startISO, endISO, startLabel, endLabel };
8908
9048
  }
8909
9049
  function setDates(startISO, endISO) {
@@ -9699,7 +9839,7 @@ ${rangeText}`;
9699
9839
  isEmpty = false;
9700
9840
  const sortedData = rawSeries.sort((a, b) => a.ts - b.ts);
9701
9841
  const points = [];
9702
- const isAggregated = aggregation && aggregation !== "NONE";
9842
+ const isAggregated = aggregation !== "NONE";
9703
9843
  if (isAggregated) {
9704
9844
  for (let i = 0; i < sortedData.length; i++) {
9705
9845
  const current = sortedData[i];
@@ -9874,10 +10014,7 @@ ${rangeText}`;
9874
10014
  <button class="myio-demand-modal-btn-update" type="button">
9875
10015
  ${strings.updatePeriod}
9876
10016
  </button>
9877
- <button id="realtime-toggle-btn" class="myio-demand-modal-btn-realtime" type="button" title="Ativar modo tempo real (atualiza\xE7\xE3o a cada 8 segundos)">
9878
- <span class="realtime-indicator"></span>
9879
- <span class="realtime-text">REAL TIME</span>
9880
- </button>
10017
+ <!-- RFC-0084: REAL TIME button removed - use RealTimeTelemetryModal instead -->
9881
10018
  <div class="myio-demand-modal-period-error" style="display: none;"></div>
9882
10019
  </div>
9883
10020
 
@@ -9925,7 +10062,6 @@ ${rangeText}`;
9925
10062
  const dateStartInput = overlay.querySelector(".myio-demand-modal-date-start");
9926
10063
  const dateEndInput = overlay.querySelector(".myio-demand-modal-date-end");
9927
10064
  const updateBtn = overlay.querySelector(".myio-demand-modal-btn-update");
9928
- const realTimeToggleBtn = overlay.querySelector("#realtime-toggle-btn");
9929
10065
  const periodErrorEl = overlay.querySelector(".myio-demand-modal-period-error");
9930
10066
  const telemetryTypeSelect = overlay.querySelector("#telemetry-type-select");
9931
10067
  const intervalSelect = overlay.querySelector("#demand-interval-select");
@@ -9936,16 +10072,10 @@ ${rangeText}`;
9936
10072
  let currentStartDate = params.startDate;
9937
10073
  let currentEndDate = params.endDate;
9938
10074
  let activeTelemetryType = currentTelemetryType;
9939
- let isRealTimeMode = false;
9940
- let realTimeIntervalId = null;
9941
- let lastFetchedTimestamp = null;
9942
10075
  const originalOverflow = document.body.style.overflow;
9943
10076
  document.body.style.overflow = "hidden";
9944
10077
  const releaseFocusTrap = createFocusTrap(overlay);
9945
10078
  function closeModal() {
9946
- if (isRealTimeMode && realTimeIntervalId) {
9947
- window.clearInterval(realTimeIntervalId);
9948
- }
9949
10079
  if (chart) {
9950
10080
  chart.destroy();
9951
10081
  }
@@ -10078,124 +10208,6 @@ ${rangeText}`;
10078
10208
  btn.innerHTML = originalHtml;
10079
10209
  }
10080
10210
  }
10081
- function getTodayStart() {
10082
- const today = /* @__PURE__ */ new Date();
10083
- today.setHours(0, 0, 0, 0);
10084
- return today.toISOString();
10085
- }
10086
- async function enableRealTimeMode() {
10087
- try {
10088
- currentStartDate = getTodayStart();
10089
- currentEndDate = (/* @__PURE__ */ new Date()).toISOString();
10090
- initializeDateInputs();
10091
- dateStartInput.disabled = true;
10092
- dateEndInput.disabled = true;
10093
- dateStartInput.style.opacity = "0.5";
10094
- dateEndInput.style.opacity = "0.5";
10095
- if (intervalSelect) {
10096
- intervalSelect.disabled = true;
10097
- intervalSelect.style.opacity = "0.5";
10098
- }
10099
- if (aggSelect) {
10100
- aggSelect.disabled = true;
10101
- aggSelect.style.opacity = "0.5";
10102
- }
10103
- if (intervalSelect) intervalSelect.value = "8000";
10104
- if (aggSelect) aggSelect.value = "AVG";
10105
- await loadData();
10106
- lastFetchedTimestamp = Date.now();
10107
- const intervalMs = params.realTimeInterval || 8e3;
10108
- realTimeIntervalId = window.setInterval(async () => {
10109
- try {
10110
- await fetchIncrementalData();
10111
- } catch (error) {
10112
- console.error("[DemandModal] Real-time update failed:", error);
10113
- }
10114
- }, intervalMs);
10115
- realTimeToggleBtn.classList.add("active");
10116
- isRealTimeMode = true;
10117
- console.log(`[DemandModal] Real-time mode started (${intervalMs}ms interval)`);
10118
- } catch (error) {
10119
- console.error("[DemandModal] Failed to enable real-time mode:", error);
10120
- await disableRealTimeMode();
10121
- alert("Erro ao ativar modo tempo real. Tente novamente.");
10122
- }
10123
- }
10124
- async function fetchIncrementalData() {
10125
- if (!lastFetchedTimestamp) {
10126
- throw new Error("No last fetched timestamp available");
10127
- }
10128
- const startTs = lastFetchedTimestamp;
10129
- const endTs = Date.now();
10130
- const startDate = new Date(startTs).toISOString();
10131
- const endDate = new Date(endTs).toISOString();
10132
- const keysStr = Array.isArray(activeTelemetryType.keys) ? activeTelemetryType.keys.join(",") : activeTelemetryType.keys;
10133
- const telemetryQuery = {
10134
- keys: keysStr,
10135
- interval: 8e3,
10136
- // 8 seconds (fixed for real-time mode)
10137
- agg: "AVG",
10138
- // Average (fixed for real-time mode)
10139
- intervalType: "MILLISECONDS",
10140
- orderBy: "ASC"
10141
- };
10142
- const newRawData = params.fetcher ? await params.fetcher({ token: params.token, deviceId: params.deviceId, startDate, endDate, telemetryQuery }) : await fetchTelemetryData(params.token, params.deviceId, startDate, endDate, telemetryQuery);
10143
- const newChartData = processMultiSeriesChartData(
10144
- newRawData,
10145
- keysStr,
10146
- params.correctionFactor || 1,
10147
- locale,
10148
- "AVG",
10149
- params.timezoneOffset
10150
- );
10151
- if (!newChartData.isEmpty && chart && chartData) {
10152
- newChartData.series.forEach((newSeries, seriesIndex) => {
10153
- if (newSeries.points.length > 0 && chart.data.datasets[seriesIndex]) {
10154
- newSeries.points.forEach((point) => {
10155
- chart.data.datasets[seriesIndex].data.push({
10156
- x: point.x,
10157
- y: point.y
10158
- });
10159
- chart.data.labels.push(point.x);
10160
- });
10161
- }
10162
- });
10163
- chart.update("none");
10164
- if (params.realTimeAutoScroll !== false) {
10165
- const latestTimestamp = newChartData.series[0]?.points[newChartData.series[0].points.length - 1]?.x;
10166
- if (latestTimestamp && chart.options.scales?.x) {
10167
- const visibleRange = 3e5;
10168
- chart.options.scales.x.min = latestTimestamp - visibleRange;
10169
- chart.options.scales.x.max = latestTimestamp;
10170
- chart.update("none");
10171
- }
10172
- }
10173
- }
10174
- lastFetchedTimestamp = endTs;
10175
- console.log(`[DemandModal] Incremental fetch completed (${newChartData.series.reduce((sum, s) => sum + s.points.length, 0)} new points)`);
10176
- }
10177
- async function disableRealTimeMode() {
10178
- if (realTimeIntervalId) {
10179
- window.clearInterval(realTimeIntervalId);
10180
- realTimeIntervalId = null;
10181
- }
10182
- dateStartInput.disabled = false;
10183
- dateEndInput.disabled = false;
10184
- dateStartInput.style.opacity = "1";
10185
- dateEndInput.style.opacity = "1";
10186
- if (intervalSelect) {
10187
- intervalSelect.disabled = false;
10188
- intervalSelect.style.opacity = "1";
10189
- }
10190
- if (aggSelect) {
10191
- aggSelect.disabled = false;
10192
- aggSelect.style.opacity = "1";
10193
- }
10194
- isRealTimeMode = false;
10195
- lastFetchedTimestamp = null;
10196
- realTimeToggleBtn.classList.remove("active");
10197
- console.log("[DemandModal] Real-time mode stopped");
10198
- }
10199
10211
  function initializeDateInputs() {
10200
10212
  const startDate = new Date(currentStartDate);
10201
10213
  const endDate = new Date(currentEndDate);
@@ -10276,13 +10288,6 @@ ${rangeText}`;
10276
10288
  pdfBtn.addEventListener("click", exportPdf);
10277
10289
  csvBtn.addEventListener("click", exportCsv);
10278
10290
  updateBtn.addEventListener("click", updatePeriod);
10279
- realTimeToggleBtn.addEventListener("click", async () => {
10280
- if (isRealTimeMode) {
10281
- await disableRealTimeMode();
10282
- } else {
10283
- await enableRealTimeMode();
10284
- }
10285
- });
10286
10291
  if (telemetryTypeSelect && allowTelemetrySwitch) {
10287
10292
  const debouncedSwitch = debounce(switchTelemetryType, 300);
10288
10293
  telemetryTypeSelect.addEventListener("change", (e) => {