Browse Source

增加tdengine支持

xiwa 3 years ago
parent
commit
19d454697e
71 changed files with 1409 additions and 125 deletions
  1. 1 1
      Dockerfile
  2. BIN
      data/components/3ababc5e-15e9-45a7-8f38-2a6afd45c780/iot-http-biz-component-0.3.2-SNAPSHOT.jar
  3. BIN
      data/components/6c095554-35e7-4e9d-a8d2-bb919e9479f4/iot-emqx-component-0.3.2-SNAPSHOT.jar
  4. 1 1
      iot-auth-server/pom.xml
  5. 1 1
      iot-common/pom.xml
  6. 1 1
      iot-components/iot-component-base/pom.xml
  7. 1 1
      iot-components/iot-component-converter/pom.xml
  8. 1 1
      iot-components/iot-component-server/pom.xml
  9. 3 3
      iot-components/iot-component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java
  10. 12 0
      iot-components/iot-component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java
  11. 2 18
      iot-components/iot-component-server/src/main/java/cc/iotkit/comps/service/DevicePropertyConsumer.java
  12. 1 1
      iot-components/iot-ctwing-component/pom.xml
  13. 5 5
      iot-components/iot-emqx-component/dependency-reduced-pom.xml
  14. 1 1
      iot-components/iot-emqx-component/pom.xml
  15. 2 2
      iot-components/iot-http-biz-component/dependency-reduced-pom.xml
  16. 1 1
      iot-components/iot-http-biz-component/pom.xml
  17. 4 4
      iot-components/iot-mqtt-component/dependency-reduced-pom.xml
  18. 1 1
      iot-components/iot-mqtt-component/pom.xml
  19. 1 1
      iot-components/pom.xml
  20. 1 1
      iot-data/iot-data-cache/pom.xml
  21. 1 1
      iot-data/iot-data-service/pom.xml
  22. 1 1
      iot-data/iot-es-temporal-service/pom.xml
  23. 23 0
      iot-data/iot-es-temporal-service/src/main/java/cc/iotkit/temporal/es/service/DbStructureDataImpl.java
  24. 10 3
      iot-data/iot-es-temporal-service/src/main/java/cc/iotkit/temporal/es/service/DevicePropertyDataImpl.java
  25. 1 0
      iot-data/iot-es-temporal-service/src/main/java/cc/iotkit/temporal/es/service/ThingModelMessageDataImpl.java
  26. 2 2
      iot-data/iot-model/pom.xml
  27. 5 0
      iot-data/iot-model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java
  28. 2 2
      iot-data/iot-rdb-data-service/pom.xml
  29. 30 0
      iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/config/JdbcTemplateConfig.java
  30. 0 1
      iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/service/DeviceInfoDataImpl.java
  31. 65 0
      iot-data/iot-td-temporal-service/pom.xml
  32. 5 0
      iot-data/iot-td-temporal-service/readme.md
  33. 18 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/config/Constants.java
  34. 34 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/config/TdDatasourceConfig.java
  35. 19 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dao/TdTemplate.java
  36. 75 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/FieldParser.java
  37. 126 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/TableManager.java
  38. 14 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/TdField.java
  39. 26 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/TdResponse.java
  40. 55 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/TdRestApi.java
  41. 20 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbDeviceProperty.java
  42. 22 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbRuleLog.java
  43. 20 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbTaskLog.java
  44. 34 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbThingModelMessage.java
  45. 22 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbVirtualDeviceLog.java
  46. 164 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/DbStructureDataImpl.java
  47. 98 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/DevicePropertyDataImpl.java
  48. 64 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/RuleLogDataImpl.java
  49. 63 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/TaskLogDataImpl.java
  50. 117 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java
  51. 60 0
      iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/VirtualDeviceLogDataImpl.java
  52. 1 1
      iot-data/iot-temporal-service/pom.xml
  53. 25 0
      iot-data/iot-temporal-service/src/main/java/cc/iotkit/temporal/IDbStructureData.java
  54. 5 2
      iot-data/iot-temporal-service/src/main/java/cc/iotkit/temporal/IDevicePropertyData.java
  55. 1 1
      iot-data/iot-temporal-service/src/main/java/cc/iotkit/temporal/IThingModelMessageData.java
  56. 1 1
      iot-data/pom.xml
  57. 1 1
      iot-message-bus/pom.xml
  58. 1 1
      iot-package/pom.xml
  59. 1 1
      iot-rule-engine/pom.xml
  60. 8 6
      iot-standalone/pom.xml
  61. 23 4
      iot-standalone/src/main/java/cc/iotkit/manager/controller/ProductController.java
  62. 3 0
      iot-standalone/src/main/java/cc/iotkit/manager/service/DeviceService.java
  63. 12 10
      iot-standalone/src/main/java/cc/iotkit/manager/service/ExampleDataInit.java
  64. 46 31
      iot-standalone/src/main/resources/application-dev.yml
  65. 18 5
      iot-standalone/src/main/resources/application-mysql.yml
  66. 15 2
      iot-standalone/src/main/resources/application.yml
  67. 1 1
      iot-test-tool/iot-test-mqtt/pom.xml
  68. 1 1
      iot-test-tool/iot-test-mqtt/src/main/java/cc/iotkit/test/mqtt/performance/ReportTest.java
  69. 1 1
      iot-test-tool/pom.xml
  70. 1 1
      iot-virtual-device/pom.xml
  71. 8 1
      pom.xml

+ 1 - 1
Dockerfile

@@ -1,6 +1,6 @@
 FROM openjdk:11-jre-slim
 WORKDIR /app
-ADD iot-standalone/target/iot-standalone-0.4.0-SNAPSHOT.tar /app
+ADD iot-standalone/target/iot-standalone-0.4.1-SNAPSHOT.tar /app
 ADD data/init /app/data/init
 ADD data/components /app/data/components
 ADD data/converters /app/data/converters

BIN
data/components/3ababc5e-15e9-45a7-8f38-2a6afd45c780/iot-http-biz-component-0.3.2-SNAPSHOT.jar


BIN
data/components/6c095554-35e7-4e9d-a8d2-bb919e9479f4/iot-emqx-component-0.3.2-SNAPSHOT.jar


+ 1 - 1
iot-auth-server/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-common/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-components/iot-component-base/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-components</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-components/iot-component-converter/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-components</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-components/iot-component-server/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-components</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 3 - 3
iot-components/iot-component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java

@@ -139,7 +139,7 @@ public class DeviceBehaviourService {
             ThingModelMessage modelMessage = new ThingModelMessage(
                     UUID.randomUUID().toString(),
                     UniqueIdUtil.newRequestId(), "",
-                    pk, dn,
+                    pk, dn, uid,
                     ThingModelMessage.TYPE_LIFETIME, "register",
                     0, new HashMap<>(), System.currentTimeMillis(),
                     System.currentTimeMillis()
@@ -193,7 +193,7 @@ public class DeviceBehaviourService {
         //否则为父设备,同步透传子设备状态
         List<String> subDeviceIds = deviceInfoData.findSubDeviceIds(device.getDeviceId());
         for (String subDeviceId : subDeviceIds) {
-            DeviceInfo subDevice=deviceInfoData.findByDeviceId(subDeviceId);
+            DeviceInfo subDevice = deviceInfoData.findByDeviceId(subDeviceId);
             Product product = productData.findById(subDevice.getProductKey());
             Boolean transparent = product.getTransparent();
             //透传设备父设备上线,子设备也上线。非透传设备父设备离线,子设备才离线
@@ -217,7 +217,7 @@ public class DeviceBehaviourService {
         ThingModelMessage modelMessage = new ThingModelMessage(
                 UUID.randomUUID().toString(),
                 UniqueIdUtil.newRequestId(), "",
-                device.getProductKey(), device.getDeviceName(),
+                device.getProductKey(), device.getDeviceName(), device.getUid(),
                 ThingModelMessage.TYPE_STATE,
                 online ? DeviceState.STATE_ONLINE : DeviceState.STATE_OFFLINE,
                 0,

+ 12 - 0
iot-components/iot-component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java

@@ -10,6 +10,8 @@
 package cc.iotkit.comps.service;
 
 import cc.iotkit.common.Constants;
+import cc.iotkit.data.IDeviceInfoData;
+import cc.iotkit.model.device.DeviceInfo;
 import cc.iotkit.model.device.message.ThingModelMessage;
 import cc.iotkit.mq.ConsumerHandler;
 import cc.iotkit.mq.MqConsumer;
@@ -17,6 +19,7 @@ import cc.iotkit.mq.MqProducer;
 import cc.iotkit.temporal.IThingModelMessageData;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 
@@ -29,6 +32,9 @@ public class DeviceMessageConsumer implements ConsumerHandler<ThingModelMessage>
     @Autowired
     private IThingModelMessageData thingModelMessageData;
     @Autowired
+    @Qualifier("deviceInfoDataCache")
+    private IDeviceInfoData deviceInfoData;
+    @Autowired
     private MqConsumer<ThingModelMessage> thingModelMessageConsumer;
     @Autowired
     private MqProducer<ThingModelMessage> thingModelMessageMqProducer;
@@ -52,6 +58,12 @@ public class DeviceMessageConsumer implements ConsumerHandler<ThingModelMessage>
                 thingModelMessageMqProducer.publish(Constants.DEVICE_CONFIG_TOPIC, msg);
             }
 
+            DeviceInfo device = deviceInfoData.findByDeviceId(msg.getDeviceId());
+            if (device == null) {
+                return;
+            }
+            msg.setUid(device.getUid());
+
             //设备消息入库
             thingModelMessageData.add(msg);
         } catch (Throwable e) {

+ 2 - 18
iot-components/iot-component-server/src/main/java/cc/iotkit/comps/service/DevicePropertyConsumer.java

@@ -12,7 +12,6 @@ package cc.iotkit.comps.service;
 import cc.iotkit.common.Constants;
 import cc.iotkit.common.utils.JsonUtil;
 import cc.iotkit.data.IDeviceInfoData;
-import cc.iotkit.model.device.message.DeviceProperty;
 import cc.iotkit.model.device.message.ThingModelMessage;
 import cc.iotkit.mq.ConsumerHandler;
 import cc.iotkit.mq.MqConsumer;
@@ -23,8 +22,6 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.PostConstruct;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -59,22 +56,9 @@ public class DevicePropertyConsumer implements ConsumerHandler<ThingModelMessage
         //更新设备当前属性
         updateDeviceCurrentProperties(deviceId, properties);
 
-        //设备属性历史数据存储
-        List<DeviceProperty> batch = new ArrayList<>();
-        for (String key : properties.keySet()) {
-            batch.add(new DeviceProperty(
-                    //防止重复id被覆盖
-                    msg.getMid() + "_" + key,
-                    deviceId,
-                    key,
-                    properties.get(key),
-                    msg.getOccurred()
-            ));
-        }
-
-        //批量保存
+        //保存属性记录
         try {
-            devicePropertyData.addProperties(batch);
+            devicePropertyData.addProperties(deviceId, properties, msg.getOccurred());
         } catch (Throwable e) {
             log.warn("save property data error", e);
         }

+ 1 - 1
iot-components/iot-ctwing-component/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-components</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 5 - 5
iot-components/iot-emqx-component/dependency-reduced-pom.xml

@@ -3,7 +3,7 @@
   <parent>
     <artifactId>iot-components</artifactId>
     <groupId>cc.iotkit</groupId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.4.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>iot-emqx-component</artifactId>
@@ -84,25 +84,25 @@
     <dependency>
       <groupId>cc.iotkit</groupId>
       <artifactId>iot-model</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
+      <version>0.4.1-SNAPSHOT</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>cc.iotkit</groupId>
       <artifactId>iot-common</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
+      <version>0.4.1-SNAPSHOT</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>cc.iotkit</groupId>
       <artifactId>iot-component-base</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
+      <version>0.4.1-SNAPSHOT</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>cc.iotkit</groupId>
       <artifactId>iot-data-service</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
+      <version>0.4.1-SNAPSHOT</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>

+ 1 - 1
iot-components/iot-emqx-component/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-components</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 2 - 2
iot-components/iot-http-biz-component/dependency-reduced-pom.xml

@@ -3,7 +3,7 @@
   <parent>
     <artifactId>iot-components</artifactId>
     <groupId>cc.iotkit</groupId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.4.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>iot-http-biz-component</artifactId>
@@ -58,7 +58,7 @@
     <dependency>
       <groupId>cc.iotkit</groupId>
       <artifactId>iot-component-base</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
+      <version>0.4.1-SNAPSHOT</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>

+ 1 - 1
iot-components/iot-http-biz-component/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-components</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 4 - 4
iot-components/iot-mqtt-component/dependency-reduced-pom.xml

@@ -3,7 +3,7 @@
   <parent>
     <artifactId>iot-components</artifactId>
     <groupId>cc.iotkit</groupId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.4.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>iot-mqtt-component</artifactId>
@@ -82,19 +82,19 @@
     <dependency>
       <groupId>cc.iotkit</groupId>
       <artifactId>iot-common</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
+      <version>0.4.1-SNAPSHOT</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>cc.iotkit</groupId>
       <artifactId>iot-component-base</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
+      <version>0.4.1-SNAPSHOT</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>cc.iotkit</groupId>
       <artifactId>iot-data-service</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
+      <version>0.4.1-SNAPSHOT</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>

+ 1 - 1
iot-components/iot-mqtt-component/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-components</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-components/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-data/iot-data-cache/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-data</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-data/iot-data-service/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-data</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-data/iot-es-temporal-service/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-data</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 23 - 0
iot-data/iot-es-temporal-service/src/main/java/cc/iotkit/temporal/es/service/DbStructureDataImpl.java

@@ -0,0 +1,23 @@
+package cc.iotkit.temporal.es.service;
+
+import cc.iotkit.model.product.ThingModel;
+import cc.iotkit.temporal.IDbStructureData;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DbStructureDataImpl implements IDbStructureData {
+    @Override
+    public void defineThingModel(ThingModel thingModel) {
+
+    }
+
+    @Override
+    public void undefineThingModel(ThingModel thingModel) {
+
+    }
+
+    @Override
+    public void initDbStructure() {
+
+    }
+}

+ 10 - 3
iot-data/iot-es-temporal-service/src/main/java/cc/iotkit/temporal/es/service/DevicePropertyDataImpl.java

@@ -23,7 +23,10 @@ import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
 import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.UUID;
 import java.util.stream.Collectors;
 
 @Service
@@ -50,9 +53,13 @@ public class DevicePropertyDataImpl implements IDevicePropertyData {
     }
 
     @Override
-    public void addProperties(List<DeviceProperty> properties) {
-        template.save(properties.stream().map(DevicePropertyMapper.M::toVo)
-                .collect(Collectors.toList()));
+    public void addProperties(String deviceId, Map<String, Object> properties, long time) {
+        List<DocDeviceProperty> deviceProperties = new ArrayList<>();
+        properties.forEach((key, val) -> deviceProperties.add(
+                new DocDeviceProperty(UUID.randomUUID().toString(), deviceId, key, val, time)
+        ));
+
+        template.save(deviceProperties);
     }
 
 

+ 1 - 0
iot-data/iot-es-temporal-service/src/main/java/cc/iotkit/temporal/es/service/ThingModelMessageDataImpl.java

@@ -76,6 +76,7 @@ public class ThingModelMessageDataImpl implements IThingModelMessageData {
                     queryBuilder.must(QueryBuilders.termQuery("uid", uid));
         }
 
+        //按小时统计消息数量
         NativeSearchQuery query = new NativeSearchQueryBuilder()
                 .withQuery(queryBuilder)
                 .withAggregations(AggregationBuilders.dateHistogram("agg")

+ 2 - 2
iot-data/iot-model/pom.xml

@@ -5,9 +5,9 @@
     <parent>
         <artifactId>iot-data</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.4.1-SNAPSHOT</version>
     <modelVersion>4.0.0</modelVersion>
 
     <artifactId>iot-model</artifactId>

+ 5 - 0
iot-data/iot-model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java

@@ -48,6 +48,11 @@ public class ThingModelMessage {
 
     private String deviceName;
 
+    /**
+     * 所属用户ID
+     */
+    private String uid;
+
     /**
      * 消息类型
      * lifetime:生命周期

+ 2 - 2
iot-data/iot-rdb-data-service/pom.xml

@@ -5,9 +5,9 @@
     <parent>
         <artifactId>iot-data</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.4.1-SNAPSHOT</version>
     <modelVersion>4.0.0</modelVersion>
 
     <artifactId>iot-rdb-data-service</artifactId>

+ 30 - 0
iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/config/JdbcTemplateConfig.java

@@ -0,0 +1,30 @@
+package cc.iotkit.data.config;
+
+
+import org.springframework.boot.autoconfigure.jdbc.JdbcProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.sql.DataSource;
+
+@Configuration(
+        proxyBeanMethods = false
+)
+class JdbcTemplateConfig {
+
+    @Bean
+    @Primary
+    JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
+        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
+        JdbcProperties.Template template = properties.getTemplate();
+        jdbcTemplate.setFetchSize(template.getFetchSize());
+        jdbcTemplate.setMaxRows(template.getMaxRows());
+        if (template.getQueryTimeout() != null) {
+            jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
+        }
+
+        return jdbcTemplate;
+    }
+}

+ 0 - 1
iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/service/DeviceInfoDataImpl.java

@@ -23,7 +23,6 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.*;
-import java.util.function.ToIntFunction;
 import java.util.stream.Collectors;
 
 @Primary

+ 65 - 0
iot-data/iot-td-temporal-service/pom.xml

@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>iot-data</artifactId>
+        <groupId>cc.iotkit</groupId>
+        <version>0.4.1-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>iot-td-temporal-service</artifactId>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.taosdata.jdbc</groupId>
+            <artifactId>taos-jdbcdriver</artifactId>
+            <version>2.0.40</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-http</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cc.iotkit</groupId>
+            <artifactId>iot-temporal-service</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cc.iotkit</groupId>
+            <artifactId>iot-data-cache</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 5 - 0
iot-data/iot-td-temporal-service/readme.md

@@ -0,0 +1,5 @@
+### 时序数据库服务接口的TDengine实现
+
+版本:v0.4.1
+
+

+ 18 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/config/Constants.java

@@ -0,0 +1,18 @@
+package cc.iotkit.temporal.td.config;
+
+public interface Constants {
+
+    /**
+     * 根据产品key获取产品属性超级表名
+     */
+    static String getProductPropertySTableName(String productKey) {
+        return String.format("product_property_%s", productKey.toLowerCase());
+    }
+
+    /**
+     * 根据deviceId获取设备属性表名
+     */
+    static String getDevicePropertyTableName(String deviceId) {
+        return String.format("device_property_%s", deviceId.toLowerCase());
+    }
+}

+ 34 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/config/TdDatasourceConfig.java

@@ -0,0 +1,34 @@
+package cc.iotkit.temporal.td.config;
+
+import cc.iotkit.temporal.td.dao.TdTemplate;
+import com.zaxxer.hikari.HikariDataSource;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class TdDatasourceConfig {
+
+    @Value("${spring.td-datasource.url}")
+    private String url;
+
+    @Value("${spring.td-datasource.driverClassName}")
+    private String driverClassName;
+
+    @Value("${spring.td-datasource.username}")
+    private String username;
+
+    @Value("${spring.td-datasource.password}")
+    private String password;
+
+    @Bean("tdJdbcTemplate")
+    public TdTemplate tdJdbcTemplate() {
+        HikariDataSource dataSource = new HikariDataSource();
+        dataSource.setJdbcUrl(url);
+        dataSource.setUsername(username);
+        dataSource.setPassword(password);
+        dataSource.setDriverClassName(driverClassName);
+        return new TdTemplate(dataSource);
+    }
+
+}

+ 19 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dao/TdTemplate.java

@@ -0,0 +1,19 @@
+package cc.iotkit.temporal.td.dao;
+
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.sql.DataSource;
+
+public class TdTemplate extends JdbcTemplate {
+
+    public TdTemplate() {
+    }
+
+    public TdTemplate(DataSource dataSource) {
+        super(dataSource);
+    }
+
+    public TdTemplate(DataSource dataSource, boolean lazyInit) {
+        super(dataSource, lazyInit);
+    }
+}

+ 75 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/FieldParser.java

@@ -0,0 +1,75 @@
+package cc.iotkit.temporal.td.dm;
+
+import cc.iotkit.model.product.ThingModel;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class FieldParser {
+
+    /**
+     * 物模型到td数据类型映射
+     */
+    private static final Map<String, String> TYPE_MAPPING = Map.of(
+            "int32", "INT",
+            "float", "FLOAT",
+            "bool", "TINYINT",
+            "enum", "TINYINT",
+            "text", "NCHAR",
+            "date", "NCHAR"
+    );
+
+    /**
+     * 将物模型字段转换为td字段
+     */
+    public static TdField parse(ThingModel.Property property) {
+        String filedName = property.getIdentifier().toLowerCase();
+        ThingModel.DataType dataType = property.getDataType();
+        String type = dataType.getType();
+
+        //将物模型字段类型映射为td字段类型
+        String fType = TYPE_MAPPING.get(type);
+        Object specs = dataType.getSpecs();
+        int len = -1;
+        if (specs instanceof Map) {
+            Object objLen = ((Map<?, ?>) specs).get("length");
+            if (objLen != null) {
+                len = Integer.parseInt(objLen.toString());
+            }
+        }
+
+        return new TdField(filedName, fType, len);
+    }
+
+    /**
+     * 获取物模型中的字段列表
+     */
+    public static List<TdField> parse(ThingModel thingModel) {
+        return thingModel.getModel().getProperties().stream().map(FieldParser::parse).collect(Collectors.toList());
+    }
+
+    /**
+     * 将从库中查出来的字段信息转换为td字段对象
+     */
+    public static List<TdField> parse(List rows) {
+        return (List<TdField>) rows.stream().map((r) -> {
+            List row = (List) r;
+            String type = row.get(1).toString().toUpperCase();
+            return new TdField(
+                    row.get(0).toString(),
+                    type,
+                    type.equals("NCHAR") ? Integer.parseInt(row.get(2).toString()) : -1);
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 获取字段字义
+     */
+    public static String getFieldDefine(TdField field) {
+        return field.getName() + " " + (field.getLength() > 0 ?
+                String.format("%s(%d)", field.getType(), field.getLength())
+                : field.getType());
+    }
+
+}

+ 126 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/TableManager.java

@@ -0,0 +1,126 @@
+package cc.iotkit.temporal.td.dm;
+
+import java.util.List;
+
+public class TableManager {
+
+    /**
+     * 创建超级表模板(含存在判断)
+     */
+    private static final String CREATE_STABLE_INE_TPL = "CREATE STABLE IF NOT EXISTS %s (%s) TAGS (%s);";
+
+    /**
+     * 删除超级表
+     */
+    private static final String DROP_STABLE_TPL = "DROP STABLE IF EXISTS %s;";
+
+    /**
+     * 获取表的结构信息
+     */
+    private static final String DESC_TB_TPL = "DESCRIBE %s;";
+
+    /**
+     * 超级表增加列
+     */
+    private static final String ALTER_STABLE_ADD_COL_TPL = "ALTER STABLE %s ADD COLUMN %s;";
+
+    /**
+     * 超级表修改列
+     */
+    private static final String ALTER_STABLE_MODIFY_COL_TPL = "ALTER STABLE %s MODIFY COLUMN %s;";
+
+    /**
+     * 超级表删除列
+     */
+    private static final String ALTER_STABLE_DROP_COL_TPL = "ALTER STABLE %s DROP COLUMN %s;";
+
+    /**
+     * 获取创建表sql
+     */
+    public static String getCreateSTableSql(String tbName, List<TdField> fields, TdField... tags) {
+        if (fields.size() == 0) {
+            return null;
+        }
+
+        //生成字段片段
+        StringBuilder sbField = new StringBuilder("time timestamp,");
+
+        for (TdField field : fields) {
+            sbField.append(FieldParser.getFieldDefine(field));
+            sbField.append(",");
+        }
+        sbField.deleteCharAt(sbField.length() - 1);
+
+        String fieldFrag = sbField.toString();
+
+        //生成tag
+        StringBuilder sbTag = new StringBuilder();
+        for (TdField tag : tags) {
+            sbTag.append(FieldParser.getFieldDefine(tag))
+                    .append(",");
+        }
+        sbTag.deleteCharAt(sbTag.length() - 1);
+
+        return String.format(CREATE_STABLE_INE_TPL, tbName, fieldFrag, sbTag.toString());
+
+    }
+
+    /**
+     * 取正确的表名
+     *
+     * @param name 表象
+     */
+    public static String rightTbName(String name) {
+        return name.toLowerCase().replace("-", "_");
+    }
+
+    /**
+     * 获取表详情的sql
+     */
+    public static String getDescTableSql(String tbName) {
+        return String.format(DESC_TB_TPL, tbName);
+    }
+
+    /**
+     * 获取添加字段sql
+     */
+    public static String getAddSTableColumnSql(String tbName, List<TdField> fields) {
+        StringBuilder sbAdd = new StringBuilder();
+        for (TdField field : fields) {
+            sbAdd.append(String.format(ALTER_STABLE_ADD_COL_TPL,
+                    tbName,
+                    FieldParser.getFieldDefine(field)
+            ));
+        }
+        return sbAdd.toString();
+    }
+
+    /**
+     * 获取修改字段sql
+     */
+    public static String getModifySTableColumnSql(String tbName, List<TdField> fields) {
+        StringBuilder sbModify = new StringBuilder();
+        for (TdField field : fields) {
+            sbModify.append(String.format(ALTER_STABLE_MODIFY_COL_TPL,
+                    tbName,
+                    FieldParser.getFieldDefine(field)
+            ));
+        }
+        return sbModify.toString();
+    }
+
+    /**
+     * 获取删除字段sql
+     */
+    public static String getDropSTableColumnSql(String tbName, List<TdField> fields) {
+        StringBuilder sbDrop = new StringBuilder();
+        for (TdField field : fields) {
+            sbDrop.append(String.format(ALTER_STABLE_DROP_COL_TPL,
+                    tbName,
+                    field.getName()
+            ));
+        }
+        return sbDrop.toString();
+    }
+
+}

+ 14 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/TdField.java

@@ -0,0 +1,14 @@
+package cc.iotkit.temporal.td.dm;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TdField {
+    private String name;
+    private String type;
+    private int length;
+}

+ 26 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/TdResponse.java

@@ -0,0 +1,26 @@
+package cc.iotkit.temporal.td.dm;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TdResponse {
+
+    public static final int CODE_SUCCESS = 0;
+    public static final int CODE_TB_NOT_EXIST = 866;
+
+    private String status;
+
+    private int code;
+
+    private String desc;
+
+    //[["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]]
+    private List data;
+
+}

+ 55 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/dm/TdRestApi.java

@@ -0,0 +1,55 @@
+package cc.iotkit.temporal.td.dm;
+
+import cc.iotkit.common.utils.JsonUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class TdRestApi {
+
+    @Value("${spring.td-datasource.url}")
+    private String url;
+
+    @Value("${spring.td-datasource.username}")
+    private String username;
+
+    @Value("${spring.td-datasource.password}")
+    private String password;
+
+    private String getRestApiUrl() {
+        //jdbc:TAOS-RS://127.0.0.1:6041/iotkit?xxxx
+        String restUrl = url.replace("jdbc:TAOS-RS://", "")
+                .replaceAll("\\?.*", "");
+        // /rest/sql/iotkit
+        int idx = restUrl.lastIndexOf("/");
+        //127.0.0.1:6041/rest/sql/iotkit
+        return String.format("%s/rest/sql/%s", restUrl.substring(0, idx), restUrl.substring(idx + 1));
+    }
+
+
+    /**
+     * 新建td api请求对象
+     */
+    public HttpRequest newApiRequest(String sql) {
+        return HttpRequest
+                .post(getRestApiUrl())
+                .body(sql)
+                .basicAuth(username, password);
+    }
+
+    /**
+     * 执行sql
+     */
+    public TdResponse execSql(String sql) {
+        log.info("exec td sql:{}", sql);
+        HttpRequest request = newApiRequest(sql);
+        HttpResponse response = request.execute();
+        return JsonUtil.parse(response.body(), TdResponse.class);
+    }
+
+
+}

+ 20 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbDeviceProperty.java

@@ -0,0 +1,20 @@
+package cc.iotkit.temporal.td.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TbDeviceProperty {
+
+    private Long time;
+
+    private String deviceId;
+
+    private String name;
+
+    private Object value;
+
+}

+ 22 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbRuleLog.java

@@ -0,0 +1,22 @@
+package cc.iotkit.temporal.td.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TbRuleLog {
+
+    private Long time;
+
+    private String ruleId;
+
+    private String state1;
+
+    private String content;
+
+    private Boolean success;
+
+}

+ 20 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbTaskLog.java

@@ -0,0 +1,20 @@
+package cc.iotkit.temporal.td.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TbTaskLog {
+
+    private Long time;
+
+    private String taskId;
+
+    private String content;
+
+    private Boolean success;
+
+}

+ 34 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbThingModelMessage.java

@@ -0,0 +1,34 @@
+package cc.iotkit.temporal.td.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TbThingModelMessage {
+
+    private Long time;
+
+    private String mid;
+
+    private String deviceId;
+
+    private String productKey;
+
+    private String deviceName;
+
+    private String uid;
+
+    private String type;
+
+    private String identifier;
+
+    private int code;
+
+    private String data;
+
+    private Long reportTime;
+
+}

+ 22 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/model/TbVirtualDeviceLog.java

@@ -0,0 +1,22 @@
+package cc.iotkit.temporal.td.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TbVirtualDeviceLog {
+
+    private Long time;
+
+    private String virtualDeviceId;
+
+    private String virtualDeviceName;
+
+    private int deviceTotal;
+
+    private String result;
+
+}

+ 164 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/DbStructureDataImpl.java

@@ -0,0 +1,164 @@
+package cc.iotkit.temporal.td.service;
+
+import cc.iotkit.common.utils.JsonUtil;
+import cc.iotkit.model.product.ThingModel;
+import cc.iotkit.temporal.IDbStructureData;
+import cc.iotkit.temporal.td.config.Constants;
+import cc.iotkit.temporal.td.dm.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class DbStructureDataImpl implements IDbStructureData {
+
+    @Autowired
+    private TdRestApi tdRestApi;
+
+    /**
+     * 根据物模型创建超级表
+     */
+    @Override
+    public void defineThingModel(ThingModel thingModel) {
+        //获取物模型中的属性定义
+        List<TdField> fields = FieldParser.parse(thingModel);
+        String tbName = Constants.getProductPropertySTableName(thingModel.getProductKey());
+        //生成sql
+        String sql = TableManager.getCreateSTableSql(tbName,
+                fields,
+                new TdField("device_id", "NCHAR", 50));
+        if (sql == null) {
+            return;
+        }
+        log.info("executing sql:{}", sql);
+
+        //执行sql
+        TdResponse response = tdRestApi.execSql(sql);
+        if (TdResponse.CODE_SUCCESS != response.getCode()) {
+            throw new RuntimeException(String.format(
+                    "create td stable failed,code:%s,desc:%s"
+                    , response.getCode(), response.getDesc()));
+        }
+    }
+
+    /**
+     * 根据物模型更新超级表结构
+     */
+    @Override
+    public void undefineThingModel(ThingModel thingModel) {
+        //获取旧字段信息
+        String tbName = Constants.getProductPropertySTableName(thingModel.getProductKey());
+        String sql = TableManager.getDescTableSql(tbName);
+        TdResponse response = tdRestApi.execSql(sql);
+        if (response.getCode() != TdResponse.CODE_SUCCESS) {
+            throw new RuntimeException("get des table error:" + JsonUtil.toJsonString(response));
+        }
+
+        List<TdField> oldFields = FieldParser.parse(response.getData());
+        List<TdField> newFields = FieldParser.parse(thingModel);
+        //对比差异
+
+        //找出新增的字段
+        List<TdField> addFields = newFields.stream().filter((f) -> oldFields.stream()
+                .noneMatch(old -> old.getName().equals(f.getName())))
+                .collect(Collectors.toList());
+        if (addFields.size() > 0) {
+            sql = TableManager.getAddSTableColumnSql(tbName, addFields);
+            response = tdRestApi.execSql(sql);
+            if (response.getCode() != TdResponse.CODE_SUCCESS) {
+                throw new RuntimeException("add table column error:" + JsonUtil.toJsonString(response));
+            }
+        }
+
+        //找出修改的字段
+        List<TdField> modifyFields = newFields.stream().filter((f) -> oldFields.stream()
+                .anyMatch(old ->
+                        old.getName().equals(f.getName()) //字段名相同
+                                //字段类型或长度不同
+                                && (old.getType().equals(f.getType()) || old.getLength() != f.getLength())
+                ))
+                .collect(Collectors.toList());
+
+        if (modifyFields.size() > 0) {
+            sql = TableManager.getModifySTableColumnSql(tbName, modifyFields);
+            response = tdRestApi.execSql(sql);
+            if (response.getCode() != TdResponse.CODE_SUCCESS) {
+                throw new RuntimeException("modify table column error:" + JsonUtil.toJsonString(response));
+            }
+        }
+
+        //找出删除的字段
+        List<TdField> dropFields = oldFields.stream().filter((f) -> newFields.stream()
+                .noneMatch(old -> old.getName().equals(f.getName())))
+                .collect(Collectors.toList());
+        if (dropFields.size() > 0) {
+            sql = TableManager.getDropSTableColumnSql(tbName, dropFields);
+            response = tdRestApi.execSql(sql);
+            if (response.getCode() != TdResponse.CODE_SUCCESS) {
+                throw new RuntimeException("drop table column error:" + JsonUtil.toJsonString(response));
+            }
+        }
+    }
+
+    /**
+     * 初始化其它数据结构
+     */
+    @Override
+    @PostConstruct
+    public void initDbStructure() {
+        //创建规则日志超级表
+        String sql = TableManager.getCreateSTableSql("rule_log", List.of(
+                new TdField("state1", "NCHAR", 32),
+                new TdField("content", "NCHAR", 255),
+                new TdField("success", "BOOL", -1)
+        ), new TdField("rule_id", "NCHAR", 50));
+        TdResponse response = tdRestApi.execSql(sql);
+        if (response.getCode() != TdResponse.CODE_SUCCESS) {
+            throw new RuntimeException("create stable rule_log error:" + JsonUtil.toJsonString(response));
+        }
+
+        //创建规则日志超级表
+        sql = TableManager.getCreateSTableSql("task_log", List.of(
+                new TdField("content", "NCHAR", 255),
+                new TdField("success", "BOOL", -1)
+        ), new TdField("task_id", "NCHAR", 50));
+        response = tdRestApi.execSql(sql);
+        if (response.getCode() != TdResponse.CODE_SUCCESS) {
+            throw new RuntimeException("create stable task_log error:" + JsonUtil.toJsonString(response));
+        }
+
+        //创建物模型消息超级表
+        sql = TableManager.getCreateSTableSql("thing_model_message", List.of(
+                new TdField("mid", "NCHAR", 50),
+                new TdField("product_key", "NCHAR", 50),
+                new TdField("device_name", "NCHAR", 50),
+                new TdField("uid", "NCHAR", 50),
+                new TdField("type", "NCHAR", 20),
+                new TdField("identifier", "NCHAR", 50),
+                new TdField("code", "INT", -1),
+                new TdField("data", "NCHAR", 255),
+                new TdField("report_time", "BIGINT", -1)
+        ), new TdField("device_id", "NCHAR", 50));
+        response = tdRestApi.execSql(sql);
+        if (response.getCode() != TdResponse.CODE_SUCCESS) {
+            throw new RuntimeException("create stable thing_model_message error:" + JsonUtil.toJsonString(response));
+        }
+
+        //创建虚拟设备日志超级表
+        sql = TableManager.getCreateSTableSql("virtual_device_log", List.of(
+                new TdField("virtual_device_name", "NCHAR", 50),
+                new TdField("device_total", "INT", -1),
+                new TdField("result", "NCHAR", 255)
+        ), new TdField("virtual_device_id", "NCHAR", 50));
+        response = tdRestApi.execSql(sql);
+        if (response.getCode() != TdResponse.CODE_SUCCESS) {
+            throw new RuntimeException("create stable virtual_device_log error:" + JsonUtil.toJsonString(response));
+        }
+
+    }
+}

+ 98 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/DevicePropertyDataImpl.java

@@ -0,0 +1,98 @@
+/*
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 奇特物联 2021-2022 All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed 未经许可不能去掉「奇特物联」相关版权
+ * +----------------------------------------------------------------------
+ * | Author: xw2sy@163.com
+ * +----------------------------------------------------------------------
+ */
+package cc.iotkit.temporal.td.service;
+
+import cc.iotkit.data.IDeviceInfoData;
+import cc.iotkit.model.device.DeviceInfo;
+import cc.iotkit.model.device.message.DeviceProperty;
+import cc.iotkit.temporal.IDevicePropertyData;
+import cc.iotkit.temporal.td.config.Constants;
+import cc.iotkit.temporal.td.dao.TdTemplate;
+import cc.iotkit.temporal.td.model.TbDeviceProperty;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class DevicePropertyDataImpl implements IDevicePropertyData {
+
+    @Autowired
+    private TdTemplate tdTemplate;
+    @Autowired
+    @Qualifier("deviceInfoDataCache")
+    private IDeviceInfoData deviceInfoData;
+
+    public List<DeviceProperty> findDevicePropertyHistory(String deviceId, String name, long start, long end) {
+        DeviceInfo device = deviceInfoData.findByDeviceId(deviceId);
+        if (device == null) {
+            return new ArrayList<>();
+        }
+
+        String tbName = Constants.getProductPropertySTableName(device.getProductKey());
+        List<TbDeviceProperty> deviceProperties = tdTemplate.query(String.format(
+                "select time,%s as value,device_id from %s where device_id=? and time>=? and time<=?",
+                name.toLowerCase(), tbName),
+                new BeanPropertyRowMapper<>(TbDeviceProperty.class),
+                deviceId, start, end
+        );
+        return deviceProperties.stream().map(p -> new DeviceProperty(
+                p.getTime().toString(),
+                p.getDeviceId(),
+                name,
+                p.getValue(),
+                p.getTime()))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public void addProperties(String deviceId, Map<String, Object> properties, long time) {
+        DeviceInfo device = deviceInfoData.findByDeviceId(deviceId);
+        if (device == null) {
+            return;
+        }
+        //获取设备旧属性
+        Map<String, Object> oldProperties = deviceInfoData.getProperties(deviceId);
+        //用新属性覆盖
+        oldProperties.putAll(properties);
+
+        StringBuilder sbFieldNames = new StringBuilder();
+        StringBuilder sbFieldPlaces = new StringBuilder();
+        List<Object> args = new ArrayList<>();
+        args.add(time);
+
+        //组织sql
+        oldProperties.forEach((key, val) -> {
+            sbFieldNames.append(key)
+                    .append(",");
+            sbFieldPlaces.append("?,");
+            args.add(val);
+        });
+        sbFieldNames.deleteCharAt(sbFieldNames.length() - 1);
+        sbFieldPlaces.deleteCharAt(sbFieldPlaces.length() - 1);
+
+        String sql = String.format("INSERT INTO %s (time,%s) USING %s TAGS ('%s') VALUES (?,%s);",
+                Constants.getDevicePropertyTableName(deviceId),
+                sbFieldNames.toString(),
+                Constants.getProductPropertySTableName(device.getProductKey()),
+                deviceId,
+                sbFieldPlaces.toString());
+
+        tdTemplate.update(sql, args.toArray());
+    }
+
+}

+ 64 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/RuleLogDataImpl.java

@@ -0,0 +1,64 @@
+/*
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 奇特物联 2021-2022 All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed 未经许可不能去掉「奇特物联」相关版权
+ * +----------------------------------------------------------------------
+ * | Author: xw2sy@163.com
+ * +----------------------------------------------------------------------
+ */
+package cc.iotkit.temporal.td.service;
+
+import cc.iotkit.model.Paging;
+import cc.iotkit.model.rule.RuleLog;
+import cc.iotkit.temporal.IRuleLogData;
+import cc.iotkit.temporal.td.dao.TdTemplate;
+import cc.iotkit.temporal.td.dm.TableManager;
+import cc.iotkit.temporal.td.model.TbRuleLog;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class RuleLogDataImpl implements IRuleLogData {
+
+    @Autowired
+    private TdTemplate tdTemplate;
+
+    @Override
+    public void deleteByRuleId(String ruleId) {
+        tdTemplate.update("delete from rule_log where rule_id=?", ruleId);
+    }
+
+    @Override
+    public Paging<RuleLog> findByRuleId(String ruleId, int page, int size) {
+        String sql = "select time,state1,content,success,rule_id from rule_log where rule_id=? " +
+                "order by time desc limit %d offset %d";
+        sql = String.format(sql, size, (page - 1) * size);
+        List<TbRuleLog> ruleLogs = tdTemplate.query(sql, new BeanPropertyRowMapper<>(TbRuleLog.class), ruleId);
+
+        sql = "select count(*) from rule_log where rule_id=?";
+        List<Long> counts = tdTemplate.queryForList(sql, Long.class, ruleId);
+
+        return new Paging<>(counts.size() > 0 ? counts.get(0) : 0, ruleLogs.stream().map(r ->
+                new RuleLog(r.getTime().toString(), ruleId, r.getState1(),
+                        r.getContent(), r.getSuccess(), r.getTime()))
+                .collect(Collectors.toList()));
+    }
+
+    @Override
+    public void add(RuleLog log) {
+        //使用ruleId作表名
+        String sql = String.format("INSERT INTO %s (%s) USING %s TAGS ('%s') VALUES (%s);",
+                "rule_log_" + TableManager.rightTbName(log.getRuleId()),
+                "time,state1,content,success",
+                "rule_log",
+                log.getRuleId(),
+                "?,?,?,?"
+        );
+        tdTemplate.update(sql, System.currentTimeMillis(), log.getState(), log.getContent(), log.getSuccess());
+    }
+}

+ 63 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/TaskLogDataImpl.java

@@ -0,0 +1,63 @@
+/*
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 奇特物联 2021-2022 All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed 未经许可不能去掉「奇特物联」相关版权
+ * +----------------------------------------------------------------------
+ * | Author: xw2sy@163.com
+ * +----------------------------------------------------------------------
+ */
+package cc.iotkit.temporal.td.service;
+
+import cc.iotkit.model.Paging;
+import cc.iotkit.model.rule.TaskLog;
+import cc.iotkit.temporal.ITaskLogData;
+import cc.iotkit.temporal.td.dao.TdTemplate;
+import cc.iotkit.temporal.td.dm.TableManager;
+import cc.iotkit.temporal.td.model.TbTaskLog;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class TaskLogDataImpl implements ITaskLogData {
+
+    @Autowired
+    private TdTemplate tdTemplate;
+
+    @Override
+    public void deleteByTaskId(String taskId) {
+        tdTemplate.update("delete from task_log where task_id=?", taskId);
+    }
+
+    @Override
+    public Paging<TaskLog> findByTaskId(String taskId, int page, int size) {
+        String sql = "select time,content,success,task_id from task_log where task_id=? order by time desc limit %d offset %d";
+        sql = String.format(sql, size, (page - 1) * size);
+        List<TbTaskLog> taskLogs = tdTemplate.query(sql, new BeanPropertyRowMapper<>(TbTaskLog.class), taskId);
+
+        sql = "select count(*) from task_log where task_id=?";
+        List<Long> counts = tdTemplate.queryForList(sql, Long.class, taskId);
+
+        return new Paging<>(counts.size() > 0 ? counts.get(0) : 0, taskLogs.stream().map(r ->
+                new TaskLog(r.getTime().toString(), taskId,
+                        r.getContent(), r.getSuccess(), r.getTime()))
+                .collect(Collectors.toList()));
+    }
+
+    @Override
+    public void add(TaskLog log) {
+        //使用taskId作表名
+        String sql = String.format("INSERT INTO %s (%s) USING %s TAGS ('%s') VALUES (%s);",
+                "task_log_" + TableManager.rightTbName(log.getTaskId()),
+                "time,content,success",
+                "task_log",
+                log.getTaskId(),
+                "?,?,?"
+        );
+        tdTemplate.update(sql, System.currentTimeMillis(), log.getContent(), log.getSuccess());
+    }
+}

+ 117 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java

@@ -0,0 +1,117 @@
+/*
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 奇特物联 2021-2022 All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed 未经许可不能去掉「奇特物联」相关版权
+ * +----------------------------------------------------------------------
+ * | Author: xw2sy@163.com
+ * +----------------------------------------------------------------------
+ */
+package cc.iotkit.temporal.td.service;
+
+import cc.iotkit.common.utils.JsonUtil;
+import cc.iotkit.model.Paging;
+import cc.iotkit.model.device.message.ThingModelMessage;
+import cc.iotkit.model.stats.TimeData;
+import cc.iotkit.temporal.IThingModelMessageData;
+import cc.iotkit.temporal.td.dao.TdTemplate;
+import cc.iotkit.temporal.td.model.TbThingModelMessage;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+public class ThingModelMessageDataImpl implements IThingModelMessageData {
+
+    @Autowired
+    private TdTemplate tdTemplate;
+
+    public Paging<ThingModelMessage> findByTypeAndIdentifier(String deviceId, String type,
+                                                             String identifier,
+                                                             int page, int size) {
+        String sql = "select time,mid,product_key,device_name,type,identifier,code,data,report_time " +
+                "from thing_model_message_%s %s order by time desc limit %d offset %d";
+
+        //构建动态条件
+        List<Object> args = new ArrayList<>();
+        List<String> cons = new ArrayList<>();
+        if (StringUtils.isNotBlank(type)) {
+            cons.add("type=?");
+            args.add(type);
+        }
+        if (StringUtils.isNotBlank(identifier)) {
+            cons.add("identifier=?");
+            args.add(identifier);
+        }
+        String condition = "";
+        if (cons.size() > 0) {
+            condition = "where " + String.join(" and ", cons);
+        }
+
+        sql = String.format(sql, deviceId.toLowerCase(), condition, size, (page - 1) * size);
+        List<TbThingModelMessage> ruleLogs = tdTemplate.query(sql,
+                new BeanPropertyRowMapper<>(TbThingModelMessage.class),
+                args.toArray()
+        );
+
+        sql = String.format("select count(*) from thing_model_message_%s %s",
+                deviceId.toLowerCase(), condition);
+        List<Long> counts = tdTemplate.queryForList(sql, Long.class, args.toArray());
+        long count = counts.size() > 0 ? counts.get(0) : 0;
+
+        return new Paging<>(count, ruleLogs.stream().map(r ->
+                new ThingModelMessage(r.getTime().toString(), r.getMid(),
+                        deviceId, r.getProductKey(), r.getDeviceName(),
+                        r.getUid(), r.getType(), r.getIdentifier(), r.getCode(),
+                        JsonUtil.parse(r.getData(), Map.class),
+                        r.getTime(), r.getReportTime()))
+                .collect(Collectors.toList()));
+    }
+
+    @Override
+    public List<TimeData> getDeviceMessageStatsWithUid(String uid, long start, long end) {
+        String sql = "select time,count(*) as data from(" +
+                "select TIMETRUNCATE(time,1h) as time from thing_model_message " +
+                "where time>=? and time<=? " + (uid != null ? "and uid=?" : "") +
+                ") a group by time order by time asc";
+
+        List<Object> args = new ArrayList<>();
+        args.add(start);
+        args.add(end);
+        if (uid != null) {
+            args.add(uid);
+        }
+
+        return tdTemplate.query(sql, new BeanPropertyRowMapper<>(TimeData.class), args.toArray());
+    }
+
+    @Override
+    public void add(ThingModelMessage msg) {
+        //使用deviceId作表名
+        String sql = String.format("INSERT INTO %s (%s) USING %s TAGS ('%s') VALUES (%s);",
+                "thing_model_message_" + msg.getDeviceId().toLowerCase(),
+                "time,mid,product_key,device_name,uid,type,identifier,code,data,report_time",
+                "thing_model_message",
+                msg.getDeviceId(),
+                "?,?,?,?,?,?,?,?,?,?"
+        );
+        tdTemplate.update(sql, msg.getOccurred(), msg.getMid(),
+                msg.getProductKey(), msg.getDeviceName(),
+                msg.getUid(), msg.getType(),
+                msg.getIdentifier(), msg.getCode(),
+                msg.getData() == null ? "{}" : JsonUtil.toJsonString(msg.getData()),
+                msg.getTime());
+    }
+
+    @Override
+    public long count() {
+        Long c = tdTemplate.queryForObject("select count(*) from thing_model_message", Long.class);
+        return c == null ? 0 : c;
+    }
+}

+ 60 - 0
iot-data/iot-td-temporal-service/src/main/java/cc/iotkit/temporal/td/service/VirtualDeviceLogDataImpl.java

@@ -0,0 +1,60 @@
+/*
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 奇特物联 2021-2022 All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed 未经许可不能去掉「奇特物联」相关版权
+ * +----------------------------------------------------------------------
+ * | Author: xw2sy@163.com
+ * +----------------------------------------------------------------------
+ */
+package cc.iotkit.temporal.td.service;
+
+import cc.iotkit.model.Paging;
+import cc.iotkit.model.device.VirtualDeviceLog;
+import cc.iotkit.temporal.IVirtualDeviceLogData;
+import cc.iotkit.temporal.td.dao.TdTemplate;
+import cc.iotkit.temporal.td.model.TbVirtualDeviceLog;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class VirtualDeviceLogDataImpl implements IVirtualDeviceLogData {
+
+    @Autowired
+    private TdTemplate tdTemplate;
+
+    @Override
+    public Paging<VirtualDeviceLog> findByVirtualDeviceId(String virtualDeviceId, int page, int size) {
+        String sql = "select time,virtual_device_id,virtual_device_name,device_total,result from virtual_device_log_%s order by time desc limit %d offset %d";
+        sql = String.format(sql, virtualDeviceId.toLowerCase(), size, (page - 1) * size);
+        List<TbVirtualDeviceLog> logs = tdTemplate.query(sql, new BeanPropertyRowMapper<>(TbVirtualDeviceLog.class));
+
+        sql = "select count(*) from virtual_device_log_" + virtualDeviceId.toLowerCase();
+        List<Long> counts = tdTemplate.queryForList(sql, Long.class);
+
+        return new Paging<>(counts.size() > 0 ? counts.get(0) : 0, logs.stream().map(r ->
+                new VirtualDeviceLog(r.getTime().toString(), virtualDeviceId,
+                        r.getVirtualDeviceName(),
+                        r.getDeviceTotal(), r.getResult(),
+                        r.getTime()))
+                .collect(Collectors.toList()));
+    }
+
+    @Override
+    public void add(VirtualDeviceLog log) {
+        //使用virtualDeviceId作表名
+        String sql = String.format("INSERT INTO %s (%s) USING %s TAGS ('%s') VALUES (%s);",
+                "virtual_device_log_" + log.getVirtualDeviceId().toLowerCase(),
+                "time,virtual_device_name,device_total,result",
+                "virtual_device_log",
+                log.getVirtualDeviceId(),
+                "?,?,?,?"
+        );
+        tdTemplate.update(sql, System.currentTimeMillis(), log.getVirtualDeviceName(),
+                log.getDeviceTotal(), log.getResult());
+    }
+}

+ 1 - 1
iot-data/iot-temporal-service/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-data</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 25 - 0
iot-data/iot-temporal-service/src/main/java/cc/iotkit/temporal/IDbStructureData.java

@@ -0,0 +1,25 @@
+package cc.iotkit.temporal;
+
+import cc.iotkit.model.product.ThingModel;
+
+/**
+ * 数据结构接口
+ */
+public interface IDbStructureData {
+
+    /**
+     * 定义物模型,根据物模型定义表
+     */
+    void defineThingModel(ThingModel thingModel);
+
+    /**
+     * 取消物模型定义
+     */
+    void undefineThingModel(ThingModel thingModel);
+
+    /**
+     * 初始化数据库结构
+     */
+    void initDbStructure();
+
+}

+ 5 - 2
iot-data/iot-temporal-service/src/main/java/cc/iotkit/temporal/IDevicePropertyData.java

@@ -13,6 +13,7 @@ package cc.iotkit.temporal;
 import cc.iotkit.model.device.message.DeviceProperty;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 设备属性时序数据接口
@@ -32,8 +33,10 @@ public interface IDevicePropertyData {
     /**
      * 添加多个属性
      *
-     * @param properties 属性列表
+     * @param deviceId   设备ID
+     * @param properties 属性
+     * @param time       属性上报时间
      */
-    void addProperties(List<DeviceProperty> properties);
+    void addProperties(String deviceId, Map<String, Object> properties, long time);
 
 }

+ 1 - 1
iot-data/iot-temporal-service/src/main/java/cc/iotkit/temporal/IThingModelMessageData.java

@@ -30,7 +30,7 @@ public interface IThingModelMessageData {
                                                       String identifier, int page, int size);
 
     /**
-     * 按用户统计时间段内上报次数
+     * 按用户统计时间段内每小时上报次数
      *
      * @param uid   用户id
      * @param start 开始时间戳

+ 1 - 1
iot-data/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>pom</packaging>

+ 1 - 1
iot-message-bus/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-package/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-rule-engine/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 8 - 6
iot-standalone/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -13,11 +13,6 @@
 
     <dependencies>
 
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
-        </dependency>
-
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
@@ -141,11 +136,18 @@
             <artifactId>iot-rdb-data-service</artifactId>
         </dependency>
 
+        <!--打开注释 启用es数据库-->
         <dependency>
             <groupId>cc.iotkit</groupId>
             <artifactId>iot-es-temporal-service</artifactId>
         </dependency>
 
+        <!--打开注释 启用tdengine数据库-->
+        <!--        <dependency>-->
+        <!--            <groupId>cc.iotkit</groupId>-->
+        <!--            <artifactId>iot-td-temporal-service</artifactId>-->
+        <!--        </dependency>-->
+
         <dependency>
             <groupId>cc.iotkit</groupId>
             <artifactId>iot-data-cache</artifactId>

+ 23 - 4
iot-standalone/src/main/java/cc/iotkit/manager/controller/ProductController.java

@@ -22,6 +22,7 @@ import cc.iotkit.model.product.Category;
 import cc.iotkit.model.product.Product;
 import cc.iotkit.model.product.ProductModel;
 import cc.iotkit.model.product.ThingModel;
+import cc.iotkit.temporal.IDbStructureData;
 import cc.iotkit.utils.AuthUtil;
 import cn.dev33.satoken.annotation.SaCheckRole;
 import com.aliyun.oss.OSS;
@@ -55,6 +56,8 @@ public class ProductController {
     private AliyunConfig aliyunConfig;
     @Autowired
     private IProductModelData productModelData;
+    @Autowired
+    private IDbStructureData dbStructureData;
 
 
     private OSS ossClient;
@@ -87,22 +90,38 @@ public class ProductController {
 
     @GetMapping("/thingModel/{productKey}")
     public ThingModel getThingModel(@PathVariable("productKey") String productKey) {
-        productKey = getProduct(productKey).getId();
+        checkProductOwner(productKey);
         return thingModelData.findById(productKey);
     }
 
     @PostMapping("/thingModel/save")
     public void saveThingModel(String productKey, String model) {
-        productKey = getProduct(productKey).getId();
-        thingModelData.save(new ThingModel(productKey, productKey, JsonUtil.parse(model, ThingModel.Model.class)));
+        checkProductOwner(productKey);
+        ThingModel oldData = thingModelData.findByProductKey(productKey);
+        ThingModel thingModel = new ThingModel(productKey, productKey, JsonUtil.parse(model, ThingModel.Model.class));
+        if (oldData == null) {
+            //定义时序数据库物模型数据结构
+            dbStructureData.defineThingModel(thingModel);
+        } else {
+            //更新时序数据库物模型数据结构
+            dbStructureData.undefineThingModel(thingModel);
+        }
+        thingModelData.save(thingModel);
     }
 
     @PostMapping("/thingModel/{productKey}/delete")
     public void deleteThingModel(String productKey) {
-        productKey = getProduct(productKey).getId();
+        checkProductOwner(productKey);
+        ThingModel thingModel = thingModelData.findByProductKey(productKey);
+        //删除时序数据库物模型数据结构
+        dbStructureData.defineThingModel(thingModel);
         thingModelData.deleteById(productKey);
     }
 
+    private void checkProductOwner(String productKey) {
+        dataOwnerService.checkOwner(productData.findById(productKey));
+    }
+
     @GetMapping("/categories")
     public List<Category> getCategories() {
         return categoryData.findAll();

+ 3 - 0
iot-standalone/src/main/java/cc/iotkit/manager/service/DeviceService.java

@@ -151,6 +151,7 @@ public class DeviceService {
             deviceComponentManager.send(thingService);
         }
         String mid = thingService.getMid();
+        DeviceInfo device = deviceInfoData.findByDeviceId(deviceId);
 
         //保存设备日志
         ThingModelMessage thingModelMessage = ThingModelMessage.builder()
@@ -158,12 +159,14 @@ public class DeviceService {
                 .deviceId(deviceId)
                 .productKey(pk)
                 .deviceName(dn)
+                .uid(device.getUid())
                 .type(type)
                 .identifier(identifier)
                 .data(data)
                 .occurred(System.currentTimeMillis())
                 .time(System.currentTimeMillis())
                 .build();
+
         thingModelMessageData.add(thingModelMessage);
 
         return mid;

+ 12 - 10
iot-standalone/src/main/java/cc/iotkit/manager/service/ExampleDataInit.java

@@ -28,6 +28,7 @@ import cc.iotkit.model.rule.TaskInfo;
 import cc.iotkit.model.space.Home;
 import cc.iotkit.model.space.Space;
 import cc.iotkit.model.space.SpaceDevice;
+import cc.iotkit.temporal.IDbStructureData;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.google.common.base.Charsets;
 import lombok.extern.slf4j.Slf4j;
@@ -35,10 +36,8 @@ import org.apache.commons.io.FileUtils;
 import org.springframework.beans.factory.SmartInitializingSingleton;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.PostConstruct;
 import java.io.File;
 import java.io.IOException;
 import java.util.List;
@@ -82,11 +81,8 @@ public class ExampleDataInit implements SmartInitializingSingleton {
     private IUserInfoData userInfoData;
     @Autowired
     private IVirtualDeviceData virtualDeviceData;
-
-
     @Autowired
-    private ElasticsearchRestTemplate restTemplate;
-
+    private IDbStructureData dbStructureData;
 
     @Override
     public void afterSingletonsInstantiated() {
@@ -127,8 +123,13 @@ public class ExampleDataInit implements SmartInitializingSingleton {
                     });
                     initData("taskInfo", taskInfoData, new TypeReference<List<TaskInfo>>() {
                     });
-                    initData("thingModel", thingModelData, new TypeReference<List<ThingModel>>() {
+                    List<ThingModel> thingModels = initData("thingModel", thingModelData, new TypeReference<>() {
                     });
+                    //初始化物模型时序数据结构
+                    for (ThingModel thingModel : thingModels) {
+                        dbStructureData.defineThingModel(thingModel);
+                    }
+
                     initData("userInfo", userInfoData, new TypeReference<List<UserInfo>>() {
                     });
                     initData("virtualDevice", virtualDeviceData, new TypeReference<List<VirtualDevice>>() {
@@ -146,13 +147,14 @@ public class ExampleDataInit implements SmartInitializingSingleton {
 
     }
 
-    private <T> void initData(String name, ICommonData service, TypeReference<T> type) throws IOException {
+    private <T> T initData(String name, ICommonData service, TypeReference<T> type) throws IOException {
         log.info("init {} data...", name);
         String json = FileUtils.readFileToString(new File("./data/init/" + name + ".json"), Charsets.UTF_8);
-        List<T> list = (List<T>) JsonUtil.parse(json, type);
-        for (T obj : list) {
+        List list = (List) JsonUtil.parse(json, type);
+        for (Object obj : list) {
             service.add((Id) obj);
         }
+        return (T) list;
     }
 
 }

+ 46 - 31
iot-standalone/src/main/resources/application-dev.yml

@@ -8,22 +8,23 @@ spring:
       max-file-size: 10MB
       max-request-size: 12MB
 
+  #注: 切换数据库时需要将项目根目录中的.init文件删除再重启
   # <<=======内置H2数据库连接设置开始==========
   jpa:
-    #show-sql: true
+    #    show-sql: true
     hibernate:
       ddl-auto: update
     properties:
       hibernate:
         format_sql: true
+
   datasource:
     url: jdbc:h2:./data/iotkit;MODE=MySQL
     username: sa
     password: 123456
     driverClassName: org.h2.Driver
 
-  #注: 切换数据库时需要将项目根目录中的.init文件删除再重启
-  ## 内置h2 web console设置
+    # 内置h2 web console设置
     platform: h2
   h2:
     console:
@@ -31,37 +32,51 @@ spring:
       path: /h2
       settings:
         web-allow-others: true
-  #  =======内置H2数据库连接设置结束==========>>
+  #=======内置H2数据库连接设置结束==========>>
+
 
   # <<==========mysql配置开始==============
-#  datasource:
-#    url: jdbc:mysql://127.0.0.1:3306/iotkit?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
-#    driverClassName: com.mysql.cj.jdbc.Driver
-#    username: root
-#    password: 123456
-#    validationQuery: SELECT 1
-#    testOnBorrow: true
-#  jpa:
-#    database: MySQL
-#    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
-##    show-sql: true
-#    hibernate:
-#      ddl-auto: update
-#    properties:
-#      hibernate:
-#        format_sql: true
+  #  datasource:
+  #    url: jdbc:mysql://127.0.0.1:3306/iotkit?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
+  #    driverClassName: com.mysql.cj.jdbc.Driver
+  #    username: root
+  #    password: 123456
+  #    validationQuery: SELECT 1
+  #    testOnBorrow: true
+  #  jpa:
+  #    database: MySQL
+  #    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
+  ##    show-sql: true
+  #    hibernate:
+  #      ddl-auto: update
+  #    properties:
+  #      hibernate:
+  #        format_sql: true
   # ============mysql配置结束============>>
 
-  elasticsearch:
-    rest:
-      #使用内置es的配置
-      uris: http://127.0.0.1:9200
-      username:
-      password:
-      connection-timeout: 10s
+  #<<================es时序数据配置开始===============
+  #  elasticsearch:
+  #    rest:
+  #      #使用内置es的配置
+  #      #uris: http://elasticsearch:9200
+  #      uris: http://127.0.0.1:9200
+  #      username:
+  #      password:
+  #      connection-timeout: 10s
+  #================es时序数据配置结束===============>>
+
+  #<<===========tdengine时序数据库配置开始============
+  td-datasource:
+    url: jdbc:TAOS-RS://127.0.0.1:6041/iotkit?timezone=UTC-8&charset=UTF-8&locale=en_US.UTF-8
+    username: root
+    password: taosdata
+    driverClassName: com.taosdata.jdbc.rs.RestfulDriver
+  #===========tdengine时序数据库配置开始============>>
+
 
   redis:
     #使用内置redis的配置
+    #host: redis
     host: 127.0.0.1
     port: 6379
     database: 0
@@ -73,10 +88,10 @@ spring:
 
 #图片存储用的是阿里云oss,如果需要上传产品图片才需要配置
 aliyun:
-  bucketId: iotkit-img
-  endpoint: oss-cn-shenzhen.aliyuncs.com
-  accessKeyId: 填写阿里云accessKeyId
-  accessKeySecret: 填写阿里云accessKeySecret
+  bucketId:
+  endpoint:
+  accessKeyId:
+  accessKeySecret:
 
 sa-token:
   # token名称 (同时也是cookie名称)

+ 18 - 5
iot-standalone/src/main/resources/application-mysql.yml

@@ -20,7 +20,7 @@ spring:
   jpa:
     database: MySQL
     database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
-#    show-sql: true
+  #    show-sql: true
     hibernate:
       ddl-auto: update
     properties:
@@ -28,16 +28,29 @@ spring:
         format_sql: true
   # ============mysql配置结束============>>
 
+  #<<================es时序数据配置开始===============
   elasticsearch:
     rest:
       #使用内置es的配置
+      #uris: http://elasticsearch:9200
       uris: http://127.0.0.1:9200
       username:
       password:
       connection-timeout: 10s
+  #================es时序数据配置结束===============>>
+
+  #<<===========tdengine时序数据库配置开始============
+#  td-datasource:
+#    url: jdbc:TAOS-RS://127.0.0.1:6041/iotkit?timezone=UTC-8&charset=UTF-8&locale=en_US.UTF-8
+#    username: root
+#    password: taosdata
+#    driverClassName: com.taosdata.jdbc.rs.RestfulDriver
+  #===========tdengine时序数据库配置开始============>>
+
 
   redis:
     #使用内置redis的配置
+    #host: redis
     host: 127.0.0.1
     port: 6379
     database: 0
@@ -49,10 +62,10 @@ spring:
 
 #图片存储用的是阿里云oss,如果需要上传产品图片才需要配置
 aliyun:
-  bucketId: iotkit-img
-  endpoint: oss-cn-shenzhen.aliyuncs.com
-  accessKeyId: 填写阿里云accessKeyId
-  accessKeySecret: 填写阿里云accessKeySecret
+  bucketId:
+  endpoint:
+  accessKeyId:
+  accessKeySecret:
 
 sa-token:
   # token名称 (同时也是cookie名称)

+ 15 - 2
iot-standalone/src/main/resources/application.yml

@@ -17,13 +17,14 @@ spring:
     properties:
       hibernate:
         format_sql: true
+
   datasource:
     url: jdbc:h2:./data/iotkit;MODE=MySQL
     username: sa
     password: 123456
     driverClassName: org.h2.Driver
 
-  ## 内置h2 web console设置
+  # 内置h2 web console设置
     platform: h2
   h2:
     console:
@@ -31,7 +32,8 @@ spring:
       path: /h2
       settings:
         web-allow-others: true
-#  =======内置H2数据库连接设置结束==========>>
+  #=======内置H2数据库连接设置结束==========>>
+
 
   # <<==========mysql配置开始==============
 #  datasource:
@@ -52,6 +54,7 @@ spring:
 #        format_sql: true
   # ============mysql配置结束============>>
 
+  #<<================es时序数据配置开始===============
   elasticsearch:
     rest:
       #使用内置es的配置
@@ -60,6 +63,16 @@ spring:
       username:
       password:
       connection-timeout: 10s
+  #================es时序数据配置结束===============>>
+
+  #<<===========tdengine时序数据库配置开始============
+#  td-datasource:
+#    url: jdbc:TAOS-RS://127.0.0.1:6041/iotkit?timezone=UTC-8&charset=UTF-8&locale=en_US.UTF-8
+#    username: root
+#    password: taosdata
+#    driverClassName: com.taosdata.jdbc.rs.RestfulDriver
+  #===========tdengine时序数据库配置开始============>>
+
 
   redis:
     #使用内置redis的配置

+ 1 - 1
iot-test-tool/iot-test-mqtt/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iot-test-tool</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
iot-test-tool/iot-test-mqtt/src/main/java/cc/iotkit/test/mqtt/performance/ReportTest.java

@@ -78,7 +78,7 @@ public class ReportTest {
                                 Request request = new Request();
                                 request.setId(UUID.randomUUID().toString());
                                 Map<String, Object> param = new HashMap<>();
-                                param.put("volt", Math.round(Math.random()*100));
+                                param.put("volt", Math.round(Math.random() * 100));
                                 request.setParams(param);
                                 return request;
                             });

+ 1 - 1
iot-test-tool/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>pom</packaging>

+ 1 - 1
iot-virtual-device/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>iotkit-parent</artifactId>
         <groupId>cc.iotkit</groupId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 8 - 1
pom.xml

@@ -14,6 +14,7 @@
         <module>iot-message-bus</module>
         <module>iot-test-tool</module>
         <module>iot-data</module>
+        <module>iot-data/iot-td-temporal-service</module>
     </modules>
     <parent>
         <groupId>org.springframework.boot</groupId>
@@ -24,7 +25,7 @@
 
     <groupId>cc.iotkit</groupId>
     <artifactId>iotkit-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.4.1-SNAPSHOT</version>
     <name>iotkit-parent</name>
     <description>iotkit parent</description>
     <properties>
@@ -292,6 +293,12 @@
                 <version>${project.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>cc.iotkit</groupId>
+                <artifactId>iot-td-temporal-service</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
             <dependency>
                 <groupId>cc.iotkit</groupId>
                 <artifactId>iot-data-cache</artifactId>