I'm coming from node where handling asynchronous design is as simple as adding a callback and getting on with your life. I'm trying to write some apps in python where I'm not having the same success and I'm struggling to find what to search for since there doesn't seem to be a direct equivalent.
Here's an example where I'm running an MQTT messaging client and waiting for a state change signal from a sensor.
import paho.mqtt.client as mqtt
from ouimeaux.environment import Environment
from ouimeaux.signals import receiver, statechange
def on_connect(client, userdata, rc):
print('Connected with result code '+str(rc))
client.subscribe('lights/#')
def turn_lights_on(client, userdata, rc):
for (x, value) in enumerate(devices['switches']):
devices['switches'][x].on()
def turn_lights_off(client, userdata, rc):
for (x, value) in enumerate(devices['switches']):
devices['switches'][x].off()
def reply_with_devices(client, userdata, rc):
for (x, value) in enumerate(devices['switches']):
client.publish('devices/new', switches[x])
for (x, value) in enumerate(devices['motions']):
client.publish('devices/new', motions[x])
def on_switch(switch):
print "Switch found: ", switch.name
devices['switches'].append(switch)
def on_motion(motion):
print "Motion found: ", motion.name
devices['motions'].append(motion)
client = mqtt.Client("wemo_controller")
client.on_connect = on_connect
client.message_callback_add('lights/on', turn_lights_on)
client.message_callback_add('lights/off', turn_lights_off)
client.message_callback_add('devices/discover', reply_with_devices)
client.connect('localhost', 1883, 60)
print 'Running WEMO controller - listening for messages on localhost:1883'
devices = { 'switches': [], 'motions': [] }
env = Environment(on_switch, on_motion)
env.start()
env.discover(seconds=3)
switch = env.get_switch('Desk lights')
@receiver(statechange)
def motion(sender, **kwargs):
print 'A THING HAPPENED'
print "{} state is {state}".format(sender.name, state="on" if kwargs.get('state') else "off")
env.wait()
client.loop_forever()
Both libraries seem to have their own way of holding up the thread but it seems like I can only have one blocking and listening at a time. I have a feeling that threading might be the answer, but I'm struggling to work out how to implement this and not sure if it's right. I'm also confused as to what wait() and loop_forever() actually do.
The answer I'm looking for is the 'python' way to solve this problem.
twisted(as already mentioned),tornado, andasyncio, which is built into Python starting with version 3.4. It looks like there's a (poorly documented) MQTT library built using tornado. An another built onasyncio.