homebridge-multiple-switch 1.6.0 → 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,70 @@
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
+
58
+ ## [1.7.0-beta.1] - 2026-05-17
59
+
60
+ ### Changed
61
+ - Switch type (Switch / Outlet) is now configured per device instead of per individual switch
62
+ - All switches within a device share the same type, set once in the device settings
63
+ - Switch cards no longer show a type selector — type is shown in the collapsed summary from the device level
64
+
65
+ ### Fixed
66
+ - Automatic migration: existing configs with per-switch `type` are migrated to device-level `switchType` on first UI save (first switch's type is used as the device type)
67
+
3
68
  ## [1.6.0] - 2026-03-22
4
69
 
5
70
  ### Added
package/README.md CHANGED
@@ -1,25 +1,34 @@
1
- # homebridge-multiple-switch
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/azadaydinli/homebridge-multiple-switch/master/banner.png" width="600">
3
+ </p>
2
4
 
3
- ![CI](https://github.com/azadaydinli/homebridge-multiple-switch/actions/workflows/ci.yml/badge.svg)
5
+ <span align="center">
6
+
7
+ # Homebridge Multiple Switch
8
+
9
+ A lightweight Homebridge plugin that lets you create multiple customizable dummy switches in HomeKit. Supports multi-device, master switch, and 14 languages.
10
+
11
+ [![verified-by-homebridge](https://img.shields.io/badge/homebridge-verified-blueviolet?color=%23491F59&style=flat)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins)
4
12
  [![npm](https://img.shields.io/npm/v/homebridge-multiple-switch)](https://www.npmjs.com/package/homebridge-multiple-switch)
5
- [![GitHub issues](https://img.shields.io/github/issues/azadaydinli/homebridge-multiple-switch)](https://github.com/azadaydinli/homebridge-multiple-switch/issues)
13
+ [![npm](https://img.shields.io/npm/dt/homebridge-multiple-switch)](https://www.npmjs.com/package/homebridge-multiple-switch)
6
14
  [![GitHub license](https://img.shields.io/github/license/azadaydinli/homebridge-multiple-switch)](https://github.com/azadaydinli/homebridge-multiple-switch/blob/master/LICENSE)
7
15
 
8
- A lightweight Homebridge plugin that lets you create multiple customizable dummy switches under a single accessory — configurable as `Switch`, `Outlet`, `Lightbulb`, or `Fan`.
9
- Supports `Independent`, `Master`, and `Single` switch modes.
16
+ </span>
10
17
 
11
18
  ---
12
19
 
13
20
  ## Features
14
21
 
15
- - Grouped multiple switches in one HomeKit tile
16
- - Accessory type: `switch`, `outlet`, `lightbulb`, or `fan`
22
+ - **Multi-device support** create multiple separate HomeKit accessories
23
+ - Accessory type: `switch` or `outlet`
17
24
  - **Independent Mode** – All switches operate separately
18
- - **Master Mode** – One switch controls all others
19
25
  - **Single Mode** – Only one switch can be active at a time
26
+ - **Master Switch** (Independent mode) — one switch controls all others
20
27
  - Per-switch config support (type, auto-off delay, default state)
21
- - Switch states preserved across Homebridge restarts via cached accessories
22
- - Automatic cleanup of stale accessories on config change
28
+ - Collapsible config UI with dark mode support
29
+ - i18n localization (14 languages)
30
+ - Homebridge v2 compatible
31
+ - Switch states preserved across restarts via cached accessories
23
32
  - Compatible with HomeKit and Siri
24
33
 
25
34
  ---
@@ -47,23 +56,40 @@ Configure from Homebridge UI or manually edit `config.json`:
47
56
  ```json
48
57
  {
49
58
  "platform": "MultipleSwitchPlatform",
50
- "name": "Multiple Switches",
51
- "switchBehavior": "single",
52
- "switches": [
59
+ "name": "Multiple Switch Platform",
60
+ "devices": [
53
61
  {
54
- "name": "Heater",
55
- "type": "outlet",
56
- "defaultState": true,
57
- "delayOff": 10000
62
+ "name": "Living Room",
63
+ "switchBehavior": "independent",
64
+ "masterSwitch": true,
65
+ "masterSwitchType": "switch",
66
+ "switches": [
67
+ {
68
+ "name": "Lamp",
69
+ "type": "outlet",
70
+ "defaultState": false,
71
+ "delayOff": 0
72
+ },
73
+ {
74
+ "name": "Heater",
75
+ "type": "switch",
76
+ "delayOff": 10000
77
+ }
78
+ ]
58
79
  },
59
80
  {
60
- "name": "Fan",
61
- "type": "fan"
62
- },
63
- {
64
- "name": "Light",
65
- "type": "lightbulb",
66
- "delayOff": 5000
81
+ "name": "Bedroom",
82
+ "switchBehavior": "single",
83
+ "switches": [
84
+ {
85
+ "name": "Scene 1",
86
+ "type": "switch"
87
+ },
88
+ {
89
+ "name": "Scene 2",
90
+ "type": "switch"
91
+ }
92
+ ]
67
93
  }
68
94
  ]
69
95
  }
@@ -73,19 +99,28 @@ Configure from Homebridge UI or manually edit `config.json`:
73
99
 
74
100
  ### Platform Options
75
101
 
76
- | Field | Type | Required | Description |
77
- |------------------|--------|----------|--------------------------------------|
78
- | `name` | string | Yes | Name of the platform instance |
79
- | `switchBehavior` | string | No | `independent`, `master`, or `single` |
80
- | `switches` | array | Yes | List of switches to create |
102
+ | Field | Type | Required | Description |
103
+ |-----------|--------|----------|-------------------------------|
104
+ | `name` | string | Yes | Name of the platform instance |
105
+ | `devices` | array | Yes | List of devices to create |
106
+
107
+ ### Device Options
108
+
109
+ | Field | Type | Required | Description |
110
+ |--------------------|---------|----------|-------------------------------------------------|
111
+ | `name` | string | Yes | Device name (becomes HomeKit accessory name) |
112
+ | `switchBehavior` | string | No | `independent` or `single` (default: independent) |
113
+ | `masterSwitch` | boolean | No | Enable master switch (Independent mode only) |
114
+ | `masterSwitchType` | string | No | `switch` or `outlet` (default: switch) |
115
+ | `switches` | array | Yes | List of switches for this device |
81
116
 
82
117
  ### Per-Switch Options
83
118
 
84
- | Field | Type | Required | Description |
85
- |----------------|---------|----------|--------------------------------------------------|
86
- | `name` | string | Yes | Name of the switch |
87
- | `type` | string | No | `switch`, `outlet`, `lightbulb`, or `fan` |
88
- | `defaultState` | boolean | No | Initial power state (default: `false`) |
119
+ | Field | Type | Required | Description |
120
+ |----------------|---------|----------|---------------------------------------------------|
121
+ | `name` | string | Yes | Name of the switch |
122
+ | `type` | string | No | `switch` or `outlet` (default: outlet) |
123
+ | `defaultState` | boolean | No | Initial power state (default: `false`) |
89
124
  | `delayOff` | number | No | Auto turn off after N milliseconds (default: `0`) |
90
125
 
91
126
  ---
@@ -95,7 +130,7 @@ Configure from Homebridge UI or manually edit `config.json`:
95
130
  - Simulate smart plugs for automation testing
96
131
  - Trigger HomeKit scenes manually
97
132
  - Create virtual switches for non-HomeKit devices
98
- - Combine several virtual accessories under one tile
133
+ - Group several virtual accessories under one device
99
134
 
100
135
  ---
101
136
 
package/banner.png ADDED
Binary file
@@ -34,9 +34,19 @@
34
34
  { "title": "Single", "enum": ["single"] }
35
35
  ]
36
36
  },
37
+ "switchType": {
38
+ "title": "Switch Type",
39
+ "description": "The HomeKit accessory type for all switches in this device.",
40
+ "type": "string",
41
+ "default": "outlet",
42
+ "oneOf": [
43
+ { "title": "Switch", "enum": ["switch"] },
44
+ { "title": "Outlet", "enum": ["outlet"] }
45
+ ]
46
+ },
37
47
  "masterSwitch": {
38
48
  "title": "Master Switch",
39
- "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.",
40
50
  "type": "boolean",
41
51
  "default": false
42
52
  },
@@ -52,22 +62,17 @@
52
62
  "description": "Display name of the switch in HomeKit.",
53
63
  "type": "string"
54
64
  },
55
- "type": {
56
- "title": "Switch Type",
57
- "description": "The HomeKit accessory type for this switch.",
65
+ "defaultState": {
66
+ "title": "Default State",
67
+ "description": "Switch state on every Homebridge restart.",
58
68
  "type": "string",
59
- "default": "outlet",
69
+ "default": "remember",
60
70
  "oneOf": [
61
- { "title": "Switch", "enum": ["switch"] },
62
- { "title": "Outlet", "enum": ["outlet"] }
71
+ { "title": "Remember Last State", "enum": ["remember"] },
72
+ { "title": "On", "enum": ["on"] },
73
+ { "title": "Off", "enum": ["off"] }
63
74
  ]
64
75
  },
65
- "defaultState": {
66
- "title": "Default State",
67
- "description": "Initial power state when Homebridge starts.",
68
- "type": "boolean",
69
- "default": false
70
- },
71
76
  "delayOff": {
72
77
  "title": "Auto Turn Off (ms)",
73
78
  "description": "Automatically turn off after this many milliseconds. Set to 0 to disable.",
@@ -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
  },
@@ -11,11 +11,12 @@
11
11
  "switchName": "اسم المفتاح",
12
12
  "switchNameDesc": "اسم العرض للمفتاح في HomeKit.",
13
13
  "switchType": "نوع المفتاح",
14
- "switchTypeDesc": "نوع ملحق HomeKit لهذا المفتاح.",
14
+ "switchTypeDesc": "نوع ملحق HomeKit لجميع المفاتيح في هذا الجهاز.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Schaltername",
12
12
  "switchNameDesc": "Anzeigename des Schalters in HomeKit.",
13
13
  "switchType": "Schaltertyp",
14
- "switchTypeDesc": "Der HomeKit-Zubehörtyp für diesen Schalter.",
14
+ "switchTypeDesc": "Der HomeKit-Zubehörtyp für alle Schalter in diesem Gerät.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Switch Name",
12
12
  "switchNameDesc": "Display name of the switch in HomeKit.",
13
13
  "switchType": "Switch Type",
14
- "switchTypeDesc": "The HomeKit accessory type for this switch.",
14
+ "switchTypeDesc": "The HomeKit accessory type for all switches in this device.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Nombre del interruptor",
12
12
  "switchNameDesc": "Nombre visible del interruptor en HomeKit.",
13
13
  "switchType": "Tipo de interruptor",
14
- "switchTypeDesc": "El tipo de accesorio HomeKit para este interruptor.",
14
+ "switchTypeDesc": "El tipo de accesorio HomeKit para todos los interruptores de este dispositivo.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Nom de l'interrupteur",
12
12
  "switchNameDesc": "Nom affiché de l'interrupteur dans HomeKit.",
13
13
  "switchType": "Type d'interrupteur",
14
- "switchTypeDesc": "Le type d'accessoire HomeKit pour cet interrupteur.",
14
+ "switchTypeDesc": "Le type d'accessoire HomeKit pour tous les interrupteurs de cet appareil.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Nome dell'interruttore",
12
12
  "switchNameDesc": "Nome visualizzato dell'interruttore in HomeKit.",
13
13
  "switchType": "Tipo di interruttore",
14
- "switchTypeDesc": "Il tipo di accessorio HomeKit per questo interruttore.",
14
+ "switchTypeDesc": "Il tipo di accessorio HomeKit per tutti gli interruttori in questo dispositivo.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "スイッチ名",
12
12
  "switchNameDesc": "HomeKit でのスイッチの表示名。",
13
13
  "switchType": "スイッチタイプ",
14
- "switchTypeDesc": "このスイッチの HomeKit アクセサリタイプ。",
14
+ "switchTypeDesc": "このデバイス内のすべてのスイッチの HomeKit アクセサリタイプ。",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "스위치 이름",
12
12
  "switchNameDesc": "HomeKit에서 스위치의 표시 이름.",
13
13
  "switchType": "스위치 유형",
14
- "switchTypeDesc": "이 스위치의 HomeKit 액세서리 유형.",
14
+ "switchTypeDesc": "이 장치의 모든 스위치에 적용되는 HomeKit 액세서리 유형.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Schakelaarnaam",
12
12
  "switchNameDesc": "Weergavenaam van de schakelaar in HomeKit.",
13
13
  "switchType": "Schakelaartype",
14
- "switchTypeDesc": "Het HomeKit-accessoiretype voor deze schakelaar.",
14
+ "switchTypeDesc": "Het HomeKit-accessoiretype voor alle schakelaars in dit apparaat.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Nazwa przełącznika",
12
12
  "switchNameDesc": "Wyświetlana nazwa przełącznika w HomeKit.",
13
13
  "switchType": "Typ przełącznika",
14
- "switchTypeDesc": "Typ akcesorium HomeKit dla tego przełącznika.",
14
+ "switchTypeDesc": "Typ akcesorium HomeKit dla wszystkich przełączników w tym urządzeniu.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Nome do interruptor",
12
12
  "switchNameDesc": "Nome de exibição do interruptor no HomeKit.",
13
13
  "switchType": "Tipo de interruptor",
14
- "switchTypeDesc": "O tipo de acessório HomeKit para este interruptor.",
14
+ "switchTypeDesc": "O tipo de acessório HomeKit para todos os interruptores deste dispositivo.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Название переключателя",
12
12
  "switchNameDesc": "Отображаемое имя переключателя в HomeKit.",
13
13
  "switchType": "Тип переключателя",
14
- "switchTypeDesc": "Тип аксессуара HomeKit для этого переключателя.",
14
+ "switchTypeDesc": "Тип аксессуара HomeKit для всех переключателей в этом устройстве.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "Anahtar Adı",
12
12
  "switchNameDesc": "Anahtarın HomeKit'teki görünen adı.",
13
13
  "switchType": "Anahtar Tipi",
14
- "switchTypeDesc": "Bu anahtar için HomeKit aksesuar tipi.",
14
+ "switchTypeDesc": "Bu cihazdaki tüm anahtarlar için HomeKit aksesuar tipi.",
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
  }
@@ -11,11 +11,12 @@
11
11
  "switchName": "开关名称",
12
12
  "switchNameDesc": "开关在 HomeKit 中的显示名称。",
13
13
  "switchType": "开关类型",
14
- "switchTypeDesc": "此开关的 HomeKit 配件类型。",
14
+ "switchTypeDesc": "此设备中所有开关的 HomeKit 配件类型。",
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
  }
@@ -181,6 +181,18 @@
181
181
  delete config.switchBehavior;
182
182
  }
183
183
 
184
+ // Migrate per-switch type to device-level switchType
185
+ if (Array.isArray(config.devices)) {
186
+ config.devices.forEach(dev => {
187
+ if (!dev.switchType && Array.isArray(dev.switches) && dev.switches.length > 0) {
188
+ dev.switchType = dev.switches[0].type || 'outlet';
189
+ }
190
+ if (Array.isArray(dev.switches)) {
191
+ dev.switches.forEach(sw => { delete sw.type; });
192
+ }
193
+ });
194
+ }
195
+
184
196
  if (!config.devices) {
185
197
  config.devices = [];
186
198
  }
@@ -221,7 +233,8 @@
221
233
  config.devices.push({
222
234
  name: '',
223
235
  switchBehavior: 'independent',
224
- switches: [{ name: '', type: 'outlet', defaultState: false, delayOff: 0 }],
236
+ switchType: 'outlet',
237
+ switches: [{ name: '', defaultState: 'remember', delayOff: 0 }],
225
238
  });
226
239
  expandedDevices.add(di);
227
240
  expandedSwitches.add(`${di}_0`);
@@ -277,22 +290,11 @@
277
290
  input.addEventListener('change', () => {
278
291
  const di = parseInt(input.dataset.dev);
279
292
  config.devices[di].masterSwitch = input.checked;
280
- if (!input.checked) {
281
- delete config.devices[di].masterSwitchType;
282
- }
283
293
  render();
284
294
  save();
285
295
  });
286
296
  });
287
297
 
288
- // Master switch type
289
- document.querySelectorAll('.master-type-field').forEach(input => {
290
- input.addEventListener('change', () => {
291
- const di = parseInt(input.dataset.dev);
292
- config.devices[di].masterSwitchType = input.value;
293
- save();
294
- });
295
- });
296
298
 
297
299
  document.querySelectorAll('.btn-remove-device').forEach(btn => {
298
300
  btn.addEventListener('click', (e) => {
@@ -310,7 +312,7 @@
310
312
  btn.addEventListener('click', () => {
311
313
  const di = parseInt(btn.dataset.dev);
312
314
  const si = config.devices[di].switches.length;
313
- config.devices[di].switches.push({ name: '', type: 'outlet', defaultState: false, delayOff: 0 });
315
+ config.devices[di].switches.push({ name: '', defaultState: 'remember', delayOff: 0 });
314
316
  expandedSwitches.add(`${di}_${si}`);
315
317
  render();
316
318
  save();
@@ -335,7 +337,7 @@
335
337
  const si = parseInt(input.dataset.sw);
336
338
  const field = input.dataset.field;
337
339
  if (field === 'defaultState') {
338
- config.devices[di].switches[si][field] = input.checked;
340
+ config.devices[di].switches[si][field] = input.value;
339
341
  } else if (field === 'delayOff') {
340
342
  config.devices[di].switches[si][field] = parseInt(input.value) || 0;
341
343
  } else {
@@ -387,7 +389,7 @@
387
389
  </div>
388
390
 
389
391
  <div class="device-body ${isOpen ? '' : 'collapsed'}">
390
- <div class="inline-row">
392
+ <div class="inline-row" style="grid-template-columns: 1fr 1fr 1fr">
391
393
  <div class="form-group">
392
394
  <label>${t.deviceName || 'Device Name'}</label>
393
395
  <input type="text" class="dev-field" data-dev="${di}" data-field="name" value="${esc(dev.name || '')}">
@@ -400,31 +402,31 @@
400
402
  </select>
401
403
  <div class="desc" style="margin-top:6px">${behaviorDesc}</div>
402
404
  </div>
405
+ <div class="form-group">
406
+ <label>${t.switchType || 'Switch Type'}</label>
407
+ <select class="dev-field" data-dev="${di}" data-field="switchType">
408
+ <option value="outlet" ${!dev.switchType || dev.switchType === 'outlet' ? 'selected' : ''}>${t.typeOutlet || 'Outlet'}</option>
409
+ <option value="switch" ${dev.switchType === 'switch' ? 'selected' : ''}>${t.typeSwitch || 'Switch'}</option>
410
+ </select>
411
+ <div class="desc" style="margin-top:6px">${t.switchTypeDesc || ''}</div>
412
+ </div>
403
413
  </div>
404
414
 
405
415
  ${isIndependent ? `
406
416
  <div class="master-option">
407
- <div style="display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap">
408
- <div class="toggle-wrap" style="flex:1;min-width:0">
409
- <input type="checkbox" class="master-toggle" data-dev="${di}" ${dev.masterSwitch ? 'checked' : ''}>
410
- <div>
411
- <label style="margin-bottom:0">${t.masterSwitch || 'Master Switch'}</label>
412
- <div class="desc" style="margin-bottom:0">${t.masterSwitchDesc || ''}</div>
413
- </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>
414
422
  </div>
415
- ${dev.masterSwitch ? `
416
- <select class="master-type-field" data-dev="${di}" style="width:auto;min-width:120px;flex-shrink:0">
417
- <option value="switch" ${dev.masterSwitchType === 'switch' || !dev.masterSwitchType ? 'selected' : ''}>${t.typeSwitch || 'Switch'}</option>
418
- <option value="outlet" ${dev.masterSwitchType === 'outlet' ? 'selected' : ''}>${t.typeOutlet || 'Outlet'}</option>
419
- </select>
420
- ` : ''}
421
423
  </div>
422
424
  </div>
423
425
  ` : ''}
424
426
 
425
427
  <div class="section-title" style="margin-top:16px">${t.switches || 'Switches'}</div>
426
428
 
427
- ${switches.map((sw, si) => renderSwitch(sw, di, si)).join('')}
429
+ ${switches.map((sw, si) => renderSwitch(sw, di, si, dev.switchType || 'outlet')).join('')}
428
430
 
429
431
  <button class="btn btn-primary btn-add-switch" data-dev="${di}">+ ${t.addSwitch || 'Add Switch'}</button>
430
432
  </div>
@@ -432,9 +434,12 @@
432
434
  `;
433
435
  }
434
436
 
435
- function renderSwitch(sw, di, si) {
437
+ function renderSwitch(sw, di, si, deviceSwitchType) {
436
438
  const isOpen = expandedSwitches.has(`${di}_${si}`);
437
439
  const swLabel = sw.name || `#${si + 1}`;
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';
438
443
 
439
444
  return `
440
445
  <div class="switch-card">
@@ -442,37 +447,29 @@
442
447
  <div class="switch-header-left">
443
448
  <span class="chevron ${isOpen ? 'open' : ''}">&#9654;</span>
444
449
  <strong>${esc(swLabel)}</strong>
445
- ${!isOpen ? `<span class="switch-summary">${sw.type || 'outlet'}${sw.delayOff ? ` / ${sw.delayOff}ms` : ''}</span>` : ''}
450
+ ${!isOpen ? `<span class="switch-summary">${typeLabel}${sw.delayOff ? ` / ${sw.delayOff}ms` : ''}</span>` : ''}
446
451
  </div>
447
452
  <div class="switch-header-right">
448
453
  <button class="btn btn-danger btn-sm btn-remove-switch" data-dev="${di}" data-sw="${si}">${t.removeSwitch || 'Remove'}</button>
449
454
  </div>
450
455
  </div>
451
456
  <div class="switch-body ${isOpen ? '' : 'collapsed'}">
452
- <div class="inline-row">
453
- <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">
454
459
  <label>${t.switchName || 'Switch Name'}</label>
455
460
  <input type="text" class="sw-field" data-dev="${di}" data-sw="${si}" data-field="name" value="${esc(sw.name || '')}">
456
461
  </div>
457
- <div class="form-group">
458
- <label>${t.switchType || 'Switch Type'}</label>
459
- <select class="sw-field" data-dev="${di}" data-sw="${si}" data-field="type">
460
- <option value="switch" ${sw.type === 'switch' ? 'selected' : ''}>${t.typeSwitch || 'Switch'}</option>
461
- <option value="outlet" ${sw.type === 'outlet' || !sw.type ? 'selected' : ''}>${t.typeOutlet || 'Outlet'}</option>
462
- </select>
463
- </div>
464
- </div>
465
- <div class="inline-row">
466
- <div class="form-group">
462
+ <div class="form-group" style="margin-bottom:0">
467
463
  <label>${t.delayOff || 'Auto Turn Off (ms)'}</label>
468
464
  <input type="number" class="sw-field" data-dev="${di}" data-sw="${si}" data-field="delayOff" min="0" value="${sw.delayOff || 0}">
469
465
  </div>
470
- <div class="form-group">
466
+ <div class="form-group" style="margin-bottom:0">
471
467
  <label>${t.defaultState || 'Default State'}</label>
472
- <div class="toggle-wrap" style="margin-top:6px">
473
- <input type="checkbox" class="sw-field" data-dev="${di}" data-sw="${si}" data-field="defaultState" ${sw.defaultState ? 'checked' : ''}>
474
- <span>${sw.defaultState ? (t.on || 'On') : (t.off || 'Off')}</span>
475
- </div>
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>
476
473
  </div>
477
474
  </div>
478
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');
@@ -133,10 +138,11 @@ class MultipleSwitchPlatform {
133
138
  }
134
139
 
135
140
  // Create regular switches
141
+ const switchType = device.switchType || (switches[0] && switches[0].type) || 'outlet';
136
142
  switches.forEach((sw, index) => {
137
143
  const subtype = `switch_${index}`;
138
144
 
139
- const ServiceClass = this.getServiceClass(sw.type);
145
+ const ServiceClass = this.getServiceClass(switchType);
140
146
  const service = accessory.addService(ServiceClass, sw.name, subtype);
141
147
 
142
148
  this.setServiceName(service, sw.name);
@@ -144,8 +150,16 @@ class MultipleSwitchPlatform {
144
150
 
145
151
  services.set(subtype, service);
146
152
 
147
- if (accessory.context.switchStates[subtype] === undefined) {
148
- 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
+ }
149
163
  }
150
164
  });
151
165
 
@@ -203,13 +217,19 @@ class MultipleSwitchPlatform {
203
217
  }
204
218
 
205
219
  scheduleAutoOff(accessory, service, sw, subtype) {
206
- 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);
207
226
  if (accessory.context.switchStates[subtype]) {
208
227
  accessory.context.switchStates[subtype] = false;
209
228
  service.updateCharacteristic(this.Characteristic.On, false);
210
229
  this.log.info(`[${sw.name}] auto-off after ${sw.delayOff}ms`);
211
230
  }
212
231
  }, sw.delayOff);
232
+ this.autoOffTimers.set(timerKey, timer);
213
233
  }
214
234
 
215
235
  getServiceClass(type) {
package/logo.png ADDED
Binary file
package/logo.svg ADDED
@@ -0,0 +1,102 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
2
+ <defs>
3
+ <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" style="stop-color:#1a1a2e"/>
5
+ <stop offset="50%" style="stop-color:#16213e"/>
6
+ <stop offset="100%" style="stop-color:#0f3460"/>
7
+ </linearGradient>
8
+ <linearGradient id="glowGreen" x1="0%" y1="0%" x2="0%" y2="100%">
9
+ <stop offset="0%" style="stop-color:#00ff88"/>
10
+ <stop offset="100%" style="stop-color:#00cc6a"/>
11
+ </linearGradient>
12
+ <linearGradient id="glowAmber" x1="0%" y1="0%" x2="0%" y2="100%">
13
+ <stop offset="0%" style="stop-color:#ffb347"/>
14
+ <stop offset="100%" style="stop-color:#ff8c00"/>
15
+ </linearGradient>
16
+ <linearGradient id="glowBlue" x1="0%" y1="0%" x2="0%" y2="100%">
17
+ <stop offset="0%" style="stop-color:#00d4ff"/>
18
+ <stop offset="100%" style="stop-color:#0099cc"/>
19
+ </linearGradient>
20
+ <linearGradient id="ringGrad" x1="0%" y1="0%" x2="100%" y2="100%">
21
+ <stop offset="0%" style="stop-color:rgba(255,255,255,0.15)"/>
22
+ <stop offset="100%" style="stop-color:rgba(255,255,255,0.03)"/>
23
+ </linearGradient>
24
+ <filter id="glowFilter1">
25
+ <feGaussianBlur stdDeviation="12" result="blur"/>
26
+ <feMerge>
27
+ <feMergeNode in="blur"/>
28
+ <feMergeNode in="SourceGraphic"/>
29
+ </feMerge>
30
+ </filter>
31
+ <filter id="glowFilter2">
32
+ <feGaussianBlur stdDeviation="8" result="blur"/>
33
+ <feMerge>
34
+ <feMergeNode in="blur"/>
35
+ <feMergeNode in="SourceGraphic"/>
36
+ </feMerge>
37
+ </filter>
38
+ <filter id="softShadow">
39
+ <feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#000" flood-opacity="0.4"/>
40
+ </filter>
41
+ </defs>
42
+
43
+ <!-- Background -->
44
+ <rect width="512" height="512" rx="112" fill="url(#bg)"/>
45
+
46
+ <!-- Subtle grid pattern -->
47
+ <line x1="256" y1="80" x2="256" y2="432" stroke="rgba(255,255,255,0.03)" stroke-width="1"/>
48
+ <line x1="80" y1="256" x2="432" y2="256" stroke="rgba(255,255,255,0.03)" stroke-width="1"/>
49
+
50
+ <!-- Central hub ring -->
51
+ <circle cx="256" cy="256" r="155" fill="none" stroke="url(#ringGrad)" stroke-width="2"/>
52
+ <circle cx="256" cy="256" r="90" fill="none" stroke="rgba(255,255,255,0.06)" stroke-width="1.5"/>
53
+
54
+ <!-- Connection lines from center to switches -->
55
+ <line x1="256" y1="256" x2="160" y2="160" stroke="rgba(0,255,136,0.25)" stroke-width="2" stroke-dasharray="4,4"/>
56
+ <line x1="256" y1="256" x2="352" y2="160" stroke="rgba(0,212,255,0.25)" stroke-width="2" stroke-dasharray="4,4"/>
57
+ <line x1="256" y1="256" x2="160" y2="352" stroke="rgba(255,179,71,0.25)" stroke-width="2" stroke-dasharray="4,4"/>
58
+ <line x1="256" y1="256" x2="352" y2="352" stroke="rgba(255,255,255,0.1)" stroke-width="2" stroke-dasharray="4,4"/>
59
+
60
+ <!-- Switch 1 — Top Left — Green (ON) -->
61
+ <g filter="url(#glowFilter1)">
62
+ <circle cx="160" cy="160" r="8" fill="#00ff88" opacity="0.3"/>
63
+ </g>
64
+ <circle cx="160" cy="160" r="38" fill="rgba(0,255,136,0.08)" stroke="rgba(0,255,136,0.4)" stroke-width="2"/>
65
+ <circle cx="160" cy="160" r="22" fill="rgba(0,255,136,0.12)" stroke="rgba(0,255,136,0.6)" stroke-width="1.5"/>
66
+ <!-- Power icon -->
67
+ <line x1="160" y1="146" x2="160" y2="155" stroke="#00ff88" stroke-width="3" stroke-linecap="round"/>
68
+ <path d="M 149 153 A 14 14 0 1 0 171 153" fill="none" stroke="#00ff88" stroke-width="2.5" stroke-linecap="round"/>
69
+
70
+ <!-- Switch 2 — Top Right — Blue (ON) -->
71
+ <g filter="url(#glowFilter1)">
72
+ <circle cx="352" cy="160" r="8" fill="#00d4ff" opacity="0.3"/>
73
+ </g>
74
+ <circle cx="352" cy="160" r="38" fill="rgba(0,212,255,0.08)" stroke="rgba(0,212,255,0.4)" stroke-width="2"/>
75
+ <circle cx="352" cy="160" r="22" fill="rgba(0,212,255,0.12)" stroke="rgba(0,212,255,0.6)" stroke-width="1.5"/>
76
+ <!-- Power icon -->
77
+ <line x1="352" y1="146" x2="352" y2="155" stroke="#00d4ff" stroke-width="3" stroke-linecap="round"/>
78
+ <path d="M 341 153 A 14 14 0 1 0 363 153" fill="none" stroke="#00d4ff" stroke-width="2.5" stroke-linecap="round"/>
79
+
80
+ <!-- Switch 3 — Bottom Left — Amber (ON) -->
81
+ <g filter="url(#glowFilter1)">
82
+ <circle cx="160" cy="352" r="8" fill="#ffb347" opacity="0.3"/>
83
+ </g>
84
+ <circle cx="160" cy="352" r="38" fill="rgba(255,179,71,0.08)" stroke="rgba(255,179,71,0.4)" stroke-width="2"/>
85
+ <circle cx="160" cy="352" r="22" fill="rgba(255,179,71,0.12)" stroke="rgba(255,179,71,0.6)" stroke-width="1.5"/>
86
+ <!-- Power icon -->
87
+ <line x1="160" y1="338" x2="160" y2="347" stroke="#ffb347" stroke-width="3" stroke-linecap="round"/>
88
+ <path d="M 149 345 A 14 14 0 1 0 171 345" fill="none" stroke="#ffb347" stroke-width="2.5" stroke-linecap="round"/>
89
+
90
+ <!-- Switch 4 — Bottom Right — OFF -->
91
+ <circle cx="352" cy="352" r="38" fill="rgba(255,255,255,0.03)" stroke="rgba(255,255,255,0.12)" stroke-width="2"/>
92
+ <circle cx="352" cy="352" r="22" fill="rgba(255,255,255,0.04)" stroke="rgba(255,255,255,0.15)" stroke-width="1.5"/>
93
+ <!-- Power icon (dimmed) -->
94
+ <line x1="352" y1="338" x2="352" y2="347" stroke="rgba(255,255,255,0.2)" stroke-width="3" stroke-linecap="round"/>
95
+ <path d="M 341 345 A 14 14 0 1 0 363 345" fill="none" stroke="rgba(255,255,255,0.2)" stroke-width="2.5" stroke-linecap="round"/>
96
+
97
+ <!-- Center hub -->
98
+ <circle cx="256" cy="256" r="32" fill="rgba(255,255,255,0.06)" stroke="rgba(255,255,255,0.15)" stroke-width="2"/>
99
+ <circle cx="256" cy="256" r="18" fill="rgba(255,255,255,0.08)" stroke="rgba(255,255,255,0.2)" stroke-width="1.5"/>
100
+ <!-- HomeKit house icon in center -->
101
+ <path d="M 245 260 L 256 249 L 267 260 L 267 270 L 261 270 L 261 263 L 251 263 L 251 270 L 245 270 Z" fill="rgba(255,255,255,0.7)" filter="url(#softShadow)"/>
102
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-multiple-switch",
3
- "version": "1.6.0",
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",