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)
Related
I borrowed code from Toms Hardware on how to use MQTT and subscribe. JRMI is the publisher of the messages and it keeps repeating them over and over again. Is there anyway to have the message sent only once? I dont have this problem when I subscribe to MQTT via http://www.hivemq.com/demos/websocket-client/ The MQTT service I'm using is broker.hivemq.com
For those not familiar with JRMI, it is the JAVA program that model railroads use to control tracks,lighting, DCC etc. Ref: https://www.jmri.org/
The link to Tom's is here https://www.tomshardware.com/how-to/send-and-receive-data-raspberry-pi-pico-w-mqtt
The code adapted from Tom's is
import network
import time
from machine import Pin
from umqtt.simple import MQTTClient
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("whatever","pwd")
time.sleep(5)
print(wlan.isconnected())
mqtt_server = 'broker.hivemq.com'
client_id = 'bigles'
topic_sub = b'/trains/track/turnout/#'
def sub_cb(topic, msg):
print("New message on topic {}".format(topic.decode('utf-8')))
msg = msg.decode('utf-8')
print(msg)
def mqtt_connect():
client = MQTTClient(client_id, mqtt_server, keepalive=60)
client.set_callback(sub_cb)
client.connect()
print('Connected to %s MQTT Broker'%(mqtt_server))
return client
def reconnect():
print('Failed to connect to MQTT Broker. Reconnecting...')
time.sleep(5)
machine.reset()
try:
client = mqtt_connect()
except OSError as e:
reconnect()
while True:
client.subscribe(topic_sub)
time.sleep(1)
The setup inside JRMI for MQTT (edit->preferences) is as follows:
JMRI, by default, publishes with "the retain option on". When you subscribe to a topic the broker will send you the most recent (if any) retained message. This occurs even if you already had an identical subscription as per the MQTT Spec:
If a Server receives a SUBSCRIBE Packet containing a Topic Filter that is identical to an existing Subscription’s Topic Filter then it MUST completely replace that existing Subscription with a new Subscription. The Topic Filter in the new Subscription will be identical to that in the previous Subscription, although its maximum QoS value could be different. Any existing retained messages matching the Topic Filter MUST be re-sent, but the flow of publications MUST NOT be interrupted [MQTT-3.8.4-3].
In your code you are calling Subscribe in a loop:
while True:
client.subscribe(topic_sub)
time.sleep(1)
To avoid the repeated messages move the subscribe out of the loop (you only need to subscribe once!). Something like the following (simplified!) code:
client = mqtt_connect()
client.subscribe(topic_sub)
while True:
client.wait_msg() // Use client.check_msg() if you have other stuff to do
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))
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 install kafka on a standalone server and try to stream data to mongodb.
when start kafka service, bin/kafka-server-start.sh config/server.properties
I had a warning:
WARN Attempting to send response via channel for which there is no open connection, connection id 0 (kafka.network.Processor)
Even though, there is no problem for data entered at producer and displayed at consumer.
but I think this cause the data write to mongodb. I have no data write to mongodb after start data streaming.
anyone can help with this issue? Thank you so much.
//processor.sendResponse
protected[network] def sendResponse(response: RequestChannel.Response) {
trace(s"Socket server received response to send, registering for write and sending data: $response")
val channel = selector.channel(response.responseSend.destination)
// `channel` can be null if the selector closed the connection because it was idle for too long
if (channel == null) {
warn(s"Attempting to send response via channel for which there is no open connection, connection id $id")
response.request.updateRequestMetrics()
}
else {
selector.send(response.responseSend)
inflightResponses += (response.request.connectionId -> response)
}
so, channel was closed by the selector because it was idle too long
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