!1296 【功能新增】IoT: 规则场景

Merge pull request !1296 from puhui999/iot
This commit is contained in:
芋道源码 2025-03-23 01:03:19 +00:00 committed by Gitee
commit 35dd91d6c9
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
28 changed files with 649 additions and 388 deletions

View File

@ -72,4 +72,7 @@ public interface ErrorCodeConstants {
// ========== IoT 数据桥梁 1-050-010-000 ==========
ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在");
// ========== IoT 规则场景场景联动 1-050-011-000 ==========
ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_011_000, "IoT 规则场景(场景联动)不存在");
}

View File

@ -50,7 +50,7 @@ public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayVa
/**
* Spring 表达式 - 目标值数组
*/
public static final String SPRING_EXPRESSION_VALUE_List = "values";
public static final String SPRING_EXPRESSION_VALUE_LIST = "values";
public static IotRuleSceneTriggerConditionParameterOperatorEnum operatorOf(String operator) {
return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values());

View File

@ -1,13 +1,24 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - IoT 规则场景")
@RestController
@ -18,6 +29,47 @@ public class IotRuleSceneController {
@Resource
private IotRuleSceneService ruleSceneService;
@PostMapping("/create")
@Operation(summary = "创建规则场景(场景联动)")
@PreAuthorize("@ss.hasPermission('iot:rule-scene:create')")
public CommonResult<Long> createRuleScene(@Valid @RequestBody IotRuleSceneSaveReqVO createReqVO) {
return success(ruleSceneService.createRuleScene(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新规则场景(场景联动)")
@PreAuthorize("@ss.hasPermission('iot:rule-scene:update')")
public CommonResult<Boolean> updateRuleScene(@Valid @RequestBody IotRuleSceneSaveReqVO updateReqVO) {
ruleSceneService.updateRuleScene(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除规则场景(场景联动)")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:rule-scene:delete')")
public CommonResult<Boolean> deleteRuleScene(@RequestParam("id") Long id) {
ruleSceneService.deleteRuleScene(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得规则场景(场景联动)")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:rule-scene:query')")
public CommonResult<IotRuleSceneRespVO> getRuleScene(@RequestParam("id") Long id) {
IotRuleSceneDO ruleScene = ruleSceneService.getRuleScene(id);
return success(BeanUtils.toBean(ruleScene, IotRuleSceneRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得规则场景(场景联动)分页")
@PreAuthorize("@ss.hasPermission('iot:rule-scene:query')")
public CommonResult<PageResult<IotRuleSceneRespVO>> getRuleScenePage(@Valid IotRuleScenePageReqVO pageReqVO) {
PageResult<IotRuleSceneDO> pageResult = ruleSceneService.getRuleScenePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, IotRuleSceneRespVO.class));
}
@GetMapping("/test")
@PermitAll
public void test() {

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - IoT 规则场景(场景联动)分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class IotRuleScenePageReqVO extends PageParam {
@Schema(description = "场景名称", example = "赵六")
private String name;
@Schema(description = "场景描述", example = "你猜")
private String description;
@Schema(description = "场景状态", example = "1")
private Integer status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneActionConfig;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneTriggerConfig;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - IoT 规则场景(场景联动) Response VO")
@Data
public class IotRuleSceneRespVO {
@Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15865")
private Long id;
@Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
private String name;
@Schema(description = "场景描述", example = "你猜")
private String description;
@Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status;
@Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
private List<IotRuleSceneTriggerConfig> triggers;
@Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
private List<IotRuleSceneActionConfig> actions;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneActionConfig;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneTriggerConfig;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - IoT 规则场景(场景联动)新增/修改 Request VO")
@Data
public class IotRuleSceneSaveReqVO {
@Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15865")
private Long id;
@Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
@NotEmpty(message = "场景名称不能为空")
private String name;
@Schema(description = "场景描述", example = "你猜")
private String description;
@Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "场景状态不能为空")
@InEnum(CommonStatusEnum.class)
private Integer status;
@Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "触发器数组不能为空")
private List<IotRuleSceneTriggerConfig> triggers;
@Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "执行器数组不能为空")
private List<IotRuleSceneActionConfig> actions;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
import lombok.Data;
/**
* 执行器配置
*
* @author 芋道源码
*/
@Data
public class IotRuleSceneActionConfig {
/**
* 执行类型
*
* 枚举 {@link IotRuleSceneActionTypeEnum}
*/
private Integer type;
/**
* 设备控制
*
* 必填 {@link #type} {@link IotRuleSceneActionTypeEnum#DEVICE_CONTROL}
*/
private IotRuleSceneActionDeviceControl deviceControl;
/**
* 数据桥接编号
*
* 必填 {@link #type} {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE}
* 关联{@link IotDataBridgeDO#getId()}
*/
private Long dataBridgeId;
}

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* 执行设备控制
*
* @author 芋道源码
*/
@Data
public class IotRuleSceneActionDeviceControl {
/**
* 产品标识
*
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
/**
* 设备名称数组
*
* 关联 {@link IotDeviceDO#getDeviceName()}
*/
private List<String> deviceNames;
/**
* 消息类型
*
* 枚举 {@link IotDeviceMessageTypeEnum#PROPERTY}{@link IotDeviceMessageTypeEnum#SERVICE}
*/
private String type;
/**
* 消息标识符
*
* 枚举 {@link IotDeviceMessageIdentifierEnum}
*
* 1. 属性设置对应 {@link IotDeviceMessageIdentifierEnum#PROPERTY_SET}
* 2. 服务调用对应 {@link IotDeviceMessageIdentifierEnum#SERVICE_INVOKE}
*/
private String identifier;
/**
* 具体数据
*
* 1. 属性设置 {@link #type} {@link IotDeviceMessageTypeEnum#PROPERTY} 对应 properties
* 2. 服务调用 {@link #type} {@link IotDeviceMessageTypeEnum#SERVICE} 对应 params
*/
private Map<String, Object> data;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
import lombok.Data;
import java.util.List;
/**
* 触发条件
*
* @author 芋道源码
*/
@Data
public class IotRuleSceneTriggerCondition {
/**
* 消息类型
*
* 枚举 {@link IotDeviceMessageTypeEnum}
*/
private String type;
/**
* 消息标识符
*
* 枚举 {@link IotDeviceMessageIdentifierEnum}
*/
private String identifier;
/**
* 参数数组
*
* 参数与参数之间的关系
*/
private List<IotRuleSceneTriggerConditionParameter> parameters;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum;
import lombok.Data;
/**
* 触发条件参数
*
* @author 芋道源码
*/
@Data
public class IotRuleSceneTriggerConditionParameter {
/**
* 标识符属性事件服务
*
* 关联 {@link IotThingModelDO#getIdentifier()}
*/
private String identifier;
/**
* 操作符
*
* 枚举 {@link IotRuleSceneTriggerConditionParameterOperatorEnum}
*/
private String operator;
/**
* 比较值
*
* 如果有多个值则使用 "," 分隔类似 "1,2,3"
* 例如说{@link IotRuleSceneTriggerConditionParameterOperatorEnum#IN}{@link IotRuleSceneTriggerConditionParameterOperatorEnum#BETWEEN}
*/
private String value;
}

View File

@ -0,0 +1,53 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
import lombok.Data;
import java.util.List;
/**
* 触发器配置
*
* @author 芋道源码
*/
@Data
public class IotRuleSceneTriggerConfig {
/**
* 触发类型
*
* 枚举 {@link IotRuleSceneTriggerTypeEnum}
*/
private Integer type;
/**
* 产品标识
*
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
/**
* 设备名称数组
*
* 关联 {@link IotDeviceDO#getDeviceName()}
*/
private List<String> deviceNames;
/**
* 触发条件数组
*
* 必填 {@link #type} {@link IotRuleSceneTriggerTypeEnum#DEVICE}
* 条件与条件之间的关系
*/
private List<IotRuleSceneTriggerCondition> conditions;
/**
* CRON 表达式
*
* 必填 {@link #type} {@link IotRuleSceneTriggerTypeEnum#TIMER}
*/
private String cronExpression;
}

View File

@ -174,8 +174,7 @@ GET {{baseUrl}}/iot/product-thing-model/get?id=67
tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
### 请求 /iot/product-thing-model/list-by-product-id 接口 => 成功
GET {{baseUrl}}/iot/product-thing-model/list-by-product-id?productId=1001
### 请求 /iot/product-thing-model/tsl-by-product-id 接口 => 成功
GET {{baseUrl}}/iot/product-thing-model/tsl-by-product-id?productId=1001
tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}

View File

@ -3,10 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelListReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
import io.swagger.v3.oas.annotations.Operation;
@ -64,13 +61,12 @@ public class IotThingModelController {
return success(BeanUtils.toBean(thingModel, IotThingModelRespVO.class));
}
@GetMapping("/list-by-product-id")
@Operation(summary = "获得产品物模型")
@GetMapping("/tsl-by-product-id")
@Operation(summary = "获得产品物模型 TSL")
@Parameter(name = "productId", description = "产品ID", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:thing-model:query')")
public CommonResult<List<IotThingModelRespVO>> getThingModelListByProductId(@RequestParam("productId") Long productId) {
List<IotThingModelDO> list = thingModelService.getThingModelListByProductId(productId);
return success(BeanUtils.toBean(list, IotThingModelRespVO.class));
public CommonResult<IotThingModelTSLRespVO> getThingModelTslByProductId(@RequestParam("productId") Long productId) {
return success(thingModelService.getThingModelTslByProductId(productId));
}
// TODO @puhui @supergetThingModelListByProductId getThingModelListByProductId 可以融合么

View File

@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -12,18 +10,15 @@ import java.time.LocalDateTime;
@Schema(description = "管理后台 - IoT 产品物模型 Response VO")
@Data
@ExcelIgnoreUnannotated
public class IotThingModelRespVO {
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816")
@ExcelProperty("产品ID")
private Long id;
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long productId;
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature_sensor")
@ExcelProperty("产品标识")
private String productKey;
@Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
@ -48,7 +43,6 @@ public class IotThingModelRespVO {
private ThingModelService service;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - IoT 产品物模型 TSL Response VO")
@Data
public class IotThingModelTSLRespVO {
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long productId;
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature_sensor")
private String productKey;
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
private List<ThingModelProperty> properties;
@Schema(description = "服务列表", requiredMode = Schema.RequiredMode.REQUIRED)
private List<ThingModelEvent> events;
@Schema(description = "事件列表", requiredMode = Schema.RequiredMode.REQUIRED)
private List<ThingModelService> services;
}

View File

@ -1,112 +0,0 @@
### 请求 /iot/think-model-function/create 接口 => 成功
POST {{baseUrl}}/iot/think-model-function/create
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
{
"productId": 1001,
"productKey": "smart-sensor-001",
"identifier": "Temperature",
"name": "温度",
"description": "当前温度值",
"type": 1,
"property": {
"identifier": "Temperature",
"name": "温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": -10.0,
"max": 100.0,
"step": 0.1,
"unit": "℃"
}
},
"description": "当前温度值"
}
}
### 请求 /iot/think-model-function/create 接口 => 成功
POST {{baseUrl}}/iot/think-model-function/create
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
{
"productId": 1001,
"productKey": "smart-sensor-001",
"identifier": "Humidity",
"name": "湿度",
"description": "当前湿度值",
"type": 1,
"property": {
"identifier": "Humidity",
"name": "湿度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": 0.0,
"max": 100.0,
"step": 0.1,
"unit": "%"
}
},
"description": "当前湿度值"
}
}
### 请求 /iot/think-model-function/update 接口 => 成功
PUT {{baseUrl}}/iot/think-model-function/update
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
{
"id": 11,
"productId": 1001,
"productKey": "smart-sensor-001",
"identifier": "Temperature",
"name": "温度",
"description": "当前温度值",
"type": 1,
"property": {
"identifier": "Temperature",
"name": "温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": -111.0,
"max": 222.0,
"step": 0.1,
"unit": "℃"
}
},
"description": "当前温度值"
}
}
### 请求 /iot/think-model-function/delete 接口 => 成功
DELETE {{baseUrl}}/iot/think-model-function/delete?id=7
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
### 请求 /iot/think-model-function/get 接口 => 成功
GET {{baseUrl}}/iot/think-model-function/get?id=10
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
### 请求 /iot/think-model-function/list-by-product-id 接口 => 成功
GET {{baseUrl}}/iot/think-model-function/list-by-product-id?productId=1001
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}

View File

@ -1,23 +1,19 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.rule;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneActionConfig;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneTriggerConfig;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
/**
* IoT 规则场景场景联动 DO
@ -56,188 +52,12 @@ public class IotRuleSceneDO extends TenantBaseDO {
* 触发器数组
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<TriggerConfig> triggers;
private List<IotRuleSceneTriggerConfig> triggers;
/**
* 执行器数组
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<ActionConfig> actions;
/**
* 触发器配置
*/
@Data
public static class TriggerConfig {
/**
* 触发类型
*
* 枚举 {@link IotRuleSceneTriggerTypeEnum}
*/
private Integer type;
/**
* 产品标识
*
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
/**
* 设备名称数组
*
* 关联 {@link IotDeviceDO#getDeviceName()}
*/
private List<String> deviceNames;
/**
* 触发条件数组
*
* 必填 {@link #type} {@link IotRuleSceneTriggerTypeEnum#DEVICE}
* 条件与条件之间的关系
*/
private List<TriggerCondition> conditions;
/**
* CRON 表达式
*
* 必填 {@link #type} {@link IotRuleSceneTriggerTypeEnum#TIMER}
*/
private String cronExpression;
}
/**
* 触发条件
*/
@Data
public static class TriggerCondition {
/**
* 消息类型
*
* 枚举 {@link IotDeviceMessageTypeEnum}
*/
private String type;
/**
* 消息标识符
*
* 枚举 {@link IotDeviceMessageIdentifierEnum}
*/
private String identifier;
/**
* 参数数组
*
* 参数与参数之间的关系
*/
private List<TriggerConditionParameter> parameters;
}
/**
* 触发条件参数
*/
@Data
public static class TriggerConditionParameter {
/**
* 标识符属性事件服务
*
* 关联 {@link IotThingModelDO#getIdentifier()}
*/
private String identifier;
/**
* 操作符
*
* 枚举 {@link IotRuleSceneTriggerConditionParameterOperatorEnum}
*/
private String operator;
/**
* 比较值
*
* 如果有多个值则使用 "," 分隔类似 "1,2,3"
* 例如说{@link IotRuleSceneTriggerConditionParameterOperatorEnum#IN}{@link IotRuleSceneTriggerConditionParameterOperatorEnum#BETWEEN}
*/
private String value;
}
/**
* 执行器配置
*/
@Data
public static class ActionConfig {
/**
* 执行类型
*
* 枚举 {@link IotRuleSceneActionTypeEnum}
*/
private Integer type;
/**
* 设备控制
*
* 必填 {@link #type} {@link IotRuleSceneActionTypeEnum#DEVICE_CONTROL}
*/
private ActionDeviceControl deviceControl;
/**
* 数据桥接编号
*
* 必填 {@link #type} {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE}
* 关联{@link IotDataBridgeDO#getId()}
*/
private Long dataBridgeId;
}
/**
* 执行设备控制
*/
@Data
public static class ActionDeviceControl {
/**
* 产品标识
*
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
/**
* 设备名称数组
*
* 关联 {@link IotDeviceDO#getDeviceName()}
*/
private List<String> deviceNames;
/**
* 消息类型
*
* 枚举 {@link IotDeviceMessageTypeEnum#PROPERTY}{@link IotDeviceMessageTypeEnum#SERVICE}
*/
private String type;
/**
* 消息标识符
*
* 枚举 {@link IotDeviceMessageIdentifierEnum}
*
* 1. 属性设置对应 {@link IotDeviceMessageIdentifierEnum#PROPERTY_SET}
* 2. 服务调用对应 {@link IotDeviceMessageIdentifierEnum#SERVICE_INVOKE}
*/
private String identifier;
/**
* 具体数据
*
* 1. 属性设置 {@link #type} {@link IotDeviceMessageTypeEnum#PROPERTY} 对应 properties
* 2. 服务调用 {@link #type} {@link IotDeviceMessageTypeEnum#SERVICE} 对应 params
*/
private Map<String, Object> data;
}
private List<IotRuleSceneActionConfig> actions;
}

View File

@ -1,10 +1,27 @@
package cn.iocoder.yudao.module.iot.dal.mysql.rule;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
import org.apache.ibatis.annotations.Mapper;
/**
* IoT 规则场景场景联动 Mapper
*
* @author HUIHUI
*/
@Mapper
public interface IotRuleSceneMapper extends BaseMapperX<IotRuleSceneDO> {
default PageResult<IotRuleSceneDO> selectPage(IotRuleScenePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<IotRuleSceneDO>()
.likeIfPresent(IotRuleSceneDO::getName, reqVO.getName())
.likeIfPresent(IotRuleSceneDO::getDescription, reqVO.getDescription())
.eqIfPresent(IotRuleSceneDO::getStatus, reqVO.getStatus())
.betweenIfPresent(IotRuleSceneDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(IotRuleSceneDO::getId));
}
}

View File

@ -1,8 +1,12 @@
package cn.iocoder.yudao.module.iot.service.rule;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
import jakarta.validation.Valid;
import java.util.List;
@ -13,6 +17,44 @@ import java.util.List;
*/
public interface IotRuleSceneService {
/**
* 创建规则场景场景联动
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createRuleScene(@Valid IotRuleSceneSaveReqVO createReqVO);
/**
* 更新规则场景场景联动
*
* @param updateReqVO 更新信息
*/
void updateRuleScene(@Valid IotRuleSceneSaveReqVO updateReqVO);
/**
* 删除规则场景场景联动
*
* @param id 编号
*/
void deleteRuleScene(Long id);
/**
* 获得规则场景场景联动
*
* @param id 编号
* @return 规则场景场景联动
*/
IotRuleSceneDO getRuleScene(Long id);
/**
* 获得规则场景场景联动分页
*
* @param pageReqVO 分页查询
* @return 规则场景场景联动分页
*/
PageResult<IotRuleSceneDO> getRuleScenePage(IotRuleScenePageReqVO pageReqVO);
/**
* 缓存获得指定设备的场景列表
*

View File

@ -8,11 +8,16 @@ import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
@ -39,8 +44,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.RULE_SCENE_NOT_EXISTS;
/**
* IoT 规则场景 Service 实现类
@ -61,6 +68,49 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
@Resource(name = "iotSchedulerManager")
private IotSchedulerManager schedulerManager;
@Override
public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) {
// 插入
IotRuleSceneDO ruleScene = BeanUtils.toBean(createReqVO, IotRuleSceneDO.class);
ruleSceneMapper.insert(ruleScene);
// 返回
return ruleScene.getId();
}
@Override
public void updateRuleScene(IotRuleSceneSaveReqVO updateReqVO) {
// 校验存在
validateRuleSceneExists(updateReqVO.getId());
// 更新
IotRuleSceneDO updateObj = BeanUtils.toBean(updateReqVO, IotRuleSceneDO.class);
ruleSceneMapper.updateById(updateObj);
}
@Override
public void deleteRuleScene(Long id) {
// 校验存在
validateRuleSceneExists(id);
// 删除
ruleSceneMapper.deleteById(id);
}
private void validateRuleSceneExists(Long id) {
if (ruleSceneMapper.selectById(id) == null) {
throw exception(RULE_SCENE_NOT_EXISTS);
}
}
@Override
public IotRuleSceneDO getRuleScene(Long id) {
return ruleSceneMapper.selectById(id);
}
@Override
public PageResult<IotRuleSceneDO> getRuleScenePage(IotRuleScenePageReqVO pageReqVO) {
return ruleSceneMapper.selectPage(pageReqVO);
}
// TODO 芋艿缓存待实现
@Override
@TenantIgnore // 忽略租户隔离因为 IotRuleSceneMessageHandler 调用时一般未传递租户所以需要忽略
@ -68,82 +118,82 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
if (true) {
IotRuleSceneDO ruleScene01 = new IotRuleSceneDO();
ruleScene01.setTriggers(CollUtil.newArrayList());
IotRuleSceneDO.TriggerConfig trigger01 = new IotRuleSceneDO.TriggerConfig();
IotRuleSceneTriggerConfig trigger01 = new IotRuleSceneTriggerConfig();
trigger01.setType(IotRuleSceneTriggerTypeEnum.DEVICE.getType());
trigger01.setConditions(CollUtil.newArrayList());
// 属性
IotRuleSceneDO.TriggerCondition condition01 = new IotRuleSceneDO.TriggerCondition();
IotRuleSceneTriggerCondition condition01 = new IotRuleSceneTriggerCondition();
condition01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
condition01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier());
condition01.setParameters(CollUtil.newArrayList());
// IotRuleSceneDO.TriggerConditionParameter parameter010 = new IotRuleSceneDO.TriggerConditionParameter();
// IotRuleSceneTriggerConditionParameter parameter010 = new IotRuleSceneTriggerConditionParameter();
// parameter010.setIdentifier("width");
// parameter010.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator());
// parameter010.setValue("abc");
// condition01.getParameters().add(parameter010);
IotRuleSceneDO.TriggerConditionParameter parameter011 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter011 = new IotRuleSceneTriggerConditionParameter();
parameter011.setIdentifier("width");
parameter011.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator());
parameter011.setValue("1");
condition01.getParameters().add(parameter011);
IotRuleSceneDO.TriggerConditionParameter parameter012 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter012 = new IotRuleSceneTriggerConditionParameter();
parameter012.setIdentifier("width");
parameter012.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS.getOperator());
parameter012.setValue("2");
condition01.getParameters().add(parameter012);
IotRuleSceneDO.TriggerConditionParameter parameter013 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter013 = new IotRuleSceneTriggerConditionParameter();
parameter013.setIdentifier("width");
parameter013.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN.getOperator());
parameter013.setValue("0");
condition01.getParameters().add(parameter013);
IotRuleSceneDO.TriggerConditionParameter parameter014 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter014 = new IotRuleSceneTriggerConditionParameter();
parameter014.setIdentifier("width");
parameter014.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator());
parameter014.setValue("0");
condition01.getParameters().add(parameter014);
IotRuleSceneDO.TriggerConditionParameter parameter015 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter015 = new IotRuleSceneTriggerConditionParameter();
parameter015.setIdentifier("width");
parameter015.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN.getOperator());
parameter015.setValue("2");
condition01.getParameters().add(parameter015);
IotRuleSceneDO.TriggerConditionParameter parameter016 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter016 = new IotRuleSceneTriggerConditionParameter();
parameter016.setIdentifier("width");
parameter016.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS.getOperator());
parameter016.setValue("2");
condition01.getParameters().add(parameter016);
IotRuleSceneDO.TriggerConditionParameter parameter017 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter017 = new IotRuleSceneTriggerConditionParameter();
parameter017.setIdentifier("width");
parameter017.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.IN.getOperator());
parameter017.setValue("1,2,3");
condition01.getParameters().add(parameter017);
IotRuleSceneDO.TriggerConditionParameter parameter018 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter018 = new IotRuleSceneTriggerConditionParameter();
parameter018.setIdentifier("width");
parameter018.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_IN.getOperator());
parameter018.setValue("0,2,3");
condition01.getParameters().add(parameter018);
IotRuleSceneDO.TriggerConditionParameter parameter019 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter019 = new IotRuleSceneTriggerConditionParameter();
parameter019.setIdentifier("width");
parameter019.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN.getOperator());
parameter019.setValue("1,3");
condition01.getParameters().add(parameter019);
IotRuleSceneDO.TriggerConditionParameter parameter020 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter020 = new IotRuleSceneTriggerConditionParameter();
parameter020.setIdentifier("width");
parameter020.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN.getOperator());
parameter020.setValue("2,3");
condition01.getParameters().add(parameter020);
trigger01.getConditions().add(condition01);
// 状态
IotRuleSceneDO.TriggerCondition condition02 = new IotRuleSceneDO.TriggerCondition();
IotRuleSceneTriggerCondition condition02 = new IotRuleSceneTriggerCondition();
condition02.setType(IotDeviceMessageTypeEnum.STATE.getType());
condition02.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier());
condition02.setParameters(CollUtil.newArrayList());
trigger01.getConditions().add(condition02);
// 事件
IotRuleSceneDO.TriggerCondition condition03 = new IotRuleSceneDO.TriggerCondition();
IotRuleSceneTriggerCondition condition03 = new IotRuleSceneTriggerCondition();
condition03.setType(IotDeviceMessageTypeEnum.EVENT.getType());
condition03.setIdentifier("xxx");
condition03.setParameters(CollUtil.newArrayList());
IotRuleSceneDO.TriggerConditionParameter parameter030 = new IotRuleSceneDO.TriggerConditionParameter();
IotRuleSceneTriggerConditionParameter parameter030 = new IotRuleSceneTriggerConditionParameter();
parameter030.setIdentifier("width");
parameter030.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator());
parameter030.setValue("1");
@ -152,21 +202,21 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
// 动作
ruleScene01.setActions(CollUtil.newArrayList());
// 设备控制
IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig();
IotRuleSceneActionConfig action01 = new IotRuleSceneActionConfig();
action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType());
IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl();
actionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT");
actionDeviceControl01.setDeviceNames(ListUtil.of("small"));
actionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
actionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());
actionDeviceControl01.setData(MapUtil.<String, Object>builder()
IotRuleSceneActionDeviceControl iotRuleSceneActionDeviceControl01 = new IotRuleSceneActionDeviceControl();
iotRuleSceneActionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT");
iotRuleSceneActionDeviceControl01.setDeviceNames(ListUtil.of("small"));
iotRuleSceneActionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
iotRuleSceneActionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());
iotRuleSceneActionDeviceControl01.setData(MapUtil.<String, Object>builder()
.put("power", 1)
.put("color", "red")
.build());
action01.setDeviceControl(actionDeviceControl01);
action01.setDeviceControl(iotRuleSceneActionDeviceControl01);
// ruleScene01.getActions().add(action01); // TODO 芋艿先不测试了
// 数据桥接http
IotRuleSceneDO.ActionConfig action02 = new IotRuleSceneDO.ActionConfig();
IotRuleSceneActionConfig action02 = new IotRuleSceneActionConfig();
action02.setType(IotRuleSceneActionTypeEnum.DATA_BRIDGE.getType());
action02.setDataBridgeId(1L);
ruleScene01.getActions().add(action02);
@ -176,7 +226,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
List<IotRuleSceneDO> list = ruleSceneMapper.selectList();
// TODO @芋艿需要考虑开启状态
return filterList(list, ruleScene -> {
for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) {
for (IotRuleSceneTriggerConfig trigger : ruleScene.getTriggers()) {
if (ObjUtil.notEqual(trigger.getProductKey(), productKey)) {
continue;
}
@ -211,22 +261,22 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
IotRuleSceneDO scene = new IotRuleSceneDO().setStatus(CommonStatusEnum.ENABLE.getStatus());
if (true) {
scene.setTenantId(1L);
IotRuleSceneDO.TriggerConfig triggerConfig = new IotRuleSceneDO.TriggerConfig();
triggerConfig.setType(IotRuleSceneTriggerTypeEnum.TIMER.getType());
scene.setTriggers(ListUtil.toList(triggerConfig));
IotRuleSceneTriggerConfig iotRuleSceneTriggerConfig = new IotRuleSceneTriggerConfig();
iotRuleSceneTriggerConfig.setType(IotRuleSceneTriggerTypeEnum.TIMER.getType());
scene.setTriggers(ListUtil.toList(iotRuleSceneTriggerConfig));
// 动作
IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig();
IotRuleSceneActionConfig action01 = new IotRuleSceneActionConfig();
action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType());
IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl();
actionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT");
actionDeviceControl01.setDeviceNames(ListUtil.of("small"));
actionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
actionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());
actionDeviceControl01.setData(MapUtil.<String, Object>builder()
IotRuleSceneActionDeviceControl iotRuleSceneActionDeviceControl01 = new IotRuleSceneActionDeviceControl();
iotRuleSceneActionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT");
iotRuleSceneActionDeviceControl01.setDeviceNames(ListUtil.of("small"));
iotRuleSceneActionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
iotRuleSceneActionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());
iotRuleSceneActionDeviceControl01.setData(MapUtil.<String, Object>builder()
.put("power", 1)
.put("color", "red")
.build());
action01.setDeviceControl(actionDeviceControl01);
action01.setDeviceControl(iotRuleSceneActionDeviceControl01);
scene.setActions(ListUtil.toList(action01));
}
if (scene == null) {
@ -238,7 +288,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
return;
}
// 1.2 判断是否有定时触发器避免脏数据
IotRuleSceneDO.TriggerConfig config = CollUtil.findOne(scene.getTriggers(),
IotRuleSceneTriggerConfig config = CollUtil.findOne(scene.getTriggers(),
trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType()));
if (config == null) {
log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene);
@ -267,7 +317,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
// 2. 匹配 trigger 触发器的条件
return filterList(ruleScenes, ruleScene -> {
for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) {
for (IotRuleSceneTriggerConfig trigger : ruleScene.getTriggers()) {
// 2.1 非设备触发不匹配
if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) {
return false;
@ -278,13 +328,13 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
return false;
}
// 2.3 多个条件只需要满足一个即可
IotRuleSceneDO.TriggerCondition matchedCondition = CollUtil.findOne(trigger.getConditions(), condition -> {
IotRuleSceneTriggerCondition matchedCondition = CollUtil.findOne(trigger.getConditions(), condition -> {
if (ObjUtil.notEqual(message.getType(), condition.getType())
|| ObjUtil.notEqual(message.getIdentifier(), condition.getIdentifier())) {
return false;
}
// 多个条件参数必须全部满足所以下面的逻辑就是找到一个不满足的条件参数
IotRuleSceneDO.TriggerConditionParameter notMatchedParameter = CollUtil.findOne(condition.getParameters(),
IotRuleSceneTriggerConditionParameter notMatchedParameter = CollUtil.findOne(condition.getParameters(),
parameter -> !isTriggerConditionParameterMatched(message, parameter, ruleScene, trigger));
return notMatchedParameter == null;
});
@ -299,6 +349,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
}
// TODO @芋艿可优化可以考虑增加下单测边界太多了
/**
* 判断触发器的条件参数是否匹配
*
@ -309,8 +360,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
* @return 是否匹配
*/
@SuppressWarnings({"unchecked", "DataFlowIssue"})
private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter,
IotRuleSceneDO ruleScene, IotRuleSceneDO.TriggerConfig trigger) {
private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneTriggerConditionParameter parameter,
IotRuleSceneDO ruleScene, IotRuleSceneTriggerConfig trigger) {
// 1.1 校验操作符是否合法
IotRuleSceneTriggerConditionParameterOperatorEnum operator =
IotRuleSceneTriggerConditionParameterOperatorEnum.operatorOf(parameter.getOperator());
@ -331,7 +382,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue);
springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE, parameter.getValue());
List<String> parameterValues = StrUtil.splitTrim(parameter.getValue(), CharPool.COMMA);
springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List, parameterValues);
springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues);
// 特殊解决数字的比较因为 Spring 是基于它的 compareTo 方法对数字的比较存在问题
if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN,
IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN,
@ -345,7 +396,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
NumberUtil.parseDouble(messageValue));
springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE,
NumberUtil.parseDouble(parameter.getValue()));
springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List,
springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_LIST,
convertList(parameterValues, NumberUtil::parseDouble));
}
// 2.2 计算 Spring 表达式
@ -410,7 +461,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
schedulerManager.addOrUpdateJob(IotRuleSceneJob.class,
IotRuleSceneJob.buildJobName(id),
"0/10 * * * * ?",
jobDataMap);
jobDataMap);
}
if (false) {
Long id = 1L;

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.iot.service.rule.action;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneActionConfig;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
@ -14,15 +14,16 @@ import javax.annotation.Nullable;
public interface IotRuleSceneAction {
// TODO @芋艿groovy 或者 javascript 实现数据的转换可以考虑基于 hutool ScriptUtil
/**
* 执行场景
*
* @param message 消息允许空
* 1. 空的情况定时触发
* 2. 非空的情况设备触发
* @param config 配置
* @param config 配置
*/
void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) throws Exception;
void execute(@Nullable IotDeviceMessage message, IotRuleSceneActionConfig config) throws Exception;
/**
* 获得类型

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.iot.service.rule.action;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneActionConfig;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
import org.springframework.stereotype.Component;
@ -16,7 +16,7 @@ import javax.annotation.Nullable;
public class IotRuleSceneAlertAction implements IotRuleSceneAction {
@Override
public void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) {
public void execute(@Nullable IotDeviceMessage message, IotRuleSceneActionConfig config) {
// TODO @芋艿待实现
}

View File

@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.iot.service.rule.action;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneActionConfig;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService;
@ -29,7 +29,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction {
private List<IotDataBridgeExecute<?>> dataBridgeExecutes;
@Override
public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) throws Exception {
public void execute(IotDeviceMessage message, IotRuleSceneActionConfig config) throws Exception {
// 1.1 如果消息为空直接返回
if (message == null) {
return;

View File

@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.iot.service.rule.action;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneActionConfig;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.config.IotRuleSceneActionDeviceControl;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
@ -27,8 +28,8 @@ public class IotRuleSceneDeviceControlAction implements IotRuleSceneAction {
private IotDeviceService deviceService;
@Override
public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) {
IotRuleSceneDO.ActionDeviceControl control = config.getDeviceControl();
public void execute(IotDeviceMessage message, IotRuleSceneActionConfig config) {
IotRuleSceneActionDeviceControl control = config.getDeviceControl();
Assert.notNull(control, "设备控制配置不能为空");
// 遍历每个设备下发消息
control.getDeviceNames().forEach(deviceName -> {

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelListReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelTSLRespVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
import jakarta.validation.Valid;
@ -90,4 +91,12 @@ public interface IotThingModelService {
*/
Long getThingModelCount(LocalDateTime createTime);
/**
* 通过产品 ID 获取产品物模型 TSL
*
* @param productId 产品 ID
* @return 产品物模型 TSL
*/
IotThingModelTSLRespVO getThingModelTslByProductId(Long productId);
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.thingmodel;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
@ -13,6 +14,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelS
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelListReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelTSLRespVO;
import cn.iocoder.yudao.module.iot.convert.thingmodel.IotThingModelConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
@ -149,6 +151,30 @@ public class IotThingModelServiceImpl implements IotThingModelService {
return thingModelMapper.selectList(reqVO);
}
@Override
public IotThingModelTSLRespVO getThingModelTslByProductId(Long productId) {
IotThingModelTSLRespVO tslRespVO = new IotThingModelTSLRespVO();
// 1. 获得产品所有物模型定义
List<IotThingModelDO> thingModelList = thingModelMapper.selectListByProductId(productId);
if (CollUtil.isEmpty(thingModelList)) {
return tslRespVO;
}
// 2.1 设置公共部分参数
IotThingModelDO thingModel = thingModelList.get(0);
tslRespVO.setProductId(thingModel.getProductId()).setProductKey(thingModel.getProductKey());
// 2.2 处理属性列表
tslRespVO.setProperties(convertList(filterList(thingModelList, item ->
ObjUtil.equal(IotThingModelTypeEnum.PROPERTY.getType(), item.getType())), IotThingModelDO::getProperty));
// 2.3 处理服务列表
tslRespVO.setServices(convertList(filterList(thingModelList, item ->
ObjUtil.equal(IotThingModelTypeEnum.SERVICE.getType(), item.getType())), IotThingModelDO::getService));
// 2.4 处理事件列表
tslRespVO.setEvents(convertList(filterList(thingModelList, item ->
ObjUtil.equal(IotThingModelTypeEnum.EVENT.getType(), item.getType())), IotThingModelDO::getEvent));
return tslRespVO;
}
/**
* 校验功能是否存在
*

View File

@ -109,11 +109,11 @@
<!-- </dependency>-->
<!-- IoT 物联网相关模块。默认注释,保证编译速度 -->
<!-- <dependency>-->
<!-- <groupId>cn.iocoder.boot</groupId>-->
<!-- <artifactId>yudao-module-iot-biz</artifactId>-->
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-iot-biz</artifactId>
<version>${revision}</version>
</dependency>
<!-- spring boot 配置所需依赖 -->
<dependency>

View File

@ -76,11 +76,12 @@ spring:
validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 127.0.0.1 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
# password: dev # 密码,建议生产环境开启
data:
redis:
host: 127.0.0.1 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
# password: dev # 密码,建议生产环境开启
--- #################### 定时任务相关配置 ####################