我无法在 Lua 上为 ESP8266 订阅 MQTT 代理

Posted

技术标签:

【中文标题】我无法在 Lua 上为 ESP8266 订阅 MQTT 代理【英文标题】:I can't subscribe to MQTT broker on Lua for ESP8266 【发布时间】:2020-06-26 01:16:12 【问题描述】:

首先我使用的是以下内容:

ESP8266 (ESP12E) 来自 Git 的默认固件(使用带有所有相关配置的 linux 构建,根据 nodemcu 文档) ESPlorer IDE

我的具体问题(我认为)是我无法将我的 MQTT 客户端连接到 adafruit.io 代理。我想我已经成功连接到 WiFi(由两个单独的 SSID 限定)。创建 MQTT 客户端并将其连接到其代理时会出现问题。

-- 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

问题:即使调用了第 27 行,也会调用 CONNECTED CALLBACK。那里没有一致性。

问题:第 42 行输出:PANIC:调用 Lua API 时出现不受保护的错误(init.lua:42:未连接)

希望 cmets 有帮助,我想说的是显而易见的:

这是我第一次使用 ESP8266、LUA 和 MQTT 我读了多少我觉得舒服的书(你永远读不够) 我不喜欢 Arduino IDE(但我会在得到答案后尝试一下)

我怀疑以下几点:

我在固件配置的某个地方搞砸了。 WiFi 没有真正连接。 我遗漏了一些明显的东西。

最好的问候,阿尔瓦罗 R.

【问题讨论】:

wifi.sta.connect(callback) 是异步函数,因为连接需要一些时间:nodemcu.readthedocs.io/en/master/modules/wifi/#wifistaconnect。最好仅在 wifi 连接成功后启动 MQTT 连接。 需要更多反馈或者这个问题解决了吗? 愿意帮助解决这个问题。否则考虑meta.stackexchange.com/questions/5234/… 【参考方案1】:

您的脚本有几个问题;一些基本的,一些具体的。

基本原理

NodeMCU 是异步的

NodeMCU 的编程模型与 Node.js 类似,只是在 卢阿。它是异步的和事件驱动的。因此,许多功能, 有回调函数的参数。

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

这意味着一旦在第 N+1 行继续执行,您就不能假设第 N 行的语句已经完成。就是这种情况,例如@darius 在评论中暗示wifi.sta.connect()。您可以注册一个回调,一旦您的设备从 DHCP 获得 IP,就会触发该回调。我们在文档中维护template for one possible way to handle this。

只相信官方文档

您显然从错误或过时的 Internet 资源中获得了一些代码 sn-ps。通常最好参考官方 API 文档。我们努力让它变得有用且与时俱进。

具体说明

MQTT 客户端初始化

wifi.sta.config() 相反,它需要单个 Lua 表参数 mqtt.Client() 需要单独的参数。因此,mqtt.Client(mqtt_client_cfg) 是错误的。

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

MQTT 客户端连接

您的mqtt.client:connect() 的签名错误。它是 connect(host[, port[, secure]][, function(client),其中 secure 是一个布尔值,而不是您传递的两个布尔值。

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

可能的修复

这是修复脚本的一种方法:

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()

【讨论】:

以上是关于我无法在 Lua 上为 ESP8266 订阅 MQTT 代理的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 lua 固件在 ESP8266 上运行 sqlite3?

ESPlorer 无法与 ESP8266 通信

Lua ESP8266 脚本期待额外 =

LUA (ESP8266) 如何从字符串调用/输入模块命令

ESP8266 NodeMCU Lua 如何清除堆?

NodeMCU lua:adc.readvdd33() 在 ESP8266 上总是返回 65535