JetLinks物聯網基礎平臺-設備消息協議解析SDK

設備消息協議解析SDK

平臺封裝了網絡通信,但是具體的數據由消息協議進行解析.協議(ProtocolSupport)主要由認證器(Authenticator),
消息編解碼器(DeviceMessageCodec),消息發送攔截器(DeviceMessageSenderInterceptor)以及配置元數據(ConfigMetadata)組成.

認證器

認證器(Authenticator)是用於在收到設備請求(例如MQTT)時,對客戶端進行認證時使用,不同的網絡協議(Transport)使用不同的認證器.

接口定義:

public interface Authenticator {
    Mono<AuthenticationResponse> authenticate(@Nonnull AuthenticationRequest request,
                                              @Nonnull DeviceOperator device);
}

參數AuthenticationRequest爲認證請求參數,不同的網絡類型請求類型也不同,請根據實際情況轉換爲對應的類型,例如:
MqttAuthenticationRequest mqttRequest = (MqttAuthenticationRequest)request;

參數DeviceOperator爲對應的設備操作接口,可通過此接口獲取設備的配置,例如:device.getConfig("mqttUsername").

返回值Mono<AuthenticationResponse>爲認證結果.

例:

   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, "密碼錯誤"));
                        }
                    });
        }

消息編解碼器

用於將平臺統一的消息(Message)設備端能處理的消息(EncodedMessage)進行相互轉換.

接口(DeviceMessageCodec)定義:

  //此編解碼器支持的網絡協議,如: DefaultTransport.MQTT
  Transport getSupportTransport();
  //將平臺發往設備的消息編碼爲設備端對消息
  Publisher<? extends EncodedMessage> encode(MessageEncodeContext context);
  //將設備發往平臺的消息解碼爲平臺統一的消息
  Publisher<? extends Message> decode(MessageDecodeContext context);

編碼: 可以從上下文MessageEncodeContext中獲取當前設備操作接口DeviceOperator以及平臺統一的設備消息Message.根據設備側定義的協議轉換爲對應的EncodedMessage.

tip 注意: 不同的網絡協議需要轉換爲不同的EncodedMessage類型.比如,MQTT需要轉換爲MqttMessage.

大部分情況下:MessageDecodeContext可轉爲FromDeviceMessageContext,可獲取到當前設備的連接會話DeviceSession,通過會話可以直接發送消息到設備.

解碼: 可以從上下文MessageDecodeContext中獲取設備操作接口DeviceOperator以及設備消息EncodedMessage,然後將消息轉換爲平臺統一的消息.

平臺統一消息定義

平臺將設備抽象爲由屬性(property),功能(function),事件(event)組成.
平臺接入設備之前,應該先將設備的屬性``功能``事件設計好.

消息組成

消息主要由deviceId,messageId,headers組成.

deviceId爲設備的唯一標識,messageId爲消息的唯一標識,headers爲消息頭,通常用於對自定義消息處理的行爲,如是否異步消息,
是否分片消息等.

常用的(Headers)[https://github.com/jetlinks/jetlinks-core/blob/master/src/main/java/org/jetlinks/core/message/Headers.java]:

  1. aysnc 是否異步,boolean類型.
  2. timeout 指定超時時間. 毫秒.
  3. frag_msg_id 分片主消息ID,爲下發消息的messageId
  4. frag_num 分片總數
  5. frag_part 當前分片索引
  6. frag_last 是否爲最後一個分片,當無法確定分片數量的時候,可以將分片設置到足夠大,最後一個分片設置:frag_last=true來完成返回.
  7. keepOnline 與DeviceOnlineMessage配合使用,在TCP短鏈接,保持設備一直在線狀態,連接斷開不會設置設備離線.

tip:messageId通常由平臺自動生成,如果設備不支持消息id,可在自定義協議中通過Map的方式來做映射,將設備返回的消息與平臺的messageId進行綁定.

屬性相關消息

  1. 獲取設備屬性(ReadPropertyMessage)對應設備回覆的消息ReadPropertyMessageReply.
  2. 修改設備屬性(WritePropertyMessage)對應設備回覆的消息WritePropertyMessageReply.
  3. 設備上報屬性(ReportPropertyMessage) 由設備上報.

注意:設備回覆的消息是通過messageId進行綁定,messageId應該注意要全局唯一,如果設備無法做到,可以在編解碼時通過添加前綴等方式實現.

消息定義:

ReadPropertyMessage{
    String deviceId; 
    String messageId;
    List<String> properties;//可讀取多個屬性
}

ReadPropertyMessageReply{
    String deviceId;
    String messageId;
    long timestamp;
    boolean success;
    Map<String,Object> properties;//屬性鍵值對
}
WritePropertyMessage{
    String deviceId; 
    String messageId;
    Map<String,Object> properties;
}

WritePropertyMessageReply{
    String deviceId;
    String messageId;
    long timestamp;
    boolean success;
    Map<String,Object> properties; //回覆被修改的屬性最新值
}
ReportPropertyMessage{
    String deviceId;
    String messageId;
    long timestamp;
    Map<String,Object> properties;
}

功能相關消息

調用設備功能到消息(FunctionInvokeMessage)由平臺發往設備,對應到返回消息FunctionInvokeMessageReply.

消息定義:

FunctionInvokeMessage{
    String functionId;//功能標識,在元數據中定義.
    String deviceId;
    String messageId;
    List<FunctionParameter> inputs;//輸入參數
}

FunctionParameter{
    String name;
    Object value;
}

FunctionInvokeMessageReply{
    String deviceId;
    String messageId;
    long timestamp;
    boolean success;
    Object output; //輸出值,需要與元數據定義中的類型一致
}

事件消息

事件消息EventMessage由設備端發往平臺.

消息定義:

EventMessage{
    String event; //事件標識,在元數據中定義
    Object data;  //與元數據中定義的類型一致,如果是對象類型,請轉爲java.util.HashMap,禁止使用自定義類型.
    long timestamp;
}

其他消息

  1. DeviceOnlineMessage 設備上線消息,通常用於網關代理的子設備的上線操作.
  2. DeviceOfflineMessage 設備上線消息,通常用於網關代理的子設備的下線操作.
  3. ChildrenDeviceMessage 子設備消息,通常用於網關代理的子設備的消息.
  4. ChildrenDeviceMessageReply 子設備消息回覆,用於平臺向網關代理的子設備發送消息後設備回覆給平臺的結果.

消息定義:

DeviceOnlineMessage{
    String deviceId;
    long timestamp;
}

DeviceOfflineMessage{
    String deviceId;
    long timestamp;
}

ChildDeviceMessage{
    String deviceId;
    String childDeviceId;
    Message childDeviceMessage; //子設備消息
}

父子設備消息處理請看這裏

消息發送攔截器

使用攔截器可以攔截消息發送和返回的動作,通過修改參數等操作實現自定義邏輯,如: 當設備離線時,將消息緩存到設備配置中,等設備上線時再重發.

DeviceMessageSenderInterceptor{
     //發送前
      Mono<DeviceMessage> preSend(DeviceOperator device, DeviceMessage message);

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

在發送前,可以將參數DeviceMessage轉爲其他消息.

發送後,會將返回結果流Flux<R>傳入,通過對該數據流對操作以實現自定義行爲,如:忽略錯誤等.

配置元數據

配置元數據用於告訴平臺,在使用此協議的時候,需要添加一些自定義配置到設備配置(DeviceOperator.setConfig)中.
在其他地方可以通過DeviceOperator.getConfig獲取這些配置.

例如:

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());
//設置MQTT所需要到配置
 support.addConfigMetadata(DefaultTransport.MQTT, mqttConfig);

完整例子

演示協議

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章