协议开发说明

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

    接口定义:

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

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

    返回值Mono<AuthenticationResponse>为认证结果.

    例:

    1. Authenticator mqttAuthenticator = (request, device) -> {
    2. MqttAuthenticationRequest mqttRequest = ((MqttAuthenticationRequest) request);
    3. return device.getConfigs("username", "password") //获取设备的配置信息,由配置元数据定义,在设备型号中进行配置.
    4. .flatMap(values -> {
    5. String username = values.getValue("username").map(Value::asString).orElse(null);
    6. String password = values.getValue("password").map(Value::asString).orElse(null);
    7. if (mqttRequest.getUsername().equals(username) && mqttRequest.getPassword().equals(password)) {
    8. return Mono.just(AuthenticationResponse.success());
    9. } else {
    10. return Mono.just(AuthenticationResponse.error(400, "密码错误"));
    11. }
    12. });
    13. }

    消息编解码器

    接口(DeviceMessageCodec)定义:

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

    注意

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

    解码上下文类结构

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

    注意

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

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

    1. class EncodedMessage{
    2. //获取原始报文
    3. ByteBuf getPayload();
    4. //报文转为字符串
    5. String payloadAsString();
    6. //报文转为JSON对象
    7. JSONObject payloadAsJson();
    8. //报文转为JSON数组
    9. JSONArray payloadAsJsonArray();
    10. // 报文转为字节数组
    11. byte[] payloadAsBytes()
    12. }

    MQTT消息

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

    1. class HttpExchangeMessage{
    2. String getUrl();
    3. String getPath();
    4. HttpMethod getMethod();
    5. MediaType getContentType();
    6. //请求头
    7. List<Header> getHeaders();
    8. //url上的查询参数
    9. Map<String, String> getQueryParameters();
    10. //响应成功
    11. Mono<Void> ok(String msg);
    12. //响应失败
    13. Mono<Void> error(int status,String msg);
    14. }

    CoAP消息

    1. CoapExchangeMessage{
    2. String getPath();
    3. CoAP.Code getCode();
    4. List<Option> getOptions();
    5. //响应请求
    6. void response(CoapResponseMessage message);
    7. //since 1.5 release
    8. void response(CoAP.ResponseCode code);
    9. //since 1.5 release
    10. void response(CoAP.ResponseCode code,byte[] body);
    11. }

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

    消息发送拦截器

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

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

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

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

    1. CompositeProtocolSupport support = new CompositeProtocolSupport();
    2. support.setId("demo-v1");
    3. support.setName("演示协议v1");
    4. support.setDescription("演示协议");
    5. support.setMetadataCodec(new JetLinksDeviceMetadataCodec()); //固定为JetLinksDeviceMetadataCodec,请勿修改.
    6. DefaultConfigMetadata mqttConfig = new DefaultConfigMetadata(
    7. "MQTT认证配置"
    8. , "")
    9. .add("username", "username", "MQTT用户名", new StringType())
    10. .add("password", "password", "MQTT密码", new PasswordType())
    11. .add("productKey", "productKey", "产品密钥", new PasswordType(),DeviceConfigScope.product) //只有产品需要配置
    12. ;
    13. support.addConfigMetadata(DefaultTransport.MQTT, mqttConfig);

    完整例子

    演示协议 (opens new window)