从抓娃娃机到成熟物联网架构的演化

1 背景

早期 X 团队在物联网做了众多探索,娃娃机是第一个项目,作为隐藏福利陪伴晚归米粒。企微打通身份识别,网络层 WebSocket 作为长连接控制机器的开局,这个是物联网技术的缩影与雏形。同时期共享单车、充电宝、智能家居等都有物联网技术的影子,我们还探索了物联网在智能零售柜的应用,目前已经有稳定成熟的架构体系,可适配于更多物联网应用,为商业探索快速落地提供技术支撑。

2 物联网平台及数据成果

2.1 数据成果

目前自研方案基于智能零售柜落地场景中的物联网架构相较于行业数据更为突出,该方案的两大综合指标“开门报错率”&“有视频率”。

  • 开门报错率,近期数据开门报错率指标较 A 方案商低 1.3%,较 B 方案商低 6.6%, 且报错率持续降低,意味着开门成功率同比行业处于领先地位。
从抓娃娃机到成熟物联网架构的演化
  • 有视频率,有视频率目前稳定于99.98%以上,处于行业领先水平,较项目初期99.88%提升0.1个百分点,直接可以减少对应货损。

2.2 解决方案

针对开门报错率高我们做了两个方案,实时预警处理系统+守护程序,目的就是快速定位问题设备,快速解决设备问题,从而降低报错率。

  • 实时预警处理系统是指根据实时设备上报信息,是设备健康度的宏观看板,触发警戒线的指标考虑到线下维护成本后,综合判定给出需要人工干预的设备。
从抓娃娃机到成熟物联网架构的演化
  • 守护程序完成最基础的信息上报及灾备升级方案,实现了对开门报错率最高的指标-开门离线率的有效判定,及设备是否拔电的准确判定,从而筛选出影响最高的设备进行告知线下巡检进行插电解决。实时干预有效降低后续因拔电引起的开门报错。
从抓娃娃机到成熟物联网架构的演化

其中守护时间+设备在线时间可以综合判定设备是否处于拔电状态。从而进行线下派单。

3 物联网架构演进

3.1 总架构

伴随移动架构的演进,从mvc到mvp,同时做了大量模块化拆分工作,可以粗分类为:系统层、公共组件层、业务组件层。在系统层积累了优秀稳定的网络请求框架、各种工具类。

物联网架构沿用模块化设计模式,平移系统层,在此基础上进行物联网框架建设,架构如下:

从抓娃娃机到成熟物联网架构的演化

物联网与移动架构侧重点不同,移动端有大量的UI 展示逻辑,需要大量UI组件支撑;物联网重点建设网络层,及硬件适配层。

3.2 总架构

网络层主要涉及MQTT + WebSocket 的方案进行双向数据交互,早期MQTT选择腾讯云单设备商接入,后面会发现,腾讯云也有发生故障的情况,后期我们升级了“多链路、自感知、自切换方案”,例如运用双向消息互通回执 ,回执超时切换机制,可以做到单链路通讯故障3分钟内自动路由至其他链路,确保稳定性。

网络层还包含大量的视频文件及日志大文件上传,通过OSS组件可路由阿里云OSS 及腾讯云COS进行大文件传输,包括但不限于断点续传和分片传输等机制。

3.3 智能硬件层

智能硬件层得益于我们模块化的设计模式,每个硬件我们视为一个模块,通过单例模式管理内部服务,实现对应功能,比如我们锁控模块统一由DeviceManager管理锁控服务

public class DeviceManager {

    private static final Logger log = LoggerFactory.getLogger(DeviceManager.class);

    private static Context context;

    public static void init(Context mContext) {
        context = mContext;
    }

    public static DeviceService getInstance() {
        return DeviceManager.Device.INSTANCE.getInstance();
    }

    private enum Device {
        INSTANCE;
        private DeviceService service;
        Device() {
            try {
                if (context == null) {
                    new Throwable("请初始化 DeviceManager.init(context)");
                }
                 XygoUtils.getSysProps("ro.build.description");
                log.info("GPIOCtrl init:{}", description);
                String module = description.substring(0, 6);
                String version = XygoUtils.getSysProps("ro.build.version.release");
                if ("rk312x".equals(module) || "rk3128".equals(module)) {
                    service = new DeviceServiceImpl_3128();
                } else {
                    service = new DeviceServiceImpl_3368();
                }
                service.init(context);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        public DeviceService getInstance() {
            return service;
        }

    }
}
public interface DeviceService {
    //初始化
    void init(Context context);

    /**
     * 设置wifi 优先
     */
    boolean setWifiFirst(boolean state);

    /**
     * 开锁
     */
    void doOpenLock();

    /**
     * 关锁
     */
    void doCloseLock();

    /**
     * 开灯
     */
    void doOpenLight();

    /**
     * 关灯
     */
    void doCloseLight();

    /**
     * 是否开锁
     *
     * @return true:(开,锁芯缩回) false:(关,锁芯伸出)
     */
    boolean isOpenedLock();

    /**
     * 是否开门
     *
     * @return true:(开,门磁移开,绿灯) false:(关,门磁返回,红灯)
     */
    boolean isOpenedDoor();

    /**
     * 是否开灯
     *
     * @return true:(开) false:(关)
     */
    boolean isOpenedLight();

    //重启App
    boolean restart(boolean report, String str);

    /**
     * 重启系统
     *
     * @param report 是否上报
     * @param msg    重启原因
     * @return
     */
    boolean reboot(boolean report, String msg);

    /**
     * 延迟多少S后重启
     * @param report
     * @param msg
     * @param delay
     * @return
     */
    boolean rebootDelay(boolean report, String msg, long delay);

    boolean silentInstallApk(String path);
    /**
     * 修复系统流量
     *
     * @return
     */
    boolean repairSysFlow();

    /**
     * 4G 开关
     *
     * @param state
     * @return
     */
    boolean change4G(boolean state);

    /**
     * 查看4G状态 0关,1开
     * @param state
     * @return
     */
    boolean query4G(boolean state);

    /**
     * 开飞行模式 0:关 1:开
     * @param state
     * @return
     */
    boolean changeFly(boolean state);

    /**
     * 锁定4G
     * @return
     */
    boolean lock4G();
}

不同硬件产品在读写GPIO 根据实现类去实现就可以对接具体的硬件产品了。

  • 摄像头模组

除了门锁外,我们还同时集成了摄像头模组,从5个摄像头的静态USB 拍照模组,到USB的动态录像模组,再到双IPCamera模组。不同的模组对应了不同的商业落地场景,从静态柜到普通柜,到动态柜。

IPCamra落地时还做了动态网络路由方案,即摄像头录制走LAN口,数据传输走4G,还要考虑开启WIFI 时数据的优先级问题。

3.4 优化实践

硬件产品与软件产品的区别在于,数据是精确的,硬件产品存在执行不到位的问题,例如发送开锁是否等于锁开,查询锁开是否等于真正锁开。常见的高频调用常见错误例如:开锁锁不开,关锁锁未关,用户不关门,未关门订单的下次用户扫码开门。保证有视频率是在以上非正常的硬件“故障”中进行兼容,例如我们目前已经优化了在首位用户不关门时,后续用户扫码开门的兼容逻辑,实现不影响第二单用户的购物流程。

如上的优化流程正是提高用户体验的细微之处,同时也是与其他厂商差异化的技术护城墙。

4 写在最后

模块化的优势:在部分提供刷脸的支付宝货柜中,其作为刷脸硬件可以独立发布APP,亦可以作为组件发布集成于主程序,极大方便了任何硬件集成于整个物联网平台。

例如一个充电宝平台,我们仅需将其作为普通硬件,实现他的读取电量、弹出充电仓,放回充电仓等逻辑,就可以完成一个商业化项目。

作者介绍:小北,现任信也科技X团队移动研发资深专家
来源:拍码场
原文:https://mp.weixin.qq.com/s/V6RvII0ySFfWTIiruGggfw

相关阅读:在线娃娃机客户端功能实现流程(H5/Web端)

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论