How to use ClientID, Username, Password?

I’ve been reading a lot of posts to find a clear answer …

  1. I installed Cayenne on one R-Pi (let’s call it rpi1) and got ClientID, username, password.
  2. I then used Cayenne API to send DHT22 data to Cayenne broker, with “Bring Your Own Thing” in the dashboard. This works.
  3. Next I wrote Python code to run on Windows desktop using paho-mqtt to be a client and subscribe for my data from rpi1. Note: I am not using Cayenne API at all on the Windows machine.
  4. Here is the first problem: what to use for ClientID, username, password? I used the same values as rpi1. This works, I am able to subscribe and get the data, but it seems wrong to use same credentials.
  5. Now I have another R-Pi (let’s call it rpi2). I have not yet installed Cayenne on it. If I do, I’ll get a new ClientID, correct? But what about username and password, will they be different?
  6. I’ve used the same ClientID, username, password on rpi2. This also works, at least for a few hours and then mysteriously stops getting subscribed message data (nothing more seen by on_message handler).

I just think what I’m doing can’t be correct. I’m using the same credentials on 3 different devices and only one of them has Cayenne installed.

Help please.

the username and password are same for all devices added on your account. it is only that the client_id that changes for different devices. so your rpi1 and rpi2 will have two separate client _id. if you have installed the pi agent you will find it in /etc/myDevices/AppSettings.ini .
when you use same client_id on different devices, it gives disconnect error.

Thank you! I am seeing one device apparently disconnect after a few hours. It then shows a new connect notice (I am logging on_connect, on_subscribe and on_message activity), which surprised me. After that I get no more messages, because the program does not re-subscribe. Now I know that I need a distinct ClientID.

Q: what do you mean by “pi agent”? Does that mean I should install Cayenne on each R-Pi?
Q: can I get a new ClientID from Cayenne for a device that only has paho-mqtt in use?
Q: if I use a different MQTT broker service, I believe I can just make up a ClientID. Is that true? For example, use test.mosquitto.org.

1)when you install cayenne on a raspberry by navigating into add new—> device/widget—>raspberry and then adding the command, it the pi agent which is installed.
yes, you need to installed cayenne(pi agent) on each rpi. so that a unique client_id is assigned to each rpi.
2) yes, you can get a new client_id by adding a new bring your own thing.
3) yes, for other broker you can create your own client id, but when using cayenne you need to get it from dashboard

Q: using Cayenne broker, when is CLIENT_ID required?
I think that the publisher needs it. I am using Cayenne API for the publisher code, but not for the subscriber.
I think that the subscriber does not need to use its own CLIENT_ID, it only needs the publisher CLIENT_ID in its topic string.

Darn, I added Cayenne to rpi2, but still have a problem maintaining subscription - I believe the connection is eventually dropped, because in my logfile I see subscribed data every 30 seconds and then it stops and I immediately get a new connection notice. But because I am not handling disconnect, I fail to attempt to resubscribe and never get any more data.
Since this is my first foray into MQTT, perhaps this is as expected - that is that random disconnects will happen.

Can someone take a look at my code below and determine if I’ve connected and subscribed correctly? Certainly it’s quasi-correct, since I get data for a few hours. But maybe I’ve missed some parameters.

Thank you so much.

The publisher is rpi1. When rpi2 subscribes, I use PUB_CLIENT_ID from rpi1 in the topic. I don’t use the MQTT_CLIENT_ID for rpi2 anywhere - it doesn’t seem to be required for the connection.

MQTT_HOST = "mqtt.mydevices.com"    # Cayenne services
MQTT_USERNAME  = "<assigned by Cayenne>" # same for all my devices
MQTT_PASSWORD  = "<assigned by Cayenne>" # same for all my devices
# Next is ID for this computer:
MQTT_CLIENT_ID = "<rpi2 ID from Cayenne>"
# Here is ClientID for the publisher, a different computer:
PUB_CLIENT_ID = "<rpi1 ID from Cayenne>"

def on_connect():
    pass # do stuff
def on_subscribe():
    pass # do stuff
def on_message():
    pass # do stuff, like logging messages and storing

def my_connect():
    client = mqtt.Client(client_id="", clean_session=True, userdata=None, transport="tcp", protocol=mqtt.MQTTv311)
    client.on_connect = on_connect
    client.on_message = on_message
    client.username_pw_set(username=MQTT_USERNAME, password=MQTT_PASSWORD)
    # Steve recommends adding a connect flag:
    client.connected_flag = False
    client.bad_connection_flag = False
    # If the broker decides to timeout the connection, the client will have to reestablish.
    client.connect(MQTT_HOST, port=1883, keepalive=60, bind_address="")
    client.loop_start()
    while not client.connected_flag:
        logger.info("Wait for connect")
        time.sleep(1)
    return client

def my_subscribe(client, message_store = None):
    # TOPIC3 and TOPIC4 are formatted like: v1/username/things/clientID/data/channel
    # clientID for TOPIC is PUB_CLIENT_ID
    logger.info("Start Main loop")
    client.has_message = False
    client.on_subscribe = on_subscribe
    client.on_message = on_message
    result,msg_id = client.subscribe(TOPIC3)
    logger.debug('subscribe: result=%s, msg_id=%s' %(str(result),str(msg_id)))
    result,msg_id = client.subscribe(TOPIC4)
    logger.debug('subscribe: result=%s, msg_id=%s' %(str(result),str(msg_id)))

client = my_connect()
my_subscribe(client)

Are you running into a rate limit problem?

@kitecamguy are you familiar with node-red?

Not a rate limit problem - I only send 4 messages per minute.
So is my code OK? The subscribe client connects with username/password and only uses the client_id of the publisher in the topic string? The subscribe client does not need to use its own client_id?
I have two clients: one publisher, one subscriber. If they are both located in my LAN, how does the Cayenne broker distinguish them, since both default to using port 1883? Of course the problem is compounded by the likelihood of having even more clients within my LAN - and they all use the same username/password.

I have never used node-red, only know that I might benefit from using it!

without its own client_id, how will it connect? you need to use subscriber client_id so that the device connects and use the publisher client_id to subscribe to publisher topic.

there is another way around if you like to do it, it is using node-red.
there is a tutorial on how to start with node-red and cayenne from @adam Using Node-RED as a Local Fallback Server
once you have got famillar with it and got your pi connect to cayenne with node-red, you can import this flow into your node-red:

[{"id":"6bc56682.b5c4f8","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"cf4707f9.2326d8","type":"mqtt in","z":"6bc56682.b5c4f8","name":"Cayenne Input","topic":"v1/username/things/client_id_of_publiser/data/14","qos":"2","broker":"33f82b09.92c7c4","x":160,"y":300,"wires":[["482ccb10.ea7314","a152a6b.6b47658","b51992fe.10189","c3a50bce.d011f8"]]},{"id":"482ccb10.ea7314","type":"debug","z":"6bc56682.b5c4f8","name":"","active":true,"console":"false","complete":"false","x":390,"y":260,"wires":[]},{"id":"a152a6b.6b47658","type":"function","z":"6bc56682.b5c4f8","name":"Send Back Received Value","func":"msg.payload = msg.payload.slice(-1);\n\nreturn msg;","outputs":1,"noerr":0,"x":440,"y":300,"wires":[["5da5bc04.608494"]]},{"id":"7340f6f4.0c1128","type":"inject","z":"6bc56682.b5c4f8","name":"Setup","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":true,"x":130,"y":180,"wires":[["f09360d8.604c9"]]},{"id":"f09360d8.604c9","type":"function","z":"6bc56682.b5c4f8","name":"Set Global Variables","func":"global.set(\"username\",\"See Post\");\nglobal.set(\"client_id_of_subscriber\",\"See Post\");\n\nreturn msg;","outputs":1,"noerr":0,"x":420,"y":180,"wires":[["cb06d1a7.6fcc3"]]},{"id":"cb06d1a7.6fcc3","type":"debug","z":"6bc56682.b5c4f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":770,"y":180,"wires":[]},{"id":"5da5bc04.608494","type":"debug","z":"6bc56682.b5c4f8","name":"","active":false,"console":"false","complete":"false","x":770,"y":240,"wires":[]},{"id":"b51992fe.10189","type":"mqtt out","z":"6bc56682.b5c4f8","name":"Cayenne Output Channel 1","topic":"v1/username/things/client_id_of_publiser/data/16","qos":"0","retain":"true","broker":"33f82b09.92c7c4","x":600,"y":440,"wires":[]},{"id":"c3a50bce.d011f8","type":"serial out","z":"6bc56682.b5c4f8","name":"output","serial":"7232faf5.520024","x":348.5,"y":546,"wires":[]},{"id":"33f82b09.92c7c4","type":"mqtt-broker","z":"","name":"","broker":"mqtt.mydevices.com","port":"1883","clientid":"client_id_of_subscriber","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"7232faf5.520024","type":"serial-port","z":"","serialport":"/dev/ttyACM0","serialbaud":"57600","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false,"responsetimeout":"10000"}]

in the flow, only the cayenne input node will have the client_id of the publisher, so that it subscriber to the topic of the publisher.
the flow gets the temperature data from the publisher and send it to the arduino via serial port and shows the temperature from the publisher on the subscriber dashboard.
this is a basic flow on how to get data from another publisher device. you have change the flow according to your need.