myio-js-library 0.1.211 → 0.1.213

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
@@ -21457,9 +21457,14 @@ var WaterTankModalView = class {
21457
21457
  overlay = null;
21458
21458
  modal = null;
21459
21459
  i18n;
21460
+ chartDisplayMode = "water_level";
21461
+ // RFC-0107: Default to water_level (m.c.a)
21460
21462
  constructor(config) {
21461
21463
  this.config = config;
21462
21464
  this.i18n = this.getI18n();
21465
+ if (config.params.displayKey) {
21466
+ this.chartDisplayMode = config.params.displayKey;
21467
+ }
21463
21468
  }
21464
21469
  /**
21465
21470
  * Get i18n strings with defaults
@@ -21771,14 +21776,14 @@ var WaterTankModalView = class {
21771
21776
  `;
21772
21777
  }
21773
21778
  /**
21774
- * Render chart section - shows water_level (m.c.a) over time
21779
+ * RFC-0107: Render chart section with display mode selector
21780
+ * Shows water_level (m.c.a) or water_percentage (%) based on user selection
21775
21781
  */
21776
21782
  renderChart() {
21777
21783
  const { data } = this.config;
21778
- const waterLevelPoints = data.telemetry.filter(
21779
- (p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
21780
- );
21781
- if (waterLevelPoints.length === 0) {
21784
+ const chartPoints = this.getChartDataPoints();
21785
+ if (chartPoints.length === 0) {
21786
+ const displayLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
21782
21787
  return `
21783
21788
  <div style="
21784
21789
  background: #f8f9fa;
@@ -21790,13 +21795,14 @@ var WaterTankModalView = class {
21790
21795
  <div style="font-size: 48px; margin-bottom: 16px; opacity: 0.3;">\u{1F4CA}</div>
21791
21796
  <div style="color: #7f8c8d; font-size: 16px;">${this.i18n.noData}</div>
21792
21797
  <div style="color: #bdc3c7; font-size: 13px; margin-top: 8px;">
21793
- No water_level (m.c.a) data available for this period
21798
+ No ${this.chartDisplayMode} (${displayLabel}) data available for this period
21794
21799
  </div>
21795
21800
  </div>
21796
21801
  `;
21797
21802
  }
21798
- const firstTs = waterLevelPoints[0]?.ts;
21799
- const lastTs = waterLevelPoints[waterLevelPoints.length - 1]?.ts;
21803
+ const firstTs = chartPoints[0]?.ts;
21804
+ const lastTs = chartPoints[chartPoints.length - 1]?.ts;
21805
+ const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
21800
21806
  return `
21801
21807
  <div style="
21802
21808
  background: white;
@@ -21804,12 +21810,38 @@ var WaterTankModalView = class {
21804
21810
  border-radius: 8px;
21805
21811
  padding: 20px;
21806
21812
  ">
21807
- <h3 style="
21808
- margin: 0 0 16px 0;
21809
- font-size: 16px;
21810
- font-weight: 600;
21811
- color: #2c3e50;
21812
- ">${this.i18n.levelChart}</h3>
21813
+ <div style="
21814
+ display: flex;
21815
+ align-items: center;
21816
+ justify-content: space-between;
21817
+ margin-bottom: 16px;
21818
+ ">
21819
+ <h3 style="
21820
+ margin: 0;
21821
+ font-size: 16px;
21822
+ font-weight: 600;
21823
+ color: #2c3e50;
21824
+ ">${chartTitle}</h3>
21825
+ <div style="
21826
+ display: flex;
21827
+ align-items: center;
21828
+ gap: 8px;
21829
+ ">
21830
+ <span style="font-size: 13px; color: #7f8c8d;">Display:</span>
21831
+ <select id="myio-water-tank-display-mode" style="
21832
+ padding: 6px 12px;
21833
+ border: 1px solid #ddd;
21834
+ border-radius: 6px;
21835
+ font-size: 13px;
21836
+ color: #2c3e50;
21837
+ background: white;
21838
+ cursor: pointer;
21839
+ ">
21840
+ <option value="water_level" ${this.chartDisplayMode === "water_level" ? "selected" : ""}>Level (m.c.a)</option>
21841
+ <option value="water_percentage" ${this.chartDisplayMode === "water_percentage" ? "selected" : ""}>Percentage (%)</option>
21842
+ </select>
21843
+ </div>
21844
+ </div>
21813
21845
  <canvas id="myio-water-tank-chart" style="width: 100%; height: 280px;"></canvas>
21814
21846
  ${firstTs && lastTs ? `
21815
21847
  <div style="
@@ -21819,12 +21851,29 @@ var WaterTankModalView = class {
21819
21851
  text-align: center;
21820
21852
  ">
21821
21853
  ${this.formatDate(firstTs, false)} \u2014 ${this.formatDate(lastTs, false)}
21822
- (${waterLevelPoints.length} readings)
21854
+ (${chartPoints.length} readings)
21823
21855
  </div>
21824
21856
  ` : ""}
21825
21857
  </div>
21826
21858
  `;
21827
21859
  }
21860
+ /**
21861
+ * RFC-0107: Get chart data points based on current display mode
21862
+ */
21863
+ getChartDataPoints() {
21864
+ const { data } = this.config;
21865
+ if (this.chartDisplayMode === "water_percentage") {
21866
+ const percentagePoints = data.telemetry.filter((p) => p.key === "water_percentage");
21867
+ return percentagePoints.map((p) => ({
21868
+ ...p,
21869
+ value: p.value <= 1.5 ? p.value * 100 : p.value
21870
+ }));
21871
+ } else {
21872
+ return data.telemetry.filter(
21873
+ (p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
21874
+ );
21875
+ }
21876
+ }
21828
21877
  /**
21829
21878
  * Render footer with actions
21830
21879
  */
@@ -21874,6 +21923,13 @@ var WaterTankModalView = class {
21874
21923
  if (applyDatesBtn) {
21875
21924
  applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
21876
21925
  }
21926
+ const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
21927
+ if (displayModeSelect) {
21928
+ displayModeSelect.addEventListener("change", () => {
21929
+ this.chartDisplayMode = displayModeSelect.value;
21930
+ this.refreshChart();
21931
+ });
21932
+ }
21877
21933
  this.overlay.addEventListener("click", (e) => {
21878
21934
  if (e.target === this.overlay) {
21879
21935
  this.config.onClose();
@@ -21918,15 +21974,25 @@ var WaterTankModalView = class {
21918
21974
  }
21919
21975
  }
21920
21976
  /**
21921
- * Render chart using Canvas API - shows water_level (m.c.a) over time
21977
+ * RFC-0107: Refresh chart when display mode changes
21978
+ */
21979
+ refreshChart() {
21980
+ if (!this.modal) return;
21981
+ const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
21982
+ const titleEl = this.modal.querySelector(".myio-water-tank-modal-body h3:last-of-type");
21983
+ if (titleEl) {
21984
+ titleEl.textContent = chartTitle;
21985
+ }
21986
+ this.renderCanvasChart();
21987
+ }
21988
+ /**
21989
+ * RFC-0107: Render chart using Canvas API
21990
+ * Shows water_level (m.c.a) or water_percentage (%) based on display mode
21922
21991
  */
21923
21992
  renderCanvasChart() {
21924
21993
  const canvas = document.getElementById("myio-water-tank-chart");
21925
21994
  if (!canvas) return;
21926
- const { data } = this.config;
21927
- const points = data.telemetry.filter(
21928
- (p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
21929
- );
21995
+ const points = this.getChartDataPoints();
21930
21996
  if (points.length < 2) return;
21931
21997
  const ctx = canvas.getContext("2d");
21932
21998
  if (!ctx) return;
@@ -21963,13 +22029,14 @@ var WaterTankModalView = class {
21963
22029
  ctx.stroke();
21964
22030
  ctx.fillText(`${value.toFixed(2)}`, padding.left - 8, y + 4);
21965
22031
  }
22032
+ const yAxisLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
21966
22033
  ctx.save();
21967
22034
  ctx.translate(15, height / 2);
21968
22035
  ctx.rotate(-Math.PI / 2);
21969
22036
  ctx.textAlign = "center";
21970
22037
  ctx.fillStyle = "#666";
21971
22038
  ctx.font = "12px Arial";
21972
- ctx.fillText("m.c.a", 0, 0);
22039
+ ctx.fillText(yAxisLabel, 0, 0);
21973
22040
  ctx.restore();
21974
22041
  ctx.strokeStyle = "#ccc";
21975
22042
  ctx.lineWidth = 1;
@@ -22055,6 +22122,13 @@ var WaterTankModalView = class {
22055
22122
  if (applyDatesBtn) {
22056
22123
  applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
22057
22124
  }
22125
+ const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
22126
+ if (displayModeSelect) {
22127
+ displayModeSelect.addEventListener("change", () => {
22128
+ this.chartDisplayMode = displayModeSelect.value;
22129
+ this.refreshChart();
22130
+ });
22131
+ }
22058
22132
  requestAnimationFrame(() => {
22059
22133
  this.renderCanvasChart();
22060
22134
  });
@@ -22227,13 +22301,12 @@ var WaterTankModal = class {
22227
22301
  }
22228
22302
  /**
22229
22303
  * Transform raw ThingsBoard response to our data points
22230
- * RFC-0107: Support displayKey option to choose between water_level or water_percentage
22304
+ * RFC-0107: Keep ALL data points with their original keys (no deduplication)
22305
+ * This allows the chart to switch between water_level and water_percentage dynamically
22231
22306
  */
22232
22307
  transformTelemetryData(rawData, keys) {
22233
22308
  const allPoints = [];
22234
- const displayKey = this.options.displayKey || "water_percentage";
22235
- const prioritizedKeys = displayKey && rawData[displayKey] ? [displayKey, ...keys.filter((k) => k !== displayKey)] : keys;
22236
- for (const key of prioritizedKeys) {
22309
+ for (const key of keys) {
22237
22310
  if (rawData[key] && Array.isArray(rawData[key])) {
22238
22311
  const keyPoints = rawData[key].map((point) => {
22239
22312
  let value = typeof point.value === "string" ? parseFloat(point.value) : point.value;
@@ -22250,16 +22323,12 @@ var WaterTankModal = class {
22250
22323
  }
22251
22324
  }
22252
22325
  allPoints.sort((a, b) => a.ts - b.ts);
22253
- const uniquePoints = [];
22254
- const seenTimestamps = /* @__PURE__ */ new Set();
22255
- for (const point of allPoints) {
22256
- if (!seenTimestamps.has(point.ts)) {
22257
- seenTimestamps.add(point.ts);
22258
- uniquePoints.push(point);
22259
- }
22326
+ const keyCounts = {};
22327
+ for (const p of allPoints) {
22328
+ keyCounts[p.key || "unknown"] = (keyCounts[p.key || "unknown"] || 0) + 1;
22260
22329
  }
22261
- console.log(`[WaterTankModal] Transformed ${uniquePoints.length} points, displayKey: ${displayKey}`);
22262
- return uniquePoints;
22330
+ console.log(`[WaterTankModal] Transformed ${allPoints.length} total points:`, keyCounts);
22331
+ return allPoints;
22263
22332
  }
22264
22333
  /**
22265
22334
  * Calculate summary statistics from telemetry data
package/dist/index.js CHANGED
@@ -21285,9 +21285,14 @@ var WaterTankModalView = class {
21285
21285
  overlay = null;
21286
21286
  modal = null;
21287
21287
  i18n;
21288
+ chartDisplayMode = "water_level";
21289
+ // RFC-0107: Default to water_level (m.c.a)
21288
21290
  constructor(config) {
21289
21291
  this.config = config;
21290
21292
  this.i18n = this.getI18n();
21293
+ if (config.params.displayKey) {
21294
+ this.chartDisplayMode = config.params.displayKey;
21295
+ }
21291
21296
  }
21292
21297
  /**
21293
21298
  * Get i18n strings with defaults
@@ -21599,14 +21604,14 @@ var WaterTankModalView = class {
21599
21604
  `;
21600
21605
  }
21601
21606
  /**
21602
- * Render chart section - shows water_level (m.c.a) over time
21607
+ * RFC-0107: Render chart section with display mode selector
21608
+ * Shows water_level (m.c.a) or water_percentage (%) based on user selection
21603
21609
  */
21604
21610
  renderChart() {
21605
21611
  const { data } = this.config;
21606
- const waterLevelPoints = data.telemetry.filter(
21607
- (p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
21608
- );
21609
- if (waterLevelPoints.length === 0) {
21612
+ const chartPoints = this.getChartDataPoints();
21613
+ if (chartPoints.length === 0) {
21614
+ const displayLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
21610
21615
  return `
21611
21616
  <div style="
21612
21617
  background: #f8f9fa;
@@ -21618,13 +21623,14 @@ var WaterTankModalView = class {
21618
21623
  <div style="font-size: 48px; margin-bottom: 16px; opacity: 0.3;">\u{1F4CA}</div>
21619
21624
  <div style="color: #7f8c8d; font-size: 16px;">${this.i18n.noData}</div>
21620
21625
  <div style="color: #bdc3c7; font-size: 13px; margin-top: 8px;">
21621
- No water_level (m.c.a) data available for this period
21626
+ No ${this.chartDisplayMode} (${displayLabel}) data available for this period
21622
21627
  </div>
21623
21628
  </div>
21624
21629
  `;
21625
21630
  }
21626
- const firstTs = waterLevelPoints[0]?.ts;
21627
- const lastTs = waterLevelPoints[waterLevelPoints.length - 1]?.ts;
21631
+ const firstTs = chartPoints[0]?.ts;
21632
+ const lastTs = chartPoints[chartPoints.length - 1]?.ts;
21633
+ const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
21628
21634
  return `
21629
21635
  <div style="
21630
21636
  background: white;
@@ -21632,12 +21638,38 @@ var WaterTankModalView = class {
21632
21638
  border-radius: 8px;
21633
21639
  padding: 20px;
21634
21640
  ">
21635
- <h3 style="
21636
- margin: 0 0 16px 0;
21637
- font-size: 16px;
21638
- font-weight: 600;
21639
- color: #2c3e50;
21640
- ">${this.i18n.levelChart}</h3>
21641
+ <div style="
21642
+ display: flex;
21643
+ align-items: center;
21644
+ justify-content: space-between;
21645
+ margin-bottom: 16px;
21646
+ ">
21647
+ <h3 style="
21648
+ margin: 0;
21649
+ font-size: 16px;
21650
+ font-weight: 600;
21651
+ color: #2c3e50;
21652
+ ">${chartTitle}</h3>
21653
+ <div style="
21654
+ display: flex;
21655
+ align-items: center;
21656
+ gap: 8px;
21657
+ ">
21658
+ <span style="font-size: 13px; color: #7f8c8d;">Display:</span>
21659
+ <select id="myio-water-tank-display-mode" style="
21660
+ padding: 6px 12px;
21661
+ border: 1px solid #ddd;
21662
+ border-radius: 6px;
21663
+ font-size: 13px;
21664
+ color: #2c3e50;
21665
+ background: white;
21666
+ cursor: pointer;
21667
+ ">
21668
+ <option value="water_level" ${this.chartDisplayMode === "water_level" ? "selected" : ""}>Level (m.c.a)</option>
21669
+ <option value="water_percentage" ${this.chartDisplayMode === "water_percentage" ? "selected" : ""}>Percentage (%)</option>
21670
+ </select>
21671
+ </div>
21672
+ </div>
21641
21673
  <canvas id="myio-water-tank-chart" style="width: 100%; height: 280px;"></canvas>
21642
21674
  ${firstTs && lastTs ? `
21643
21675
  <div style="
@@ -21647,12 +21679,29 @@ var WaterTankModalView = class {
21647
21679
  text-align: center;
21648
21680
  ">
21649
21681
  ${this.formatDate(firstTs, false)} \u2014 ${this.formatDate(lastTs, false)}
21650
- (${waterLevelPoints.length} readings)
21682
+ (${chartPoints.length} readings)
21651
21683
  </div>
21652
21684
  ` : ""}
21653
21685
  </div>
21654
21686
  `;
21655
21687
  }
21688
+ /**
21689
+ * RFC-0107: Get chart data points based on current display mode
21690
+ */
21691
+ getChartDataPoints() {
21692
+ const { data } = this.config;
21693
+ if (this.chartDisplayMode === "water_percentage") {
21694
+ const percentagePoints = data.telemetry.filter((p) => p.key === "water_percentage");
21695
+ return percentagePoints.map((p) => ({
21696
+ ...p,
21697
+ value: p.value <= 1.5 ? p.value * 100 : p.value
21698
+ }));
21699
+ } else {
21700
+ return data.telemetry.filter(
21701
+ (p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
21702
+ );
21703
+ }
21704
+ }
21656
21705
  /**
21657
21706
  * Render footer with actions
21658
21707
  */
@@ -21702,6 +21751,13 @@ var WaterTankModalView = class {
21702
21751
  if (applyDatesBtn) {
21703
21752
  applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
21704
21753
  }
21754
+ const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
21755
+ if (displayModeSelect) {
21756
+ displayModeSelect.addEventListener("change", () => {
21757
+ this.chartDisplayMode = displayModeSelect.value;
21758
+ this.refreshChart();
21759
+ });
21760
+ }
21705
21761
  this.overlay.addEventListener("click", (e) => {
21706
21762
  if (e.target === this.overlay) {
21707
21763
  this.config.onClose();
@@ -21746,15 +21802,25 @@ var WaterTankModalView = class {
21746
21802
  }
21747
21803
  }
21748
21804
  /**
21749
- * Render chart using Canvas API - shows water_level (m.c.a) over time
21805
+ * RFC-0107: Refresh chart when display mode changes
21806
+ */
21807
+ refreshChart() {
21808
+ if (!this.modal) return;
21809
+ const chartTitle = this.chartDisplayMode === "water_percentage" ? "Water Level History (%)" : this.i18n.levelChart;
21810
+ const titleEl = this.modal.querySelector(".myio-water-tank-modal-body h3:last-of-type");
21811
+ if (titleEl) {
21812
+ titleEl.textContent = chartTitle;
21813
+ }
21814
+ this.renderCanvasChart();
21815
+ }
21816
+ /**
21817
+ * RFC-0107: Render chart using Canvas API
21818
+ * Shows water_level (m.c.a) or water_percentage (%) based on display mode
21750
21819
  */
21751
21820
  renderCanvasChart() {
21752
21821
  const canvas = document.getElementById("myio-water-tank-chart");
21753
21822
  if (!canvas) return;
21754
- const { data } = this.config;
21755
- const points = data.telemetry.filter(
21756
- (p) => p.key === "water_level" || p.key === "waterLevel" || p.key === "nivel" || p.key === "level"
21757
- );
21823
+ const points = this.getChartDataPoints();
21758
21824
  if (points.length < 2) return;
21759
21825
  const ctx = canvas.getContext("2d");
21760
21826
  if (!ctx) return;
@@ -21791,13 +21857,14 @@ var WaterTankModalView = class {
21791
21857
  ctx.stroke();
21792
21858
  ctx.fillText(`${value.toFixed(2)}`, padding.left - 8, y + 4);
21793
21859
  }
21860
+ const yAxisLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
21794
21861
  ctx.save();
21795
21862
  ctx.translate(15, height / 2);
21796
21863
  ctx.rotate(-Math.PI / 2);
21797
21864
  ctx.textAlign = "center";
21798
21865
  ctx.fillStyle = "#666";
21799
21866
  ctx.font = "12px Arial";
21800
- ctx.fillText("m.c.a", 0, 0);
21867
+ ctx.fillText(yAxisLabel, 0, 0);
21801
21868
  ctx.restore();
21802
21869
  ctx.strokeStyle = "#ccc";
21803
21870
  ctx.lineWidth = 1;
@@ -21883,6 +21950,13 @@ var WaterTankModalView = class {
21883
21950
  if (applyDatesBtn) {
21884
21951
  applyDatesBtn.addEventListener("click", () => this.handleDateRangeChange());
21885
21952
  }
21953
+ const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
21954
+ if (displayModeSelect) {
21955
+ displayModeSelect.addEventListener("change", () => {
21956
+ this.chartDisplayMode = displayModeSelect.value;
21957
+ this.refreshChart();
21958
+ });
21959
+ }
21886
21960
  requestAnimationFrame(() => {
21887
21961
  this.renderCanvasChart();
21888
21962
  });
@@ -22055,13 +22129,12 @@ var WaterTankModal = class {
22055
22129
  }
22056
22130
  /**
22057
22131
  * Transform raw ThingsBoard response to our data points
22058
- * RFC-0107: Support displayKey option to choose between water_level or water_percentage
22132
+ * RFC-0107: Keep ALL data points with their original keys (no deduplication)
22133
+ * This allows the chart to switch between water_level and water_percentage dynamically
22059
22134
  */
22060
22135
  transformTelemetryData(rawData, keys) {
22061
22136
  const allPoints = [];
22062
- const displayKey = this.options.displayKey || "water_percentage";
22063
- const prioritizedKeys = displayKey && rawData[displayKey] ? [displayKey, ...keys.filter((k) => k !== displayKey)] : keys;
22064
- for (const key of prioritizedKeys) {
22137
+ for (const key of keys) {
22065
22138
  if (rawData[key] && Array.isArray(rawData[key])) {
22066
22139
  const keyPoints = rawData[key].map((point) => {
22067
22140
  let value = typeof point.value === "string" ? parseFloat(point.value) : point.value;
@@ -22078,16 +22151,12 @@ var WaterTankModal = class {
22078
22151
  }
22079
22152
  }
22080
22153
  allPoints.sort((a, b) => a.ts - b.ts);
22081
- const uniquePoints = [];
22082
- const seenTimestamps = /* @__PURE__ */ new Set();
22083
- for (const point of allPoints) {
22084
- if (!seenTimestamps.has(point.ts)) {
22085
- seenTimestamps.add(point.ts);
22086
- uniquePoints.push(point);
22087
- }
22154
+ const keyCounts = {};
22155
+ for (const p of allPoints) {
22156
+ keyCounts[p.key || "unknown"] = (keyCounts[p.key || "unknown"] || 0) + 1;
22088
22157
  }
22089
- console.log(`[WaterTankModal] Transformed ${uniquePoints.length} points, displayKey: ${displayKey}`);
22090
- return uniquePoints;
22158
+ console.log(`[WaterTankModal] Transformed ${allPoints.length} total points:`, keyCounts);
22159
+ return allPoints;
22091
22160
  }
22092
22161
  /**
22093
22162
  * Calculate summary statistics from telemetry data