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.
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'm making this addons that have to send to the raid my interrupt cooldown.
The problem is that whenever i send a message to the raid i am the only one that receive it.
This is the code that send the message:
C_ChatInfo.SendAddonMessage("KickRotation",string.format( "%0.2f",remainingCd ), "RAID")
This is the event handler:
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("CHAT_MSG_ADDON")
frame:SetScript("OnEvent", function(self, event, ...)
local prefix, msg, msgType, sender = ...;
if event == "CHAT_MSG_ADDON" then
if prefix == "KickRotation" then
print("[KickRotation]" ..tostring(sender) .." potrĂ interrompere tra: " ..msg);
end
end
if event == "PLAYER_ENTERING_WORLD" then
print("[KickRotation] v0.1 by Galfrad")
end
end)
Basically when the message is sended it is printed only to me.
Network messages are handled and transferred to the recipient channel (in this case, Raid Group) by the server. The reason that you are seeing the message locally, but the other people do not see it is that the message will be handled on the local system (sender) to reduce the repetition of data transmit.
Server however, only accepts and sends messages that are registered to it.
Therefore, you must first register your add-on messages to the server so the other players in the requested channel be able to receive it.
First, register your add-on messages with the name you have given already (But be sure to call the registration method only once per client):
local success = C_ChatInfo.RegisterAddonMessagePrefix("KickRotation") -- Addon name.
Next, check if your message was accepted and registered to the server. In case success is set to false (failure), you may want to handle proper warning messages and notifications to the user. The case of failure means that either server has disabled add-on messages or you have reached the limit of add-on message registrations.
Finally, send your message again check if it did not fail.
if not C_ChatInfo.SendAddonMessage("KickRotation",string.format( "%0.2f",remainingCd ), "RAID") then
print("[KickRotation] Failed to send add-on message, message rejected by the server.")
end
I am using Chrome 66.0.3359.181 (64-bit). I am running the following code:
navigator.serviceWorker.ready
.then(sw=>{
addData('sync-posts',post)
.then(()=>{
return sw.sync.register('sync-new-posts');
})
.then(()=>{
var snackbarContainer = document.querySelector('#confirmation-toast');
const data = {message: 'Your post was saved for syncing!'};
snackbarContainer.MaterialSnackbar.showSnackbar(data);
})
.catch(err=>{
console.log(err);
});
})
However even when I have disconnected my wifi it still triggers the sync event immediately.
ANSWER: I actually figured this out while I was writing it but since I didn't find anyone else answer this type of question AND it took an hour or so out of my time I thought I'd post it anyway.
I had a VM network adapter enabled (for Docker) and that was causing it to try and sync even though that connection didn't go anywhere useful.
Then I also discovered that provided I was throwing an error from that sync event when it failed, it would retry syncing. Originally I was catching errors and just logging to console but this meant the sync thought it was complete.
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
I've been searching Google for awhile and there seems to be no offers on fixing this problem I have here.
I am using LuaSocket as a simple way to connect to a external server I created, and I am able to connect to it successfully and send a signal.
However, when I try to send a second message later on, the external server does not seem to be receiving the message, even though I am still connected to the socket.
socket = require("socket")
host, port = ip, port
tcp = assert(socket.tcp())
tcp:settimeout( 0 )
tcp:connect(host, port);
msg = {
["status"]="connect",
["usrName"]=username
}
msg = Json.Encode(msg)
tcp:send(msg); -- This message, the server received this message.
-- Later in my code, I attempt to send another message.
msg = {
["status"]="anotherMessage",
["usrName"]=username
};
msg = Json.Encode(msg)
tcp:send(msg); -- This message is not sending, even though i'm still connected.
You need to show what happens on the other side as it may be simply not reading even though the connection may be open. You also don't say what exactly happens when "message is not sending"; do you get an error? the script finishes but the message is not sent?
There are several things you can try:
Switch to the (default) synchronous send until you get it working; remove tcp:settimeout(0), as your send may simply fail with "timeout" message if the other side is not ready to read the message.
Check the error message from :send call to see if it's timing out or not.
local ok, err = tcp:send(msg)
Use socket.select to check if the other side it ready to accept the message you are sending.
Try adding "\r\n" at the end of your serialized JSON.