MQTT 介绍

MQTT是一种机器对机器(M2M)/“物联网 “连接协议。它被设计为一种极其轻量级的发布/订阅消息传输。它对于需要少量代码占用和/或网络带宽很高的远程地点的连接非常有用。

MQTT 适配器在paho.mqtt.golang上实现,有助于与 MQTT 经纪商进行通信,以与链接设备进行交互。

MQTT 杂谈

数据结构

我们知道,MQTT 是没有固定的结构,所以没有标准的主题命名模式和payload格式。发布者组织数据结构的方式将直接影响到订阅者的使用情况。在社区中,我们总结了两种常见的模式。下面我们来看看。

第一种模式可以命名为属性主题:发布者将属性扁平化为主题,然后将属性的有效载荷发送到对应的主题。它在 Github 上有一个代表:HomieMQTT 公约。

  1. homie/kitchen/$homie -> 4.0
  2. homie/kitchen/$name -> "Living Room"
  3. homie/kitchen/$node -> "light,door"
  4. homie/kitchen/$state -> "ready"
  5. homie/kitchen/light/$name -> "Living room light"
  6. homie/kitchen/light/$type -> "LED"
  7. homie/kitchen/light/$properties -> "switch,gear,parameter_power,parameter_luminance,manufacturer,production_date,service_life"
  8. ...
  9. homie/kitchen/light/switch/$name -> "The switch of light"
  10. homie/kitchen/light/switch/$settable -> "true"
  11. homie/kitchen/light/switch/$datatype -> "boolean"
  12. homie/kitchen/light/switch -> "false"
  13. ...
  14. homie/kitchen/light/parameter_power/$name -> "The power of light"
  15. homie/kitchen/light/parameter_power/$settable -> "false"
  16. homie/kitchen/light/parameter_power/$datatype -> "float"
  17. homie/kitchen/light/parameter_power/$unit -> "watt"
  18. homie/kitchen/light/parameter_power -> "3.0"
  19. ...

Homie 很有意思,它最大的特点就是自发现,也就是订阅者不需要知道数据结构,只需要订阅根主题,然后公约实现客户端就会反映出所有属性,包括名称、描述、值、类型等。但是,属性主题模式会创建很多主题,所以需要一个类似 Homie 的公约来保证标准化和可扩展性。

另一种直接将属性压缩成一个有效载荷的模式可以命名为属性消息。发布者将属性序列化为一种目标格式,如 XML、JSON 或自定义表单,然后将整个序列化结果发送给一个主题。

  1. home/bedroom/light -> {"switch":true,"action":{"gear":"low"},"parameter":{"power":70,"luminance":4900},"production":{"manufacturer":"Rancher Octopus Fake Device","date":"2020-07-09T13:00:00.00Z","serviceLife":"P1Y0M0D"}}

Attributed Message模式减少了 topic 的使用频率,但订阅者需要知道如何在每个主题中反序列化有效载荷,并了解数据的组织结构。更好的方法是在所有主题中使用相同的序列化格式,并引入数据结构的层次描述。例如,如果发布者选择 JSON 作为序列化格式,发布者可以在另一个主题中附加数据结构的JSONschema

  1. home/bedroom/light/$schema -> {"$schema":"http://json-schema.org/draft-04/schema#","type":"object","additionalProperties":true,"properties":{"switch":{"description":"The switch of light","type":"boolean"},"action":{"description":"The action of light","type":"object","additionalProperties":true,"properties":{"gear":{"description":"The gear of power","type":"string"}}},"parameter":{"description":"The parameter of light","type":"object","additionalProperties":true,"properties":{"power":{"description":"The power of light","type":"float"},"luminance":{"description":"The luminance of light","type":"int"}}},"production":{"description":"The production information of light","type":"object","additionalProperties":true,"properties":{"manufacturer":{"description":"The manufacturer of light","type":"string"},"date":{"description":"The production date of light","type":"string"},"serviceLife":{"description":"The service life of light","type":"string"}}}}}

操作

在 MQTT 中,对于数据的pub/sub(pub:发布,sub:订阅)只有两种方式:一是在同一个主题上执行pub/sub,二是将pub/sub分为两个主题。

第一种方式不受欢迎,可能需要在有效载荷中加入操作命令。

  1. home/light -> {"$data":{"on":true,"brightness":4,"power":{"powerDissipation":"10KWH","electricQuantity":19.99}}}
  2. home/light <- {"$set":{"on":false}}
  3. home/light -> {"$set":{"on":false}}

虽然使用声明式管理的系统(如Kubernetes)可以避免上述的命令式操作,但当发布者做了pub时,必须引入一个sub,这在功耗极低的环境下是不可接受的。

  1. home/light -> {"on":true,"brightness":4,"power":{"powerDissipation":"10KWH","electricQuantity":19.99}}
  2. home/light <- {"on":false}
  3. home/light -> {"on":false}

因此,第二种方式会更容易被接受。由于属性已经被扁平化,在属性主题模式下,发布者可以将数据发送到与属性对应的特殊后缀的主题。例如,Homie 更喜欢使用以set结尾的 topic 来接收值的变化。

  1. homie/light/on/$settable -> "true"
  2. homie/light/on -> "true"
  3. homie/light/on/set <- "false"
  4. homie/light/on -> "false"

对于属性消息模式也是如此,期望发布者需要选择只发送修改的属性还是所有属性。

  1. home/light -> {"on":"true","brightness":4,"power":{"dissipation":"10KWH","quantity":19.99}}
  2. home/light/set <- {"on":false}
  3. home/light -> {"on":false}

公约

MQTTDevice 集成了MQTT 插件的配置。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "..."
  15. client:
  16. ...
  17. message:
  18. ...
  19. ...

AttributedTopic 模式

指定pattern: AttributedTopic来与多主题中扁平化属性的设备进行交互。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedTopic"
  15. client:
  16. ...
  17. message:
  18. ...
  19. ...

指定templated topic,用:path关键字来渲染对应属性名的目标主题。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedTopic"
  15. client:
  16. ...
  17. message:
  18. topic: "cattle.io/octopus/home/your/device/:path"
  19. properties:
  20. # subscribes to "cattle.io/octopus/home/your/device/property-a" topic
  21. - name: property-a
  22. type: string

或用path字段说明:path

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedTopic"
  15. client:
  16. ...
  17. message:
  18. topic: "cattle.io/octopus/home/your/device/:path"
  19. properties:
  20. # subscribes to "cattle.io/octopus/home/your/device/property-a" topic
  21. - name: property-a
  22. type: string
  23. # subscribes to "cattle.io/octopus/home/your/device/path/to/property-b" topic
  24. - name: property-b
  25. path: "path/to/property-b"
  26. type: string

将读写属性指定为readOnly: false

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedTopic"
  15. client:
  16. ...
  17. message:
  18. topic: "cattle.io/octopus/home/your/device/:path"
  19. properties:
  20. # subscribes to "cattle.io/octopus/home/your/device/property-a" topic
  21. - name: property-a
  22. type: string
  23. # subscribes to "cattle.io/octopus/home/your/device/path/to/property-b" topic
  24. - name: property-b
  25. path: "path/to/property-b"
  26. type: string
  27. # subscribes to "cattle.io/octopus/home/your/device/property-c" topic
  28. # publishes to "cattle.io/octopus/home/your/device/property-c" topic
  29. - name: property-c
  30. readOnly: false
  31. type: string

改变可写属性,发布到另一个主题。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedTopic"
  15. client:
  16. ...
  17. message:
  18. topic: "cattle.io/octopus/home/your/device/:path/:operator"
  19. operator:
  20. write: "set"
  21. properties:
  22. # subscribes to "cattle.io/octopus/home/your/device/property-a" topic
  23. - name: property-a
  24. type: string
  25. # subscribes to "cattle.io/octopus/home/your/device/path/to/property-b" topic
  26. - name: property-b
  27. path: "path/to/property-b"
  28. type: string
  29. # subscribes to "cattle.io/octopus/home/your/device/property-c" topic
  30. # publishes to "cattle.io/octopus/home/your/device/property-c/set" topic
  31. - name: property-c
  32. readOnly: false
  33. type: string

注意,:operator可以被覆盖。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedTopic"
  15. client:
  16. ...
  17. message:
  18. topic: "cattle.io/octopus/home/your/device/:path/:operator"
  19. operator:
  20. write: "set"
  21. properties:
  22. # subscribes to "cattle.io/octopus/home/your/device/property-a" topic
  23. - name: property-a
  24. type: string
  25. # subscribes to "cattle.io/octopus/home/your/device/path/to/property-b" topic
  26. - name: property-b
  27. path: "path/to/property-b"
  28. type: string
  29. # subscribes to "cattle.io/octopus/home/your/device/property-c" topic
  30. # publishes to "cattle.io/octopus/home/your/device/property-c/update" topic
  31. - name: property-c
  32. readOnly: false
  33. type: string
  34. operator:
  35. write: "update"

AttributedMessage

指定pattern: AttributedMessage与设备交互,将其属性压缩在一个主题中。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedMessage"
  15. client:
  16. ...
  17. message:
  18. ...
  19. ...

:::note AttributedMessage模式目前只支持 JSON 格式的有效载荷内容。 :::

If the JSON of payload content looks as below:

  1. {
  2. "property-a":"value-a",
  3. "property-b":false,
  4. "property-c":{
  5. "c1":"c1",
  6. "c2":[
  7. "c2.1",
  8. "c2.2"
  9. ]
  10. }
  11. }

通过属性name提取内容。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedMessage"
  15. client:
  16. ...
  17. message:
  18. # subscribes to "cattle.io/octopus/home/your/device" topic
  19. topic: "cattle.io/octopus/home/your/device"
  20. properties:
  21. # extracts the content of the corresponding JSONPath: "property-a"
  22. - name: property-a
  23. type: string

或说明重新启动 path参数的JSONPath

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedMessage"
  15. client:
  16. ...
  17. message:
  18. # subscribes to "cattle.io/octopus/home/your/device" topic
  19. topic: "cattle.io/octopus/home/your/device"
  20. properties:
  21. # extracts the content of the corresponding JSONPath: "property-a"
  22. - name: property-a
  23. type: string
  24. # extracts the content of the corresponding JSONPath: "property-c.c1"
  25. - name: c1
  26. path: "property-c.c1"
  27. type: "string"

指定一个readOnly: false'的可写属性。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedMessage"
  15. client:
  16. ...
  17. message:
  18. # subscribes to "cattle.io/octopus/home/your/device" topic
  19. topic: "cattle.io/octopus/home/your/device"
  20. properties:
  21. # extracts the content of the corresponding JSONPath: "property-a"
  22. - name: property-a
  23. type: string
  24. # extracts the content of the corresponding JSONPath: "property-c.c1"
  25. - name: c1
  26. path: "property-c.c1"
  27. type: "string"
  28. # extracts the content of the corresponding JSONPath: "property-b",
  29. # and publishs to "cattle.io/octopus/home/your/device" if indicated the value.
  30. - name: property-b
  31. type: boolean
  32. readOnly: false

更改发布主题:

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. adaptor:
  6. ...
  7. name: adaptors.edge.cattle.io/mqtt
  8. model:
  9. apiVersion: "devices.edge.cattle.io/v1alpha1"
  10. kind: "MQTTDevice"
  11. template:
  12. spec:
  13. protocol:
  14. pattern: "AttributedMessage"
  15. client:
  16. ...
  17. message:
  18. # subscribes to "cattle.io/octopus/home/your/device" topic
  19. topic: "cattle.io/octopus/home/your/device"
  20. operator:
  21. write: "set"
  22. properties:
  23. # extracts the content of the corresponding JSONPath: "property-a"
  24. - name: property-a
  25. type: string
  26. # extracts the content of the corresponding JSONPath: "property-c.c1"
  27. - name: c1
  28. path: "property-c.c1"
  29. type: "string"
  30. # extracts the content of the corresponding JSONPath: "property-b",
  31. # and publishes the '{"property-b":true}' to "cattle.io/octopus/home/your/device/set".
  32. - name: property-b
  33. type: boolean
  34. readOnly: false
  35. value: true

JSONPath

:::note JSONPath 只在AttributedMessage模式下可用。 :::

MQTT 适配器集成了tidwall/gjsontidwall/sjson

对于Read Only属性,path字段可以接受GJSON Path Syntax,这是一种神奇而丰富的路径检索机制。

  1. # given JSON
  2. {
  3. "name": {"first": "Tom", "last": "Anderson"},
  4. "age": 37,
  5. "children": ["Sara","Alex","Jack"],
  6. "fav.movie": "Deer Hunter",
  7. "friends": [
  8. {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
  9. {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
  10. {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
  11. ]
  12. }
  13. # basic retrival
  14. name.last -> "Anderson"
  15. # array retrival
  16. children.0 -> "Sara"
  17. # wildcards
  18. child*.2 -> " Jack"
  19. # queries
  20. friends.#(last=="Murphy").first -> "Dale"

但是,针对Writable属性,path字段只能接受restrictedSJSON Path Syntax

  1. # given JSON
  2. {
  3. "name": {"first": "Tom", "last": "Anderson"},
  4. "age": 37,
  5. "children": ["Sara","Alex","Jack"],
  6. "fav.movie": "Deer Hunter",
  7. "friends": [
  8. {"first": "James", "last": "Murphy"},
  9. {"first": "Roger", "last": "Craig"}
  10. ]
  11. }
  12. # basic patch
  13. name.last <- "Murphy"
  14. # array patch
  15. children.1 <- "Frank"

为了保证一个属性的读写路径一致,MQTT 适配器在Writable属性上阻止了以下路径:

  • children.-1
  • children|@reverse
  • child*.2
  • c?ildren.0
  • friends.#.first

用户案例

试想一下,我们的家用电器是非常智能的,可以主动向 MQTT agent 报告自己的状态信息,然后我们就会用MQTTDevice来连接和获取这些信息。例如,我们的厨房门可以告诉我们它的生产信息,它的关闭状态等等。

  1. cattle.io/octopus/home/status/kitchen/door/state -> open
  2. ...
  3. cattle.io/octopus/home/status/kitchen/door/production_material -> wood

我们可以用 “AttributedTopic “模式定义一个 “MQTTDevice “设备连接来监视我们的厨房门。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. metadata:
  4. namespace: smart-home
  5. name: kitchen-door
  6. spec:
  7. adaptor:
  8. node: kitchen
  9. name: adaptors.edge.cattle.io/mqtt
  10. model:
  11. apiVersion: "devices.edge.cattle.io/v1alpha1"
  12. kind: "MQTTDevice"
  13. template:
  14. spec:
  15. protocol:
  16. pattern: "AttributedTopic"
  17. client:
  18. server: "..."
  19. message:
  20. topic: "cattle.io/octopus/home/status/kitchen/door/:path"
  21. properties:
  22. - name: "state"
  23. type: "string"
  24. ...
  25. - name: "material"
  26. path: "production_material"
  27. type: "string"

在 “AttributedTopic “模式中,每个 “property “都是一个 topic,默认情况下,property 的 “name “可以作为”:path “关键字来呈现 topic,最后得到对应的 topic 来订阅。默认情况下,属性的 “name “可以作为”:path “关键字来呈现该主题,并最终获得相应的主题来订阅。

厨房灯也会将其属性报告给 MQTT agent,让我们可以远程控制厨房灯。

  1. cattle.io/octopus/home/status/kitchen/light/switch -> false
  2. cattle.io/octopus/home/get/kitchen/light/gear -> low
  3. ...
  4. # 打开厨房灯
  5. cattle.io/octopus/home/set/kitchen/light/switch <- true
  6. # 控制厨房灯的亮度
  7. cattle.io/octopus/hom/control/kitchen/light/gear <- mid

我们可以利用MQTTDevice设备链接的可写属性来控制厨房灯。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. metadata:
  4. namespace: smart-home
  5. name: kitchen-light
  6. spec:
  7. adaptor:
  8. node: kitchen
  9. name: adaptors.edge.cattle.io/mqtt
  10. model:
  11. apiVersion: "devices.edge.cattle.io/v1alpha1"
  12. kind: "MQTTDevice"
  13. template:
  14. spec:
  15. protocol:
  16. pattern: "AttributedTopic"
  17. client:
  18. server: "..."
  19. message:
  20. topic: "cattle.io/octopus/home/:operator/kitchen/light/:path"
  21. operator:
  22. read: "status"
  23. write: "set"
  24. properties:
  25. - name: "switch"
  26. type: "boolean"
  27. readOnly: false
  28. - name: "gear"
  29. type: "string"
  30. readOnly: false
  31. operator:
  32. read: "get"
  33. write: "control"
  34. ...

使用 “readOnly: false “来确定一个可写属性。此外,属性级别 “operator “可以覆盖 “AttributedTopic “模式中协议级别的定义。

例如,我们可以打开厨房的灯,将其调整到中等亮度。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. metadata:
  4. namespace: smart-home
  5. name: kitchen-light
  6. spec:
  7. ...
  8. template:
  9. spec:
  10. protocol:
  11. pattern: "AttributedTopic"
  12. client:
  13. server: "..."
  14. message:
  15. topic: "cattle.io/octopus/home/:operator/kitchen/light/:path"
  16. operator:
  17. read: "status"
  18. write: "set"
  19. properties:
  20. - name: "switch"
  21. type: "boolean"
  22. readOnly: false
  23. value: true
  24. - name: "gear"
  25. type: "string"
  26. readOnly: false
  27. operator:
  28. read: "get"
  29. write: "control"
  30. value: "mid"
  31. ...

此外,我们可以在同一个MQTTDevice设备链接中监控门和灯的状态。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. metadata:
  4. namespace: smart-home
  5. name: kitchen-monitor
  6. spec:
  7. adaptor:
  8. node: kitchen
  9. name: adaptors.edge.cattle.io/mqtt
  10. model:
  11. apiVersion: "devices.edge.cattle.io/v1alpha1"
  12. kind: "MQTTDevice"
  13. template:
  14. spec:
  15. protocol:
  16. pattern: "AttributedTopic"
  17. client:
  18. server: "..."
  19. message:
  20. topic: "cattle.io/octopus/home/:operator/kitchen/:path"
  21. operator:
  22. read: status
  23. properties:
  24. - name: "doorState"
  25. path: "door/state"
  26. type: "string"
  27. - name: "isLightOn"
  28. path: "light/switch"
  29. type: "boolean"
  30. - name: "lightGear"
  31. path: "light/gear"
  32. type: "string"
  33. operator:
  34. read: get

最近新买了一盏智能卧室灯,但是发现传输的数据格式和之前的不一样。

  1. cattle.io/octopus/home/bedroom/light -> {"switch":true,"action":{"gear":"low"},"parameter":{"power":70,"luminance":4900},"production":{"manufacturer":"Rancher Octopus Fake Device","date":"2020-07-09T13:00:00.00Z","serviceLife":"P1Y0M0D"}}
  2. # to turn off the bedroom light
  3. cattle.io/octopus/home/bedroom/light/set <- {"switch":false}
  4. # to control the kitchen light
  5. cattle.io/octopus/home/bedroom/light/set <- {"action":{"gear":"mid"}}

我们可以定义一个 “MQTTDevice “设备链接与 “AttributedMessage “模式来监控新的卧室灯。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. metadata:
  4. namespace: smart-home
  5. name: bedroom-light
  6. spec:
  7. adaptor:
  8. node: bedroom
  9. name: adaptors.edge.cattle.io/mqtt
  10. model:
  11. apiVersion: "devices.edge.cattle.io/v1alpha1"
  12. kind: "MQTTDevice"
  13. template:
  14. spec:
  15. protocol:
  16. pattern: "AttributedMessage"
  17. client:
  18. server: "..."
  19. message:
  20. topic: "cattle.io/octopus/home/bedroom/light"
  21. properties:
  22. - name: "switch"
  23. type: "boolean"
  24. - name: "gear"
  25. path: "action.gear"
  26. type: "string"
  27. ...
  28. - name: "serviceLife"
  29. path: "production.serviceLife"
  30. type: "string"

AttributedMessage模式中,整个链接是一个主题。默认情况下,属性的 “name “可以作为 payload 内容的检索路径。

如果需要的话,我们可以修改上面的MQTTDevice设备链接,关闭新卧室的灯。

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. metadata:
  4. namespace: smart-home
  5. name: bedroom-light
  6. spec:
  7. ...
  8. template:
  9. ...
  10. spec:
  11. protocol:
  12. pattern: "AttributedMessage"
  13. client:
  14. server: "..."
  15. message:
  16. topic: "cattle.io/octopus/home/bedroom/light/:operator"
  17. operator:
  18. write: "set"
  19. properties:
  20. - name: "switch"
  21. type: "boolean"
  22. readOnly: false
  23. value: false
  24. - name: "gear"
  25. path: "action.gear"
  26. type: "string"
  27. ...
  28. - name: "serviceLife"
  29. path: "production.serviceLife"
  30. type: "string"

注册信息

版本注册名称端点 Socket是否可用
v1alpha1adaptors.edge.cattle.io/mqttmqtt.sock

支持模板

类型设备组版本是否可用
MQTTDevicedevices.edge.cattle.iov1alpha1

支持的平台

操作系统架构
linuxamd64
linuxarm
linuxarm64

使用方式

  1. kubectl apply -f https://raw.githubusercontent.com/cnrancher/octopus/master/adaptors/mqtt/deploy/e2e/all_in_one.yaml

权限

对 Octopus 授予权限,如下所示:

  1. Resources Non-Resource URLs Resource Names Verbs
  2. --------- ----------------- -------------- -----
  3. mqttdevices.devices.edge.cattle.io [] [] [create delete get list patch update watch]
  4. mqttdevices.devices.edge.cattle.io/status [] [] [get patch update]

YAML 示例

  • 指定 “MQTTDevice “设备链接,订阅厨房房间门的信息。

    1. apiVersion: edge.cattle.io/v1alpha1
    2. kind: DeviceLink
    3. metadata:
    4. name: kitchen-door
    5. spec:
    6. adaptor:
    7. node: edge-worker
    8. name: adaptors.edge.cattle.io/mqtt
    9. model:
    10. apiVersion: "devices.edge.cattle.io/v1alpha1"
    11. kind: "MQTTDevice"
    12. template:
    13. metadata:
    14. labels:
    15. device: kitchen-door
    16. spec:
    17. protocol:
    18. pattern: "AttributedTopic"
    19. client:
    20. server: "tcp://test.mosquitto.org:1883"
    21. message:
    22. topic: "cattle.io/octopus/home/status/kitchen/door/:path"
    23. properties:
    24. - name: "state"
    25. path: "state"
    26. description: "The state of door"
    27. type: "string"
    28. annotations:
    29. type: "enum"
    30. format: "open,close"
    31. - name: "width"
    32. path: "width"
    33. description: "The width of door"
    34. type: "float"
    35. annotations:
    36. unit: "meter"
    37. - name: "height"
    38. path: "height"
    39. description: "The height of door"
    40. type: "float"
    41. annotations:
    42. unit: "meter"
    43. - name: "material"
    44. path: "material"
    45. description: "The material of light"
    46. type: "string"
  • 指定 “MQTTDevice “设备链接,订阅卧室灯的信息。

    1. apiVersion: edge.cattle.io/v1alpha1
    2. kind: DeviceLink
    3. metadata:
    4. name: bedroom-light
    5. spec:
    6. adaptor:
    7. node: edge-worker
    8. name: adaptors.edge.cattle.io/mqtt
    9. model:
    10. apiVersion: "devices.edge.cattle.io/v1alpha1"
    11. kind: "MQTTDevice"
    12. template:
    13. metadata:
    14. labels:
    15. device: bedroom-light
    16. spec:
    17. protocol:
    18. pattern: "AttributedMessage"
    19. client:
    20. server: "tcp://test.mosquitto.org:1883"
    21. message:
    22. topic: "cattle.io/octopus/home/bedroom/light/:operator"
    23. operator:
    24. write: "set"
    25. properties:
    26. - name: "switch"
    27. path: "switch"
    28. description: "The switch of light"
    29. type: "boolean"
    30. readOnly: false
    31. - name: "gear"
    32. path: "action.gear"
    33. description: "The gear of light"
    34. type: "string"
    35. readOnly: false
    36. annotations:
    37. type: "enum"
    38. format: "low,mid,high"
    39. - name: "power"
    40. path: "parameter.power"
    41. description: "The power of light"
    42. type: "float"
    43. annotations:
    44. group: "parameter"
    45. unit: "watt"
    46. - name: "luminance"
    47. path: "parameter.luminance"
    48. description: "The luminance of light"
    49. type: "int"
    50. annotations:
    51. group: "parameter"
    52. unit: "luminance"
    53. - name: "manufacturer"
    54. path: "production.manufacturer"
    55. description: "The manufacturer of light"
    56. type: "string"
    57. annotations:
    58. group: "production"
    59. - name: "productionDate"
    60. path: "production.date"
    61. description: "The production date of light"
    62. type: "string"
    63. annotations:
    64. group: "production"
    65. type: "datetime"
    66. standard: "ISO 8601"
    67. format: "YYYY-MM-DDThh:mm:ss.SSZ"
    68. - name: "serviceLife"
    69. path: "production.serviceLife"
    70. description: "The service life of light"
    71. type: "string"
    72. annotations:
    73. group: "production"
    74. type: "duration"
    75. standard: "ISO 8601"
    76. format: "PYYMMDD"

更多的 “MQTTDevice “设备链接示例,请参考deploy/e2e目录,并使用deploy/e2e/simulator.yaml进行快速体验。

MQTTDevice

参数描述类型是否必填
metadata元数据metav1.ObjectMetafalse
spec定义 “MQTTDevice”的预期状态MQTTDeviceSpec
status定义 “MQTTDevice”的实际状态MQTTDeviceStatus

MQTTDeviceSpec

参数描述类型是否必填
protocol指定访问设备时使用的协议MQTTDeviceProtocol
properties指定设备的属性[]MQTTDeviceProperty

MQTTDeviceStatus

参数描述类型是否必填
properties上报设备的属性[]MQTTDeviceStatusProperty

MQTTDeviceProtocol

参数描述类型是否必填
pattern指定 MQTTDevice 协议的模式MQTTDevicePattern
client指定客户端的设置MQTTClientOptions
message指定消息的设置MQTTMessageOptions

MQTTDevicePattern

参数描述类型
AttributedMessage将属性压缩成一条消息,一个主题有其所有的属性值string
AttributedTopic扁平化属性到主题,每个主题都有自己的属性值string

MQTTDeviceProperty

参数描述类型是否必填
annotations指定属性的注释mapstring]string
name指定属性的名称string
description指定属性的描述string
readOnly指定该属性是否为只读,默认为 “true”*bool
type指定属性的类型MQTTDevicePropertyType
value指定属性的值,只在可写属性中可用MQTTDevicePropertyValue
path指定 topic 的:path关键字的渲染路径,默认与name相同。

AttributedTopic模式下,该路径将呈现在 topic 上;
AttributedMessage模式下,该路径应该是一个JSONPath,可以访问 payload 内容。
string
operator指定用于呈现主题的:operator关键字的操作符。MQTTMessageTopicOperator。
qos指定消息的 QoS,只有在AttributedTopic模式下才有。默认值是1MQTTMessageQoSLevel
retained指定是否保留最后发布的消息,只有在AttributedTopic模式下才有。默认为 “true”。*bool

MQTT 适配器会返回 MQTT broker 接收到的原始数据,因此,”type “的意义并不是告诉 MQTT 适配器如何处理有效载荷,而是让用户描述期望值。因此,”type “的含义不是告诉 MQTT 适配器如何处理有效载荷,而是让用户描述期望的内容。

MQTTDeviceStatusProperty

参数描述类型是否必填
annotations属性的注释map[string]string
name属性的名称string
description属性的描述string
readOnly该属性是否为只读,默认为 “true”bool
type属性的类型MQTTDevicePropertyType
value属性的值,只在可写属性中可用MQTTDevicePropertyValue
pathtopic 的:path关键字的渲染路径,默认与name相同。

AttributedTopic模式下,这个路径将在 topic 上呈现;
AttributedMessage模式下,这个路径应该是一个JSONPath,可以访问 payload 内容
string
operator用于呈现主题的:operator关键字的操作符。MQTTMessageTopicOperator
qos消息的 QoS,只有在AttributedTopic模式下才有。默认值是1MQTTMessageQoSLevel
retained是否保留最后发布的消息,只有在AttributedTopic模式下才有。默认为 “true”。bool

MQTTDevicePropertyType

参数描述类型
string属性数据类型为 stringstring
int属性数据类型为 intstring
float属性数据类型为 floatstring
boolean属性数据类型为 booleanstring
array属性数据类型为 arraystring
object属性数据类型为 objectstring

MQTTDevicePropertyValue

MQTTDevicePropertyValue 需要根据type输入相应的内容。例如:

  1. apiVersion: edge.cattle.io/v1alpha1
  2. kind: DeviceLink
  3. ...
  4. spec:
  5. ...
  6. template:
  7. ...
  8. spec:
  9. ...
  10. properties:
  11. - name: "string"
  12. readOnly: false
  13. type: "string"
  14. value: "str"
  15. - name: "int"
  16. readOnly: false
  17. type: "int"
  18. value: 1
  19. - name: "float"
  20. readOnly: false
  21. type: "float"
  22. value: 3.3
  23. - name: "bool"
  24. readOnly: false
  25. type: "boolean"
  26. value: true
  27. - name: "array"
  28. readOnly: false
  29. type: "array"
  30. value:
  31. - item-1
  32. - item-2
  33. - item-3
  34. - name: "object"
  35. readOnly: false
  36. type: "object"
  37. value:
  38. name: "james"
  39. age: 12