我是庖丁,<肢解IOT平臺>之物模型

穆書偉發表於2019-04-17

banner

前言

物模型是對裝置在雲端的功能描述,包括裝置的屬性,資料,服務和事件。

物聯網平臺通過定義一種物的描述語言來描述物模型,稱之為 TSL(即 Thing Specification Language),採用JSON格式,您可以根據TSL組裝上報裝置的資料。

最終能達到的效果:

  • 識別JSON中的鍵值內容,預設情況下,Key始終是一個字串,而value可以是String,boolean,double或long。

  • 解析識別JSON字串和JSON陣列型別的字串

  • 解析識別帶有毫秒精度的unix時間戳的JSON字串

效果如下:

我是庖丁,<肢解IOT平臺>之物模型

引入依賴

使用序列化框架GSON對JSON格式的鍵值對進行識別解析,可以通過引入com.google.code.gson來配置關係。

 <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
 </dependency>
複製程式碼

鍵值屬性

KvEntry

KvEntry

KvEntry中提供了獲取鍵值對屬性的基本介面,例如獲取字元屬性的鍵,值和獲取字串,布林型和數字型別的介面方法。BasicKvEntry定義了鍵只能為字串型別,LongDataEntry,BooleanDataEntry,DoubleDataEntry和StringDataEntry分別定義了相應屬性的值。

public interface KvEntry extends Serializable {

    String getKey();

    DataType getDataType();

    Optional<String> getStrValue();

    Optional<Long> getLongValue();

    Optional<Boolean> getBooleanValue();

    Optional<Double> getDoubleValue();

    String getValueAsString();

    Object getValue();

}

複製程式碼

FromDeviceMsg

屬性和上傳資料

通過將來自裝置的訊息根據型別劃分為裝置屬性(AttributesUpdateRequest)和裝置上傳資料(TelemetryUploadRequest),

其中TelemetryUploadRequest包含了Long型的unix時間戳。

Json識別解析

屬性識別解析

屬性識別解析如下,上傳資料解析識別類似

UML 時序圖如下:

AttributesUpdateRequest

public class JsonConverter {

    private static final Gson GSON = new Gson();
    public static final String CAN_T_PARSE_VALUE = "Can't parse value: ";

   //遍歷鍵值屬性,對相應鍵值進行處理
   public static List<KvEntry> parseValues(JsonObject valuesObject) {
        List<KvEntry> result = new ArrayList<>();
        for (Map.Entry<String, JsonElement> valueEntry : valuesObject.entrySet()) {
            JsonElement element = valueEntry.getValue();
            if (element.isJsonPrimitive()) {
                JsonPrimitive value = element.getAsJsonPrimitive();
                //如果值為字串
                if (value.isString()) {
                	//新建StringDataEntry
                    result.add(new StringDataEntry(valueEntry.getKey(), value.getAsString()));
                //如果值為布林型
                } else if (value.isBoolean()) {
                //新建BooleanDataEntry
                    result.add(new BooleanDataEntry(valueEntry.getKey(), value.getAsBoolean()));
                    //如果值為數值型別
                } else if (value.isNumber()) {
                    parseNumericValue(result, valueEntry, value);
                } else {
                    throw new JsonSyntaxException(CAN_T_PARSE_VALUE + value);
                }
            } else {
                throw new JsonSyntaxException(CAN_T_PARSE_VALUE + element);
            }
        }
        return result;
    }
    
    private static void parseNumericValue(List<KvEntry> result, Map.Entry<String, JsonElement> valueEntry, JsonPrimitive value) {
    	//數值轉化為字串型別,並判斷是不是包含".",來判斷是Long,還是Double
        if (value.getAsString().contains(".")) {
            result.add(new DoubleDataEntry(valueEntry.getKey(), value.getAsDouble()));
        } else {
            try {
                long longValue = Long.parseLong(value.getAsString());
                result.add(new LongDataEntry(valueEntry.getKey(), longValue));
            } catch (NumberFormatException e) {
                throw new JsonSyntaxException("Big integer values are not supported!");
            }
        }
    }

    public static AttributesUpdateRequest convertToAttributes(JsonElement element) {
        return convertToAttributes(element, BasicRequest.DEFAULT_REQUEST_ID);
    }

    public static AttributesUpdateRequest convertToAttributes(JsonElement element, int requestId) {
        if (element.isJsonObject()) {
            BasicAttributesUpdateRequest request = new BasicAttributesUpdateRequest(requestId);
            long ts = System.currentTimeMillis();
            //將JSON字串解析為鍵值屬性的集合
            request.add(parseValues(element.getAsJsonObject()).stream().map(kv -> new BaseAttributeKvEntry(kv, ts)).collect(Collectors.toList()));
            return request;
        } else {
            throw new JsonSyntaxException(CAN_T_PARSE_VALUE + element);
        }
    }
}

複製程式碼

執行

準備工作:

​ 安裝Docker

我已經將此工程製作成映象,並上傳到DockerHub上。

原始碼地址IOT-Guide-TSL

  1. 從DockerHub下載sanshengshui/iot-guide-tsl映象
 docker pull sanshengshui/iot-gui-tsl
複製程式碼

​ 2. 後臺執行iot-guide-tsl,並將映象埠80080對映到本機的8080

 docker run -d -p 8080:8080 sanshengshui/iot-guide-tsl
複製程式碼
  1. 利用curl測試介面
curl -v -X POST -d '{"key1":"value1", "key2":true, "key3": 3.0, "key4": 4}' http://localhost:8080/api/v1/tsl --header "Content-Type:application/json"
複製程式碼

相關文章