Xively Reflections

Modifying devices over MQTT

This section describes how to modify device properties and custom fields using MQTT channels, and how to get notifications about rejected and successful modifications. This feature is called Xively Reflections.

Every device in Xively, independently of its device template, is created with the same basic elements, which include the following:

  • A default set of properties (listed in The device object)
  • Four custom fields ("deviceVersion", "location", "name", "purchaseDate")
  • Four default channels ("_log", "_set/fields", "_rejected", "_updates/fields")

You can make changes in the device properties and custom fields over MQTT, using the following three channels:

  • _set/fields - to modify device properties and custom fields
  • _rejected - to track errors resulting from an unsuccessful modification
  • _updates/fields - to track all the successful modifications

Each of the channels is described below with examples of MQTT payloads.

What can be modified over MQTT

Over MQTT, you can modify values of all the device custom fields and the same set of device properties as if you were using HTTP APIs with one exception: "organizationId" cannot be updated through MQTT calls. So to change the group the device belongs to, use API calls. For more details on which properties can be modified, see: The device object.

You cannot create or delete properties, custom fields, nor channels through MQTT. Properties cannot be removed at all, only their values can be modified. To create or remove custom fields or channels, use API calls or Xively management app.

The _set/fields channel

Publish to the _set/fields channel of your device to set a device property or custom field value.

Subscribe to the _set/fields channel of your device to watch messages published to this channel. This can be useful if you want to collect logs from this channel.

The MQTT topic has the following format:
xi/blue/v1/<accountID>/d/<deviceID>/_set/fields

For example, to change the device latitude and longitude, publish the following message:

{
    "state": {
        "latitude": 42.348062,
        "longitude": -71.050344
    }
}

Optionally, add a condition verifying the device version, or a "requestId" to identify the message. Version is the unique string that represents the most recent state of this device; "requestId" is a string. For example, update a device field only if the device version has a given value 3F, and set this message ID to 1234ABCD:

{
    "state": {
        "<field to be updated>": "<value>"
    },
    "condition": {
        "version": "3F"
    },
    "requestId" : "1234ABCD"
}

If a message sent to the _set/fields channel cannot be processed, the _rejected channel informs you about this fact.

Important: If you publish a message that contains a field the device does not yet have, this field will NOT be created and you will NOT be notified about any error, as long as the syntax of the payload is correct.

The _rejected channel

Subscribe to the _rejected channel of a device to get notifications about all the rejected MQTT payloads sent to the _set/fields channel of this device. You can only subscribe to this channel.

The _rejected channel tracks all MQTT messages sent to the _set/fields channel and in case of rejection of the payload, returns the cause of the error, for example: invalid message payload or a precondition failed (for example, version mismatch). The tracking takes place within one device, so the _rejected channel of a device A controls the _set/fields channel of the same device A. This channel informs only about rejected MQTT calls, not about wrong HTTP API calls.

The MQTT topic has the following format: xi/blue/v1/<accountID>/d/<deviceID>/_rejected

The following example shows an error returned after publishing an incorrect syntax payload to the _set/fields channel.

{
    "request" : {
        "state" : null
    },
    "error" : {
        "code" : 400,
        "message" : "Invalid message payload."
    },
    "requester" : {
        "id" : "759a4ebe-a5c2-4016-9112-bb956e39fd07"
    },
    "requestId" : "9876WXYZ"
}

The message contains the following information:

  • Error cause - for the full list of error codes, see Error codes
  • "requester" - the GUID of the actor that requested the modification (userId, applicationId, or device id)
  • "requestId" - the message ID, present only if "requestId" was defined at the time of publishing this message on the _set/fields channel

The _updates/fields channel

Subscribe to the _updates/fields channel of your device to download the initial state of this device and get notifications about changes in its state.

At the time of subscription, the current device state is published, and you see all the device properties and custom fields displayed on the _updates/fields channel.

{
    "state" : {
        "version" : "3F",
        "field1" : "<value>",
        "field2" : "<value>",
        "lastModified" : "2017-03-28T15:39:42.000Z",
        "lastModifiedById" : "759a4ebe-a5c2-4016-9112-bb956e39fd07"
    }
}

After the device state is published, the channel displays all the changes in this device made over the _set/fields channel or HTTP API calls since the time of your subscription. The messages include also the changes in the system-updated fields, like "provisioningState". You can only subscribe to this channel, do not publish there.

When a message is published on the _updates/fields channel right after you sent a device modification message over the _set/fields channel, it is a confirmation that your MQTT message has been processed correctly.

This channel does not show any data changes coming from the device sensors, nor does it include any updates to the device template or channels. It informs that a modification in device properties or custom fields has taken place, however the message does not specify whether the modification resulted from an MQTT or an HTTP API call.

The MQTT topic has the following format:
xi/blue/v1/<accountID>/d/<deviceID>/_updates/fields

The following example shows a log published after the "latitude" and "longitude" custom fields have been changed.

{
    "state" : {
        "version" : "Xe",
        "latitude" : 42.348062,
        "longitude" : -71.050344,
        "lastModified" : "2017-03-30T14:43:42.000Z",
        "lastModifiedById" : "759a4ebe-a5c2-4016-9112-bb956e39fd07"
    },
    "requester" : {
        "id" : "759a4ebe-a5c2-4016-9112-bb956e39fd07"
    },
    "requestId" : "1234ABCD"
}

The log lists the following information:

  • "version" - the version of the device after the change has been made
  • All the device fields that have been modified and their new values
  • "lastModified" - the ISO 8601 formatted timestamp of the modification
  • "lastModifiedById" - the GUID of the actor that last modified this device (userId, applicationId, or device id)
  • "requester" - the GUID of the actor that requested the modification (userId, applicationId, or device id)
  • "requestId" - the message ID, present only if "requestId" was defined at the time of publishing this message on the _set/fields channel

The ID of "requester" and "lastModifiedById" always take the same value.

Summary

The _set/fields, _rejected, and _updates/fields channels are complementary:

  • Publish to _set/fields to send a device field change.
  • Subscribe to _set/fields to see your message.
  • Subscribe to _rejected to see any errors related to your published message.
  • Subscribe to _updates/fields to get the initial state of a device, track changes in the device fields, and to get a confirmation that your published message has been processed correctly.

Xively Reflections

Modifying devices over MQTT