@switchbot/homebridge-switchbot 5.0.0-beta.108 → 5.0.0-beta.109
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/TODO.md +564 -0
- package/config.schema.json +100 -25
- package/dist/device-types.d.ts +15 -0
- package/dist/device-types.d.ts.map +1 -0
- package/dist/device-types.js +145 -0
- package/dist/device-types.js.map +1 -0
- package/dist/deviceFactory.d.ts +1 -1
- package/dist/deviceFactory.d.ts.map +1 -1
- package/dist/deviceFactory.js +55 -17
- package/dist/deviceFactory.js.map +1 -1
- package/dist/devices/genericDevice.d.ts +1 -1
- package/dist/devices/genericDevice.d.ts.map +1 -1
- package/dist/devices/genericDevice.js +4 -2
- package/dist/devices/genericDevice.js.map +1 -1
- package/dist/homebridge-ui/endpoints/config.d.ts +6 -0
- package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/config.js +73 -0
- package/dist/homebridge-ui/endpoints/config.js.map +1 -0
- package/dist/homebridge-ui/endpoints/credentials.d.ts +6 -0
- package/dist/homebridge-ui/endpoints/credentials.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/credentials.js +65 -0
- package/dist/homebridge-ui/endpoints/credentials.js.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts +6 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.js +285 -0
- package/dist/homebridge-ui/endpoints/devices.js.map +1 -0
- package/dist/homebridge-ui/endpoints/discovery.d.ts +7 -0
- package/dist/homebridge-ui/endpoints/discovery.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/discovery.js +171 -0
- package/dist/homebridge-ui/endpoints/discovery.js.map +1 -0
- package/dist/homebridge-ui/public/index.html +144 -624
- package/dist/homebridge-ui/public/js/api.d.ts +15 -0
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/api.js +164 -0
- package/dist/homebridge-ui/public/js/api.js.map +1 -0
- package/dist/homebridge-ui/public/js/api.ts +189 -0
- package/dist/homebridge-ui/public/js/app.d.ts +2 -0
- package/dist/homebridge-ui/public/js/app.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/app.js +1069 -0
- package/dist/homebridge-ui/public/js/app.js.map +7 -0
- package/dist/homebridge-ui/public/js/app.ts +21 -0
- package/dist/homebridge-ui/public/js/constants.d.ts +2 -0
- package/dist/homebridge-ui/public/js/constants.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/constants.js +2 -0
- package/dist/homebridge-ui/public/js/constants.js.map +1 -0
- package/dist/homebridge-ui/public/js/constants.ts +1 -0
- package/dist/homebridge-ui/public/js/credentials.d.ts +3 -0
- package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/credentials.js +96 -0
- package/dist/homebridge-ui/public/js/credentials.js.map +1 -0
- package/dist/homebridge-ui/public/js/credentials.ts +100 -0
- package/dist/homebridge-ui/public/js/devices-delete.d.ts +2 -0
- package/dist/homebridge-ui/public/js/devices-delete.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.js +99 -0
- package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.ts +113 -0
- package/dist/homebridge-ui/public/js/devices.d.ts +8 -0
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/devices.js +71 -0
- package/dist/homebridge-ui/public/js/devices.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices.ts +78 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts +3 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.js +107 -0
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.ts +123 -0
- package/dist/homebridge-ui/public/js/logger.d.ts +6 -0
- package/dist/homebridge-ui/public/js/logger.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/logger.js +12 -0
- package/dist/homebridge-ui/public/js/logger.js.map +1 -0
- package/dist/homebridge-ui/public/js/logger.ts +11 -0
- package/dist/homebridge-ui/public/js/modal.d.ts +5 -0
- package/dist/homebridge-ui/public/js/modal.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/modal.js +26 -0
- package/dist/homebridge-ui/public/js/modal.js.map +1 -0
- package/dist/homebridge-ui/public/js/modal.ts +28 -0
- package/dist/homebridge-ui/public/js/modals.d.ts +2 -0
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/modals.js +132 -0
- package/dist/homebridge-ui/public/js/modals.js.map +1 -0
- package/dist/homebridge-ui/public/js/modals.ts +153 -0
- package/dist/homebridge-ui/public/js/render.d.ts +6 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/render.js +166 -0
- package/dist/homebridge-ui/public/js/render.js.map +1 -0
- package/dist/homebridge-ui/public/js/render.ts +190 -0
- package/dist/homebridge-ui/public/js/toast.d.ts +6 -0
- package/dist/homebridge-ui/public/js/toast.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/toast.js +29 -0
- package/dist/homebridge-ui/public/js/toast.js.map +1 -0
- package/dist/homebridge-ui/public/js/toast.ts +37 -0
- package/dist/homebridge-ui/public/js/types.d.ts +23 -0
- package/dist/homebridge-ui/public/js/types.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/types.js +2 -0
- package/dist/homebridge-ui/public/js/types.js.map +1 -0
- package/dist/homebridge-ui/public/js/types.ts +26 -0
- package/dist/homebridge-ui/server.d.ts +1 -3
- package/dist/homebridge-ui/server.d.ts.map +1 -1
- package/dist/homebridge-ui/server.js +10 -561
- package/dist/homebridge-ui/server.js.map +1 -1
- package/dist/homebridge-ui/utils/config-parser.d.ts +35 -0
- package/dist/homebridge-ui/utils/config-parser.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/config-parser.js +87 -0
- package/dist/homebridge-ui/utils/config-parser.js.map +1 -0
- package/dist/homebridge-ui/utils/logger.d.ts +7 -0
- package/dist/homebridge-ui/utils/logger.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/logger.js +17 -0
- package/dist/homebridge-ui/utils/logger.js.map +1 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +6 -2
- package/dist/platform.js.map +1 -1
- package/dist/switchbotClient.d.ts.map +1 -1
- package/dist/switchbotClient.js +2 -0
- package/dist/switchbotClient.js.map +1 -1
- package/docs/variables/default.html +1 -1
- package/eslint.config.js +5 -0
- package/nodemon.json +2 -2
- package/package.json +20 -10
- package/scripts/build-ui.js +36 -0
- package/scripts/free-dev-ports.mjs +105 -0
- package/scripts/sync-device-types.mjs +28 -0
- package/src/device-types.ts +145 -0
- package/src/deviceFactory.ts +71 -31
- package/src/devices/genericDevice.ts +5 -2
- package/src/homebridge-ui/endpoints/config.ts +79 -0
- package/src/homebridge-ui/endpoints/credentials.ts +74 -0
- package/src/homebridge-ui/endpoints/devices.ts +321 -0
- package/src/homebridge-ui/endpoints/discovery.ts +191 -0
- package/src/homebridge-ui/public/index.html +144 -624
- package/src/homebridge-ui/public/js/api.ts +189 -0
- package/src/homebridge-ui/public/js/app.ts +21 -0
- package/src/homebridge-ui/public/js/constants.ts +1 -0
- package/src/homebridge-ui/public/js/credentials.ts +100 -0
- package/src/homebridge-ui/public/js/devices-delete.ts +113 -0
- package/src/homebridge-ui/public/js/devices.ts +78 -0
- package/src/homebridge-ui/public/js/discovery.ts +123 -0
- package/src/homebridge-ui/public/js/logger.ts +11 -0
- package/src/homebridge-ui/public/js/modal.ts +28 -0
- package/src/homebridge-ui/public/js/modals.ts +153 -0
- package/src/homebridge-ui/public/js/render.ts +190 -0
- package/src/homebridge-ui/public/js/toast.ts +37 -0
- package/src/homebridge-ui/public/js/types.ts +26 -0
- package/src/homebridge-ui/server.ts +11 -647
- package/src/homebridge-ui/utils/config-parser.ts +108 -0
- package/src/homebridge-ui/utils/logger.ts +17 -0
- package/src/platform.ts +6 -2
- package/src/switchbotClient.ts +2 -0
- package/switchbot-homebridge-switchbot-5.0.0.tgz +0 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { RequestError } from '@homebridge/plugin-ui-utils';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { getAllDevices, getDeviceArrays, getSwitchBotPlatformConfig } from '../utils/config-parser.js';
|
|
4
|
+
import { uiLog } from '../utils/logger.js';
|
|
5
|
+
/**
|
|
6
|
+
* Register device CRUD endpoints
|
|
7
|
+
*/
|
|
8
|
+
export function registerDeviceEndpoints(server) {
|
|
9
|
+
/**
|
|
10
|
+
* POST /add-device - Add a single device to config
|
|
11
|
+
*/
|
|
12
|
+
server.onRequest('/add-device', async (body) => {
|
|
13
|
+
try {
|
|
14
|
+
const { deviceId, name, type } = body;
|
|
15
|
+
if (!deviceId) {
|
|
16
|
+
throw new Error('Device ID is required');
|
|
17
|
+
}
|
|
18
|
+
const { cfg, platform, cfgPath } = await getSwitchBotPlatformConfig(server);
|
|
19
|
+
uiLog.info('POST /add-device - Request received');
|
|
20
|
+
uiLog.debug(`POST /add-device - Request body: ${JSON.stringify(body)}`);
|
|
21
|
+
uiLog.debug(`POST /add-device - Config file path: ${cfgPath}`);
|
|
22
|
+
const deviceArrays = getDeviceArrays(platform);
|
|
23
|
+
const allDevices = getAllDevices(platform);
|
|
24
|
+
const normalizedDeviceId = String(deviceId).trim().toLowerCase();
|
|
25
|
+
const exists = allDevices.some((d) => String(d.deviceId ?? d.id ?? '').trim().toLowerCase() === normalizedDeviceId);
|
|
26
|
+
if (exists) {
|
|
27
|
+
uiLog.info(`POST /add-device - Device already exists: ${deviceId}`);
|
|
28
|
+
return {
|
|
29
|
+
success: true,
|
|
30
|
+
data: {
|
|
31
|
+
message: 'Device already in config',
|
|
32
|
+
alreadyExists: true,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
let addCount = 0;
|
|
37
|
+
for (const ref of deviceArrays) {
|
|
38
|
+
const refHasDevice = ref.some((d) => String(d.deviceId ?? d.id ?? '').trim().toLowerCase() === normalizedDeviceId);
|
|
39
|
+
if (!refHasDevice) {
|
|
40
|
+
const newDevice = {
|
|
41
|
+
deviceId,
|
|
42
|
+
configDeviceName: name,
|
|
43
|
+
configDeviceType: type,
|
|
44
|
+
};
|
|
45
|
+
ref.push(newDevice);
|
|
46
|
+
addCount++;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (!addCount) {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
data: { message: 'Failed to add device to config' },
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const configJson = JSON.stringify(cfg, null, 2);
|
|
56
|
+
const fileHandle = await fs.open(cfgPath, 'w');
|
|
57
|
+
try {
|
|
58
|
+
await fileHandle.writeFile(configJson, 'utf8');
|
|
59
|
+
await fileHandle.sync();
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
await fileHandle.close();
|
|
63
|
+
}
|
|
64
|
+
// Notify Homebridge UI that config changed
|
|
65
|
+
server.pushEvent('configChanged', { source: 'switchbot-plugin' });
|
|
66
|
+
uiLog.debug('POST /add-device - Sent configChanged event to UI');
|
|
67
|
+
return {
|
|
68
|
+
success: true,
|
|
69
|
+
data: {
|
|
70
|
+
message: `Device "${name}" added successfully`,
|
|
71
|
+
alreadyExists: false,
|
|
72
|
+
added: true,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
uiLog.error(`Error in /add-device: ${e instanceof Error ? e.message : String(e)}`);
|
|
78
|
+
throw new RequestError(`Failed to add device: ${e instanceof Error ? e.message : String(e)}`, e);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* POST /add-devices - Add multiple devices to config (bulk add)
|
|
83
|
+
*/
|
|
84
|
+
server.onRequest('/add-devices', async (body) => {
|
|
85
|
+
try {
|
|
86
|
+
const { devices } = body;
|
|
87
|
+
if (!Array.isArray(devices) || devices.length === 0) {
|
|
88
|
+
throw new Error('Devices array is required and must not be empty');
|
|
89
|
+
}
|
|
90
|
+
const { cfg, platform, cfgPath } = await getSwitchBotPlatformConfig(server);
|
|
91
|
+
uiLog.debug(`POST /add-devices - Received ${devices.length} device(s) to add`);
|
|
92
|
+
uiLog.debug(`POST /add-devices - Config path: ${cfgPath}`);
|
|
93
|
+
const deviceArrays = getDeviceArrays(platform);
|
|
94
|
+
const allDevices = getAllDevices(platform);
|
|
95
|
+
uiLog.debug(`POST /add-devices - Device arrays count: ${deviceArrays.length}, existing devices: ${allDevices.length}`);
|
|
96
|
+
uiLog.debug(`POST /add-devices - Platform.devices exists: ${!!platform.devices}, length: ${platform.devices?.length || 0}`);
|
|
97
|
+
let addedCount = 0;
|
|
98
|
+
let skippedCount = 0;
|
|
99
|
+
const results = [];
|
|
100
|
+
for (const { deviceId, name, type } of devices) {
|
|
101
|
+
if (!deviceId) {
|
|
102
|
+
results.push({ deviceId: '?', success: false, message: 'Device ID is required' });
|
|
103
|
+
skippedCount++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const normalizedDeviceId = String(deviceId).trim().toLowerCase();
|
|
107
|
+
const exists = allDevices.some((d) => String(d.deviceId ?? d.id ?? '').trim().toLowerCase() === normalizedDeviceId);
|
|
108
|
+
if (exists) {
|
|
109
|
+
uiLog.debug(`POST /add-devices - Device already exists: ${deviceId}`);
|
|
110
|
+
results.push({ deviceId, success: true, message: 'Already in config', alreadyExists: true });
|
|
111
|
+
skippedCount++;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
let addedToArray = false;
|
|
115
|
+
for (const ref of deviceArrays) {
|
|
116
|
+
const refHasDevice = ref.some((d) => String(d.deviceId ?? d.id ?? '').trim().toLowerCase() === normalizedDeviceId);
|
|
117
|
+
if (!refHasDevice) {
|
|
118
|
+
const newDevice = {
|
|
119
|
+
deviceId,
|
|
120
|
+
configDeviceName: name,
|
|
121
|
+
configDeviceType: type,
|
|
122
|
+
};
|
|
123
|
+
ref.push(newDevice);
|
|
124
|
+
addedToArray = true;
|
|
125
|
+
uiLog.debug(`POST /add-devices - Added device to array: ${deviceId} (${name}, ${type})`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (addedToArray) {
|
|
129
|
+
results.push({ deviceId, success: true, message: `Device "${name}" added` });
|
|
130
|
+
addedCount++;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
uiLog.warn(`POST /add-devices - Failed to add device: ${deviceId}`);
|
|
134
|
+
results.push({ deviceId, success: false, message: 'Failed to add device' });
|
|
135
|
+
skippedCount++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
uiLog.info(`POST /add-devices - Adding ${addedCount} devices to config: ${cfgPath}`);
|
|
139
|
+
const configJson = JSON.stringify(cfg, null, 2);
|
|
140
|
+
const fileHandle = await fs.open(cfgPath, 'w');
|
|
141
|
+
try {
|
|
142
|
+
await fileHandle.writeFile(configJson, 'utf8');
|
|
143
|
+
await fileHandle.sync();
|
|
144
|
+
uiLog.info(`POST /add-devices - Config file written successfully`);
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
await fileHandle.close();
|
|
148
|
+
}
|
|
149
|
+
// Notify Homebridge UI that config changed to prevent cache overwrite
|
|
150
|
+
server.pushEvent('configChanged', { source: 'switchbot-plugin' });
|
|
151
|
+
uiLog.debug('POST /add-devices - Sent configChanged event to UI');
|
|
152
|
+
return {
|
|
153
|
+
success: true,
|
|
154
|
+
data: {
|
|
155
|
+
message: `Added ${addedCount} device(s)${skippedCount > 0 ? ` (${skippedCount} skipped)` : ''}`,
|
|
156
|
+
addedCount,
|
|
157
|
+
skippedCount,
|
|
158
|
+
results,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
const errorMsg = e instanceof Error ? e.message : String(e);
|
|
164
|
+
uiLog.error(`Error in /add-devices: ${errorMsg}`);
|
|
165
|
+
if (e instanceof Error && e.stack) {
|
|
166
|
+
uiLog.debug(`Stack trace: ${e.stack}`);
|
|
167
|
+
}
|
|
168
|
+
throw new RequestError(`Failed to add devices: ${errorMsg}`, e);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
/**
|
|
172
|
+
* POST /update-device - Update existing device in config
|
|
173
|
+
*/
|
|
174
|
+
server.onRequest('/update-device', async (body) => {
|
|
175
|
+
try {
|
|
176
|
+
const { deviceId, configDeviceName, configDeviceType, connectionPreference, room } = body;
|
|
177
|
+
if (!deviceId) {
|
|
178
|
+
throw new Error('Device ID is required');
|
|
179
|
+
}
|
|
180
|
+
const { cfg, platform, cfgPath } = await getSwitchBotPlatformConfig(server);
|
|
181
|
+
const deviceArrays = getDeviceArrays(platform);
|
|
182
|
+
const devices = getAllDevices(platform);
|
|
183
|
+
const normalizedDeviceId = String(deviceId).trim().toLowerCase();
|
|
184
|
+
const device = devices.find((d) => String(d.deviceId ?? d.id ?? '').trim().toLowerCase() === normalizedDeviceId);
|
|
185
|
+
if (!device) {
|
|
186
|
+
throw new Error('Device not found in config');
|
|
187
|
+
}
|
|
188
|
+
for (const ref of deviceArrays) {
|
|
189
|
+
for (const entry of ref) {
|
|
190
|
+
const entryId = String(entry.deviceId ?? entry.id ?? '').trim().toLowerCase();
|
|
191
|
+
if (entryId !== normalizedDeviceId) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (configDeviceName !== undefined && configDeviceName !== null && String(configDeviceName).trim() !== '') {
|
|
195
|
+
entry.configDeviceName = configDeviceName;
|
|
196
|
+
}
|
|
197
|
+
if (configDeviceType !== undefined && configDeviceType !== null && String(configDeviceType).trim() !== '') {
|
|
198
|
+
entry.configDeviceType = configDeviceType;
|
|
199
|
+
}
|
|
200
|
+
if (connectionPreference !== undefined) {
|
|
201
|
+
entry.connectionPreference = connectionPreference;
|
|
202
|
+
}
|
|
203
|
+
if (room !== undefined) {
|
|
204
|
+
entry.room = room || undefined;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const configJson = JSON.stringify(cfg, null, 2);
|
|
209
|
+
const fileHandle = await fs.open(cfgPath, 'w');
|
|
210
|
+
try {
|
|
211
|
+
await fileHandle.writeFile(configJson, 'utf8');
|
|
212
|
+
await fileHandle.sync();
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
await fileHandle.close();
|
|
216
|
+
}
|
|
217
|
+
// Notify Homebridge UI that config changed
|
|
218
|
+
server.pushEvent('configChanged', { source: 'switchbot-plugin' });
|
|
219
|
+
uiLog.debug('POST /update-device - Sent configChanged event to UI');
|
|
220
|
+
return {
|
|
221
|
+
success: true,
|
|
222
|
+
data: { message: `Device updated successfully - type: ${configDeviceType || device.configDeviceType}` },
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
uiLog.error(`Error in /update-device: ${e instanceof Error ? e.message : String(e)}`);
|
|
227
|
+
throw new RequestError(`Failed to update device: ${e instanceof Error ? e.message : String(e)}`, e);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
/**
|
|
231
|
+
* POST /delete-device - Remove device from config
|
|
232
|
+
*/
|
|
233
|
+
server.onRequest('/delete-device', async (body) => {
|
|
234
|
+
try {
|
|
235
|
+
const { deviceId } = body;
|
|
236
|
+
uiLog.info(`POST /delete-device - Requested deviceId: ${deviceId ?? 'undefined'}`);
|
|
237
|
+
if (!deviceId) {
|
|
238
|
+
throw new Error('Device ID is required');
|
|
239
|
+
}
|
|
240
|
+
const { cfg, platform, cfgPath } = await getSwitchBotPlatformConfig(server);
|
|
241
|
+
const deviceArrays = getDeviceArrays(platform);
|
|
242
|
+
const normalizedDeviceId = String(deviceId).trim().toLowerCase();
|
|
243
|
+
const allDevices = getAllDevices(platform);
|
|
244
|
+
const existing = allDevices.find((d) => String(d.deviceId ?? d.id ?? '').trim().toLowerCase() === normalizedDeviceId);
|
|
245
|
+
if (!existing) {
|
|
246
|
+
throw new Error('Device not found in config');
|
|
247
|
+
}
|
|
248
|
+
const deviceName = existing.configDeviceName || deviceId;
|
|
249
|
+
let removedCount = 0;
|
|
250
|
+
for (const ref of deviceArrays) {
|
|
251
|
+
for (let i = ref.length - 1; i >= 0; i--) {
|
|
252
|
+
const id = String(ref[i]?.deviceId ?? ref[i]?.id ?? '').trim().toLowerCase();
|
|
253
|
+
if (id === normalizedDeviceId) {
|
|
254
|
+
ref.splice(i, 1);
|
|
255
|
+
removedCount++;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (!removedCount) {
|
|
260
|
+
throw new Error('Device not found in config');
|
|
261
|
+
}
|
|
262
|
+
const configJson = JSON.stringify(cfg, null, 2);
|
|
263
|
+
const fileHandle = await fs.open(cfgPath, 'w');
|
|
264
|
+
try {
|
|
265
|
+
await fileHandle.writeFile(configJson, 'utf8');
|
|
266
|
+
await fileHandle.sync();
|
|
267
|
+
}
|
|
268
|
+
finally {
|
|
269
|
+
await fileHandle.close();
|
|
270
|
+
}
|
|
271
|
+
// Notify Homebridge UI that config changed
|
|
272
|
+
server.pushEvent('configChanged', { source: 'switchbot-plugin' });
|
|
273
|
+
uiLog.debug('DELETE /delete-device - Sent configChanged event to UI');
|
|
274
|
+
return {
|
|
275
|
+
success: true,
|
|
276
|
+
data: { message: `Device "${deviceName}" removed from config` },
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
catch (e) {
|
|
280
|
+
uiLog.error(`Error in /delete-device: ${e instanceof Error ? e.message : String(e)}`);
|
|
281
|
+
throw new RequestError('Failed to delete device', e);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=devices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devices.js","sourceRoot":"","sources":["../../../src/homebridge-ui/endpoints/devices.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HomebridgePluginUiServer } from '@homebridge/plugin-ui-utils';
|
|
2
|
+
/**
|
|
3
|
+
* Register discovery endpoint
|
|
4
|
+
* Discovers SwitchBot devices via BLE and OpenAPI
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerDiscoveryEndpoint(server: HomebridgePluginUiServer): void;
|
|
7
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/homebridge-ui/endpoints/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AAO3E;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,wBAAwB,QAmLzE"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { RequestError } from '@homebridge/plugin-ui-utils';
|
|
2
|
+
import { getCredential, getSwitchBotPlatformConfig } from '../utils/config-parser.js';
|
|
3
|
+
import { uiLog } from '../utils/logger.js';
|
|
4
|
+
/**
|
|
5
|
+
* Register discovery endpoint
|
|
6
|
+
* Discovers SwitchBot devices via BLE and OpenAPI
|
|
7
|
+
*/
|
|
8
|
+
export function registerDiscoveryEndpoint(server) {
|
|
9
|
+
server.onRequest('/discover', async () => {
|
|
10
|
+
try {
|
|
11
|
+
const { platform } = await getSwitchBotPlatformConfig(server);
|
|
12
|
+
uiLog.debug(`GET /discover - Platform config keys: ${Object.keys(platform).join(', ')}`);
|
|
13
|
+
const token = getCredential(platform, 'openApiToken') || platform.token;
|
|
14
|
+
const secret = getCredential(platform, 'openApiSecret') || platform.secret;
|
|
15
|
+
const hasOpenAPICredentials = !!token;
|
|
16
|
+
if (!hasOpenAPICredentials) {
|
|
17
|
+
uiLog.warn('GET /discover - No OpenAPI credentials found, will attempt BLE-only discovery');
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
uiLog.info('GET /discover - Using OpenAPI credentials for discovery');
|
|
21
|
+
}
|
|
22
|
+
// Import and initialize node-switchbot
|
|
23
|
+
const { SwitchBot } = await import('node-switchbot');
|
|
24
|
+
const switchbot = new SwitchBot({
|
|
25
|
+
token: token || undefined,
|
|
26
|
+
secret: secret || undefined,
|
|
27
|
+
enableBLE: true,
|
|
28
|
+
enableFallback: true,
|
|
29
|
+
enableRetry: true,
|
|
30
|
+
});
|
|
31
|
+
const deviceMap = new Map();
|
|
32
|
+
// 1. Try BLE discovery first (with timeout)
|
|
33
|
+
uiLog.info('GET /discover - Starting BLE scan...');
|
|
34
|
+
try {
|
|
35
|
+
const bleTimeout = 8000; // 8 second timeout for BLE scan
|
|
36
|
+
const bleDiscoveryPromise = switchbot.discover({ timeout: 5000 }); // 5 second scan timeout
|
|
37
|
+
const bleDevices = await Promise.race([
|
|
38
|
+
bleDiscoveryPromise,
|
|
39
|
+
new Promise(resolve => setTimeout(resolve, bleTimeout, [])),
|
|
40
|
+
]);
|
|
41
|
+
if (Array.isArray(bleDevices) && bleDevices.length > 0) {
|
|
42
|
+
uiLog.info(`GET /discover - Found ${bleDevices.length} BLE devices`);
|
|
43
|
+
for (const [index, d] of bleDevices.entries()) {
|
|
44
|
+
const info = typeof d?.getInfo === 'function' ? d.getInfo() : undefined;
|
|
45
|
+
const id = d?.id
|
|
46
|
+
|| (typeof d?.getId === 'function' ? d.getId() : undefined)
|
|
47
|
+
|| info?.id;
|
|
48
|
+
const mac = d?.mac
|
|
49
|
+
|| (typeof d?.getMAC === 'function' ? d.getMAC() : undefined)
|
|
50
|
+
|| info?.mac;
|
|
51
|
+
if (!id) {
|
|
52
|
+
uiLog.warn(`GET /discover - BLE device at index ${index} has no id, skipping`);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const connectionTypes = Array.isArray(info?.connectionTypes) ? info.connectionTypes : [];
|
|
56
|
+
const isHybrid = connectionTypes.includes('api');
|
|
57
|
+
deviceMap.set(id, {
|
|
58
|
+
id,
|
|
59
|
+
name: d?.name || (typeof d?.getName === 'function' ? d.getName() : undefined) || info?.name || d?.deviceName || id,
|
|
60
|
+
type: d?.deviceType || (typeof d?.getDeviceType === 'function' ? d.getDeviceType() : undefined) || info?.deviceType || d?.type || d?.model || 'unknown',
|
|
61
|
+
model: info?.model || d?.model || d?.deviceModel,
|
|
62
|
+
address: mac,
|
|
63
|
+
connectionType: isHybrid ? 'Both' : 'BLE',
|
|
64
|
+
rssi: info?.rssi || d?.rssi,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
uiLog.info('GET /discover - No BLE devices found or scan timed out');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (bleErr) {
|
|
73
|
+
uiLog.warn(`GET /discover - BLE discovery failed: ${bleErr instanceof Error ? bleErr.message : String(bleErr)}`);
|
|
74
|
+
// Continue with OpenAPI even if BLE fails
|
|
75
|
+
}
|
|
76
|
+
// 2. Get devices from OpenAPI (only if credentials are available)
|
|
77
|
+
if (hasOpenAPICredentials) {
|
|
78
|
+
uiLog.info('GET /discover - Fetching devices from OpenAPI...');
|
|
79
|
+
try {
|
|
80
|
+
const apiClient = switchbot.getAPIClient();
|
|
81
|
+
if (!apiClient) {
|
|
82
|
+
throw new Error('API client not available - token/secret may be missing');
|
|
83
|
+
}
|
|
84
|
+
const apiData = await apiClient.getDevices();
|
|
85
|
+
uiLog.debug(`GET /discover - OpenAPI response: ${JSON.stringify(apiData)}`);
|
|
86
|
+
// Parse physical devices - apiData is DeviceListResponse with deviceList and infraredRemoteList
|
|
87
|
+
const devices = apiData.deviceList || [];
|
|
88
|
+
const irDevices = apiData.infraredRemoteList || [];
|
|
89
|
+
uiLog.info(`GET /discover - Found ${devices.length} OpenAPI physical devices and ${irDevices.length} IR devices`);
|
|
90
|
+
// Process physical devices from OpenAPI
|
|
91
|
+
for (const d of devices) {
|
|
92
|
+
const id = d.deviceId;
|
|
93
|
+
if (!id) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const existing = deviceMap.get(id);
|
|
97
|
+
if (existing) {
|
|
98
|
+
// Device found via both BLE and OpenAPI
|
|
99
|
+
existing.connectionType = 'Both';
|
|
100
|
+
existing.name = d.deviceName || existing.name;
|
|
101
|
+
existing.type = d.deviceType || existing.type;
|
|
102
|
+
// Note: APIDevice doesn't have a model property
|
|
103
|
+
existing.enabled = d.enableCloudService !== false;
|
|
104
|
+
existing.hubDeviceId = d.hubDeviceId;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Device only found via OpenAPI
|
|
108
|
+
deviceMap.set(id, {
|
|
109
|
+
id,
|
|
110
|
+
name: d.deviceName || id,
|
|
111
|
+
type: d.deviceType || 'unknown',
|
|
112
|
+
enabled: d.enableCloudService !== false,
|
|
113
|
+
hubDeviceId: d.hubDeviceId,
|
|
114
|
+
connectionType: 'OpenAPI',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Process IR devices (OpenAPI only)
|
|
119
|
+
for (const d of irDevices) {
|
|
120
|
+
const id = d.deviceId;
|
|
121
|
+
if (!id) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
deviceMap.set(id, {
|
|
125
|
+
id,
|
|
126
|
+
name: d.deviceName || id,
|
|
127
|
+
type: d.remoteType || 'unknown',
|
|
128
|
+
enabled: true,
|
|
129
|
+
hubDeviceId: d.hubDeviceId,
|
|
130
|
+
connectionType: 'OpenAPI',
|
|
131
|
+
isIR: true,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (apiErr) {
|
|
136
|
+
uiLog.error(`GET /discover - OpenAPI discovery failed: ${apiErr instanceof Error ? apiErr.message : String(apiErr)}`);
|
|
137
|
+
// If we have BLE devices, we can still return those
|
|
138
|
+
if (deviceMap.size === 0) {
|
|
139
|
+
throw apiErr;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
uiLog.info('GET /discover - Skipping OpenAPI discovery (no credentials configured)');
|
|
145
|
+
}
|
|
146
|
+
const normalizedBleDevices = [...deviceMap.values()].filter(d => d.connectionType === 'BLE' || d.connectionType === 'Both');
|
|
147
|
+
const firstNormalizedBleId = normalizedBleDevices[0]?.id || 'none';
|
|
148
|
+
uiLog.info(`GET /discover - Normalized BLE devices: ${normalizedBleDevices.length} (firstId: ${firstNormalizedBleId})`);
|
|
149
|
+
// Check if we found any devices
|
|
150
|
+
if (deviceMap.size === 0) {
|
|
151
|
+
const errorMsg = hasOpenAPICredentials
|
|
152
|
+
? 'No devices found via BLE or OpenAPI. Make sure devices are powered on and in range.'
|
|
153
|
+
: 'No devices found via BLE. OpenAPI credentials not configured. Please save your credentials in settings to discover cloud-connected devices, or ensure BLE devices are powered on and in range.';
|
|
154
|
+
uiLog.error(`GET /discover - ${errorMsg}`);
|
|
155
|
+
throw new Error(errorMsg);
|
|
156
|
+
}
|
|
157
|
+
// Convert map to array
|
|
158
|
+
const allDiscovered = [...deviceMap.values()];
|
|
159
|
+
const bleCount = allDiscovered.filter(d => d.connectionType === 'BLE').length;
|
|
160
|
+
const apiCount = allDiscovered.filter(d => d.connectionType === 'OpenAPI').length;
|
|
161
|
+
const bothCount = allDiscovered.filter(d => d.connectionType === 'Both').length;
|
|
162
|
+
uiLog.info(`GET /discover - Total: ${allDiscovered.length} devices (BLE: ${bleCount}, OpenAPI: ${apiCount}, Both: ${bothCount})`);
|
|
163
|
+
return { success: true, data: allDiscovered };
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
uiLog.error(`Error in /discover: ${e instanceof Error ? e.message : String(e)}`);
|
|
167
|
+
throw new RequestError(`Failed to discover devices: ${e instanceof Error ? e.message : String(e)}`, e);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/homebridge-ui/endpoints/discovery.ts"],"names":[],"mappings":"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"}
|