homey-lib 2.44.4 → 2.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/app/schema.json +1 -1
- package/assets/capability/capabilities/target_power.json +137 -0
- package/assets/capability/capabilities/target_power_mode.json +204 -0
- package/assets/capability/capabilities.json +2 -0
- package/lib/App/index.js +31 -1
- package/package.json +1 -1
- package/test/validate-driver-manifest.js +242 -0
- package/webpack/index.js +1 -1
package/assets/app/schema.json
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "number",
|
|
3
|
+
"title": {
|
|
4
|
+
"en": "Target power",
|
|
5
|
+
"nl": "Doelvermogen",
|
|
6
|
+
"de": "Ziel-Leistung",
|
|
7
|
+
"fr": "Puissance cible",
|
|
8
|
+
"it": "Potenza target",
|
|
9
|
+
"sv": "Måleffekt",
|
|
10
|
+
"no": "Måleffekt",
|
|
11
|
+
"es": "Potencia objetivo",
|
|
12
|
+
"da": "Måleffekt",
|
|
13
|
+
"ru": "Целевая мощность",
|
|
14
|
+
"pl": "Moc docelowa",
|
|
15
|
+
"ko": "목표 전력",
|
|
16
|
+
"ar": "الطاقة المستهدفة"
|
|
17
|
+
},
|
|
18
|
+
"desc": {
|
|
19
|
+
"en": "Target power in watt",
|
|
20
|
+
"nl": "Doelvermogen in watt",
|
|
21
|
+
"de": "Ziel-Leistung in Watt",
|
|
22
|
+
"fr": "Puissance cible en watt",
|
|
23
|
+
"it": "Potenza target in watt",
|
|
24
|
+
"sv": "Måleffekt i watt",
|
|
25
|
+
"no": "Måleffekt i watt",
|
|
26
|
+
"es": "Potencia objetivo en vatios",
|
|
27
|
+
"da": "Måleffekt i watt",
|
|
28
|
+
"ru": "Целевая мощность в ваттах",
|
|
29
|
+
"pl": "Moc docelowa w watach",
|
|
30
|
+
"ko": "목표 전력 와트",
|
|
31
|
+
"ar": "الطاقة المستهدفة بالواط"
|
|
32
|
+
},
|
|
33
|
+
"units": {
|
|
34
|
+
"en": "W",
|
|
35
|
+
"nl": "W",
|
|
36
|
+
"de": "W",
|
|
37
|
+
"fr": "W",
|
|
38
|
+
"it": "W",
|
|
39
|
+
"sv": "W",
|
|
40
|
+
"no": "W",
|
|
41
|
+
"es": "W",
|
|
42
|
+
"da": "W",
|
|
43
|
+
"ru": "Вт",
|
|
44
|
+
"pl": "W",
|
|
45
|
+
"ko": "W",
|
|
46
|
+
"ar": "واط"
|
|
47
|
+
},
|
|
48
|
+
"insights": true,
|
|
49
|
+
"chartType": "stepLine",
|
|
50
|
+
"min": -25000,
|
|
51
|
+
"max": 25000,
|
|
52
|
+
"step": 1,
|
|
53
|
+
"decimals": 0,
|
|
54
|
+
"color": "#6DD400",
|
|
55
|
+
"getable": true,
|
|
56
|
+
"setable": true,
|
|
57
|
+
"uiComponent": "slider",
|
|
58
|
+
"minCompatibility": "12.13.0",
|
|
59
|
+
"$flow": {
|
|
60
|
+
"triggers": [
|
|
61
|
+
{
|
|
62
|
+
"id": "target_power_changed",
|
|
63
|
+
"highlight": true,
|
|
64
|
+
"title": {
|
|
65
|
+
"en": "The target power changed",
|
|
66
|
+
"nl": "Het doelvermogen is veranderd",
|
|
67
|
+
"de": "Die Ziel-Leistung hat sich geändert",
|
|
68
|
+
"fr": "La puissance cible a changé",
|
|
69
|
+
"it": "La potenza target è cambiata",
|
|
70
|
+
"sv": "Måleffekten ändrades",
|
|
71
|
+
"no": "Måleffekten ble endret",
|
|
72
|
+
"es": "La potencia objetivo ha cambiado",
|
|
73
|
+
"da": "Måleffekten blev ændret",
|
|
74
|
+
"ru": "Целевая мощность изменена",
|
|
75
|
+
"pl": "Moc docelowa uległa zmianie",
|
|
76
|
+
"ko": "목표 전력이 변경되면",
|
|
77
|
+
"ar": "تغيرت الطاقة المستهدفة"
|
|
78
|
+
},
|
|
79
|
+
"tokens": [
|
|
80
|
+
{
|
|
81
|
+
"name": "$id",
|
|
82
|
+
"title": "$title",
|
|
83
|
+
"type": "$type",
|
|
84
|
+
"example": 2500
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"actions": [
|
|
90
|
+
{
|
|
91
|
+
"id": "target_power_set",
|
|
92
|
+
"highlight": true,
|
|
93
|
+
"title": {
|
|
94
|
+
"en": "Set the target power",
|
|
95
|
+
"nl": "Stel het doelvermogen in",
|
|
96
|
+
"de": "Ziel-Leistung setzen",
|
|
97
|
+
"fr": "Définir la puissance cible",
|
|
98
|
+
"it": "Imposta la potenza target",
|
|
99
|
+
"sv": "Ställ in måleffekten",
|
|
100
|
+
"no": "Angi måleffekten",
|
|
101
|
+
"es": "Establecer la potencia objetivo",
|
|
102
|
+
"da": "Indstil måleffekten",
|
|
103
|
+
"ru": "Установить целевую мощность",
|
|
104
|
+
"pl": "Ustaw moc docelową",
|
|
105
|
+
"ko": "목표 전력 설정",
|
|
106
|
+
"ar": "ضبط الطاقة المستهدفة"
|
|
107
|
+
},
|
|
108
|
+
"hint": {
|
|
109
|
+
"en": "This also switches the target power mode to Homey. For EV chargers, charging is automatically started or stopped.",
|
|
110
|
+
"nl": "Dit schakelt ook de doelvermogenmodus naar Homey. Bij een EV-lader wordt het laden automatisch gestart of gestopt.",
|
|
111
|
+
"de": "Dies schaltet auch den Zielleistungsmodus auf Homey um. Bei EV-Ladegeräten wird der Ladevorgang automatisch gestartet oder gestoppt.",
|
|
112
|
+
"fr": "Ceci bascule également le mode de puissance cible sur Homey. Pour les bornes de recharge, la charge est automatiquement démarrée ou arrêtée.",
|
|
113
|
+
"it": "Questo imposta anche la modalità potenza target su Homey. Per i caricatori EV, la ricarica viene avviata o interrotta automaticamente.",
|
|
114
|
+
"sv": "Detta växlar även måleffektläget till Homey. För EV-laddare startas eller stoppas laddningen automatiskt.",
|
|
115
|
+
"no": "Dette bytter også måleffektmodus til Homey. For EV-ladere startes eller stoppes ladingen automatisk.",
|
|
116
|
+
"es": "Esto también cambia el modo de potencia objetivo a Homey. Para cargadores de vehículos eléctricos, la carga se inicia o detiene automáticamente.",
|
|
117
|
+
"da": "Dette skifter også måleffekttilstanden til Homey. For EV-ladere startes eller stoppes opladningen automatisk.",
|
|
118
|
+
"ru": "Это также переключает режим целевой мощности на Homey. Для зарядных станций зарядка автоматически запускается или останавливается.",
|
|
119
|
+
"pl": "To również przełącza tryb mocy docelowej na Homey. W przypadku ładowarek EV ładowanie jest automatycznie uruchamiane lub zatrzymywane.",
|
|
120
|
+
"ko": "이 작업은 목표 전력 모드도 Homey로 전환합니다. EV 충전기의 경우 충전이 자동으로 시작되거나 중지됩니다.",
|
|
121
|
+
"ar": "يؤدي هذا أيضًا إلى تبديل وضع الطاقة المستهدفة إلى Homey. بالنسبة لشواحن السيارات الكهربائية، يتم بدء الشحن أو إيقافه تلقائيًا."
|
|
122
|
+
},
|
|
123
|
+
"args": [
|
|
124
|
+
{
|
|
125
|
+
"name": "target_power",
|
|
126
|
+
"type": "range",
|
|
127
|
+
"min": -25000,
|
|
128
|
+
"max": 25000,
|
|
129
|
+
"step": 1,
|
|
130
|
+
"label": "W",
|
|
131
|
+
"labelDecimals": 0
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "enum",
|
|
3
|
+
"title": {
|
|
4
|
+
"en": "Target power mode",
|
|
5
|
+
"nl": "Doelvermogenmodus",
|
|
6
|
+
"de": "Zielleistungsmodus",
|
|
7
|
+
"fr": "Mode de puissance cible",
|
|
8
|
+
"it": "Modalità potenza target",
|
|
9
|
+
"sv": "Måleffektläge",
|
|
10
|
+
"no": "Måleffektmodus",
|
|
11
|
+
"es": "Modo de potencia objetivo",
|
|
12
|
+
"da": "Måleffekttilstand",
|
|
13
|
+
"ru": "Режим целевой мощности",
|
|
14
|
+
"pl": "Tryb mocy docelowej",
|
|
15
|
+
"ko": "목표 전력 모드",
|
|
16
|
+
"ar": "وضع الطاقة المستهدفة"
|
|
17
|
+
},
|
|
18
|
+
"desc": {
|
|
19
|
+
"en": "The target power control mode",
|
|
20
|
+
"nl": "De doelvermogen besturingsmodus",
|
|
21
|
+
"de": "Der Zielleistungs-Steuermodus",
|
|
22
|
+
"fr": "Le mode de contrôle de puissance cible",
|
|
23
|
+
"it": "La modalità di controllo della potenza target",
|
|
24
|
+
"sv": "Måleffektens styrläge",
|
|
25
|
+
"no": "Måleffektens kontrollmodus",
|
|
26
|
+
"es": "El modo de control de potencia objetivo",
|
|
27
|
+
"da": "Måleffektens kontroltilstand",
|
|
28
|
+
"ru": "Режим управления целевой мощностью",
|
|
29
|
+
"pl": "Tryb sterowania mocą docelową",
|
|
30
|
+
"ko": "목표 전력 제어 모드",
|
|
31
|
+
"ar": "وضع التحكم في الطاقة المستهدفة"
|
|
32
|
+
},
|
|
33
|
+
"values": [
|
|
34
|
+
{
|
|
35
|
+
"id": "device",
|
|
36
|
+
"title": {
|
|
37
|
+
"en": "Automatic",
|
|
38
|
+
"nl": "Automatisch",
|
|
39
|
+
"de": "Automatisch",
|
|
40
|
+
"fr": "Automatique",
|
|
41
|
+
"it": "Automatico",
|
|
42
|
+
"sv": "Automatisk",
|
|
43
|
+
"no": "Automatisk",
|
|
44
|
+
"es": "Automático",
|
|
45
|
+
"da": "Automatisk",
|
|
46
|
+
"ru": "Автоматический",
|
|
47
|
+
"pl": "Automatyczny",
|
|
48
|
+
"ko": "자동",
|
|
49
|
+
"ar": "تلقائي"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "homey",
|
|
54
|
+
"title": {
|
|
55
|
+
"en": "Homey",
|
|
56
|
+
"nl": "Homey",
|
|
57
|
+
"de": "Homey",
|
|
58
|
+
"fr": "Homey",
|
|
59
|
+
"it": "Homey",
|
|
60
|
+
"sv": "Homey",
|
|
61
|
+
"no": "Homey",
|
|
62
|
+
"es": "Homey",
|
|
63
|
+
"da": "Homey",
|
|
64
|
+
"ru": "Homey",
|
|
65
|
+
"pl": "Homey",
|
|
66
|
+
"ko": "Homey",
|
|
67
|
+
"ar": "Homey"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"color": "#6DD400",
|
|
72
|
+
"getable": true,
|
|
73
|
+
"setable": true,
|
|
74
|
+
"uiComponent": "picker",
|
|
75
|
+
"minCompatibility": "12.13.0",
|
|
76
|
+
"$flow": {
|
|
77
|
+
"triggers": [
|
|
78
|
+
{
|
|
79
|
+
"id": "target_power_mode_changed",
|
|
80
|
+
"title": {
|
|
81
|
+
"en": "Target power mode changed to",
|
|
82
|
+
"nl": "Doelvermogenmodus is veranderd naar",
|
|
83
|
+
"de": "Zielleistungsmodus hat sich geändert zu",
|
|
84
|
+
"fr": "Le mode de puissance cible est passé à",
|
|
85
|
+
"it": "La modalità potenza target è cambiata in",
|
|
86
|
+
"sv": "Måleffektläge ändrades till",
|
|
87
|
+
"no": "Måleffektmodus ble endret til",
|
|
88
|
+
"es": "El modo de potencia objetivo cambió a",
|
|
89
|
+
"da": "Måleffekttilstand blev ændret til",
|
|
90
|
+
"ru": "Режим целевой мощности изменен на",
|
|
91
|
+
"pl": "Tryb mocy docelowej zmieniono na",
|
|
92
|
+
"ko": "목표 전력 모드가 변경되면",
|
|
93
|
+
"ar": "تم تغيير وضع الطاقة المستهدفة إلى"
|
|
94
|
+
},
|
|
95
|
+
"hint": {
|
|
96
|
+
"en": "\"Homey\" means Homey controls the device's target power. \"Automatic\" means the device controls its own power.",
|
|
97
|
+
"nl": "\"Homey\" betekent dat Homey het doelvermogen van het apparaat regelt. \"Automatisch\" betekent dat het apparaat zelf het vermogen regelt.",
|
|
98
|
+
"de": "\"Homey\" bedeutet, dass Homey die Zielleistung des Geräts steuert. \"Automatisch\" bedeutet, dass das Gerät seine eigene Leistung steuert.",
|
|
99
|
+
"fr": "« Homey » signifie que Homey contrôle la puissance cible de l'appareil. « Automatique » signifie que l'appareil contrôle lui-même sa puissance.",
|
|
100
|
+
"it": "\"Homey\" significa che Homey controlla la potenza target del dispositivo. \"Automatico\" significa che il dispositivo controlla autonomamente la propria potenza.",
|
|
101
|
+
"sv": "\"Homey\" innebär att Homey styr enhetens måleffekt. \"Automatisk\" innebär att enheten styr sin egen effekt.",
|
|
102
|
+
"no": "\"Homey\" betyr at Homey styrer enhetens måleffekt. \"Automatisk\" betyr at enheten styrer sin egen effekt.",
|
|
103
|
+
"es": "\"Homey\" significa que Homey controla la potencia objetivo del dispositivo. \"Automático\" significa que el dispositivo controla su propia potencia.",
|
|
104
|
+
"da": "\"Homey\" betyder, at Homey styrer enhedens måleffekt. \"Automatisk\" betyder, at enheden styrer sin egen effekt.",
|
|
105
|
+
"ru": "«Homey» означает, что Homey управляет целевой мощностью устройства. «Автоматический» означает, что устройство само управляет своей мощностью.",
|
|
106
|
+
"pl": "\"Homey\" oznacza, że Homey steruje mocą docelową urządzenia. \"Automatyczny\" oznacza, że urządzenie samo steruje swoją mocą.",
|
|
107
|
+
"ko": "\"Homey\"는 Homey가 기기의 목표 전력을 제어함을 의미합니다. \"자동\"은 기기가 자체적으로 전력을 제어함을 의미합니다.",
|
|
108
|
+
"ar": "\"Homey\" يعني أن Homey يتحكم في الطاقة المستهدفة للجهاز. \"تلقائي\" يعني أن الجهاز يتحكم في طاقته بنفسه."
|
|
109
|
+
},
|
|
110
|
+
"args": [
|
|
111
|
+
{
|
|
112
|
+
"name": "target_power_mode",
|
|
113
|
+
"type": "dropdown",
|
|
114
|
+
"values": "$values"
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"conditions": [
|
|
120
|
+
{
|
|
121
|
+
"id": "target_power_mode_is",
|
|
122
|
+
"title": {
|
|
123
|
+
"en": "Target power mode !{{is|is not}}",
|
|
124
|
+
"nl": "Doelvermogenmodus !{{is|is niet}}",
|
|
125
|
+
"de": "Zielleistungsmodus !{{ist|ist nicht}}",
|
|
126
|
+
"fr": "Mode de puissance cible !{{est|n'est pas}}",
|
|
127
|
+
"it": "La modalità potenza target !{{è|non è}}",
|
|
128
|
+
"sv": "Måleffektläge !{{är|är inte}}",
|
|
129
|
+
"no": "Måleffektmodus !{{er|er ikke}}",
|
|
130
|
+
"es": "El modo de potencia objetivo !{{está|no está}}",
|
|
131
|
+
"da": "Måleffekttilstand !{{er|er ikke}}",
|
|
132
|
+
"ru": "Режим целевой мощности !{{|не}}",
|
|
133
|
+
"pl": "Tryb mocy docelowej !{{to|to nie}}",
|
|
134
|
+
"ko": "목표 전력 모드가 다음!{{이면|이 아니면}}",
|
|
135
|
+
"ar": "وضع الطاقة المستهدفة !{{هو|ليس}}"
|
|
136
|
+
},
|
|
137
|
+
"hint": {
|
|
138
|
+
"en": "\"Homey\" means Homey controls the device's target power. \"Automatic\" means the device controls its own power.",
|
|
139
|
+
"nl": "\"Homey\" betekent dat Homey het doelvermogen van het apparaat regelt. \"Automatisch\" betekent dat het apparaat zelf het vermogen regelt.",
|
|
140
|
+
"de": "\"Homey\" bedeutet, dass Homey die Zielleistung des Geräts steuert. \"Automatisch\" bedeutet, dass das Gerät seine eigene Leistung steuert.",
|
|
141
|
+
"fr": "« Homey » signifie que Homey contrôle la puissance cible de l'appareil. « Automatique » signifie que l'appareil contrôle lui-même sa puissance.",
|
|
142
|
+
"it": "\"Homey\" significa che Homey controlla la potenza target del dispositivo. \"Automatico\" significa che il dispositivo controlla autonomamente la propria potenza.",
|
|
143
|
+
"sv": "\"Homey\" innebär att Homey styr enhetens måleffekt. \"Automatisk\" innebär att enheten styr sin egen effekt.",
|
|
144
|
+
"no": "\"Homey\" betyr at Homey styrer enhetens måleffekt. \"Automatisk\" betyr at enheten styrer sin egen effekt.",
|
|
145
|
+
"es": "\"Homey\" significa que Homey controla la potencia objetivo del dispositivo. \"Automático\" significa que el dispositivo controla su propia potencia.",
|
|
146
|
+
"da": "\"Homey\" betyder, at Homey styrer enhedens måleffekt. \"Automatisk\" betyder, at enheden styrer sin egen effekt.",
|
|
147
|
+
"ru": "«Homey» означает, что Homey управляет целевой мощностью устройства. «Автоматический» означает, что устройство само управляет своей мощностью.",
|
|
148
|
+
"pl": "\"Homey\" oznacza, że Homey steruje mocą docelową urządzenia. \"Automatyczny\" oznacza, że urządzenie samo steruje swoją mocą.",
|
|
149
|
+
"ko": "\"Homey\"는 Homey가 기기의 목표 전력을 제어함을 의미합니다. \"자동\"은 기기가 자체적으로 전력을 제어함을 의미합니다.",
|
|
150
|
+
"ar": "\"Homey\" يعني أن Homey يتحكم في الطاقة المستهدفة للجهاز. \"تلقائي\" يعني أن الجهاز يتحكم في طاقته بنفسه."
|
|
151
|
+
},
|
|
152
|
+
"args": [
|
|
153
|
+
{
|
|
154
|
+
"name": "target_power_mode",
|
|
155
|
+
"type": "dropdown",
|
|
156
|
+
"values": "$values"
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
],
|
|
161
|
+
"actions": [
|
|
162
|
+
{
|
|
163
|
+
"id": "target_power_mode_set",
|
|
164
|
+
"title": {
|
|
165
|
+
"en": "Set target power mode to",
|
|
166
|
+
"nl": "Stel doelvermogenmodus in op",
|
|
167
|
+
"de": "Zielleistungsmodus setzen auf",
|
|
168
|
+
"fr": "Définir le mode de puissance cible sur",
|
|
169
|
+
"it": "Imposta la modalità potenza target su",
|
|
170
|
+
"sv": "Ställ in måleffektläge på",
|
|
171
|
+
"no": "Sett måleffektmodus til",
|
|
172
|
+
"es": "Establecer el modo de potencia objetivo en",
|
|
173
|
+
"da": "Indstil måleffekttilstand til",
|
|
174
|
+
"ru": "Установить режим целевой мощности на",
|
|
175
|
+
"pl": "Ustaw tryb mocy docelowej na",
|
|
176
|
+
"ko": "목표 전력 모드 설정",
|
|
177
|
+
"ar": "ضبط وضع الطاقة المستهدفة على"
|
|
178
|
+
},
|
|
179
|
+
"hint": {
|
|
180
|
+
"en": "To control the target power of this device via Homey, select \"Homey\". To let the device determine its own target power, select \"Automatic\".",
|
|
181
|
+
"nl": "Wil je via Homey het doelvermogen van dit apparaat aanpassen, gebruik dan \"Homey\". Wil je dat het apparaat zelf het doelvermogen bepaalt, gebruik dan \"Automatisch\".",
|
|
182
|
+
"de": "Um die Zielleistung dieses Geräts über Homey zu steuern, wähle \"Homey\". Um das Gerät seine eigene Zielleistung bestimmen zu lassen, wähle \"Automatisch\".",
|
|
183
|
+
"fr": "Pour contrôler la puissance cible de cet appareil via Homey, sélectionnez « Homey ». Pour laisser l'appareil déterminer sa propre puissance cible, sélectionnez « Automatique ».",
|
|
184
|
+
"it": "Per controllare la potenza target di questo dispositivo tramite Homey, seleziona \"Homey\". Per lasciare che il dispositivo determini la propria potenza target, seleziona \"Automatico\".",
|
|
185
|
+
"sv": "För att styra måleffekten för denna enhet via Homey, välj \"Homey\". För att låta enheten bestämma sin egen måleffekt, välj \"Automatisk\".",
|
|
186
|
+
"no": "For å styre måleffekten til denne enheten via Homey, velg \"Homey\". For å la enheten bestemme sin egen måleffekt, velg \"Automatisk\".",
|
|
187
|
+
"es": "Para controlar la potencia objetivo de este dispositivo a través de Homey, selecciona \"Homey\". Para dejar que el dispositivo determine su propia potencia objetivo, selecciona \"Automático\".",
|
|
188
|
+
"da": "For at styre måleffekten for denne enhed via Homey, vælg \"Homey\". For at lade enheden bestemme sin egen måleffekt, vælg \"Automatisk\".",
|
|
189
|
+
"ru": "Чтобы управлять целевой мощностью этого устройства через Homey, выберите «Homey». Чтобы устройство само определяло целевую мощность, выберите «Автоматический».",
|
|
190
|
+
"pl": "Aby sterować mocą docelową tego urządzenia przez Homey, wybierz \"Homey\". Aby urządzenie samo określało moc docelową, wybierz \"Automatyczny\".",
|
|
191
|
+
"ko": "Homey를 통해 이 기기의 목표 전력을 제어하려면 \"Homey\"를 선택하세요. 기기가 자체적으로 목표 전력을 결정하게 하려면 \"자동\"을 선택하세요.",
|
|
192
|
+
"ar": "للتحكم في الطاقة المستهدفة لهذا الجهاز عبر Homey، اختر \"Homey\". لترك الجهاز يحدد الطاقة المستهدفة بنفسه، اختر \"تلقائي\"."
|
|
193
|
+
},
|
|
194
|
+
"args": [
|
|
195
|
+
{
|
|
196
|
+
"name": "target_power_mode",
|
|
197
|
+
"type": "dropdown",
|
|
198
|
+
"values": "$values"
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
}
|
package/lib/App/index.js
CHANGED
|
@@ -230,7 +230,7 @@ class App {
|
|
|
230
230
|
App.validatePythonVersion(appJson);
|
|
231
231
|
|
|
232
232
|
// Validate that Python apps have cross-platform venvs
|
|
233
|
-
if (levelPublish && appJson.runtime === 'python' && appJson.
|
|
233
|
+
if (levelPublish && appJson.runtime === 'python' && appJson.pythonPackages !== undefined && appJson.pythonPackages.length > 0) {
|
|
234
234
|
const missingVenvs = [];
|
|
235
235
|
for (const platform of App.REQUIRED_PYTHON_PLATFORMS) {
|
|
236
236
|
const venvPath = join(this._path, 'venvs', platform);
|
|
@@ -368,6 +368,36 @@ class App {
|
|
|
368
368
|
}
|
|
369
369
|
});
|
|
370
370
|
|
|
371
|
+
// validate `appJson.drivers[].capabilitiesOptions`
|
|
372
|
+
if (driver.capabilitiesOptions) {
|
|
373
|
+
for (const [capabilityId, capabilityOptions] of Object.entries(driver.capabilitiesOptions)) {
|
|
374
|
+
// Enforce fixed values for target_power_mode — always use the canonical values from the capability definition
|
|
375
|
+
if (Capability.isInstanceOfId(capabilityId, 'target_power_mode')) {
|
|
376
|
+
capabilityOptions.values = Capability.getCapability('target_power_mode').values;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// validate target_power exclude range must include 0
|
|
380
|
+
if (Capability.isInstanceOfId(capabilityId, 'target_power')) {
|
|
381
|
+
if (typeof capabilityOptions.excludeMin === 'number' || typeof capabilityOptions.excludeMax === 'number') {
|
|
382
|
+
const excludeMin = typeof capabilityOptions.excludeMin === 'number' ? capabilityOptions.excludeMin : 0;
|
|
383
|
+
const excludeMax = typeof capabilityOptions.excludeMax === 'number' ? capabilityOptions.excludeMax : 0;
|
|
384
|
+
if (excludeMin > 0 || excludeMax < 0) {
|
|
385
|
+
throw new Error(`drivers.${driver.id}.capabilitiesOptions.${capabilityId}.excludeMin/excludeMax must include 0 (excludeMin <= 0 <= excludeMax)`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// validate target_power min/max range must include 0 (all devices need idle)
|
|
391
|
+
if (Capability.isInstanceOfId(capabilityId, 'target_power')) {
|
|
392
|
+
const min = typeof capabilityOptions.min === 'number' ? capabilityOptions.min : 0;
|
|
393
|
+
const max = typeof capabilityOptions.max === 'number' ? capabilityOptions.max : 0;
|
|
394
|
+
if (min > 0 || max < 0) {
|
|
395
|
+
throw new Error(`drivers.${driver.id}.capabilitiesOptions.${capabilityId}.min/max must include 0 (min <= 0 <= max) to allow idle state`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
371
401
|
// validate `appJson.drivers[].pair`
|
|
372
402
|
if (Array.isArray(driver.pair)) {
|
|
373
403
|
for (let j = 0; j < driver.pair.length; j++) {
|
package/package.json
CHANGED
|
@@ -590,4 +590,246 @@ describe('HomeyLib.App#validate() driver manifest', function() {
|
|
|
590
590
|
verified: /zigbee\.endpoints\['1'].bindings\[0] should be number/i,
|
|
591
591
|
});
|
|
592
592
|
});
|
|
593
|
+
|
|
594
|
+
/*
|
|
595
|
+
* target_power_mode values validation
|
|
596
|
+
*/
|
|
597
|
+
|
|
598
|
+
it('`target_power_mode` with custom values should pass (values are silently replaced)', async function() {
|
|
599
|
+
const app = mockApp({
|
|
600
|
+
...baseAppManifest,
|
|
601
|
+
compatibility: '>=12.13.0',
|
|
602
|
+
drivers: [{
|
|
603
|
+
...baseDriverManifest,
|
|
604
|
+
capabilities: ['target_power', 'target_power_mode'],
|
|
605
|
+
capabilitiesOptions: {
|
|
606
|
+
target_power_mode: {
|
|
607
|
+
values: [
|
|
608
|
+
{ id: 'custom', title: { en: 'Custom' } },
|
|
609
|
+
],
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
}],
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
await assertValidates(app, {
|
|
616
|
+
debug: true,
|
|
617
|
+
publish: true,
|
|
618
|
+
verified: true,
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
it('`target_power_mode` without values array should pass', async function() {
|
|
623
|
+
const app = mockApp({
|
|
624
|
+
...baseAppManifest,
|
|
625
|
+
compatibility: '>=12.13.0',
|
|
626
|
+
drivers: [{
|
|
627
|
+
...baseDriverManifest,
|
|
628
|
+
capabilities: ['target_power', 'target_power_mode'],
|
|
629
|
+
capabilitiesOptions: {
|
|
630
|
+
target_power_mode: {
|
|
631
|
+
title: { en: 'Power Mode' },
|
|
632
|
+
},
|
|
633
|
+
},
|
|
634
|
+
}],
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
await assertValidates(app, {
|
|
638
|
+
debug: true,
|
|
639
|
+
publish: true,
|
|
640
|
+
verified: true,
|
|
641
|
+
});
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
/*
|
|
645
|
+
* target_power exclude validation
|
|
646
|
+
*/
|
|
647
|
+
|
|
648
|
+
it('`target_power` exclude must include 0 (excludeMin > 0 should fail)', async function() {
|
|
649
|
+
const app = mockApp({
|
|
650
|
+
...baseAppManifest,
|
|
651
|
+
compatibility: '>=12.13.0',
|
|
652
|
+
drivers: [{
|
|
653
|
+
...baseDriverManifest,
|
|
654
|
+
capabilities: ['target_power'],
|
|
655
|
+
capabilitiesOptions: {
|
|
656
|
+
target_power: {
|
|
657
|
+
excludeMin: 100, excludeMax: 1380, // Invalid: excludeMin > 0
|
|
658
|
+
},
|
|
659
|
+
},
|
|
660
|
+
}],
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
await assertValidates(app, {
|
|
664
|
+
debug: /capabilitiesOptions\.target_power\.excludeMin\/excludeMax must include 0/i,
|
|
665
|
+
publish: /capabilitiesOptions\.target_power\.excludeMin\/excludeMax must include 0/i,
|
|
666
|
+
verified: /capabilitiesOptions\.target_power\.excludeMin\/excludeMax must include 0/i,
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
it('`target_power` exclude must include 0 (excludeMax < 0 should fail)', async function() {
|
|
671
|
+
const app = mockApp({
|
|
672
|
+
...baseAppManifest,
|
|
673
|
+
compatibility: '>=12.13.0',
|
|
674
|
+
drivers: [{
|
|
675
|
+
...baseDriverManifest,
|
|
676
|
+
capabilities: ['target_power'],
|
|
677
|
+
capabilitiesOptions: {
|
|
678
|
+
target_power: {
|
|
679
|
+
excludeMin: -1380, excludeMax: -100, // Invalid: excludeMax < 0
|
|
680
|
+
},
|
|
681
|
+
},
|
|
682
|
+
}],
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
await assertValidates(app, {
|
|
686
|
+
debug: /capabilitiesOptions\.target_power\.excludeMin\/excludeMax must include 0/i,
|
|
687
|
+
publish: /capabilitiesOptions\.target_power\.excludeMin\/excludeMax must include 0/i,
|
|
688
|
+
verified: /capabilitiesOptions\.target_power\.excludeMin\/excludeMax must include 0/i,
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
it('`target_power` valid exclude that includes 0 should pass', async function() {
|
|
693
|
+
const app = mockApp({
|
|
694
|
+
...baseAppManifest,
|
|
695
|
+
compatibility: '>=12.13.0',
|
|
696
|
+
drivers: [{
|
|
697
|
+
...baseDriverManifest,
|
|
698
|
+
capabilities: ['target_power'],
|
|
699
|
+
capabilitiesOptions: {
|
|
700
|
+
target_power: {
|
|
701
|
+
excludeMin: 0, // Valid: includes 0
|
|
702
|
+
excludeMax: 1380,
|
|
703
|
+
},
|
|
704
|
+
},
|
|
705
|
+
}],
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
await assertValidates(app, {
|
|
709
|
+
debug: true,
|
|
710
|
+
publish: true,
|
|
711
|
+
verified: true,
|
|
712
|
+
});
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
it('`target_power` valid bidirectional exclude should pass', async function() {
|
|
716
|
+
const app = mockApp({
|
|
717
|
+
...baseAppManifest,
|
|
718
|
+
compatibility: '>=12.13.0',
|
|
719
|
+
drivers: [{
|
|
720
|
+
...baseDriverManifest,
|
|
721
|
+
capabilities: ['target_power'],
|
|
722
|
+
capabilitiesOptions: {
|
|
723
|
+
target_power: {
|
|
724
|
+
min: -11000,
|
|
725
|
+
max: 22000,
|
|
726
|
+
excludeMin: -1380,
|
|
727
|
+
excludeMax: 1380, // Valid: symmetric around 0
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
}],
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
await assertValidates(app, {
|
|
734
|
+
debug: true,
|
|
735
|
+
publish: true,
|
|
736
|
+
verified: true,
|
|
737
|
+
});
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
it('`target_power` without excludeMin/excludeMax should pass', async function() {
|
|
741
|
+
const app = mockApp({
|
|
742
|
+
...baseAppManifest,
|
|
743
|
+
compatibility: '>=12.13.0',
|
|
744
|
+
drivers: [{
|
|
745
|
+
...baseDriverManifest,
|
|
746
|
+
capabilities: ['target_power'],
|
|
747
|
+
capabilitiesOptions: {
|
|
748
|
+
target_power: {
|
|
749
|
+
min: -5000,
|
|
750
|
+
max: 5000,
|
|
751
|
+
},
|
|
752
|
+
},
|
|
753
|
+
}],
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
await assertValidates(app, {
|
|
757
|
+
debug: true,
|
|
758
|
+
publish: true,
|
|
759
|
+
verified: true,
|
|
760
|
+
});
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
/*
|
|
764
|
+
* target_power min/max validation (all devices)
|
|
765
|
+
*/
|
|
766
|
+
|
|
767
|
+
it('`target_power` min/max must include 0 (min > 0 should fail)', async function() {
|
|
768
|
+
const app = mockApp({
|
|
769
|
+
...baseAppManifest,
|
|
770
|
+
compatibility: '>=12.13.0',
|
|
771
|
+
drivers: [{
|
|
772
|
+
...baseDriverManifest,
|
|
773
|
+
capabilities: ['target_power'],
|
|
774
|
+
capabilitiesOptions: {
|
|
775
|
+
target_power: {
|
|
776
|
+
min: 100, // Invalid: min > 0
|
|
777
|
+
max: 5000,
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
}],
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
await assertValidates(app, {
|
|
784
|
+
debug: /capabilitiesOptions\.target_power\.min\/max must include 0/i,
|
|
785
|
+
publish: /capabilitiesOptions\.target_power\.min\/max must include 0/i,
|
|
786
|
+
verified: /capabilitiesOptions\.target_power\.min\/max must include 0/i,
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
it('`target_power` min/max must include 0 (max < 0 should fail)', async function() {
|
|
791
|
+
const app = mockApp({
|
|
792
|
+
...baseAppManifest,
|
|
793
|
+
compatibility: '>=12.13.0',
|
|
794
|
+
drivers: [{
|
|
795
|
+
...baseDriverManifest,
|
|
796
|
+
capabilities: ['target_power'],
|
|
797
|
+
capabilitiesOptions: {
|
|
798
|
+
target_power: {
|
|
799
|
+
min: -5000,
|
|
800
|
+
max: -100, // Invalid: max < 0
|
|
801
|
+
},
|
|
802
|
+
},
|
|
803
|
+
}],
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
await assertValidates(app, {
|
|
807
|
+
debug: /capabilitiesOptions\.target_power\.min\/max must include 0/i,
|
|
808
|
+
publish: /capabilitiesOptions\.target_power\.min\/max must include 0/i,
|
|
809
|
+
verified: /capabilitiesOptions\.target_power\.min\/max must include 0/i,
|
|
810
|
+
});
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
it('`target_power` valid min/max that includes 0 should pass', async function() {
|
|
814
|
+
const app = mockApp({
|
|
815
|
+
...baseAppManifest,
|
|
816
|
+
compatibility: '>=12.13.0',
|
|
817
|
+
drivers: [{
|
|
818
|
+
...baseDriverManifest,
|
|
819
|
+
capabilities: ['target_power'],
|
|
820
|
+
capabilitiesOptions: {
|
|
821
|
+
target_power: {
|
|
822
|
+
min: -5000,
|
|
823
|
+
max: 5000, // Valid: includes 0
|
|
824
|
+
},
|
|
825
|
+
},
|
|
826
|
+
}],
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
await assertValidates(app, {
|
|
830
|
+
debug: true,
|
|
831
|
+
publish: true,
|
|
832
|
+
verified: true,
|
|
833
|
+
});
|
|
834
|
+
});
|
|
593
835
|
});
|