Commit d1cb0d70d272c7ccba37eefdb8d6f8b7582915b2

Authored by xp.Huang
2 parents 846f63ff f7faa072

Merge branch '20220304' into 'master'

feat: 密码找回

See merge request huang/thingsboard3.3.2!55
1 1 package org.thingsboard.server.controller.yunteng;
2 2
  3 +import io.swagger.annotations.ApiOperation;
3 4 import lombok.RequiredArgsConstructor;
4 5 import org.springframework.util.Assert;
5   -import org.springframework.web.bind.annotation.PathVariable;
6   -import org.springframework.web.bind.annotation.PostMapping;
7   -import org.springframework.web.bind.annotation.RequestMapping;
8   -import org.springframework.web.bind.annotation.RestController;
  6 +import org.springframework.web.bind.annotation.*;
  7 +import org.thingsboard.server.common.data.exception.ThingsboardException;
  8 +import org.thingsboard.server.common.data.yunteng.dto.request.AccountReqDTO;
  9 +import org.thingsboard.server.common.data.yunteng.dto.request.SendResetPasswordEmailMsg;
  10 +import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
9 11 import org.thingsboard.server.dao.yunteng.service.YtSmsService;
  12 +import org.thingsboard.server.dao.yunteng.service.YtUserService;
10 13
11 14 import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CHINA_MOBILE_PATTERN;
12 15
... ... @@ -16,11 +19,24 @@ import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstan
16 19 public class YtNoAuthController {
17 20
18 21 private final YtSmsService smsService;
  22 + private final YtUserService userService;
19 23
20 24 @PostMapping("/sendLoginSmsCode/{phoneNumber}")
21 25 public boolean sendVerificationCode(@PathVariable("phoneNumber") String phoneNumber) {
22 26 Assert.isTrue(
23 27 CHINA_MOBILE_PATTERN.matcher(phoneNumber).matches(), "please input correct phone number");
24   - return smsService.sendLoginSmsCode(phoneNumber);
  28 + return smsService.sendSmsCode(phoneNumber, MsgTemplatePurposeEnum.FOR_LOGIN);
  29 + }
  30 +
  31 + @PostMapping("/reset/{userId}")
  32 + @ApiOperation("密码找回")
  33 + public void saveForgetPassword(@PathVariable("phoneNumber") String phoneNumber,@RequestBody AccountReqDTO forget) throws ThingsboardException {
  34 + userService.forgetPassword(phoneNumber,forget);
  35 + }
  36 +
  37 + @PostMapping("/resetCode/{phoneNumber}")
  38 + @ApiOperation("密码找回短信验证码")
  39 + public void forgetPasswordCode(@PathVariable("phoneNumber") String phoneNumber) {
  40 + smsService.sendSmsCode(phoneNumber, MsgTemplatePurposeEnum.FOR_FORGET_PASSWORD);
25 41 }
26 42 }
... ...
... ... @@ -10,6 +10,7 @@ import org.thingsboard.server.dao.yunteng.service.YtUserService;
10 10 @RestController
11 11 @RequestMapping("/api/yt/tenant")
12 12 @RequiredArgsConstructor
  13 +@Deprecated
13 14 public class YtTenantController extends BaseController {
14 15
15 16 private final YtUserService userService;
... ...
1 1 package org.thingsboard.server.common.data.yunteng.dto;
2 2
  3 +import com.fasterxml.jackson.databind.JsonNode;
3 4 import io.swagger.annotations.ApiModelProperty;
4 5 import lombok.Data;
5 6 import lombok.EqualsAndHashCode;
  7 +import org.thingsboard.common.util.JacksonUtil;
  8 +import org.thingsboard.server.common.data.DeviceProfileType;
6 9 import org.thingsboard.server.common.data.DeviceTransportType;
7 10 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
8 11 import org.thingsboard.server.common.data.yunteng.common.AddGroup;
... ... @@ -50,26 +53,39 @@ public class DeviceProfileDTO extends TenantDTO {
50 53 /**默认消息队列*/
51 54 private String defaultQueueName;
52 55
  56 + /**设备配置图片*/
  57 + private String image;
  58 + /**是否默认设备配置*/
  59 + private boolean isDefault;
  60 + private String type;
  61 +
53 62 public DeviceProfileDTO() {
54 63 }
55 64
56   - public DeviceProfileDTO(UUID id, String name, Long time, String description, DeviceTransportType transportType, UUID defaultRuleChainId) {
  65 + public DeviceProfileDTO(UUID id, String name, Long time, String description, DeviceTransportType transportType, UUID defaultRuleChainId,boolean isDefault,String image,DeviceProfileType type,Object profileData) {
57 66 setId(id.toString());
58 67 setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneOffset.UTC));
59 68 this.name = name;
  69 + this.isDefault = isDefault;
  70 + this.image = image;
60 71 this.description = description;
  72 + this.type = type.name();
61 73 this.transportType = transportType.name();
62 74 this.defaultRuleChainId = Optional.ofNullable(defaultRuleChainId).map(chainId -> chainId.toString()).orElse(null);
  75 + this.profileData = JacksonUtil.convertValue(profileData, DeviceProfileData.class);
  76 +
63 77 }
64 78
65   - public DeviceProfileDTO(UUID id, String name, Long time, String description, String convertJs, DeviceTransportType transportType, DeviceProfileData profileData, String defaultRuleChainId) {
  79 + public DeviceProfileDTO(UUID id, String name, Long time, String description, DeviceTransportType transportType, String defaultRuleChainId,boolean isDefault,String image,DeviceProfileType type, String convertJs) {
66 80 setId(id.toString());
67 81 setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneOffset.UTC));
68 82 this.name = name;
  83 + this.isDefault = isDefault;
  84 + this.image = image;
69 85 this.description = description;
  86 + this.type = type.name();
70 87 this.convertJs = convertJs;
71 88 this.transportType = transportType.name();
72 89 this.defaultRuleChainId = defaultRuleChainId.toString();
73   - this.profileData = profileData;
74 90 }
75 91 }
... ...
... ... @@ -106,9 +106,10 @@ public class YtSmsServiceImpl implements YtSmsService {
106 106 return false;
107 107 }
108 108
  109 +
109 110 @Override
110 111 @Transactional
111   - public boolean sendLoginSmsCode(String phoneNumber) {
  112 + public boolean sendSmsCode(String phoneNumber,MsgTemplatePurposeEnum purpose) {
112 113 // 检查手机号码是否存在系统,以免乱发消息
113 114 if (userMapper
114 115 .selectList(new QueryWrapper<User>().lambda().eq(User::getPhoneNumber, phoneNumber))
... ... @@ -117,7 +118,7 @@ public class YtSmsServiceImpl implements YtSmsService {
117 118 }
118 119 // 获取是否有验证码存在,防止发送数量过多
119 120 String key =
120   - MsgTemplatePurposeEnum.FOR_LOGIN.name()
  121 + purpose.name()
121 122 + DEFAULT_DELIMITER
122 123 + MessageTypeEnum.PHONE_MESSAGE.name()
123 124 + DEFAULT_DELIMITER
... ... @@ -139,7 +140,7 @@ public class YtSmsServiceImpl implements YtSmsService {
139 140 messageTemplateMapper.selectList(
140 141 new QueryWrapper<MessageTemplate>()
141 142 .lambda()
142   - .eq(MessageTemplate::getTemplatePurpose, MsgTemplatePurposeEnum.FOR_LOGIN.name())
  143 + .eq(MessageTemplate::getTemplatePurpose, purpose.name())
143 144 .eq(MessageTemplate::getMessageType, MessageTypeEnum.PHONE_MESSAGE.name()));
144 145 if (messageTemplates.isEmpty()) {
145 146 throw new YtDataValidationException("no sms provider config");
... ... @@ -152,7 +153,7 @@ public class YtSmsServiceImpl implements YtSmsService {
152 153 smsReqDTO.setParams(params);
153 154 smsReqDTO.setPhoneNumbers(phoneNumber);
154 155 smsReqDTO.setId(messageTemplate.getId());
155   - smsReqDTO.setTemplatePurpose(MsgTemplatePurposeEnum.FOR_LOGIN.name());
  156 + smsReqDTO.setTemplatePurpose(purpose.name());
156 157 if (this.sendSms(smsReqDTO)) {
157 158 cacheUtils.put(MOBILE_LOGIN_SMS_CODE, key, new CodeTTL(code, System.currentTimeMillis()));
158 159 return true;
... ...
... ... @@ -11,28 +11,34 @@ import lombok.RequiredArgsConstructor;
11 11 import lombok.extern.slf4j.Slf4j;
12 12 import org.apache.commons.lang3.RandomStringUtils;
13 13 import org.apache.commons.lang3.StringUtils;
  14 +import org.springframework.context.ApplicationEventPublisher;
14 15 import org.springframework.scheduling.annotation.Async;
15 16 import org.springframework.security.access.AccessDeniedException;
  17 +import org.springframework.security.authentication.BadCredentialsException;
16 18 import org.springframework.security.crypto.password.PasswordEncoder;
17 19 import org.springframework.stereotype.Service;
18 20 import org.springframework.transaction.annotation.Transactional;
  21 +import org.thingsboard.server.common.data.edge.EdgeEventActionType;
19 22 import org.thingsboard.server.common.data.id.EntityId;
  23 +import org.thingsboard.server.common.data.id.TenantId;
  24 +import org.thingsboard.server.common.data.id.UserId;
20 25 import org.thingsboard.server.common.data.query.TsValue;
  26 +import org.thingsboard.server.common.data.security.UserCredentials;
  27 +import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
21 28 import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
22 29 import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  30 +import org.thingsboard.server.common.data.yunteng.core.cache.CacheUtils;
23 31 import org.thingsboard.server.common.data.yunteng.core.exception.YtDataValidationException;
24 32 import org.thingsboard.server.common.data.yunteng.core.exception.NoneTenantAssetException;
25 33 import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
26 34 import org.thingsboard.server.common.data.yunteng.dto.*;
27   -import org.thingsboard.server.common.data.yunteng.dto.request.AccountReqDTO;
28   -import org.thingsboard.server.common.data.yunteng.dto.request.RoleOrOrganizationReqDTO;
29   -import org.thingsboard.server.common.data.yunteng.dto.request.SendResetPasswordEmailMsg;
30   -import org.thingsboard.server.common.data.yunteng.dto.request.SmsReqDTO;
  35 +import org.thingsboard.server.common.data.yunteng.dto.request.*;
31 36 import org.thingsboard.server.common.data.yunteng.enums.MessageTypeEnum;
32 37 import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
33 38 import org.thingsboard.server.common.data.yunteng.enums.UserStatusEnum;
34 39 import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils;
35 40 import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData;
  41 +import org.thingsboard.server.dao.user.UserService;
36 42 import org.thingsboard.server.dao.yunteng.entities.*;
37 43 import org.thingsboard.server.dao.yunteng.mapper.*;
38 44 import org.thingsboard.server.dao.yunteng.service.*;
... ... @@ -43,8 +49,9 @@ import java.util.*;
43 49 import java.util.concurrent.CompletableFuture;
44 50 import java.util.stream.Collectors;
45 51
46   -import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CHINA_MOBILE_PATTERN;
47   -import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.EMAIL_PATTERN;
  52 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.*;
  53 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CacheConfigKey.MOBILE_LOGIN_SMS_CODE;
  54 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.DEFAULT_DELIMITER;
48 55 import static org.thingsboard.server.common.data.yunteng.constant.ModelConstants.TablePropertyMapping.*;
49 56
50 57 @Service
... ... @@ -68,6 +75,10 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User>
68 75 public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s";
69 76 private final PasswordEncoder passwordEncoder;
70 77
  78 + private CacheUtils cacheUtils;
  79 + private final UserService tbUserService;
  80 + private final ApplicationEventPublisher eventPublisher;
  81 +
71 82 @Override
72 83 public List<UserDetailsDTO> findUserDetailsByUsername(String username) {
73 84 // 多个租户可能存在多个username相同的情况
... ... @@ -427,6 +438,52 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User>
427 438 }
428 439
429 440 @Override
  441 + public void forgetPassword(String phoneNumber,AccountReqDTO forget) {
  442 + String key =
  443 + MsgTemplatePurposeEnum.FOR_FORGET_PASSWORD.name()
  444 + + DEFAULT_DELIMITER
  445 + + MessageTypeEnum.PHONE_MESSAGE.name()
  446 + + DEFAULT_DELIMITER
  447 + + phoneNumber;
  448 + boolean correct =
  449 + cacheUtils
  450 + .get(MOBILE_LOGIN_SMS_CODE, key)
  451 + .map(
  452 + o -> {
  453 + CodeTTL codeTTL = (CodeTTL) o;
  454 + if (System.currentTimeMillis() - codeTTL.getSendTs() < 5 * 60 * 1000) {
  455 + return Objects.equals(codeTTL.getCode(), forget.getUserId());
  456 + } else {
  457 + return false;
  458 + }
  459 + })
  460 + .orElse(false);
  461 + if (!correct) {
  462 + throw new BadCredentialsException("验证码不正确");
  463 + }
  464 + String pwd = forget.getPassword();
  465 + if (StringUtils.isEmpty(pwd)
  466 + || StringUtils.isEmpty(forget.getResetPassword())
  467 + || !pwd.equals(forget.getResetPassword())) {
  468 + throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  469 + }
  470 +
  471 + User user = baseMapper.selectOne(new QueryWrapper<User>().lambda().eq(User::getPhoneNumber, phoneNumber));
  472 +
  473 + UserId userId = new UserId(UUID.fromString(user.getTbUser()));
  474 + UserCredentials userCredentials =
  475 + tbUserService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, userId);
  476 +
  477 + String encodePwd = passwordEncoder.encode(pwd);
  478 + userCredentials.setPassword(encodePwd);
  479 + user.setPassword(encodePwd);
  480 + tbUserService.replaceUserCredentials(new TenantId(UUID.fromString(user.getTenantId())), userCredentials);
  481 + eventPublisher.publishEvent(new UserAuthDataChangedEvent(userId));
  482 +
  483 + changePassword(user);
  484 + }
  485 +
  486 + @Override
430 487 public List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber) {
431 488 return baseMapper.findUserDetailsByPhoneNumber(phoneNumber);
432 489 }
... ... @@ -586,6 +643,11 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User>
586 643 @Override
587 644 public User validateChangePasswordAccount(AccountReqDTO accountReqDTO) {
588 645 User user = baseMapper.selectById(accountReqDTO.getUserId());
  646 + checkPassword(accountReqDTO, user);
  647 + return user;
  648 + }
  649 +
  650 + private void checkPassword(AccountReqDTO accountReqDTO, User user) {
589 651 if (null == user
590 652 || StringUtils.isEmpty(accountReqDTO.getPassword())
591 653 || StringUtils.isEmpty(accountReqDTO.getResetPassword())) {
... ... @@ -597,7 +659,6 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User>
597 659 throw new YtDataValidationException(ErrorMessage.USERNAME_PASSWORD_INCORRECT.getMessage());
598 660 }
599 661 user.setPassword(accountReqDTO.getResetPassword());
600   - return user;
601 662 }
602 663
603 664 /**
... ...
... ... @@ -30,7 +30,7 @@ import java.util.UUID;
30 30 public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEntity, UUID> {
31 31
32 32
33   - @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId) " +
  33 + @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId,d.isDefault,d.image,d.type,d.profileData) " +
34 34 "FROM DeviceProfileEntity d WHERE " +
35 35 "d.tenantId = :tenantId AND d.transportType = :transportType AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))")
36 36 Page<DeviceProfileDTO> findDeviceProfileInfos(@Param("tenantId") UUID tenantId,
... ... @@ -38,7 +38,7 @@ public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEn
38 38 @Param("transportType") DeviceTransportType transportType,
39 39 Pageable pageable);
40 40
41   - @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId) " +
  41 + @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId,d.isDefault,d.image,d.type,d.profileData) " +
42 42 "FROM DeviceProfileEntity d WHERE " +
43 43 "d.tenantId = :tenantId AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))")
44 44 Page<DeviceProfileDTO> findDeviceProfileInfos(@Param("tenantId") UUID tenantId,
... ... @@ -46,7 +46,7 @@ public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEn
46 46 Pageable pageable);
47 47
48 48
49   - @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId) " +
  49 + @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId,d.isDefault,d.image,d.type,d.profileData) " +
50 50 "FROM DeviceProfileEntity d WHERE d.tenantId = :tenantId ")
51 51 List<DeviceProfileDTO> findDeviceProfileByTenantId(@Param("tenantId") UUID tenantId);
52 52
... ...
... ... @@ -2,9 +2,16 @@ package org.thingsboard.server.dao.yunteng.service;
2 2
3 3
4 4 import org.thingsboard.server.common.data.yunteng.dto.request.SmsReqDTO;
  5 +import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
5 6
6 7 public interface YtSmsService {
7 8 boolean sendSms(SmsReqDTO smsReqDTO);
8 9
9   - boolean sendLoginSmsCode(String phoneNumber);
  10 + /**
  11 + * 推送短信验证码
  12 + * @param phoneNumber 手机号
  13 + * @param purpose 模板用途
  14 + * @return
  15 + */
  16 + boolean sendSmsCode(String phoneNumber, MsgTemplatePurposeEnum purpose);
10 17 }
... ...
... ... @@ -42,6 +42,8 @@ public interface YtUserService {
42 42
43 43 void resetPassword(String userId, boolean isPtSysadmin, String tenantId);
44 44
  45 + void forgetPassword(String phoneNumber,AccountReqDTO forget);
  46 +
45 47 List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber);
46 48
47 49 void validateUserNameAndPhoneNumberAndEmail(UserDTO userDTO);
... ...
... ... @@ -3,10 +3,8 @@
3 3 */
4 4 package org.thingsboard.rule.engine.yunteng.scene;
5 5
6   -import com.fasterxml.jackson.databind.JsonNode;
7 6 import lombok.extern.slf4j.Slf4j;
8   -import org.thingsboard.common.util.JacksonUtil;
9   -import org.thingsboard.rule.engine.action.TbAlarmResult;
  7 +import org.jetbrains.annotations.NotNull;
10 8 import org.thingsboard.rule.engine.api.TbContext;
11 9 import org.thingsboard.server.common.data.DataConstants;
12 10 import org.thingsboard.server.common.data.device.profile.AlarmCondition;
... ... @@ -14,7 +12,6 @@ import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter;
14 12 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey;
15 13 import org.thingsboard.server.common.data.rule.RuleNodeState;
16 14 import org.thingsboard.server.common.data.yunteng.dto.TriggerDTO;
17   -import org.thingsboard.server.common.data.yunteng.enums.ActionTypeEnum;
18 15 import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils;
19 16 import org.thingsboard.server.common.msg.TbMsg;
20 17 import org.thingsboard.server.common.msg.TbMsgMetaData;
... ... @@ -41,6 +38,12 @@ class ReactState {
41 38 */
42 39 private ConcurrentHashMap<String, TriggerState> triggerState = new ConcurrentHashMap<>();
43 40
  41 + /**场景联动的执行条件状态
  42 + * 键:设备主键
  43 + * 值:设备指标参与的触发器
  44 + */
  45 + private ConcurrentHashMap<String, TriggerState> conditionState = new ConcurrentHashMap<>();
  46 +
44 47
45 48
46 49
... ... @@ -71,18 +74,36 @@ class ReactState {
71 74 public void process(TbContext ctx, TbMsg msg,String deviceId) throws ExecutionException, InterruptedException {
72 75 TriggerState triggerState = getOrCreateTriggerState(deviceId);
73 76 boolean matched = false;
74   - if(triggerState != null && actions != null){
  77 + if( actions != null){
  78 + ctx.tellSuccess(msg);
  79 + }
  80 +
  81 + if(triggerState != null){
75 82 matched = triggerState.process(ctx,msg);
76 83 }
77 84
78   - if(matched){
79   - // TODO 执行条件
  85 +
  86 + if(matched && conditions != null ){
  87 + matched = false;
  88 + for(DoCondition item:conditions){
  89 + TriggerState conditionState = getOrCreateConditionState(item.getEntityId(),item.getTriggerCondition());
  90 + boolean result = false;
  91 + if( conditionState != null){
  92 + result =conditionState.process(ctx,msg);
  93 + }
  94 + if( result){
  95 + matched = true;
  96 + break;
  97 + }
  98 + }
80 99 }
81 100
82 101 if(matched){
83 102 for(DoAction item: actions){
84 103 pushMsg(ctx, msg, item);
85 104 }
  105 + }else{
  106 + ctx.tellSuccess(msg);
86 107 }
87 108
88 109 }
... ... @@ -99,18 +120,35 @@ class ReactState {
99 120 TriggerService triggerService = SpringBeanUtils.getBean(TriggerService.class);
100 121 TriggerDTO trigger =triggerService.getTrigger(reactId,deviceId);
101 122 if(trigger != null){
102   - AlarmCondition condition = trigger.getTriggerCondition();
103   - Set<AlarmConditionFilterKey> filterKeys = new HashSet<>();
104   - for(AlarmConditionFilter filter :condition.getCondition()){
105   - filterKeys.add(filter.getKey());
106   - }
107   - TriggerState state = new TriggerState(deviceId,condition, filterKeys,null);
  123 + TriggerState state = createTriggerState(deviceId, trigger.getTriggerCondition());
108 124 triggerState.put(deviceId, state);
109   - return state;
  125 + return state;
110 126 }
111 127 return null;
112 128 }
113 129
  130 + protected TriggerState getOrCreateConditionState(String deviceId,AlarmCondition condition) {
  131 + if(conditionState.containsKey(deviceId)){
  132 + return conditionState.get(deviceId);
  133 + }else{
  134 + TriggerState state = createTriggerState(deviceId, condition);
  135 + conditionState.put(deviceId, state);
  136 + return state;
  137 + }
  138 +
  139 + }
  140 +
  141 + @NotNull
  142 + private TriggerState createTriggerState(String deviceId, AlarmCondition condition) {
  143 + Set<AlarmConditionFilterKey> filterKeys = new HashSet<>();
  144 + for(AlarmConditionFilter filter :condition.getCondition()){
  145 + filterKeys.add(filter.getKey());
  146 + }
  147 + TriggerState state = new TriggerState(deviceId,condition, filterKeys,null);
  148 +
  149 + return state;
  150 + }
  151 +
114 152 private void pushMsg(TbContext ctx, TbMsg msg, DoAction action) {
115 153 TbMsgMetaData metaData = //lastMsgMetaData != null ? lastMsgMetaData.copy() :
116 154 new TbMsgMetaData();
... ...
... ... @@ -110,6 +110,7 @@ public class TbSceneReactNode implements TbNode {
110 110 @Override
111 111 public void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) {
112 112 // Cleanup the cache for all entities that are no longer assigned to current server partitions
  113 + reactStates.clear();
113 114 }
114 115
115 116 protected ReactState getOrCreateReactState(TbContext ctx, TbSceneReactNodeConfig config, String sceneId) {
... ...