data;
+
+ @JSONField(name = "request_id")
+ private String requestId;
+
+ @Override
+ public String toString() {
+ return JSONObject.toJSONString(this);
+ }
+}
diff --git a/src/main/java/net/javase/onenet/api/DataPointApi.java b/src/main/java/net/javase/onenet/api/DataPointApi.java
new file mode 100644
index 0000000..163936e
--- /dev/null
+++ b/src/main/java/net/javase/onenet/api/DataPointApi.java
@@ -0,0 +1,75 @@
+package net.javase.onenet.api;
+
+import cn.hutool.http.ContentType;
+import cn.hutool.http.Method;
+import net.javase.onenet.config.Config;
+import net.javase.onenet.enums.ApiEnum;
+import net.javase.onenet.enums.SignMethod;
+import net.javase.onenet.model.DataPointQueryModel;
+import net.javase.onenet.model.SyncCmdsModel;
+
+/**
+ * DataPointApi
+ *
+ * 数据流API
+ *
+ * @author Frank
+ */
+public class DataPointApi {
+
+ /**
+ * 查询设备数据点
+ *
+ * @param config {@link Config}
+ * @param model {@link DataPointQueryModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse historyDataPoints(Config config, DataPointQueryModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DATAPOINT_HISTORY.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(model.toMap())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 批量查询产品下设备最新数据点
+ *
+ * @param config {@link Config}
+ * @param model {@link DataPointQueryModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse currentDataPoints(Config config, DataPointQueryModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DATAPOINT_CURRENT.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(model.toMap())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * MQTT命令下发
+ *
+ * @param config {@link Config}
+ * @param model 请求参数对象
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse syncCmds(Config config, SyncCmdsModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DATAPOINT_SYNCCMDS.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .body(model.getArgs())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+}
diff --git a/src/main/java/net/javase/onenet/api/DeviceApi.java b/src/main/java/net/javase/onenet/api/DeviceApi.java
new file mode 100644
index 0000000..300ceac
--- /dev/null
+++ b/src/main/java/net/javase/onenet/api/DeviceApi.java
@@ -0,0 +1,364 @@
+package net.javase.onenet.api;
+
+import cn.hutool.http.ContentType;
+import cn.hutool.http.Method;
+import net.javase.onenet.config.Config;
+import net.javase.onenet.enums.ApiEnum;
+import net.javase.onenet.enums.SignMethod;
+import net.javase.onenet.model.device.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * DeviceApi 设备API
+ *
+ * @author Frank
+ */
+public class DeviceApi {
+
+ /**
+ * 创建设备
+ *
+ * @param config {@link Config}
+ * @param model model
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceCreate(Config config, net.javase.onenet.model.device.DeviceModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_CREATE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .model(model)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 编辑设备
+ *
+ * @param config {@link Config}
+ * @param model model
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceUpdate(Config config, net.javase.onenet.model.device.DeviceModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_UPDATE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .model(model)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备详情
+ *
+ * @param config {@link Config}
+ * @param model model
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceDetail(Config config, DeviceModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_DETAIL.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 删除设备
+ *
+ * @param config {@link Config}
+ * @param model model
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceDelete(Config config, DeviceModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_DELETE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 更新设备sec_key
+ *
+ * @param config {@link Config}
+ * @param model model
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceResetSecKey(Config config, DeviceResetSecKeyModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_REST_SECKEY.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备状态变更记录
+ *
+ * @param config {@link Config}
+ * @param model model
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceStatusHistory(Config config, DeviceStatusHistoryModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_STATUS_HISTORY.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备事件记录查询
+ *
+ * @param config {@link Config}
+ * @param model model
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceEventLog(Config config, DeviceEventLogModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_EVENT_LOG.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备操作记录查询
+ *
+ * @param config {@link Config}
+ * @param model model
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceOperationLog(Config config, DeviceStatusHistoryModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_OPERATION_LOG.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备服务记录查询
+ *
+ * @param config {@link Config}
+ * @param traceId 调用服务后的request_id
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceServiceLog(Config config, String traceId) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("trace_id", traceId);
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_SERVICE_LOG.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(query)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备转移
+ *
+ * @param config {@link Config}
+ * @param model model
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceMove(Config config, DeviceMoveModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_MOVE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+
+ /**
+ * 设备分组列表
+ *
+ * @param config {@link Config}
+ * @param model 请求参数
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceGroupList(Config config, DeviceGroupListModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_GROUP_LIST.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+
+ /**
+ * 设备分组详情
+ *
+ * @param config {@link Config}
+ * @param groupId 分组ID
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceGroupDetail(Config config, String groupId) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("group_id", groupId);
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_GROUP_DETAIL.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(query)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 新建设备分组
+ *
+ * @param config {@link Config}
+ * @param model 请求参数
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceGroupCreate(Config config, DeviceGroupModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_GROUP_CREATE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 编辑设备分组
+ *
+ * @param config {@link Config}
+ * @param model 请求参数
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceGroupUpdate(Config config, DeviceGroupModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_GROUP_UPDATE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 删除设备分组
+ *
+ * @param config {@link Config}
+ * @param groupId 分组ID
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceGroupDelete(Config config, String groupId) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("group_id", groupId);
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_GROUP_DELETE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(query)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备分组-添加设备
+ *
+ * @param config {@link Config}
+ * @param model 请求参数
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceGroupAddDevices(Config config, DeviceGroupOptModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_GROUP_ADD_DEVICES.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+
+ /**
+ * 设备分组-删除设备
+ *
+ * @param config {@link Config}
+ * @param model 请求参数
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceGroupDelDevices(Config config, DeviceGroupOptModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_GROUP_DEL_DEVICES.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备分组-删除设备
+ *
+ * @param config {@link Config}
+ * @param model 请求参数
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceGroupDevices(Config config, DeviceGroupListModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DEVICE_GROUP_DEL_DEVICES.api())
+ .method(Method.GET)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+}
diff --git a/src/main/java/net/javase/onenet/api/NbIotApi.java b/src/main/java/net/javase/onenet/api/NbIotApi.java
new file mode 100644
index 0000000..0b874b0
--- /dev/null
+++ b/src/main/java/net/javase/onenet/api/NbIotApi.java
@@ -0,0 +1,403 @@
+package net.javase.onenet.api;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.ContentType;
+import cn.hutool.http.Method;
+import net.javase.onenet.config.Config;
+import net.javase.onenet.enums.ApiEnum;
+import net.javase.onenet.enums.SignMethod;
+import net.javase.onenet.model.NbInstantModel;
+import net.javase.onenet.model.NbOfflineModel;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * NbIotApi
+ *
+ * @author Frank
+ */
+public class NbIotApi {
+
+ /**
+ * 获取资源列表
+ *
+ * @param config {@link Config}
+ * @param imei nbiot设备的身份码
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse resources(Config config, String imei) {
+ return resources(config, imei, null);
+ }
+
+ /**
+ * 获取资源列表
+ *
+ * @param config {@link Config}
+ * @param imei nbiot设备的身份码
+ * @param objId 设备objectId,根据终端SDK确定
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse resources(Config config, String imei, String objId) {
+ Map query = new HashMap<>();
+ query.put("imei", imei);
+ if (StrUtil.isNotBlank(objId)) {
+ query.put("obj_id", objId);
+ }
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_RESOURCES.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(query)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 即时命令-资源发现
+ *
+ * @param config {@link Config}
+ * @param model {@link NbInstantModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse discover(Config config, NbInstantModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_DISCOVER.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 即时命令-资源订阅
+ *
+ * @param config {@link Config}
+ * @param model {@link NbInstantModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse observe(Config config, NbInstantModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_OBSERVE.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 即时命令-读设备资源
+ *
+ * @param config {@link Config}
+ * @param model {@link NbInstantModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse readResource(Config config, NbInstantModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 即时命令-写设备资源
+ *
+ * @param config {@link Config}
+ * @param model {@link NbInstantModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse writeResource(Config config, NbInstantModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .model(model)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 即时命令-即时命令下发
+ *
+ * @param config {@link Config}
+ * @param model {@link NbInstantModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse execute(Config config, NbInstantModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_EXECUTE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .model(model)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+
+ // 缓存命令
+
+ /**
+ * 缓存命令-读设备资源
+ *
+ * @param config {@link Config}
+ * @param model {@link NbOfflineModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse readOfflineResource(Config config, NbOfflineModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_OFFLINE.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 缓存命令-写设备资源
+ *
+ * @param config {@link Config}
+ * @param model {@link NbOfflineModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse writeOfflineResource(Config config, NbOfflineModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_OFFLINE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 缓存命令下发
+ *
+ * @param config {@link Config}
+ * @param model {@link NbOfflineModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse executeOffline(Config config, NbOfflineModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_OFFLINE_EXECUTE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .model(model)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 查看缓存命令详情
+ *
+ * @param config {@link Config}
+ * @param uuid 缓存命令ID
+ * @param imei nbiot设备的身份码
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse offlineHistory(Config config, String uuid, String imei) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("imei", imei);
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_OFFLINE_HISTORY_UUID.api(uuid))
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(query)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 取消缓存命令
+ *
+ * @param config {@link Config}
+ * @param uuid 缓存命令ID
+ * @param imei nbiot设备的身份码
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse offlineCancel(Config config, String uuid, String imei) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("imei", imei);
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_OFFLINE_CANCEL_UUID.api(uuid))
+ .method(Method.PUT)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(query)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 取消所有未下发缓存命令
+ *
+ * @param config {@link Config}
+ * @param imei nbiot设备的身份码
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse offlineCancelAll(Config config, String imei) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("imei", imei);
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_OFFLINE_CANCEL_ALL.api())
+ .method(Method.PUT)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(query)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 全链路日志查询
+ *
+ * @param config {@link Config}
+ * @param uuid 缓存命令ID
+ * @param imei nbiot设备的身份码
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse offlineHistoryPiecewise(Config config, String uuid, String imei) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("imei", imei);
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_OFFLINE_HISTORY_PIECEWISE.api(uuid))
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(query)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 查看bs_psk
+ *
+ * @param config {@link Config}
+ * @param imei nbiot设备的身份码
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse devicePskQuery(Config config, String imei) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("imei", imei);
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_DEVICE_PSK.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(query)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 更新bs_psk
+ *
+ * @param config {@link Config}
+ * @param imei nbiot设备的身份码
+ * @param key 修改连接引导机的PSK,长度8-16个字节,字母或数字组成
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse devicePskUpdate(Config config, String imei, String key) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("imei", imei);
+ Map body = new HashMap<>((int) ((1 / 0.75f) + 1));
+ body.put("key", key);
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_DEVICE_PSK.api())
+ .method(Method.PUT)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(query)
+ .body(body)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 查看acc_psk
+ *
+ * @param config {@link Config}
+ * @param imei nbiot设备的身份码
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceAccPskQuery(Config config, String imei) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("imei", imei);
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_DEVICE_ACCPSK.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(query)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 新增acc_psk
+ *
+ * @param config {@link Config}
+ * @param imei nbiot设备的身份码
+ * @param key 修改连接引导机的PSK,长度8-16个字节,字母或数字组成
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceAccPskAdd(Config config, String imei, String key) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("imei", imei);
+ Map body = new HashMap<>((int) ((1 / 0.75f) + 1));
+ body.put("key", key);
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_DEVICE_ACCPSK.api())
+ .method(Method.POST)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(query)
+ .body(body)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 更新acc_psk
+ *
+ * @param config {@link Config}
+ * @param imei nbiot设备的身份码
+ * @param key 修改连接引导机的PSK,长度8-16个字节,字母或数字组成
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse deviceAccPskUpdate(Config config, String imei, String key) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("imei", imei);
+ Map body = new HashMap<>((int) ((1 / 0.75f) + 1));
+ body.put("key", key);
+ return ApiRequest.builder()
+ .api(ApiEnum.NBIOT_DEVICE_ACCPSK.api())
+ .method(Method.PUT)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .query(query)
+ .body(body)
+ .build()
+ .send(config.getAccessKey());
+ }
+
+}
diff --git a/src/main/java/net/javase/onenet/api/TSLApi.java b/src/main/java/net/javase/onenet/api/TSLApi.java
new file mode 100644
index 0000000..72a2550
--- /dev/null
+++ b/src/main/java/net/javase/onenet/api/TSLApi.java
@@ -0,0 +1,237 @@
+package net.javase.onenet.api;
+
+import cn.hutool.http.ContentType;
+import cn.hutool.http.Method;
+import net.javase.onenet.config.Config;
+import net.javase.onenet.enums.ApiEnum;
+import net.javase.onenet.enums.SignMethod;
+import net.javase.onenet.model.tsl.ThingModel;
+import net.javase.onenet.model.tsl.ThingQueryHistoryModel;
+import net.javase.onenet.model.tsl.ThingQueryModel;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * TSLApi 物模型API
+ *
+ * @author Frank
+ */
+public class TSLApi {
+
+ /**
+ * 物模型系统功能点列表
+ *
+ * @param config {@link Config}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse querySystemThingModel(Config config) {
+ return ApiRequest.builder()
+ .api(ApiEnum.TSL_QUERY_SYSTEM_THING_MODEL.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 物模型查询
+ *
+ * @param config {@link Config}
+ * @param productId 产品ID
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse queryThingModel(Config config, String productId) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("product_id", productId);
+ return ApiRequest.builder()
+ .api(ApiEnum.QUERY_THING_MODEL.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(query)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设置设备属性
+ *
+ * @param config {@link Config}
+ * @param model 请求参数对象
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse setDeviceProperty(Config config, ThingModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.SET_DEVICE_PROPERTY.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 获取设备属性详情
+ *
+ * @param config {@link Config}
+ * @param model 请求参数对象
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse queryDevicePropertyDetail(Config config, ThingQueryModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.QUERY_DEVICE_PROPERTY_DETAIL.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备属性最新数据查询
+ *
+ * @param config {@link Config}
+ * @param productId 产品ID
+ * @param deviceName 设备名称
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse queryDeviceProperty(Config config,
+ String productId, String deviceName) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("product_id", productId);
+ query.put("device_name", deviceName);
+ return ApiRequest.builder()
+ .api(ApiEnum.QUERY_DEVICE_PROPERTY.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(query)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备属性最新数据查询
+ *
+ * @param config {@link Config}
+ * @param productId 产品ID
+ * @param deviceName 设备名称
+ * @param clazz clazz
+ * @param T
+ * @return T
+ */
+ public static T queryDeviceProperty(Config config, String productId, String deviceName, Class clazz) {
+ Map query = new HashMap<>((int) ((1 / 0.75f) + 1));
+ query.put("product_id", productId);
+ query.put("device_name", deviceName);
+ return ApiRequest.builder()
+ .api(ApiEnum.QUERY_DEVICE_PROPERTY.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(query)
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey(), clazz);
+ }
+
+ /**
+ * 设备属性最新数据查询
+ *
+ * @param config {@link Config}
+ * @param model {@link ThingQueryHistoryModel}
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse queryDevicePropertyHistory(Config config, ThingQueryHistoryModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.QUERY_DEVICE_PROPERTY_HISTORY.api())
+ .method(Method.GET)
+ .signMethod(SignMethod.MD5)
+ .query(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备服务调用
+ *
+ * @param config {@link Config}
+ * @param model 请求参数对象
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse callService(Config config, ThingModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.CALL_SERVICE.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备属性期望设置
+ *
+ * @param config {@link Config}
+ * @param model 请求参数对象
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse setDeviceDesiredProperty(Config config, ThingModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.SET_DEVICE_DESIRED_PROPERTY.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备属性期望查询
+ *
+ * @param config {@link Config}
+ * @param model 请求参数对象
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse queryDeviceDesiredProperty(Config config, ThingQueryModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.QUERY_DEVICE_DESIRED_PROPERTY.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+ /**
+ * 设备属性期望删除
+ *
+ * @param config {@link Config}
+ * @param model 请求参数对象
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse delDeviceDesiredProperty(Config config, ThingModel model) {
+ return ApiRequest.builder()
+ .api(ApiEnum.DELETE_DEVICE_DESIRED_PROPERTY.api())
+ .method(Method.POST)
+ .contentType(ContentType.JSON)
+ .signMethod(SignMethod.MD5)
+ .body(model.toMap())
+ .userid(config.getUserid())
+ .build()
+ .send(config.getAccessKey());
+ }
+
+}
diff --git a/src/main/java/net/javase/onenet/config/Config.java b/src/main/java/net/javase/onenet/config/Config.java
new file mode 100644
index 0000000..de2d2b7
--- /dev/null
+++ b/src/main/java/net/javase/onenet/config/Config.java
@@ -0,0 +1,44 @@
+package net.javase.onenet.config;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Config
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class Config implements Serializable {
+
+ private static final long serialVersionUID = 2864466266722905367L;
+
+ /**
+ * 用户ID
+ */
+ private String userid;
+
+ /**
+ * 用户accessKey
+ */
+ private String accessKey;
+
+ /**
+ * 创建配置对象
+ *
+ * @param userid 用户ID
+ * @param accessKey 用户accessKey
+ * @return {@link Config}
+ */
+ public static Config create(String userid, String accessKey) {
+ return new Config(userid, accessKey);
+ }
+
+}
diff --git a/src/main/java/net/javase/onenet/enums/ApiEnum.java b/src/main/java/net/javase/onenet/enums/ApiEnum.java
new file mode 100644
index 0000000..7f972f3
--- /dev/null
+++ b/src/main/java/net/javase/onenet/enums/ApiEnum.java
@@ -0,0 +1,363 @@
+package net.javase.onenet.enums;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * ApiEnum
+ *
+ * @author Frank
+ */
+@Getter
+@AllArgsConstructor
+public enum ApiEnum {
+
+ // 设备管理
+ /**
+ * 创建设备
+ */
+ DEVICE_CREATE("/device/create"),
+
+ /**
+ * 设备详情
+ */
+ DEVICE_DETAIL("/device/detail"),
+
+ /**
+ * 更新设备
+ */
+ DEVICE_UPDATE("/device/update"),
+
+ /**
+ * 删除设备
+ */
+ DEVICE_DELETE("/device/delete"),
+
+ /**
+ * 重置设备接入鉴权key
+ */
+ DEVICE_REST_SECKEY("/device/reset-seckey"),
+
+ /**
+ * 设备状态历史变更记录
+ */
+ DEVICE_STATUS_HISTORY("/device/status-history"),
+
+ /**
+ * 设备操作记录查询
+ */
+ DEVICE_OPERATION_LOG("/device/operation-log"),
+
+ /**
+ * 设备服务记录查询
+ */
+ DEVICE_SERVICE_LOG("/device/service-log"),
+
+ /**
+ * 设备事件记录查询
+ */
+ DEVICE_EVENT_LOG("/device/event-log"),
+
+ /**
+ * 设备转移
+ */
+ DEVICE_MOVE("/device/movedevice"),
+
+ /**
+ * 设备分组列表
+ */
+ DEVICE_GROUP_LIST("/devicegroup/list"),
+
+ /**
+ * 设备分组详情
+ */
+ DEVICE_GROUP_DETAIL("/devicegroup/detail"),
+
+ /**
+ * 新建设备分组
+ */
+ DEVICE_GROUP_CREATE("/devicegroup/create"),
+
+ /**
+ * 编辑设备分组
+ */
+ DEVICE_GROUP_UPDATE("/devicegroup/update"),
+
+ /**
+ * 删除设备分组
+ */
+ DEVICE_GROUP_DELETE("/devicegroup/delete"),
+
+ /**
+ * 设备分组-添加设备
+ */
+ DEVICE_GROUP_ADD_DEVICES("/devicegroup/add-devices"),
+
+ /**
+ * 设备分组-删除设备
+ */
+ DEVICE_GROUP_DEL_DEVICES("/devicegroup/del-devices"),
+
+ /**
+ * 设备分组-设备列表
+ */
+ DEVICE_GROUP_DEVICES("/devicegroup/devices"),
+
+
+ // 设备文件管理
+ /**
+ * 账户文件列表查询
+ */
+ DEVICE_FILE_LIST("/device/file-list"),
+
+ /**
+ * 设备文件上传
+ */
+ DEVICE_FILE_UPLOAD("/device/file-upload"),
+
+ /**
+ * 设备文件删除
+ */
+ DEVICE_FILE_DELETE("/device/file-delete"),
+
+ /**
+ * 设备文件下载
+ */
+ DEVICE_FILE_DOWNLOAD("/device/file-download"),
+
+ /**
+ * 账户文件存储空间查询
+ */
+ DEVICE_FILE_SPACE("/device/file-space"),
+
+ /**
+ * 设备文件数量查询
+ */
+ DEVICE_FILE_DEVICE_COUNT("/device/file-device-count"),
+
+ // 物模型管理
+ /**
+ * 物模型系统功能点列表
+ */
+ TSL_QUERY_SYSTEM_THING_MODEL("/thingmodel/query-system-thing-model"),
+
+ /**
+ * 物模型查询
+ */
+ QUERY_THING_MODEL("/thingmodel/query-thing-model"),
+
+ /**
+ * 设置设备属性
+ */
+ SET_DEVICE_PROPERTY("/thingmodel/set-device-property"),
+
+ /**
+ * 获取设备属性详情
+ */
+ QUERY_DEVICE_PROPERTY_DETAIL("/thingmodel/query-device-property-detail"),
+
+ /**
+ * 设备属性最新数据查询
+ */
+ QUERY_DEVICE_PROPERTY("/thingmodel/query-device-property"),
+
+ /**
+ * 设备属性记录查询
+ */
+ QUERY_DEVICE_PROPERTY_HISTORY("/thingmodel/query-device-property-history"),
+
+ /**
+ * 设备服务调用
+ */
+ CALL_SERVICE("/thingmodel/call-service"),
+
+ /**
+ * 设备属性期望设置
+ */
+ SET_DEVICE_DESIRED_PROPERTY("/thingmodel/set-device-desired-property"),
+
+ /**
+ * 设备属性期望查询
+ */
+ QUERY_DEVICE_DESIRED_PROPERTY("/thingmodel/query-device-desired-property"),
+
+ /**
+ * 设备属性期望删除
+ */
+ DELETE_DEVICE_DESIRED_PROPERTY("/thingmodel/delete-device-desired-property"),
+
+ // 数据流使用
+ /**
+ * 查询设备数据点
+ */
+ DATAPOINT_HISTORY("/datapoint/history-datapoints"),
+
+ /**
+ * 批量查询产品下设备最新数据点
+ */
+ DATAPOINT_CURRENT("/datapoint/current-datapoints"),
+
+ /**
+ * 设备下发命令
+ */
+ DATAPOINT_SYNCCMDS("/datapoint/synccmds"),
+
+ // LwM2M-即时命令
+
+ /**
+ * 获取资源列表
+ */
+ NBIOT_RESOURCES("/nb-iot/resources"),
+
+ /**
+ * 即时命令-资源发现
+ */
+ NBIOT_DISCOVER("/nb-iot/discover"),
+
+ /**
+ * 即时命令-资源订阅
+ */
+ NBIOT_OBSERVE("/nb-iot/observe"),
+
+ /**
+ * 即时命令-读取/写入 设备资源
+ */
+ NBIOT("/nb-iot"),
+
+ /**
+ * 即时命令-设备命令下发
+ */
+ NBIOT_EXECUTE("/nb-iot/execute"),
+
+ // LwM2M-缓存命令
+
+ /**
+ * 缓存命令- 写入/读取 设备资源
+ */
+ NBIOT_OFFLINE("/nb-iot/offline"),
+
+ /**
+ * 缓存命令-设备命令下发
+ */
+ NBIOT_OFFLINE_EXECUTE("/nb-iot/execute/offline"),
+
+ /**
+ * 缓存命令-查询指定设备缓存命令列表
+ */
+ NBIOT_OFFLINE_HISTORY("/nb-iot/offline/history"),
+
+ /**
+ * 缓存命令-查询指定缓存命令详情
+ */
+ NBIOT_OFFLINE_HISTORY_UUID("/nb-iot/offline/history/{}"),
+
+
+ /**
+ * 缓存命令-取消指定的缓存命令
+ */
+ NBIOT_OFFLINE_CANCEL_UUID("/nb-iot/offline/cancel/{}"),
+
+ /**
+ * 缓存命令-取消设备所有未下发的缓存命令
+ */
+ NBIOT_OFFLINE_CANCEL_ALL("/nb-iot/offline/cancel/all"),
+
+ /**
+ * 缓存命令-全链路日志查询
+ */
+ NBIOT_OFFLINE_HISTORY_PIECEWISE("/nb-iot/offline/history/{}/piecewise"),
+
+ // LwM2M-DTLS
+
+ /**
+ * 查看/更新 指定设备bs_psk信息
+ */
+ NBIOT_DEVICE_PSK("/nb-iot/device/psk"),
+
+ /**
+ * 查看/新增/编辑 指定设备acc_psk信息
+ */
+ NBIOT_DEVICE_ACCPSK("/nb-iot/device/accpsk"),
+
+ // 工业标识管理
+
+ /**
+ * 工业标识管理-设备批量自动注册标识接口
+ */
+ FUSE_IDENTITY_DEVICE("/fuse-identity-device/batch-auto-regist-device-identity"),
+
+ // LBS位置能力
+
+ /**
+ * 基站定位获取最新位置接口
+ */
+ LBS_LATEST_LOCATION("/fuse-lbs/latest-location"),
+
+ /**
+ * 基站定位历史轨迹查询接口
+ */
+ LBS_GET_TRAIL("/fuse-lbs/get-trail"),
+
+ /**
+ * WIFI定位获取最新位置接口
+ */
+ LBS_LATEST_WIFI_LOCATION("/fuse-lbs/latest-wifi-location"),
+
+ /**
+ * WIFI定位历史轨迹查询接口
+ */
+ LBS_GET_WIFI_TRAIL("/fuse-lbs/get-wifi-trail"),
+
+ // OTA南向
+
+ /**
+ * 检测升级任务
+ */
+ OTA_CHECK("/fuse-ota/{}/{}/check"),
+
+ /**
+ * 下载升级包
+ */
+ OTA_DOWNLOAD("/fuse-ota/{}/{}/{}/download"),
+
+ /**
+ * 上报升级状态
+ */
+ OTA_STATUS("/fuse-ota/{}/{}/{}/status"),
+
+ /**
+ * 检测任务状态
+ */
+ OTA_TID_CHECK("/fuse-ota/{}/{}/{}/check"),
+
+ /**
+ * 上报/查看 版本号
+ */
+ OTA_VERSION("/fuse-ota/{}/{}/version"),
+
+ // 语音能力
+
+ /**
+ * 语音通知接口
+ */
+ VOICE_NOTIFY("/fuse-voice/voiceNotify"),
+
+ ;
+
+ /**
+ * api url
+ */
+ private final String url;
+
+ /**
+ * 获取api, 用于处理带占位符url参数的api
+ *
+ * @param params 参数
+ * @return 完整url
+ */
+ public String api(Object... params) {
+ return StrUtil.format(url, params);
+ }
+
+}
diff --git a/src/main/java/net/javase/onenet/enums/OneNetDomain.java b/src/main/java/net/javase/onenet/enums/OneNetDomain.java
new file mode 100644
index 0000000..35c154b
--- /dev/null
+++ b/src/main/java/net/javase/onenet/enums/OneNetDomain.java
@@ -0,0 +1,26 @@
+package net.javase.onenet.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * OneNetDomain
+ *
+ * @author Frank
+ */
+@Getter
+@AllArgsConstructor
+public enum OneNetDomain {
+
+ /**
+ * 新版物联网平台api
+ */
+ IOT_API("https://iot-api.heclouds.com"),
+
+ ;
+
+ /**
+ * domain
+ */
+ private final String domain;
+}
diff --git a/src/main/java/net/javase/onenet/enums/SignMethod.java b/src/main/java/net/javase/onenet/enums/SignMethod.java
new file mode 100644
index 0000000..246df0d
--- /dev/null
+++ b/src/main/java/net/javase/onenet/enums/SignMethod.java
@@ -0,0 +1,26 @@
+package net.javase.onenet.enums;
+
+/**
+ * SignMethod
+ *
+ * @author Frank
+ */
+
+public enum SignMethod {
+
+ /**
+ * SHA1
+ */
+ SHA1,
+
+ /**
+ * MD5
+ */
+ MD5,
+
+ /**
+ * SHA256
+ */
+ SHA256,
+ ;
+}
diff --git a/src/main/java/net/javase/onenet/exception/ApiException.java b/src/main/java/net/javase/onenet/exception/ApiException.java
new file mode 100644
index 0000000..82bdc37
--- /dev/null
+++ b/src/main/java/net/javase/onenet/exception/ApiException.java
@@ -0,0 +1,28 @@
+package net.javase.onenet.exception;
+
+/**
+ * ApiException
+ *
+ * @author Frank
+ */
+public class ApiException extends RuntimeException {
+
+ public ApiException() {
+ }
+
+ public ApiException(String message) {
+ super(message);
+ }
+
+ public ApiException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ApiException(Throwable cause) {
+ super(cause);
+ }
+
+ public ApiException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+}
diff --git a/src/main/java/net/javase/onenet/model/DataPointQueryModel.java b/src/main/java/net/javase/onenet/model/DataPointQueryModel.java
new file mode 100644
index 0000000..e8a0848
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/DataPointQueryModel.java
@@ -0,0 +1,73 @@
+package net.javase.onenet.model;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+/**
+ * DataPointQueryModel
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class DataPointQueryModel extends BaseModel {
+
+ /**
+ * 数据流ID,多个id之间用逗号分开,缺省时取数据流或数据流模板100条为缺省数据流id条件
+ */
+ @ApiParam(name = "datastream_id")
+ private String dataStreamId;
+
+ /**
+ * 产品名称
+ */
+ @ApiParam(name = "product_id")
+ private String productId;
+
+ /**
+ * 设备名称
+ */
+ @ApiParam(name = "device_name")
+ private String deviceName;
+
+ /**
+ * lwm2m协议时传,设备imei
+ */
+ private String imei;
+
+ /**
+ * 提取数据点的开始时间,精确到秒,示例:2015-01-10T08:00:35
+ */
+ private String start;
+
+ /**
+ * 提取数据点的结束时间,精确到秒,示例:2015-01-10T08:00:35
+ */
+ private String end;
+
+ /**
+ * 查询时间区间,单位为秒
+ */
+ private Integer duration;
+
+ /**
+ * 限定本次请求最多返回的数据点数,默认100,范围为(0,6000]
+ */
+ private Integer limit;
+
+ /**
+ * 指定本次请求继续从cursor位置开始提取数据
+ */
+ private String cursor;
+
+ /**
+ * 时间排序方式,DESC:倒序,ASC:升序,默认为DESC
+ */
+ private String sort;
+
+
+}
diff --git a/src/main/java/net/javase/onenet/model/NbInstantModel.java b/src/main/java/net/javase/onenet/model/NbInstantModel.java
new file mode 100644
index 0000000..13f0563
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/NbInstantModel.java
@@ -0,0 +1,103 @@
+package net.javase.onenet.model;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+import java.util.Map;
+
+/**
+ * NbInstantModel
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class NbInstantModel extends BaseModel {
+
+ /**
+ * nbiot设备的身份码,必填
+ */
+ @ApiParam(isQuery = true)
+ private String imei;
+
+ /**
+ * true为取消订阅,false为订阅,必填
+ */
+ @ApiParam(isQuery = true)
+ private Boolean cancel;
+
+ /**
+ * nbiot设备的object id , 对应到平台模型中为数据流id,必填
+ */
+ @ApiParam(name = "obj_id", isQuery = true)
+ private Integer objId;
+
+ /**
+ * 设备object下具体一个instance的id ,对应到平台模型中数据点key值的一部分,选填
+ */
+ @ApiParam(name = "obj_inst_id", isQuery = true)
+ private Integer objInstId;
+
+ /**
+ * nbiot设备的资源id,选填
+ */
+ @ApiParam(name = "res_id", isQuery = true)
+ private Integer resId;
+
+ /**
+ * 上传数据的最小时间间隔,默认为0,此时有数据就上传
+ */
+ @ApiParam(isQuery = true)
+ private Integer pmin;
+
+ /**
+ * 上传数据的最大时间间隔
+ */
+ @ApiParam(isQuery = true)
+ private Integer pmax;
+
+ /**
+ * 当数据值大于该值时上传
+ */
+ @ApiParam(isQuery = true)
+ private Double gt;
+
+ /**
+ * 当数据值小于该值时上传
+ */
+ @ApiParam(isQuery = true)
+ private Double lt;
+
+ /**
+ * 当前后两个数据点值相差大于或者等于该值时
+ */
+ @ApiParam(isQuery = true)
+ private Double st;
+
+ /**
+ * 超时时间,可选,默认25秒,取值范围[5,40]
+ */
+ @ApiParam(isQuery = true)
+ private Integer timeout;
+
+ /**
+ * write模式,只能为1或者2
+ */
+ @ApiParam(isQuery = true)
+ private Integer mode;
+
+ /**
+ * 写设备资源的json数组,通过HTTP BODY提交,大小限制2k
+ */
+ private Map data;
+
+ /**
+ * 命令字符串,大小限制2KB
+ */
+ private String args;
+
+}
diff --git a/src/main/java/net/javase/onenet/model/NbOfflineModel.java b/src/main/java/net/javase/onenet/model/NbOfflineModel.java
new file mode 100644
index 0000000..3b4e497
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/NbOfflineModel.java
@@ -0,0 +1,97 @@
+package net.javase.onenet.model;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+import java.util.Map;
+
+/**
+ * NbOfflineModel 缓存命令
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class NbOfflineModel extends BaseModel {
+
+ /**
+ * nbiot设备的身份码,必填
+ */
+ @ApiParam(isQuery = true)
+ private String imei;
+
+ /**
+ * nbiot设备的object id , 对应到平台模型中为数据流id,必填
+ */
+ @ApiParam(name = "obj_id", isQuery = true)
+ private Integer objId;
+
+ /**
+ * 设备object下具体一个instance的id ,对应到平台模型中数据点key值的一部分,选填
+ */
+ @ApiParam(name = "obj_inst_id", isQuery = true)
+ private Integer objInstId;
+
+ /**
+ * nbiot设备的资源id,选填
+ */
+ @ApiParam(name = "res_id", isQuery = true)
+ private Integer resId;
+
+ /**
+ * 1:直接替换;2:局部更新
+ */
+ @ApiParam(isQuery = true)
+ private Integer mode;
+
+ /**
+ * 命令开始生效时间,可选(不填时默认为OneNET当前时间),填写必须大于OneNET服务器的当前时间
+ */
+ @ApiParam(name = "valid_time", isQuery = true)
+ private String validTime;
+
+ /**
+ * 命令过期时间,必须大于valid_time
+ */
+ @ApiParam(name = "expired_time", isQuery = true)
+ private String expiredTime;
+
+ /**
+ * 表示失败重试次数(等待下一次设备update或者上线),可选(不填时默认为3),填写时必须在[0, 10]之间
+ */
+ @ApiParam(isQuery = true)
+ private Integer retry;
+
+ /**
+ * 命令触发的上行消息类型,填写时必须在[1,7]之间;不填写默认为7
+ */
+ @ApiParam(name = "trigger_msg", isQuery = true)
+ private Integer triggerMsg;
+
+ /**
+ * 命令触发的上行消息类型,填写时必须在[1,7]之间;不填写默认为7
+ */
+ @ApiParam(isQuery = true)
+ private Boolean bin2hex;
+
+ /**
+ * true/false,默认false,如果bin2hex为true,资源类型为Opaque的值将被转换成十六进制字符串返回
+ */
+ @ApiParam(isQuery = true)
+ private Integer timeout;
+
+ /**
+ * 写设备资源的json,大小限制2k
+ */
+ private Map data;
+
+ /**
+ * 命令字符串,大小限制2KB
+ */
+ private String args;
+
+}
diff --git a/src/main/java/net/javase/onenet/model/SyncCmdsModel.java b/src/main/java/net/javase/onenet/model/SyncCmdsModel.java
new file mode 100644
index 0000000..771baea
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/SyncCmdsModel.java
@@ -0,0 +1,43 @@
+package net.javase.onenet.model;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+import java.util.Map;
+
+/**
+ * SyncCmdsModel
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class SyncCmdsModel extends BaseModel {
+
+ /**
+ * 产品名称
+ */
+ @ApiParam(name = "product_id")
+ private String productId;
+
+ /**
+ * 设备名称
+ */
+ @ApiParam(name = "device_name")
+ private String deviceName;
+
+ /**
+ * 同步API最长等待时间,取值范围 5-30, 单位秒
+ */
+ private String timeout;
+
+ /**
+ * 命令字符串,大小限制20KB
+ */
+ @ApiParam(ignore = true)
+ private Map args;
+}
diff --git a/src/main/java/net/javase/onenet/model/base/BaseModel.java b/src/main/java/net/javase/onenet/model/base/BaseModel.java
new file mode 100644
index 0000000..0a5f2d2
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/base/BaseModel.java
@@ -0,0 +1,98 @@
+package net.javase.onenet.model.base;
+
+import cn.hutool.core.util.StrUtil;
+import net.javase.onenet.annotation.ApiParam;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * BaseModel
+ *
+ * @author Frank
+ */
+public class BaseModel {
+
+ /**
+ * This To Map
+ *
+ * @return {@link Map}
+ */
+ public Map toMap() {
+ Map map = new HashMap<>();
+ Field[] fields = this.getClass().getDeclaredFields();
+ for (Field field : fields) {
+ Object obj;
+ try {
+ field.setAccessible(true);
+ obj = field.get(this);
+ if (obj != null) {
+ ApiParam apiParam = field.getAnnotation(ApiParam.class);
+ if (apiParam != null) {
+ if (apiParam.ignore()) {
+ continue;
+ }
+ if (StrUtil.isNotBlank(apiParam.name())) {
+ map.put(apiParam.name(), obj);
+ continue;
+ }
+ }
+ map.put(field.getName(), obj);
+ }
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ return map;
+ }
+
+ /**
+ * 获取参数map
+ *
+ * @return Map
+ */
+ public Map> paramsMap() {
+ Map> params = new HashMap<>((int) ((2 / 0.75f) + 1));
+ Map bodyMap = new HashMap<>();
+ Map queryMap = new HashMap<>();
+ Field[] fields = this.getClass().getDeclaredFields();
+ for (Field field : fields) {
+ Object obj;
+ try {
+ field.setAccessible(true);
+ obj = field.get(this);
+ if (obj != null) {
+ ApiParam apiParam = field.getAnnotation(ApiParam.class);
+ if (apiParam != null) {
+ if (apiParam.ignore()) {
+ continue;
+ }
+ if (StrUtil.isNotBlank(apiParam.name())) {
+ if (apiParam.isQuery()) {
+ queryMap.put(apiParam.name(), obj);
+ } else {
+ bodyMap.put(apiParam.name(), obj);
+ }
+ } else {
+ if (apiParam.isQuery()) {
+ queryMap.put(field.getName(), obj);
+ } else {
+ bodyMap.put(field.getName(), obj);
+ }
+ }
+ } else {
+ bodyMap.put(field.getName(), obj);
+ }
+ }
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ params.put("body", bodyMap);
+ params.put("query", queryMap);
+ return params;
+ }
+
+
+}
diff --git a/src/main/java/net/javase/onenet/model/device/DeviceEventLogModel.java b/src/main/java/net/javase/onenet/model/device/DeviceEventLogModel.java
new file mode 100644
index 0000000..aa65132
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/device/DeviceEventLogModel.java
@@ -0,0 +1,73 @@
+package net.javase.onenet.model.device;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+/**
+ * DeviceEventLogModel 设备事件记录查询
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class DeviceEventLogModel extends BaseModel {
+
+ /**
+ * 产品ID
+ */
+ @ApiParam(name = "product_id")
+ protected String productId;
+
+ /**
+ * 设备名称
+ */
+ @ApiParam(name = "device_name")
+ protected String deviceName;
+
+ /**
+ * 设备imei (当设备来自于老平台下NB套件产品时,imei必填,且device_name应当为空)
+ */
+ protected String imei;
+
+ /**
+ * 查询起始时间-毫秒时间戳
+ */
+ @ApiParam(name = "start_time", isQuery = true)
+ private String startTime;
+
+ /**
+ * 查询截止时间-毫秒时间戳
+ */
+ @ApiParam(name = "end_time", isQuery = true)
+ private String endTime;
+
+ /**
+ * 事件功能点标识
+ */
+ @ApiParam(isQuery = true)
+ private String identifier;
+
+ /**
+ * 事件类型,1-信息,2-告警,3-故障
+ */
+ @ApiParam(name = "event_type", isQuery = true)
+ private Integer eventType;
+
+ /**
+ * 请求起始位置,默认0
+ */
+ @ApiParam(isQuery = true)
+ private Integer offset;
+
+ /**
+ * 每次请求记录数,默认10,范围[1,100]
+ */
+ @ApiParam(isQuery = true)
+ private Integer limit;
+
+}
diff --git a/src/main/java/net/javase/onenet/model/device/DeviceGroupListModel.java b/src/main/java/net/javase/onenet/model/device/DeviceGroupListModel.java
new file mode 100644
index 0000000..25e1ccc
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/device/DeviceGroupListModel.java
@@ -0,0 +1,53 @@
+package net.javase.onenet.model.device;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+/**
+ * DeviceGroupListModel
+ *
+ * 设备分组列表
+ * 设备分组-设备列表
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class DeviceGroupListModel extends BaseModel {
+
+ /**
+ * 分组名称,从左模糊匹配
+ */
+ private String name;
+
+ /**
+ * 设备分组标签key,必须与value一起出现,否则无效
+ */
+ private String key;
+
+ /**
+ * 设备分组标签value,必须与key一起出现,否则无效
+ */
+ private String value;
+
+ /**
+ * 分组ID
+ */
+ @ApiParam(name = "group_id")
+ private String groupId;
+
+ /**
+ * 请求起始位置,默认0
+ */
+ private String offset;
+
+ /**
+ * 每次请求记录数,默认10,范围[1,100]
+ */
+ private String limit;
+
+}
diff --git a/src/main/java/net/javase/onenet/model/device/DeviceGroupModel.java b/src/main/java/net/javase/onenet/model/device/DeviceGroupModel.java
new file mode 100644
index 0000000..8b544d7
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/device/DeviceGroupModel.java
@@ -0,0 +1,43 @@
+package net.javase.onenet.model.device;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+import java.util.Map;
+
+/**
+ * DeviceGroupModel
+ * 新建设备分组和编辑设备分组
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class DeviceGroupModel extends BaseModel {
+
+ /**
+ * 分组ID, 编辑时必传
+ */
+ @ApiParam(name = "group_id")
+ private String groupId;
+
+ /**
+ * 分组名称,由中英文、数字、短横线-、下划线_组成,开头首位必须是中英文,长度不超过64位
+ */
+ private String name;
+
+ /**
+ * 分组描述,长度不超过100位
+ */
+ private String desc;
+
+ /**
+ * 分组标签,格式为字典,字典key只能为1-16位英文数字,value长度不超过50
+ */
+ private Map tags;
+
+}
diff --git a/src/main/java/net/javase/onenet/model/device/DeviceGroupOptModel.java b/src/main/java/net/javase/onenet/model/device/DeviceGroupOptModel.java
new file mode 100644
index 0000000..36f3a00
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/device/DeviceGroupOptModel.java
@@ -0,0 +1,40 @@
+package net.javase.onenet.model.device;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+/**
+ * DeviceGroupModel
+ *
+ * 设备分组-添加和删除设备
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class DeviceGroupOptModel extends BaseModel {
+
+ /**
+ * 分组ID
+ */
+ @ApiParam(name = "group_id")
+ private String groupId;
+
+ /**
+ * 产品ID
+ */
+ @ApiParam(name = "product_id")
+ private String productId;
+
+ /**
+ * 设备名称列表
+ */
+ @ApiParam(name = "device_name_list")
+ private String[] deviceNameList;
+
+
+}
diff --git a/src/main/java/net/javase/onenet/model/device/DeviceModel.java b/src/main/java/net/javase/onenet/model/device/DeviceModel.java
new file mode 100644
index 0000000..3506088
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/device/DeviceModel.java
@@ -0,0 +1,78 @@
+package net.javase.onenet.model.device;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+import java.util.List;
+
+/**
+ * DeviceModel
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+public class DeviceModel extends BaseModel {
+
+ /**
+ * 产品名称
+ */
+ @ApiParam(name = "product_id")
+ private String productId;
+
+ /**
+ * 设备名称
+ */
+ @ApiParam(name = "device_name")
+ private String deviceName;
+
+ /**
+ * 设备描述
+ */
+ private String desc;
+
+ /**
+ * 经度
+ */
+ private String lon;
+
+ /**
+ * 纬度
+ */
+ private String lat;
+
+ /**
+ * 设备标签,字符串数组
+ */
+ private List tags;
+
+ /**
+ * LwM2M设备专有,当接入协议为LwM2M时必填,15位数字
+ */
+ private String imei;
+
+ /**
+ * LwM2M设备专有,必填,1-15位数字
+ */
+ private String imsi;
+
+ /**
+ * LwM2M设备专有,允许为空,当接入协议为LwM2M时该属性有效,
+ * 格式为英文字母、数字,长度为8-16位,若不传/传空则平台自动生成一个随机字符串作为psk
+ */
+ private String psk;
+
+ /**
+ * LwM2M设备专有,允许为空,格式为英文字母、数字,长度不超过16位
+ */
+ @ApiParam(name = "auth_code")
+ private String authCode;
+
+}
diff --git a/src/main/java/net/javase/onenet/model/device/DeviceMoveModel.java b/src/main/java/net/javase/onenet/model/device/DeviceMoveModel.java
new file mode 100644
index 0000000..193378d
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/device/DeviceMoveModel.java
@@ -0,0 +1,37 @@
+package net.javase.onenet.model.device;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+/**
+ * DeviceMoveModel
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class DeviceMoveModel extends BaseModel {
+
+ /**
+ * 产品ID
+ */
+ @ApiParam(name = "product_id")
+ private String productId;
+
+ /**
+ * 接收人账户,可以是手机号或者用户名
+ */
+ @ApiParam(name = "target_user_tel")
+ private String targetUserTel;
+
+ /**
+ * 被转移设备的名称数组(对于NB设备只能是imei数组),
+ * 如["name_1", "name_2"],每个元素名称最长限制64位,数组元素不超过1000个
+ */
+ @ApiParam(name = "device_name")
+ private String[] deviceName;
+}
diff --git a/src/main/java/net/javase/onenet/model/device/DeviceResetSecKeyModel.java b/src/main/java/net/javase/onenet/model/device/DeviceResetSecKeyModel.java
new file mode 100644
index 0000000..f03cb2c
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/device/DeviceResetSecKeyModel.java
@@ -0,0 +1,43 @@
+package net.javase.onenet.model.device;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+/**
+ * DeviceResetSecKeyModel 更新设备sec_key
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class DeviceResetSecKeyModel extends BaseModel {
+
+ /**
+ * 产品ID
+ */
+ @ApiParam(name = "product_id")
+ protected String productId;
+
+ /**
+ * 设备名称
+ */
+ @ApiParam(name = "device_name")
+ protected String deviceName;
+
+ /**
+ * 设备imei (当设备来自于老平台下NB套件产品时,imei必填,且device_name应当为空)
+ */
+ protected String imei;
+
+ /**
+ * 设备最新sec_key,值格式为base64 encode后的字符串,
+ * 原始内容格式只能包含英文和数字,长度不超过32位,若不传则会随机生成
+ */
+ @ApiParam(name = "sec_key")
+ private String secKey;
+
+}
diff --git a/src/main/java/net/javase/onenet/model/device/DeviceStatusHistoryModel.java b/src/main/java/net/javase/onenet/model/device/DeviceStatusHistoryModel.java
new file mode 100644
index 0000000..df8d23b
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/device/DeviceStatusHistoryModel.java
@@ -0,0 +1,61 @@
+package net.javase.onenet.model.device;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+/**
+ * DeviceStatusHistoryModel 设备状态变更记录
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class DeviceStatusHistoryModel extends BaseModel {
+
+ /**
+ * 产品ID
+ */
+ @ApiParam(name = "product_id")
+ protected String productId;
+
+ /**
+ * 设备名称
+ */
+ @ApiParam(name = "device_name")
+ protected String deviceName;
+
+ /**
+ * 设备imei (当设备来自于老平台下NB套件产品时,imei必填,且device_name应当为空)
+ */
+ protected String imei;
+
+ /**
+ * 查询起始时间-毫秒时间戳
+ */
+ @ApiParam(name = "start_time", isQuery = true)
+ private String startTime;
+
+ /**
+ * 查询截止时间-毫秒时间戳
+ */
+ @ApiParam(name = "end_time", isQuery = true)
+ private String endTime;
+
+ /**
+ * 请求起始位置,默认0
+ */
+ @ApiParam(isQuery = true)
+ private Integer offset;
+
+ /**
+ * 每次请求记录数,默认10,范围[1,100]
+ */
+ @ApiParam(isQuery = true)
+ private Integer limit;
+
+}
diff --git a/src/main/java/net/javase/onenet/model/tsl/ThingModel.java b/src/main/java/net/javase/onenet/model/tsl/ThingModel.java
new file mode 100644
index 0000000..10a3cd6
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/tsl/ThingModel.java
@@ -0,0 +1,52 @@
+package net.javase.onenet.model.tsl;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+import java.util.Map;
+
+/**
+ * ThingModel
+ *
+ * 设置设备属性
+ *
+ * 设备服务调用
+ *
+ * 设备属性期望设置
+ *
+ * 设备属性期望删除
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class ThingModel extends BaseModel {
+
+ /**
+ * 产品名称
+ */
+ @ApiParam(name = "product_id")
+ private String productId;
+
+ /**
+ * 设备名称
+ */
+ @ApiParam(name = "device_name")
+ private String deviceName;
+
+ /**
+ * 属性功能点标识
+ */
+ private String identifier;
+
+ /**
+ * 设置的属性值, 数据格式为json对象,形式为key:value,
+ * key为属性功能点标识, value为属性值,取值符合物模型定义的数据类型和取值范围, 例如{ "switch": true }
+ */
+ private Map params;
+
+}
diff --git a/src/main/java/net/javase/onenet/model/tsl/ThingQueryHistoryModel.java b/src/main/java/net/javase/onenet/model/tsl/ThingQueryHistoryModel.java
new file mode 100644
index 0000000..887eed1
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/tsl/ThingQueryHistoryModel.java
@@ -0,0 +1,62 @@
+package net.javase.onenet.model.tsl;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+/**
+ * ThingQueryHistoryModel
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class ThingQueryHistoryModel extends BaseModel {
+
+ /**
+ * 产品名称
+ */
+ @ApiParam(name = "product_id")
+ private String productId;
+
+ /**
+ * 设备名称
+ */
+ @ApiParam(name = "device_name")
+ private String deviceName;
+
+ /**
+ * 属性功能点标识
+ */
+ private String identifier;
+
+ /**
+ * 查询起始时间-毫秒时间戳
+ */
+ @ApiParam(name = "start_time")
+ private String startTime;
+
+ /**
+ * 查询截止时间-毫秒时间戳
+ */
+ @ApiParam(name = "end_time")
+ private String endTime;
+
+ /**
+ * 排序参数 1-正序 2-倒序 默认倒叙
+ */
+ private String sort;
+
+ /**
+ * 请求起始位置,默认0
+ */
+ private String offset;
+
+ /**
+ * 每次请求记录数,默认10,范围[1,100]
+ */
+ private String limit;
+}
diff --git a/src/main/java/net/javase/onenet/model/tsl/ThingQueryModel.java b/src/main/java/net/javase/onenet/model/tsl/ThingQueryModel.java
new file mode 100644
index 0000000..09f03f6
--- /dev/null
+++ b/src/main/java/net/javase/onenet/model/tsl/ThingQueryModel.java
@@ -0,0 +1,35 @@
+package net.javase.onenet.model.tsl;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import net.javase.onenet.annotation.ApiParam;
+import net.javase.onenet.model.base.BaseModel;
+
+/**
+ * ThingQueryModel
+ *
+ * @author Frank
+ */
+@Getter
+@Setter
+@Builder
+public class ThingQueryModel extends BaseModel {
+
+ /**
+ * 产品名称
+ */
+ @ApiParam(name = "product_id")
+ private String productId;
+
+ /**
+ * 设备名称
+ */
+ @ApiParam(name = "device_name")
+ private String deviceName;
+
+ /**
+ * 功能点标识数组,expample: ["light","model"]
+ */
+ private String[] params;
+}
diff --git a/src/main/java/net/javase/onenet/utils/Kv.java b/src/main/java/net/javase/onenet/utils/Kv.java
new file mode 100644
index 0000000..11a1e7d
--- /dev/null
+++ b/src/main/java/net/javase/onenet/utils/Kv.java
@@ -0,0 +1,31 @@
+package net.javase.onenet.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Kv
+ *
+ * @author Frank
+ */
+public class Kv {
+
+ private Map map;
+
+ public Kv() {
+ this.map = new HashMap<>();
+ }
+
+ public Kv put(K key, V value) {
+ this.map.put(key, value);
+ return this;
+ }
+
+ public Map build() {
+ return this.map;
+ }
+
+ public static Kv create(K key, V value) {
+ return new Kv().put(key, value);
+ }
+}
diff --git a/src/main/java/net/javase/onenet/utils/RequestUtil.java b/src/main/java/net/javase/onenet/utils/RequestUtil.java
new file mode 100644
index 0000000..b701b54
--- /dev/null
+++ b/src/main/java/net/javase/onenet/utils/RequestUtil.java
@@ -0,0 +1,81 @@
+package net.javase.onenet.utils;
+
+import cn.hutool.core.util.URLUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.Method;
+import com.alibaba.fastjson.JSONObject;
+import net.javase.onenet.api.ApiRequest;
+import net.javase.onenet.api.ApiResponse;
+import net.javase.onenet.exception.ApiException;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 请求工具
+ *
+ * @author Frank
+ */
+public class RequestUtil {
+
+ /**
+ * 发送请求
+ *
+ * @param req request
+ * @param accessKey accessKey
+ * @return {@link ApiResponse}
+ */
+ public static ApiResponse doRequest(ApiRequest req, String accessKey) {
+ return doRequest(req, accessKey, ApiResponse.class);
+ }
+
+ /**
+ * 发送请求
+ *
+ * @param req req
+ * @param accessKey accessKey
+ * @param clazz clazz
+ * @param T
+ * @return T
+ */
+ public static T doRequest(ApiRequest req, String accessKey, Class clazz) {
+ Method method = req.getMethod();
+ String url = req.getDomain().getDomain() + req.url();
+ if (req.getQuery() != null && req.getQuery().size() > 0) {
+ String query = URLUtil.buildQuery(req.getQuery(), StandardCharsets.UTF_8);
+ url += "?" + query;
+ }
+ HttpRequest request = HttpRequest.of(url).method(method);
+ if (req.getContentType() != null) {
+ request.contentType(req.getContentType().toString());
+ }
+ if (req.getBody() != null && req.getBody().size() > 0) {
+ request.body(JSONObject.toJSONString(req.getBody()));
+ }
+
+ String expirationTime = String.valueOf((System.currentTimeMillis() / 1000) + 600);
+ String token = SignUtil.assembleToken(req.getVersion(),
+ req.getRes(), expirationTime, req.getSignMethod(), accessKey);
+ request.header("authorization", token);
+ return doRequest(request, clazz);
+ }
+
+
+ /**
+ * 发送请求
+ *
+ * @param request {@link HttpRequest}
+ * @param clazz response class
+ * @param T
+ * @return response
+ */
+ public static T doRequest(HttpRequest request, Class clazz) {
+ try (HttpResponse response = request.execute()) {
+ String body = response.body();
+ System.out.println(body);
+ return JSONObject.parseObject(body, clazz);
+ } catch (Exception ex) {
+ throw new ApiException("请求异常", ex);
+ }
+ }
+}
diff --git a/src/main/java/net/javase/onenet/utils/SignUtil.java b/src/main/java/net/javase/onenet/utils/SignUtil.java
new file mode 100644
index 0000000..498ec18
--- /dev/null
+++ b/src/main/java/net/javase/onenet/utils/SignUtil.java
@@ -0,0 +1,93 @@
+package net.javase.onenet.utils;
+
+import cn.hutool.core.util.URLUtil;
+import net.javase.onenet.enums.SignMethod;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+
+/**
+ * SignUtil 签名工具
+ *
+ * @author Frank
+ */
+public class SignUtil {
+
+ /**
+ * 默认版本号
+ */
+ public static final String DEFAULT_VERSION = "2022-05-01";
+
+ /**
+ * 构建token
+ *
+ * @param version version
+ * @param resourceName resourceName
+ * @param expirationTime expirationTime
+ * @param signMethod signMethod
+ * @param accessKey accessKey
+ * @return token {@link String}
+ */
+ public static String assembleToken(String version,
+ String resourceName,
+ String expirationTime,
+ SignMethod signMethod,
+ String accessKey) {
+ StringBuilder sb = new StringBuilder();
+ String res = URLUtil.encodeAll(resourceName, StandardCharsets.UTF_8);
+ String sign = generatorSignature(version, resourceName, expirationTime, accessKey, signMethod.name().toLowerCase());
+ sb.append("version=").append(version)
+ .append("&res=").append(res)
+ .append("&et=").append(expirationTime)
+ .append("&method=").append(signMethod.name().toLowerCase())
+ .append("&sign=").append(URLUtil.encodeAll(sign, StandardCharsets.UTF_8));
+ return sb.toString();
+ }
+
+ /**
+ * 生成sign
+ *
+ * @param version version
+ * @param resourceName resourceName
+ * @param expirationTime expirationTime
+ * @param accessKey accessKey
+ * @param signatureMethod signatureMethod
+ * @return sign
+ */
+ public static String generatorSignature(String version,
+ String resourceName,
+ String expirationTime,
+ String accessKey,
+ String signatureMethod) {
+ String encryptText = expirationTime + "\n" + signatureMethod + "\n" + resourceName + "\n" + version;
+ byte[] bytes = hmacEncrypt(encryptText, accessKey, signatureMethod);
+ return Base64.getEncoder().encodeToString(bytes);
+ }
+
+ /**
+ * 加密
+ *
+ * @param data data
+ * @param key key
+ * @param signatureMethod signatureMethod
+ * @return 加密后数据
+ */
+ public static byte[] hmacEncrypt(String data, String key, String signatureMethod) {
+ String instanceName = "Hmac" + signatureMethod.toUpperCase();
+ SecretKeySpec secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), instanceName);
+ try {
+ Mac mac = Mac.getInstance(instanceName);
+ mac.init(secretKey);
+ return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("不支持的签名算法", e);
+ } catch (InvalidKeyException e) {
+ throw new RuntimeException("无效秘钥", e);
+ }
+ }
+
+}
diff --git a/src/test/java/net/javase/onenet/test/TestSign.java b/src/test/java/net/javase/onenet/test/TestSign.java
new file mode 100644
index 0000000..d2156e8
--- /dev/null
+++ b/src/test/java/net/javase/onenet/test/TestSign.java
@@ -0,0 +1,47 @@
+package net.javase.onenet.test;
+
+import net.javase.onenet.enums.SignMethod;
+import net.javase.onenet.utils.SignUtil;
+import org.junit.Test;
+
+/**
+ * TestSign sign生成测试
+ *
+ * @author Frank
+ */
+public class TestSign {
+
+ /**
+ * accessKey
+ */
+ static String KEY = "";
+
+ /**
+ * 用户ID
+ */
+ static String USERID = "";
+
+ /**
+ * sign生成
+ */
+ @Test
+ public void testSign() {
+ String resourceName = "userid/" + USERID;
+ String expirationTime = String.valueOf((System.currentTimeMillis() / 1000) + 600);
+ String sign = SignUtil.generatorSignature(SignUtil.DEFAULT_VERSION,
+ resourceName, expirationTime, KEY, SignMethod.MD5.name().toLowerCase());
+ System.out.println(sign);
+ }
+
+ /**
+ * token生成
+ */
+ @Test
+ public void testToken() {
+ String resourceName = "userid/" + USERID;
+ String expirationTime = String.valueOf((System.currentTimeMillis() / 1000) + 600);
+ String token = SignUtil.assembleToken(SignUtil.DEFAULT_VERSION,
+ resourceName, expirationTime, SignMethod.MD5, KEY);
+ System.out.println("authorization: " + token);
+ }
+}