Python script running in IDLE but not in terminal - python

There are many instances of this problem here, but all of them list an error when attempting to run the script. When I try to run my script from the terminal, it thinks for about a second, then just goes back to a normal terminal prompt (without an error message).
I am new to Python, so forgive me if I'm simply doing something wrong, but for the life of me . . . this runs perfectly fine when opening/running in IDLE.
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
import RPi.GPIO as GPIO
RELAY_PIN_1 = 23
RELAY_PIN_2 = 24
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(RELAY_PIN_1, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(RELAY_PIN_2, GPIO.OUT, initial=GPIO.HIGH)
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe("/amber/1/1")
client.subscribe("/amber/1/2")
def on_message(client, userdata, msg):
if msg.topic == "/amber/1/1":
if msg.payload == b'ON':
GPIO.output(RELAY_PIN_1, GPIO.LOW)
elif msg.payload == b'OFF':
GPIO.output(RELAY_PIN_1, GPIO.HIGH)
if msg.topic == "/amber/1/2":
if msg.payload == b'ON':
GPIO.output(RELAY_PIN_2, GPIO.LOW)
elif msg.payload == b'OFF':
GPIO.output(RELAY_PIN_2, GPIO.HIGH)
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("10.0.0.163", 1883, 60)
client.loop_start()
In case anyone is wondering, I have been trying to run this using the command python mqtt.py (with mqtt.py being the file name). Also, I am using Python2.7 in both IDLE and from the terminal.

When you call loop_start() you start the client on another thread, but right after that the script ends and the process terminates and so nothing happens.
If you want the client to keep running, either sleep() in your main thread after loop_start(), or instead, call loop_forever(), which will loop in the current thread and so your script will not terminate.
See the network loop section in the documentation.

Related

paho loop issue in python on raspbian

I am attempting to write a python script (for Raspbian) that sends mqtt message on button pushes, and changes LED's on/off when mqtt messages are received.
I can send no worries, and my script structure on 4 RPi's is the same;
import
set variables
while true:
do stuff endlessly
I however can not get a basic script running for paho to receive in this structure.
I tried to follow the paho guide but can not adapt it to an endless while loop application.
Why can't I receive mqtt messages? I cross check with 2 terminals; mosquito sub & pub, they are definitely been sent/received elsewhere on network.
Edit;
New on_connect callback displays "Connected" every 2 seconds, but the script still doesn't receive/print mqtt messages. It still does send them when I push the button.
Attempted to fire up a different MQTT broker in Docker, made no difference.
Edit3; WORKS! :D Last I test I must not have been awake and had the subscribe line commented out in the on_connect callback.
I also removed the "P1" from the mqtt.Client thing which I copied from a tutorial.
Can happierly confirm, it sends and receives mqtt messages. Now I can integrate into my larger script. Thanks hardlib
New code is this;
import sys
sys.path.append('/usr/local/lib/python2.7/dist-packages/paho/mqtt')
import os
import time
import paho.mqtt.client as mqtt
from gpiozero import Button
from time import sleep
def on_message(client, userdata, message):
print("message received " ,str(message.payload.decode("utf-8")))
print("message topic=",message.topic)
print("message qos=",message.qos)
print("message retain flag=",message.retain)
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe("button")
button = Button(25)
broker_address="192.168.1.10"
client = mqtt.Client()
client.on_message=on_message
client.on_connect=on_connect
client.connect(broker_address, 1883, 60)
#client.subscribe("button")
client.loop_start()
while 1:
if button.is_pressed:
print("button pressed")
client.publish("button","ON",1)
sleep(0.1)
sleep(0.1)
print("*")

Publish in on_message with Paho Mqtt Client not working

The publish call in the main method dosen't send a message to the broker, but returns (0,2). on_publish won't be called.
I am not sure how I should look where the error is. I tried qos=2 and run the main method async but it didn't fixed it. The base connection work, because the on_message is called. The mqtt-server works fine with other projects too.
Has anyone some ideas?
import paho.mqtt.client as mqtt
import subprocess
import shutil
import os
import glob
import logging
from datetime import datetime
import RPi.GPIO as GPIO
import time
from multiprocessing import Pool
GPIO.setmode(GPIO.BCM)
direction = 19
pwm = 26
GPIO.setup(direction, GPIO.OUT)
GPIO.setup(pwm, GPIO.OUT)
pwm = GPIO.PWM(pwm,19000)
speed = 0
pwm.start(speed)
running = False
client = mqtt.Client()
#First: pip3 install paho-mqtt
print("Starte Listener")
def start():
GPIO.output(direction, GPIO.LOW)
for dc in range(10, 40, 1):
speed = dc
pwm.ChangeDutyCycle(speed)
time.sleep(0.25)
def end():
GPIO.output(direction, GPIO.LOW)
for dc in list(reversed(range(0,40,1))):
speed = dc
pwm.ChangeDutyCycle(speed)
time.sleep(0.5)
def main(mqttClient):
print("Started Spinning")
running = True
start()
print(mqttClient.publish("scanner","shoot"))
print("Waiting 124 seconds")
time.sleep(124)
print("ending spinning")
end()
print("finished spinning")
running = False
def on_connect2(client, userdata, flags, rc):
client.subscribe("scanner",2)
print("Connected "+str(rc))
# The callback for when a PUBLISH message is received from the server.
def on_message(mqttClient, userdata, msg):
print("Recived message: "+str(msg.payload,'UTF-8'))
if(str(msg.payload,'UTF-8') == "spin" and running == False):
main(mqttClient)
def disconnected():
print("Disconneted")
def on_publish(self, client, userdata, mid):
print("onPublish")
print(client,userdata,mid)
logger = logging.getLogger(__name__)
client.enable_logger(logger)
client.on_connect = on_connect2
client.on_message = on_message
client.on_publish = on_publish
client.on_disconnect = disconnected
client.username_pw_set("....","....")
client.connect("gx1", 1883,60)
client.loop_forever()
This is because you are blocking the MQTT client thread.
When you call client.loop_forever() it takes over the processes main thread and uses it to handle all the MQTT communication. When a new message is received it is picked up from the network stack by the MQTT client thread and turned into the message object that is then passed to the on_message() callback. This function runs on the client thread.
When you call client.publish() this will do one of 2 things
If the message is QOS 0 and smaller than the network MTU it will publish the message.
If the message is QOS 1 or 2 or larger than the network MTU then it will queue the message to be handled by the client thread.
The problem* in your code is that you are blocking the return from main() by 124 seconds which in turn is blocking the return of the on_message() function so the client thread can not get to publishing your message.
If you want to do things the take a long time or block in the on_message() (or any of the callback functions) you should start a separate thread to run them on.
*In theory your message looks like it should fall into case 1 listed above, but there may be other factors that are causing it to queue)
As a quickfix I created a new Client:
def main(mqttClient):
print("Started Spinning")
running = True
start()
mq = mqtt.Client("shot_idicator")
mq.username_pw_set("...","...")
mq.connect("gx1", 1883,60)
mq.publish("scanner","shoot")
mq.disconnect()
mq = None
print("Waiting 124 seconds")
time.sleep(124)
print("ending spinning")
end()
print("finished spinning")
running = False
Now it works but I think this is not how it should be done.

python script stop running but no error showed

Working on the following python script but I find difficult to check if it runs fine because I noticed that for some errors the console doesn't show any error.
For example, if I try to print a not defined object like threadObj (see line 27) the script doesn't go further and don't even print the string on the same line
Is that the expected behavior?
The issue happen both on windows 10 and linux (raspbian)
import json
from math import ceil
import os
import queue
import sys
import subprocess
import time
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected to {0} with result code {1}".format(HOST, rc))
# Subscribe to any hotword topic --- old code: # client.subscribe("hermes/hotword/default/detected")
client.subscribe("hermes/hotword/#")
# Subscribe to any topic starting with 'hermes/intent/'
client.subscribe('hermes/intent/#')
def on_message(client, userdata, msg):
print("- Message received on topic {0}: {1}".format(msg.topic, msg.payload))
print('* ledPulse instance count {0}'.format(threadObj))
if msg.topic == 'hermes/hotword/default/detected':
print("Wakeword detected! Wakeword light!")
if msg.topic == 'hermes/intent/mywai:ShowMarketplace':
# intent ShowMarketplace light
print("Intent detected! ShowMarketplace light!")
if msg.topic == 'hermes/intent/mywai:Shutdown':
print("Intent detected! Shutdowndevice")
os.system('shutdown -s') #windows
os.system('sudo shutdown now') #linux
#########################################################################
# MAIN
#########################################################################
if __name__ == '__main__':
#main()
HOST = '192.168.1.6'
PORT = 1883
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(HOST, PORT, 60)
client.loop_forever()

MQTT - Is there a way to check if the client is still connected

Is there a way to check if the client is still connected to the MQTT broker?
Something like
if client.isConnected(): # for example
# if True then do stuff
Edit: There was instance where my Raspberry Pi stopped receiving from the client although it was still (from the look of it, the code was still showing updated results) running.
Here is the code since I may be doing something wrong:
client = mqtt.Client()
client.connect(address, 1883, 60)
while True:
data = getdata()
client.publish("$ahmed/",data,0)
time.sleep(0.2)
The thing is that I was away, so I am not even sure why it stopped! Only if I restart my broker then it will start receiving again.
You can activate a flag in on_connect and deactivate it in on_disconnect. In this way you can know if the client is connected or not.
import paho.mqtt.client as mqtt
flag_connected = 0
def on_connect(client, userdata, flags, rc):
global flag_connected
flag_connected = 1
def on_disconnect(client, userdata, rc):
global flag_connected
flag_connected = 0
client = mqtt.Client()
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.connect(server,port)
client.loop_forever()
if flag_connected == 1:
# Publish message
else:
# Wait to reconnect
I can't see one in the doc but there are the on_disconnect on_connect callbacks that can be used to set your own state variable
EDIT:
You need to call one of the loop functions to give the client cycles to handle the network operations:
client = mqtt.Client()
client.connect(address, 1883, 60)
while True:
data = getdata()
client.publish("$ahmed/",data,0)
client.loop(timeout=1.0, max_packets=1)
time.sleep(0.2)
You can use will message to do this.
client=mqtt.Client()
client.will_set('will_message_topic',payload=time.time(),qos=2,retain=True)
client.connect(address,1883,60)
client.publish('will_message_topic',payload='I am alive',qos=2,retain=True)
client.loop_start()#this line is important
while 1:#faster than while True
you loop
By leaving a will message, you can use another client to make sure if the client is online or not.
You can also view this article: How to use MQTT in Python (Paho)
A block of code from the article answering your question:
from paho.mqtt import client as mqtt_client
broker = 'broker.io'
port = 8888
client_id = 'client_id '
username = 'username'
password = 'password'
def connect_mqtt():
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
# Set Connecting Client ID
client = mqtt_client.Client(client_id)
client.username_pw_set(username, password)
client.on_connect = on_connect
client.connect(broker, port)
return client
Here is the API available.
You just use client.is_connected() returns True or False.

Publish MQTT Message every 10 Seconds...and reconnect if needed

This code that was suggested to handle publishing a message every 10 seconds. But how to handle reconnects if needed?
import paho.mqtt as mqtt
import time
mqttc=mqtt.Client("ioana")
mqttc.connect("127.0.0.1" 1883, 60, True)
#mqttc.subscribe("test/", 2) # <- pointless unless you include a subscribe callback
mqttc.loop_start()
while True:
mqttc.publish("test","Hello")
time.sleep(10)# sleep for 10 seconds before next call
The script is the absolute bare bones of what is needed send a MQTT message repeatedly but it will automatically reconnect if disconnected as it stands.
You can have it print a message when it is disconnected and reconnected to track this by modifying it as follows:
import paho.mqtt.client as mqtt
import time
def onDisconnect(client, userdata, rc):
print("disonnected")
def onConnect(client, userdata, rc):
print("connected")
mqttc=mqtt.Client("ioana")
mqttc.on_connect = onConnect
mqttc.on_disconnect = onDisconnect
mqttc.connect("127.0.0.1", port=1883, keepalive=60)
mqttc.loop_start()
while True:
mqttc.publish("test","Hello")
time.sleep(10)# sleep for 10 seconds before next call
EDIT:
To test. If you are using mosquitto as your broker then you will probably have the mosquitto_pub command installed, you can use this to force the python to disconnect by using the same client id.
mosquitto_pub -t test -i 'ioana' -m foo

Categories