Create Asset by MQTT

Hello,

Once again I’m trying to replicate an existing process through the HTTP API in MQTT protocol and I’m not sure if this is possible, so I decided to ask here on the forum.

In this endpoint I can create a new asset by HTTP request sending its JSON structure:
http://{{root}}/api/{{realm}}/asset

payload example:

{
  "id" : "UUID converted base62 22bytes",
  "version" : 0,
  "createdOn" : 0,
  "name" : "asset-name",
  "accessPublicRead" : false,
  "realm" : "asset-realm",
  "type" : "BuildingAsset",
  "path" : ["id defined base62 22bytes" ],
  "attributes" : {
    "area" : {
      "type" : "positiveInteger",
      "value" : null,
      "name" : "area",
      "timestamp" : 0
    },
    "notes" : {
      "type" : "text",
      "value" : null,
      "name" : "notes",
      "timestamp" : 0
    },
    "city" : {
      "type" : "text",
      "value" : null,
      "name" : "city",
      "timestamp" : 0
    },
    "street" : {
      "type" : "text",
      "value" : null,
      "name" : "street",
      "timestamp" : 0
    },
    "postalCode" : {
      "type" : "text",
      "value" : null,
      "name" : "postalCode",
      "timestamp" : 0
    },
    "location" : {
      "type" : "GEO_JSONPoint",
      "value" : null,
      "name" : "location",
      "timestamp" : 0
    }
  }
}

can I do the same through MQTT?

I verified that when creating an Asset the JSON structure sended is:

{
  "eventType" : "asset",
  "cause" : "CREATE",
  "asset" : {
    "id" : "7VesBAWXNhBIxF0ZNJvWBc",
    "version" : 0,
    "createdOn" : 0,
    "name" : "New Asset",
    "accessPublicRead" : false,
    "realm" : "master",
    "type" : "ThingAsset",
    "path" : [ "7VesBAWXNhBIxF0ZNJvWBc" ],
    "attributes" : {
      "notes" : {
        "type" : "text",
        "value" : null,
        "name" : "notes",
        "timestamp" : 0
      },
      "location" : {
        "type" : "GEO_JSONPoint",
        "value" : null,
        "name" : "location",
        "timestamp" : 0
      }
    }
  },
  "timestamp" : 0
}

sended to topic:
{{realm}}/{{MQTTClientID}}/asset/{{AssetID}}

however, when trying to replicate the same scenario above (created using the UI), I get stuck with an error:

2022-08-31 15:16:18.124  WARNING [pool-11-thread-1              ] te.model.util.ValueUtil.MODEL_AND_VALUES : Failed to parse JSON
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'asset' as a subtype of `org.openremote.model.attribute.AttributeEvent`: Class `org.openremote.model.asset.AssetEvent` not subtype of `org.openremote.model.attribute.AttributeEvent`
 at [Source: (String)"{
  "eventType" : "asset",
  "cause" : "CREATE",
  "asset" : {
    "id" : "7VesBAWXNhBIxF0ZNJvWBc",
    "version" : 0,
    "createdOn" : 0,
    "name" : "New Asset",
    "accessPublicRead" : false,
    "realm" : "master",
    "type" : "ThingAsset",
    "path" : [ "7VesBAWXNhBIxF0ZNJvWBc" ],
    "attributes" : {
      "notes" : {
        "type" : "text",
        "value" : null,
        "name" : "notes",
        "timestamp" : 0
      },
      "location" : {
        "type" : "GEO_JSONPoint",
    "[truncated 111 chars]; line: 2, column: 17]
        at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
        at com.fasterxml.jackson.databind.DeserializationContext.invalidTypeIdException(DeserializationContext.java:2073)
        at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:199)
        at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:125)
        at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:110)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1292)
        at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:74)
        at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323)
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4674)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3629)
        at org.openremote.model.util.ValueUtil.parse(ValueUtil.java:189)
        at org.openremote.model.util.ValueUtil.parse(ValueUtil.java:201)
        at org.openremote.manager.mqtt.DefaultMQTTHandler.doPublish(DefaultMQTTHandler.java:374)
        at org.openremote.manager.mqtt.ORInterceptHandler.onPublish(ORInterceptHandler.java:201)
        at io.moquette.interception.BrokerInterceptor.lambda$notifyTopicPublished$3(BrokerInterceptor.java:134)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        at java.base/java.lang.Thread.run(Thread.java:833)

That’s when I was in doubt if I was using the correct topic, or even if there is this topic for creating assets through MQTT. As far as I’ve seen in the documentation, it seems to have only topics related to attribute state update.

What I would like to know:
- Which topic should I point to? If it exists, of course.
- Is the payload structure correct?
- If this feature doesn’t exist, where could I start to try to implement it? If it makes sense.

Any help would be appreciated, thanks.

Hi Luiz, did you find this wiki: User Guide: Auto Provisioning · openremote/openremote Wiki · GitHub ? Although I am not an expert, this flow describes the way assets get created (via MQTT) and might be of help solving your problem?

Thank you Pierre,

I will read this content and see if it is what I need for implementation.

The wiki guide @Pierre mentioned is for auto provisioning an asset that represents a device connecting via MQTT.

The functionality available over MQTT is limited at the moment but you can use websockets to perform most tasks available in the REST API; unfortunately create assets is not one of the available actions simply because it is better suited to a request-response pattern (i.e. HTTP).

The goal long term is to expose the full API over MQTT and to then allow MQTT over websockets.

Would be interested to hear about your use case for creating assets over MQTT though :slight_smile:

2 Likes

Could you provide your code? What kind of Device you use?

Cause when you send an JSON Structure with c++, it should look like e.g:


>     char mqtt_payload[100] = "";
>     snprintf (mqtt_payload, 100, "{ \"type\":\"Point\", \"coordinates\":[ %lf, %lf\n]}", longitude, latitude);

But i guess the Create Statement won’t work over MQTT.

If you are using e.g. an ESP, you can use the x509 registration. like Pierre already mentioned in the Auto Provisioning guide.

It’s like Rick said, there is no create implementation for MQTT.
I had to do this one over HTTP and then I use MQTT.