As the title says... Chat on...

User avatar
By lepass7
#29500 Hello guys,
I am trying to implement a simple senario with mqtt client where I will publish and subscribe simple messages. At the moment I am trying to make the system as robust as it can be. I have noticed that esp sometimes disconnects (probably due to bad router from my isp), on wifi disconnection mqtt client it activates the offline event:
Code: Select allm:on("offline", function(con) disconnected() end)


So i think it will be a good idea when there is a disconnection, using the function disconnected() I will try to reconnect to wifi and reconnect the client but if I do that
Code: Select allfunction disconnected()
    print(CLIENTID..": Lost connection, don't worry I'll try to reconnect...")
    m:close();
   
    tmr.alarm(0, 2500, 0, checkWIFI)
end


And then try to reconnect my mqtt client :
Code: Select allm = mqtt.Client("clientid", 0, "user", "password")
m:lwt("pub_test", CLIENTID.."I out, I will try to come back", 0, 0)
m:on("connect", function(con) print (CLIENTID..": Mqtt reconnected") end) --eof m:on
--m:on("offline", function(con) print ("offline") end)
m:on("offline", function(con) disconnected() end)
m:on("message", function(conn, topic, data)
  print("Data received on topic: "..topic .. ":" )
  if data ~= nil then
    print(data)
    tmr.delay(1000000)   -- wait 1,000,000 us = 1 second
    -- publish a message with data = hello, QoS = 0, retain = 0
    m:publish("pub_test","Message received:" .. data,0,0, function(conn)
    print("Data published")
        end)
  end
end)
m:connect(BROKER, 1883, 0, function(conn)
     print(CLIENTID..": Mqtt reconnecting...")
     m:subscribe(sub_topic,0, function(conn) print(CLIENTID..": Subscribed to "..sub_topic.." topic")
         -- m:subscribe("test2",0, function(conn) print("subscribe test2")
          end)
     
     end)


I get "not enough memory". I am suspecting that the reason of this is that I am trying to recreate the instance of mqtt.client so in order to avoid this I thought it would be a good idea to destroy the instance by:
m = nil
on disconnect function.
Because I am not an expert on lua language and on nodemcu I would like to hear your suggestions regarding this.

THank you.
User avatar
By ashubhatt
#29963 So you want to create a robust MQTT connection, which upon failure should wait and reconnect to broker.

Considering that, I would suggest: Instead of creating a new MQTT client use an existing client.
Consider this example:

Code: Select all-- "mqtt.lua" File --
-- Call this file from your init.lua file by command dofile("mqtt.lua")

mqtt_conn = 0 -- Flag to keep check of MQTT Connection

function mqtt_connect()
    mqtt:connect( host, port, secure, function(client) )
         print("Connected to MQTT:" .. host.. ":" .. port)
         mqtt_conn = 1  -- update the flag
         tmr.stop(2)    -- reset reboot timer
         run_main_prog() --jump to main program if connected
    end)
    --Not connected
    if(mqtt_conn == 0) then   -- check the connection flag
        --Rebooting
        tmr.alarm(2, 10000, 0, function() dofile("mqtt.lua") end) -- start connection again if got offline
    end
end

-- Main Program
function run_main_prog()
     -- MQTT connection established
     -- Now you can add Pub/Sub Functions  or any other code here
     -- Finaly ...
     -- Check the status of connection
     m:on("offline", function(conn)
        -- Connection Failure
        mqtt_conn = 0  -- clear the flag to detect disconnection
        m:close()       
        tmr.alarm(2, 10000, 0, function() dofile("mqtt.lua") end) -- start connection again if got offline
     end )
end

----------------------------------------------------
-- Program execution starts from here--

-- connect to the broker
print "Connecting to MQTT broker. Please wait..."
m = mqtt.Client(clientid, keepalive, user, pass)
mqtt_connect() -- call connect function



I have commented the code. It should work well.
However, if you need any explanation for any particular line, post a comment.
User avatar
By lepass7
#30660 Hello ashubhatt,
Sorry for my late reply. I tried to use your code but I get some weird out of memory errors. This is my code but I have some problems that I would like your opinion on this:

Code: Select allfunction mqtt_connect()
    print("mqtt connect function")
    ip = wifi.sta.getip() --function retures ip, subnet mask, gateway
    if ip ~= nil then
          ip = nil
          print("I have ip: "..wifi.sta.getip())
          sending = 0         --if get offline before set
        m = mqtt.Client(CLIENTID, ALIVE_TIME, "user", "password")
        m:lwt(pub_topic_lwt, CLIENTID.."I am out, I will try to come back", 0, 0)
        m:on("offline", function(con)
            sending = 0
            print(CLIENTID.." gonne offline")
            lastError = "Client: ("..CLIENTID..") - ".."Current heap: ("..node.heap()..") - Time("..tmr.now()..") - Error: (Mqtt client disconnected)"
            m:close();
            m = nil
            --wifi.sta.disconnect()
            --tmr.alarm(0,1000,0,function() dofile("check_wifi.lua") end)
            tmr.alarm(0,10000,0,mqtt_connect)    --TODO: loop for ever???????????      maybe call wifi_connect()         
        end)
        m:on("message", function(conn, topic, data)
                        --print("Data received on topic: "..topic .. ":" )
                        receive_data = data
                        messageReceived()   
        end)
        m:connect(BROKER, 1883, 0, function(conn)
                                   m:subscribe(sub_topic,0, function(conn)
                                   
                                                            print(CLIENTID..": Subscribed to "..sub_topic.." topic")
                                                            tmr.alarm(0,1000,0,publishMessage)
                                              end)
                                   end)
    else
        print("No wifi")
        lastError = "Client: ("..CLIENTID..") - ".."Current heap: ("..node.heap()..") - Time("..tmr.now()..") - Error: (No wifi...I will try again)"
        tmr.alarm(0,10000,0,mqtt_connect) --TODO: maybe i should call check_wifi.lua
    end
end


My logic is if there is no WIFI keep looping until there is (maybe in the future I will set a counter and a notifier) on offline call mqtt_connect() again. If I disconnect router from power the code works perfect because there is no IP assigned to esp thats why at the first if (if ip~=nil) goes to else and keep calling mqtt_connect(). But if I just unplugged the ISP cable, the esp wont loose IP so it will execute the if (if ip~=nil) and at the n:connect I will get 5 "dns retry" and at the end "fail" and then nothing. It stops there.
So I was thinking that good solutions will be:
1. ping the Broker ( i dont know how to that) and if there is response then it will continue to m:connect
2. Catch m:connect failure (I dont know how to that)

Do you have any other ideas? Do you know how to do the two ideas above? Do you have any other suggestions on how mqtt_connect() function it will be, in order to reconnect to broker after a quick disconnection?

Thank you
User avatar
By GregorZagar
#46969 I solved the problem with reconnecting to mqtt broker with simple publish message from mqtt server side.

The script on server side checks if mqtt server is running. If its running true signal is sent to esp8266 node. Node receives message and checks every two seconds if signal is received, if "true" signal is not received the esp restarts and connects to wifi and mqtt broker.