conson-xp 1.50.1__py3-none-any.whl → 1.51.1__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.
- {conson_xp-1.50.1.dist-info → conson_xp-1.51.1.dist-info}/METADATA +2 -1
- {conson_xp-1.50.1.dist-info → conson_xp-1.51.1.dist-info}/RECORD +21 -16
- xp/__init__.py +1 -1
- xp/cli/commands/conbus/conbus_export_commands.py +8 -2
- xp/cli/commands/term/term_commands.py +23 -0
- xp/models/homekit/homekit_config.py +2 -0
- xp/models/term/__init__.py +2 -0
- xp/models/term/accessory_state.py +50 -0
- xp/services/conbus/actiontable/actiontable_download_service.py +2 -0
- xp/services/conbus/conbus_export_actiontable_service.py +47 -27
- xp/services/homekit/homekit_config_validator.py +1 -1
- xp/services/term/homekit_service.py +512 -0
- xp/services/term/state_monitor_service.py +1 -1
- xp/term/homekit.py +116 -0
- xp/term/homekit.tcss +86 -0
- xp/term/widgets/room_list.py +232 -0
- xp/term/widgets/status_footer.py +6 -3
- xp/utils/dependencies.py +33 -0
- {conson_xp-1.50.1.dist-info → conson_xp-1.51.1.dist-info}/WHEEL +0 -0
- {conson_xp-1.50.1.dist-info → conson_xp-1.51.1.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.50.1.dist-info → conson_xp-1.51.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: conson-xp
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.51.1
|
|
4
4
|
Summary: XP Protocol Communication Tools
|
|
5
5
|
Author-Email: ldvchosal <ldvchosal@github.com>
|
|
6
6
|
License: MIT License
|
|
@@ -450,6 +450,7 @@ xp telegram version
|
|
|
450
450
|
|
|
451
451
|
|
|
452
452
|
xp term
|
|
453
|
+
xp term homekit
|
|
453
454
|
xp term protocol
|
|
454
455
|
xp term state
|
|
455
456
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
conson_xp-1.
|
|
2
|
-
conson_xp-1.
|
|
3
|
-
conson_xp-1.
|
|
4
|
-
conson_xp-1.
|
|
5
|
-
xp/__init__.py,sha256=
|
|
1
|
+
conson_xp-1.51.1.dist-info/METADATA,sha256=15wTMgVInRD7kUjYvZe3AtZPgmPGG_XcXsaGRB3Vjds,11448
|
|
2
|
+
conson_xp-1.51.1.dist-info/WHEEL,sha256=tsUv_t7BDeJeRHaSrczbGeuK-TtDpGsWi_JfpzD255I,90
|
|
3
|
+
conson_xp-1.51.1.dist-info/entry_points.txt,sha256=1OcdIcDM1hz3ljCXgybaPUh1IOFEwkaTgLIW9u9zGeg,50
|
|
4
|
+
conson_xp-1.51.1.dist-info/licenses/LICENSE,sha256=rxj6woMM-r3YCyGq_UHFtbh7kHTAJgrccH6O-33IDE4,1419
|
|
5
|
+
xp/__init__.py,sha256=PTmuTUb4TXiPuSSkKX3UT63IhH_fx4EpMP33cMsA6Nc,182
|
|
6
6
|
xp/cli/__init__.py,sha256=QjnKB1KaI2aIyKlzrnvCwfbBuUj8HNgwNMvNJVQofbI,81
|
|
7
7
|
xp/cli/__main__.py,sha256=l2iKwMdat5rTGd3JWs-uGksnYYDDffp_Npz05QdKEeU,117
|
|
8
8
|
xp/cli/commands/__init__.py,sha256=G7A1KFRSV0CEeDTqr_khu-K9_sc01CTI2KSfkFcaBRM,4949
|
|
@@ -16,7 +16,7 @@ xp/cli/commands/conbus/conbus_custom_commands.py,sha256=TqWo45yqEp_ezmKZ0tymQ0C4
|
|
|
16
16
|
xp/cli/commands/conbus/conbus_datapoint_commands.py,sha256=uYsvi37vl2od2XJB0semAF0sH3UrRWTt_qHnBmUBR-w,3788
|
|
17
17
|
xp/cli/commands/conbus/conbus_discover_commands.py,sha256=gSK5Y4lespNKFNgGtp7VkqStGe4fWxDNNfyPPuJiwXQ,1931
|
|
18
18
|
xp/cli/commands/conbus/conbus_event_commands.py,sha256=faaSGRNtJCttk-0VO5Z4m4Zz37aOsSgmbuzWbTOUZIQ,3103
|
|
19
|
-
xp/cli/commands/conbus/conbus_export_commands.py,sha256=
|
|
19
|
+
xp/cli/commands/conbus/conbus_export_commands.py,sha256=pWZlS0MMcc8sZAfXx8xMSn53NT5cg3HpF-msBOU7whI,5992
|
|
20
20
|
xp/cli/commands/conbus/conbus_lightlevel_commands.py,sha256=WH4ZQHxSbquPlAqd0uRxq8VR-sO4_AnfseMqaoPoGoA,7092
|
|
21
21
|
xp/cli/commands/conbus/conbus_linknumber_commands.py,sha256=3bkik8nHXY89XfzeUnKWmvKA70r4qJJ79j8FfLL4sL0,3556
|
|
22
22
|
xp/cli/commands/conbus/conbus_modulenumber_commands.py,sha256=fOIO0f85iDJBfGnRCEN8zK6j4i43uuF_9YKQc_nQ39A,3628
|
|
@@ -43,7 +43,7 @@ xp/cli/commands/telegram/telegram_parse_commands.py,sha256=xCDRRFgj41RtStvwROfi-
|
|
|
43
43
|
xp/cli/commands/telegram/telegram_version_commands.py,sha256=hAMjSAa7zfMNfNFln63sKeNPcmW89bISkcVs6BgsqOg,1558
|
|
44
44
|
xp/cli/commands/term/__init__.py,sha256=1NNST_8YJfj5LCujQISwQflK6LyEn7mDmZpMpvI9d-o,116
|
|
45
45
|
xp/cli/commands/term/term.py,sha256=gjvsv2OE-F_KNWQrWi04fXQ5cGo0l8P-Ortbb5KTA-A,309
|
|
46
|
-
xp/cli/commands/term/term_commands.py,sha256=
|
|
46
|
+
xp/cli/commands/term/term_commands.py,sha256=Z3pq_xzP0j5YfYFOwASaZUxXDkikSV_E4cFjMb69LUU,1796
|
|
47
47
|
xp/cli/main.py,sha256=Wbtji5ddW3IEoAfecHrEPk8W_w1bGD20B-NqAWfI_F4,1968
|
|
48
48
|
xp/cli/utils/__init__.py,sha256=gTGIj60Uai0iE7sr9_TtEpl04fD7krtTzbbigXUsUVU,46
|
|
49
49
|
xp/cli/utils/click_tree.py,sha256=sr4l9RWTCnASkdvkJKnRRxWSQPlF1DbFdBNu9gL7Ekc,1693
|
|
@@ -84,7 +84,7 @@ xp/models/config/__init__.py,sha256=gEZnX9eE3DjFtLtF32riEjJQLypqQRbyPauBI4Cowbs,
|
|
|
84
84
|
xp/models/config/conson_module_config.py,sha256=t1G0LnNNMnjs3ahhz4-Z_5SlEv2FCrcRq13OmvZ2pvA,3009
|
|
85
85
|
xp/models/homekit/__init__.py,sha256=5HDSOClCu0ArK3IICn3_LDMMLBAzLjBxUUSF73bxSSk,34
|
|
86
86
|
xp/models/homekit/homekit_accessory.py,sha256=ANjDWlFxeNTstl7lKdmf6vMOC0wc005vpiD6awRcptA,1052
|
|
87
|
-
xp/models/homekit/homekit_config.py,sha256=
|
|
87
|
+
xp/models/homekit/homekit_config.py,sha256=EqoiZ1E6l9bBjxKqK1nxVGRfFY5ZtRHH-jZhYtRH2gU,3048
|
|
88
88
|
xp/models/log_entry.py,sha256=tAiNwouCP2d4jKiHJY9a-2iAi8LWTpG-TZsOPDIstlA,4423
|
|
89
89
|
xp/models/protocol/__init__.py,sha256=TJ_CJKchA-xgQiv5vCo_ndBBZjrcaTmjT74bR0T-5Cw,38
|
|
90
90
|
xp/models/protocol/conbus_protocol.py,sha256=hF78N5xvBzMiyWoKd8i_avA8kJ1As_9Pplkw1GMqKzk,9145
|
|
@@ -105,7 +105,8 @@ xp/models/telegram/system_telegram.py,sha256=064AlFi_WghoYlVDUtIIbvwtZyUEZj7_auK
|
|
|
105
105
|
xp/models/telegram/telegram.py,sha256=-kNloBlwMJ5w1-FAMSLzBPnyOGUNEBG3SG2d0eTi2PY,847
|
|
106
106
|
xp/models/telegram/telegram_type.py,sha256=IjGEosbs7IDqYT7ktn-FcKS-kAJ4eXW-KJGkkoAGysw,428
|
|
107
107
|
xp/models/telegram/timeparam_type.py,sha256=z5EQ32SQjDi7zKshtkvDzqaMfPMUeXCWKEGI5VgvBvU,1142
|
|
108
|
-
xp/models/term/__init__.py,sha256=
|
|
108
|
+
xp/models/term/__init__.py,sha256=VVZsEyXBEr-TnBlrFFifZ6PjJHUl2kwnRUZx_kC2Ljg,343
|
|
109
|
+
xp/models/term/accessory_state.py,sha256=GcMtCxOeHpc3IPDO1F9j2I6rdhaNV75iQ2md--XY6jo,1650
|
|
109
110
|
xp/models/term/connection_state.py,sha256=oYcst01uH35kO541jGuXMqvJ2iduiHYryUsMK0d89pQ,1807
|
|
110
111
|
xp/models/term/module_state.py,sha256=i7u8y_B5ScMRULQb_kMSD_wwKzbrLHlkECsTgNS46PQ,939
|
|
111
112
|
xp/models/term/protocol_keys_config.py,sha256=tSlkxEwgQuVRYLTaUNd569osQsNCdb9ED4InNgX9rKo,1223
|
|
@@ -123,7 +124,7 @@ xp/services/actiontable/msactiontable_xp33_serializer.py,sha256=9JzG9dOrfamu8Ujs
|
|
|
123
124
|
xp/services/actiontable/serializer_protocol.py,sha256=PMsZbPwPQD1MJYo_KpZSgpnVQCtXFXSfzXFpCiA6Xi8,2002
|
|
124
125
|
xp/services/conbus/__init__.py,sha256=Hi35sMKu9o6LpYoi2tQDaQoMb8M5sOt_-LUTxxaCU_0,28
|
|
125
126
|
xp/services/conbus/actiontable/__init__.py,sha256=oD6vRk_Ye-eZ9s_hldAgtRJFu4mfAnODqpkJUGHHszk,40
|
|
126
|
-
xp/services/conbus/actiontable/actiontable_download_service.py,sha256=
|
|
127
|
+
xp/services/conbus/actiontable/actiontable_download_service.py,sha256=41Hr1753IBpUeHQqO57uS7qxOB0rJt8qCpznzKlUPOM,15028
|
|
127
128
|
xp/services/conbus/actiontable/actiontable_list_service.py,sha256=oTDSpBkp-MJeaF5bhRnwkSy3na55xqQ4e2ykJzbMCUo,3236
|
|
128
129
|
xp/services/conbus/actiontable/actiontable_show_service.py,sha256=WISY2VsmSlceGa5_9lpFO-gs5TnTjv6YidQksUjCapk,3058
|
|
129
130
|
xp/services/conbus/actiontable/actiontable_upload_service.py,sha256=FaQzOSg8s2zUL5xz9qZY9fvzrdDosc3CoxkVDvNg2SU,13252
|
|
@@ -135,7 +136,7 @@ xp/services/conbus/conbus_datapoint_service.py,sha256=WBQC42-6xuPWhMKKRtHtRzwEmV
|
|
|
135
136
|
xp/services/conbus/conbus_discover_service.py,sha256=mvqjHFMmEkQjHD9YDIk9gE8MowPMkOIJRmyjX96G5pw,12868
|
|
136
137
|
xp/services/conbus/conbus_event_list_service.py,sha256=-jl3WHpyidbh-h4NMK2gERqu48mTNFD6rpPo2EyGxeg,3641
|
|
137
138
|
xp/services/conbus/conbus_event_raw_service.py,sha256=viXuEXw165-RytdqC76wQShJLD7Yd0rtURxWZZ8hyKA,7060
|
|
138
|
-
xp/services/conbus/conbus_export_actiontable_service.py,sha256=
|
|
139
|
+
xp/services/conbus/conbus_export_actiontable_service.py,sha256=d6Y2RDiVOH-jTMWOIE_gY_WBJnHFrbJGguk-WZWbNPs,11818
|
|
139
140
|
xp/services/conbus/conbus_export_service.py,sha256=RP8nADTIs4FGUf_BFLRZMtEJZdXV94zg3QrlWaDnhKA,17536
|
|
140
141
|
xp/services/conbus/conbus_output_service.py,sha256=e57bRkLgPnJuB8hkllNh0kgGkjPt9IK75tuBxd_bOkE,9361
|
|
141
142
|
xp/services/conbus/conbus_raw_service.py,sha256=OQuV521VOQraf2PGF2B9868vh7sDgmfc19YebrkZnyw,5844
|
|
@@ -145,7 +146,7 @@ xp/services/conbus/write_config_service.py,sha256=BCfmLNPRDpwSwRMRYJvx2FXA8IZsdg
|
|
|
145
146
|
xp/services/homekit/__init__.py,sha256=xAMKmln_AmEFdOOJGKWYi96seRlKDQpKx3-hm7XbdIo,36
|
|
146
147
|
xp/services/homekit/homekit_cache_service.py,sha256=z1TB6icEqd1paoilVTewuFL0lXVCQbvrOJkJvvQECJY,11060
|
|
147
148
|
xp/services/homekit/homekit_conbus_service.py,sha256=XPKv7Mit1rn7XLaQZcKmlMMUlyj-o0J2z8XBH3NaEIM,3390
|
|
148
|
-
xp/services/homekit/homekit_config_validator.py,sha256=
|
|
149
|
+
xp/services/homekit/homekit_config_validator.py,sha256=jf09jHIFbZg7YpDbGsGHT1p4a1vpUED2xR6iZN19cfM,10875
|
|
149
150
|
xp/services/homekit/homekit_conson_validator.py,sha256=tmUxBzytX9FbUWTR1XdbAi_qb_whAdGPSaml98Czszg,3858
|
|
150
151
|
xp/services/homekit/homekit_dimminglight.py,sha256=EzfGhy3zZkbFPfN72Dh_eSb5mJQOpxGi6ZwnyEOSHxU,5819
|
|
151
152
|
xp/services/homekit/homekit_dimminglight_service.py,sha256=0Ve6cXtY7v7JCv7gibOBWjPfCU7KK4Lk6GjIu9_GhyE,5282
|
|
@@ -184,9 +185,12 @@ xp/services/telegram/telegram_output_service.py,sha256=9deqtcPndRqJ-3XQUWlJhXaVc
|
|
|
184
185
|
xp/services/telegram/telegram_service.py,sha256=jPu0Xrh3IpvqPLyuQT5Vf8HHw00vBingONHdxf_9TkI,13315
|
|
185
186
|
xp/services/telegram/telegram_version_service.py,sha256=oXnZ_K7OQ7xD-GEj3zDYp52KlkqVuHpO4bf7gMlC_w4,10574
|
|
186
187
|
xp/services/term/__init__.py,sha256=BIeOK042bMR-0l6MA80wdW5VuHlpWOXtRER9IG5ilQA,245
|
|
188
|
+
xp/services/term/homekit_service.py,sha256=3g6Twhg6wcRT2E01Daa2J41lzdyX6gVjfz5wgutOvgQ,19307
|
|
187
189
|
xp/services/term/protocol_monitor_service.py,sha256=5YBI0Nu7B7gMhaTbUhL6k9LSRfnCIj6CwrCYHiMHavA,10067
|
|
188
|
-
xp/services/term/state_monitor_service.py,sha256=
|
|
190
|
+
xp/services/term/state_monitor_service.py,sha256=EK9tNBfamAIV0z0EMsXDYWC-rXv6l6k_bHsC8xyEFSo,17116
|
|
189
191
|
xp/term/__init__.py,sha256=Xg2DhBeI3xQJLfc7_BPWI1por-rUXemyer5OtOt9Cus,51
|
|
192
|
+
xp/term/homekit.py,sha256=IYJEVhQUFUcmC_TubYxcvlU5IKF-2sL_giBNKO35fjU,3642
|
|
193
|
+
xp/term/homekit.tcss,sha256=qeR_OV8D_9Mxb-aPNz-MH0ZJOsdCk-fJ-zv6CQV5ihw,1382
|
|
190
194
|
xp/term/protocol.py,sha256=6MX3mduLei-AgLGaIe8lfOSu4Hi0y3KGePFFM2ssstc,3475
|
|
191
195
|
xp/term/protocol.tcss,sha256=r_KfxrbpycGHLVXqZc6INBBcUJME0hLrAZkF1oqnab4,2126
|
|
192
196
|
xp/term/state.py,sha256=FBpYV_bWYJh9o17qcMx6sHgUARQS-uNOtUt6G7Vs1n8,3274
|
|
@@ -195,13 +199,14 @@ xp/term/widgets/__init__.py,sha256=ftWmN_fmjxy2E8Qfm-YSRmzKfgL0KTBCTpgvYWCPbUY,2
|
|
|
195
199
|
xp/term/widgets/help_menu.py,sha256=KLkdIXfhARLFNEs2lv1u0sYBz9LzOCcDLxbMGzc7e5Y,1812
|
|
196
200
|
xp/term/widgets/modules_list.py,sha256=qAG-n0nK0YdNE9v4C3-sHgxLvF1i1FR7v_GArdaoUQw,7831
|
|
197
201
|
xp/term/widgets/protocol_log.py,sha256=E68QmSMpOFrvrPTo_gOQVfyiDqY5c_y8fkNKnQw6Vwo,2650
|
|
198
|
-
xp/term/widgets/
|
|
202
|
+
xp/term/widgets/room_list.py,sha256=3q3otusnQn4qFRbTY0-QbpMP3vPmywM0izYRA_KjXn0,7871
|
|
203
|
+
xp/term/widgets/status_footer.py,sha256=biV3EzfVSgm1T7Ofi88LXsTFCkD5mI_6Cpe-RpuOSxA,3429
|
|
199
204
|
xp/utils/__init__.py,sha256=_avMF_UOkfR3tNeDIPqQ5odmbq5raKkaq1rZ9Cn1CJs,332
|
|
200
205
|
xp/utils/checksum.py,sha256=Px1S3dFGA-_plavBxrq3IqmprNlgtNDunE3whg6Otwg,1722
|
|
201
|
-
xp/utils/dependencies.py,sha256=
|
|
206
|
+
xp/utils/dependencies.py,sha256=XHOAq5nIbXD8oq4FBp3wWvinDa4Ti7cUktJtUB0z51A,25339
|
|
202
207
|
xp/utils/event_helper.py,sha256=zD0K3TPfGEThU9vUNlDtglTai3Cmm30727iwjDZy6Dk,1007
|
|
203
208
|
xp/utils/logging.py,sha256=wJ1d-yg97NiZUrt2F8iDMcmnHVwC-PErcI-7dpyiRDc,3777
|
|
204
209
|
xp/utils/serialization.py,sha256=TS1OwpTOemSvXsCGw3js4JkYYFEqkzrPe8V9QYQefdw,4684
|
|
205
210
|
xp/utils/state_machine.py,sha256=W9AY4ntRZnFeHAa5d43hm37j53uJPlqkRvWTPiBhJ_0,2464
|
|
206
211
|
xp/utils/time_utils.py,sha256=K17godWpL18VEypbTlvNOEDG6R3huYnf29yjkcnwRpU,3796
|
|
207
|
-
conson_xp-1.
|
|
212
|
+
conson_xp-1.51.1.dist-info/RECORD,,
|
xp/__init__.py
CHANGED
|
@@ -117,16 +117,21 @@ def export_conbus_actiontable(ctx: click.Context) -> None:
|
|
|
117
117
|
xp conbus export actiontable
|
|
118
118
|
"""
|
|
119
119
|
|
|
120
|
-
def on_progress(
|
|
120
|
+
def on_progress(
|
|
121
|
+
serial_number: str, actiontable_type: str, current: int, total: int
|
|
122
|
+
) -> None:
|
|
121
123
|
"""
|
|
122
124
|
Handle progress updates during export.
|
|
123
125
|
|
|
124
126
|
Args:
|
|
125
127
|
serial_number: Serial number of discovered device.
|
|
128
|
+
actiontable_type: Type of action table being exported.
|
|
126
129
|
current: Current device number.
|
|
127
130
|
total: Total devices discovered.
|
|
128
131
|
"""
|
|
129
|
-
click.echo(
|
|
132
|
+
click.echo(
|
|
133
|
+
f"Querying device {current}/{total}: {serial_number} / {actiontable_type}."
|
|
134
|
+
)
|
|
130
135
|
|
|
131
136
|
def on_device_actiontable_exported(
|
|
132
137
|
module: ConsonModuleConfig,
|
|
@@ -176,4 +181,5 @@ def export_conbus_actiontable(ctx: click.Context) -> None:
|
|
|
176
181
|
service.on_device_actiontable_exported.connect(on_device_actiontable_exported)
|
|
177
182
|
service.on_finish.connect(on_finish)
|
|
178
183
|
service.set_timeout(5)
|
|
184
|
+
service.configure()
|
|
179
185
|
service.start_reactor()
|
|
@@ -48,3 +48,26 @@ def state_monitor(ctx: Context) -> None:
|
|
|
48
48
|
|
|
49
49
|
# Resolve StateMonitorApp from container and run
|
|
50
50
|
ctx.obj.get("container").get_container().resolve(StateMonitorApp).run()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@term.command("homekit")
|
|
54
|
+
@click.pass_context
|
|
55
|
+
def homekit_monitor(ctx: Context) -> None:
|
|
56
|
+
r"""
|
|
57
|
+
Start TUI for HomeKit accessory monitoring.
|
|
58
|
+
|
|
59
|
+
Displays HomeKit rooms and accessories with real-time state updates
|
|
60
|
+
in an interactive terminal interface. Press action keys (a-z) to
|
|
61
|
+
toggle accessories.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
ctx: Click context object.
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
\b
|
|
68
|
+
xp term homekit
|
|
69
|
+
"""
|
|
70
|
+
from xp.term.homekit import HomekitApp
|
|
71
|
+
|
|
72
|
+
# Resolve HomekitApp from container and run
|
|
73
|
+
ctx.obj.get("container").get_container().resolve(HomekitApp).run()
|
|
@@ -61,6 +61,7 @@ class HomekitAccessoryConfig(BaseModel):
|
|
|
61
61
|
service: Service type for the accessory.
|
|
62
62
|
on_action: on code for the accessory.
|
|
63
63
|
off_action: off code for the accessory.
|
|
64
|
+
toggle_action: Optional toggle action code for the accessory.
|
|
64
65
|
hap_accessory: Optional HAP accessory identifier.
|
|
65
66
|
"""
|
|
66
67
|
|
|
@@ -72,6 +73,7 @@ class HomekitAccessoryConfig(BaseModel):
|
|
|
72
73
|
service: str
|
|
73
74
|
on_action: str
|
|
74
75
|
off_action: str
|
|
76
|
+
toggle_action: Optional[str] = None
|
|
75
77
|
hap_accessory: Optional[int] = None
|
|
76
78
|
|
|
77
79
|
|
xp/models/term/__init__.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Terminal UI models."""
|
|
2
2
|
|
|
3
|
+
from xp.models.term.accessory_state import AccessoryState
|
|
3
4
|
from xp.models.term.module_state import ModuleState
|
|
4
5
|
from xp.models.term.protocol_keys_config import (
|
|
5
6
|
ProtocolKeyConfig,
|
|
@@ -7,6 +8,7 @@ from xp.models.term.protocol_keys_config import (
|
|
|
7
8
|
)
|
|
8
9
|
|
|
9
10
|
__all__ = [
|
|
11
|
+
"AccessoryState",
|
|
10
12
|
"ModuleState",
|
|
11
13
|
"ProtocolKeyConfig",
|
|
12
14
|
"ProtocolKeysConfig",
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Accessory state data model for Homekit TUI."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class AccessoryState:
|
|
10
|
+
"""
|
|
11
|
+
State of a HomeKit accessory for TUI display.
|
|
12
|
+
|
|
13
|
+
Attributes:
|
|
14
|
+
room_name: Room containing the accessory (e.g., "Salon").
|
|
15
|
+
accessory_name: Accessory display name (e.g., "Variateur salon").
|
|
16
|
+
action: Action key (a-z) for toggle control.
|
|
17
|
+
output_state: Output state ("ON", "OFF", "?").
|
|
18
|
+
dimming_state: Dimming percentage for dimmable modules, "-" if OFF, empty otherwise.
|
|
19
|
+
module_name: Module identifier (e.g., "A12").
|
|
20
|
+
serial_number: Module serial number.
|
|
21
|
+
module_type: Module type (e.g., "XP24", "XP33LED").
|
|
22
|
+
error_status: Status code ("OK" or error like "E10").
|
|
23
|
+
output: Module output number (1-based for display).
|
|
24
|
+
sort: Sort accessories according to homekit.yml configuration.
|
|
25
|
+
last_update: Last communication timestamp. None if never updated.
|
|
26
|
+
toggle_action: Raw toggle action telegram (e.g., "E02L12I02").
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
room_name: str
|
|
30
|
+
accessory_name: str
|
|
31
|
+
action: str
|
|
32
|
+
output_state: str
|
|
33
|
+
dimming_state: str
|
|
34
|
+
module_name: str
|
|
35
|
+
serial_number: str
|
|
36
|
+
module_type: str
|
|
37
|
+
error_status: str
|
|
38
|
+
output: int
|
|
39
|
+
sort: int
|
|
40
|
+
last_update: Optional[datetime] = None
|
|
41
|
+
toggle_action: Optional[str] = None
|
|
42
|
+
|
|
43
|
+
def is_dimmable(self) -> bool:
|
|
44
|
+
"""
|
|
45
|
+
Check if accessory is dimmable.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
True if module type is XP33LR or XP33LED, False otherwise.
|
|
49
|
+
"""
|
|
50
|
+
return self.module_type in ("XP33LR", "XP33LED")
|
|
@@ -292,6 +292,8 @@ class ActionTableDownloadService(DownloadStateMachine):
|
|
|
292
292
|
raise RuntimeError("Cannot configure while download in progress")
|
|
293
293
|
self.logger.info("Configuring actiontable download")
|
|
294
294
|
self.serial_number = serial_number
|
|
295
|
+
self.actiontable_data = []
|
|
296
|
+
|
|
295
297
|
if actiontable_type == ActionTableType.ACTIONTABLE:
|
|
296
298
|
self.serializer = self.actiontable_serializer
|
|
297
299
|
elif actiontable_type == ActionTableType.MSACTIONTABLE_XP20:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from queue import SimpleQueue
|
|
6
|
+
from queue import Empty, SimpleQueue
|
|
7
7
|
from typing import Any, Optional, Tuple
|
|
8
8
|
|
|
9
9
|
import yaml
|
|
@@ -38,7 +38,7 @@ class ConbusActiontableExportService:
|
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
40
|
# Signals (class attributes)
|
|
41
|
-
on_progress: Signal = Signal(str, int, int) # serial, current, total
|
|
41
|
+
on_progress: Signal = Signal(str, str, int, int) # serial, current, total
|
|
42
42
|
on_device_actiontable_exported: Signal = Signal(
|
|
43
43
|
ConsonModuleConfig, ActionTableType, str
|
|
44
44
|
)
|
|
@@ -64,25 +64,35 @@ class ConbusActiontableExportService:
|
|
|
64
64
|
self.logger = logging.getLogger(__name__)
|
|
65
65
|
self.download_service = download_service
|
|
66
66
|
self._module_list: ConsonModuleListConfig = module_list
|
|
67
|
+
self._module_dic: dict[str, ConsonModuleConfig] = {
|
|
68
|
+
module.serial_number: module for module in module_list.root
|
|
69
|
+
}
|
|
67
70
|
# State management
|
|
68
|
-
self.device_queue: SimpleQueue[Tuple[
|
|
71
|
+
self.device_queue: SimpleQueue[Tuple[str, ActionTableType]] = (
|
|
69
72
|
SimpleQueue()
|
|
70
73
|
) # FIFO
|
|
71
74
|
for module in self._module_list.root:
|
|
72
|
-
self.
|
|
73
|
-
if module.module_type == "xp20":
|
|
74
|
-
self.device_queue.put(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if module.module_type == "
|
|
78
|
-
self.device_queue.put(
|
|
75
|
+
self.logger.info("Export module %s", module)
|
|
76
|
+
if module.module_type.lower() == "xp20":
|
|
77
|
+
self.device_queue.put(
|
|
78
|
+
(module.serial_number, ActionTableType.MSACTIONTABLE_XP20)
|
|
79
|
+
)
|
|
80
|
+
if module.module_type.lower() == "xp24":
|
|
81
|
+
self.device_queue.put(
|
|
82
|
+
(module.serial_number, ActionTableType.MSACTIONTABLE_XP24)
|
|
83
|
+
)
|
|
84
|
+
if module.module_type.lower() == "xp33":
|
|
85
|
+
self.device_queue.put(
|
|
86
|
+
(module.serial_number, ActionTableType.MSACTIONTABLE_XP33)
|
|
87
|
+
)
|
|
88
|
+
self.device_queue.put((module.serial_number, ActionTableType.ACTIONTABLE))
|
|
89
|
+
|
|
90
|
+
self.logger.info("Export module %s", self.device_queue.qsize())
|
|
79
91
|
|
|
80
92
|
self.current_module: Optional[ConsonModuleConfig] = None
|
|
81
|
-
self.
|
|
93
|
+
self.current_actiontable_type: Optional[ActionTableType] = None
|
|
82
94
|
self.export_result = ConbusExportResponse(success=False)
|
|
83
95
|
self.export_status = "OK"
|
|
84
|
-
# Connect protocol signals
|
|
85
|
-
self._connect_signals()
|
|
86
96
|
|
|
87
97
|
def on_module_actiontable_received(
|
|
88
98
|
self, actiontable: Any, short_actiontable: list[str]
|
|
@@ -94,7 +104,7 @@ class ConbusActiontableExportService:
|
|
|
94
104
|
actiontable: Full actiontable data.
|
|
95
105
|
short_actiontable: Short representation of the actiontable.
|
|
96
106
|
"""
|
|
97
|
-
if not self.
|
|
107
|
+
if not self.current_actiontable_type:
|
|
98
108
|
self._fail("Invalid state (curent_actiontable_type)")
|
|
99
109
|
return
|
|
100
110
|
|
|
@@ -102,17 +112,17 @@ class ConbusActiontableExportService:
|
|
|
102
112
|
self._fail("Invalid state (current_module)")
|
|
103
113
|
return
|
|
104
114
|
|
|
105
|
-
if self.
|
|
115
|
+
if self.current_actiontable_type == ActionTableType.ACTIONTABLE:
|
|
106
116
|
self.current_module.action_table = short_actiontable
|
|
107
|
-
elif self.
|
|
117
|
+
elif self.current_actiontable_type == ActionTableType.MSACTIONTABLE_XP20:
|
|
108
118
|
self.current_module.xp20_msaction_table = short_actiontable
|
|
109
|
-
elif self.
|
|
119
|
+
elif self.current_actiontable_type == ActionTableType.MSACTIONTABLE_XP24:
|
|
110
120
|
self.current_module.xp24_msaction_table = short_actiontable
|
|
111
|
-
elif self.
|
|
121
|
+
elif self.current_actiontable_type == ActionTableType.MSACTIONTABLE_XP33:
|
|
112
122
|
self.current_module.xp33_msaction_table = short_actiontable
|
|
113
123
|
|
|
114
124
|
self.on_device_actiontable_exported.emit(
|
|
115
|
-
self.current_module, self.
|
|
125
|
+
self.current_module, self.current_actiontable_type, short_actiontable
|
|
116
126
|
)
|
|
117
127
|
|
|
118
128
|
def on_module_finish(self) -> None:
|
|
@@ -127,10 +137,13 @@ class ConbusActiontableExportService:
|
|
|
127
137
|
serial_number = (
|
|
128
138
|
self.current_module.serial_number if self.current_module else "UNKNOWN"
|
|
129
139
|
)
|
|
140
|
+
current_actiontable_type = self.current_actiontable_type or "UNKNOWN"
|
|
130
141
|
total_modules = len(self._module_list.root)
|
|
131
142
|
current_index = total_modules - self.device_queue.qsize()
|
|
132
143
|
|
|
133
|
-
self.on_progress.emit(
|
|
144
|
+
self.on_progress.emit(
|
|
145
|
+
serial_number, current_actiontable_type, current_index, total_modules
|
|
146
|
+
)
|
|
134
147
|
|
|
135
148
|
def on_module_error(self, error_message: str) -> None:
|
|
136
149
|
"""
|
|
@@ -162,7 +175,6 @@ class ConbusActiontableExportService:
|
|
|
162
175
|
"enabled",
|
|
163
176
|
"conbus_ip",
|
|
164
177
|
"conbus_port",
|
|
165
|
-
"action_table",
|
|
166
178
|
}
|
|
167
179
|
}
|
|
168
180
|
},
|
|
@@ -203,16 +215,24 @@ class ConbusActiontableExportService:
|
|
|
203
215
|
True if there is a module to export, False otherwise.
|
|
204
216
|
"""
|
|
205
217
|
self.download_service.reset()
|
|
206
|
-
|
|
207
|
-
self.
|
|
208
|
-
|
|
209
|
-
|
|
218
|
+
try:
|
|
219
|
+
(current_serial_number, self.current_actiontable_type) = (
|
|
220
|
+
self.device_queue.get_nowait()
|
|
221
|
+
)
|
|
222
|
+
except Empty:
|
|
223
|
+
return False
|
|
224
|
+
|
|
225
|
+
self.current_module = self._module_dic[current_serial_number]
|
|
226
|
+
if not (self.current_module or self.current_actiontable_type):
|
|
210
227
|
self.logger.error("No module to export")
|
|
211
228
|
return False
|
|
212
229
|
|
|
230
|
+
self.logger.info(
|
|
231
|
+
f"Downloading {self.current_module.serial_number} / {self.current_actiontable_type}"
|
|
232
|
+
)
|
|
213
233
|
self.download_service.configure(
|
|
214
234
|
self.current_module.serial_number,
|
|
215
|
-
self.
|
|
235
|
+
self.current_actiontable_type,
|
|
216
236
|
)
|
|
217
237
|
self.download_service.do_connect()
|
|
218
238
|
return True
|
|
@@ -275,7 +295,7 @@ class ConbusActiontableExportService:
|
|
|
275
295
|
|
|
276
296
|
def _disconnect_signals(self) -> None:
|
|
277
297
|
"""Disconnect download service signals from handlers."""
|
|
278
|
-
self.download_service.on_actiontable_received.
|
|
298
|
+
self.download_service.on_actiontable_received.disconnect(
|
|
279
299
|
self.on_module_actiontable_received
|
|
280
300
|
)
|
|
281
301
|
self.download_service.on_finish.disconnect(self.on_module_finish)
|