8000 Event firing and handling on status changes by alengwenus · Pull Request #129 · alengwenus/pypck · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Event firing and handling on status changes #129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
653 changes: 293 additions & 360 deletions pypck/connection.py

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions pypck/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,45 @@ def try_parse(data: str) -> list[Input] | None:
return None


class Ping(Input):
"""Ping message received from PCHK."""

def __init__(self, count: int | None):
"""Construct Input object."""
super().__init__()
self._count = count

@property
def count(self) -> int | None:
"""Return the ping count.

:return: Ping count
:rtype: int | None
"""
return self._count

@staticmethod
def try_parse(data: str) -> list[Input] | None:
"""Try to parse the given input text.

Will return a list of parsed Inputs. The list might be empty (but not
null).

:param data str: The input data received from LCN-PCHK

:return: The parsed Inputs (never null)
:rtype: List with instances of :class:`~pypck.input.Input`
"""
matcher = PckParser.PATTERN_PING.match(data)
if matcher:
count = matcher.group("count")
if count == "":
return [Ping(None)]
return [Ping(int(count))]

return None


# ## Inputs received from modules


Expand Down Expand Up @@ -1136,6 +1175,7 @@ class InputParser:
LicenseError,
DecModeSet,
CommandError,
Ping,
ModAck,
ModNameComment,
ModSk,
Expand Down
35 changes: 26 additions & 9 deletions pypck/lcn_defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1381,26 +1381,43 @@ class AccessControlPeriphery(Enum):
CODELOCK = "codelock"


class LcnEvent(Enum):
"""LCN events."""

CONNECTION_ESTABLISHED = "connection-established"
CONNECTION_LOST = "connection-lost"
CONNECTION_REFUSED = "connection-refused"
CONNECTION_TIMEOUT = "connection-timeout"
PING_TIMEOUT = "ping-timeout"
TIMEOUT_ERROR = "timeout-error"
LICENSE_ERROR = "license-error"
AUTHENTICATION_ERROR = "authentic 8000 ation-error"
BUS_CONNECTED = "bus-connected"
BUS_DISCONNECTED = "bus-disconnected"
BUS_CONNECTION_STATUS_CHANGED = "bus-connection-status-changed"


default_connection_settings: dict[str, Any] = {
"NUM_TRIES": 3, # Total number of request to sent before going into
# failed-state.
"SK_NUM_TRIES": 3, # Total number of segment coupler scan tries
"DIM_MODE": OutputPortDimMode.STEPS50,
"ACKNOWLEDGE": True, # modules request an acknowledge command
"PING_TIMEOUT": 600000, # The default timeout for pings sent to PCHK.
"DEFAULT_TIMEOUT_MSEC": 3500, # Default timeout for send command retries
"MAX_STATUS_EVENTBASED_VALUEAGE_MSEC": 600000, # Poll interval for
"DEFAULT_TIMEOUT": 3.5, # Default timeout for send command retries
"MAX_STATUS_EVENTBASED_VALUEAGE": 600, # Poll interval for
# status values that
# automatically send
# their values on change.
"MAX_STATUS_POLLED_VALUEAGE_MSEC": 30000, # Poll interval for status
# their values on change
"MAX_STATUS_POLLED_VALUEAGE": 30, # Poll interval for status
# values that do not send
# their values on change
# (always polled).
"STATUS_REQUEST_DELAY_AFTER_COMMAND_MSEC": 2000, # Status request delay
# (always polled)
"STATUS_REQUEST_DELAY_AFTER_COMMAND": 2, # Status request delay
# after a command has
# been send which
# potentially changed
# that status.
"BUS_IDLE_TIME": 0.05, # Time to wait for message traffic before sending.
# that status
"BUS_IDLE_TIME": 0.05, # Time to wait for message traffic before sending
"PING_SEND_DELAY": 600, # The default timeout for pings sent to PCHK
"PING_RECV_TIMEOUT": 10, # The default timeout for pings expected from PCHK
}
20 changes: 8 additions & 12 deletions pypck/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -768,31 +768,27 @@ def __init__(

# RequestHandlers
num_tries: int = self.conn.settings["NUM_TRIES"]
timeout_msec: int = self.conn.settings["DEFAULT_TIMEOUT_MSEC"]
timeout: int = self.conn.settings["DEFAULT_TIMEOUT"]

# Serial Number request
self.serials_request_handler = SerialRequestHandler(
self,
num_tries,
timeout_msec,
timeout,
software_serial=software_serial,
)

# Name, Comment, OemText requests
self.name_request_handler = NameRequestHandler(self, num_tries, timeout_msec)
self.comment_request_handler = CommentRequestHandler(
self, num_tries, timeout_msec
)
self.oem_text_request_handler = OemTextRequestHandler(
self, num_tries, timeout_msec
)
self.name_request_handler = NameRequestHandler(self, num_tries, timeout)
self.comment_request_handler = CommentRequestHandler(self, num_tries, timeout)
self.oem_text_request_handler = OemTextRequestHandler(self, num_tries, timeout)

# Group membership request
self.static_groups_request_handler = GroupMembershipStaticRequestHandler(
self, num_tries, timeout_msec
self, num_tries, timeout
)
self.dynamic_groups_request_handler = GroupMembershipDynamicRequestHandler(
self, num_tries, timeout_msec
self, num_tries, timeout
)

self.status_requests_handler = StatusRequestsHandler(self)
Expand Down Expand Up @@ -830,7 +826,7 @@ async def send_command_with_ack(self, pck: str | bytes) -> bool:
try:
code = await asyncio.wait_for(
self.acknowledges.get(),
timeout=self.conn.settings["DEFAULT_TIMEOUT_MSEC"] / 1000,
timeout=self.conn.settings["DEFAULT_TIMEOUT"],
)
except asyncio.TimeoutError:
count += 1
Expand Down
3 changes: 3 additions & 0 deletions pypck/pck_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class PckParser:
# Pattern to parse error messages.
PATTERN_COMMAND_ERROR = re.compile(r"\((?P<message>.+)\?\)")

# Pattern to parse ping messages.
PATTERN_PING = re.compile(r"\^ping(?P<count>\d*)-")

# Pattern to parse positive acknowledges.
PATTERN_ACK_POS = re.compile(r"-M(?P<seg_id>\d{3})(?P<mod_id>\d{3})!")

Expand Down
52 changes: 26 additions & 26 deletions pypck/request_handlers.py
F438
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ def __init__(
self,
addr_conn: ModuleConnection,
num_tries: int = 3,
timeout_msec: int = 1500,
timeout: float = 1.5,
):
"""Initialize class instance."""
self.addr_conn = addr_conn

self.trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout_msec)
self.trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout)
self.trh.set_timeout_callback(self.timeout)

# callback
Expand Down Expand Up @@ -69,7 +69,7 @@ def __init__(
self,
addr_conn: ModuleConnection,
num_tries: int = 3,
timeout_msec: int = 1500,
timeout: float = 1.5,
software_serial: int | None = None,
):
"""Initialize class instance."""
Expand All @@ -83,7 +83,7 @@ def __init__(
# events
self.serial_known = asyncio.Event()

super().__init__(addr_conn, num_tries, timeout_msec)
super().__init__(addr_conn, num_tries, timeout)

async def async_process_input(self, inp: inputs.Input) -> None:
"""Process incoming input object.
Expand Down Expand Up @@ -132,17 +132,17 @@ def __init__(
self,
addr_conn: ModuleConnection,
num_tries: int = 3,
timeout_msec: int = 1500,
timeout: float = 1.5,
):
"""Initialize class instance."""
self._name: list[str | None] = [None] * 2
self.name_known = asyncio.Event()

super().__init__(addr_conn, num_tries, timeout_msec)
super().__init__(addr_conn, num_tries, timeout)

self.trhs = []
for block_id in range(2):
trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout_msec)
trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout)
trh.set_timeout_callback(self.timeout, block_id=block_id)
self.trhs.append(trh)

Expand Down Expand Up @@ -205,17 +205,17 @@ def __init__(
self,
addr_conn: ModuleConnection,
num_tries: int = 3,
timeout_msec: int = 1500,
timeout: float = 1.5,
):
"""Initialize class instance."""
self._comment: list[str | None] = [None] * 3
self.comment_known = asyncio.Event()

super().__init__(addr_conn, num_tries, timeout_msec)
super().__init__(addr_conn, num_tries, timeout)

self.trhs = []
for block_id in range(3):
trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout_msec)
trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout)
trh.set_timeout_callback(self.timeout, block_id=block_id)
self.trhs.append(trh)

Expand Down Expand Up @@ -278,17 +278,17 @@ def __init__(
self,
addr_conn: ModuleConnection,
num_tries: int = 3,
timeout_msec: int = 1500,
timeout: float = 1.5,
):
"""Initialize class instance."""
self._oem_text: list[str | None] = [None] * 4
self.oem_text_known = asyncio.Event()

super().__init__(addr_conn, num_tries, timeout_msec)
super().__init__(addr_conn, num_tries, timeout)

self.trhs = []
for block_id in range(4):
trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout_msec)
trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout)
trh.set_timeout_callback(self.timeout, block_id=block_id)
self.trhs.append(trh)

Expand Down Expand Up @@ -355,13 +355,13 @@ def __init__(
self,
addr_conn: ModuleConnection,
num_tries: int = 3,
timeout_msec: int = 1500,
timeout: float = 1500,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey, didn't you miss to update the value here?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks. #131 will fix this.

):
"""Initialize class instance."""
self.groups: set[LcnAddr] = set()
self.groups_known = asyncio.Event()

super().__init__(addr_conn, num_tries, timeout_msec)
super().__init__(addr_conn, num_tries, timeout)

async def async_process_input(self, inp: inputs.Input) -> None:
"""Process incoming input object.
Expand Down Expand Up @@ -399,13 +399,13 @@ def __init__(
self,
addr_conn: ModuleConnection,
num_tries: int = 3,
timeout_msec: int = 1500,
timeout: float = 1.5,
):
"""Initialize class instance."""
self.groups: set[LcnAddr] = set()
self.groups_known = asyncio.Event()

super().__init__(addr_conn, num_tries, timeout_msec)
super().__init__(addr_conn, num_tries, timeout)

async def async_process_input(self, inp: inputs.Input) -> None:
"""Process incoming input object.
Expand Down Expand Up @@ -453,22 +453,22 @@ def __init__(self, addr_conn: ModuleConnection):
trh = TimeoutRetryHandler(
self.task_registry,
-1,
self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"],
self.settings["MAX_STATUS_EVENTBASED_VALUEAGE"],
)
trh.set_timeout_callback(self.request_status_outputs_timeout, output_port)
self.request_status_outputs.append(trh)

# Relay request status (all 8)
self.request_status_relays = TimeoutRetryHandler(
self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"]
self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE"]
)
self.request_status_relays.set_timeout_callback(
self.request_status_relays_timeout
)

# Binary-sensors request status (all 8)
self.request_status_bin_sensors = TimeoutRetryHandler(
self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"]
self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE"]
)
self.request_status_bin_sensors.set_timeout_callback(
self.request_status_bin_sensors_timeout
Expand All @@ -483,23 +483,23 @@ def __init__(self, addr_conn: ModuleConnection):
self.request_status_vars[var] = TimeoutRetryHandler(
self.task_registry,
-1,
self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"],
self.settings["MAX_STATUS_EVENTBASED_VALUEAGE"],
)
self.request_status_vars[var].set_timeout_callback(
self.request_status_var_timeout, var=var
)

# LEDs and logic-operations request status (all 12+4).
self.request_status_leds_and_logic_ops = TimeoutRetryHandler(
self.task_registry, -1, self.settings["MAX_STATUS_POLLED_VALUEAGE_MSEC"]
self.task_registry, -1, self.settings["MAX_STATUS_POLLED_VALUEAGE"]
)
self.request_status_leds_and_logic_ops.set_timeout_callback(
self.request_status_leds_and_logic_ops_timeout
)

# Key lock-states request status (all tables, A-D).
self.request_status_locked_keys = TimeoutRetryHandler(
self.task_registry, -1, self.settings["MAX_STATUS_POLLED_VALUEAGE_MSEC"]
self.task_registry, -1, self.settings["MAX_STATUS_POLLED_VALUEAGE"]
)
self.request_status_locked_keys.set_timeout_callback(
self.request_status_locked_keys_timeout
Expand Down Expand Up @@ -597,10 +597,10 @@ async def activate(self, item: Any) -> None:
# wait until we know the software version
await self.addr_conn.serial_known
if self.addr_conn.software_serial >= 0x170206:
timeout_msec = self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"]
timeout = self.settings["MAX_STATUS_EVENTBASED_VALUEAGE"]
else:
timeout_msec = self.settings["MAX_STATUS_POLLED_VALUEAGE_MSEC"]
self.request_status_vars[item].set_timeout_msec(timeout_msec)
timeout = self.settings["MAX_STATUS_POLLED_VALUEAGE"]
self.request_status_vars[item].set_timeout(timeout)
self.request_status_vars[item].activate()
elif item in lcn_defs.OutputPort:
self.request_status_outputs[item.value].activate()
Expand Down
Loading
Loading
0