From 4b77217641cf8715855a55a541e43259c9040694 Mon Sep 17 00:00:00 2001 From: hdlee27 <54927573+hdlee27@users.noreply.github.com> Date: Wed, 9 Apr 2025 03:37:24 +0100 Subject: [PATCH 1/6] fp2: Add offline check logic and remove inefficient code Signed-off-by: hdlee27 <54927573+hdlee27@users.noreply.github.com> --- drivers/Aqara/aqara-presence-sensor/src/init.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/Aqara/aqara-presence-sensor/src/init.lua b/drivers/Aqara/aqara-presence-sensor/src/init.lua index c0d0e953b9..1bd2ba0373 100644 --- a/drivers/Aqara/aqara-presence-sensor/src/init.lua +++ b/drivers/Aqara/aqara-presence-sensor/src/init.lua @@ -125,7 +125,6 @@ local function create_monitoring_thread(driver, device, device_info) local monitoring_interval = DEFAULT_MONITORING_INTERVAL local new_timer = device.thread:call_on_schedule(monitoring_interval, function() check_and_update_connection(driver, device) - driver.device_manager.device_monitor(driver, device, device_info) end, "monitor_timer") device:set_field(fields.MONITORING_TIMER, new_timer) end @@ -194,6 +193,13 @@ local function device_init(driver, device) update_connection(driver, device, device_ip, device_info) + local eventsource = device:get_field(fields.EVENT_SOURCE) + if not eventsource then + log.error_with({ hub_logs = true }, "failed to create EVENT_SOURCE.") + device:offline() + return + end + do_refresh(driver, device, nil) end From 4344bd429899be5b0e3ae4ce6f03dd46f2bb77e4 Mon Sep 17 00:00:00 2001 From: hdlee27 <54927573+hdlee27@users.noreply.github.com> Date: Wed, 9 Apr 2025 06:21:48 +0100 Subject: [PATCH 2/6] fp2: add disconnect log Signed-off-by: hdlee27 <54927573+hdlee27@users.noreply.github.com> --- drivers/Aqara/aqara-presence-sensor/src/fields.lua | 3 ++- drivers/Aqara/aqara-presence-sensor/src/init.lua | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/Aqara/aqara-presence-sensor/src/fields.lua b/drivers/Aqara/aqara-presence-sensor/src/fields.lua index 2df3fb0708..9f07db292e 100644 --- a/drivers/Aqara/aqara-presence-sensor/src/fields.lua +++ b/drivers/Aqara/aqara-presence-sensor/src/fields.lua @@ -10,7 +10,8 @@ local fields = { EVENT_SOURCE = "eventsource", MONITORING_TIMER = "monitoring_timer", CREDENTIAL = "credential", - _INIT = "init" + _INIT = "init", + CONNECTION_STATUS = "connection_status" } return fields diff --git a/drivers/Aqara/aqara-presence-sensor/src/init.lua b/drivers/Aqara/aqara-presence-sensor/src/init.lua index 1bd2ba0373..531a784ed9 100644 --- a/drivers/Aqara/aqara-presence-sensor/src/init.lua +++ b/drivers/Aqara/aqara-presence-sensor/src/init.lua @@ -54,13 +54,22 @@ local function create_sse(driver, device, credential) end eventsource.onerror = function() - log.error(string.format("Eventsource error: dni= %s", device.device_network_id)) + local DISCONNECTED_STATUS = "disconnected" + local connection_status = device:get_field(fields.CONNECTION_STATUS) + if connection_status and connection_status == DISCONNECTED_STATUS then + log.error(string.format("Eventsource error: dni= %s", device.device_network_id)) + else + log.error_with({ hub_logs = true }, string.format("Eventsource error: disconnected, dni= %s", device.device_network_id)) + device:set_field(fields.CONNECTION_STATUS, DISCONNECTED_STATUS) + end device:offline() + end eventsource.onopen = function() log.info_with({ hub_logs = true }, string.format("Eventsource open: dni= %s", device.device_network_id)) device:online() + device:set_field(fields.CONNECTION_STATUS, "connected") local success, err = status_update(driver, device) if not success then log.warn(string.format("Failed to status_update during eventsource.onopen, err = %s dni= %s", err, device.device_network_id)) From 5c7ad8762057b0dcd453feee7e2c8f19ed0fe699 Mon Sep 17 00:00:00 2001 From: hdlee27 <54927573+hdlee27@users.noreply.github.com> Date: Wed, 9 Apr 2025 06:22:22 +0100 Subject: [PATCH 3/6] fp2: Reuse device_info to shorten onboarding time Signed-off-by: hdlee27 <54927573+hdlee27@users.noreply.github.com> --- .../Aqara/aqara-presence-sensor/src/discovery.lua | 8 ++++---- .../src/fp2/discovery_helper.lua | 12 +++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/Aqara/aqara-presence-sensor/src/discovery.lua b/drivers/Aqara/aqara-presence-sensor/src/discovery.lua index fd68872679..5678f62d19 100644 --- a/drivers/Aqara/aqara-presence-sensor/src/discovery.lua +++ b/drivers/Aqara/aqara-presence-sensor/src/discovery.lua @@ -22,8 +22,7 @@ function discovery.set_device_field(driver, device) driver.datastore.discovery_cache[device.device_network_id] = nil end -local function update_device_discovery_cache(driver, dni, ip) - local device_info = driver.discovery_helper.get_device_info(driver, dni, ip) +local function update_device_discovery_cache(driver, dni, ip, device_info) if driver.datastore.discovery_cache[dni] == nil then driver.datastore.discovery_cache[dni] = {} end @@ -33,9 +32,10 @@ end local function try_add_device(driver, device_dni, device_ip) log.trace(string.format("try_add_device : dni= %s, ip= %s", device_dni, device_ip)) + local device_info = driver.discovery_helper.get_device_info(driver, device_dni, device_ip) - update_device_discovery_cache(driver, device_dni, device_ip) - local create_device_msg = driver.discovery_helper.get_device_create_msg(driver, device_dni, device_ip) + update_device_discovery_cache(driver, device_dni, device_ip, device_info) + local create_device_msg = driver.discovery_helper.get_device_create_msg(driver, device_dni, device_ip, device_info) local credential = driver.discovery_helper.get_credential(driver, device_dni, device_ip) diff --git a/drivers/Aqara/aqara-presence-sensor/src/fp2/discovery_helper.lua b/drivers/Aqara/aqara-presence-sensor/src/fp2/discovery_helper.lua index dcc24b61dd..422b690db4 100644 --- a/drivers/Aqara/aqara-presence-sensor/src/fp2/discovery_helper.lua +++ b/drivers/Aqara/aqara-presence-sensor/src/fp2/discovery_helper.lua @@ -25,12 +25,14 @@ function discovery_helper.get_service_type_and_domain() return SERVICE_TYPE, DOMAIN end -function discovery_helper.get_device_create_msg(driver, device_dni, device_ip) - local device_info = fp2_api.get_info(device_ip, fp2_api.labeled_socket_builder(device_dni)) - +function discovery_helper.get_device_create_msg(driver, device_dni, device_ip, device_info) if not device_info then - log.warn("failed to create device create msg. device_info is nil.") - return nil + device_info = fp2_api.get_info(device_ip, fp2_api.labeled_socket_builder(device_dni)) + + if not device_info then + log.warn("failed to create device create msg. device_info is nil.") + return nil + end end local device_label = device_info.label or "Aqara-FP2" From 6f181d1874022da413625b49a7e21bef3936f7cf Mon Sep 17 00:00:00 2001 From: hdlee27 <54927573+hdlee27@users.noreply.github.com> Date: Wed, 9 Apr 2025 08:29:56 +0100 Subject: [PATCH 4/6] fp2: wait device remove action Signed-off-by: hdlee27 <54927573+hdlee27@users.noreply.github.com> --- .../Aqara/aqara-presence-sensor/src/init.lua | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/Aqara/aqara-presence-sensor/src/init.lua b/drivers/Aqara/aqara-presence-sensor/src/init.lua index 531a784ed9..dd38f98506 100644 --- a/drivers/Aqara/aqara-presence-sensor/src/init.lua +++ b/drivers/Aqara/aqara-presence-sensor/src/init.lua @@ -1,4 +1,5 @@ local log = require "log" +local socket = require "cosock.socket" local capabilities = require "st.capabilities" local Driver = require "st.driver" local discovery = require "discovery" @@ -153,15 +154,19 @@ end local function device_removed(driver, device) local conn_info = device:get_field(fields.CONN_INFO) + driver.removing_devices = driver.removing_devices + 1 + log.info_with({ hub_logs = true }, string.format("Device removed: dni= %s", device.device_network_id)) if not conn_info then - log.warn(string.format("remove : failed to find conn_info, dni = %s", device.device_network_id)) + log.warn_with({ hub_logs = true }, string.format("remove : failed to find conn_info, dni = %s", device.device_network_id)) else local _, err, status = conn_info:get_remove() if err or status ~= 200 then - log.error(string.format("remove : failed to get remove, dni= %s, err= %s, status= %s", device.device_network_id, + log.error_with({ hub_logs = true }, string.format("remove : failed to get remove, dni= %s, err= %s, status= %s", device.device_network_id, err, status)) + else + log.info_with({ hub_logs = true }, string.format("Device removed: token reset success. dni= %s", device.device_network_id)) end end @@ -169,6 +174,7 @@ local function device_removed(driver, device) if eventsource then eventsource:close() end + driver.removing_devices = driver.removing_devices - 1 end local function device_init(driver, device) @@ -216,6 +222,27 @@ local function device_info_changed(driver, device, event, args) do_refresh(driver, device, nil) end +local function driver_lifecycle_handler(driver, event_name) + log.info(string.format("driver lifecycle event :'%s'", event_name)) + if event_name == "shutdown" then + local MAXIMUM_WAITING_TIME = 30 + local WAITING_TIME = 1 + local total_waiting_time = 0 + + while (driver.removing_devices > 0) do + log.info("waiting for all devices to be removed") + total_waiting_time = total_waiting_time + WAITING_TIME + socket.sleep(WAITING_TIME) -- wait for 1 seconds + + if total_waiting_time > MAXIMUM_WAITING_TIME then + log.error_with({ hub_logs = true }, "maximum waiting time exceeded") + end + end + log.info(string.format("forced exit")) + os.exit(0) + end +end + local lan_driver = Driver("aqara-fp2", { discovery = discovery.do_network_discovery, @@ -225,6 +252,7 @@ local lan_driver = Driver("aqara-fp2", infoChanged = device_info_changed, removed = device_removed }, + driver_lifecycle = driver_lifecycle_handler, capability_handlers = { [capabilities.refresh.ID] = { [capabilities.refresh.commands.refresh.NAME] = do_refresh, @@ -236,6 +264,7 @@ local lan_driver = Driver("aqara-fp2", discovery_helper = fp2_discovery_helper, device_manager = fp2_device_manager, controlled_devices = {}, + removing_devices = 0 } ) From 896de11ac0135a25517ca321ca1b5d838a8092b2 Mon Sep 17 00:00:00 2001 From: hdlee27 <54927573+hdlee27@users.noreply.github.com> Date: Wed, 9 Apr 2025 08:58:05 +0100 Subject: [PATCH 5/6] fp2: Double check whether the device is already registered If there are many fp2 devices in the network, the waiting time increases, and the device added during waiting is attempted to re-register. To prevent this problem, check whether it is registered again. Signed-off-by: hdlee27 <54927573+hdlee27@users.noreply.github.com> --- drivers/Aqara/aqara-presence-sensor/src/discovery.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/Aqara/aqara-presence-sensor/src/discovery.lua b/drivers/Aqara/aqara-presence-sensor/src/discovery.lua index 5678f62d19..29b944e072 100644 --- a/drivers/Aqara/aqara-presence-sensor/src/discovery.lua +++ b/drivers/Aqara/aqara-presence-sensor/src/discovery.lua @@ -93,7 +93,14 @@ local function discovery_device(driver) for dni, ip in pairs(unknown_discovered_devices) do log.trace(string.format("unknown dni= %s, ip= %s", dni, ip)) - if not processing_devices[dni] then + local is_already_added = false + for _, device in pairs(driver:get_devices()) do + if device.device_network_id == dni then + is_already_added = true + break + end + end + if (not processing_devices[dni]) and (not is_already_added) then try_add_device(driver, dni, ip) end end From d14c2e373984ebdb57ab5563472b3c3db5409575 Mon Sep 17 00:00:00 2001 From: hdlee27 <54927573+hdlee27@users.noreply.github.com> Date: Thu, 10 Apr 2025 06:59:22 +0100 Subject: [PATCH 6/6] fp2: eventsource: stop reconnect for unauthorized status Signed-off-by: hdlee27 <54927573+hdlee27@users.noreply.github.com> --- .../src/lunchbox/sse/eventsource.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/Aqara/aqara-presence-sensor/src/lunchbox/sse/eventsource.lua b/drivers/Aqara/aqara-presence-sensor/src/lunchbox/sse/eventsource.lua index 5afc79fc98..8012c96bab 100644 --- a/drivers/Aqara/aqara-presence-sensor/src/lunchbox/sse/eventsource.lua +++ b/drivers/Aqara/aqara-presence-sensor/src/lunchbox/sse/eventsource.lua @@ -7,6 +7,8 @@ local util = require "lunchbox.util" local Request = require "luncheon.request" local Response = require "luncheon.response" +local MAX_RECONNECT_TIME_SEC = 60 + --- A pure Lua implementation of the EventSource interface. --- The EventSource interface represents the client end of an HTTP(S) --- connection that receives an event stream following the Server-Sent events @@ -302,6 +304,11 @@ local function connecting_action(source) return nil, err or "nil response from Response.tcp_source" end + if response.status == 401 then + source._reconnect = false + return nil, "Server response is 401 Unauthorized, stop reconnect", { response.status, response.status_msg } + end + if response.status ~= 200 then return nil, "Server responded with status other than 200 OK", { response.status, response.status_msg } end @@ -317,6 +324,8 @@ local function connecting_action(source) end source.ready_state = EventSource.ReadyStates.OPEN + source._reconnect = true + source._reconnect_time_millis = 1000 if type(source.onopen) == "function" then source.onopen() @@ -418,7 +427,9 @@ local function closed_action(source) local sleep_time_secs = source._reconnect_time_millis / 1000.0 socket.sleep(sleep_time_secs) - + if source._reconnect_time_millis <= MAX_RECONNECT_TIME_SEC * 1000 then + source._reconnect_time_millis = source._reconnect_time_millis + 1000.0 + end source.ready_state = EventSource.ReadyStates.CONNECTING end end