最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

世界快看点丨如何防止设备被重复控制

来源:博客园

1. 引言

在一个物联网的系统中,主要有三部分组成:云端、WiFi、电控。当用户在APP上控制设备时,其控制下发链路是:云端>>WIFI>> 电控。当电控收到控制指令后,执行设备控制,控制成功后,返回结果给云端,并将结果展示在APP上,其状态上报链路是: 电控 >> WIFI>> 云端。

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

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

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


(资料图)

但是存在一个问题,云端只解析同一种协议,如何区分是控制的上报还是定时的上报的?

2. 场景联动实例

举个相关的例子,在冬天的时候,空调长时间开制热模式会导致空气湿度下降,可能会导致用户皮肤脱皮、流鼻血等情况发生。这时候就可以创建一个空调和加湿器联动的场景,当空调设置为制热模式的时候,就帮助打开用户家里的加湿器,帮助房屋保湿。

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

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

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

3. 如何解决重复控制设备

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

  • 缓存第一次状态,设置过期时间
  • 判断之后上报状态与缓存中是否一致
    • 如果一致,直接返回;
    • 如果不一致,修改缓存,控制设备。

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

3.1 定义一个状态状态的BO

@Datapublic class StatusPushBO {    private String applianceId;    private String power;    private String mode;}

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

3.2 Redis实现缓存

在这个demo中依旧使用SpringBoot作为基础框架。

  • 引入Redis依赖
    org.springframework.boot    spring-boot-starter-data-redis
  • 创建一个RedisClient
public class RedisClient {private RedisTemplate redisTemplate;private ValueOperations valueOperation;        public RedisClient(RedisTemplate redisTemplate) {        this.redisTemplate = redisTemplate;        this.valueOperations = redisTemplate.opsForValue();    }        // 通过key 获取redis中value    public  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缓存状态,防止相同状态控制设备。
@Servicepublic 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中间件,避免了相同的状态,重复控制设备。

关键词: