Receiving operations via MQTT with JSON payload

Cumulocity IoT 10.18.0

Receiving operations via MQTT with JSON payload.

As reported in the documentation at the following link
SmartREST 2.0 - Cumulocity IoT Guides I tried to subscribe to the devicecontrol/notifications topic (using Eclipse Path for java) but I always get an error. I can subscribe to other topics (example error) but not devicecontrol/notifications. I found on the forum that it is deprecated and that it should be replaced with /notification/operations but the result does not change, I get the same error.
What I would like to know is how to receive a message like the one below on the device, via MQTT, as reported in the documentation. Thank you very much

{
“agentId”: “1”,
“creationTime”: “2018-05-17T07:33:15.555Z”,
“delivery”: {
“log”: [

 ],
 "status": "PENDING",
 "time": "2018-05-17T07:33:15.575Z"

},
“deviceId”: “2”,
“id”: “123”,
“status”: “PENDING”,
“c8y_Command”: {
“text”: “Do something”
},
“description”: “Execute shell command”,
“externalSource”: {
“externalId”: “3”,
“type”: “c8y_Serial”
}
}

If you get an error, what is the error you get?

Please note that if you want to receive operations you need to make sure that the device you are subscribing to is flagged as agent. Also the owner of the device should match with the device user of you your client otherwise you have permissions problems.

Best way would be to create the device via the MQTT client and directly subscribing on the topics.

Do you have any reasons using JSON over MQTT instead of SmarREST 2.0 via MQTT?

Hello Stefan,

the java error is:

Exception in thread “main” MqttException (128)
at org.eclipse.paho.client.mqttv3.MqttClient.subscribe(MqttClient.java:438)
at org.eclipse.paho.client.mqttv3.MqttClient.subscribe(MqttClient.java:469)
at org.eclipse.paho.client.mqttv3.MqttClient.subscribe(MqttClient.java:464)
at tests.AppPureMQTT.main(AppPureMQTT.java:73)

Yes my device is flagged as Agent. Using JSON over MQTT is a customer requirement.

Thanks, Marco

I tried to create the MO via MQTT and immediately after subscribing to /notification/operations but the result does not change. Same error: MqttException (128)

{
“name”: “JSON_MQTT_GATEWAY”,
“c8y_IsDevice”: { },
“com_cumulocity_model_Agent”:{},
“c8y_DeviceTypes”: [
“C8Y_MQTT”
],
“c8y_SupportedOperations”: [
“c8y_Restart”, “c8y_Command”
]
}

Check the following:

  • The MQTT topic is devicecontrol/notifications not /devicecontrol/notifications…so that might be causing the main issue.
  • Check that the credentials you are using have access to the device. If you manually created the device managed object, then it might cause a problem if you are using device credentials from within the Java MQTT client.

Hi, I also tried /devicecontrol/notifications but the error is the same.
Yes, the credentials are the same. I can subscribe to the error topic without errors.

Just checking, you are using the MQTT topic devicecontrol/notifications correct? (Your response was a bit ambiguous) .

Being able to subscribe to the error topic (s/e) does not prove that your user has permissions to the device managed object. Typically if you are using device credentials, then the device managed object will have a owner property which will be of the format device_<userid>.

Though posting your Java code would be helpful for other Java people to review it (I’m not a Java person, so I won’t be able to help here).

1 Like

Here is the java code:

         // MQTT connection options
	final MqttConnectOptions options = new MqttConnectOptions();
	options.setUserName(tenantId + "/" + username);
	options.setPassword(password.toCharArray());
	options.setCleanSession(true); 

	final MqttClient client = new MqttClient(serverUrl, clientId);
	client.connect(options);
	client.subscribe("error", new IMqttMessageListener() {

		@Override
		public void messageArrived(final String topic, final MqttMessage message) throws Exception {
			final String payload = new String(message.getPayload());
			System.out.println("Error occured: " + payload);
		}
	});

	String createDevive = "{\r\n" + "	\"name\": \"JSON_MQTT_GATEWAY_XYZ\",\r\n" + "	\"c8y_IsDevice\": { },\r\n"
			+ "	\"com_cumulocity_model_Agent\":{},\r\n" + "	\"c8y_DeviceTypes\": [\r\n" + "		\"C8Y_MQTT\"\r\n" + "	],\r\n"
			+ "	\"c8y_SupportedOperations\": [\r\n" + "		\"c8y_Restart\", \"c8y_Command\"\r\n" + "	]\r\n" + "}\r\n" + "";

	client.publish("/inventory/managedObjects/create", new MqttMessage(createDevive.getBytes()));

	client.subscribe("/devicecontrol/notifications", new IMqttMessageListener() {

		@Override
		public void messageArrived(final String topic, final MqttMessage message) throws Exception {
			final String payload = new String(message.getPayload());
			System.out.println("Command received: " + payload);
		}
	});

At least some functional problems that I see:

  1. You are using the incorrect devicecontrol topic. It should be devicecontrol/notifications
  2. Device’s should be registered first using the SmartREST 2.0 template - 100. This is important as it will create a device in Cumulocity and give it an External ID with the type c8y_Serial. This is critical for device communication.
  3. You should be connecting the MQTT client using a client id which matches the External ID used in the previous step (see mqtt-clientid)

Though I just checked some docs, and I think this example will be closer to what you want, as the example includes the initial device registration using the SmartREST template 100 message, and then you will just have to change it to subscribe to JSON over MQTT operation topic, devicecontrol/notifications:

Hello Reuben, I solved, creating device using SmartRest 2.0 I can subscribe the topic. It works.
Thank you so much for you support!

1 Like

In addition to Reuben comments:

  • You might need use object parsing to create json objects
  • You can use a combination of SmartREST 2.0 and JSON (over REST or MQTT) like Reuben mentioned with the 100 static template. I would use SmartREST 2.0 wherever it is possible as it is much more efficient.

Hello,
I am now able to receive commands subscribing the topic “devicecontrol/notifications” . But I didn’t find how to change the command state using MQTT with JSON Payload? . Is there a way to do this?
Marco

I don’t know of a way using JSON via MQTT (see also the note here, it is more meant as an addition to Smart Rest and does not have the goal to fully replace it).

But you can do it easily via Smart Rest 2:

topic: s/us, message: 504,{operation id}  => sets Operation to executing
topic: s/us, message: 505,{operation id},{failure reason}  => sets Operation to failed
topic: s/us, message: 506,{operation id}  => sets Operation to successful
1 Like

Thanks for the reply. Since the client also wants to use JSON via MQTT I was wondering if there is a way to change the state with a JSON message. I get a message like this:

{
“agentId”: “1”,
“creationTime”: “2018-05-17T07:33:15.555Z”,
“delivery”: {
“log”: [

],
"status": "PENDING",
"time": "2018-05-17T07:33:15.575Z"

},
“deviceId”: “2”,
“id”: “123”,
“status”: “PENDING”,
“c8y_Command”: {
“text”: “Do something”
},
“description”: “Execute shell command”,
“externalSource”: {
“externalId”: “3”,
“type”: “c8y_Serial”
}
}

on topic devicecontrol/notifications, I guess there is a way to also reply with an MQTT message with pure JSON payload.

No there is not a way to update the operation using JSON via MQTT.

I would really question the customer requirement here, as “using MQTT payloads” is not really a requirement it is more a solution to a requirement.

In the end the requirement is to update an operation using the API provided by the platform, and in this case it is SmartREST API. You can still use JSON via MQTT for other API calls (e.g. update managed object fragments, create alarms, create events etc.).

1 Like