# Logic implementation
The edge-app environment will automatically inject the variables set by the user into our app together with all functions defined for this installation.
The first thing we want is for the app to find each topic we need to use. I created a function to get the FunctionX with id as specified.
function findFunction(id)
for i, fun in ipairs(functions) do
if fun.id == id then
return functions[i]
end
end
end
I added a message handler that we will be bound to run every time an MQTT message is delivered on a specific topic, in this case the topic for the trigger function.
function handleTrigger(topic, payload, retained)
local data = json:decode(payload)
-- Verify that the door was opened
if data.value == openState then
-- Turn on
local payload = json:encode({ value = onValue })
mq:pub(controlTopic, payload, false, 0)
-- Start timer for off..
timer:after(cfg.timeout, function()
local payload = json:encode({ value = offValue })
mq:pub(controlTopic, payload, false, 0)
end)
end
end
This function takes action if the state corresponds to openState, it also starts a timer to turn off again.
Then all of that needs to be initialized and bound to the MQTT events. This is
done using the onStart
callback function. The function will be called
automatically when the app starts. Here we also set the values for the different
states and variables.
function onStart()
-- Get all values for the trigger
local triggerFunction = findFunction(cfg.trigger_function)
openState = triggerFunction.meta.state_open
closedState = triggerFunction.meta.state_closed
local controlFunction = findFunction(cfg.control)
controlTopic = controlFunction.meta.topic_write
onValue = controlFunction.meta.state_on
offValue = controlFunction.meta.state_off
mq:sub(triggerTopic, 0)
mq:bind(triggerTopic, handleTrigger)
end
Note: _the local
keyword limits the variable to the current scope
(function/if/loop) and without it the variable is global.
I had a slight problem with the value comparison in the handler function at
first. This was due to all meta-data being strings, and I tried to compare it
with the value from MQTT which is a number. To Solve this I added the build in
tonumber
function when accessing the meta values. This was added for all
numbers from meta-data like this.
openState = tonumber(triggerFunction.meta.state_open)
I then realized that this app would not work correctly if the states where
changed for the FunctionX object. I will need to update the values if the
functions had been updated. Fortunately this is possible using the
onFunctionsUpdated
callback. This will be triggered whenever updates to the
functions is done on the API:s.
function onFunctionsUpdated()
-- Set new states so that they are in sync
local triggerFunction = findFunction(cfg.trigger_function)
openState = tonumber(triggerFunction.meta.state_open)
closedState = tonumber(triggerFunction.meta.state_closed)
local controlFunction = findFunction(cfg.control)
controlTopic = controlFunction.meta.topic_write
onValue = tonumber(controlFunction.meta.state_on)
offValue = tonumber(controlFunction.meta.state_off)
end
Since this added a lot of duplicated code, getting functions and setting the
global values I removed that from the onStart
function and added a manual call
to this function like so.
function onStart()
-- Get all values for the trigger
local triggerFunction = findFunction(cfg.triggerFunction)
triggerTopic = triggerFunction.meta.topic_read
-- Manually call the updated function to set the initial state of the variables
onFunctionsUpdated()
mq:sub(triggerTopic, 0)
mq:bind(triggerTopic, handleTrigger)
end