myio-js-library 0.1.144 → 0.1.146

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.
@@ -4933,15 +4933,41 @@
4933
4933
  function verifyOfflineStatus(entityObject) {
4934
4934
  const lastConnectionTime = new Date(entityObject.lastConnectTime || 0);
4935
4935
  const lastDisconnectTime = new Date(entityObject.lastDisconnectTime || 0);
4936
- if (lastDisconnectTime.getTime() > lastConnectionTime.getTime()) {
4937
- return false;
4938
- }
4939
4936
  const now = /* @__PURE__ */ new Date();
4940
4937
  const fifteenMinutesInMs = 15 * 60 * 1e3;
4941
4938
  const timeSinceConnection = now.getTime() - lastConnectionTime.getTime();
4939
+ if (String(entityObject.labelOrName || "").toLowerCase().includes("chiller 1")) {
4940
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] ========================================");
4941
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] label:", entityObject.labelOrName);
4942
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] deviceStatus (before):", entityObject.deviceStatus);
4943
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] lastConnectTime (raw):", entityObject.lastConnectTime);
4944
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] lastDisconnectTime (raw):", entityObject.lastDisconnectTime);
4945
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] lastConnectionTime (Date):", lastConnectionTime.toISOString());
4946
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] lastDisconnectTime (Date):", lastDisconnectTime.toISOString());
4947
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] now:", now.toISOString());
4948
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] timeSinceConnection (ms):", timeSinceConnection);
4949
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] timeSinceConnection (min):", (timeSinceConnection / 6e4).toFixed(2));
4950
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] disconnect > connect?", lastDisconnectTime.getTime() > lastConnectionTime.getTime());
4951
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] timeSinceConnection < 15min?", timeSinceConnection < fifteenMinutesInMs);
4952
+ }
4953
+ if (lastDisconnectTime.getTime() > lastConnectionTime.getTime()) {
4954
+ if (String(entityObject.labelOrName || "").toLowerCase().includes("chiller 1")) {
4955
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] RESULT: false (disconnect > connect)");
4956
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] ========================================");
4957
+ }
4958
+ return false;
4959
+ }
4942
4960
  if (timeSinceConnection < fifteenMinutesInMs) {
4961
+ if (String(entityObject.labelOrName || "").toLowerCase().includes("chiller 1")) {
4962
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] RESULT: false (connection < 15min ago)");
4963
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] ========================================");
4964
+ }
4943
4965
  return false;
4944
4966
  }
4967
+ if (String(entityObject.labelOrName || "").toLowerCase().includes("chiller 1")) {
4968
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] RESULT: true (online)");
4969
+ console.log("[DEBUG CHILLER 1 - verifyOfflineStatus] ========================================");
4970
+ }
4945
4971
  return true;
4946
4972
  }
4947
4973
  function paint(root, state) {
@@ -15119,7 +15145,13 @@ ${rangeText}`;
15119
15145
  render(initialData) {
15120
15146
  this.originalActiveElement = document.activeElement;
15121
15147
  document.body.appendChild(this.container);
15122
- this.populateForm(initialData);
15148
+ let formData = { ...initialData };
15149
+ if (initialData.deviceMapInstaneousPower && typeof initialData.deviceMapInstaneousPower === "object") {
15150
+ console.log("[SettingsModalView] Configura\xE7\xE3o salva encontrada (Device Scope). Processando...");
15151
+ const flatLimits = this.parseDeviceSavedLimits(initialData.deviceMapInstaneousPower);
15152
+ formData = { ...formData, ...flatLimits };
15153
+ }
15154
+ this.populateForm(formData);
15123
15155
  this.attachEventListeners();
15124
15156
  this.setupAccessibility();
15125
15157
  this.setupFocusTrap();
@@ -16688,6 +16720,42 @@ ${rangeText}`;
16688
16720
  }
16689
16721
  }
16690
16722
  }
16723
+ /**
16724
+ * Helper: Traduz o JSON RFC-0086 (deviceMapInstaneousPower)
16725
+ * para os campos planos do formulário (ex: standbyLimitUpConsumption)
16726
+ */
16727
+ parseDeviceSavedLimits(deviceJson) {
16728
+ const extracted = {};
16729
+ try {
16730
+ if (!deviceJson || !deviceJson.limitsByInstantaneoustPowerType) return extracted;
16731
+ const consumptionGroup = deviceJson.limitsByInstantaneoustPowerType.find(
16732
+ (g) => g.telemetryType === "consumption"
16733
+ );
16734
+ const deviceItem = consumptionGroup?.itemsByDeviceType?.[0];
16735
+ if (!deviceItem?.limitsByDeviceStatus) return extracted;
16736
+ const mapPrefix = {
16737
+ "standBy": "standby",
16738
+ "normal": "normal",
16739
+ "alert": "alert",
16740
+ "failure": "failure"
16741
+ };
16742
+ deviceItem.limitsByDeviceStatus.forEach((status) => {
16743
+ const prefix = mapPrefix[status.deviceStatusName];
16744
+ if (prefix && status.limitsValues) {
16745
+ const { baseValue, topValue } = status.limitsValues;
16746
+ if (baseValue !== null && baseValue !== void 0) {
16747
+ extracted[`${prefix}LimitDownConsumption`] = baseValue;
16748
+ }
16749
+ if (topValue !== null && topValue !== void 0) {
16750
+ extracted[`${prefix}LimitUpConsumption`] = topValue;
16751
+ }
16752
+ }
16753
+ });
16754
+ } catch (e) {
16755
+ console.warn("[SettingsModalView] Erro ao processar deviceMapInstaneousPower:", e);
16756
+ }
16757
+ return extracted;
16758
+ }
16691
16759
  attachEventListeners() {
16692
16760
  this.form.addEventListener("submit", (event) => {
16693
16761
  event.preventDefault();
@@ -16959,11 +17027,25 @@ ${rangeText}`;
16959
17027
  }
16960
17028
  async saveServerScopeAttributes(deviceId, attributes) {
16961
17029
  try {
16962
- const mapInstantaneousPower = this.buildMapInstantaneousPower(attributes);
16963
- const payload = {
16964
- mapInstantaneousPower
16965
- };
16966
- console.log("[SettingsPersister] RFC-0080: Saving mapInstantaneousPower as JSON:", payload);
17030
+ const payload = { ...attributes };
17031
+ const effectiveDeviceType = this.getEffectiveDeviceType();
17032
+ const deviceJson = this.buildDevicePowerJson(payload, effectiveDeviceType);
17033
+ if (deviceJson) {
17034
+ payload.deviceMapInstaneousPower = deviceJson;
17035
+ }
17036
+ const flatKeysToRemove = [
17037
+ "telemetryType",
17038
+ "standbyLimitDownConsumption",
17039
+ "standbyLimitUpConsumption",
17040
+ "normalLimitDownConsumption",
17041
+ "normalLimitUpConsumption",
17042
+ "alertLimitDownConsumption",
17043
+ "alertLimitUpConsumption",
17044
+ "failureLimitDownConsumption",
17045
+ "failureLimitUpConsumption"
17046
+ ];
17047
+ flatKeysToRemove.forEach((key) => delete payload[key]);
17048
+ console.log("[SettingsPersister] Saving Server Scope Attributes:", payload);
16967
17049
  const res = await fetch(
16968
17050
  `${this.tbBaseUrl}/api/plugins/telemetry/DEVICE/${deviceId}/attributes/SERVER_SCOPE`,
16969
17051
  {
@@ -16980,13 +17062,70 @@ ${rangeText}`;
16980
17062
  }
16981
17063
  return {
16982
17064
  ok: true,
16983
- updatedKeys: ["mapInstantaneousPower"]
17065
+ updatedKeys: Object.keys(payload)
16984
17066
  };
16985
17067
  } catch (error) {
16986
17068
  console.error("[SettingsPersister] Attributes save failed:", error);
16987
17069
  return { ok: false, error: this.mapError(error) };
16988
17070
  }
16989
17071
  }
17072
+ /**
17073
+ * Constrói o JSON Reduzido (apenas o deviceType atual) para salvar no Device.
17074
+ * Retorna null se nenhum campo de potência estiver presente.
17075
+ */
17076
+ buildDevicePowerJson(formData, deviceType) {
17077
+ const statuses = ["standby", "normal", "alert", "failure"];
17078
+ const hasPowerData = statuses.some(
17079
+ (status) => formData[`${status}LimitDownConsumption`] !== void 0 && formData[`${status}LimitDownConsumption`] !== "" || formData[`${status}LimitUpConsumption`] !== void 0 && formData[`${status}LimitUpConsumption`] !== ""
17080
+ );
17081
+ if (!hasPowerData) return null;
17082
+ const statusMap = {
17083
+ "standby": "standBy",
17084
+ "normal": "normal",
17085
+ "alert": "alert",
17086
+ "failure": "failure"
17087
+ };
17088
+ const limitsList = [];
17089
+ statuses.forEach((statusKey) => {
17090
+ const down = formData[`${statusKey}LimitDownConsumption`];
17091
+ const up = formData[`${statusKey}LimitUpConsumption`];
17092
+ if (down !== void 0 && down !== "" || up !== void 0 && up !== "") {
17093
+ limitsList.push({
17094
+ deviceStatusName: statusMap[statusKey],
17095
+ limitsValues: {
17096
+ // Converte para Number ou null
17097
+ baseValue: down !== "" && down !== void 0 ? Number(down) : null,
17098
+ topValue: up !== "" && up !== void 0 ? Number(up) : null
17099
+ }
17100
+ });
17101
+ }
17102
+ });
17103
+ if (limitsList.length === 0) return null;
17104
+ return {
17105
+ version: "1.0.0",
17106
+ limitsByInstantaneoustPowerType: [
17107
+ {
17108
+ telemetryType: "consumption",
17109
+ itemsByDeviceType: [
17110
+ {
17111
+ deviceType,
17112
+ // Gera um nome descritivo interno
17113
+ name: `deviceMapInstaneousPower${this.formatDeviceTypeName(deviceType)}`,
17114
+ description: "Override manual configurado via Dashboard",
17115
+ limitsByDeviceStatus: limitsList
17116
+ }
17117
+ ]
17118
+ }
17119
+ ]
17120
+ };
17121
+ }
17122
+ /**
17123
+ * Helper para formatar o nome do tipo (PascalCase) para uso no campo "name" do JSON
17124
+ */
17125
+ formatDeviceTypeName(deviceType) {
17126
+ if (!deviceType) return "";
17127
+ return deviceType.charAt(0).toUpperCase() + deviceType.slice(1).toLowerCase();
17128
+ }
16990
17129
  /**
16991
17130
  * RFC-0086: Build mapInstantaneousPower JSON structure from form data
16992
17131
  * IMPORTANT: When saving to a DEVICE, only include entries for the specific deviceType
@@ -17043,25 +17182,6 @@ ${rangeText}`;
17043
17182
  console.log(`[SettingsPersister] RFC-0086: Built mapInstantaneousPower for deviceType=${effectiveDeviceType}:`, result);
17044
17183
  return result;
17045
17184
  }
17046
- /**
17047
- * Format device type name for display (e.g., ELEVADOR -> Elevador)
17048
- */
17049
- formatDeviceTypeName(deviceType) {
17050
- const map = {
17051
- "ELEVADOR": "Elevator",
17052
- "ESCADA_ROLANTE": "Escalator",
17053
- "MOTOR": "Motor",
17054
- "BOMBA": "Pump",
17055
- "3F_MEDIDOR": "3FMedidor",
17056
- "CHILLER": "Chiller",
17057
- "FANCOIL": "Fancoil",
17058
- "AR_CONDICIONADO": "AirConditioner",
17059
- "HVAC": "HVAC",
17060
- "HIDROMETRO": "Hidrometro",
17061
- "TERMOSTATO": "Termostato"
17062
- };
17063
- return map[deviceType] || deviceType;
17064
- }
17065
17185
  sanitizeLabel(label) {
17066
17186
  return label.trim().slice(0, 255).replace(/[\x00-\x1F\x7F]/g, "");
17067
17187
  }
@@ -17198,18 +17318,16 @@ ${rangeText}`;
17198
17318
  }
17199
17319
  const attributesArray = await response.json();
17200
17320
  const attributes = {};
17201
- const settingsNamespace = "myio.settings.energy.";
17202
17321
  for (const attr of attributesArray) {
17203
17322
  if (attr.key && attr.value !== void 0 && attr.value !== null && attr.value !== "") {
17204
- if (attr.key.startsWith(settingsNamespace)) {
17205
- const key = attr.key.replace(settingsNamespace, "");
17206
- if (key !== "__version") {
17207
- attributes[key] = attr.value;
17208
- }
17209
- } else if (attr.key === "floor") {
17323
+ if (attr.key === "floor") {
17210
17324
  attributes.floor = attr.value;
17211
17325
  } else if (attr.key === "identifier") {
17212
17326
  attributes.identifier = attr.value;
17327
+ } else if (attr.key === "mapInstantaneousPower") {
17328
+ attributes.mapInstantaneousPower = attr.value;
17329
+ } else if (attr.key === "deviceMapInstaneousPower") {
17330
+ attributes.deviceMapInstaneousPower = attr.value;
17213
17331
  }
17214
17332
  }
17215
17333
  }
@@ -17231,23 +17349,12 @@ ${rangeText}`;
17231
17349
  }
17232
17350
  return merged;
17233
17351
  }
17234
- /**
17235
- * Utility method to validate and sanitize fetched data
17236
- */
17237
17352
  static sanitizeFetchedData(data) {
17238
17353
  const sanitized = {};
17239
17354
  const stringFields = [
17240
17355
  "label",
17241
17356
  "floor",
17242
- "identifier",
17243
- "alertLimitDownConsumption",
17244
- "alertLimitUpConsumption",
17245
- "failureLimitDownConsumption",
17246
- "failureLimitUpConsumption",
17247
- "normalLimitDownConsumption",
17248
- "normalLimitUpConsumption",
17249
- "standbyLimitDownConsumption",
17250
- "standbyLimitUpConsumption"
17357
+ "identifier"
17251
17358
  ];
17252
17359
  for (const field of stringFields) {
17253
17360
  if (data[field] && typeof data[field] === "string") {
@@ -17263,6 +17370,12 @@ ${rangeText}`;
17263
17370
  }
17264
17371
  }
17265
17372
  }
17373
+ const objectFields = ["mapInstantaneousPower", "deviceMapInstaneousPower"];
17374
+ for (const field of objectFields) {
17375
+ if (data[field] && typeof data[field] === "object") {
17376
+ sanitized[field] = data[field];
17377
+ }
17378
+ }
17266
17379
  return sanitized;
17267
17380
  }
17268
17381
  };
@@ -17312,8 +17425,9 @@ ${rangeText}`;
17312
17425
  // Pass connection info for display
17313
17426
  onSave: this.handleSave.bind(this),
17314
17427
  onClose: this.handleClose.bind(this),
17315
- mapInstantaneousPower: params.mapInstantaneousPower
17316
- // RFC-0077: Pass instantaneous power map for Power Limits feature
17428
+ mapInstantaneousPower: params.mapInstantaneousPower,
17429
+ // RFC-0077: Pass instantaneous power map for Power Limits feature,
17430
+ deviceMapInstaneousPower: params.deviceMapInstaneousPower
17317
17431
  });
17318
17432
  }
17319
17433
  async show() {