关于后端:如何防止设备被重复控制

42次阅读

共计 2669 个字符,预计需要花费 7 分钟才能阅读完成。

1. 引言

在一个物联网的零碎中,次要有三局部组成:云端、WiFi、电控。当用户在 APP 上管制设施时,其管制下发链路是:云端 >> WIFI >> 电控。当电控收到控制指令后,执行设施管制,管制胜利后,返回后果给云端,并将后果展现在 APP 上,其状态上报链路是:电控 >> WIFI >> 云端。

在云端和电控交互之间存在着三种指令,其别离是:

  • 控制指令:属于云端发下给电控
  • 管制返回:电控管制后,将设施的状态返回给云端
  • 定时上报:电控端会定时向云端上报本身的状态

在做设施之间联动的时候,云端只解析上报,除了存在定时上报外,当控制指令下发后,也会触发状态上报(其协定头和定时上报是同一个),因而云端只会关注上报。

然而存在一个问题,云端只解析同一种协定,如何辨别是管制的上报还是定时的上报的?


2. 场景联动实例

举个相干的例子,在冬天的时候,空调长时间开制热模式会导致空气湿度降落,可能会导致用户皮肤脱皮、流鼻血等状况产生。这时候就能够创立一个空调和加湿器联动的场景,当空调设置为制热模式的时候,就帮忙关上用户家里的加湿器,帮忙屋宇保湿。

其管制逻辑是:当用户管制空调到制热模式时,APP端通过云端下发指令到电控,电控再去管制空调的模式,当模式扭转后,会触发电控端上报,此时就会上报空调此时的状态到云端。

当空调设备的状态上报到云端后,需进行逻辑判断,如果空调状态为:开机、制热模式,云端就去管制和空调绑定的加湿器,这就实现了空调联动加湿器。

在引言中提到,设施的状态存在定时被动上报,依照之前的逻辑,会再次管制加湿器开机。但这并不合理,因为该上报的状态并不是管制产生的,因而云端需进行过滤,以此来解决反复管制设施。


3. 如何解决反复管制设施

在这部分应用 Redis 搭建一个去重逻辑:

  • 缓存第一次状态,设置过期工夫
  • 判断之后上报状态与缓存中是否统一

    • 如果统一,间接返回;
    • 如果不统一,批改缓存,管制设施。

接下来就以代码展现一下,去重逻辑。

3.1 定义一个状态状态的 BO

@Data
public class StatusPushBO {
    private String applianceId;
    private String power;
    private String mode;
}

如上所示,BO中蕴含设施id、电源、模式,用于接管电控上报的状态。

3.2 Redis 实现缓存

在这个 demo 中仍旧应用 SpringBoot 作为根底框架。

  • 引入 Redis 依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 创立一个RedisClient
public class RedisClient<T> {
    private RedisTemplate<String, T> redisTemplate;
    private ValueOperations<String, T> valueOperation;
    
    public RedisClient(RedisTemplate<String, T> redisTemplate) {
        this.redisTemplate = redisTemplate;
        this.valueOperations = redisTemplate.opsForValue();}
    
    // 通过 key 获取 redis 中 value
    public <T> T get(String key) {return this.redisTemplate.opsForValue().get(key);
    }
    
    // 判断 redis key 是否存在
    public Boolean exists(String key) {return redisTemplate.hasKey(key);
    }
    
    // 设置过期工夫
    public void setExpire(String key, long timeout, TimeUnit unit) {redisTemplate.expire(key, timeout, unit);
    }
    
    // 将数据放入 redis 中,并且设置过期工夫
    public void setex(String key, Object value, Long timeout, TimeUnit timeUnit) {redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }
}

如上建设了一个 RedisClient 类,其中蕴含四个办法:getexistssetExpiresetex

  • 应用 redis 缓存状态,避免雷同状态管制设施。
@Service
public class DemoLinkageService{
    // 注入 redisClient
    @Autowired
    RedisClient redisClient;
    
    // 联动加湿器, linkage: 联动
    public void linkageHumidier(StatusPushBO statusPushBO){String applianceId = statusPushBO.getApplianceId();
        String redisKey = "linkage" + applianceId;
        // 判断该 key 是否曾经存在 redis 中
        if (redisClient.exists(redisKey)) {
            // 存在就取值
            StatusPushBO statusBOByRedis = redisClient.get(redisKey);
            if (statusPushBO.equals(statusBOByRedis)) {
                // 判断上报的状态和缓存中的状态统一,就从新更新 redisKey 的工夫。redisClient.setExpire(redisKey, 80L, TimeUnit.MINUTES);
                // 间接 return
                return;
            }
        }
        // 将首次状态放入 redis 进行缓存
        redisClient.setex(redisKey, StatusPushBO, 80L, TimeUnit.MINUTES);
        
        // TODO 管制设施
    }
}

如上,如果设施第一次上报状态,此时 Redis 外面是没有该设施的状态,就跳过状态相等判断逻辑,之后将这次的状态增加进 Redis 缓存一段时间;如果之后的状态没有变换,来自于设施的被动上报,此时就会进入状态是否雷同判断逻辑中,并且状态相等,那就从新更新过期工夫,并间接返回,不进行后续逻辑解决。


结语

如上应用 Redis 中间件,防止了雷同的状态,反复管制设施。

本文由 mdnice 多平台公布

正文完
 0