When HA restarts without a clean DTLS close_notify (crash, host reboot), the appliance keeps an orphaned DTLS association keyed to the client's (IP, source port). Reconnecting from a fresh ephemeral port looks like a new peer, so the device holds the orphan until its own timer reaps it, which is 5 to 15 min on always-on appliances (fridges), during which the new session's first reads hang. This is the root cause behind the repeated "DTLS handshake timeout" reconnect storms on always-on devices (#119). Bind a deterministic source port per device so every reconnect re-handshakes over the same 5-tuple, which the device must treat as a rebooted peer and evict the old association for (RFC 6347 §4.2.8). Recovery drops from a device-timer wait to a single handshake. The port must be stable across restarts and unique per device on the HA host (the library socket is unconnected, so a shared source port would cross- deliver datagrams). _local_source_port() uses the host's last IPv4 octet as the offset from DTLS_LOCAL_PORT_BASE (unique on a /24), with a CRC32 fallback for non-IPv4 hosts. Requires smartthings-local >= 0.1.1, which adds DtlsCoapSession(local_port=). The fix is backwards compatible upstream: local_port defaults to None (previous ephemeral-port behaviour). Root-caused and verified upstream in QuiteYellow/SmartThings-Local#14 (bench-verified on oven + dryer, field-verified on an always-on fridge across repeated restarts).
57 lines
2.4 KiB
Python
57 lines
2.4 KiB
Python
DOMAIN = "localthings"
|
|
|
|
PLATFORMS = [
|
|
"sensor", "binary_sensor", "switch", "number", "select", "button",
|
|
"time", "climate", "fan",
|
|
]
|
|
|
|
CONF_HOST = "host"
|
|
CONF_PORT = "port"
|
|
CONF_CA_CERT_PEM = "ca_cert_pem"
|
|
CONF_CA_KEY_PEM = "ca_key_pem"
|
|
CONF_LEAF_CERT_PEM = "leaf_cert_pem"
|
|
CONF_LEAF_KEY_PEM = "leaf_key_pem"
|
|
|
|
# Options-flow key (entry.options, not entry.data): lets a user override the
|
|
# device-wide remote-control-off write block for a specific device (issue
|
|
# #54). Some devices report remote control off yet still accept certain
|
|
# writes (e.g. default detergent/softener dosing on a washer, applied even
|
|
# to the built-in programs) -- the block exists to give a clear error
|
|
# instead of a silent device-side rejection, but that assumption doesn't
|
|
# hold for every model. Defaults to False (block stays on) everywhere it's
|
|
# read, so devices this doesn't apply to see no behavior change.
|
|
CONF_BYPASS_REMOTE_CONTROL = "bypass_remote_control_lock"
|
|
|
|
# The DTLS/CoAP local API binds somewhere in this ephemeral range; which port
|
|
# depends on firmware. Newer builds answer on 49154/49155, but older ones have
|
|
# been seen as low as 49153, so we sweep the whole range for a live UDP port
|
|
# before attempting the (expensive) DTLS handshake.
|
|
PROBE_PORT_RANGE = list(range(49152, 49161))
|
|
|
|
# Ports we've historically seen complete a DTLS handshake. When more than one
|
|
# port in the range looks live, these are tried first.
|
|
PREFERRED_PROBE_PORTS = [49154, 49155]
|
|
|
|
# Per-port timeout for the cheap UDP liveness sweep. Closed ports return an
|
|
# ICMP port-unreachable almost immediately; a live-but-silent port is only
|
|
# detected by this timeout elapsing, so keep it short.
|
|
LIVENESS_PROBE_TIMEOUT_S = 1.5
|
|
|
|
# Deadline for the blockwise /device/0 GET during the config-flow probe. The
|
|
# slowest device observed returns a full dump in ~8s, so 10s leaves headroom
|
|
# without stalling setup; it matches the per-resource read timeout elsewhere.
|
|
PROBE_GET_TIMEOUT_S = 10.0
|
|
|
|
# Base for the local (client-side) DTLS source port, distinct from the
|
|
# destination probe ports above. See coordinator._local_source_port for why a
|
|
# fixed per-device source port matters and how the per-device offset is
|
|
# derived. Base mirrors the upstream smartthings-local reference bridge.
|
|
# Requires smartthings-local >= 0.1.1.
|
|
DTLS_LOCAL_PORT_BASE = 49700
|
|
|
|
SUMMARY_INTERVAL_S = 30.0
|
|
|
|
DEVICE_SUPPORT_ISSUE_URL = (
|
|
"https://github.com/mbillow/localthings/issues/new?template=device-support.yml"
|
|
)
|