文章

JetLinks 协议开发说明

JetLinks 协议开发说明

协议开发说明

平台封装了网络通信,但是具体的数据由消息协议进行解析.协议(ProtocolSupport)主要由认证器(Authenticator), 消息编解码器(DeviceMessageCodec),消息发送拦截器(DeviceMessageSenderInterceptor)以及配置元数据(ConfigMetadata)组成.

认证器

认证器(Authenticator)是用于在收到设备请求(例如MQTT)时,对客户端进行认证时使用,不同的网络协议(Transport)使用不同的认证器.

接口定义:

```plain text public interface Authenticator { /** * 对指定对设备进行认证 * * @param request 认证请求 * @param device 设备 * @return 认证结果 */ Mono authenticate(@Nonnull AuthenticationRequest request, @Nonnull DeviceOperator device);

1
2
3
4
5
6
7
8
9
10
11
/**
 *  在MQTT服务网关中指定了认证协议时,将调用此方法进行认证。
 *  注意: 认证通过后,需要设置设备ID.{@link AuthenticationResponse#success(String)}
 * @param request  认证请求
 * @param registry 设备注册中心
 * @return 认证结果
 */
default Mono<AuthenticationResponse> authenticate(@Nonnull AuthenticationRequest request,
                                                  @Nonnull DeviceRegistry registry) {
    return Mono.just(AuthenticationResponse.success());
} } ```

参数AuthenticationRequest为认证请求参数,不同的网络类型请求类型也不同,请根据实际情况转换为对应的类型,例如: MqttAuthenticationRequest mqttRequest = (MqttAuthenticationRequest)request;

参数DeviceOperator为对应的设备操作接口,可通过此接口获取设备的配置,例如:device.getConfig(“mqttUsername”).

返回值Mono为认证结果.

例:

```plain text Authenticator mqttAuthenticator = (request, device) -> { MqttAuthenticationRequest mqttRequest = ((MqttAuthenticationRequest) request); return device.getConfigs(“username”, “password”) //获取设备的配置信息,由配置元数据定义,在设备型号中进行配置. .flatMap(values -> { String username = values.getValue(“username”).map(Value::asString).orElse(null); String password = values.getValue(“password”).map(Value::asString).orElse(null); if (mqttRequest.getUsername().equals(username) && mqttRequest.getPassword().equals(password)) { return Mono.just(AuthenticationResponse.success()); } else { return Mono.just(AuthenticationResponse.error(400, “密码错误”)); } }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## 消息编解码器

用于将平台统一的消息(Message)与设备端能处理的消息(EncodedMessage)进行相互转换. 设备网关从网络组件中接收到报文后,会调用对应协议包的消息编解码器进行处理.

接口(DeviceMessageCodec)定义:

```plain text
class DeviceMessageCodec{
  //此编解码器支持的网络协议,如: DefaultTransport.MQTT
  Transport getSupportTransport();
  //将平台发往设备的消息编码为设备端对消息
  Publisher<? extends EncodedMessage> encode(MessageEncodeContext context);
  //将设备发往平台的消息解码为平台统一的消息
  Publisher<? extends Message> decode(MessageDecodeContext context);
}

注意

方法返回值是响应式结果,根据情况返回Mono(单条消息)或者Flux(多条消息).

上下文

编码上下文类结构

```plain text class MessageEncodeContext{ //获取当前设备操作接口,可通过此接口获取对应设备的配置等信息 DeviceOperator getDevice(); //平台下发的指令,具体请查看平台统一设备消息定义 Message getMessage();

1
2
3
4
5
//强制回复设备消息,在http等场景下,通过调用http api下发指令,然后直接调用此方法回复结果即可.
Mono<Void> reply(Publisher<? extends DeviceMessage> replyMessage);

//获取当前会话,需要将MessageEncodeContext强制转换为ToDeviceMessageContext
DeviceSession getSession(); } ```

解码上下文类结构

```plain text class class MessageDecodeContext{ //获取当前设备操作接口,可通过此接口获取对应设备的配置等信息 DeviceOperator getDevice();

1
2
3
//从网络组件中接收到的消息,不同的网络组件消息类型不同,
//使用时根据网络方式强制转换为对应的类型.
EncodedMessage getMessage(); } ```

注意

不同的网络协议需要转换为不同的EncodedMessage类型.比如,MQTT需要转换为MqttMessage.

大部分情况下:MessageDecodeContext可转为FromDeviceMessageContext,可获取到当前设备的连接会话DeviceSession,通过会话可以直接发送消息到设备.

EncodedMessage

从网络组件中接收到的消息,不同的网络组件消息类型不同。 公共方法:

```plain text class EncodedMessage{ //获取原始报文 ByteBuf getPayload(); //报文转为字符串 String payloadAsString(); //报文转为JSON对象 JSONObject payloadAsJson(); //报文转为JSON数组 JSONArray payloadAsJsonArray(); // 报文转为字节数组 byte[] payloadAsBytes() }

1
2
3
4
5
6
7
8
### MQTT消息

```plain text
class MqttMessage extends EncodedMessage{
    String getTopic();
    int getQos();
}

HTTP消息

如果是POST,PUT,PATCH等请求,EncodedMessage.getPayload即为请求体.

```plain text class HttpExchangeMessage{ String getUrl(); String getPath(); HttpMethod getMethod(); MediaType getContentType(); //请求头 List<Header> getHeaders(); //url上的查询参数 Map<String, String> getQueryParameters(); //POST application/x-www-form-urlencoded时的请求参数 Map<String, String> getRequestParam();

1
2
3
4
//响应成功
Mono<Void> ok(String msg);
//响应失败
Mono<Void> error(int status,String msg); } ```

CoAP消息

```plain text CoapExchangeMessage{ String getPath(); CoAP.Code getCode(); List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
### TCP,UDP消息

TCP和UDP 直接操作EncodedMessage中的方法即可

## 消息发送拦截器

使用拦截器可以拦截消息发送和返回的动作,通过修改参数等操作实现自定义逻辑,如: 当设备离线时,将消息缓存到设备配置中,等设备上线时再重发.

```plain text
DeviceMessageSenderInterceptor{
     //发送前
      Mono<DeviceMessage> preSend(DeviceOperator device, DeviceMessage message);

     //发送后
      <R extends DeviceMessage> Flux<R> afterSent(DeviceOperator device, DeviceMessage message, Flux<R> reply);
}

在发送前,可以将参数DeviceMessage转为其他消息.

发送后,会将返回结果流Flux传入,通过对该数据流对操作以实现自定义行为,如:忽略错误等.

配置元数据

配置元数据用于告诉平台,在使用此协议的时候,需要添加一些自定义配置到设备配置(DeviceOperator.setConfig)中. 在其他地方可以通过DeviceOperator.getConfig获取这些配置.

例如:

```plain text CompositeProtocolSupport support = new CompositeProtocolSupport(); support.setId(“demo-v1”); support.setName(“演示协议v1”); support.setDescription(“演示协议”); support.setMetadataCodec(new JetLinksDeviceMetadataCodec()); //固定为JetLinksDeviceMetadataCodec,请勿修改.

DefaultConfigMetadata mqttConfig = new DefaultConfigMetadata( “MQTT认证配置”, “”) .add(“username”, “username”, “MQTT用户名”, new StringType()) .add(“password”, “password”, “MQTT密码”, new PasswordType()) .add(“productKey”, “productKey”, “产品密钥”, new PasswordType(),DeviceConfigScope.product) //只有产品需要配置 ; //设置MQTT所需要到配置 support.addConfigMetadata(DefaultTransport.MQTT, mqttConfig); ```

%23%20%E5%8D%8F%E8%AE%AE%E5%BC%80%E5%8F%91%E8%AF%B4%E6%98%8E%0A%0A%5Btoc%5D%0A%0A%E5%B9%B3%E5%8F%B0%E5%B0%81%E8%A3%85%E4%BA%86%E7%BD%91%E7%BB%9C%E9%80%9A%E4%BF%A1%2C%E4%BD%86%E6%98%AF%E5%85%B7%E4%BD%93%E7%9A%84%E6%95%B0%E6%8D%AE%E7%94%B1%E6%B6%88%E6%81%AF%E5%8D%8F%E8%AE%AE%E8%BF%9B%E8%A1%8C%E8%A7%A3%E6%9E%90.%60%E5%8D%8F%E8%AE%AE(ProtocolSupport)%60%E4%B8%BB%E8%A6%81%E7%94%B1%60%E8%AE%A4%E8%AF%81%E5%99%A8(Authenticator)%60%2C%20%60%E6%B6%88%E6%81%AF%E7%BC%96%E8%A7%A3%E7%A0%81%E5%99%A8(DeviceMessageCodec)%60%2C%60%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E6%8B%A6%E6%88%AA%E5%99%A8(DeviceMessageSenderInterceptor)%60%E4%BB%A5%E5%8F%8A%60%E9%85%8D%E7%BD%AE%E5%85%83%E6%95%B0%E6%8D%AE(ConfigMetadata)%60%E7%BB%84%E6%88%90.%0A%0A%23%23%20%E8%AE%A4%E8%AF%81%E5%99%A8%0A%0A%E8%AE%A4%E8%AF%81%E5%99%A8(Authenticator)%E6%98%AF%E7%94%A8%E4%BA%8E%E5%9C%A8%E6%94%B6%E5%88%B0%E8%AE%BE%E5%A4%87%E8%AF%B7%E6%B1%82(%E4%BE%8B%E5%A6%82MQTT)%E6%97%B6%2C%E5%AF%B9%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%BF%9B%E8%A1%8C%E8%AE%A4%E8%AF%81%E6%97%B6%E4%BD%BF%E7%94%A8%2C%E4%B8%8D%E5%90%8C%E7%9A%84%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE(Transport)%E4%BD%BF%E7%94%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E8%AE%A4%E8%AF%81%E5%99%A8.%0A%0A%E6%8E%A5%E5%8F%A3%E5%AE%9A%E4%B9%89%3A%0A%0A%60%60%60java%0Apublic%20interface%20Authenticator%20%7B%0A%20%20%20%2F%0A%20%20%20%20%20%20%E5%AF%B9%E6%8C%87%E5%AE%9A%E5%AF%B9%E8%AE%BE%E5%A4%87%E8%BF%9B%E8%A1%8C%E8%AE%A4%E8%AF%81%0A%20%20%20%20%20%0A%20%20%20%20%20%20%40param%20request%20%E8%AE%A4%E8%AF%81%E8%AF%B7%E6%B1%82%0A%20%20%20%20%20%20%40param%20device%20%20%E8%AE%BE%E5%A4%87%0A%20%20%20%20%20%20%40return%20%E8%AE%A4%E8%AF%81%E7%BB%93%E6%9E%9C%0A%20%20%20%20%20%2F%0A%20%20%20%20Mono%3CAuthenticationResponse%3E%20authenticate(%40Nonnull%20AuthenticationRequest%20request%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%40Nonnull%20DeviceOperator%20device)%3B%0A%0A%20%20%20%20%2F%0A%20%20%20%20%20%20%20%E5%9C%A8MQTT%E6%9C%8D%E5%8A%A1%E7%BD%91%E5%85%B3%E4%B8%AD%E6%8C%87%E5%AE%9A%E4%BA%86%E8%AE%A4%E8%AF%81%E5%8D%8F%E8%AE%AE%E6%97%B6%2C%E5%B0%86%E8%B0%83%E7%94%A8%E6%AD%A4%E6%96%B9%E6%B3%95%E8%BF%9B%E8%A1%8C%E8%AE%A4%E8%AF%81%E3%80%82%0A%20%20%20%20%20%20%20%E6%B3%A8%E6%84%8F%3A%20%E8%AE%A4%E8%AF%81%E9%80%9A%E8%BF%87%E5%90%8E%2C%E9%9C%80%E8%A6%81%E8%AE%BE%E7%BD%AE%E8%AE%BE%E5%A4%87ID.%7B%40link%20AuthenticationResponse%23success(String)%7D%0A%20%20%20%20%20%20%40param%20request%20%20%E8%AE%A4%E8%AF%81%E8%AF%B7%E6%B1%82%0A%20%20%20%20%20%20%40param%20registry%20%E8%AE%BE%E5%A4%87%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A%20%20%20%20%20%20%40return%20%E8%AE%A4%E8%AF%81%E7%BB%93%E6%9E%9C%0A%20%20%20%20%20%2F%0A%20%20%20%20default%20Mono%3CAuthenticationResponse%3E%20authenticate(%40Nonnull%20AuthenticationRequest%20request%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%40Nonnull%20DeviceRegistry%20registry)%20%7B%0A%20%20%20%20%20%20%20%20return%20Mono.just(AuthenticationResponse.success())%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%E5%8F%82%E6%95%B0%60AuthenticationRequest%60%E4%B8%BA%E8%AE%A4%E8%AF%81%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%2C%E4%B8%8D%E5%90%8C%E7%9A%84%E7%BD%91%E7%BB%9C%E7%B1%BB%E5%9E%8B%E8%AF%B7%E6%B1%82%E7%B1%BB%E5%9E%8B%E4%B9%9F%E4%B8%8D%E5%90%8C%2C%E8%AF%B7%E6%A0%B9%E6%8D%AE%E5%AE%9E%E9%99%85%E6%83%85%E5%86%B5%E8%BD%AC%E6%8D%A2%E4%B8%BA%E5%AF%B9%E5%BA%94%E7%9A%84%E7%B1%BB%E5%9E%8B%2C%E4%BE%8B%E5%A6%82%3A%20%60MqttAuthenticationRequest%20mqttRequest%20%3D%20(MqttAuthenticationRequest)request%3B%60%0A%0A%E5%8F%82%E6%95%B0%60DeviceOperator%60%E4%B8%BA%E5%AF%B9%E5%BA%94%E7%9A%84%E8%AE%BE%E5%A4%87%E6%93%8D%E4%BD%9C%E6%8E%A5%E5%8F%A3%2C%E5%8F%AF%E9%80%9A%E8%BF%87%E6%AD%A4%E6%8E%A5%E5%8F%A3%E8%8E%B7%E5%8F%96%E8%AE%BE%E5%A4%87%E7%9A%84%E9%85%8D%E7%BD%AE%2C%E4%BE%8B%E5%A6%82%3A%60device.getConfig(%22mqttUsername%22)%60.%0A%0A%E8%BF%94%E5%9B%9E%E5%80%BC%60Mono%3CAuthenticationResponse%3E%60%E4%B8%BA%E8%AE%A4%E8%AF%81%E7%BB%93%E6%9E%9C.%0A%0A%E4%BE%8B%3A%0A%0A%60%60%60java%0A%20%20%20Authenticator%20mqttAuthenticator%20%3D%20%20(request%2C%20device)%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20MqttAuthenticationRequest%20mqttRequest%20%3D%20((MqttAuthenticationRequest)%20request)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20device.getConfigs(%22username%22%2C%20%22password%22)%20%2F%2F%E8%8E%B7%E5%8F%96%E8%AE%BE%E5%A4%87%E7%9A%84%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%2C%E7%94%B1%E9%85%8D%E7%BD%AE%E5%85%83%E6%95%B0%E6%8D%AE%E5%AE%9A%E4%B9%89%2C%E5%9C%A8%E8%AE%BE%E5%A4%87%E5%9E%8B%E5%8F%B7%E4%B8%AD%E8%BF%9B%E8%A1%8C%E9%85%8D%E7%BD%AE.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.flatMap(values%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20username%20%3D%20values.getValue(%22username%22).map(Value%3A%3AasString).orElse(null)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20password%20%3D%20values.getValue(%22password%22).map(Value%3A%3AasString).orElse(null)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(mqttRequest.getUsername().equals(username)%20%26%26%20mqttRequest.getPassword().equals(password))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20Mono.just(AuthenticationResponse.success())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20Mono.just(AuthenticationResponse.error(400%2C%20%22%E5%AF%86%E7%A0%81%E9%94%99%E8%AF%AF%22))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%60%60%60%0A%0A%23%23%20%E6%B6%88%E6%81%AF%E7%BC%96%E8%A7%A3%E7%A0%81%E5%99%A8%0A%0A%E7%94%A8%E4%BA%8E%E5%B0%86%E5%B9%B3%E5%8F%B0%60%E7%BB%9F%E4%B8%80%E7%9A%84%E6%B6%88%E6%81%AF(Message)%60%E4%B8%8E%60%E8%AE%BE%E5%A4%87%E7%AB%AF%E8%83%BD%E5%A4%84%E7%90%86%E7%9A%84%E6%B6%88%E6%81%AF(EncodedMessage)%60%E8%BF%9B%E8%A1%8C%E7%9B%B8%E4%BA%92%E8%BD%AC%E6%8D%A2.%20%E8%AE%BE%E5%A4%87%E7%BD%91%E5%85%B3%E4%BB%8E%60%E7%BD%91%E7%BB%9C%E7%BB%84%E4%BB%B6%60%E4%B8%AD%E6%8E%A5%E6%94%B6%E5%88%B0%E6%8A%A5%E6%96%87%E5%90%8E%2C%E4%BC%9A%E8%B0%83%E7%94%A8%E5%AF%B9%E5%BA%94%E5%8D%8F%E8%AE%AE%E5%8C%85%E7%9A%84%E6%B6%88%E6%81%AF%E7%BC%96%E8%A7%A3%E7%A0%81%E5%99%A8%E8%BF%9B%E8%A1%8C%E5%A4%84%E7%90%86.%0A%0A%E6%8E%A5%E5%8F%A3(%60DeviceMessageCodec%60)%E5%AE%9A%E4%B9%89%3A%0A%0A%60%60%60java%0Aclass%20DeviceMessageCodec%7B%0A%20%20%2F%2F%E6%AD%A4%E7%BC%96%E8%A7%A3%E7%A0%81%E5%99%A8%E6%94%AF%E6%8C%81%E7%9A%84%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%2C%E5%A6%82%3A%20DefaultTransport.MQTT%0A%20%20Transport%20getSupportTransport()%3B%0A%20%20%2F%2F%E5%B0%86%E5%B9%B3%E5%8F%B0%E5%8F%91%E5%BE%80%E8%AE%BE%E5%A4%87%E7%9A%84%E6%B6%88%E6%81%AF%E7%BC%96%E7%A0%81%E4%B8%BA%E8%AE%BE%E5%A4%87%E7%AB%AF%E5%AF%B9%E6%B6%88%E6%81%AF%0A%20%20Publisher%3C%3F%20extends%20EncodedMessage%3E%20encode(MessageEncodeContext%20context)%3B%0A%20%20%2F%2F%E5%B0%86%E8%AE%BE%E5%A4%87%E5%8F%91%E5%BE%80%E5%B9%B3%E5%8F%B0%E7%9A%84%E6%B6%88%E6%81%AF%E8%A7%A3%E7%A0%81%E4%B8%BA%E5%B9%B3%E5%8F%B0%E7%BB%9F%E4%B8%80%E7%9A%84%E6%B6%88%E6%81%AF%0A%20%20Publisher%3C%3F%20extends%20Message%3E%20decode(MessageDecodeContext%20context)%3B%0A%7D%0A%60%60%60%0A%0A%E6%B3%A8%E6%84%8F%0A%0A%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E5%80%BC%E6%98%AF%E5%93%8D%E5%BA%94%E5%BC%8F%E7%BB%93%E6%9E%9C%2C%E6%A0%B9%E6%8D%AE%E6%83%85%E5%86%B5%E8%BF%94%E5%9B%9E%60Mono%60(%E5%8D%95%E6%9D%A1%E6%B6%88%E6%81%AF)%E6%88%96%E8%80%85%60Flux%60(%E5%A4%9A%E6%9D%A1%E6%B6%88%E6%81%AF).%0A%0A%23%23%20%E4%B8%8A%E4%B8%8B%E6%96%87%0A%0A%23%23%23%20%E7%BC%96%E7%A0%81%E4%B8%8A%E4%B8%8B%E6%96%87%E7%B1%BB%E7%BB%93%E6%9E%84%0A%0A%60%60%60java%0Aclass%20MessageEncodeContext%7B%0A%20%20%20%20%2F%2F%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E8%AE%BE%E5%A4%87%E6%93%8D%E4%BD%9C%E6%8E%A5%E5%8F%A3%2C%E5%8F%AF%E9%80%9A%E8%BF%87%E6%AD%A4%E6%8E%A5%E5%8F%A3%E8%8E%B7%E5%8F%96%E5%AF%B9%E5%BA%94%E8%AE%BE%E5%A4%87%E7%9A%84%E9%85%8D%E7%BD%AE%E7%AD%89%E4%BF%A1%E6%81%AF%0A%20%20%20%20DeviceOperator%20getDevice()%3B%0A%20%20%20%20%2F%2F%E5%B9%B3%E5%8F%B0%E4%B8%8B%E5%8F%91%E7%9A%84%E6%8C%87%E4%BB%A4%2C%E5%85%B7%E4%BD%93%E8%AF%B7%E6%9F%A5%E7%9C%8B%E5%B9%B3%E5%8F%B0%E7%BB%9F%E4%B8%80%E8%AE%BE%E5%A4%87%E6%B6%88%E6%81%AF%E5%AE%9A%E4%B9%89%0A%20%20%20%20Message%20getMessage()%3B%0A%0A%20%20%20%20%2F%2F%E5%BC%BA%E5%88%B6%E5%9B%9E%E5%A4%8D%E8%AE%BE%E5%A4%87%E6%B6%88%E6%81%AF%2C%E5%9C%A8http%E7%AD%89%E5%9C%BA%E6%99%AF%E4%B8%8B%2C%E9%80%9A%E8%BF%87%E8%B0%83%E7%94%A8http%20api%E4%B8%8B%E5%8F%91%E6%8C%87%E4%BB%A4%2C%E7%84%B6%E5%90%8E%E7%9B%B4%E6%8E%A5%E8%B0%83%E7%94%A8%E6%AD%A4%E6%96%B9%E6%B3%95%E5%9B%9E%E5%A4%8D%E7%BB%93%E6%9E%9C%E5%8D%B3%E5%8F%AF.%0A%20%20%20%20Mono%3CVoid%3E%20reply(Publisher%3C%3F%20extends%20DeviceMessage%3E%20replyMessage)%3B%0A%0A%20%20%20%20%2F%2F%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E4%BC%9A%E8%AF%9D%2C%E9%9C%80%E8%A6%81%E5%B0%86MessageEncodeContext%E5%BC%BA%E5%88%B6%E8%BD%AC%E6%8D%A2%E4%B8%BAToDeviceMessageContext%0A%20%20%20%20DeviceSession%20getSession()%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%20%E8%A7%A3%E7%A0%81%E4%B8%8A%E4%B8%8B%E6%96%87%E7%B1%BB%E7%BB%93%E6%9E%84%0A%0A%60%60%60java%0Aclass%20class%20MessageDecodeContext%7B%0A%20%20%20%20%2F%2F%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E8%AE%BE%E5%A4%87%E6%93%8D%E4%BD%9C%E6%8E%A5%E5%8F%A3%2C%E5%8F%AF%E9%80%9A%E8%BF%87%E6%AD%A4%E6%8E%A5%E5%8F%A3%E8%8E%B7%E5%8F%96%E5%AF%B9%E5%BA%94%E8%AE%BE%E5%A4%87%E7%9A%84%E9%85%8D%E7%BD%AE%E7%AD%89%E4%BF%A1%E6%81%AF%0A%20%20%20%20DeviceOperator%20getDevice()%3B%0A%0A%20%20%20%20%2F%2F%E4%BB%8E%E7%BD%91%E7%BB%9C%E7%BB%84%E4%BB%B6%E4%B8%AD%E6%8E%A5%E6%94%B6%E5%88%B0%E7%9A%84%E6%B6%88%E6%81%AF%2C%E4%B8%8D%E5%90%8C%E7%9A%84%E7%BD%91%E7%BB%9C%E7%BB%84%E4%BB%B6%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B%E4%B8%8D%E5%90%8C%2C%0A%20%20%20%20%2F%2F%E4%BD%BF%E7%94%A8%E6%97%B6%E6%A0%B9%E6%8D%AE%E7%BD%91%E7%BB%9C%E6%96%B9%E5%BC%8F%E5%BC%BA%E5%88%B6%E8%BD%AC%E6%8D%A2%E4%B8%BA%E5%AF%B9%E5%BA%94%E7%9A%84%E7%B1%BB%E5%9E%8B.%0A%20%20%20%20EncodedMessage%20getMessage()%3B%0A%7D%0A%60%60%60%0A%0A%E6%B3%A8%E6%84%8F%0A%0A%E4%B8%8D%E5%90%8C%E7%9A%84%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E9%9C%80%E8%A6%81%E8%BD%AC%E6%8D%A2%E4%B8%BA%E4%B8%8D%E5%90%8C%E7%9A%84%60EncodedMessage%60%E7%B1%BB%E5%9E%8B.%E6%AF%94%E5%A6%82%2CMQTT%E9%9C%80%E8%A6%81%E8%BD%AC%E6%8D%A2%E4%B8%BA%60MqttMessage%60.%0A%0A%E5%A4%A7%E9%83%A8%E5%88%86%E6%83%85%E5%86%B5%E4%B8%8B%3A%60MessageDecodeContext%60%E5%8F%AF%E8%BD%AC%E4%B8%BA%60FromDeviceMessageContext%60%2C%E5%8F%AF%E8%8E%B7%E5%8F%96%E5%88%B0%E5%BD%93%E5%89%8D%E8%AE%BE%E5%A4%87%E7%9A%84%E8%BF%9E%E6%8E%A5%E4%BC%9A%E8%AF%9D%60DeviceSession%60%2C%E9%80%9A%E8%BF%87%E4%BC%9A%E8%AF%9D%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E5%88%B0%E8%AE%BE%E5%A4%87.%0A%0A%23%23%23%20EncodedMessage%0A%0A%E4%BB%8E%E7%BD%91%E7%BB%9C%E7%BB%84%E4%BB%B6%E4%B8%AD%E6%8E%A5%E6%94%B6%E5%88%B0%E7%9A%84%E6%B6%88%E6%81%AF%2C%E4%B8%8D%E5%90%8C%E7%9A%84%E7%BD%91%E7%BB%9C%E7%BB%84%E4%BB%B6%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B%E4%B8%8D%E5%90%8C%E3%80%82%20%E5%85%AC%E5%85%B1%E6%96%B9%E6%B3%95%3A%0A%0A%60%60%60java%0Aclass%20EncodedMessage%7B%0A%20%20%20%20%2F%2F%E8%8E%B7%E5%8F%96%E5%8E%9F%E5%A7%8B%E6%8A%A5%E6%96%87%0A%20%20%20%20ByteBuf%20getPayload()%3B%0A%20%20%20%20%2F%2F%E6%8A%A5%E6%96%87%E8%BD%AC%E4%B8%BA%E5%AD%97%E7%AC%A6%E4%B8%B2%0A%20%20%20%20String%20payloadAsString()%3B%0A%20%20%20%20%2F%2F%E6%8A%A5%E6%96%87%E8%BD%AC%E4%B8%BAJSON%E5%AF%B9%E8%B1%A1%0A%20%20%20%20JSONObject%20payloadAsJson()%3B%0A%20%20%20%20%2F%2F%E6%8A%A5%E6%96%87%E8%BD%AC%E4%B8%BAJSON%E6%95%B0%E7%BB%84%0A%20%20%20%20JSONArray%20payloadAsJsonArray()%3B%0A%20%20%20%20%2F%2F%20%E6%8A%A5%E6%96%87%E8%BD%AC%E4%B8%BA%E5%AD%97%E8%8A%82%E6%95%B0%E7%BB%84%0A%20%20%20%20byte%5B%5D%20payloadAsBytes()%0A%7D%0A%60%60%60%0A%0A%23%23%23%20MQTT%E6%B6%88%E6%81%AF%0A%0A%60%60%60java%0Aclass%20MqttMessage%20extends%20EncodedMessage%7B%0A%20%20%20%20String%20getTopic()%3B%0A%20%20%20%20int%20getQos()%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%20HTTP%E6%B6%88%E6%81%AF%0A%0A%E5%A6%82%E6%9E%9C%E6%98%AF%60POST%60%2C%60PUT%60%2C%60PATCH%60%E7%AD%89%E8%AF%B7%E6%B1%82%2C%60EncodedMessage.getPayload%60%E5%8D%B3%E4%B8%BA%E8%AF%B7%E6%B1%82%E4%BD%93.%0A%0A%60%60%60java%0Aclass%20HttpExchangeMessage%7B%0A%20%20%20%20String%20getUrl()%3B%0A%20%20%20%20String%20getPath()%3B%0A%20%20%20%20HttpMethod%20getMethod()%3B%0A%20%20%20%20MediaType%20getContentType()%3B%0A%20%20%20%20%2F%2F%E8%AF%B7%E6%B1%82%E5%A4%B4%0A%20%20%20%20List%3CHeader%3E%20getHeaders()%3B%0A%20%20%20%20%2F%2Furl%E4%B8%8A%E7%9A%84%E6%9F%A5%E8%AF%A2%E5%8F%82%E6%95%B0%0A%20%20%20%20Map%3CString%2C%20String%3E%20getQueryParameters()%3B%0A%20%20%20%20%2F%2FPOST%20application%2Fx-www-form-urlencoded%E6%97%B6%E7%9A%84%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%0A%20%20%20%20Map%3CString%2C%20String%3E%20getRequestParam()%3B%0A%0A%20%20%20%20%2F%2F%E5%93%8D%E5%BA%94%E6%88%90%E5%8A%9F%0A%20%20%20%20Mono%3CVoid%3E%20ok(String%20msg)%3B%0A%20%20%20%20%2F%2F%E5%93%8D%E5%BA%94%E5%A4%B1%E8%B4%A5%0A%20%20%20%20Mono%3CVoid%3E%20error(int%20status%2CString%20msg)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%20CoAP%E6%B6%88%E6%81%AF%0A%0A%60%60%60java%0ACoapExchangeMessage%7B%0A%20%20%20%20String%20getPath()%3B%0A%20%20%20%20CoAP.Code%20getCode()%3B%0A%20%20%20%20List%3COption%3E%20getOptions()%3B%0A%20%20%20%20%2F%2F%E5%93%8D%E5%BA%94%E8%AF%B7%E6%B1%82%0A%20%20%20%20void%20response(CoapResponseMessage%20message)%3B%0A%20%20%20%20%2F%2Fsince%201.5%20release%0A%20%20%20%20void%20response(CoAP.ResponseCode%20code)%3B%0A%20%20%20%20%2F%2Fsince%201.5%20release%0A%20%20%20%20void%20response(CoAP.ResponseCode%20code%2Cbyte%5B%5D%20body)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%20TCP%2CUDP%E6%B6%88%E6%81%AF%0A%0ATCP%E5%92%8CUDP%20%E7%9B%B4%E6%8E%A5%E6%93%8D%E4%BD%9C%60EncodedMessage%60%E4%B8%AD%E7%9A%84%E6%96%B9%E6%B3%95%E5%8D%B3%E5%8F%AF%0A%0A%23%23%20%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E6%8B%A6%E6%88%AA%E5%99%A8%0A%0A%E4%BD%BF%E7%94%A8%E6%8B%A6%E6%88%AA%E5%99%A8%E5%8F%AF%E4%BB%A5%E6%8B%A6%E6%88%AA%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E5%92%8C%E8%BF%94%E5%9B%9E%E7%9A%84%E5%8A%A8%E4%BD%9C%2C%E9%80%9A%E8%BF%87%E4%BF%AE%E6%94%B9%E5%8F%82%E6%95%B0%E7%AD%89%E6%93%8D%E4%BD%9C%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%AE%9A%E4%B9%89%E9%80%BB%E8%BE%91%2C%E5%A6%82%3A%20%E5%BD%93%E8%AE%BE%E5%A4%87%E7%A6%BB%E7%BA%BF%E6%97%B6%2C%E5%B0%86%E6%B6%88%E6%81%AF%E7%BC%93%E5%AD%98%E5%88%B0%E8%AE%BE%E5%A4%87%E9%85%8D%E7%BD%AE%E4%B8%AD%2C%E7%AD%89%E8%AE%BE%E5%A4%87%E4%B8%8A%E7%BA%BF%E6%97%B6%E5%86%8D%E9%87%8D%E5%8F%91.%0A%0A%60%60%60java%0ADeviceMessageSenderInterceptor%7B%0A%20%20%20%20%20%2F%2F%E5%8F%91%E9%80%81%E5%89%8D%0A%20%20%20%20%20%20Mono%3CDeviceMessage%3E%20preSend(DeviceOperator%20device%2C%20DeviceMessage%20message)%3B%0A%0A%20%20%20%20%20%2F%2F%E5%8F%91%E9%80%81%E5%90%8E%0A%20%20%20%20%20%20%3CR%20extends%20DeviceMessage%3E%20Flux%3CR%3E%20afterSent(DeviceOperator%20device%2C%20DeviceMessage%20message%2C%20Flux%3CR%3E%20reply)%3B%0A%7D%0A%60%60%60%0A%0A%E5%9C%A8%E5%8F%91%E9%80%81%E5%89%8D%2C%E5%8F%AF%E4%BB%A5%E5%B0%86%E5%8F%82%E6%95%B0%60DeviceMessage%60%E8%BD%AC%E4%B8%BA%E5%85%B6%E4%BB%96%E6%B6%88%E6%81%AF.%0A%0A%E5%8F%91%E9%80%81%E5%90%8E%2C%E4%BC%9A%E5%B0%86%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E6%B5%81%60Flux%3CR%3E%60%E4%BC%A0%E5%85%A5%2C%E9%80%9A%E8%BF%87%E5%AF%B9%E8%AF%A5%E6%95%B0%E6%8D%AE%E6%B5%81%E5%AF%B9%E6%93%8D%E4%BD%9C%E4%BB%A5%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%AE%9A%E4%B9%89%E8%A1%8C%E4%B8%BA%2C%E5%A6%82%3A%E5%BF%BD%E7%95%A5%E9%94%99%E8%AF%AF%E7%AD%89.%0A%0A%23%23%20%E9%85%8D%E7%BD%AE%E5%85%83%E6%95%B0%E6%8D%AE%0A%0A%E9%85%8D%E7%BD%AE%E5%85%83%E6%95%B0%E6%8D%AE%E7%94%A8%E4%BA%8E%E5%91%8A%E8%AF%89%E5%B9%B3%E5%8F%B0%2C%E5%9C%A8%E4%BD%BF%E7%94%A8%E6%AD%A4%E5%8D%8F%E8%AE%AE%E7%9A%84%E6%97%B6%E5%80%99%2C%E9%9C%80%E8%A6%81%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%BA%9B%E8%87%AA%E5%AE%9A%E4%B9%89%E9%85%8D%E7%BD%AE%E5%88%B0%E8%AE%BE%E5%A4%87%E9%85%8D%E7%BD%AE(%60DeviceOperator.setConfig%60)%E4%B8%AD.%20%E5%9C%A8%E5%85%B6%E4%BB%96%E5%9C%B0%E6%96%B9%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%60DeviceOperator.getConfig%60%E8%8E%B7%E5%8F%96%E8%BF%99%E4%BA%9B%E9%85%8D%E7%BD%AE.%0A%0A%E4%BE%8B%E5%A6%82%3A%0A%0A%60%60%60java%0ACompositeProtocolSupport%20support%20%3D%20new%20CompositeProtocolSupport()%3B%0Asupport.setId(%22demo-v1%22)%3B%0Asupport.setName(%22%E6%BC%94%E7%A4%BA%E5%8D%8F%E8%AE%AEv1%22)%3B%0Asupport.setDescription(%22%E6%BC%94%E7%A4%BA%E5%8D%8F%E8%AE%AE%22)%3B%0Asupport.setMetadataCodec(new%20JetLinksDeviceMetadataCodec())%3B%20%2F%2F%E5%9B%BA%E5%AE%9A%E4%B8%BAJetLinksDeviceMetadataCodec%2C%E8%AF%B7%E5%8B%BF%E4%BF%AE%E6%94%B9.%0A%0ADefaultConfigMetadata%20mqttConfig%20%3D%20new%20DefaultConfigMetadata(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22MQTT%E8%AE%A4%E8%AF%81%E9%85%8D%E7%BD%AE%22%2C%20%22%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.add(%22username%22%2C%20%22username%22%2C%20%22MQTT%E7%94%A8%E6%88%B7%E5%90%8D%22%2C%20new%20StringType())%0A%20%20%20%20%20%20%20%20%20%20%20%20.add(%22password%22%2C%20%22password%22%2C%20%22MQTT%E5%AF%86%E7%A0%81%22%2C%20new%20PasswordType())%0A%20%20%20%20%20%20%20%20%20%20%20%20.add(%22productKey%22%2C%20%22productKey%22%2C%20%22%E4%BA%A7%E5%93%81%E5%AF%86%E9%92%A5%22%2C%20new%20PasswordType()%2CDeviceConfigScope.product)%20%2F%2F%E5%8F%AA%E6%9C%89%E4%BA%A7%E5%93%81%E9%9C%80%E8%A6%81%E9%85%8D%E7%BD%AE%0A%20%20%20%20%20%20%20%20%20%20%20%20%3B%0A%2F%2F%E8%AE%BE%E7%BD%AEMQTT%E6%89%80%E9%9C%80%E8%A6%81%E5%88%B0%E9%85%8D%E7%BD%AE%0A%20support.addConfigMetadata(DefaultTransport.MQTT%2C%20mqttConfig)%3B%0A%60%60%60%0A%0A

本文由作者按照 CC BY 4.0 进行授权