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
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)
I have been trying to connect mqtt to my mqtt Server using 3.1, but i am unable to do so. here is my code :
i am using Cocoa MQTT for this:
mqtt = CocoaMQTT(clientID: clientId, host: server, port: UInt16(port))
mqtt.username = ""
mqtt.password = password
self.mqtt.delegate = self
mqtt.connect()
Only disconnect and status change delegate called, other delegates never get called.
When I set loglevel to debug
it only prints:
CocoaMQTT(info): Connected to 18.194.27.95 : 8000
CocoaMQTT(debug): Socket write message with tag: 0
and only status change and disconnect delegate get called.
We are using Lettuce in our project. We have a requirement to monitor the status of connection.
I know Lettuce can re-connect Redis when the connection is down. But is there some way to notify application that the connection is down/up?
Thanks,
Steven
Lettuce provides an event-model for connection events. You can subscribe to the EventBus and react to events published on the bus. There are multiple events, but for your case, you'd want to listen to connected and disconnected events:
ConnectionActivatedEvent: The logical connection is activated and can be used to dispatch Redis commands (SSL handshake complete, PING before activating response received)
ConnectionDeactivatedEvent: The logical connection is deactivated. The internal processing state is reset and the isOpen() flag is set to false.
Both events are fired after receiving Transport-related events such as ConnectedEvent respective DisconnectedEvent.
The following example illustrates how to consume these events:
RedisClient client = RedisClient.create()
EventBus eventBus = client.getresources().eventBus();
Disposable subscription = eventBus.get().subscribe(e -> {
if (e instanceOf ConnectionActivatedEvent) {
// …
}
});
…
subscription.dispose();
client.shutdown();
Please note that events are dispatched asynchronously. Anything that happens in the event listener should be non-blocking (i.e. if you need to call blocking code such as further Redis interaction, please offload this task to a dedicated Thread).
Read more
Lettuce Reference Documentation: Events
The documentation for mqtt.client:connect() states that the last arg is a "callback function for when the connection could not be established".
I have a case where mqtt.client:connect() succeeds, so the "not established" callback is not called (correct behavior). But, later, when my mqtt broker goes down, the "not established" callback function gets unexpectedly activated.
I have the following code:
function handle_mqtt_error (client, reason)
print("mqtt connect failed, reason = "..reason..". Trying again shortly.")
tmr.create():alarm(10 * 1000, tmr.ALARM_SINGLE, do_mqtt_connect)
end
function do_mqtt_connect ()
print("connecting---")
m:connect(MQTT_HOST, MQTT_PORT, 1, function(client)
print("mqtt connected")
client:publish("topic/status", "online", 1, 1)
end,
handle_mqtt_error
)
print("returning---")
end
-- init mqtt client
m = mqtt.Client(MQTT_CLIENT_ID, 120, MQTT_USER, MQTT_PASS)
-- connect to mqtt
print("Starting Test")
do_mqtt_connect()
I see the output from the test begin, as expected, with:
Starting Test
connecting---
returning---
mqtt connected
At this point, I kill my mqtt broker, and I unexpectedly see:
mqtt connect failed, reason = -5. Trying again shortly.
connecting---
returning---
mqtt connect failed, reason = -5. Trying again shortly.
connecting---
returning---
And, happily, but unexpectedly, when I restart my broker, I see:
mqtt connected
So, it appears that handle_mqtt_error() is not only called "when the connection could not be established". It appears that it also be called if mqtt.client:connect() successfully establishes a connection, then the connection is later broken.
======= New Information =======
I downloaded the "dev" tree and used the Docker image to build the firmware. Within mqtt.c, I enabled NODE_DBG. The interesting lines are:
enter mqtt_socket_reconnected.
mqtt connect failed, reason = -5. Trying again shortly.
enter mqtt_socket_disconnected.
leave mqtt_socket_disconnected.
leave mqtt_socket_reconnected.
The "mqtt connect failed..." message is printed by handle_mqtt_error(), which is my "connect failed" callback.
Here's my theory. When my test starts, do_mqtt_connect() calls mqtt_socket_connect(), which does this:
espconn_regist_reconcb(pesp_conn, mqtt_socket_reconnected);
This sets reconnect_callback (in app/lwip/app/espconn.c). Later, after my broker goes down and comes back up, espconn_tcp_reconnect() is called (in app/lwip/app/espconn_tcp.c). It calls the reconnect_callback, which is mqtt_socket_reconnected(), which calls handle_mqtt_error().
So, I think the end result doesn't match the documentation, but it works out okay for me. If the behavior did match the documentation, I would just add some Lua code to handle the "offline" event, and try to reestablish the mqtt connection. I just thought someone might be interested if the behavior doesn't match the documentation.
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.