aiohomematic-test-support 2025.12.23__py3-none-any.whl → 2026.1.23__py3-none-any.whl

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.
@@ -0,0 +1,364 @@
1
+ {
2
+ "INT0000001": "HM-CC-VG-1.json",
3
+ "VCU0000001": "HMW-RCV-50.json",
4
+ "VCU0000002": "HMW-IO-12-Sw14-DR.json",
5
+ "VCU0000004": "HMW-IO-12-Sw7-DR.json",
6
+ "VCU0000005": "HMW-IO-12-FM.json",
7
+ "VCU0000007": "HMW-IO-4-FM.json",
8
+ "VCU0000008": "HMW-IO-SR-FM.json",
9
+ "VCU0000010": "HMW-LC-Bl1-DR-2.json",
10
+ "VCU0000011": "HMW-LC-Bl1-DR.json",
11
+ "VCU0000012": "HMW-LC-Dim1L-DR.json",
12
+ "VCU0000014": "HMW-LC-Sw2-DR.json",
13
+ "VCU0000015": "HMW-Sen-SC-12-DR.json",
14
+ "VCU0000016": "HMW-Sen-SC-12-FM.json",
15
+ "VCU0000017": "HM-PB-4Dis-WM.json",
16
+ "VCU0000018": "ZEL STG RM DWT 10.json",
17
+ "VCU0000019": "263 155.json",
18
+ "VCU0000020": "HM-PB-4Dis-WM-2.json",
19
+ "VCU0000021": "HM-LC-AO-SM.json",
20
+ "VCU0000022": "ASH550I.json",
21
+ "VCU0000023": "ASH550.json",
22
+ "VCU0000024": "HM-WDS10-TH-O.json",
23
+ "VCU0000025": "263 158.json",
24
+ "VCU0000026": "HM-WDS20-TH-O.json",
25
+ "VCU0000027": "HM-WDS40-TH-I.json",
26
+ "VCU0000028": "263 157.json",
27
+ "VCU0000029": "IS-WDS-TH-OD-S-R3.json",
28
+ "VCU0000036": "HM-LC-Bl1-SM-2.json",
29
+ "VCU0000037": "HM-LC-Bl1-FM-2.json",
30
+ "VCU0000042": "HM-LC-Bl1PBU-FM.json",
31
+ "VCU0000043": "263 147.json",
32
+ "VCU0000044": "HM-LC-Bl1-SM.json",
33
+ "VCU0000045": "HM-LC-Bl1-FM.json",
34
+ "VCU0000046": "HM-LC-Bl1-PB-FM.json",
35
+ "VCU0000047": "ZEL STG RM FEP 230V.json",
36
+ "VCU0000048": "263 146.json",
37
+ "VCU0000049": "HM-LC-BlX.json",
38
+ "VCU0000050": "HM-CC-RT-DN.json",
39
+ "VCU0000051": "HM-CC-RT-DN-BoM.json",
40
+ "VCU0000053": "ZEL STG RM FWT.json",
41
+ "VCU0000054": "HM-CC-TC.json",
42
+ "VCU0000055": "HM-CC-VD.json",
43
+ "VCU0000056": "ZEL STG RM FSA.json",
44
+ "VCU0000057": "HM-RCV-50.json",
45
+ "VCU0000058": "HM-OU-CF-Pl.json",
46
+ "VCU0000059": "HM-OU-CFM-Pl.json",
47
+ "VCU0000060": "HM-OU-CFM-TW.json",
48
+ "VCU0000061": "HM-OU-CM-PCB.json",
49
+ "VCU0000062": "CMM.json",
50
+ "VCU0000064": "HM-LC-Dim1L-Pl-2.json",
51
+ "VCU0000066": "263 132.json",
52
+ "VCU0000070": "HM-LC-DDC1-PCB.json",
53
+ "VCU0000073": "HM-LC-Dim1L-Pl-3.json",
54
+ "VCU0000074": "HM-LC-Dim1L-CV-2.json",
55
+ "VCU0000078": "HM-LC-Dim1PWM-CV-2.json",
56
+ "VCU0000079": "HM-LC-Dim1PWM-CV.json",
57
+ "VCU0000081": "HM-LC-Dim1TPBU-FM-2.json",
58
+ "VCU0000082": "HM-LC-Dim1TPBU-FM.json",
59
+ "VCU0000083": "263 133.json",
60
+ "VCU0000087": "HM-LC-Dim1T-Pl-3.json",
61
+ "VCU0000088": "HM-LC-Dim1T-CV-2.json",
62
+ "VCU0000089": "HM-LC-Dim1T-FM-2.json",
63
+ "VCU0000093": "HM-LC-Dim1T-DR.json",
64
+ "VCU0000094": "HM-LC-Dim1T-FM-LF.json",
65
+ "VCU0000096": "HM-LC-Dim2L-SM-2.json",
66
+ "VCU0000098": "HM-DW-WM.json",
67
+ "VCU0000100": "HM-LC-Dim2T-SM-2.json",
68
+ "VCU0000103": "HM-LC-Dim1T-Pl-2.json",
69
+ "VCU0000105": "263 134.json",
70
+ "VCU0000108": "HM-LC-Dim1T-Pl.json",
71
+ "VCU0000109": "HM-LC-Dim1T-CV.json",
72
+ "VCU0000110": "HM-LC-Dim2T-SM.json",
73
+ "VCU0000111": "HM-LC-Dim1T-FM.json",
74
+ "VCU0000113": "HM-Dis-EP-WM55.json",
75
+ "VCU0000114": "HM-Dis-WM55.json",
76
+ "VCU0000115": "HM-LC-DW-WM.json",
77
+ "VCU0000121": "HM-LC-Dim1L-Pl.json",
78
+ "VCU0000122": "HM-LC-Dim1L-CV.json",
79
+ "VCU0000123": "HM-LC-Dim2L-CV.json",
80
+ "VCU0000124": "HM-LC-Dim2L-SM.json",
81
+ "VCU0000125": "HSS-DX.json",
82
+ "VCU0000126": "HM-MOD-EM-8.json",
83
+ "VCU0000127": "HM-MOD-EM-8Bit.json",
84
+ "VCU0000129": "HM-ES-PMSw1-Pl-DN-R1.json",
85
+ "VCU0000130": "HM-ES-PMSw1-Pl-DN-R2.json",
86
+ "VCU0000131": "HM-ES-PMSw1-Pl-DN-R3.json",
87
+ "VCU0000132": "HM-ES-PMSw1-Pl-DN-R4.json",
88
+ "VCU0000133": "HM-ES-PMSw1-Pl-DN-R5.json",
89
+ "VCU0000134": "HM-ES-PMSw1-DR.json",
90
+ "VCU0000135": "HM-ES-PMSw1-SM.json",
91
+ "VCU0000137": "HM-ES-PMSw1-Pl.json",
92
+ "VCU0000138": "HM-ES-PMSwX.json",
93
+ "VCU0000141": "HM-ES-TX-WM.json",
94
+ "VCU0000142": "HM-Dis-TD-T.json",
95
+ "VCU0000143": "HM-WDS100-C6-O-2.json",
96
+ "VCU0000144": "HM-LC-Ja1PBU-FM.json",
97
+ "VCU0000145": "HM-LC-JaX.json",
98
+ "VCU0000146": "HM-Sec-Key.json",
99
+ "VCU0000147": "HM-Sec-Key-S.json",
100
+ "VCU0000148": "HM-Sec-Key-O.json",
101
+ "VCU0000149": "HM-Sec-Key-Generic.json",
102
+ "VCU0000150": "KS550.json",
103
+ "VCU0000151": "KS888.json",
104
+ "VCU0000152": "KS550Tech.json",
105
+ "VCU0000153": "KS550LC.json",
106
+ "VCU0000154": "HM-WDS100-C6-O.json",
107
+ "VCU0000155": "OLIGO.smart.iq.HM.json",
108
+ "VCU0000158": "HM-OU-LED16.json",
109
+ "VCU0000159": "HM-OU-X.json",
110
+ "VCU0000160": "HM-PB-2-WM55-2.json",
111
+ "VCU0000164": "HM-PB-2-WM55.json",
112
+ "VCU0000165": "ZEL STG RM WT 2.json",
113
+ "VCU0000166": "263 135.json",
114
+ "VCU0000167": "HM-PB-2-FM.json",
115
+ "VCU0000168": "HM-PBI-4-FM.json",
116
+ "VCU0000169": "ZEL STG RM FST UP4.json",
117
+ "VCU0000170": "263 145.json",
118
+ "VCU0000171": "HM-PBI-X.json",
119
+ "VCU0000172": "HM-RC-4-2.json",
120
+ "VCU0000173": "HM-PB-6-WM55.json",
121
+ "VCU0000174": "HM-RC-8.json",
122
+ "VCU0000175": "HM-RC-4-3.json",
123
+ "VCU0000176": "HM-RC-4-3-D.json",
124
+ "VCU0000177": "HM-RC-Key4-2.json",
125
+ "VCU0000178": "HM-RC-Key4-3.json",
126
+ "VCU0000179": "HM-RC-Sec4-2.json",
127
+ "VCU0000180": "HM-RC-Sec4-3.json",
128
+ "VCU0000181": "HM-RC-4.json",
129
+ "VCU0000182": "HM-RC-4-B.json",
130
+ "VCU0000183": "HM-RC-P1.json",
131
+ "VCU0000184": "HM-RC-Sec3.json",
132
+ "VCU0000185": "HM-RC-Sec3-B.json",
133
+ "VCU0000186": "HM-RC-Key3.json",
134
+ "VCU0000187": "HM-RC-Key3-B.json",
135
+ "VCU0000188": "HM-PB-4-WM.json",
136
+ "VCU0000189": "HM-PB-2-WM.json",
137
+ "VCU0000190": "RC-H.json",
138
+ "VCU0000191": "atent.json",
139
+ "VCU0000192": "ZEL STG RM HS 4.json",
140
+ "VCU0000193": "HM-RC-X.json",
141
+ "VCU0000194": "HM-RC-12.json",
142
+ "VCU0000195": "HM-RC-12-B.json",
143
+ "VCU0000196": "HM-RC-12-SW.json",
144
+ "VCU0000197": "HM-RC-19.json",
145
+ "VCU0000198": "HM-RC-19-B.json",
146
+ "VCU0000199": "HM-RC-19-SW.json",
147
+ "VCU0000200": "HM-RC-2-PBU-FM.json",
148
+ "VCU0000201": "HM-RC-2-PBU-FM-2.json",
149
+ "VCU0000202": "HM-RC-Dis-H-x-EU.json",
150
+ "VCU0000203": "BRC-H.json",
151
+ "VCU0000204": "HM-RC-SB-X.json",
152
+ "VCU0000206": "HM-Sen-RD-O.json",
153
+ "VCU0000207": "HM-Sys-sRP-Pl.json",
154
+ "VCU0000208": "HM-ReSC-Win-PCB-xx.json",
155
+ "VCU0000209": "HM-LC-RGBW-WM.json",
156
+ "VCU0000211": "ZEL STG RM FDK.json",
157
+ "VCU0000212": "HM-Sec-RHS-2.json",
158
+ "VCU0000216": "HM-Sec-RHS.json",
159
+ "VCU0000217": "HM-Sec-xx.json",
160
+ "VCU0000218": "WDF solar.json",
161
+ "VCU0000236": "S550IA.json",
162
+ "VCU0000237": "HM-WDS30-T-O.json",
163
+ "VCU0000239": "ZEL STG RM FFK.json",
164
+ "VCU0000240": "HM-Sec-SC-2.json",
165
+ "VCU0000241": "HM-CC-SCD.json",
166
+ "VCU0000242": "263 160.json",
167
+ "VCU0000243": "HM-SCI-3-FM.json",
168
+ "VCU0000245": "HM-Sec-SC.json",
169
+ "VCU0000246": "HM-Sec-MDIR-3.json",
170
+ "VCU0000247": "HM-Sec-MDIR-2.json",
171
+ "VCU0000251": "HM-Sec-MDIR.json",
172
+ "VCU0000252": "263 162.json",
173
+ "VCU0000253": "HM-Sec-MD.json",
174
+ "VCU0000254": "HM-Sec-SCo.json",
175
+ "VCU0000255": "HM-Sec-SD.json",
176
+ "VCU0000256": "HM-Sec-SD-Generic.json",
177
+ "VCU0000257": "HM-Sec-SD-2.json",
178
+ "VCU0000258": "HM-Sec-SD-2-Generic.json",
179
+ "VCU0000259": "263 167.json",
180
+ "VCU0000260": "HM-Sec-SFA-SM.json",
181
+ "VCU0000261": "HM-Sec-Sir-WM.json",
182
+ "VCU0000262": "HM-Sen-DB-PCB.json",
183
+ "VCU0000263": "HM-Sen-EP.json",
184
+ "VCU0000264": "HM-Sen-X.json",
185
+ "VCU0000265": "HM-Sen-LI-O.json",
186
+ "VCU0000266": "HM-Sen-MDIR-O-3.json",
187
+ "VCU0000267": "HM-Sen-MDIR-O-2.json",
188
+ "VCU0000271": "HM-Sen-MDIR-SM.json",
189
+ "VCU0000272": "HM-Sen-MDIR-O.json",
190
+ "VCU0000273": "HM-MD.json",
191
+ "VCU0000274": "HM-Sen-MDIR-WM55.json",
192
+ "VCU0000275": "HM-Sen-Wa-Od.json",
193
+ "VCU0000276": "ST6-SH.json",
194
+ "VCU0000277": "HM-SwI-3-FM.json",
195
+ "VCU0000278": "ZEL STG RM FSS UP3.json",
196
+ "VCU0000279": "263 144.json",
197
+ "VCU0000280": "HM-SwI-X.json",
198
+ "VCU0000285": "HM-LC-Sw1PBU-FM.json",
199
+ "VCU0000286": "263 131.json",
200
+ "VCU0000287": "HM-LC-Sw2PBU-FM.json",
201
+ "VCU0000288": "HM-LC-Sw4-Ba-PCB.json",
202
+ "VCU0000289": "HM-LC-Sw1-Pl-3.json",
203
+ "VCU0000290": "HM-LC-Sw1-SM-2.json",
204
+ "VCU0000292": "HM-LC-Sw4-SM-2.json",
205
+ "VCU0000293": "HM-LC-Sw4-PCB-2.json",
206
+ "VCU0000294": "HM-LC-Sw4-WM-2.json",
207
+ "VCU0000295": "HM-LC-Sw1-FM-2.json",
208
+ "VCU0000296": "HM-LC-Sw2-FM-2.json",
209
+ "VCU0000297": "HM-LC-Sw4-DR-2.json",
210
+ "VCU0000298": "HM-LC-Sw2-DR-2.json",
211
+ "VCU0000299": "HM-LC-Sw1-Pl-DN-R1.json",
212
+ "VCU0000300": "HM-LC-Sw1-Pl-DN-R2.json",
213
+ "VCU0000301": "HM-LC-Sw1-Pl-DN-R3.json",
214
+ "VCU0000302": "HM-LC-Sw1-Pl-DN-R4.json",
215
+ "VCU0000303": "HM-LC-Sw1-Pl-DN-R5.json",
216
+ "VCU0000304": "HM-LC-Sw1-DR.json",
217
+ "VCU0000305": "HM-LC-Sw1-Pl-CT-R1.json",
218
+ "VCU0000306": "HM-LC-Sw1-Pl-CT-R2.json",
219
+ "VCU0000307": "HM-LC-Sw1-Pl-CT-R3.json",
220
+ "VCU0000308": "HM-LC-Sw1-Pl-CT-R4.json",
221
+ "VCU0000309": "HM-LC-Sw1-Pl-CT-R5.json",
222
+ "VCU0000310": "HM-LC-Sw1-PCB.json",
223
+ "VCU0000311": "HM-MOD-Re-8.json",
224
+ "VCU0000312": "HM-LC-Sw1-Ba-PCB.json",
225
+ "VCU0000321": "HM-LC-Sw1-Pl.json",
226
+ "VCU0000322": "HM-LC-Sw1-Pl-2.json",
227
+ "VCU0000323": "HM-LC-Sw1-SM.json",
228
+ "VCU0000324": "HM-LC-Sw2-SM.json",
229
+ "VCU0000325": "HM-LC-Sw4-SM.json",
230
+ "VCU0000326": "HM-LC-Sw4-PCB.json",
231
+ "VCU0000327": "HM-LC-Sw4-WM.json",
232
+ "VCU0000328": "HM-LC-Sw1-FM.json",
233
+ "VCU0000329": "263 130.json",
234
+ "VCU0000330": "HM-LC-Sw2-FM.json",
235
+ "VCU0000331": "HM-LC-Sw1-PB-FM.json",
236
+ "VCU0000332": "HM-LC-Sw2-PB-FM.json",
237
+ "VCU0000333": "HM-LC-Sw4-DR.json",
238
+ "VCU0000334": "HM-LC-Sw2-DR.json",
239
+ "VCU0000335": "ZEL STG RM FZS.json",
240
+ "VCU0000336": "ZEL STG RM FZS-2.json",
241
+ "VCU0000337": "HM-LC-SwX.json",
242
+ "VCU0000338": "HM-LC-Sw1-Pl-OM54.json",
243
+ "VCU0000339": "HM-LC-Sw1-SM-ATmega168.json",
244
+ "VCU0000340": "HM-LC-Sw4-SM-ATmega168.json",
245
+ "VCU0000341": "HM-TC-IT-WM-W-EU.json",
246
+ "VCU0000343": "HM-Sec-TiS.json",
247
+ "VCU0000344": "HM-WDS30-OT2-SM.json",
248
+ "VCU0000345": "HM-WDS30-OT2-SM-2.json",
249
+ "VCU0000346": "HM-WDS40-TH-I-2.json",
250
+ "VCU0000348": "HM-Sec-WDS.json",
251
+ "VCU0000349": "HM-Sec-WDS-2.json",
252
+ "VCU0000350": "HM-Sec-Win.json",
253
+ "VCU0000351": "HM-Sec-Win-Generic.json",
254
+ "VCU0000352": "WS550.json",
255
+ "VCU0000353": "WS888.json",
256
+ "VCU0000354": "WS550Tech.json",
257
+ "VCU0000355": "WS550LCB.json",
258
+ "VCU0000356": "WS550LCW.json",
259
+ "VCU0000357": "HM-WDC7000.json",
260
+ "VCU1004487": "HmIPW-DRAP.json",
261
+ "VCU1111390": "HmIP-HDM2.json",
262
+ "VCU1150287": "HmIP-HAP.json",
263
+ "VCU1152627": "HmIP-RC8.json",
264
+ "VCU1223813": "HmIP-FBL.json",
265
+ "VCU1260322": "HmIP-RFUSB.json",
266
+ "VCU1289997": "HmIP-SPDR.json",
267
+ "VCU1362746": "HmIP-SWO-PR.json",
268
+ "VCU1366171": "HMIP-PS.json",
269
+ "VCU1399816": "HmIP-BDT.json",
270
+ "VCU1437294": "HmIP-SMI.json",
271
+ "VCU1494703": "HmIP-eTRV-E.json",
272
+ "VCU1533290": "HmIP-WRC6.json",
273
+ "VCU1543608": "HmIP-MP3P.json",
274
+ "VCU1673350": "HmIPW-FIO6.json",
275
+ "VCU1768323": "HmIP-eTRV-C-2.json",
276
+ "VCU1769958": "HmIP-BWTH.json",
277
+ "VCU1803301": "HmIP-USBSM.json",
278
+ "VCU1815001": "HmIP-SWD.json",
279
+ "VCU1841406": "HmIP-SWO-PL.json",
280
+ "VCU1891174": "HmIPW-DRS8.json",
281
+ "VCU1954019": "HmIP-FAL230-C10.json",
282
+ "VCU2118827": "HmIP-DLS.json",
283
+ "VCU2128127": "HmIP-BSM.json",
284
+ "VCU2333555": "HmIP-FSI16.json",
285
+ "VCU2407364": "HmIP-PCBS.json",
286
+ "VCU2428569": "HmIPW-FAL230-C6.json",
287
+ "VCU2573721": "HmIP-SMO-2.json",
288
+ "VCU2680226": "HmIP-WTH-2.json",
289
+ "VCU2721398": "HmIPW-DRI32.json",
290
+ "VCU2737768": "HMIP-SWDO.json",
291
+ "VCU2822385": "HmIP-SWSD.json",
292
+ "VCU2826390": "HmIPW-STH.json",
293
+ "VCU2913614": "HmIP-WHS2.json",
294
+ "VCU3015080": "HmIP-SCI.json",
295
+ "VCU3056370": "HmIP-SLO.json",
296
+ "VCU3188750": "HmIP-WGC.json",
297
+ "VCU3432945": "HmIP-STV.json",
298
+ "VCU3560967": "HmIP-HDM1.json",
299
+ "VCU3609622": "HmIP-eTRV-2.json",
300
+ "VCU3790312": "HmIP-SWO-B.json",
301
+ "VCU3880755": "HB-UNI-Sensor-THPD-BME280.json",
302
+ "VCU3941846": "HMIP-PSM.json",
303
+ "VCU4070501": "HmIP-FSM16.json",
304
+ "VCU4243444": "HmIP-WRCD.json",
305
+ "VCU4264293": "HmIP-RCV-50.json",
306
+ "VCU4523900": "HmIP-STHO.json",
307
+ "VCU4567298": "HmIP-DBB.json",
308
+ "VCU4613288": "HmIP-FROLL.json",
309
+ "VCU4704397": "HmIPW-WRC6.json",
310
+ "VCU4743739": "HmIPW-SPI.json",
311
+ "VCU4898089": "HmIP-KRC4.json",
312
+ "VCU4984404": "HmIPW-STHD.json",
313
+ "VCU5092447": "HmIP-SMO-A.json",
314
+ "VCU5334484": "HmIP-KRCA.json",
315
+ "VCU5424977": "HmIP-DSD-PCB.json",
316
+ "VCU5429697": "HmIP-SAM.json",
317
+ "VCU5597068": "HmIPW-SMI55.json",
318
+ "VCU5628817": "HmIP-SMO.json",
319
+ "VCU5644414": "HmIP-SWDM.json",
320
+ "VCU5778428": "HmIP-HEATING.json",
321
+ "VCU5801873": "HmIP-PMFS.json",
322
+ "VCU5864966": "HmIP-SWDO-I.json",
323
+ "VCU5980155": "HmIP-PCBS-BAT.json",
324
+ "VCU6153495": "HmIP-FCI1.json",
325
+ "VCU6306084": "HmIP-BRC2.json",
326
+ "VCU6354483": "HmIP-STHD.json",
327
+ "VCU6531931": "HmIP-RCB1.json",
328
+ "VCU6874371": "HmIP-MOD-RC8.json",
329
+ "VCU6948166": "HmIP-DRDI3.json",
330
+ "VCU6977344": "HmIP-MIO16-PCB.json",
331
+ "VCU6985973": "HmIP-BSL.json",
332
+ "VCU7171997": "HB-WDS40-THP-O.json",
333
+ "VCU7204276": "HmIP-DRSI4.json",
334
+ "VCU7447418": "HmIP-PCBS2.json",
335
+ "VCU7549831": "HmIP-STE2-PCB.json",
336
+ "VCU7631078": "HmIP-FDT.json",
337
+ "VCU7652142": "HmIP-SRD.json",
338
+ "VCU7807849": "HmIPW-DRBL4.json",
339
+ "VCU7808411": "HmIP-eTRV-B1.json",
340
+ "VCU7935803": "HMIP-WRC2.json",
341
+ "VCU7981740": "HmIP-SRH.json",
342
+ "VCU8063453": "HmIP-STH.json",
343
+ "VCU8066814": "RPI-RF-MOD.json",
344
+ "VCU8126977": "HmIP-MOD-OC8.json",
345
+ "VCU8205532": "HmIP-SCTH230.json",
346
+ "VCU8249617": "HmIP-ASIR-2.json",
347
+ "VCU8255833": "HmIP-STHO-A.json",
348
+ "VCU8333683": "HmIP-SWDM-B2.json",
349
+ "VCU8451105": "HmIPW-WTH.json",
350
+ "VCU8492627": "HB-UNI-Sensor1.json",
351
+ "VCU8537918": "HmIP-BROLL.json",
352
+ "VCU8539034": "HmIP-WRCR.json",
353
+ "VCU8585352": "HmIP-DRSI1.json",
354
+ "VCU8655720": "HmIP-CCU3.json",
355
+ "VCU8688276": "HmIP-eTRV-B.json",
356
+ "VCU9333179": "HmIP-ASIR.json",
357
+ "VCU9344471": "HmIP-SPI.json",
358
+ "VCU9628024": "HmIPW-FALMOT-C12.json",
359
+ "VCU9710932": "HmIP-SMI55.json",
360
+ "VCU9724704": "HmIP-DLD.json",
361
+ "VCU9834159": "HB-LC-Bl1PBU-FM.json",
362
+ "VCU9933791": "HmIPW-DRD3.json",
363
+ "VCU9981826": "HmIP-SFD.json"
364
+ }
@@ -0,0 +1,257 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2021-2026
3
+ """
4
+ Event capture utilities for test verification.
5
+
6
+ This module provides tools for capturing and asserting events in tests,
7
+ enabling behavior-focused testing through event verification.
8
+
9
+ Public API
10
+ ----------
11
+ - EventCapture: Capture events for test verification
12
+ - EventSequenceAssertion: Verify event ordering
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from collections.abc import Callable
18
+ from dataclasses import dataclass, field
19
+ from typing import TYPE_CHECKING, Any, TypeVar
20
+
21
+ if TYPE_CHECKING:
22
+ from aiohomematic.central.events import Event, EventBus
23
+
24
+ T = TypeVar("T", bound="Event")
25
+
26
+
27
+ @dataclass
28
+ class EventCapture:
29
+ """
30
+ Capture events from EventBus for test verification.
31
+
32
+ Provides methods to subscribe to events, capture them, and make assertions
33
+ about what events were emitted during test execution.
34
+
35
+ Example:
36
+ -------
37
+ capture = EventCapture()
38
+ capture.subscribe_to(event_bus, CircuitBreakerTrippedEvent)
39
+
40
+ # ... perform test actions ...
41
+
42
+ capture.assert_event_emitted(
43
+ CircuitBreakerTrippedEvent,
44
+ interface_id="test",
45
+ failure_count=5,
46
+ )
47
+ capture.cleanup()
48
+
49
+ """
50
+
51
+ captured_events: list[Event] = field(default_factory=list)
52
+ """List of all captured events."""
53
+
54
+ _unsubscribers: list[Callable[[], None]] = field(default_factory=list)
55
+ """Unsubscribe callbacks for cleanup."""
56
+
57
+ def assert_event_emitted(
58
+ self,
59
+ *,
60
+ event_type: type[Event],
61
+ count: int | None = None,
62
+ **expected_attrs: Any,
63
+ ) -> None:
64
+ """
65
+ Assert that an event with specific attributes was emitted.
66
+
67
+ Args:
68
+ event_type: The expected event type
69
+ count: If provided, assert exactly this many events were emitted
70
+ **expected_attrs: Expected attribute values on the event
71
+
72
+ Raises:
73
+ AssertionError: If no matching event found or count mismatch
74
+
75
+ """
76
+ events = self.get_events_of_type(event_type=event_type)
77
+
78
+ if count is not None and len(events) != count:
79
+ raise AssertionError(f"Expected {count} {event_type.__name__} events, got {len(events)}")
80
+
81
+ if not expected_attrs:
82
+ if not events:
83
+ raise AssertionError(f"No {event_type.__name__} events captured")
84
+ return
85
+
86
+ for event in events:
87
+ if all(getattr(event, k, None) == v for k, v in expected_attrs.items()):
88
+ return
89
+
90
+ raise AssertionError(
91
+ f"No {event_type.__name__} found with attributes {expected_attrs}. Captured {len(events)} events: {events}"
92
+ )
93
+
94
+ def assert_no_event(self, *, event_type: type[Event]) -> None:
95
+ """
96
+ Assert that no events of a specific type were emitted.
97
+
98
+ Args:
99
+ event_type: The event type that should not exist
100
+
101
+ Raises:
102
+ AssertionError: If any events of that type were captured
103
+
104
+ """
105
+ if events := self.get_events_of_type(event_type=event_type):
106
+ raise AssertionError(f"Expected no {event_type.__name__} events, but found {len(events)}: {events}")
107
+
108
+ def cleanup(self) -> None:
109
+ """Unsubscribe from all events and clear captured events."""
110
+ for unsub in self._unsubscribers:
111
+ unsub()
112
+ self._unsubscribers.clear()
113
+ self.captured_events.clear()
114
+
115
+ def clear(self) -> None:
116
+ """Clear all captured events."""
117
+ self.captured_events.clear()
118
+
119
+ def get_event_count(self, *, event_type: type[Event]) -> int:
120
+ """
121
+ Return count of captured events of a specific type.
122
+
123
+ Args:
124
+ event_type: The event type to count
125
+
126
+ Returns:
127
+ Number of events of that type
128
+
129
+ """
130
+ return len(self.get_events_of_type(event_type=event_type))
131
+
132
+ def get_events_of_type(self, *, event_type: type[T]) -> list[T]:
133
+ """
134
+ Return all captured events of a specific type.
135
+
136
+ Args:
137
+ event_type: The event type to filter by
138
+
139
+ Returns:
140
+ List of events matching the type
141
+
142
+ """
143
+ return [e for e in self.captured_events if isinstance(e, event_type)]
144
+
145
+ def subscribe_to(self, event_bus: EventBus, *event_types: type[Event]) -> None:
146
+ """
147
+ Subscribe to specific event types on the EventBus.
148
+
149
+ Args:
150
+ event_bus: The EventBus to subscribe to
151
+ *event_types: Event types to capture
152
+
153
+ """
154
+ for event_type in event_types:
155
+ self._unsubscribers.append(
156
+ event_bus.subscribe(
157
+ event_type=event_type,
158
+ event_key=None,
159
+ handler=self._capture_handler,
160
+ )
161
+ )
162
+
163
+ def _capture_handler(self, *, event: Event) -> None:
164
+ """Handle event by capturing it."""
165
+ self.captured_events.append(event)
166
+
167
+
168
+ @dataclass
169
+ class EventSequenceAssertion:
170
+ """
171
+ Assert events occur in expected sequence.
172
+
173
+ Useful for verifying state machine transitions and multi-step processes.
174
+
175
+ Example:
176
+ -------
177
+ sequence = EventSequenceAssertion(expected_sequence=[
178
+ ConnectionStageChangedEvent,
179
+ ClientStateChangedEvent,
180
+ CentralStateChangedEvent,
181
+ ])
182
+ event_bus.subscribe(Event, sequence.on_event)
183
+
184
+ # ... perform actions ...
185
+
186
+ sequence.verify()
187
+
188
+ """
189
+
190
+ expected_sequence: list[type[Event]]
191
+ """The expected sequence of event types."""
192
+
193
+ captured_types: list[type[Event]] = field(default_factory=list)
194
+ """Captured event types in order."""
195
+
196
+ def on_event(self, *, event: Event) -> None:
197
+ """
198
+ Handle event by capturing its type.
199
+
200
+ Args:
201
+ event: The event that was published
202
+
203
+ """
204
+ self.captured_types.append(type(event))
205
+
206
+ def reset(self) -> None:
207
+ """Reset captured types for reuse."""
208
+ self.captured_types.clear()
209
+
210
+ def verify(self, *, strict: bool = False) -> None:
211
+ """
212
+ Verify the captured sequence matches expected.
213
+
214
+ Args:
215
+ strict: If True, require exact sequence match.
216
+ If False, verify expected events appear in order
217
+ (other events may be interspersed).
218
+
219
+ Raises:
220
+ AssertionError: If sequence doesn't match
221
+
222
+ """
223
+ if strict:
224
+ self._verify_strict()
225
+ else:
226
+ self._verify_subsequence()
227
+
228
+ def _verify_strict(self) -> None:
229
+ """Verify exact sequence match."""
230
+ if len(self.captured_types) != len(self.expected_sequence):
231
+ raise AssertionError(
232
+ f"Expected {len(self.expected_sequence)} events, "
233
+ f"got {len(self.captured_types)}.\n"
234
+ f"Expected: {[e.__name__ for e in self.expected_sequence]}\n"
235
+ f"Got: {[e.__name__ for e in self.captured_types]}"
236
+ )
237
+
238
+ for i, (expected, actual) in enumerate(zip(self.expected_sequence, self.captured_types, strict=True)):
239
+ if expected != actual:
240
+ raise AssertionError(f"Event {i}: expected {expected.__name__}, got {actual.__name__}")
241
+
242
+ def _verify_subsequence(self) -> None:
243
+ """Verify expected events appear in order (non-strict)."""
244
+ expected_idx = 0
245
+ for actual_type in self.captured_types:
246
+ if expected_idx >= len(self.expected_sequence):
247
+ break
248
+ if actual_type == self.expected_sequence[expected_idx]:
249
+ expected_idx += 1
250
+
251
+ if expected_idx < len(self.expected_sequence):
252
+ missing = self.expected_sequence[expected_idx:]
253
+ raise AssertionError(
254
+ f"Missing expected events in sequence: {[e.__name__ for e in missing]}\n"
255
+ f"Expected: {[e.__name__ for e in self.expected_sequence]}\n"
256
+ f"Got: {[e.__name__ for e in self.captured_types]}"
257
+ )