I'm trying to test programs with a concept of Internet of Things. I got this simple mqtt lua's client. It works fine after flashing my devkit nodemcu v2, but when i restart it or i save it again ESPlorer says:
test.lua:2: attempt to call field 'Client' (a nil value)
Code:
Source: https://www.cloudmqtt.com/docs-nodemcu.html
-- initiate the mqtt client and set keepalive timer to 120sec
mqtt = mqtt.Client("client_id", 120) -- "username", "password")
mqtt:on("connect", function(con) print ("connected") end)
mqtt:on("offline", function(con) print ("offline") end)
-- on receive message
mqtt:on("message", function(conn, topic, data)
print(topic .. ":" )
if data ~= nil then
print(data)
end
end)
mqtt:connect("IP", 1883, 0, function(conn)
print("connected")
-- subscribe topic with qos = 0
mqtt:subscribe("/topic",0, function(conn)
-- publish a message with data = my_message, QoS = 0, retain = 0
mqtt:publish("/topic","hello",0,0, function(conn)
print("sent")
end)
end)
end)
Is it possible that this client can work anytime? What am i missing? Right now i can only communicate with broker after saving script on flashed device.
Related
when I try to test to connect to my broker and publish it keeps connecting but then failing to stay connected an publish a test. does anyone see a problem in my code?
import paho.mqtt.client as mqtt
import time
broker = "*************"
port = ****
def on_log(client, userdata, level, buf):
print(buf)
def on_connect(client,usedata,flags,rc):
if rc == 0:
client.connected_flag=True ##set flag
print("client is connected")
global connected
else:
print("connection failed")
client.loop_stop()
def on_disconnect(client, userdata, rc):
print("client disconnected ok")
def on_publish(client, userdata, mid):
print("In on_pub callback mid= ", mid)
mqtt.Client.connected_flag=False #create flag in class
client = mqtt.Client("MyClient-01") #create new instance
client.on_log=on_log
client.on_connect=on_connect
client.on_disconnect=on_disconnect
client.on_publish=on_publish
client.connect(broker,port) #establish connection
client.loop_start()
while not client.connected_flag:
print("in wait loop")
time.sleep(1)
time.sleep(3)
print("publishing")
#client.loop()
ret=client.publish("house/bulb1","Test message 0",0)
time.sleep(3)
#client.loop()
ret=client.publish("house/bulb1","Test message 1",1)
time.sleep(3)
#client.loop()
ret=client.publish("house/bulb1","Test message 2",2)
time.sleep(3)
client.loop_stop()
client.disconnect()
and I get this log:
Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'MyClient-01'
in wait loop
Received CONNACK (0, 5)
connection failed
client disconnected ok
in wait loop
in wait loop
in wait loop
in wait loop
in wait loop
in wait loop
in wait loop
It just stays in the loop to try and connect , broker is found with an ip and port should be the correct one.
The MQTT specification may be some of the clearest documentation I've ever had the pleasure to read, porbably because it is so simple. For version 3.1.1 and the CONNACK message you can find it here:
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033
You configured the library to log and got this message printed:
Received CONNACK (0, 5)
CONNACK is your message type (response to your CONNECT message). 0 and 5 refer to the Conneck Acknowledge Flags and Connect Return code variables from the CONNACK variable header. 0 means that this is the beginning of a new session and 5 means that you are not authorized, as you figured out.
Fixed with adding username and password arguments and adding
client.username_pw_set(user,password=password)
Right now I have managed to create a Bluetooth advertisement using the code below:
bthci.reset(function(err) print(err or "Ok!") end)
bthci.adv.setparams({type=bthci.adv.CONN_DIR_HI}, function(err) print(err or "Ok!") end)
bthci.adv.setdata(encoder.fromHex("0708486f6d65494f"), function(err) print(err or "Ok!") end)
bthci.adv.enable(1, function(err) print(err or "Ok!") end)
The ESP32 is recognised by the smartphone using a Bluetooth scanner app.
I also added this piece of code:
uart.setup(1, 921600, 8, uart.PARITY_NONE, uart.STOPBITS_1, 1)
-- error handler
uart.on(1, "error",
function(data)
print("error from uart:", data)
end)
uart.start(1)
uart.write(1, "Hello, world\n")
To try to send something to the smartphone, but when I try to connect to the ESP32 I get 'Connection failed: gatt status 133'.
My BT configuration is like this:
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
CONFIG_BTDM_CTRL_MODE_BTDM=y
CONFIG_BTDM_CTRL_BLE_MAX_CONN=9
CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN=7
CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=3
CONFIG_BT_HCI_UART=y
CONFIG_BT_HCI_UART_NO_DEFAULT=1
CONFIG_BT_HCI_UART_BAUDRATE_DEFAULT=921600
The only examples I can find are about c with the Arduino IDE. Anyone implemented something similar in Lua so I can see an example?
Ok so this is one of those "what-am-I-missing-here?" kind of questions.
My callback registered for the client.on_publish event is never called even though messages are successfully published to the broker (no log messages are printed from the callback and it doesn't stop on a break point in VS Code). The message in particular that I'm interested in is published from the on_msg callback, I have tried to publish it outside of any callbacks but it makes no difference, the message is received by the broker but the on_publish callback never triggers.
When debugging I can see that at the time of publishing there is a function registered for the on_publish callback (the client._on_publish property is set)
Python version 3.7.4
OS Windows 10
Code that initializes the client:
import paho.mqtt.client as mqtt
#configure mqtt client
client = mqtt.Client(config['MQTT']['client_id'])
client.on_connect = on_connect
client.on_message = on_msg
client.on_disconnect = on_disconnect
client.on_publish = on_publish
try:
client.connect(config["MQTT"]["host"], int(config["MQTT"]["port"]))
except Exception as e:
log.error("Failed to connect to MQTT broker", exc_info=True)
client.loop_start()
My callbacks for on_msg and on_publish:
def on_msg(client, userdata, msg):
global status_msg_id
log.debug("on_msg")
payload = json.loads(msg.payload)
if payload['id'] == config["MISC"]["session_id"]:
if payload['result'] == 0:
log.debug("payload content=ok")
status_msg_id = client.publish(
topic = config["MQTT"]["pub_status"],
payload = json.dumps({'status':'ok'}),
qos = 2)
else:
log.debug("payload content=error")
client.publish(
topic = config["MQTT"]["pub_status"],
payload = json.dumps({'status':'error'}),
qos = 2)
log.debug("msg id (mid) of status msg: {}".format(status_msg_id))
def on_publish(client, userdata, mid, granted_qos):
log.debug("on_publish, mid {}".format(mid))
# we never get here :(
So, why isn't the on_publish function called, what am I missing?
The signature for the on_publish callback is wrong.
From the docs:
on_publish()
on_publish(client, userdata, mid)
It should be:
def on_publish(client, userdata, mid):
log.debug("on_publish, mid {}".format(mid))
Dears,
I am trying to use mqtt on esp8266 build on nodemcu. I am currently using a custom build (https://nodemcu-build.com/index.php)
modules used: adc,enduser_setup,file,gpio,http,mqtt,net,node,ow,pwm,tmr,uart,wifi
version:powered by Lua 5.1.4 on SDK 1.5.1(e67da894)
function connect_to_mqtt_broker()
print("Connecting to broker...")
m:connect(BROKER, PORT, 0, 1, function(client)
print("connected")
print("["..tmr.time().."(s)] - Client connected to broker: "..BROKER)
m:subscribe(SUB_TOPIC,0, function(conn)
print("Subscribed to "..SUB_TOPIC.." topic")
led(0,204,0,150)
end)
m:publish(PUB_TOPIC,"Hello from: "..node.chipid()..RESTART_REASON,0,0, function(conn)
print("sent")
end)
end,
function(client, reason)
print("failed reason: "..reason)
end)
end
---MQTT client---
print("--------------> Create mqtt clinet")
--set up MQTT client
-- init mqtt client with keepalive timer 120sec
m = mqtt.Client("ESP"..node.chipid(), KEEP_ALIVE_TMR, USER, PASSWORD)
m:lwt(PUB_TOPIC, "offline", 0, 0)
m:on("offline", function(conn)
print("["..tmr.time().."(s)] - Mqtt client gone offline")
end)
m:on("message", function(conn, topic, data)
--receive_data(data, topic)
print("Data received: "..data)
led(200,50,50,30)
receive_data(data, topic)
led(0,204,0,150)
end)
So at the initialization of the of the program I am calling connect_to_mqtt_broker(), which is working perfectly and I can subscribe and publish to topics.
The problem is that the keepalive timer is not correct. Let me explain that with an example. I set KEEP_ALIVE_TMR = 120s and after the esp8266 connected successfully to mqtt broker I disabled the wifi on my router and start counting seconds. According to KEEP_ALIVE_TMR the offline event:
m:on("offline", function(conn)
print("["..tmr.time().."(s)] - Mqtt client gone offline")
end)
should fire exactly 120 seconds from the moment I have disable WiFi, but for some unknown reason this won't happen. Usually the event fires up about 10-15 minutes later.
I am struggling to understand the reason of this delay with no success.
Do you have any ideas why this strange thing happens?
I've also faced with the same issue when autoreconnect flag was set. This flag breaks the run of offline event of connection between broker.
Try it without setting autoreconnect, whose default is 0 :
m:connect(BROKER, PORT, 0, function(client)
If you do your testing by turning your mqtt broker on/off, and it works. But not by switching your wifi connections, then it is the nodemcu's mqtt library problem.
I believe that there is no such mqtt offline/disconnect event on wifi disconnection. Here it is the workaround by add connection's watchdog.
tmr.alarm(1, 3000, 1, function()
if wifi.sta.getip() == nil then
--mark as mqtt restart needed
restart = true
else
-- wifi reconnect detected then restart mqtt connections
if restart == true then
--reset flag, clean object, init for a new one
restart = false
m = nil
mqtt_init()
connect()
end
end
end)
Here it is the full code example
Using Bluemix. Using NodeMCU MQTT Lua. Get the following message about topic is not valid. How to debug?
Closed connection from 108.67.152.187. [The topic is not valid.] [6] times in the last [5] minutes
Token auth succeeded: ClientID='myClientID'
NodeMCU Lua code:
t1=123 -- arbitrary value
topic = "iotsensor.fake"
m:publish(topic ,'{"d": {"data":'..t1..'}}', 0, 0,
function(conn)
-- Print confirmation of data published
print("Sent message #"..count.." data:"..t1)
end)
For IoT Foundation:
Publishing events topic iot-2/evt/event_id/fmt/format_string
Subscribing to commands topic iot-2/cmd/command_id/fmt/format_string
Refer to the documentation for more details.