0

First of all I'm using the following:

  • ESP8266 (ESP12E)
  • Default firmware from Git (built with linux with all pertinent configs, according with nodemcu documentation)
  • ESPlorer IDE

My specific problem (I think) is that I can't connect my MQTT client to a adafruit.io broker. I think I've successfully connected to WiFi (confimed by two separate SSIDs). The issue comes when creating the MQTT client AND connecting it to its broker.

-- INITIAL DEFINES
-- defines
station_cfg={}
station_cfg.ssid        = "<my wifi>"    -- my personal ssid
station_cfg.pwd         = "<wifi pwd>"   -- my wifi pwd
--station_cfg.ssid        = "IoT"        -- campus' ssid
--station_cfg.pwd         = "<wifi pwd>" -- campus' wifi pwd, I tried this first, then my home's. It 
                                            worked as it should
station_cfg.auto        = false
station_cfg.save        = false

mqtt_client_cfg = {}
mqtt_client_cfg.clientid    = "alro"          -- any ID
mqtt_client_cfg.keepalive   = 120             -- went for the example's value
mqtt_client_cfg.username    = "AlvaRocha"     -- obviously a paranoic Ctrl+C/V from adafruit
mqtt_client_cfg.password    = "aio_KO<safety edit>sXwbgtWCboCal" -- obviously a paranoic Ctrl+C/V 
                                                                 -- from adafruit

wifi.setmode(wifi.STATION)
wifi.sta.config(station_cfg)
wifi.sta.connect(connect)         -- so far so good

iot_test = mqtt.Client(mqtt_client_cfg) -- open client, apparently OK
--iot_test:lwt("/lwt", "offline", 0, 0) -- this line is on examples, doesn't affect outputs

iot_test:on("connect", function(client) print("client connected") end)
iot_test:on("offline", function(client) print("client offline") end) -- this event is called
                                                                     -- always (line 27)

function connect(params)
    print('Connected to:', params.SSID) -- I understant from documentation that this is called IF 
                                        -- successfull wifi connection. Double checked with 
                                        -- campus' and home wifi
end

function disconnect(params)
    print('Disconnected from:', params.SSID) -- ignore this function
end

function get_broker(mqtt_client)
    mqtt_client:connect("io.adafruit.com", 1883, false, false, --Found this double 'false' on 
                                                   --https://www.electronicwings.com/nodemcu/nodemcu- 
                                                   --mqtt-client-with-esplorer-ide 
           function(client) -- CONNECTED CALLBACK
            print('connected to broker') 
            --break
            -- continue
            client:subscribe("/Test", 0, function(client) print("Succesfull sub.") end) -- (LINE 42)
            --break
      --- continue
      end,
      function(_reason) -- OFFLINE CALLBACK not called (called if I don't write the 'double false' 
                        -- from the example)
            print('connection failed', reason) 
      end)
 end

 get_broker(iot_test) -- connect to broker

ISSUE: even though line 27 is called, CONNECTED CALLBACK is called. No consistency there.

ISSUE: Line 42 output : PANIC: unprotected error in call to Lua API (init.lua:42: not connected)

Hoping the comments are helpfull, I want to state the obvious:

  • This is my first time using ESP8266, LUA and MQTT
  • I read as much as I felt comfortable with (you can never read enough)
  • I don't like Arduino IDE (but I'll try it as this gets answered)

I suspect the following:

  • I messed up somewhere at firmware config.
  • WiFi is not really connected.
  • I'm missing something obvious.

Best regards, Alvaro R.

Marcel Stör
  • 22,695
  • 19
  • 92
  • 198
  • `wifi.sta.connect(callback)` is asynchronous function as connection takes some time: https://nodemcu.readthedocs.io/en/master/modules/wifi/#wifistaconnect. It is better initiate MQTT connection only **after** successful wifi connection. – Darius Mar 14 '20 at 14:28
  • Any more feedback required or is this problem solved? – Marcel Stör Mar 19 '20 at 06:22
  • Would like to help solve this problem. Otherwise consider https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – Marcel Stör Apr 02 '20 at 21:43

1 Answers1

0

There are a couple of things wrong with your script; some fundamental, some specific.

Fundamentals

NodeMCU is asynchronous

The NodeMCU programming model is similar to that of Node.js, only in Lua. It is asynchronous and event-driven. Many functions, therefore, have parameters for callback functions.

-> https://nodemcu.readthedocs.io/en/latest/#programming-model

That means that you cannot assume that a statement on line N has completed once the execution continues on line N+1. That is the case e.g. for wifi.sta.connect() as @darius hinted in the comment. You can register a callback that fires once your device got an IP from DHCP. We maintain a template for one possible way to handle this in the docs.

Only trust the official documentation

You apparently got some code snippets from an internet resource that is wrong or outdated. It's usually better to refer to the official API documentation. We strive for it to be useful and up to date.

Specifics

MQTT client initialization

Contrary to wifi.sta.config() which expects a single Lua table parameter mqtt.Client() expects individual parameters. Hence, mqtt.Client(mqtt_client_cfg) is wrong.

-> https://nodemcu.readthedocs.io/en/latest/modules/mqtt/#mqttclient

MQTT client connection

The signature of your mqtt.client:connect() is wrong. It is connect(host[, port[, secure]][, function(client) with secure being a boolean rather than the two booleans you pass.

-> https://nodemcu.readthedocs.io/en/latest/modules/mqtt/#mqttclientconnect

Possible fix

Here is one way to fix your script:

station_cfg = {}
station_cfg.ssid = "***"
station_cfg.pwd  = "***"

station_cfg.auto = false
station_cfg.save = false

mqtt_cfg = {}
mqtt_cfg.host      = "io.adafruit.com"
mqtt_cfg.port      = 1883
mqtt_cfg.clientid  = "alro"
mqtt_cfg.keepalive = 120
mqtt_cfg.username  = "AlvaRocha"
mqtt_cfg.password  = "aio_KO<safety edit>sXwbgtWCboCal"

wifi.setmode(wifi.STATION)
wifi.sta.config(station_cfg)

iot_test = mqtt.Client(mqtt_cfg.clientid, mqtt_cfg.keepalive, mqtt_cfg.username, mqtt_cfg.password)
iot_test:on("offline", function(client)
  print("client offline")
end)
iot_test:on("message", function(client, topic, data)
  print("MQTT msg received on '" .. topic .. "':")
  if data ~= nil then
    print("\t" .. data)
  end
end)

function get_broker(mqtt_client)
  mqtt_client:connect(mqtt_cfg.host, mqtt_cfg.port, false,
    function(client)
      client:subscribe("/topic", 0, function(client)
        print("subscribe success")
      end)
      client:publish("/topic", "hello", 0, 0, function(client)
        print("sent")
      end)
    end,
    function(client, reason)
      print('connection failed', reason)
    end)
end

function startup()
  if file.open("init.lua") == nil then
    print("init.lua deleted or renamed")
  else
    print("Running")
    file.close("init.lua")
    get_broker(iot_test)
  end
end

wifi_connect_event = function(T)
  print("Connection to AP(" .. T.SSID .. ") established!")
  print("Waiting for IP address...")
  if disconnect_ct ~= nil then
    disconnect_ct = nil
  end
end

wifi_got_ip_event = function(T)
  -- Note: Having an IP address does not mean there is internet access!
  -- Internet connectivity can be determined with net.dns.resolve().
  print("Wifi connection is ready! IP address is: " .. T.IP)
  print("Startup will resume momentarily, you have 3 seconds to abort.")
  print("Waiting...")
  tmr.create():alarm(3000, tmr.ALARM_SINGLE, startup)
end

wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, wifi_connect_event)
wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, wifi_got_ip_event)

wifi.sta.connect()
Marcel Stör
  • 22,695
  • 19
  • 92
  • 198