增加tdengine支持

V0.5.x
xiwa 2022-08-07 00:51:10 +08:00
parent 4866c27ed9
commit 19d454697e
71 changed files with 1409 additions and 125 deletions

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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,

View File

@ -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) {

View File

@ -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);
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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() {
}
}

View File

@ -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);
}

View File

@ -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")

View File

@ -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>

View File

@ -48,6 +48,11 @@ public class ThingModelMessage {
private String deviceName;
/**
* ID
*/
private String uid;
/**
*
* lifetime:

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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

View File

@ -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>

View File

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

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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));
}
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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>

View File

@ -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();
}

View File

@ -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);
}

View File

@ -30,7 +30,7 @@ public interface IThingModelMessageData {
String identifier, int page, int size);
/**
*
*
*
* @param uid id
* @param start

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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();

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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名称)

View File

@ -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名称)

View File

@ -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的配置

View File

@ -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>

View File

@ -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;
});

View File

@ -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>

View File

@ -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>

View File

@ -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>