homebridge-ac-freedom 1.2.2 → 2.0.0
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/CHANGELOG.md +12 -1
- package/README.md +19 -23
- package/config.schema.json +62 -109
- package/package.json +1 -1
- package/src/ac-accessory.js +9 -5
- package/src/platform.js +11 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.0 — Breaking Change
|
|
4
|
+
|
|
5
|
+
- **Config structure flattened** — nested `cloud`, `local`, `presets` objects replaced with flat properties (`cloudEmail`, `cloudPassword`, `cloudRegion`, `cloudDeviceId`, `localIp`, `localMac`, `sleep`, `health`, `eco`, `clean`, `comfwind`, `display`)
|
|
6
|
+
- **Config UI completely rewritten** — no custom layout, no `oneOf` dropdowns, fixes all floating popup bugs
|
|
7
|
+
- **Conditional fields** — cloud/local fields show/hide based on connection mode
|
|
8
|
+
- Existing configs need to be re-entered via Homebridge UI after upgrading
|
|
9
|
+
|
|
10
|
+
## 1.2.3
|
|
11
|
+
|
|
12
|
+
- Attempt fix for floating popup — replace `oneOf` with `enum` + `titleMap`
|
|
13
|
+
|
|
3
14
|
## 1.2.2
|
|
4
15
|
|
|
5
|
-
- Remove unused `changelog` field from config.schema.json
|
|
16
|
+
- Remove unused `changelog` field from config.schema.json
|
|
6
17
|
|
|
7
18
|
## 1.2.1
|
|
8
19
|
|
package/README.md
CHANGED
|
@@ -87,11 +87,9 @@ Add the following to your Homebridge `config.json`:
|
|
|
87
87
|
{
|
|
88
88
|
"name": "Living Room AC",
|
|
89
89
|
"connection": "cloud",
|
|
90
|
-
"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"region": "eu"
|
|
94
|
-
}
|
|
90
|
+
"cloudEmail": "your-email@example.com",
|
|
91
|
+
"cloudPassword": "your-password",
|
|
92
|
+
"cloudRegion": "eu"
|
|
95
93
|
}
|
|
96
94
|
]
|
|
97
95
|
}
|
|
@@ -111,10 +109,8 @@ Add the following to your Homebridge `config.json`:
|
|
|
111
109
|
{
|
|
112
110
|
"name": "Bedroom AC",
|
|
113
111
|
"connection": "local",
|
|
114
|
-
"
|
|
115
|
-
|
|
116
|
-
"mac": "AA:BB:CC:DD:EE:FF"
|
|
117
|
-
}
|
|
112
|
+
"localIp": "192.168.1.100",
|
|
113
|
+
"localMac": "AA:BB:CC:DD:EE:FF"
|
|
118
114
|
}
|
|
119
115
|
]
|
|
120
116
|
}
|
|
@@ -133,32 +129,32 @@ Add the following to your Homebridge `config.json`:
|
|
|
133
129
|
| `pollInterval` | integer | `30` | State polling interval in seconds (5--300) |
|
|
134
130
|
| `tempStep` | number | `0.5` | Temperature adjustment step: `0.5` or `1` |
|
|
135
131
|
|
|
136
|
-
#### Cloud Options
|
|
132
|
+
#### Cloud Options (when `connection` is `"cloud"`)
|
|
137
133
|
|
|
138
134
|
| Option | Type | Required | Description |
|
|
139
135
|
|--------|------|----------|-------------|
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
136
|
+
| `cloudEmail` | string | Yes | AC Freedom app email |
|
|
137
|
+
| `cloudPassword` | string | Yes | AC Freedom app password |
|
|
138
|
+
| `cloudRegion` | string | No | Server region: `"eu"`, `"usa"`, `"cn"`, `"rus"` (default: `"eu"`) |
|
|
139
|
+
| `cloudDeviceId` | string | No | Specific device endpoint ID (leave empty for auto-detect) |
|
|
144
140
|
|
|
145
|
-
#### Local Options
|
|
141
|
+
#### Local Options (when `connection` is `"local"`)
|
|
146
142
|
|
|
147
143
|
| Option | Type | Required | Description |
|
|
148
144
|
|--------|------|----------|-------------|
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
145
|
+
| `localIp` | string | Yes | AC unit's IP address on your local network |
|
|
146
|
+
| `localMac` | string | Yes | AC unit's MAC address (`AA:BB:CC:DD:EE:FF` format) |
|
|
151
147
|
|
|
152
148
|
#### Feature Switches
|
|
153
149
|
|
|
154
150
|
| Option | Type | Default | Description |
|
|
155
151
|
|--------|------|---------|-------------|
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
152
|
+
| `sleep` | boolean | `true` | Show Sleep Mode switch |
|
|
153
|
+
| `health` | boolean | `true` | Show Health / Ionizer switch |
|
|
154
|
+
| `eco` | boolean | `true` | Show Eco / Mildew Prevention switch |
|
|
155
|
+
| `clean` | boolean | `true` | Show Self Clean switch |
|
|
156
|
+
| `comfwind` | boolean | `true` | Show Comfortable Wind switch |
|
|
157
|
+
| `display` | boolean | `true` | Show Display (LED) switch |
|
|
162
158
|
|
|
163
159
|
## HomeKit Climate Card
|
|
164
160
|
|
package/config.schema.json
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
"headerDisplay": "AUX Air Conditioner control via Broadlink (local) or AUX Cloud API.",
|
|
6
6
|
"schema": {
|
|
7
7
|
"type": "object",
|
|
8
|
-
"required": ["name"],
|
|
9
8
|
"properties": {
|
|
10
9
|
"name": {
|
|
11
10
|
"title": "Platform Name",
|
|
12
11
|
"type": "string",
|
|
12
|
+
"required": true,
|
|
13
13
|
"default": "AC Freedom"
|
|
14
14
|
},
|
|
15
15
|
"devices": {
|
|
@@ -17,78 +17,81 @@
|
|
|
17
17
|
"type": "array",
|
|
18
18
|
"items": {
|
|
19
19
|
"type": "object",
|
|
20
|
-
"required": ["name", "connection"],
|
|
21
20
|
"properties": {
|
|
22
21
|
"name": {
|
|
23
22
|
"title": "Device Name",
|
|
24
23
|
"type": "string",
|
|
24
|
+
"required": true,
|
|
25
25
|
"default": "AC Freedom"
|
|
26
26
|
},
|
|
27
27
|
"connection": {
|
|
28
28
|
"title": "Connection Mode",
|
|
29
29
|
"type": "string",
|
|
30
|
+
"required": true,
|
|
30
31
|
"default": "cloud",
|
|
31
|
-
"
|
|
32
|
-
{ "title": "Cloud (AUX Cloud API)", "enum": ["cloud"] },
|
|
33
|
-
{ "title": "Local (Broadlink UDP)", "enum": ["local"] }
|
|
34
|
-
]
|
|
32
|
+
"enum": ["cloud", "local"]
|
|
35
33
|
},
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
34
|
+
"cloudEmail": {
|
|
35
|
+
"title": "Cloud Email",
|
|
36
|
+
"type": "string",
|
|
37
|
+
"condition": { "functionBody": "return model.devices[arrayIndices[0]].connection === 'cloud';" }
|
|
38
|
+
},
|
|
39
|
+
"cloudPassword": {
|
|
40
|
+
"title": "Cloud Password",
|
|
41
|
+
"type": "string",
|
|
42
|
+
"condition": { "functionBody": "return model.devices[arrayIndices[0]].connection === 'cloud';" }
|
|
43
|
+
},
|
|
44
|
+
"cloudRegion": {
|
|
45
|
+
"title": "Cloud Region",
|
|
46
|
+
"type": "string",
|
|
47
|
+
"default": "eu",
|
|
48
|
+
"enum": ["eu", "usa", "cn", "rus"],
|
|
49
|
+
"condition": { "functionBody": "return model.devices[arrayIndices[0]].connection === 'cloud';" }
|
|
50
|
+
},
|
|
51
|
+
"cloudDeviceId": {
|
|
52
|
+
"title": "Cloud Device ID (leave empty for auto-detect)",
|
|
53
|
+
"type": "string",
|
|
54
|
+
"condition": { "functionBody": "return model.devices[arrayIndices[0]].connection === 'cloud';" }
|
|
55
|
+
},
|
|
56
|
+
"localIp": {
|
|
57
|
+
"title": "IP Address",
|
|
58
|
+
"type": "string",
|
|
59
|
+
"format": "ipv4",
|
|
60
|
+
"condition": { "functionBody": "return model.devices[arrayIndices[0]].connection === 'local';" }
|
|
61
|
+
},
|
|
62
|
+
"localMac": {
|
|
63
|
+
"title": "MAC Address",
|
|
64
|
+
"type": "string",
|
|
65
|
+
"pattern": "^([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}$",
|
|
66
|
+
"placeholder": "AA:BB:CC:DD:EE:FF",
|
|
67
|
+
"condition": { "functionBody": "return model.devices[arrayIndices[0]].connection === 'local';" }
|
|
63
68
|
},
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
|
|
68
|
-
"title": "IP Address",
|
|
69
|
-
"type": "string"
|
|
70
|
-
},
|
|
71
|
-
"mac": {
|
|
72
|
-
"title": "MAC Address (AA:BB:CC:DD:EE:FF)",
|
|
73
|
-
"type": "string"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
69
|
+
"sleep": {
|
|
70
|
+
"title": "Sleep Mode",
|
|
71
|
+
"type": "boolean",
|
|
72
|
+
"default": true
|
|
76
73
|
},
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
"health": { "title": "Health / Ionizer", "type": "boolean", "default": true },
|
|
82
|
-
"eco": { "title": "Eco / Mildew Prevention", "type": "boolean", "default": true },
|
|
83
|
-
"clean": { "title": "Self Clean", "type": "boolean", "default": true }
|
|
84
|
-
}
|
|
74
|
+
"health": {
|
|
75
|
+
"title": "Health / Ionizer",
|
|
76
|
+
"type": "boolean",
|
|
77
|
+
"default": true
|
|
85
78
|
},
|
|
86
|
-
"
|
|
79
|
+
"eco": {
|
|
80
|
+
"title": "Eco / Mildew Prevention",
|
|
81
|
+
"type": "boolean",
|
|
82
|
+
"default": true
|
|
83
|
+
},
|
|
84
|
+
"clean": {
|
|
85
|
+
"title": "Self Clean",
|
|
86
|
+
"type": "boolean",
|
|
87
|
+
"default": true
|
|
88
|
+
},
|
|
89
|
+
"comfwind": {
|
|
87
90
|
"title": "Comfortable Wind",
|
|
88
91
|
"type": "boolean",
|
|
89
92
|
"default": true
|
|
90
93
|
},
|
|
91
|
-
"
|
|
94
|
+
"display": {
|
|
92
95
|
"title": "Display",
|
|
93
96
|
"type": "boolean",
|
|
94
97
|
"default": true
|
|
@@ -104,64 +107,14 @@
|
|
|
104
107
|
"title": "Temperature Step",
|
|
105
108
|
"type": "number",
|
|
106
109
|
"default": 0.5,
|
|
107
|
-
"
|
|
108
|
-
|
|
109
|
-
{ "title": "1 °C", "enum": [1] }
|
|
110
|
-
]
|
|
110
|
+
"minimum": 0.5,
|
|
111
|
+
"maximum": 1
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
117
|
},
|
|
117
|
-
"
|
|
118
|
-
|
|
119
|
-
{
|
|
120
|
-
"key": "devices",
|
|
121
|
-
"type": "tabarray",
|
|
122
|
-
"title": "{{ value.name || 'New Device' }}",
|
|
123
|
-
"buttonText": "Add Device",
|
|
124
|
-
"items": [
|
|
125
|
-
{ "key": "devices[].name" },
|
|
126
|
-
{ "key": "devices[].connection" },
|
|
127
|
-
{
|
|
128
|
-
"key": "devices[].cloud",
|
|
129
|
-
"type": "fieldset",
|
|
130
|
-
"title": "Cloud Settings",
|
|
131
|
-
"condition": { "functionBody": "return model.devices[arrayIndices[0]].connection === 'cloud';" },
|
|
132
|
-
"items": [
|
|
133
|
-
{ "key": "devices[].cloud.email" },
|
|
134
|
-
{ "key": "devices[].cloud.password" },
|
|
135
|
-
{ "key": "devices[].cloud.region" },
|
|
136
|
-
{ "key": "devices[].cloud.deviceId" }
|
|
137
|
-
]
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
"key": "devices[].local",
|
|
141
|
-
"type": "fieldset",
|
|
142
|
-
"title": "Local Settings",
|
|
143
|
-
"condition": { "functionBody": "return model.devices[arrayIndices[0]].connection === 'local';" },
|
|
144
|
-
"items": [
|
|
145
|
-
{ "key": "devices[].local.ip" },
|
|
146
|
-
{ "key": "devices[].local.mac" }
|
|
147
|
-
]
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
"key": "devices[].presets",
|
|
151
|
-
"type": "fieldset",
|
|
152
|
-
"title": "Preset Modes",
|
|
153
|
-
"items": [
|
|
154
|
-
{ "key": "devices[].presets.sleep" },
|
|
155
|
-
{ "key": "devices[].presets.health" },
|
|
156
|
-
{ "key": "devices[].presets.eco" },
|
|
157
|
-
{ "key": "devices[].presets.clean" }
|
|
158
|
-
]
|
|
159
|
-
},
|
|
160
|
-
{ "key": "devices[].showComfWind" },
|
|
161
|
-
{ "key": "devices[].showDisplay" },
|
|
162
|
-
{ "key": "devices[].pollInterval" },
|
|
163
|
-
{ "key": "devices[].tempStep" }
|
|
164
|
-
]
|
|
165
|
-
}
|
|
166
|
-
]
|
|
118
|
+
"form": null,
|
|
119
|
+
"display": null
|
|
167
120
|
}
|
package/package.json
CHANGED
package/src/ac-accessory.js
CHANGED
|
@@ -210,7 +210,12 @@ class AcFreedomAccessory {
|
|
|
210
210
|
|
|
211
211
|
// ── Preset Switches (linked to HeaterCooler) ──────────────────
|
|
212
212
|
setupPresetSwitches() {
|
|
213
|
-
const presets =
|
|
213
|
+
const presets = {
|
|
214
|
+
sleep: this.config.sleep !== false,
|
|
215
|
+
health: this.config.health !== false,
|
|
216
|
+
eco: this.config.eco !== false,
|
|
217
|
+
clean: this.config.clean !== false,
|
|
218
|
+
};
|
|
214
219
|
|
|
215
220
|
this.presetSwitches = {};
|
|
216
221
|
|
|
@@ -254,7 +259,7 @@ class AcFreedomAccessory {
|
|
|
254
259
|
|
|
255
260
|
// ── Comfortable Wind Switch (linked to HeaterCooler) ────────────
|
|
256
261
|
setupComfWindSwitch() {
|
|
257
|
-
if (this.config.
|
|
262
|
+
if (this.config.comfwind === false) {
|
|
258
263
|
const existing = this.accessory.getServiceById(this.Service.Switch, 'comfwind');
|
|
259
264
|
if (existing) this.accessory.removeService(existing);
|
|
260
265
|
return;
|
|
@@ -277,7 +282,7 @@ class AcFreedomAccessory {
|
|
|
277
282
|
|
|
278
283
|
// ── Display Switch (linked to HeaterCooler) ────────────────────
|
|
279
284
|
setupDisplaySwitch() {
|
|
280
|
-
if (this.config.
|
|
285
|
+
if (this.config.display === false) {
|
|
281
286
|
const existing = this.accessory.getServiceById(this.Service.Switch, 'display');
|
|
282
287
|
if (existing) this.accessory.removeService(existing);
|
|
283
288
|
return;
|
|
@@ -351,8 +356,7 @@ class AcFreedomAccessory {
|
|
|
351
356
|
if (err.message && err.message.includes('server busy')) return;
|
|
352
357
|
// Re-login on token expiry
|
|
353
358
|
if (err.message && err.message.includes('token')) {
|
|
354
|
-
|
|
355
|
-
await api.login(cloud.email, cloud.password);
|
|
359
|
+
await api.login(this.config.cloudEmail, this.config.cloudPassword);
|
|
356
360
|
}
|
|
357
361
|
throw err;
|
|
358
362
|
}
|
package/src/platform.js
CHANGED
|
@@ -45,8 +45,8 @@ class AcFreedomPlatform {
|
|
|
45
45
|
async setupDevice(deviceConfig) {
|
|
46
46
|
const uuid = this.api.hap.uuid.generate(
|
|
47
47
|
deviceConfig.connection === 'cloud'
|
|
48
|
-
? `ac-freedom-cloud-${deviceConfig.
|
|
49
|
-
: `ac-freedom-local-${deviceConfig.
|
|
48
|
+
? `ac-freedom-cloud-${deviceConfig.cloudEmail}-${deviceConfig.cloudDeviceId || 'auto'}`
|
|
49
|
+
: `ac-freedom-local-${deviceConfig.localIp}-${deviceConfig.localMac}`,
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
const existingAccessory = this.accessories.get(uuid);
|
|
@@ -74,16 +74,15 @@ class AcFreedomPlatform {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
async setupCloudDevice(config) {
|
|
77
|
-
|
|
78
|
-
if (!cloud || !cloud.email || !cloud.password) {
|
|
77
|
+
if (!config.cloudEmail || !config.cloudPassword) {
|
|
79
78
|
this.log.error('Cloud config missing email/password');
|
|
80
79
|
return null;
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
const api = new AuxCloudAPI(
|
|
82
|
+
const api = new AuxCloudAPI(config.cloudRegion || 'eu');
|
|
84
83
|
try {
|
|
85
|
-
await api.login(
|
|
86
|
-
this.log.info('Cloud login successful: %s',
|
|
84
|
+
await api.login(config.cloudEmail, config.cloudPassword);
|
|
85
|
+
this.log.info('Cloud login successful: %s', config.cloudEmail);
|
|
87
86
|
|
|
88
87
|
const families = await api.getFamilies();
|
|
89
88
|
let devices = [];
|
|
@@ -92,8 +91,8 @@ class AcFreedomPlatform {
|
|
|
92
91
|
devices.push(...devs);
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
if (
|
|
96
|
-
devices = devices.filter(d => d.endpointId ===
|
|
94
|
+
if (config.cloudDeviceId) {
|
|
95
|
+
devices = devices.filter(d => d.endpointId === config.cloudDeviceId);
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
if (devices.length === 0) {
|
|
@@ -111,20 +110,19 @@ class AcFreedomPlatform {
|
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
async setupLocalDevice(config) {
|
|
114
|
-
|
|
115
|
-
if (!local || !local.ip || !local.mac) {
|
|
113
|
+
if (!config.localIp || !config.localMac) {
|
|
116
114
|
this.log.error('Local config missing ip/mac');
|
|
117
115
|
return null;
|
|
118
116
|
}
|
|
119
117
|
|
|
120
|
-
const api = new BroadlinkAcApi(
|
|
118
|
+
const api = new BroadlinkAcApi(config.localIp, config.localMac);
|
|
121
119
|
try {
|
|
122
120
|
const connected = await api.connect();
|
|
123
121
|
if (!connected) {
|
|
124
122
|
this.log.error('Failed to connect to local device at %s', local.ip);
|
|
125
123
|
return null;
|
|
126
124
|
}
|
|
127
|
-
this.log.info('Local device connected: %s',
|
|
125
|
+
this.log.info('Local device connected: %s', config.localIp);
|
|
128
126
|
return { type: 'local', api };
|
|
129
127
|
} catch (err) {
|
|
130
128
|
this.log.error('Local connection failed: %s', err.message);
|