Change Raspberry Pi GPIO state by manually publishing MQTT

Hi,

I have just started using Cayenne and I’m working my way through it. I have managed to get an Arduino Yun connected and I can control the I/O from either the dashboard or using MQTT.fx.

I have also managed to setup a Raspberry Pi on the dashboard and have multiple DS18B20 devices pushing data from the Pi and I can control the GPIO though dashboard widgets.

What I can’t figure out is how to send a command using MQTT.fx to Cayenne to control the GPIO. I have tried using:

v1/xxx-my-user-id-xxx/things/xxx-pi-device-id-xxx/cmd/dev:wq12KGELzpo1vtD/1

with dev:wq12KGELzpo1vtD being the channel ID assigned to the GPIO button in the dashboard but all that happens is that MQTT.fx says the command was published correctly, then disconnects!

Could someone point me in the right direction, either by example or a link to a page that explains how to do it.

Thanks in advance

Andy Hodges

first of all, you cannot connect two instances with same client id, hence you are getting the disconnect.

Are you trying to change the state of actuator widget like button? then this is not possible. You can publish the sensor widget data.

Hi,

Thanks for your response.

I have setup a client in Cayenne specifically for MQTT.fx by going to “Add New → Device/Widget → Bring your own thing” in order to avoid using a duplicate client ID, so MQTT.fx is it’s own entity.

I then try and publish as per my original post to:

v1/xxx-my-user-id-xxx/things/xxx-pi-device-id-xxx/cmd/dev:wq12KGELzpo1vtD/1

with the Pi’s device ID in the MQTT publish command. This disconnects me and does not change the relay on the Pi GPIO. If I use the MQTT.fx client ID then my command gets published (under the MQTT.fx device) and I don’t get disconnected.

The workaround I have at the moment involves creating two triggers using the virtual actuator under the MQTT.fx device to control the actual actuator on the Raspberry Pi device. Something like:

Trigger 1
IF
MQTT.fx channel 1 > 0
THEN
Raspberry Pi dev:wq12KGELzpo1vtD = ON

Trigger 2
IF
MQTT.fx channel 1 < 1
THEN
Raspberry Pi dev:wq12KGELzpo1vtD = OFF

That works but it seems a very long way round the issue if I have to do that for all the relays I have connected.

Am I not able to control the Pi’s GPIO directly from a different device in my Cayenne dashboard?

Thanks again for your help.

Regards

Andy Hodges

We do not support this.

Hi,

Thanks again for your reply. Good to know, at least I won’t be chasing my tail trying to get it working.

Regards

Andy Hodges

But why do you want to control it from another device? You can use trigger like you mentioned above.

Hi,

From what I can tell a Cayenne trigger can only have one input and one output.

For one project I need to be able to control multispeed fans (Off, Low, Medium, High) based on a temperature range rather than just “If greater than x turn y on, if less than x turn y off”. I am not going to be able to do that with the options available. Another project is to control a fridge / freezer during the winter months to ensure that the freezer stays at a low enough temperature. In that instance, the compressor needs to be turned on / off based on the results of three temperatures (Fridge, Freezer, Plate) which again does not appear something I can easily do within the realms of Cayenne triggers.

I had hoped to do the main interfacing with Cayenne and the extended processing with NodeRED but as you have pointed out, Cayenne does not support different MQTT devices controlling each other.

The easiest solution will be to leave the data collection / processing / control etc in NodeRED and just publish temperatures to Cayenne for data logging purposes.

Regards

Andy Hodges

1 Like

First of all, do not use raspberry pi cayenne agent for this. Better will be to shift to using cayenne python library GitHub - myDevicesIoT/Cayenne-MQTT-Python: Python Library for Cayenne MQTT API which will give you must more control to do what you want manually by adding the appropriate code.

This is possible by using 4 different triggers for each mode. Though as you mentioned it won’t be a straight forward and will be a long way.
Same for other project.
If you want we can try doing some try and error methods to get it working.

Unfortunately I am not familiar with Python at this point so using the Python library is more of a headache than it may seem.

I am not sure that triggers will work with the fan solution, purely due to the way I have the hardware setup, currently I use two GPIO / relays to select between the four modes:

Mode: Off Relay1: Off Relay2: Off
Mode: Low Relay1: On Relay2: Off
Mode: Med Relay1: Off Relay2: On
Mode: High Relay1: On Relay2: On

The current projects are already running in NodeRED, coded and working. I liked the look and feel of Cayenne and wanted to take advantage of the historic data logging, something I don’t currently have the facility for. It looks like I would need to start these projects almost from scratch in order to implement them within this system and that is sadly something current commitments will not allow.

Regards

Andy Hodges

2 Likes

I was able to do exactly this over the winter with a root cellar, but then they discontinued the REST API integration, now i cannot control my fans. Haven’t found a solution yet.

Rob

from basic trigger control you can do on the cayenne, but more advance control you can do it on your device itself.

But can you do advanced trigger control between devices as Andy has suggested. I have 5 EXP8266 devices sending data to Cayenne, but I want a single python script to monitor that data and send triggers to any of the 5 devices. Can you do that with Python cayenne-mqtt on Raspberry Pi by sending virtualWrite commands to any of the 5 devices in Cayenne? I guess it would mean I would have to establish a new MQTT client connection with a MQTT Client ID specific to each of the 5 devices I would need to set. Is this possible?

You can communicate between esp8266 device using this code Multiple MQTT Clients on 8266
For python you can use this code How to interface two RaspberryPis over MQTT with Cayenne - #6 by shramik_salgaonkar

Hi Shramik,

I’ve tried updating a sensor state on any of my esp8266 (Zone 1, 2, 4) using the attached python code on a linux host. Visually, I can see the state of the sensor has changed in the Cayenne dashboard based on the colour change to the sensor, however the ESP8266 is not picking up the state change and activating the sensor (ie. fan switch). I’ve even changed from using digital_sensor to digital_actuator but no difference observed. Any ideas?

#!/usr/bin/env python
import cayenne.client
import time
import logging

Cayenne authentication info. This should be obtained from the Cayenne Dashboard.

NOTE: the MQTT_CLIENT_ID is the client_id for the ESP8266

MQTT_USERNAME = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
MQTT_PASSWORD = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
#Zone 1 ESP8266
#MQTT_CLIENT_ID = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
#Zone 2 ESP8266
#MQTT_CLIENT_ID = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
#Zone 4 ESP8266
MQTT_CLIENT_ID = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
#Test_python
#MQTT_CLIENT_ID = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
#Test_python2
#MQTT_CLIENT_ID = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”

TRIGGER_CHANNEL = 2 #Virtual channel for publishing the trigger value.
STATE = 0

i=0
timestamp = 0

The callback for when a message is received from Cayenne.

def on_message(message):
print("message received: " + str(message))
# If there is an error processing the message return an error string, otherwise return nothing.

client = cayenne.client.CayenneMQTTClient()
client.on_message = on_message
client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID)

For a secure connection use port 8883 when calling client.begin:

client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID, port=8883, loglevel=logging.INFO)

def fan_state(STATE):
if STATE:
#client.virtualWrite(TRIGGER_CHANNEL,1,“digital_sensor”,“d”)
client.virtualWrite(TRIGGER_CHANNEL,1,“digital_actuator”,“d”)
else:
#client.virtualWrite(TRIGGER_CHANNEL,0,“digital_sensor”,“d”)
client.virtualWrite(TRIGGER_CHANNEL,0,“digital_actuator”,“d”)

while True:
client.loop()
if (time.time() > timestamp + 10):
timestamp = time.time()
if (i%2):
fan_state(1)
else:
fan_state(0)

    i = i + 1
    if (i == 12): # Reset the sensor value to test that the trigger gets reset.
        i = 0

why are you using the python code for esp8266? there is arduino library that you can use.

Hi Shramik,

To clarify, I am using the Arduino IDE for the esp8266 and then doing some additional processing on a raspberry pi with the python code.

When using the python code I provided to set the state of some fans connected to the esp8266’s the change in state is not detected by the esp8266 unless I manually change the state in the dashboard.

changing the state of the actuator is not just publishing the state. When a state is changed from the dashboard, it need a response back from the device.
So in short, you cannot change the actuator state from the device.

Hi Shramik,

So what is the best option to publish the state (turn fan on or off) from source A (python code on Raspberry pi) to affect the fan on source B (esp8266)?

Thanks

Use trigger Cayenne Docs