homebridge-multiple-switch 1.7.0-beta.1 → 1.7.0-beta.10

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 CHANGED
@@ -1,5 +1,60 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.7.0-beta.10] - 2026-05-17
4
+
5
+ ### Fixed
6
+ - Auto-off timer leak: rapidly toggling a switch no longer accumulates stale timeouts — each new auto-off cancels the previous one
7
+ - Duplicate device name now logs a clear warning instead of silently causing UUID collision
8
+
9
+ ## [1.7.0-beta.9] - 2026-05-17
10
+
11
+ ### Changed
12
+ - Default State is now a 3-option dropdown: **Remember Last State** / **On** / **Off**
13
+ - Remember: keeps the last known state across restarts (new default)
14
+ - On: always starts ON on every Homebridge restart
15
+ - Off: always starts OFF on every Homebridge restart
16
+ - Backward compatible: old boolean `true`/`false` configs still work correctly
17
+
18
+ ## [1.7.0-beta.8] - 2026-05-17
19
+
20
+ ### Changed
21
+ - Default State now applies on every Homebridge restart, not just on first creation — switches always start in their configured default state
22
+
23
+ ## [1.7.0-beta.7] - 2026-05-17
24
+
25
+ ### Fixed
26
+ - `"type"` removed from switch schema `required` array (field no longer exists at switch level)
27
+ - New devices and switches no longer include stale `type` field on creation
28
+ - Removed unused `masterSwitchType` key from all 14 i18n locale files
29
+
30
+ ## [1.7.0-beta.6] - 2026-05-17
31
+
32
+ ### Changed
33
+ - Master Switch now uses the device-level switch type automatically — separate type selector removed
34
+
35
+ ### Removed
36
+ - Master Switch Type selector from UI and schema (`masterSwitchType` config field is no longer used)
37
+
38
+ ## [1.7.0-beta.5] - 2026-05-17
39
+
40
+ ### Changed
41
+ - Switch fields (Switch Name, Auto Turn Off, Default State) now use the same 3-equal-column grid as device fields
42
+
43
+ ## [1.7.0-beta.4] - 2026-05-17
44
+
45
+ ### Changed
46
+ - Auto Turn Off column narrowed to 120px so Default State checkbox has more breathing room
47
+
48
+ ## [1.7.0-beta.3] - 2026-05-17
49
+
50
+ ### Changed
51
+ - Switch card: Switch Name, Auto Turn Off and Default State are now on a single compact row
52
+
53
+ ## [1.7.0-beta.2] - 2026-05-17
54
+
55
+ ### Fixed
56
+ - Switch Type description now appears below the dropdown, consistent with Switch Behavior Mode
57
+
3
58
  ## [1.7.0-beta.1] - 2026-05-17
4
59
 
5
60
  ### Changed
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "masterSwitch": {
48
48
  "title": "Master Switch",
49
- "description": "Add a master switch that turns all switches on or off at once. Only available in Single mode.",
49
+ "description": "Add a master switch that turns all switches on or off at once. Uses the same type as the device.",
50
50
  "type": "boolean",
51
51
  "default": false
52
52
  },
@@ -64,9 +64,14 @@
64
64
  },
65
65
  "defaultState": {
66
66
  "title": "Default State",
67
- "description": "Initial power state when Homebridge starts.",
68
- "type": "boolean",
69
- "default": false
67
+ "description": "Switch state on every Homebridge restart.",
68
+ "type": "string",
69
+ "default": "remember",
70
+ "oneOf": [
71
+ { "title": "Remember Last State", "enum": ["remember"] },
72
+ { "title": "On", "enum": ["on"] },
73
+ { "title": "Off", "enum": ["off"] }
74
+ ]
70
75
  },
71
76
  "delayOff": {
72
77
  "title": "Auto Turn Off (ms)",
@@ -76,7 +81,7 @@
76
81
  "minimum": 0
77
82
  }
78
83
  },
79
- "required": ["name", "type"]
84
+ "required": ["name"]
80
85
  }
81
86
  }
82
87
  },
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "مفتاح",
16
16
  "typeOutlet": "مقبس",
17
17
  "defaultState": "الحالة الافتراضية",
18
- "defaultStateDesc": "حالة الطاقة الأولية عند بدء تشغيل Homebridge.",
18
+ "defaultStateDesc": "حالة المفتاح عند كل إعادة تشغيل لـ Homebridge.",
19
+ "remember": "تذكر آخر حالة",
19
20
  "delayOff": "إيقاف تلقائي (مللي ثانية)",
20
21
  "delayOffDesc": "يتم الإيقاف تلقائيًا بعد هذا العدد من المللي ثانية. اضبط على 0 للتعطيل.",
21
22
  "addSwitch": "إضافة مفتاح",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "يمكن تشغيل مفتاح واحد فقط في نفس الوقت. تشغيل واحد يقوم بإيقاف جميع الآخرين تلقائياً.",
34
35
  "masterSwitch": "المفتاح الرئيسي",
35
36
  "masterSwitchDesc": "يضيف مفتاحاً رئيسياً يقوم بتشغيل أو إيقاف جميع المفاتيح دفعة واحدة.",
36
- "switchSingular": "مفتاح",
37
- "masterSwitchType": "نوع المفتاح الرئيسي"
37
+ "switchSingular": "مفتاح"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Schalter",
16
16
  "typeOutlet": "Steckdose",
17
17
  "defaultState": "Standardzustand",
18
- "defaultStateDesc": "Anfänglicher Energiezustand beim Start von Homebridge.",
18
+ "defaultStateDesc": "Schaltzustand bei jedem Neustart von Homebridge.",
19
+ "remember": "Letzten Zustand merken",
19
20
  "delayOff": "Automatisch ausschalten (ms)",
20
21
  "delayOffDesc": "Schaltet nach dieser Anzahl von Millisekunden automatisch aus. Zum Deaktivieren auf 0 setzen.",
21
22
  "addSwitch": "Schalter hinzufügen",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Es kann nur ein Schalter gleichzeitig eingeschaltet sein. Das Einschalten eines Schalters schaltet alle anderen automatisch aus.",
34
35
  "masterSwitch": "Hauptschalter",
35
36
  "masterSwitchDesc": "Fügt einen Hauptschalter hinzu, der alle Schalter auf einmal ein- oder ausschaltet.",
36
- "switchSingular": "Schalter",
37
- "masterSwitchType": "Hauptschaltertyp"
37
+ "switchSingular": "Schalter"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Switch",
16
16
  "typeOutlet": "Outlet",
17
17
  "defaultState": "Default State",
18
- "defaultStateDesc": "Initial power state when Homebridge starts.",
18
+ "defaultStateDesc": "Switch state on every Homebridge restart.",
19
+ "remember": "Remember Last State",
19
20
  "delayOff": "Auto Turn Off (ms)",
20
21
  "delayOffDesc": "Automatically turn off after this many milliseconds. Set to 0 to disable.",
21
22
  "addSwitch": "Add Switch",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Only one switch can be on at a time. Turning one on automatically turns off all others.",
34
35
  "masterSwitch": "Master Switch",
35
36
  "masterSwitchDesc": "Adds a master switch that turns all switches on or off at once.",
36
- "switchSingular": "switch",
37
- "masterSwitchType": "Master Switch Type"
37
+ "switchSingular": "switch"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Interruptor",
16
16
  "typeOutlet": "Enchufe",
17
17
  "defaultState": "Estado predeterminado",
18
- "defaultStateDesc": "Estado de energía inicial cuando Homebridge se inicia.",
18
+ "defaultStateDesc": "Estado del interruptor en cada reinicio de Homebridge.",
19
+ "remember": "Recordar último estado",
19
20
  "delayOff": "Apagado automático (ms)",
20
21
  "delayOffDesc": "Se apaga automáticamente después de estos milisegundos. Establecer en 0 para desactivar.",
21
22
  "addSwitch": "Agregar interruptor",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Solo un interruptor puede estar encendido a la vez. Encender uno apaga automáticamente todos los demás.",
34
35
  "masterSwitch": "Interruptor maestro",
35
36
  "masterSwitchDesc": "Agrega un interruptor maestro que enciende o apaga todos los interruptores a la vez.",
36
- "switchSingular": "interruptor",
37
- "masterSwitchType": "Tipo de interruptor maestro"
37
+ "switchSingular": "interruptor"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Interrupteur",
16
16
  "typeOutlet": "Prise",
17
17
  "defaultState": "État par défaut",
18
- "defaultStateDesc": "État d'alimentation initial au démarrage de Homebridge.",
18
+ "defaultStateDesc": "État de l'interrupteur à chaque redémarrage de Homebridge.",
19
+ "remember": "Mémoriser le dernier état",
19
20
  "delayOff": "Arrêt automatique (ms)",
20
21
  "delayOffDesc": "S'éteint automatiquement après ce nombre de millisecondes. Mettre à 0 pour désactiver.",
21
22
  "addSwitch": "Ajouter un interrupteur",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Un seul interrupteur peut être activé à la fois. En activer un désactive automatiquement tous les autres.",
34
35
  "masterSwitch": "Interrupteur principal",
35
36
  "masterSwitchDesc": "Ajoute un interrupteur principal qui active ou désactive tous les interrupteurs en une seule fois.",
36
- "switchSingular": "interrupteur",
37
- "masterSwitchType": "Type d'interrupteur principal"
37
+ "switchSingular": "interrupteur"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Interruttore",
16
16
  "typeOutlet": "Presa",
17
17
  "defaultState": "Stato predefinito",
18
- "defaultStateDesc": "Stato di alimentazione iniziale all'avvio di Homebridge.",
18
+ "defaultStateDesc": "Stato dell'interruttore ad ogni riavvio di Homebridge.",
19
+ "remember": "Ricorda ultimo stato",
19
20
  "delayOff": "Spegnimento automatico (ms)",
20
21
  "delayOffDesc": "Si spegne automaticamente dopo questi millisecondi. Impostare a 0 per disattivare.",
21
22
  "addSwitch": "Aggiungi interruttore",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Solo un interruttore può essere acceso alla volta. Accenderne uno spegne automaticamente tutti gli altri.",
34
35
  "masterSwitch": "Interruttore principale",
35
36
  "masterSwitchDesc": "Aggiunge un interruttore principale che accende o spegne tutti gli interruttori contemporaneamente.",
36
- "switchSingular": "interruttore",
37
- "masterSwitchType": "Tipo di interruttore principale"
37
+ "switchSingular": "interruttore"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "スイッチ",
16
16
  "typeOutlet": "コンセント",
17
17
  "defaultState": "デフォルト状態",
18
- "defaultStateDesc": "Homebridge 起動時の初期電源状態。",
18
+ "defaultStateDesc": "Homebridge を再起動するたびのスイッチ状態。",
19
+ "remember": "最後の状態を記憶",
19
20
  "delayOff": "自動オフ(ミリ秒)",
20
21
  "delayOffDesc": "指定したミリ秒後に自動的にオフになります。無効にするには 0 に設定してください。",
21
22
  "addSwitch": "スイッチを追加",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "同時に1つのスイッチのみオンにできます。1つをオンにすると他はすべて自動的にオフになります。",
34
35
  "masterSwitch": "マスタースイッチ",
35
36
  "masterSwitchDesc": "すべてのスイッチを一度にオン/オフするマスタースイッチを追加します。",
36
- "switchSingular": "スイッチ",
37
- "masterSwitchType": "マスタースイッチタイプ"
37
+ "switchSingular": "スイッチ"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "스위치",
16
16
  "typeOutlet": "콘센트",
17
17
  "defaultState": "기본 상태",
18
- "defaultStateDesc": "Homebridge 시작 초기 전원 상태.",
18
+ "defaultStateDesc": "Homebridge 재시작할 때마다의 스위치 상태.",
19
+ "remember": "마지막 상태 기억",
19
20
  "delayOff": "자동 꺼짐 (ms)",
20
21
  "delayOffDesc": "지정된 밀리초 후 자동으로 꺼집니다. 비활성화하려면 0으로 설정하세요.",
21
22
  "addSwitch": "스위치 추가",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "한 번에 하나의 스위치만 켤 수 있습니다. 하나를 켜면 다른 모든 것이 자동으로 꺼집니다.",
34
35
  "masterSwitch": "마스터 스위치",
35
36
  "masterSwitchDesc": "모든 스위치를 한 번에 켜거나 끄는 마스터 스위치를 추가합니다.",
36
- "switchSingular": "스위치",
37
- "masterSwitchType": "마스터 스위치 유형"
37
+ "switchSingular": "스위치"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Schakelaar",
16
16
  "typeOutlet": "Stopcontact",
17
17
  "defaultState": "Standaardstatus",
18
- "defaultStateDesc": "Initiële voedingsstatus wanneer Homebridge opstart.",
18
+ "defaultStateDesc": "Schakelaarstatus bij elke herstart van Homebridge.",
19
+ "remember": "Laatste status onthouden",
19
20
  "delayOff": "Automatisch uitschakelen (ms)",
20
21
  "delayOffDesc": "Schakelt automatisch uit na dit aantal milliseconden. Stel in op 0 om uit te schakelen.",
21
22
  "addSwitch": "Schakelaar toevoegen",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Er kan slechts één schakelaar tegelijk aan staan. Het inschakelen van één schakelaar schakelt alle andere automatisch uit.",
34
35
  "masterSwitch": "Hoofdschakelaar",
35
36
  "masterSwitchDesc": "Voegt een hoofdschakelaar toe die alle schakelaars in één keer in- of uitschakelt.",
36
- "switchSingular": "schakelaar",
37
- "masterSwitchType": "Type hoofdschakelaar"
37
+ "switchSingular": "schakelaar"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Przełącznik",
16
16
  "typeOutlet": "Gniazdko",
17
17
  "defaultState": "Stan domyślny",
18
- "defaultStateDesc": "Początkowy stan zasilania przy uruchomieniu Homebridge.",
18
+ "defaultStateDesc": "Stan przełącznika przy każdym ponownym uruchomieniu Homebridge.",
19
+ "remember": "Zapamiętaj ostatni stan",
19
20
  "delayOff": "Automatyczne wyłączenie (ms)",
20
21
  "delayOffDesc": "Automatycznie wyłącza się po podanej liczbie milisekund. Ustaw 0, aby wyłączyć.",
21
22
  "addSwitch": "Dodaj przełącznik",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Tylko jeden przełącznik może być włączony jednocześnie. Włączenie jednego automatycznie wyłącza wszystkie pozostałe.",
34
35
  "masterSwitch": "Przełącznik główny",
35
36
  "masterSwitchDesc": "Dodaje przełącznik główny, który włącza lub wyłącza wszystkie przełączniki jednocześnie.",
36
- "switchSingular": "przełącznik",
37
- "masterSwitchType": "Typ przełącznika głównego"
37
+ "switchSingular": "przełącznik"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Interruptor",
16
16
  "typeOutlet": "Tomada",
17
17
  "defaultState": "Estado padrão",
18
- "defaultStateDesc": "Estado de energia inicial quando o Homebridge inicia.",
18
+ "defaultStateDesc": "Estado do interruptor em cada reinício do Homebridge.",
19
+ "remember": "Lembrar último estado",
19
20
  "delayOff": "Desligamento automático (ms)",
20
21
  "delayOffDesc": "Desliga automaticamente após estes milissegundos. Defina como 0 para desativar.",
21
22
  "addSwitch": "Adicionar interruptor",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Apenas um interruptor pode estar ligado por vez. Ligar um desliga automaticamente todos os outros.",
34
35
  "masterSwitch": "Interruptor principal",
35
36
  "masterSwitchDesc": "Adiciona um interruptor principal que liga ou desliga todos os interruptores de uma só vez.",
36
- "switchSingular": "interruptor",
37
- "masterSwitchType": "Tipo de interruptor principal"
37
+ "switchSingular": "interruptor"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Выключатель",
16
16
  "typeOutlet": "Розетка",
17
17
  "defaultState": "Состояние по умолчанию",
18
- "defaultStateDesc": "Начальное состояние питания при запуске Homebridge.",
18
+ "defaultStateDesc": "Состояние переключателя при каждом перезапуске Homebridge.",
19
+ "remember": "Запомнить последнее состояние",
19
20
  "delayOff": "Автоматическое выключение (мс)",
20
21
  "delayOffDesc": "Автоматически выключается через указанное количество миллисекунд. Установите 0 для отключения.",
21
22
  "addSwitch": "Добавить переключатель",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Одновременно может быть включён только один переключатель. Включение одного автоматически выключает все остальные.",
34
35
  "masterSwitch": "Главный переключатель",
35
36
  "masterSwitchDesc": "Добавляет главный переключатель, который включает или выключает все переключатели одновременно.",
36
- "switchSingular": "переключатель",
37
- "masterSwitchType": "Тип главного переключателя"
37
+ "switchSingular": "переключатель"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "Anahtar",
16
16
  "typeOutlet": "Priz",
17
17
  "defaultState": "Varsayılan Durum",
18
- "defaultStateDesc": "Homebridge başladığında başlangıç güç durumu.",
18
+ "defaultStateDesc": "Her Homebridge yeniden başlatmasında anahtarın durumu.",
19
+ "remember": "Son Durumu Hatırla",
19
20
  "delayOff": "Otomatik Kapanma (ms)",
20
21
  "delayOffDesc": "Belirtilen milisaniye sonra otomatik kapanır. Devre dışı bırakmak için 0 yazın.",
21
22
  "addSwitch": "Anahtar Ekle",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "Aynı anda yalnızca bir anahtar açık olabilir. Birini açmak diğerlerini otomatik kapatır.",
34
35
  "masterSwitch": "Ana Anahtar",
35
36
  "masterSwitchDesc": "Tüm anahtarları tek seferde açan veya kapatan bir ana anahtar ekler.",
36
- "switchSingular": "anahtar",
37
- "masterSwitchType": "Ana Anahtar Tipi"
37
+ "switchSingular": "anahtar"
38
38
  }
@@ -15,7 +15,8 @@
15
15
  "typeSwitch": "开关",
16
16
  "typeOutlet": "插座",
17
17
  "defaultState": "默认状态",
18
- "defaultStateDesc": "Homebridge 启动时的初始电源状态。",
18
+ "defaultStateDesc": "每次 Homebridge 重启时的开关状态。",
19
+ "remember": "记住上次状态",
19
20
  "delayOff": "自动关闭(毫秒)",
20
21
  "delayOffDesc": "在指定的毫秒数后自动关闭。设置为 0 以禁用。",
21
22
  "addSwitch": "添加开关",
@@ -33,6 +34,5 @@
33
34
  "behaviorSingleDesc": "同一时间只能有一个开关处于打开状态。打开一个会自动关闭所有其他开关。",
34
35
  "masterSwitch": "主开关",
35
36
  "masterSwitchDesc": "添加一个主开关,可以一次性打开或关闭所有开关。",
36
- "switchSingular": "开关",
37
- "masterSwitchType": "主开关类型"
37
+ "switchSingular": "开关"
38
38
  }
@@ -233,7 +233,8 @@
233
233
  config.devices.push({
234
234
  name: '',
235
235
  switchBehavior: 'independent',
236
- switches: [{ name: '', type: 'outlet', defaultState: false, delayOff: 0 }],
236
+ switchType: 'outlet',
237
+ switches: [{ name: '', defaultState: 'remember', delayOff: 0 }],
237
238
  });
238
239
  expandedDevices.add(di);
239
240
  expandedSwitches.add(`${di}_0`);
@@ -289,22 +290,11 @@
289
290
  input.addEventListener('change', () => {
290
291
  const di = parseInt(input.dataset.dev);
291
292
  config.devices[di].masterSwitch = input.checked;
292
- if (!input.checked) {
293
- delete config.devices[di].masterSwitchType;
294
- }
295
293
  render();
296
294
  save();
297
295
  });
298
296
  });
299
297
 
300
- // Master switch type
301
- document.querySelectorAll('.master-type-field').forEach(input => {
302
- input.addEventListener('change', () => {
303
- const di = parseInt(input.dataset.dev);
304
- config.devices[di].masterSwitchType = input.value;
305
- save();
306
- });
307
- });
308
298
 
309
299
  document.querySelectorAll('.btn-remove-device').forEach(btn => {
310
300
  btn.addEventListener('click', (e) => {
@@ -322,7 +312,7 @@
322
312
  btn.addEventListener('click', () => {
323
313
  const di = parseInt(btn.dataset.dev);
324
314
  const si = config.devices[di].switches.length;
325
- config.devices[di].switches.push({ name: '', type: 'outlet', defaultState: false, delayOff: 0 });
315
+ config.devices[di].switches.push({ name: '', defaultState: 'remember', delayOff: 0 });
326
316
  expandedSwitches.add(`${di}_${si}`);
327
317
  render();
328
318
  save();
@@ -347,7 +337,7 @@
347
337
  const si = parseInt(input.dataset.sw);
348
338
  const field = input.dataset.field;
349
339
  if (field === 'defaultState') {
350
- config.devices[di].switches[si][field] = input.checked;
340
+ config.devices[di].switches[si][field] = input.value;
351
341
  } else if (field === 'delayOff') {
352
342
  config.devices[di].switches[si][field] = parseInt(input.value) || 0;
353
343
  } else {
@@ -414,30 +404,22 @@
414
404
  </div>
415
405
  <div class="form-group">
416
406
  <label>${t.switchType || 'Switch Type'}</label>
417
- <div class="desc">${t.switchTypeDesc || ''}</div>
418
407
  <select class="dev-field" data-dev="${di}" data-field="switchType">
419
408
  <option value="outlet" ${!dev.switchType || dev.switchType === 'outlet' ? 'selected' : ''}>${t.typeOutlet || 'Outlet'}</option>
420
409
  <option value="switch" ${dev.switchType === 'switch' ? 'selected' : ''}>${t.typeSwitch || 'Switch'}</option>
421
410
  </select>
411
+ <div class="desc" style="margin-top:6px">${t.switchTypeDesc || ''}</div>
422
412
  </div>
423
413
  </div>
424
414
 
425
415
  ${isIndependent ? `
426
416
  <div class="master-option">
427
- <div style="display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap">
428
- <div class="toggle-wrap" style="flex:1;min-width:0">
429
- <input type="checkbox" class="master-toggle" data-dev="${di}" ${dev.masterSwitch ? 'checked' : ''}>
430
- <div>
431
- <label style="margin-bottom:0">${t.masterSwitch || 'Master Switch'}</label>
432
- <div class="desc" style="margin-bottom:0">${t.masterSwitchDesc || ''}</div>
433
- </div>
417
+ <div class="toggle-wrap">
418
+ <input type="checkbox" class="master-toggle" data-dev="${di}" ${dev.masterSwitch ? 'checked' : ''}>
419
+ <div>
420
+ <label style="margin-bottom:0">${t.masterSwitch || 'Master Switch'}</label>
421
+ <div class="desc" style="margin-bottom:0">${t.masterSwitchDesc || ''}</div>
434
422
  </div>
435
- ${dev.masterSwitch ? `
436
- <select class="master-type-field" data-dev="${di}" style="width:auto;min-width:120px;flex-shrink:0">
437
- <option value="switch" ${dev.masterSwitchType === 'switch' || !dev.masterSwitchType ? 'selected' : ''}>${t.typeSwitch || 'Switch'}</option>
438
- <option value="outlet" ${dev.masterSwitchType === 'outlet' ? 'selected' : ''}>${t.typeOutlet || 'Outlet'}</option>
439
- </select>
440
- ` : ''}
441
423
  </div>
442
424
  </div>
443
425
  ` : ''}
@@ -456,6 +438,8 @@
456
438
  const isOpen = expandedSwitches.has(`${di}_${si}`);
457
439
  const swLabel = sw.name || `#${si + 1}`;
458
440
  const typeLabel = deviceSwitchType === 'switch' ? (t.typeSwitch || 'Switch') : (t.typeOutlet || 'Outlet');
441
+ const ds = sw.defaultState;
442
+ const dsValue = (ds === true || ds === 'on') ? 'on' : (ds === false || ds === 'off') ? 'off' : 'remember';
459
443
 
460
444
  return `
461
445
  <div class="switch-card">
@@ -470,21 +454,22 @@
470
454
  </div>
471
455
  </div>
472
456
  <div class="switch-body ${isOpen ? '' : 'collapsed'}">
473
- <div class="inline-row">
474
- <div class="form-group">
457
+ <div class="inline-row" style="grid-template-columns: 1fr 1fr 1fr; align-items: end;">
458
+ <div class="form-group" style="margin-bottom:0">
475
459
  <label>${t.switchName || 'Switch Name'}</label>
476
460
  <input type="text" class="sw-field" data-dev="${di}" data-sw="${si}" data-field="name" value="${esc(sw.name || '')}">
477
461
  </div>
478
- <div class="form-group">
462
+ <div class="form-group" style="margin-bottom:0">
479
463
  <label>${t.delayOff || 'Auto Turn Off (ms)'}</label>
480
464
  <input type="number" class="sw-field" data-dev="${di}" data-sw="${si}" data-field="delayOff" min="0" value="${sw.delayOff || 0}">
481
465
  </div>
482
- </div>
483
- <div class="form-group">
484
- <label>${t.defaultState || 'Default State'}</label>
485
- <div class="toggle-wrap" style="margin-top:6px">
486
- <input type="checkbox" class="sw-field" data-dev="${di}" data-sw="${si}" data-field="defaultState" ${sw.defaultState ? 'checked' : ''}>
487
- <span>${sw.defaultState ? (t.on || 'On') : (t.off || 'Off')}</span>
466
+ <div class="form-group" style="margin-bottom:0">
467
+ <label>${t.defaultState || 'Default State'}</label>
468
+ <select class="sw-field" data-dev="${di}" data-sw="${si}" data-field="defaultState">
469
+ <option value="remember" ${dsValue === 'remember' ? 'selected' : ''}>${t.remember || 'Remember'}</option>
470
+ <option value="on" ${dsValue === 'on' ? 'selected' : ''}>${t.on || 'On'}</option>
471
+ <option value="off" ${dsValue === 'off' ? 'selected' : ''}>${t.off || 'Off'}</option>
472
+ </select>
488
473
  </div>
489
474
  </div>
490
475
  </div>
package/index.js CHANGED
@@ -23,6 +23,7 @@ class MultipleSwitchPlatform {
23
23
  this.Characteristic = api.hap.Characteristic;
24
24
  this.cachedAccessories = new Map();
25
25
  this.deviceServices = new Map();
26
+ this.autoOffTimers = new Map();
26
27
 
27
28
  this.api.on('didFinishLaunching', () => {
28
29
  this.log.info('MultipleSwitchPlatform started.');
@@ -78,6 +79,10 @@ class MultipleSwitchPlatform {
78
79
  const hasMaster = behavior === 'independent' && device.masterSwitch === true;
79
80
  const uuid = this.api.hap.uuid.generate(name);
80
81
 
82
+ if (this.deviceServices.has(uuid)) {
83
+ this.log.warn(`Duplicate device name "${name}" detected. Each device must have a unique name.`);
84
+ }
85
+
81
86
  let accessory = this.cachedAccessories.get(uuid);
82
87
  const isNew = !accessory;
83
88
 
@@ -119,7 +124,7 @@ class MultipleSwitchPlatform {
119
124
 
120
125
  // Create master switch if enabled
121
126
  if (hasMaster) {
122
- const MasterServiceClass = this.getServiceClass(device.masterSwitchType || 'switch');
127
+ const MasterServiceClass = this.getServiceClass(device.switchType || 'outlet');
123
128
  const masterService = accessory.addService(MasterServiceClass, 'Master', MASTER_SUBTYPE);
124
129
 
125
130
  this.setServiceName(masterService, 'Master');
@@ -145,8 +150,16 @@ class MultipleSwitchPlatform {
145
150
 
146
151
  services.set(subtype, service);
147
152
 
148
- if (accessory.context.switchStates[subtype] === undefined) {
149
- accessory.context.switchStates[subtype] = sw.defaultState || false;
153
+ const ds = sw.defaultState;
154
+ if (ds === false || ds === 'off') {
155
+ accessory.context.switchStates[subtype] = false;
156
+ } else if (ds === true || ds === 'on') {
157
+ accessory.context.switchStates[subtype] = true;
158
+ } else {
159
+ // 'remember' or undefined — keep existing state; initialise to false on first run
160
+ if (accessory.context.switchStates[subtype] === undefined) {
161
+ accessory.context.switchStates[subtype] = false;
162
+ }
150
163
  }
151
164
  });
152
165
 
@@ -204,13 +217,19 @@ class MultipleSwitchPlatform {
204
217
  }
205
218
 
206
219
  scheduleAutoOff(accessory, service, sw, subtype) {
207
- setTimeout(() => {
220
+ const timerKey = `${accessory.UUID}_${subtype}`;
221
+ if (this.autoOffTimers.has(timerKey)) {
222
+ clearTimeout(this.autoOffTimers.get(timerKey));
223
+ }
224
+ const timer = setTimeout(() => {
225
+ this.autoOffTimers.delete(timerKey);
208
226
  if (accessory.context.switchStates[subtype]) {
209
227
  accessory.context.switchStates[subtype] = false;
210
228
  service.updateCharacteristic(this.Characteristic.On, false);
211
229
  this.log.info(`[${sw.name}] auto-off after ${sw.delayOff}ms`);
212
230
  }
213
231
  }, sw.delayOff);
232
+ this.autoOffTimers.set(timerKey, timer);
214
233
  }
215
234
 
216
235
  getServiceClass(type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-multiple-switch",
3
- "version": "1.7.0-beta.1",
3
+ "version": "1.7.0-beta.10",
4
4
  "description": "Multiple switch platform for Homebridge",
5
5
  "homepage": "https://github.com/azadaydinli/homebridge-multiple-switch",
6
6
  "main": "index.js",