conson-xp 1.1.0__py3-none-any.whl → 1.3.0__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.1.0.dist-info → conson_xp-1.3.0.dist-info}/METADATA +1 -5
- conson_xp-1.3.0.dist-info/RECORD +164 -0
- xp/__init__.py +4 -3
- xp/cli/__init__.py +1 -1
- xp/cli/commands/__init__.py +1 -2
- xp/cli/commands/conbus/conbus.py +9 -37
- xp/cli/commands/conbus/conbus_actiontable_commands.py +26 -4
- xp/cli/commands/conbus/conbus_autoreport_commands.py +58 -30
- xp/cli/commands/conbus/conbus_blink_commands.py +61 -29
- xp/cli/commands/conbus/conbus_config_commands.py +10 -5
- xp/cli/commands/conbus/conbus_custom_commands.py +16 -5
- xp/cli/commands/conbus/conbus_datapoint_commands.py +32 -10
- xp/cli/commands/conbus/conbus_discover_commands.py +20 -7
- xp/cli/commands/conbus/conbus_lightlevel_commands.py +114 -39
- xp/cli/commands/conbus/conbus_linknumber_commands.py +50 -25
- xp/cli/commands/conbus/conbus_msactiontable_commands.py +36 -5
- xp/cli/commands/conbus/conbus_output_commands.py +52 -14
- xp/cli/commands/conbus/conbus_raw_commands.py +17 -6
- xp/cli/commands/conbus/conbus_receive_commands.py +20 -10
- xp/cli/commands/conbus/conbus_scan_commands.py +17 -4
- xp/cli/commands/file_commands.py +35 -18
- xp/cli/commands/homekit/homekit.py +14 -8
- xp/cli/commands/homekit/homekit_start_commands.py +8 -6
- xp/cli/commands/module_commands.py +38 -23
- xp/cli/commands/reverse_proxy_commands.py +27 -19
- xp/cli/commands/server/server_commands.py +18 -18
- xp/cli/commands/telegram/telegram.py +4 -12
- xp/cli/commands/telegram/telegram_blink_commands.py +10 -8
- xp/cli/commands/telegram/telegram_checksum_commands.py +19 -8
- xp/cli/commands/telegram/telegram_discover_commands.py +2 -4
- xp/cli/commands/telegram/telegram_linknumber_commands.py +11 -8
- xp/cli/commands/telegram/telegram_parse_commands.py +10 -9
- xp/cli/commands/telegram/telegram_version_commands.py +8 -4
- xp/cli/main.py +5 -3
- xp/cli/utils/click_tree.py +23 -3
- xp/cli/utils/datapoint_type_choice.py +20 -0
- xp/cli/utils/decorators.py +165 -14
- xp/cli/utils/error_handlers.py +49 -18
- xp/cli/utils/formatters.py +95 -10
- xp/cli/utils/serial_number_type.py +18 -0
- xp/cli/utils/system_function_choice.py +20 -0
- xp/cli/utils/xp_module_type.py +20 -0
- xp/connection/__init__.py +1 -1
- xp/connection/exceptions.py +5 -5
- xp/models/__init__.py +1 -1
- xp/models/actiontable/__init__.py +1 -0
- xp/models/actiontable/actiontable.py +17 -1
- xp/models/actiontable/msactiontable_xp20.py +10 -0
- xp/models/actiontable/msactiontable_xp24.py +20 -3
- xp/models/actiontable/msactiontable_xp33.py +27 -4
- xp/models/conbus/__init__.py +1 -0
- xp/models/conbus/conbus.py +34 -4
- xp/models/conbus/conbus_autoreport.py +20 -2
- xp/models/conbus/conbus_blink.py +22 -2
- xp/models/conbus/conbus_client_config.py +22 -1
- xp/models/conbus/conbus_connection_status.py +16 -2
- xp/models/conbus/conbus_custom.py +21 -2
- xp/models/conbus/conbus_datapoint.py +25 -2
- xp/models/conbus/conbus_discover.py +18 -2
- xp/models/conbus/conbus_lightlevel.py +20 -2
- xp/models/conbus/conbus_linknumber.py +20 -2
- xp/models/conbus/conbus_output.py +22 -2
- xp/models/conbus/conbus_raw.py +17 -2
- xp/models/conbus/conbus_receive.py +16 -2
- xp/models/conbus/conbus_writeconfig.py +60 -0
- xp/models/homekit/__init__.py +1 -0
- xp/models/homekit/homekit_accessory.py +15 -1
- xp/models/homekit/homekit_config.py +52 -0
- xp/models/homekit/homekit_conson_config.py +32 -0
- xp/models/log_entry.py +49 -9
- xp/models/protocol/__init__.py +1 -0
- xp/models/protocol/conbus_protocol.py +130 -21
- xp/models/telegram/__init__.py +1 -0
- xp/models/telegram/action_type.py +16 -2
- xp/models/telegram/datapoint_type.py +36 -2
- xp/models/telegram/event_telegram.py +46 -10
- xp/models/telegram/event_type.py +8 -1
- xp/models/telegram/input_action_type.py +34 -2
- xp/models/telegram/input_type.py +9 -1
- xp/models/telegram/module_type.py +69 -19
- xp/models/telegram/module_type_code.py +43 -1
- xp/models/telegram/output_telegram.py +30 -6
- xp/models/telegram/reply_telegram.py +56 -11
- xp/models/telegram/system_function.py +35 -3
- xp/models/telegram/system_telegram.py +18 -4
- xp/models/telegram/telegram.py +12 -3
- xp/models/telegram/telegram_type.py +8 -1
- xp/models/telegram/timeparam_type.py +27 -0
- xp/models/write_config_type.py +17 -2
- xp/services/__init__.py +1 -1
- xp/services/conbus/__init__.py +1 -0
- xp/services/conbus/actiontable/__init__.py +1 -0
- xp/services/conbus/actiontable/actiontable_service.py +33 -2
- xp/services/conbus/actiontable/msactiontable_service.py +40 -3
- xp/services/conbus/actiontable/msactiontable_xp24_serializer.py +36 -4
- xp/services/conbus/actiontable/msactiontable_xp33_serializer.py +45 -5
- xp/services/conbus/conbus_blink_all_service.py +40 -21
- xp/services/conbus/conbus_blink_service.py +37 -13
- xp/services/conbus/conbus_custom_service.py +29 -13
- xp/services/conbus/conbus_datapoint_queryall_service.py +40 -16
- xp/services/conbus/conbus_datapoint_service.py +42 -18
- xp/services/conbus/conbus_discover_service.py +43 -7
- xp/services/conbus/conbus_output_service.py +33 -13
- xp/services/conbus/conbus_raw_service.py +36 -16
- xp/services/conbus/conbus_receive_service.py +38 -6
- xp/services/conbus/conbus_scan_service.py +44 -18
- xp/services/conbus/write_config_service.py +193 -0
- xp/services/homekit/__init__.py +1 -0
- xp/services/homekit/homekit_cache_service.py +31 -6
- xp/services/homekit/homekit_conbus_service.py +33 -2
- xp/services/homekit/homekit_config_validator.py +97 -15
- xp/services/homekit/homekit_conson_validator.py +51 -7
- xp/services/homekit/homekit_dimminglight.py +47 -1
- xp/services/homekit/homekit_dimminglight_service.py +35 -1
- xp/services/homekit/homekit_hap_service.py +71 -18
- xp/services/homekit/homekit_lightbulb.py +35 -1
- xp/services/homekit/homekit_lightbulb_service.py +30 -2
- xp/services/homekit/homekit_module_service.py +23 -1
- xp/services/homekit/homekit_outlet.py +47 -1
- xp/services/homekit/homekit_outlet_service.py +44 -2
- xp/services/homekit/homekit_service.py +113 -19
- xp/services/log_file_service.py +37 -41
- xp/services/module_type_service.py +26 -5
- xp/services/protocol/__init__.py +1 -1
- xp/services/protocol/conbus_protocol.py +110 -16
- xp/services/protocol/protocol_factory.py +40 -0
- xp/services/protocol/telegram_protocol.py +38 -7
- xp/services/reverse_proxy_service.py +79 -14
- xp/services/server/__init__.py +1 -0
- xp/services/server/base_server_service.py +102 -14
- xp/services/server/cp20_server_service.py +12 -4
- xp/services/server/server_service.py +26 -11
- xp/services/server/xp130_server_service.py +11 -3
- xp/services/server/xp20_server_service.py +11 -3
- xp/services/server/xp230_server_service.py +11 -3
- xp/services/server/xp24_server_service.py +33 -6
- xp/services/server/xp33_server_service.py +41 -8
- xp/services/telegram/__init__.py +1 -0
- xp/services/telegram/telegram_blink_service.py +19 -31
- xp/services/telegram/telegram_checksum_service.py +10 -10
- xp/services/telegram/telegram_datapoint_service.py +70 -0
- xp/services/telegram/telegram_discover_service.py +58 -29
- xp/services/telegram/telegram_link_number_service.py +27 -40
- xp/services/telegram/telegram_output_service.py +46 -49
- xp/services/telegram/telegram_service.py +41 -41
- xp/services/telegram/telegram_version_service.py +4 -2
- xp/utils/__init__.py +1 -1
- xp/utils/dependencies.py +4 -47
- xp/utils/serialization.py +6 -0
- xp/utils/time_utils.py +6 -11
- conson_xp-1.1.0.dist-info/RECORD +0 -181
- xp/api/__init__.py +0 -1
- xp/api/main.py +0 -110
- xp/api/models/__init__.py +0 -1
- xp/api/models/api.py +0 -20
- xp/api/models/discover.py +0 -21
- xp/api/routers/__init__.py +0 -17
- xp/api/routers/conbus.py +0 -5
- xp/api/routers/conbus_blink.py +0 -105
- xp/api/routers/conbus_custom.py +0 -63
- xp/api/routers/conbus_datapoint.py +0 -67
- xp/api/routers/conbus_output.py +0 -147
- xp/api/routers/errors.py +0 -37
- xp/cli/commands/api.py +0 -16
- xp/cli/commands/api_start_commands.py +0 -126
- xp/services/conbus/conbus_autoreport_get_service.py +0 -85
- xp/services/conbus/conbus_autoreport_set_service.py +0 -128
- xp/services/conbus/conbus_lightlevel_get_service.py +0 -101
- xp/services/conbus/conbus_lightlevel_set_service.py +0 -205
- xp/services/conbus/conbus_linknumber_get_service.py +0 -86
- xp/services/conbus/conbus_linknumber_set_service.py +0 -155
- {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/WHEEL +0 -0
- {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.1.0.dist-info → conson_xp-1.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"""HomeKit Light Bulb Accessory.
|
|
2
|
+
|
|
3
|
+
This module provides a light bulb accessory for HomeKit integration.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
import logging
|
|
2
7
|
|
|
3
8
|
from bubus import EventBus
|
|
@@ -14,7 +19,18 @@ from xp.models.protocol.conbus_protocol import (
|
|
|
14
19
|
|
|
15
20
|
|
|
16
21
|
class LightBulb(Accessory):
|
|
17
|
-
"""
|
|
22
|
+
"""HomeKit light bulb accessory.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
category: HomeKit category (CATEGORY_LIGHTBULB).
|
|
26
|
+
event_bus: Event bus for inter-service communication.
|
|
27
|
+
logger: Logger instance.
|
|
28
|
+
identifier: Unique identifier for the accessory.
|
|
29
|
+
accessory: Accessory configuration.
|
|
30
|
+
module: Module configuration.
|
|
31
|
+
is_on: Current on/off state.
|
|
32
|
+
char_on: On characteristic.
|
|
33
|
+
"""
|
|
18
34
|
|
|
19
35
|
category = CATEGORY_LIGHTBULB
|
|
20
36
|
event_bus: EventBus
|
|
@@ -26,6 +42,14 @@ class LightBulb(Accessory):
|
|
|
26
42
|
accessory: HomekitAccessoryConfig,
|
|
27
43
|
event_bus: EventBus,
|
|
28
44
|
):
|
|
45
|
+
"""Initialize the light bulb accessory.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
driver: HAP accessory driver.
|
|
49
|
+
module: Module configuration.
|
|
50
|
+
accessory: Accessory configuration.
|
|
51
|
+
event_bus: Event bus for inter-service communication.
|
|
52
|
+
"""
|
|
29
53
|
super().__init__(driver, accessory.description)
|
|
30
54
|
|
|
31
55
|
self.logger = logging.getLogger(__name__)
|
|
@@ -56,6 +80,11 @@ class LightBulb(Accessory):
|
|
|
56
80
|
)
|
|
57
81
|
|
|
58
82
|
def set_on(self, value: bool) -> None:
|
|
83
|
+
"""Set the on/off state of the light bulb.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
value: True to turn on, False to turn off.
|
|
87
|
+
"""
|
|
59
88
|
# Emit set event
|
|
60
89
|
self.logger.debug(f"set_on {value}")
|
|
61
90
|
if self.is_on != value:
|
|
@@ -71,6 +100,11 @@ class LightBulb(Accessory):
|
|
|
71
100
|
)
|
|
72
101
|
|
|
73
102
|
def get_on(self) -> bool:
|
|
103
|
+
"""Get the on/off state of the light bulb.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
True if on, False if off.
|
|
107
|
+
"""
|
|
74
108
|
# Emit event and get response
|
|
75
109
|
self.logger.debug("get_on")
|
|
76
110
|
self.event_bus.dispatch(
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"""HomeKit Light Bulb Service.
|
|
2
|
+
|
|
3
|
+
This module provides service implementation for light bulb accessories.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
import logging
|
|
2
7
|
|
|
3
8
|
from bubus import EventBus
|
|
@@ -12,11 +17,21 @@ from xp.models.telegram.datapoint_type import DataPointType
|
|
|
12
17
|
|
|
13
18
|
|
|
14
19
|
class HomeKitLightbulbService:
|
|
15
|
-
"""Lightbulb service for HomeKit
|
|
20
|
+
"""Lightbulb service for HomeKit.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
event_bus: Event bus for inter-service communication.
|
|
24
|
+
logger: Logger instance.
|
|
25
|
+
"""
|
|
16
26
|
|
|
17
27
|
event_bus: EventBus
|
|
18
28
|
|
|
19
29
|
def __init__(self, event_bus: EventBus):
|
|
30
|
+
"""Initialize the lightbulb service.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
event_bus: Event bus instance.
|
|
34
|
+
"""
|
|
20
35
|
self.event_bus = event_bus
|
|
21
36
|
self.logger = logging.getLogger(__name__)
|
|
22
37
|
|
|
@@ -25,6 +40,11 @@ class HomeKitLightbulbService:
|
|
|
25
40
|
self.event_bus.on(LightBulbSetOnEvent, self.handle_lightbulb_set_on)
|
|
26
41
|
|
|
27
42
|
def handle_lightbulb_get_on(self, event: LightBulbGetOnEvent) -> None:
|
|
43
|
+
"""Handle lightbulb get on event.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
event: Lightbulb get on event.
|
|
47
|
+
"""
|
|
28
48
|
self.logger.info(
|
|
29
49
|
f"Getting lightbulb state for serial {event.serial_number}, output {event.output_number}"
|
|
30
50
|
)
|
|
@@ -40,8 +60,16 @@ class HomeKitLightbulbService:
|
|
|
40
60
|
self.logger.debug(f"Dispatched ReadDatapointEvent for {event.serial_number}")
|
|
41
61
|
|
|
42
62
|
def handle_lightbulb_set_on(self, event: LightBulbSetOnEvent) -> None:
|
|
63
|
+
"""Handle lightbulb set on event.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
event: Lightbulb set on event.
|
|
67
|
+
"""
|
|
43
68
|
self.logger.info(
|
|
44
|
-
f"Setting lightbulb
|
|
69
|
+
f"Setting lightbulb "
|
|
70
|
+
f"for serial {event.serial_number}, "
|
|
71
|
+
f"output {event.output_number} "
|
|
72
|
+
f"to {'ON' if event.value else 'OFF'}"
|
|
45
73
|
)
|
|
46
74
|
self.logger.debug(f"lightbulb_set_on {event}")
|
|
47
75
|
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"""HomeKit Module Service.
|
|
2
|
+
|
|
3
|
+
This module provides service implementation for HomeKit module management.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
import logging
|
|
2
7
|
from typing import Optional
|
|
3
8
|
|
|
@@ -8,18 +13,35 @@ from xp.models.homekit.homekit_conson_config import (
|
|
|
8
13
|
|
|
9
14
|
|
|
10
15
|
class HomekitModuleService:
|
|
16
|
+
"""Service for managing HomeKit module configurations.
|
|
17
|
+
|
|
18
|
+
Attributes:
|
|
19
|
+
logger: Logger instance.
|
|
20
|
+
conson_modules_config: Conson module list configuration.
|
|
21
|
+
"""
|
|
11
22
|
|
|
12
23
|
def __init__(
|
|
13
24
|
self,
|
|
14
25
|
conson_modules_config: ConsonModuleListConfig,
|
|
15
26
|
):
|
|
27
|
+
"""Initialize the HomeKit module service.
|
|
16
28
|
|
|
29
|
+
Args:
|
|
30
|
+
conson_modules_config: Conson module list configuration.
|
|
31
|
+
"""
|
|
17
32
|
# Set up logging
|
|
18
33
|
self.logger = logging.getLogger(__name__)
|
|
19
34
|
self.conson_modules_config = conson_modules_config
|
|
20
35
|
|
|
21
36
|
def get_module_by_serial(self, serial_number: str) -> Optional[ConsonModuleConfig]:
|
|
22
|
-
"""Get a module by its serial number
|
|
37
|
+
"""Get a module by its serial number.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
serial_number: Serial number of the module to find.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Module configuration if found, None otherwise.
|
|
44
|
+
"""
|
|
23
45
|
module = next(
|
|
24
46
|
(
|
|
25
47
|
module
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"""HomeKit Outlet Accessory.
|
|
2
|
+
|
|
3
|
+
This module provides an outlet accessory for HomeKit integration.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
import logging
|
|
2
7
|
|
|
3
8
|
from bubus import EventBus
|
|
@@ -16,7 +21,20 @@ from xp.models.protocol.conbus_protocol import (
|
|
|
16
21
|
|
|
17
22
|
|
|
18
23
|
class Outlet(Accessory):
|
|
19
|
-
"""
|
|
24
|
+
"""HomeKit outlet accessory.
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
category: HomeKit category (CATEGORY_OUTLET).
|
|
28
|
+
event_bus: Event bus for inter-service communication.
|
|
29
|
+
logger: Logger instance.
|
|
30
|
+
identifier: Unique identifier for the accessory.
|
|
31
|
+
accessory: Accessory configuration.
|
|
32
|
+
module: Module configuration.
|
|
33
|
+
is_on: Current on/off state.
|
|
34
|
+
is_in_use: Current in-use state.
|
|
35
|
+
char_on: On characteristic.
|
|
36
|
+
char_outlet_in_use: Outlet in-use characteristic.
|
|
37
|
+
"""
|
|
20
38
|
|
|
21
39
|
category = CATEGORY_OUTLET
|
|
22
40
|
event_bus: EventBus
|
|
@@ -28,6 +46,14 @@ class Outlet(Accessory):
|
|
|
28
46
|
accessory: HomekitAccessoryConfig,
|
|
29
47
|
event_bus: EventBus,
|
|
30
48
|
):
|
|
49
|
+
"""Initialize the outlet accessory.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
driver: HAP accessory driver.
|
|
53
|
+
module: Module configuration.
|
|
54
|
+
accessory: Accessory configuration.
|
|
55
|
+
event_bus: Event bus for inter-service communication.
|
|
56
|
+
"""
|
|
31
57
|
super().__init__(driver=driver, display_name=accessory.description)
|
|
32
58
|
|
|
33
59
|
self.logger = logging.getLogger(__name__)
|
|
@@ -62,6 +88,11 @@ class Outlet(Accessory):
|
|
|
62
88
|
)
|
|
63
89
|
|
|
64
90
|
def set_outlet_in_use(self, value: bool) -> None:
|
|
91
|
+
"""Set the in-use state of the outlet.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
value: True if in use, False otherwise.
|
|
95
|
+
"""
|
|
65
96
|
self.logger.debug(f"set_outlet_in_use {value}")
|
|
66
97
|
|
|
67
98
|
self.is_in_use = value
|
|
@@ -77,6 +108,11 @@ class Outlet(Accessory):
|
|
|
77
108
|
self.logger.debug(f"set_outlet_in_use {value} end")
|
|
78
109
|
|
|
79
110
|
def get_outlet_in_use(self) -> bool:
|
|
111
|
+
"""Get the in-use state of the outlet.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
True if in use, False otherwise.
|
|
115
|
+
"""
|
|
80
116
|
# Emit event and get response
|
|
81
117
|
self.logger.debug("get_outlet_in_use")
|
|
82
118
|
|
|
@@ -92,6 +128,11 @@ class Outlet(Accessory):
|
|
|
92
128
|
return self.is_in_use
|
|
93
129
|
|
|
94
130
|
def set_on(self, value: bool) -> None:
|
|
131
|
+
"""Set the on/off state of the outlet.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
value: True to turn on, False to turn off.
|
|
135
|
+
"""
|
|
95
136
|
# Emit set event
|
|
96
137
|
self.logger.debug(f"set_on {value}")
|
|
97
138
|
|
|
@@ -108,6 +149,11 @@ class Outlet(Accessory):
|
|
|
108
149
|
)
|
|
109
150
|
|
|
110
151
|
def get_on(self) -> bool:
|
|
152
|
+
"""Get the on/off state of the outlet.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
True if on, False if off.
|
|
156
|
+
"""
|
|
111
157
|
# Emit event and get response
|
|
112
158
|
self.logger.debug("get_on")
|
|
113
159
|
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"""HomeKit Outlet Service.
|
|
2
|
+
|
|
3
|
+
This module provides service implementation for outlet accessories.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
import logging
|
|
2
7
|
|
|
3
8
|
from bubus import EventBus
|
|
@@ -13,11 +18,21 @@ from xp.models.telegram.datapoint_type import DataPointType
|
|
|
13
18
|
|
|
14
19
|
|
|
15
20
|
class HomeKitOutletService:
|
|
16
|
-
"""Outlet service for HomeKit
|
|
21
|
+
"""Outlet service for HomeKit.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
event_bus: Event bus for inter-service communication.
|
|
25
|
+
logger: Logger instance.
|
|
26
|
+
"""
|
|
17
27
|
|
|
18
28
|
event_bus: EventBus
|
|
19
29
|
|
|
20
30
|
def __init__(self, event_bus: EventBus):
|
|
31
|
+
"""Initialize the outlet service.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
event_bus: Event bus instance.
|
|
35
|
+
"""
|
|
21
36
|
self.event_bus = event_bus
|
|
22
37
|
self.logger = logging.getLogger(__name__)
|
|
23
38
|
|
|
@@ -27,6 +42,14 @@ class HomeKitOutletService:
|
|
|
27
42
|
self.event_bus.on(OutletGetInUseEvent, self.handle_outlet_get_in_use)
|
|
28
43
|
|
|
29
44
|
def handle_outlet_get_on(self, event: OutletGetOnEvent) -> bool:
|
|
45
|
+
"""Handle outlet get on event.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
event: Outlet get on event.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
True if request was dispatched successfully.
|
|
52
|
+
"""
|
|
30
53
|
self.logger.debug(
|
|
31
54
|
f"Getting outlet state for serial {event.serial_number}, output {event.output_number}"
|
|
32
55
|
)
|
|
@@ -42,8 +65,19 @@ class HomeKitOutletService:
|
|
|
42
65
|
return True
|
|
43
66
|
|
|
44
67
|
def handle_outlet_set_on(self, event: OutletSetOnEvent) -> bool:
|
|
68
|
+
"""Handle outlet set on event.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
event: Outlet set on event.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
True if command was sent successfully.
|
|
75
|
+
"""
|
|
45
76
|
self.logger.info(
|
|
46
|
-
f"Setting outlet
|
|
77
|
+
f"Setting outlet "
|
|
78
|
+
f"for serial {event.serial_number}, "
|
|
79
|
+
f"output {event.output_number} "
|
|
80
|
+
f"to {'ON' if event.value else 'OFF'}"
|
|
47
81
|
)
|
|
48
82
|
self.logger.debug(f"outlet_set_on {event}")
|
|
49
83
|
|
|
@@ -61,6 +95,14 @@ class HomeKitOutletService:
|
|
|
61
95
|
return True
|
|
62
96
|
|
|
63
97
|
def handle_outlet_get_in_use(self, event: OutletGetInUseEvent) -> bool:
|
|
98
|
+
"""Handle outlet get in-use event.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
event: Outlet get in-use event.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
True if request was dispatched successfully.
|
|
105
|
+
"""
|
|
64
106
|
self.logger.info(
|
|
65
107
|
f"Getting outlet in-use status for serial {event.serial_number}"
|
|
66
108
|
)
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"""HomeKit Service for Apple HomeKit integration.
|
|
2
|
+
|
|
3
|
+
This module provides the main service for HomeKit integration.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
# Install asyncio reactor before importing reactor
|
|
2
7
|
|
|
3
8
|
import asyncio
|
|
@@ -29,6 +34,23 @@ from xp.services.protocol.protocol_factory import TelegramFactory
|
|
|
29
34
|
|
|
30
35
|
|
|
31
36
|
class HomeKitService:
|
|
37
|
+
"""Main HomeKit service for Apple HomeKit integration.
|
|
38
|
+
|
|
39
|
+
Attributes:
|
|
40
|
+
cli_config: Conbus client configuration.
|
|
41
|
+
reactor: Twisted reactor instance.
|
|
42
|
+
telegram_factory: Telegram factory for protocol.
|
|
43
|
+
protocol: Telegram protocol instance.
|
|
44
|
+
event_bus: Event bus for inter-service communication.
|
|
45
|
+
lightbulb_service: Lightbulb service instance.
|
|
46
|
+
dimminglight_service: Dimming light service instance.
|
|
47
|
+
outlet_service: Outlet service instance.
|
|
48
|
+
cache_service: Cache service instance.
|
|
49
|
+
conbus_service: Conbus service instance.
|
|
50
|
+
module_factory: HAP service instance.
|
|
51
|
+
telegram_service: Telegram service instance.
|
|
52
|
+
logger: Logger instance.
|
|
53
|
+
"""
|
|
32
54
|
|
|
33
55
|
def __init__(
|
|
34
56
|
self,
|
|
@@ -44,7 +66,21 @@ class HomeKitService:
|
|
|
44
66
|
module_factory: HomekitHapService,
|
|
45
67
|
telegram_service: TelegramService,
|
|
46
68
|
):
|
|
47
|
-
|
|
69
|
+
"""Initialize the HomeKit service.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
cli_config: Conbus client configuration.
|
|
73
|
+
event_bus: Event bus instance.
|
|
74
|
+
telegram_factory: Telegram factory instance.
|
|
75
|
+
reactor: Twisted reactor instance.
|
|
76
|
+
lightbulb_service: Lightbulb service instance.
|
|
77
|
+
outlet_service: Outlet service instance.
|
|
78
|
+
dimminglight_service: Dimming light service instance.
|
|
79
|
+
cache_service: Cache service instance.
|
|
80
|
+
conbus_service: Conbus service instance.
|
|
81
|
+
module_factory: HAP service instance.
|
|
82
|
+
telegram_service: Telegram service instance.
|
|
83
|
+
"""
|
|
48
84
|
self.cli_config = cli_config.conbus
|
|
49
85
|
self.reactor = reactor
|
|
50
86
|
self.telegram_factory = telegram_factory
|
|
@@ -67,23 +103,24 @@ class HomeKitService:
|
|
|
67
103
|
self.event_bus.on(ModuleDiscoveredEvent, self.handle_module_discovered)
|
|
68
104
|
|
|
69
105
|
def start(self) -> None:
|
|
70
|
-
|
|
106
|
+
"""Start the HomeKit service."""
|
|
107
|
+
self.logger.info("Starting HomeKit service.")
|
|
71
108
|
self.logger.debug("start")
|
|
72
109
|
|
|
73
110
|
# Run reactor in its own dedicated thread
|
|
74
|
-
self.logger.info("Starting reactor in dedicated thread
|
|
111
|
+
self.logger.info("Starting reactor in dedicated thread.")
|
|
75
112
|
reactor_thread = threading.Thread(
|
|
76
113
|
target=self._run_reactor_in_thread, daemon=True, name="ReactorThread"
|
|
77
114
|
)
|
|
78
115
|
reactor_thread.start()
|
|
79
116
|
|
|
80
117
|
# Keep MainThread alive while reactor thread runs
|
|
81
|
-
self.logger.info("Reactor thread started, MainThread waiting
|
|
118
|
+
self.logger.info("Reactor thread started, MainThread waiting.")
|
|
82
119
|
reactor_thread.join()
|
|
83
120
|
|
|
84
121
|
def _run_reactor_in_thread(self) -> None:
|
|
85
|
-
"""Run reactor in dedicated thread with its own event loop"""
|
|
86
|
-
self.logger.info("Reactor thread starting
|
|
122
|
+
"""Run reactor in dedicated thread with its own event loop."""
|
|
123
|
+
self.logger.info("Reactor thread starting.")
|
|
87
124
|
|
|
88
125
|
# The asyncio reactor already has an event loop set up
|
|
89
126
|
# We just need to use it
|
|
@@ -101,17 +138,21 @@ class HomeKitService:
|
|
|
101
138
|
self.reactor.callLater(0, self._start_module_factory)
|
|
102
139
|
|
|
103
140
|
# Run the reactor (which now uses asyncio underneath)
|
|
104
|
-
self.logger.info("Starting reactor event loop
|
|
141
|
+
self.logger.info("Starting reactor event loop.")
|
|
105
142
|
self.reactor.run()
|
|
106
143
|
|
|
107
144
|
def _start_module_factory(self) -> None:
|
|
108
|
-
"""Start module factory after reactor starts
|
|
109
|
-
|
|
145
|
+
"""Start module factory after reactor starts.
|
|
146
|
+
|
|
147
|
+
Creates and schedules an async task to start the HAP service.
|
|
148
|
+
"""
|
|
149
|
+
self.logger.info("Starting module factory.")
|
|
110
150
|
self.logger.debug("callWhenRunning executed, scheduling async task")
|
|
111
151
|
|
|
112
152
|
# Run HAP-python driver asynchronously in the reactor's event loop
|
|
113
153
|
async def async_start() -> None:
|
|
114
|
-
|
|
154
|
+
"""Start the HAP service asynchronously."""
|
|
155
|
+
self.logger.info("async_start executing.")
|
|
115
156
|
try:
|
|
116
157
|
await self.module_factory.async_start()
|
|
117
158
|
self.logger.info("Module factory started successfully")
|
|
@@ -130,23 +171,42 @@ class HomeKitService:
|
|
|
130
171
|
|
|
131
172
|
# Event handlers
|
|
132
173
|
def handle_connection_made(self, event: ConnectionMadeEvent) -> None:
|
|
133
|
-
"""Handle connection established - send initial telegram
|
|
174
|
+
"""Handle connection established - send initial telegram.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
event: Connection made event.
|
|
178
|
+
"""
|
|
134
179
|
self.logger.debug("Connection established successfully")
|
|
135
180
|
self.logger.debug("Sending initial discovery telegram: S0000000000F01D00")
|
|
136
181
|
event.protocol.sendFrame(b"S0000000000F01D00")
|
|
137
182
|
|
|
138
183
|
def handle_connection_failed(self, event: ConnectionFailedEvent) -> None:
|
|
139
|
-
"""Handle connection failed
|
|
184
|
+
"""Handle connection failed.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
event: Connection failed event.
|
|
188
|
+
"""
|
|
140
189
|
self.logger.error(f"Connection failed: {event.reason}")
|
|
141
190
|
|
|
142
191
|
def handle_connection_lost(self, event: ConnectionLostEvent) -> None:
|
|
143
|
-
"""Handle connection lost
|
|
192
|
+
"""Handle connection lost.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
event: Connection lost event.
|
|
196
|
+
"""
|
|
144
197
|
self.logger.warning(
|
|
145
198
|
f"Connection lost: {event.reason if hasattr(event, 'reason') else 'Unknown reason'}"
|
|
146
199
|
)
|
|
147
200
|
|
|
148
201
|
def handle_telegram_received(self, event: TelegramReceivedEvent) -> str:
|
|
149
|
-
"""Handle received telegram events
|
|
202
|
+
"""Handle received telegram events.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
event: Telegram received event.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
Frame data from the event.
|
|
209
|
+
"""
|
|
150
210
|
self.logger.debug(
|
|
151
211
|
f"handle_telegram_received ENTERED with telegram: {event.telegram}"
|
|
152
212
|
)
|
|
@@ -176,10 +236,18 @@ class HomeKitService:
|
|
|
176
236
|
return event.frame
|
|
177
237
|
|
|
178
238
|
def dispatch_light_level_event(self, event: TelegramReceivedEvent) -> None:
|
|
179
|
-
|
|
239
|
+
"""Dispatch light level received event.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
event: Telegram received event.
|
|
243
|
+
"""
|
|
244
|
+
self.logger.debug("Light level Datapoint, parsing telegram.")
|
|
180
245
|
reply_telegram = self.telegram_service.parse_reply_telegram(event.frame)
|
|
181
246
|
self.logger.debug(
|
|
182
|
-
f"Parsed telegram:
|
|
247
|
+
f"Parsed telegram: "
|
|
248
|
+
f"serial={reply_telegram.serial_number}, "
|
|
249
|
+
f"type={reply_telegram.datapoint_type}, "
|
|
250
|
+
f"value={reply_telegram.data_value}"
|
|
183
251
|
)
|
|
184
252
|
self.logger.debug("About to dispatch LightLevelReceivedEvent")
|
|
185
253
|
self.event_bus.dispatch(
|
|
@@ -192,10 +260,18 @@ class HomeKitService:
|
|
|
192
260
|
self.logger.debug("LightLevelReceivedEvent dispatched successfully")
|
|
193
261
|
|
|
194
262
|
def dispatch_output_state_event(self, event: TelegramReceivedEvent) -> None:
|
|
195
|
-
|
|
263
|
+
"""Dispatch output state received event.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
event: Telegram received event.
|
|
267
|
+
"""
|
|
268
|
+
self.logger.debug("Module Read Datapoint, parsing telegram.")
|
|
196
269
|
reply_telegram = self.telegram_service.parse_reply_telegram(event.frame)
|
|
197
270
|
self.logger.debug(
|
|
198
|
-
f"Parsed telegram:
|
|
271
|
+
f"Parsed telegram: "
|
|
272
|
+
f"serial={reply_telegram.serial_number}, "
|
|
273
|
+
f"type={reply_telegram.datapoint_type}, "
|
|
274
|
+
f"value={reply_telegram.data_value}"
|
|
199
275
|
)
|
|
200
276
|
self.logger.debug("About to dispatch OutputStateReceivedEvent")
|
|
201
277
|
self.event_bus.dispatch(
|
|
@@ -210,7 +286,12 @@ class HomeKitService:
|
|
|
210
286
|
def dispatch_event_telegram_received_event(
|
|
211
287
|
self, event: TelegramReceivedEvent
|
|
212
288
|
) -> None:
|
|
213
|
-
|
|
289
|
+
"""Dispatch event telegram received event.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
event: Telegram received event.
|
|
293
|
+
"""
|
|
294
|
+
self.logger.debug("Event telegram received, parsing.")
|
|
214
295
|
|
|
215
296
|
# Parse event telegram to extract module information
|
|
216
297
|
event_telegram = self.telegram_service.parse_event_telegram(event.frame)
|
|
@@ -238,6 +319,11 @@ class HomeKitService:
|
|
|
238
319
|
self.logger.debug("ModuleStateChangedEvent dispatched successfully")
|
|
239
320
|
|
|
240
321
|
def dispatch_module_discovered_event(self, event: TelegramReceivedEvent) -> None:
|
|
322
|
+
"""Dispatch module discovered event.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
event: Telegram received event.
|
|
326
|
+
"""
|
|
241
327
|
self.logger.debug("Module discovered, dispatching ModuleDiscoveredEvent")
|
|
242
328
|
self.event_bus.dispatch(
|
|
243
329
|
ModuleDiscoveredEvent(
|
|
@@ -253,6 +339,14 @@ class HomeKitService:
|
|
|
253
339
|
self.logger.debug("ModuleDiscoveredEvent dispatched successfully")
|
|
254
340
|
|
|
255
341
|
def handle_module_discovered(self, event: ModuleDiscoveredEvent) -> str:
|
|
342
|
+
"""Handle module discovered event.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
event: Module discovered event.
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
Serial number of the discovered module.
|
|
349
|
+
"""
|
|
256
350
|
self.logger.debug("Handling module discovered event")
|
|
257
351
|
|
|
258
352
|
# Replace R with S and F01D with F02D00
|