homebridge-ac-freedom 1.0.2 → 1.0.4

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.
@@ -83,15 +83,6 @@
83
83
  }
84
84
  }
85
85
  },
86
- "hvacModes": {
87
- "title": "Enabled HVAC Modes",
88
- "type": "object",
89
- "properties": {
90
- "auto": { "title": "Auto", "type": "boolean", "default": true },
91
- "cool": { "title": "Cool", "type": "boolean", "default": true },
92
- "heat": { "title": "Heat", "type": "boolean", "default": true }
93
- }
94
- },
95
86
  "presets": {
96
87
  "title": "Enabled Preset Modes (shown as switches in climate card)",
97
88
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-ac-freedom",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "displayName": "AC Freedom",
5
5
  "description": "Homebridge plugin for AUX air conditioners via Broadlink (local UDP) and AUX Cloud API",
6
6
  "main": "index.js",
@@ -66,10 +66,11 @@ class AcFreedomAccessory {
66
66
 
67
67
  this.setupAccessoryInfo();
68
68
  this.setupHeaterCooler();
69
- this.reorderLinkedServices();
69
+ this.purgeLinkedServices();
70
70
  this.setupFanService();
71
71
  this.setupPresetSwitches();
72
72
  this.setupDisplaySwitch();
73
+ this.enforceServiceOrder();
73
74
 
74
75
  // Start polling
75
76
  const interval = (config.pollInterval || 30) * 1000;
@@ -94,7 +95,6 @@ class AcFreedomAccessory {
94
95
  || this.accessory.addService(this.Service.HeaterCooler, this.config.name);
95
96
 
96
97
  const C = this.Characteristic;
97
- const hvac = this.config.hvacModes || { auto: true, cool: true, heat: true };
98
98
 
99
99
  // Active (on/off)
100
100
  this.heaterCooler.getCharacteristic(C.Active)
@@ -115,15 +115,15 @@ class AcFreedomAccessory {
115
115
  }
116
116
  });
117
117
 
118
- // Target state (auto/heat/cool)
119
- const validStates = [];
120
- if (hvac.auto) validStates.push(C.TargetHeaterCoolerState.AUTO);
121
- if (hvac.heat) validStates.push(C.TargetHeaterCoolerState.HEAT);
122
- if (hvac.cool) validStates.push(C.TargetHeaterCoolerState.COOL);
123
- if (validStates.length === 0) validStates.push(C.TargetHeaterCoolerState.AUTO);
124
-
118
+ // Target state – all HVAC modes always enabled (auto/heat/cool)
125
119
  this.heaterCooler.getCharacteristic(C.TargetHeaterCoolerState)
126
- .setProps({ validValues: validStates })
120
+ .setProps({
121
+ validValues: [
122
+ C.TargetHeaterCoolerState.AUTO,
123
+ C.TargetHeaterCoolerState.HEAT,
124
+ C.TargetHeaterCoolerState.COOL,
125
+ ],
126
+ })
127
127
  .onGet(() => {
128
128
  switch (this.state.mode) {
129
129
  case CLOUD_MODE.HEAT: return C.TargetHeaterCoolerState.HEAT;
@@ -179,24 +179,47 @@ class AcFreedomAccessory {
179
179
  });
180
180
  }
181
181
 
182
- // ── Reorder linked services ───────────────────────────────────
183
- // Remove cached linked services from the accessory so they are
184
- // re-added in the correct display order: Fan Presets → Display.
185
- reorderLinkedServices() {
186
- const ids = [
187
- { type: this.Service.Fanv2, subtype: 'fan' },
188
- { type: this.Service.Switch, subtype: 'sleep' },
189
- { type: this.Service.Switch, subtype: 'health' },
190
- { type: this.Service.Switch, subtype: 'eco' },
191
- { type: this.Service.Switch, subtype: 'clean' },
192
- { type: this.Service.Switch, subtype: 'display' },
193
- ];
194
- for (const { type, subtype } of ids) {
182
+ // ── Purge linked services ────────────────────────────────────
183
+ // Remove every cached linked service from the accessory AND clear
184
+ // the HeaterCooler's linked list so they are re-created fresh in
185
+ // the correct display order: Fan → Presets → Display.
186
+ purgeLinkedServices() {
187
+ // 1. Clear HeaterCooler's linked services array
188
+ this.heaterCooler.linkedServices = [];
189
+
190
+ // 2. Remove cached services from the accessory
191
+ const subtypes = ['fan', 'sleep', 'health', 'eco', 'clean', 'display'];
192
+ for (const subtype of subtypes) {
193
+ const type = subtype === 'fan' ? this.Service.Fanv2 : this.Service.Switch;
195
194
  const svc = this.accessory.getServiceById(type, subtype);
196
195
  if (svc) this.accessory.removeService(svc);
197
196
  }
198
197
  }
199
198
 
199
+ // ── Enforce service order in accessory ──────────────────────
200
+ // HomeKit reads the services array order from the HAP database to
201
+ // determine tile layout. We sort the array so that Fan always
202
+ // comes right after HeaterCooler, followed by preset switches and
203
+ // the display switch.
204
+ enforceServiceOrder() {
205
+ const S = this.Service;
206
+ const rank = (svc) => {
207
+ if (svc.UUID === S.AccessoryInformation.UUID) return 0;
208
+ if (svc.UUID === S.HeaterCooler.UUID) return 1;
209
+ if (svc.UUID === S.Fanv2.UUID) return 2; // Fan first
210
+ if (svc.UUID === S.Switch.UUID) {
211
+ const sub = svc.subtype;
212
+ if (sub === 'sleep') return 3;
213
+ if (sub === 'health') return 4;
214
+ if (sub === 'eco') return 5;
215
+ if (sub === 'clean') return 6;
216
+ if (sub === 'display') return 7;
217
+ }
218
+ return 99;
219
+ };
220
+ this.accessory.services.sort((a, b) => rank(a) - rank(b));
221
+ }
222
+
200
223
  // ── Fan Service (linked to HeaterCooler) ────────────────────────
201
224
  setupFanService() {
202
225
  const C = this.Characteristic;