@switchbot/homebridge-switchbot 5.0.0-beta.77 → 5.0.0-beta.79

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.
@@ -48,6 +48,17 @@
48
48
  <div id="saveStatus"></div>
49
49
  </div>
50
50
 
51
+ <div class="card">
52
+ <h2>Discover Devices</h2>
53
+ <p>Click "Discover" to find all devices available in your SwitchBot account and add them to your configuration.</p>
54
+ <button id="discoverBtn" onclick="discoverDevices()" style="margin-bottom: 16px">🔍 Discover Devices</button>
55
+ <div id="discoverStatus" style="margin-bottom: 16px"></div>
56
+ <div id="discoveredList" style="display: none">
57
+ <h3 style="margin-top: 0">Available Devices</h3>
58
+ <ul id="discoveredDevices" style="max-height: 300px; overflow-y: auto"></ul>
59
+ </div>
60
+ </div>
61
+
51
62
  <div class="card">
52
63
  <h2>Configured Devices</h2>
53
64
  <p>This page lists devices found in your Homebridge config for the SwitchBot platform. Use the copy button to insert device IDs into the plugin configuration. Connection preference (BLE/OpenAPI) is shown when available.</p>
@@ -144,7 +155,7 @@
144
155
  async function fetchDevices() {
145
156
  try {
146
157
  const resp = await homebridge.request('/devices', {})
147
- if (!resp || !resp.success) throw new Error(resp?.data?.message || 'request failed')
158
+ if (!resp || resp.success === false) throw new Error(resp?.data?.message || 'request failed')
148
159
  return resp.data || []
149
160
  } catch (e) {
150
161
  console.error(e)
@@ -152,6 +163,124 @@
152
163
  }
153
164
  }
154
165
 
166
+ async function discoverDevices() {
167
+ const btn = document.getElementById('discoverBtn')
168
+ const status = document.getElementById('discoverStatus')
169
+ const list = document.getElementById('discoveredList')
170
+ const ul = document.getElementById('discoveredDevices')
171
+
172
+ try {
173
+ btn.disabled = true
174
+ btn.textContent = '🔍 Discovering...'
175
+ status.textContent = 'Searching SwitchBot account...'
176
+ status.classList.remove('error')
177
+
178
+ const resp = await homebridge.request('/discover', {})
179
+ console.log('Discover response:', resp)
180
+
181
+ if (!resp || resp.success === false) {
182
+ throw new Error(resp?.data?.message || 'Discovery failed')
183
+ }
184
+
185
+ const devices = resp.data || []
186
+
187
+ if (!devices.length) {
188
+ status.textContent = 'No devices found in your SwitchBot account'
189
+ list.style.display = 'none'
190
+ return
191
+ }
192
+
193
+ status.textContent = `Found ${devices.length} device(s)`
194
+ ul.innerHTML = ''
195
+
196
+ for (const d of devices) {
197
+ const li = document.createElement('li')
198
+ li.style.display = 'flex'
199
+ li.style.gap = '8px'
200
+ li.style.alignItems = 'center'
201
+ li.style.justifyContent = 'space-between'
202
+ li.style.padding = '8px'
203
+ li.style.background = '#333'
204
+ li.style.borderRadius = '4px'
205
+ li.style.marginBottom = '8px'
206
+
207
+ const info = document.createElement('div')
208
+ info.style.flex = '1'
209
+ const name = document.createElement('div')
210
+ name.style.fontWeight = '500'
211
+ name.textContent = d.name || d.id
212
+ const details = document.createElement('div')
213
+ details.style.fontSize = '12px'
214
+ details.style.opacity = '0.75'
215
+ details.textContent = `ID: ${d.id} | Type: ${d.type} | Model: ${d.model || 'N/A'}`
216
+ info.appendChild(name)
217
+ info.appendChild(details)
218
+
219
+ const addBtn = document.createElement('button')
220
+ addBtn.textContent = '+ Add'
221
+ addBtn.style.marginLeft = '8px'
222
+ addBtn.onclick = async () => {
223
+ await addDeviceToConfig(d)
224
+ }
225
+
226
+ li.appendChild(info)
227
+ li.appendChild(addBtn)
228
+ ul.appendChild(li)
229
+ }
230
+
231
+ list.style.display = 'block'
232
+ } catch (e) {
233
+ console.error('Discovery error:', e)
234
+ status.textContent = 'Error: ' + (e?.message || 'Discovery failed')
235
+ status.classList.add('error')
236
+ list.style.display = 'none'
237
+ } finally {
238
+ btn.disabled = false
239
+ btn.textContent = '🔍 Discover Devices'
240
+ }
241
+ }
242
+
243
+ async function addDeviceToConfig(device) {
244
+ try {
245
+ console.log('Adding device to config:', device)
246
+
247
+ const resp = await homebridge.request('/add-device', {
248
+ deviceId: device.id,
249
+ name: device.name,
250
+ type: device.type,
251
+ })
252
+
253
+ console.log('Add device response:', resp)
254
+
255
+ if (!resp || resp.success === false) {
256
+ throw new Error(resp?.data?.message || 'Failed to add device')
257
+ }
258
+
259
+ // Show success message
260
+ const message = resp.data?.message || `Device "${device.name}" added successfully!`
261
+ const status = document.getElementById('discoverStatus')
262
+ status.textContent = '✓ ' + message
263
+ status.classList.remove('error')
264
+ status.classList.add('success-msg')
265
+
266
+ // Refresh lists after 1 second
267
+ setTimeout(async () => {
268
+ await loadConfiguredDevices()
269
+ await discoverDevices()
270
+ }, 1000)
271
+ } catch (e) {
272
+ console.error('Add device error:', e)
273
+ const status = document.getElementById('discoverStatus')
274
+ status.textContent = '✗ Error: ' + (e?.message || 'Failed to add device')
275
+ status.classList.add('error')
276
+ }
277
+ }
278
+
279
+ async function loadConfiguredDevices() {
280
+ const list = await fetchDevices()
281
+ render(list)
282
+ }
283
+
155
284
  function render(list) {
156
285
  const ul = document.getElementById('devices')
157
286
  const status = document.getElementById('status')
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/homebridge-ui/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAgB,MAAM,6BAA6B,CAAA;AAGpF,QAAA,MAAM,MAAM,0BAAiC,CAAA;AA6H7C,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/homebridge-ui/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAgB,MAAM,6BAA6B,CAAA;AAGpF,QAAA,MAAM,MAAM,0BAAiC,CAAA;AAoP7C,eAAe,MAAM,CAAA"}
@@ -65,6 +65,108 @@ server.onRequest('/devices', async () => {
65
65
  throw new RequestError('Failed to read Homebridge config', e);
66
66
  }
67
67
  });
68
+ server.onRequest('/discover', async () => {
69
+ try {
70
+ const { platform } = await getSwitchBotPlatformConfig();
71
+ console.log('[SwitchBot UI] GET /discover - Platform config:', Object.keys(platform));
72
+ const token = platform.openApiToken || platform.token;
73
+ if (!token) {
74
+ console.error('[SwitchBot UI] No API token found in platform config');
75
+ throw new Error('OpenAPI token not configured. Please save your credentials first.');
76
+ }
77
+ console.log('[SwitchBot UI] GET /discover - Fetching devices from SwitchBot API');
78
+ const url = 'https://api.switch-bot.com/v1.0/devices';
79
+ const opts = {
80
+ headers: {
81
+ Authorization: token,
82
+ },
83
+ };
84
+ console.log('[SwitchBot UI] GET /discover - Making request to', url);
85
+ const resp = await fetch(url, opts);
86
+ console.log('[SwitchBot UI] GET /discover - API response status:', resp.status);
87
+ if (!resp.ok) {
88
+ const errorText = await resp.text();
89
+ console.error('[SwitchBot UI] API error response:', errorText);
90
+ throw new Error(`SwitchBot API returned ${resp.status}: ${errorText}`);
91
+ }
92
+ const data = await resp.json();
93
+ console.log('[SwitchBot UI] GET /discover - Full API response:', JSON.stringify(data, null, 2));
94
+ // Handle different response formats
95
+ let devices = [];
96
+ if (Array.isArray(data)) {
97
+ devices = data;
98
+ }
99
+ else if (Array.isArray(data.body)) {
100
+ devices = data.body;
101
+ }
102
+ else if (Array.isArray(data.devices)) {
103
+ devices = data.devices;
104
+ }
105
+ else if (data.body && typeof data.body === 'object') {
106
+ // Sometimes the response has devices listed within body
107
+ const bodyKeys = Object.keys(data.body);
108
+ if (bodyKeys.includes('deviceList')) {
109
+ devices = Array.isArray(data.body.deviceList) ? data.body.deviceList : [];
110
+ }
111
+ else if (bodyKeys.includes('devices')) {
112
+ devices = Array.isArray(data.body.devices) ? data.body.devices : [];
113
+ }
114
+ }
115
+ if (!Array.isArray(devices)) {
116
+ console.warn('[SwitchBot UI] Could not find devices array in API response. Response keys:', Object.keys(data), 'Body keys:', data.body ? Object.keys(data.body) : 'N/A');
117
+ devices = [];
118
+ }
119
+ const discovered = devices.map((d) => ({
120
+ id: d.deviceId || d.id,
121
+ name: d.deviceName || d.name,
122
+ type: d.deviceType || d.type || 'unknown',
123
+ model: d.deviceModel || d.model,
124
+ enabled: d.enableCloudService !== false,
125
+ }));
126
+ console.log('[SwitchBot UI] GET /discover - Found', discovered.length, 'devices from API');
127
+ return { success: true, data: discovered };
128
+ }
129
+ catch (e) {
130
+ console.error('[SwitchBot UI] Error in /discover:', e instanceof Error ? e.message : String(e));
131
+ throw new RequestError(`Failed to discover devices: ${e instanceof Error ? e.message : String(e)}`, e);
132
+ }
133
+ });
134
+ server.onRequest('/add-device', async (body) => {
135
+ try {
136
+ const { deviceId, name, type } = body;
137
+ if (!deviceId) {
138
+ throw new Error('Device ID is required');
139
+ }
140
+ const { config, platform, cfgPath } = await getSwitchBotPlatformConfig();
141
+ console.log('[SwitchBot UI] POST /add-device - Adding device:', deviceId);
142
+ // Initialize devices array if needed
143
+ if (!Array.isArray(platform.devices)) {
144
+ platform.devices = [];
145
+ }
146
+ // Check if already exists
147
+ const exists = platform.devices.some((d) => (d.deviceId ?? d.id) === deviceId);
148
+ if (exists) {
149
+ return { success: false, data: { message: 'Device already in config' } };
150
+ }
151
+ // Add device
152
+ platform.devices.push({
153
+ deviceId,
154
+ configDeviceName: name,
155
+ configDeviceType: type,
156
+ });
157
+ // Save config
158
+ await fs.writeFile(cfgPath, JSON.stringify(config, null, 2), 'utf8');
159
+ console.log('[SwitchBot UI] Device added successfully:', deviceId);
160
+ return {
161
+ success: true,
162
+ data: { message: `Device "${name}" added successfully` },
163
+ };
164
+ }
165
+ catch (e) {
166
+ console.error('[SwitchBot UI] Error in /add-device:', e);
167
+ throw new RequestError('Failed to add device', e);
168
+ }
169
+ });
68
170
  server.onRequest('/credentials', async (body) => {
69
171
  try {
70
172
  // Handle both GET and POST requests
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/homebridge-ui/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/homebridge-ui/server.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AACpF,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAEjC,MAAM,MAAM,GAAG,IAAI,wBAAwB,EAAE,CAAA;AAE7C,wDAAwD;AACxD,KAAK,UAAU,0BAA0B;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,oBAAoB,CAAA;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACnD,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;IAEnE,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,MAAM,YAAY,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,CAAA;QAC/C,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;YAC9D,SAAQ;QACV,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAA;IAC9C,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;AAC3D,CAAC;AAED,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;IACtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,oBAAoB,CAAA;QAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;QACnD,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC3B,MAAM,KAAK,GAAsG,EAAE,CAAA;QAEnH,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;QACnE,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,MAAM,YAAY,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,CAAA;gBAC/C,6CAA6C;gBAC7C,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;oBAC9D,SAAQ;gBACV,CAAC;gBAED,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAA;gBAC9B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;gBACrE,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;oBACxB,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAA;oBAC7B,IAAI,CAAC,EAAE,EAAE,CAAC;wBACR,SAAQ;oBACV,CAAC;oBAED,KAAK,CAAC,IAAI,CAAC;wBACT,EAAE;wBACF,IAAI,EAAE,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,UAAU;wBAClD,IAAI,EAAE,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,UAAU;wBAClD,oBAAoB,EAAE,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,UAAU,IAAI,MAAM;wBACtE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,SAAS;qBACxC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,oCAAoC;YACtC,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,qCAAqC,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QAC3E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;IACvC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,CAAC,CAAC,CAAA;QACrD,MAAM,IAAI,YAAY,CAAC,kCAAkC,EAAE,CAAC,CAAC,CAAA;IAC/D,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;IACvC,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAA;QAEvD,OAAO,CAAC,GAAG,CAAC,iDAAiD,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;QAErF,MAAM,KAAK,GAAG,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,KAAK,CAAA;QACrD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAA;YACrE,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAA;QACtF,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAA;QAEjF,MAAM,GAAG,GAAG,yCAAyC,CAAA;QACrD,MAAM,IAAI,GAAG;YACX,OAAO,EAAE;gBACP,aAAa,EAAE,KAAK;aACrB;SACF,CAAA;QAED,OAAO,CAAC,GAAG,CAAC,kDAAkD,EAAE,GAAG,CAAC,CAAA;QACpE,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QAEnC,OAAO,CAAC,GAAG,CAAC,qDAAqD,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QAE/E,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;YACnC,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,SAAS,CAAC,CAAA;YAC9D,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAA;QACxE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAC9B,OAAO,CAAC,GAAG,CAAC,mDAAmD,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAE/F,oCAAoC;QACpC,IAAI,OAAO,GAAU,EAAE,CAAA;QACvB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,OAAO,GAAG,IAAI,CAAA;QAChB,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAA;QACrB,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QACxB,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtD,wDAAwD;YACxD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACvC,IAAI,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBACpC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAA;YAC3E,CAAC;iBAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBACxC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;YACrE,CAAC;QACH,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,6EAA6E,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YACxK,OAAO,GAAG,EAAE,CAAA;QACd,CAAC;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;YAC1C,EAAE,EAAE,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE;YACtB,IAAI,EAAE,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI;YAC5B,IAAI,EAAE,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI,IAAI,SAAS;YACzC,KAAK,EAAE,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,KAAK;YAC/B,OAAO,EAAE,CAAC,CAAC,kBAAkB,KAAK,KAAK;SACxC,CAAC,CAAC,CAAA;QAEH,OAAO,CAAC,GAAG,CAAC,sCAAsC,EAAE,UAAU,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;QAC1F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAA;IAC5C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/F,MAAM,IAAI,YAAY,CAAC,+BAA+B,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;IACxG,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,SAAS,CAAC,aAAa,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;IAClD,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;QAErC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;QAC1C,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAA;QAExE,OAAO,CAAC,GAAG,CAAC,kDAAkD,EAAE,QAAQ,CAAC,CAAA;QAEzE,qCAAqC;QACrC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACrC,QAAQ,CAAC,OAAO,GAAG,EAAE,CAAA;QACvB,CAAC;QAED,0BAA0B;QAC1B,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAA;QACnF,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,0BAA0B,EAAE,EAAE,CAAA;QAC1E,CAAC;QAED,aAAa;QACb,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;YACpB,QAAQ;YACR,gBAAgB,EAAE,IAAI;YACtB,gBAAgB,EAAE,IAAI;SACvB,CAAC,CAAA;QAEF,cAAc;QACd,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;QAEpE,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,QAAQ,CAAC,CAAA;QAElE,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,EAAE,OAAO,EAAE,WAAW,IAAI,sBAAsB,EAAE;SACzD,CAAA;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,CAAC,CAAC,CAAA;QACxD,MAAM,IAAI,YAAY,CAAC,sBAAsB,EAAE,CAAC,CAAC,CAAA;IACnD,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,SAAS,CAAC,cAAc,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;IACnD,IAAI,CAAC;QACH,oCAAoC;QACpC,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5C,sCAAsC;YACtC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAA;YAEvD,MAAM,MAAM,GAAG;gBACb,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,YAAY;gBACjC,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,aAAa;gBACnC,WAAW,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC7E,YAAY,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;aACjF,CAAA;YAED,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,MAAM,CAAC,CAAA;YAChE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QACxC,CAAC;aAAM,CAAC;YACN,kCAAkC;YAClC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;YAE9B,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;YAClD,CAAC;YAED,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAA;YAExE,OAAO,CAAC,GAAG,CAAC,wDAAwD,EAAE,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAA;YACzG,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,OAAO,CAAC,CAAA;YACnD,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,KAAK,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;YAE1F,wDAAwD;YACxD,QAAQ,CAAC,YAAY,GAAG,KAAK,CAAA;YAC7B,QAAQ,CAAC,aAAa,GAAG,MAAM,CAAA;YAE/B,4BAA4B;YAC5B,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;YAEpE,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;YAE5D,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,EAAE,OAAO,EAAE,gCAAgC,EAAE;aACpD,CAAA;QACH,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,CAAC,CAAC,CAAA;QACzD,MAAM,IAAI,YAAY,CAAC,sCAAsC,EAAE,CAAC,CAAC,CAAA;IACnE,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,KAAK,EAAE,CAAA;AAEd,eAAe,MAAM,CAAA"}
@@ -1 +1 @@
1
- <!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=&gt;</span> <span class="tsd-signature-type">void</span></div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter-signature"><ul class="tsd-signatures"><li class="tsd-signature" id="__type"><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">void</span></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">api</span>: <span class="tsd-signature-type">API</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4></li></ul></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/fdf94c065018b63f189137635c0d74689aa57769/src/index.ts#L12">index.ts:12</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">@switchbot/homebridge-switchbot</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>
1
+ <!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=&gt;</span> <span class="tsd-signature-type">void</span></div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter-signature"><ul class="tsd-signatures"><li class="tsd-signature" id="__type"><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">void</span></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">api</span>: <span class="tsd-signature-type">API</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4></li></ul></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/42cb2bab88e1db495b6b92e75a31f7cf34eb8670/src/index.ts#L12">index.ts:12</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">@switchbot/homebridge-switchbot</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@switchbot/homebridge-switchbot",
3
3
  "displayName": "SwitchBot",
4
4
  "type": "module",
5
- "version": "5.0.0-beta.77",
5
+ "version": "5.0.0-beta.79",
6
6
  "description": "The SwitchBot plugin allows you to access your SwitchBot device(s) from HomeKit.",
7
7
  "author": "SwitchBot <support@wondertechlabs.com> (https://github.com/SwitchBot)",
8
8
  "contributors": [
@@ -48,6 +48,17 @@
48
48
  <div id="saveStatus"></div>
49
49
  </div>
50
50
 
51
+ <div class="card">
52
+ <h2>Discover Devices</h2>
53
+ <p>Click "Discover" to find all devices available in your SwitchBot account and add them to your configuration.</p>
54
+ <button id="discoverBtn" onclick="discoverDevices()" style="margin-bottom: 16px">🔍 Discover Devices</button>
55
+ <div id="discoverStatus" style="margin-bottom: 16px"></div>
56
+ <div id="discoveredList" style="display: none">
57
+ <h3 style="margin-top: 0">Available Devices</h3>
58
+ <ul id="discoveredDevices" style="max-height: 300px; overflow-y: auto"></ul>
59
+ </div>
60
+ </div>
61
+
51
62
  <div class="card">
52
63
  <h2>Configured Devices</h2>
53
64
  <p>This page lists devices found in your Homebridge config for the SwitchBot platform. Use the copy button to insert device IDs into the plugin configuration. Connection preference (BLE/OpenAPI) is shown when available.</p>
@@ -144,7 +155,7 @@
144
155
  async function fetchDevices() {
145
156
  try {
146
157
  const resp = await homebridge.request('/devices', {})
147
- if (!resp || !resp.success) throw new Error(resp?.data?.message || 'request failed')
158
+ if (!resp || resp.success === false) throw new Error(resp?.data?.message || 'request failed')
148
159
  return resp.data || []
149
160
  } catch (e) {
150
161
  console.error(e)
@@ -152,6 +163,124 @@
152
163
  }
153
164
  }
154
165
 
166
+ async function discoverDevices() {
167
+ const btn = document.getElementById('discoverBtn')
168
+ const status = document.getElementById('discoverStatus')
169
+ const list = document.getElementById('discoveredList')
170
+ const ul = document.getElementById('discoveredDevices')
171
+
172
+ try {
173
+ btn.disabled = true
174
+ btn.textContent = '🔍 Discovering...'
175
+ status.textContent = 'Searching SwitchBot account...'
176
+ status.classList.remove('error')
177
+
178
+ const resp = await homebridge.request('/discover', {})
179
+ console.log('Discover response:', resp)
180
+
181
+ if (!resp || resp.success === false) {
182
+ throw new Error(resp?.data?.message || 'Discovery failed')
183
+ }
184
+
185
+ const devices = resp.data || []
186
+
187
+ if (!devices.length) {
188
+ status.textContent = 'No devices found in your SwitchBot account'
189
+ list.style.display = 'none'
190
+ return
191
+ }
192
+
193
+ status.textContent = `Found ${devices.length} device(s)`
194
+ ul.innerHTML = ''
195
+
196
+ for (const d of devices) {
197
+ const li = document.createElement('li')
198
+ li.style.display = 'flex'
199
+ li.style.gap = '8px'
200
+ li.style.alignItems = 'center'
201
+ li.style.justifyContent = 'space-between'
202
+ li.style.padding = '8px'
203
+ li.style.background = '#333'
204
+ li.style.borderRadius = '4px'
205
+ li.style.marginBottom = '8px'
206
+
207
+ const info = document.createElement('div')
208
+ info.style.flex = '1'
209
+ const name = document.createElement('div')
210
+ name.style.fontWeight = '500'
211
+ name.textContent = d.name || d.id
212
+ const details = document.createElement('div')
213
+ details.style.fontSize = '12px'
214
+ details.style.opacity = '0.75'
215
+ details.textContent = `ID: ${d.id} | Type: ${d.type} | Model: ${d.model || 'N/A'}`
216
+ info.appendChild(name)
217
+ info.appendChild(details)
218
+
219
+ const addBtn = document.createElement('button')
220
+ addBtn.textContent = '+ Add'
221
+ addBtn.style.marginLeft = '8px'
222
+ addBtn.onclick = async () => {
223
+ await addDeviceToConfig(d)
224
+ }
225
+
226
+ li.appendChild(info)
227
+ li.appendChild(addBtn)
228
+ ul.appendChild(li)
229
+ }
230
+
231
+ list.style.display = 'block'
232
+ } catch (e) {
233
+ console.error('Discovery error:', e)
234
+ status.textContent = 'Error: ' + (e?.message || 'Discovery failed')
235
+ status.classList.add('error')
236
+ list.style.display = 'none'
237
+ } finally {
238
+ btn.disabled = false
239
+ btn.textContent = '🔍 Discover Devices'
240
+ }
241
+ }
242
+
243
+ async function addDeviceToConfig(device) {
244
+ try {
245
+ console.log('Adding device to config:', device)
246
+
247
+ const resp = await homebridge.request('/add-device', {
248
+ deviceId: device.id,
249
+ name: device.name,
250
+ type: device.type,
251
+ })
252
+
253
+ console.log('Add device response:', resp)
254
+
255
+ if (!resp || resp.success === false) {
256
+ throw new Error(resp?.data?.message || 'Failed to add device')
257
+ }
258
+
259
+ // Show success message
260
+ const message = resp.data?.message || `Device "${device.name}" added successfully!`
261
+ const status = document.getElementById('discoverStatus')
262
+ status.textContent = '✓ ' + message
263
+ status.classList.remove('error')
264
+ status.classList.add('success-msg')
265
+
266
+ // Refresh lists after 1 second
267
+ setTimeout(async () => {
268
+ await loadConfiguredDevices()
269
+ await discoverDevices()
270
+ }, 1000)
271
+ } catch (e) {
272
+ console.error('Add device error:', e)
273
+ const status = document.getElementById('discoverStatus')
274
+ status.textContent = '✗ Error: ' + (e?.message || 'Failed to add device')
275
+ status.classList.add('error')
276
+ }
277
+ }
278
+
279
+ async function loadConfiguredDevices() {
280
+ const list = await fetchDevices()
281
+ render(list)
282
+ }
283
+
155
284
  function render(list) {
156
285
  const ul = document.getElementById('devices')
157
286
  const status = document.getElementById('status')
@@ -75,6 +75,125 @@ server.onRequest('/devices', async () => {
75
75
  }
76
76
  })
77
77
 
78
+ server.onRequest('/discover', async () => {
79
+ try {
80
+ const { platform } = await getSwitchBotPlatformConfig()
81
+
82
+ console.log('[SwitchBot UI] GET /discover - Platform config:', Object.keys(platform))
83
+
84
+ const token = platform.openApiToken || platform.token
85
+ if (!token) {
86
+ console.error('[SwitchBot UI] No API token found in platform config')
87
+ throw new Error('OpenAPI token not configured. Please save your credentials first.')
88
+ }
89
+
90
+ console.log('[SwitchBot UI] GET /discover - Fetching devices from SwitchBot API')
91
+
92
+ const url = 'https://api.switch-bot.com/v1.0/devices'
93
+ const opts = {
94
+ headers: {
95
+ Authorization: token,
96
+ },
97
+ }
98
+
99
+ console.log('[SwitchBot UI] GET /discover - Making request to', url)
100
+ const resp = await fetch(url, opts)
101
+
102
+ console.log('[SwitchBot UI] GET /discover - API response status:', resp.status)
103
+
104
+ if (!resp.ok) {
105
+ const errorText = await resp.text()
106
+ console.error('[SwitchBot UI] API error response:', errorText)
107
+ throw new Error(`SwitchBot API returned ${resp.status}: ${errorText}`)
108
+ }
109
+
110
+ const data = await resp.json()
111
+ console.log('[SwitchBot UI] GET /discover - Full API response:', JSON.stringify(data, null, 2))
112
+
113
+ // Handle different response formats
114
+ let devices: any[] = []
115
+ if (Array.isArray(data)) {
116
+ devices = data
117
+ } else if (Array.isArray(data.body)) {
118
+ devices = data.body
119
+ } else if (Array.isArray(data.devices)) {
120
+ devices = data.devices
121
+ } else if (data.body && typeof data.body === 'object') {
122
+ // Sometimes the response has devices listed within body
123
+ const bodyKeys = Object.keys(data.body)
124
+ if (bodyKeys.includes('deviceList')) {
125
+ devices = Array.isArray(data.body.deviceList) ? data.body.deviceList : []
126
+ } else if (bodyKeys.includes('devices')) {
127
+ devices = Array.isArray(data.body.devices) ? data.body.devices : []
128
+ }
129
+ }
130
+
131
+ if (!Array.isArray(devices)) {
132
+ console.warn('[SwitchBot UI] Could not find devices array in API response. Response keys:', Object.keys(data), 'Body keys:', data.body ? Object.keys(data.body) : 'N/A')
133
+ devices = []
134
+ }
135
+
136
+ const discovered = devices.map((d: any) => ({
137
+ id: d.deviceId || d.id,
138
+ name: d.deviceName || d.name,
139
+ type: d.deviceType || d.type || 'unknown',
140
+ model: d.deviceModel || d.model,
141
+ enabled: d.enableCloudService !== false,
142
+ }))
143
+
144
+ console.log('[SwitchBot UI] GET /discover - Found', discovered.length, 'devices from API')
145
+ return { success: true, data: discovered }
146
+ } catch (e) {
147
+ console.error('[SwitchBot UI] Error in /discover:', e instanceof Error ? e.message : String(e))
148
+ throw new RequestError(`Failed to discover devices: ${e instanceof Error ? e.message : String(e)}`, e)
149
+ }
150
+ })
151
+
152
+ server.onRequest('/add-device', async (body: any) => {
153
+ try {
154
+ const { deviceId, name, type } = body
155
+
156
+ if (!deviceId) {
157
+ throw new Error('Device ID is required')
158
+ }
159
+
160
+ const { config, platform, cfgPath } = await getSwitchBotPlatformConfig()
161
+
162
+ console.log('[SwitchBot UI] POST /add-device - Adding device:', deviceId)
163
+
164
+ // Initialize devices array if needed
165
+ if (!Array.isArray(platform.devices)) {
166
+ platform.devices = []
167
+ }
168
+
169
+ // Check if already exists
170
+ const exists = platform.devices.some((d: any) => (d.deviceId ?? d.id) === deviceId)
171
+ if (exists) {
172
+ return { success: false, data: { message: 'Device already in config' } }
173
+ }
174
+
175
+ // Add device
176
+ platform.devices.push({
177
+ deviceId,
178
+ configDeviceName: name,
179
+ configDeviceType: type,
180
+ })
181
+
182
+ // Save config
183
+ await fs.writeFile(cfgPath, JSON.stringify(config, null, 2), 'utf8')
184
+
185
+ console.log('[SwitchBot UI] Device added successfully:', deviceId)
186
+
187
+ return {
188
+ success: true,
189
+ data: { message: `Device "${name}" added successfully` },
190
+ }
191
+ } catch (e) {
192
+ console.error('[SwitchBot UI] Error in /add-device:', e)
193
+ throw new RequestError('Failed to add device', e)
194
+ }
195
+ })
196
+
78
197
  server.onRequest('/credentials', async (body: any) => {
79
198
  try {
80
199
  // Handle both GET and POST requests