Skip to content

Commit

Permalink
Merge pull request #1831 from SmartThingsCommunity/fix/hue-multibutto…
Browse files Browse the repository at this point in the history
…n-remote-reliability

Hue: Fix multi-component device initialization race condition
  • Loading branch information
dljsjr authored Dec 19, 2024
2 parents ac0ebbb + 6b62177 commit f4868ab
Show file tree
Hide file tree
Showing 24 changed files with 184 additions and 14 deletions.
3 changes: 3 additions & 0 deletions drivers/SmartThings/philips-hue/src/disco/button.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local log = require "log"
local socket = require "cosock".socket
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local HueDeviceTypes = require "hue_device_types"

Expand Down
3 changes: 3 additions & 0 deletions drivers/SmartThings/philips-hue/src/disco/contact.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local log = require "log"
local socket = require "cosock".socket
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local HueDeviceTypes = require "hue_device_types"

Expand Down
3 changes: 3 additions & 0 deletions drivers/SmartThings/philips-hue/src/disco/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ local socket = require "cosock.socket"
local mdns = require "st.mdns"
local net_utils = require "st.net_utils"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local Fields = require "fields"
local HueApi = require "hue.api"
Expand Down
3 changes: 3 additions & 0 deletions drivers/SmartThings/philips-hue/src/disco/light.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local log = require "log"
local socket = require "cosock".socket
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local HueDeviceTypes = require "hue_device_types"

Expand Down
3 changes: 3 additions & 0 deletions drivers/SmartThings/philips-hue/src/disco/motion.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local log = require "log"
local socket = require "cosock".socket
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local HueDeviceTypes = require "hue_device_types"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local capabilities = require "st.capabilities"
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: table, name: string?, multi_line: boolean?): string
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local Consts = require "consts"
Expand Down
5 changes: 4 additions & 1 deletion drivers/SmartThings/philips-hue/src/handlers/commands.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local Consts = require "consts"
local Fields = require "fields"
Expand All @@ -8,7 +11,7 @@ local HueColorUtils = require "utils.cie_utils"
local utils = require "utils"

-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: table, name: string?, multi_line: boolean?): string
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

---@class CommandHandlers
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local capabilities = require "st.capabilities"
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local refresh_handler = require("handlers.commands").refresh_handler

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local refresh_handler = require("handlers.commands").refresh_handler

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local capabilities = require "st.capabilities"

local Discovery = require "disco"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ local log = require "log"
local capabilities = require "st.capabilities"
local refresh_handler = require("handlers.commands").refresh_handler
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local Consts = require "consts"
local Discovery = require "disco"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local refresh_handler = require("handlers.commands").refresh_handler

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local capabilities = require "st.capabilities"
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local Discovery = require "disco"
local Fields = require "fields"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local cosock = require "cosock"
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local Fields = require "fields"
local HueDeviceTypes = require "hue_device_types"
Expand Down Expand Up @@ -123,6 +126,7 @@ function RefreshHandlers.do_refresh_all_for_bridge(driver, bridge_device)
-- but only the first time we encounter a device type. We cache them since we're refreshing
-- everything.
if
device_type and
type(device_type_refresh_handlers_map[device_type]) == "function" and
statuses_by_device_type[device_type] == nil
then
Expand Down
10 changes: 9 additions & 1 deletion drivers/SmartThings/philips-hue/src/hue/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ local json = require "st.json"
local log = require "log"
local RestClient = require "lunchbox.rest"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local HueDeviceTypes = require "hue_device_types"

-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: table, name: string?, multi_line: boolean?): string
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local APPLICATION_KEY_HEADER = "hue-application-key"
Expand Down Expand Up @@ -82,6 +85,7 @@ end
---@return table? tbl the table representation of the JSON response, nil on error
---@return string? err the error message, nil on success
---@return string? partial the partial response if the response was not complete
---@return ...
local function process_rest_response(response, err, partial, err_callback)
if err == nil and response == nil then
log.error_with({ hub_logs = true },
Expand Down Expand Up @@ -208,6 +212,7 @@ end
---@param path string
---@return table|nil response REST response, nil if error
---@return nil|string error nil on success
---@return ...
local function do_get(instance, path)
local reply_tx, reply_rx = channel.new()
reply_rx:settimeout(10)
Expand All @@ -226,6 +231,7 @@ end
---@param payload string
---@return table|nil response REST response, nil if error
---@return nil|string error nil on success
---@return ...
local function do_put(instance, path, payload)
local reply_tx, reply_rx = channel.new()
reply_rx:settimeout(10)
Expand All @@ -244,6 +250,7 @@ end
---@return HueBridgeInfo|nil bridge_info nil on err
---@return nil|string error nil on success
---@return nil|string partial partial response if available, nil otherwise
---@return ...
function PhilipsHueApi.get_bridge_info(bridge_ip, socket_builder)
local tx, rx = channel.new()
rx:settimeout(10)
Expand All @@ -266,6 +273,7 @@ end
---@return HueApiKeyResponse[]? api_key_response nil on err
---@return string? error nil on success
---@return string? partial partial response if available, nil otherwise
---@return ...
function PhilipsHueApi.request_api_key(bridge_ip, socket_builder)
local tx, rx = channel.new()
rx:settimeout(10)
Expand Down
3 changes: 3 additions & 0 deletions drivers/SmartThings/philips-hue/src/hue_debug/init.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local log = require "log"
local utils = require "utils"
Expand Down
8 changes: 6 additions & 2 deletions drivers/SmartThings/philips-hue/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
-- Improvements to be made:
--
-- ===============================================================================================
local Driver = require "st.driver"
local logjam = require "logjam"
logjam.enable_passthrough()
logjam.inject_global()

local log = require "log"

local Driver = require "st.driver"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: table, name: string?, multi_line: boolean?): string
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local Discovery = require "disco"
Expand Down
108 changes: 101 additions & 7 deletions drivers/SmartThings/philips-hue/src/logjam.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,84 @@
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local logjam = {}

logjam.real_log = log.log

logjam.enabled_modules = {}

function logjam.inject_global()
for field_key, level_key in pairs(log) do
if
string.find(field_key, "LOG_LEVEL_") and
type(level_key) == "string" and
type(log[level_key]) == "function"
then
log[level_key] = logjam[level_key]
local level_with_key = string.format("%s_with", level_key)
if type(log[level_with_key]) == "function" then
log[level_with_key] = logjam[level_with_key]
end
end
end
log.log = logjam.log
end

function logjam.enable_passthrough()
logjam.passthrough = true
end

function logjam.disable_passthrough()
logjam.passthrough = false
end

function logjam.enable(module)
logjam.enabled_modules[module] = true
end

function logjam.disable(module)
logjam.enabled_modules[module] = nil
end

function logjam.log(opts, level, ...)
if opts.on == true then
log.log(opts, level, ...)
local call_info
if not opts.call_info then
call_info = debug.getinfo(2)
else
call_info = opts.call_info
end
opts.call_info = nil

local module_name = nil
if type(call_info.source) == "string" then
module_name =
call_info.source
:gsub("%.lua", "")
:gsub("/init", "")
:gsub("/", ".")
:gsub("^init$", "philips-hue")
end

local module_enabled = false
local module_prefix = ""
if type(module_name) == "string" and module_name:len() > 0 then
module_enabled = logjam.enabled_modules[module_name]
module_prefix = string.format("[%s] ", module_name)
end

-- explicit on/off log option takes precedence, so that we can allow
-- `false` to override passthrough/module_enabled flags.
if type(opts.on) == "boolean" then
if opts.on then
logjam.real_log(opts, level, module_prefix, ...)
end
return
end
if logjam.passthrough or module_enabled then
logjam.real_log(opts, level, module_prefix, ...)
end
end

Expand All @@ -16,16 +91,35 @@ for field_key, level_key in pairs(log) do
local level_with_key = string.format("%s_with", level_key)
logjam[level_key] = function(...)
local first_arg = select(1, ...)
if first_arg == true or (type(first_arg) == "table" and first_arg.on == true) then
log[level_key](select(2, ...))
local opts = {}
local log_args_start_idx = 1
if type(first_arg) == "boolean" then
opts.on = first_arg
log_args_start_idx = 2
elseif type(first_arg) == "table" then
opts = first_arg
log_args_start_idx = 2
end
local info = debug.getinfo(2)
opts.call_info = info
logjam.log(opts, level_key, select(log_args_start_idx, ...))
end

logjam[level_with_key] = function(opts, ...)
opts = opts or {}
if opts.on == true then
log[level_with_key](...)
local log_opts = {}
local log_args = table.pack(...)
if type(opts) == "table" then
for k, v in pairs(opts) do
log_opts[k] = v
end
elseif type(opts) == "boolean" then
log_opts.on = opts
elseif opts ~= nil then
log_args.insert(log_args, 1, opts)
end
local info = debug.getinfo(2)
log_opts.call_info = info
logjam.log(log_opts, level_key, table.unpack(log_args))
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ local ssl = require "cosock.ssl"
---@type fun(sock: table, config: table?): table?, string?
ssl.wrap = ssl.wrap

local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local log = require "log"
local util = require "lunchbox.util"
local Request = require "luncheon.request"
Expand Down Expand Up @@ -474,7 +479,6 @@ function EventSource.new(url, extra_headers, sock_builder)
}, EventSource)

cosock.spawn(function()
local st_utils = require "st.utils"
while true do
if source.ready_state == EventSource.ReadyStates.CLOSED and
not source._reconnect
Expand Down
3 changes: 3 additions & 0 deletions drivers/SmartThings/philips-hue/src/stray_device_helper.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local cosock = require "cosock"
local log = require "log"
local st_utils = require "st.utils"
-- trick to fix the VS Code Lua Language Server typechecking
---@type fun(val: any?, name: string?, multi_line: boolean?): string
st_utils.stringify_table = st_utils.stringify_table

local Discovery = require "disco"
local Fields = require "fields"
Expand Down
Loading

0 comments on commit f4868ab

Please sign in to comment.