I wrote this MQTT publisher code:
import paho.mqtt.client as mqtt
import time
HOST = "localhost"
PORT = 1883
KEEP_ALIVE_INT = 100
TOPIC = "noti"
def sendMsg():
MSG = ["1111", "2222", "3333", "4444", "5555"]
i = 0
try:
while i<5:
client.publish(TOPIC, MSG[i], qos=0)
i+=1
time.sleep(1)
except Exception as e:
print("Caught Exception: " + e)
def onConnect(client, userdata, flags, rc):
if rc == 0:
print("Connected successfully")
sendMsg()
else:
print("Connection failed, result code: " + str(rc))
def onPublish(client, userdata, mid):
print ("Message is published")
client = mqtt.Client("pub")
client.on_connect = onConnect
client.on_publish = onPublish
client.connect(HOST, PORT, KEEP_ALIVE_INT)
client.loop_forever()
And, the following is the MQTT subscriber code:
import paho.mqtt.client as mqtt
import time
HOST = "localhost"
PORT = 1883
KEEP_ALIVE_INT = 100
TOPIC = "noti"
def onConnect(client, userdata, flags, rc):
if rc == 0:
print("=> Connected successfully")
client.subscribe(TOPIC, 0)
else:
print("=> Connection failed, result code: " + str(rc))
def onSubscribe(mosq, obj, mid, granted_qos):
print ("=> Subscribed to topic: " + TOPIC)
print ("Granted QOS: "+str(granted_qos))
def onMessage(client, userdata, msg):
print("=> Received message: " + msg.topic +" - " + msg.payload.decode("utf-8"))
client = mqtt.Client("sub")
client.on_message = onMessage
client.on_connect = onConnect
client.on_subscribe = onSubscribe
client.connect(HOST, PORT, KEEP_ALIVE_INT )
client.loop_forever()
I am using Mosquitto broker in my PC.
The publish is done in every 1 second, but I can see the print "Message is published" 5 times after all 5 messages are published. Also, the subscriber receives the messages together after 5 seconds, not in every 1 second.
Please help me understand the mistake, suggest modification.
This is because all callbacks and message handling happen on the client network loop thread and you are blocking that thread by not returning from the on_connect() callback.
So the calls to client.publish() are queued up until the on_connect() callback returns.
You need to find a way to trigger the sendMsg() function not on the client loop. (Probably on a separate thread)
Related
I have a Raspberry Pi Pico W that I am trying to get to communicate with AWS IoT, and after about 12-24 hours it seems to lose its connection. I have the keep alive set and I can see it's pinging the server. And then it suddenly stops. I'm going to add some code below to show the connection and stuff, but I'm baffled at this point (I am cross-posting this on other Raspberry Pi sites too). Any thoughts on why I can't keep the connection open?
import machine
import time
import ussl as ssl
from robust import MQTTClient
def sub_cb(btopic, bmsg):
global led
led = machine.Pin(15, machine.Pin.OUT)
topic = btopic.decode()
msg = bmsg.decode()
mqtt_message_json = ujson.loads(msg)
if 'desired' in mqtt_message_json['state']:
led_status_update = (mqtt_message_json['state']['desired']['led_status'])
if led.value() != str(led_status_update):
if led_status_update == '0':
print("turning off LED")
led.value(0)
elif led_status_update == '1':
print("turning on LED")
led.value(1)
DeviceID='PicoTestBed03'
PORT=8883
AWS_ENDPOINT={My AWS API End Point}
DISCONNECTED = 0
CONNECTING = 1
CONNECTED = 2
state = DISCONNECTED
KeepAliveSeconds = 60
led = machine.Pin(15, machine.Pin.OUT, value=1)
#Use Websockets
useWebsocket = False
#Create SSL Params object
#Assume the cert, key, and rootCA are all created correctly because my connection is successful
SSL_PARAMS = {'cert': cert, 'key': key, 'server_side': False, "cert_reqs":ssl.CERT_REQUIRED, 'cadata':rootCA}
#Create MQTT Client
client = MQTTClient(DeviceId, AWS_ENDPOINT, port=PORT, keepalive=KeepAliveSeconds, ssl=True, ssl_params=SSL_PARAMS)
#Connect MQTT Client
while state != CONNECTED:
try:
state = CONNECTING
print('AWS TEST: Trying to connect via MQTT...')
client.connect()
state = CONNECTED
except Exception as e:
print('AWS TEST: Could not establish MQTT connection')
continue
print('AWS TEST: MQTT LIVE!')
device_shadow_last_checked = time.localtime()
while 1:
if current_led_status != led.value():
current_led_status = led.value()
device_shadow_update_msg = b'{"state":{"reported":{"led_status":%d}}}' %(led.value())
mqtt_client.publish(led_status_shadow_topic_update, device_shadow_update_msg, qos=0)
if (time.mktime(time.localtime()) - time.mktime(device_shadow_last_checked)) >=60:
client.ping()
device_shadow_last_checked = time.localtime()
client.check_msg()
I want to send a message from server to client at 1 second intervals,
writing the string 'send clock' to console before the message is sent.
However, client does not receive "clock" message.
I have got the echo message is working fine, so it's not a connection issue.
How can I send a message at 1 second intervals?
Server code(python):
import threading
import time
import socketio
import eventlet
socket = socketio.Server(async_mode='eventlet')
app = socketio.WSGIApp(socket)
#socket.on('echo')
def echo(sid, message):
socket.emit('echo', message)
def worker1():
eventlet.wsgi.server(eventlet.listen(('', 5030)), app)
def worker2():
while(1):
print("send clock")
socket.emit('clock', '1 sec')
time.sleep(1)
def main():
t1 = threading.Thread(target=worker1)
t2 = threading.Thread(target=worker2)
t1.start()
t2.start()
if __name__ == '__main__':
main()
Client code(nodejs):
const io = require("socket.io-client");
socket = io("http://xxx.xxx.xxx.xxx:5030", {
transports: ["websocket"],
});
socket.emit("echo", "test");
socket.on("echo", (data) => {
console.log(data);
});
socket.on("clock", (data) => {
console.log("receive clock");
});
My server side environment:
python: 3.7.3
python-socketio: 4.5.1
eventlet: 0.25.1
Thank you for reading it until the very end. <3
You can't combine threads or the sleep() function with eventlet, you should use greenlet based equivalents instead. The easiest way to do this is to start your background tasks with the socket.start_background_task() helper function, and sleep with socket.sleep(). I'm writing this by memory so there might be small mistakes, but your application could do something like the following:
import socketio
import eventlet
socket = socketio.Server(async_mode='eventlet')
app = socketio.WSGIApp(socket)
#socket.on('echo')
def echo(sid, message):
socket.emit('echo', message)
def worker1():
eventlet.wsgi.server(eventlet.listen(('', 5030)), app)
def worker2():
while(1):
print("send clock")
socket.emit('clock', '1 sec')
socket.sleep(1)
def main():
socket.start_background_task(worker2)
worker1()
if __name__ == '__main__':
main()
I am trying to start a camera recording using Pi Zero W (which acts as MQTT client) upon receiving message and stop the recording on receiving the stop message. Below is my code:
continueRecording = 1
Broker = "192.168.0.105"
pub_topic = "picamera1"
sub_topics = ["Rpi_Master", 0]
def on_connect(client, userdata, flags, rc):
if rc == 0:
pass
else:
print("Bad Connection with result code: " + str(rc))
for topic in sub_topics:
client.subscribe(topic)
def on_message(client, userdata, msg):
global message_topic, message
global continueRecording
message = str(msg.payload.decode("utf-8"))
print("Received message is" + message)
message_start = str(message[:4])
print("Command to start recording is " + message_start)
if message_start == "shop":
print("Enter shop")
with picamera.PiCamera as camera:
camera.resolution = (640, 480)
camera.framerate=20
camera.start_recording("/home/pi/camera-recording/shop/shoprecording.h264")
time.sleep(0.5)
while continueRecording == 1:
camera.wait_recording(.01)
if message == "OK":
print("Stopping to record")
camera.stop_recording()
continueRecording = 0
def on_publish(mosq, obj, mid):
pass
# on mqtt disconnection#
def on_disconnect(client, userdata, rc):
if rc == 0:
pass
elif rc != 0:
print("Unexpected MQTT disconnection. Will try to reconnect")
try:
client.username_pw_set(username="ab", password="abcdef")
client.connect(Broker, 1883, 60)
except:
print("Error in trying to reconnect with the Broker")
# mqtt client broker Connection
def clientBrokerConnection():
print("Client Broker Function Running")
global client
client = mqtt.Client("piCamera1") # creating a new instance
##Defining the callback functions
client.username_pw_set(username="pi", password="lotus56789")
client.on_connect = on_connect
client.on_message = on_message
client.on_publish = on_publish
client.on_disconnect = on_disconnect
##End of callback functions
client.connect(Broker, 1883, 60) # Connecting to Broker
client.loop_start()
clientBrokerConnection()
The issue I am facing is that the Pi is recieving the correct message to start recording but it fails to enter the with picamera.PiCamera as camera: loop and the recording doesn't start. The compiler does not show any error in the code. I am unable understand why the recording doesn't start. I have checked the camera and it works fine. Thanks for your help and time in advance.
I have this javascript code that send data to channels
// Note that the path doesn't matter for routing; any WebSocket
// connection gets bumped over to WebSocket consumers
socket = new WebSocket("ws://" + window.location.host + "/chat/");
socket.onmessage = function(e) {
alert(e.data);
}
socket.onopen = function() {
socket.send({"test":"data"});
}
// Call onopen directly if socket is already open
if (socket.readyState == WebSocket.OPEN) socket.onopen();
I'm curios how from message I can get the json {"test":"data"}
here's the view
# Connected to websocket.connect
#channel_session
def ws_connect(message, key):
# Accept connection
message.reply_channel.send({"accept": True})
You implemented the connection callback, but did not implement what should happen when a message arrives the server endpoint. Add add message receive function:
def on_receive(message):
print('test received: {}'.format(message.content['test']))
Register the function in routing.py:
channel_routing = [
route("websocket.connect", ws_connect),
route("websocket.receive", on_receive),
]
The JSON message you send will be stored in message.content which is basically just a python dict.
I am trying to monitor an mqtt broker so I can fire a notification if there is a connection interruption.
My approach was to create a cloud client who does nothing besides monitor the broker. "on_disconnect" seems like the appropriate method however I cannot get it to trigger. (I have been loading and unloading the broker service in a different terminal).
The method is a skeleton:
import random
import time
def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False
def on_message(client, userdata, message):
print message
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
mqttc.subscribe('control/iterate',qos=0)
def on_disconnect(client, userdata, rc):
print("Disconnected")
mqttc = mqtt.Client()
mqttc.on_connect = on_connect
mqttc.on_message = on_message
mqttc.connect('10.147.17.234', port=1883, keepalive=1)
print("test")
mqttc.loop_forever()
Obviously there are easy ways to do this but I feel like there is an elegant solution to this problem that I am just missing.
You've not actually added the on_disconnect call back in your code:
import random
import time
def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False
def on_message(client, userdata, message):
print message
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
mqttc.subscribe('control/iterate',qos=0)
def on_disconnect(client, userdata, rc):
print("Disconnected")
mqttc = mqtt.Client()
mqttc.on_connect = on_connect
mqttc.on_message = on_message
#added the following line
mqttc.on_disconnect = on_disconnect
mqttc.connect('10.147.17.234', port=1883, keepalive=1)
print("test")
mqttc.loop_forever()