Hello,
the last days I spent my time to implement a MQTT Client in Lua to work with Mach4. Actually I can connect to a MQTT Broker, publish Messages via functions und subscribe topics. But I'm not sure if I place all MQTT functions at the right place. I've made the main MQTT Connection in the Screen Load Script with the following code:
---------------------------------------------------------------
-- Load modules
....
--MQTT module
package.loaded.MqttModul = nil
mqtt = require "mqtt_library"
....
---------------------------------------------------------------
....
....
function mqttCallback(
topic, -- string
message) -- string
mc.mcCntlSetLastError(inst,"Topic: " .. topic .. ", message: '" .. message .. "'")
end
function SendMessage(msg)
mc.mcCntlSetLastError(inst, msg);
mqtt_client:publish("mach4",msg)
end
function MQTT_Connect()
mqtt_client = mqtt.client.create("192.168.0.55", nil, mqttCallback)
mqtt_client:connect("mach4")
mqtt_client:publish("mach4", "online")
mqtt_client:subscribe({"mach4/set"})
end
MQTT_Connect()
To maintain the MQTT Connection and to recieve messages it is important to call a handle function et least every few seconds. So I put this handler in the PLC Script:
local inst = mc.mcGetInstance()
local rc = 0;
testcount = testcount + 1
machState, rc = mc.mcCntlGetState(inst);
local inCycle = mc.mcCntlIsInCycle(inst);
mqtt_client:handler()
......
At the moment everything works fine but I have the following question: Is it a Problem that I call the mqtt_client:handler() in the PLC Script? Will I get problems like a delay if the handle function block for a moment? The code for the mqtt_client:handler() is:
function MQTT.client:handler() -- Public API
if (self.connected == false) then
error("MQTT.client:handler(): Not connected")
end
MQTT.Utility.debug("MQTT.client:handler()")
-- Transmit MQTT PING message
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~
-- MQTT 3.1 Specification: Section 3.13: PING request
--
-- bytes 1,2: Fixed message header, see MQTT.client:message_write()
local activity_timeout = self.last_activity + MQTT.client.KEEP_ALIVE_TIME
if (MQTT.Utility.get_time() > activity_timeout) then
MQTT.Utility.debug("MQTT.client:handler(): PINGREQ")
self:message_write(MQTT.message.TYPE_PINGREQ, nil)
end
-- Check for available client socket data
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local ready = MQTT.Utility.socket_ready(self.socket_client)
if (ready) then
local error_message, buffer =
MQTT.Utility.socket_receive(self.socket_client)
if (error_message ~= nil) then
self:destroy()
error_message = "socket_client:receive(): " .. error_message
MQTT.Utility.debug(error_message)
return(error_message)
end
if (buffer ~= nil and #buffer > 0) then
local index = 1
-- Parse individual messages (each must be at least 2 bytes long)
-- Decode "remaining length" (MQTT v3.1 specification pages 6 and 7)
while (index < #buffer) do
local message_type_flags = string.byte(buffer, index)
local multiplier = 1
local remaining_length = 0
repeat
index = index + 1
local digit = string.byte(buffer, index)
remaining_length = remaining_length + ((digit % 128) * multiplier)
multiplier = multiplier * 128
until digit < 128 -- check continuation bit
local message = string.sub(buffer, index + 1, index + remaining_length)
if (#message == remaining_length) then
self:parse_message(message_type_flags, remaining_length, message)
else
MQTT.Utility.debug(
"MQTT.client:handler(): Incorrect remaining length: " ..
remaining_length .. " ~= message length: " .. #message
)
end
index = index + remaining_length + 1
end
-- Check for any left over bytes, i.e. partial message received
if (index ~= (#buffer + 1)) then
local error_message =
"MQTT.client:handler(): Partial message received" ..
index .. " ~= " .. (#buffer + 1)
if (MQTT.ERROR_TERMINATE) then -- TODO: Refactor duplicate code
self:destroy()
error(error_message)
else
MQTT.Utility.debug(error_message)
end
end
end
end
return(nil)
end
The MQTT Client library is from
https://github.com/geekscape/mqtt_luaIf someone is interested in the modified code and an installation instruction please let me know.
Thanks for help