Executing custom code on your Raspberry Pi from Cayenne


#1

A frequent question on the forum has been how Raspberry Pi users can run any code on their Pi, triggered from a Cayenne action or widget. This is possible with your Pi connected through our ‘Bring Your Own Thing’ MQTT API, so I’ve made a quick guide to show how to do this.

Setup

For this example to work, your Pi must be connected to Cayenne via the MQTT API rather than via the original Cayenne Pi Agent software. To do this, follow the ‘Installation’ and ‘Cayenne Setup’ instructions for the Cayenne-MQTT-Python library.

I’ll be using the Example-03-CayenneClient.py Python script for the rest of this example. It should be present in the /Cayenne-MQTT-Python/examples folder after running the install steps mentioned above.

Steps

  1. Edit the example script to enter your MQTT Username / Password / Client ID, obtained from the Cayenne Dashboard, so it can make a connection to your account.

  2. Edit the block of code labeled “The callback for when a message is received from Cayenne.” to add two new lines at the bottom:

# The callback for when a message is received from Cayenne.
def on_message(message):
    print("message received: " + str(message))
    if (message.channel == 4) and (message.value == "1"):
        execfile("test.py")

These lines check for a value of ‘1’ on MQTT channel 4. You can edit message.value and message.channel to anything you’d like. Once the value of 1 is received and the if statement is true, it will execute the python script test.py in same folder as the example client.

In my case test.py just prints “Hello World” to the terminal, but you can run any python code you’d like using this same concept.

  1. In order to send the value of 1 to trigger the python script, we need an actuator on the Cayenne dashboard. Go to Add New > Device/Widget > Custom Widgets > Button, and set it as follows:
  • Device: Your MQTT-connected Pi
  • Data: Digital Actuator
  • Unit: Digital (0/1)
  • Channel: The MQTT channel that your script is monitoring to run custom code – in my example, 4
  1. With the button widget created, toggle it while Example-03-CayenneClient.py is running on your Pi. Notice that when it is an ON (1) state, it will execute the script specified in the execfile() statement. If you want to run it again, you’ll need to toggle the button back to OFF (0), and then to ON again for the client to receive the next 1 value. This could be accomplished with a Cayenne trigger to automatically set it back to 0 so it behaves like a momentary switch.

Conclusion

Using this base logic, you can then use Cayenne triggers and scheduled events to interact with button widgets like this on your dashboard, and thus run arbitrary code on your Pi in response to Cayenne dashboard activity / widgets!


Temperature comparison with triggers
Controlling a USB Relay board through Raspberry PI
MQTT syntax
Access to Customize Triggers or Run Python Scripts
My GPIO is all low , problem
Questions about Cayenne and Raspberry
* Pi 2 Model B * Web, IOS * Can not add a servo as "Connectivity" "Channel" not working
Device not support - Help pushing data
Gestion emetteur/recepteur radio
Can't add a widget (first time...)
How to trigger a script on pi 3?
Cayenne + BH1750
TXT messages and triggers
Subscribe to topic on another device
#2

I’m not able to run Example-03-CayenneClient.py (same with the other Examples) on my Pi (raspbian-jessy-lite).
I always get this message:

pi@raspberrypi:~ $ python Cayenne-MQTT-Python/examples/Example-03-CayenneClient.py 
Connecting to mqtt.mydevices.com...
Traceback (most recent call last):
  File "Cayenne-MQTT-Python/examples/Example-03-CayenneClient.py", line 24, in <module>
    client.loop()
  File "build/bdist.linux-armv7l/egg/cayenne/client.py", line 151, in loop
  File "/usr/local/lib/python2.7/dist-packages/paho_mqtt-1.3.0-py2.7.egg/paho/mqtt/client.py", line 995, in loop
    rc = self.loop_read(max_packets)
  File "/usr/local/lib/python2.7/dist-packages/paho_mqtt-1.3.0-py2.7.egg/paho/mqtt/client.py", line 1273, in loop_read
    rc = self._packet_read()
  File "/usr/local/lib/python2.7/dist-packages/paho_mqtt-1.3.0-py2.7.egg/paho/mqtt/client.py", line 1838, in _packet_read
    rc = self._packet_handle()
  File "/usr/local/lib/python2.7/dist-packages/paho_mqtt-1.3.0-py2.7.egg/paho/mqtt/client.py", line 2291, in _packet_handle
    return self._handle_connack()
  File "/usr/local/lib/python2.7/dist-packages/paho_mqtt-1.3.0-py2.7.egg/paho/mqtt/client.py", line 2349, in _handle_connack
    self.on_connect(self, self._userdata, flags_dict, result)
TypeError: on_connect() takes exactly 3 arguments (4 given)

I’ve only set my Username,Password,Client ID and my device is displayed in the webui
Do you know what I have to change?


#3

Hi @kelltob, welcome to the Cayenne Community.

See this post that I made earlier today – I ran into this same issue on one of my Pi’s, as did another user. That should explain whats going on (the version of paho-mqtt on the Pi isn’t compatible with our example code), and how to resolve it until we update the code such that it works with both versions (or at least the newest one).

Let me know if you have any questions about that post, or trouble with the steps within.


#4

Thanks for your fast answer.
I’m sorry that I didn’t see your post. Thought i’ve searched everything.


#5

No worries at all, just wrote it up today and I’m glad to have it linked here since people using this article are going to run into it. :slight_smile:


#6

In case anyone is running into issues with execfile(), it is removed from python 3.0 and onwards.
Alternatively the command exec(open(file.py).read()) could work but I feel like that’s not a good alternative. Is there a better way?


#7

There’s always os.system() but it won’t run in the current execution context, if that’s important to you.


Creating a 10 second Latch