新零售终端的一些实现

即将离开毕业后加入的第一家公司,有些舍不得熟悉的人和物,毕竟是待了两年的地方,都有点家的感觉。但另一方面也长舒一口气,甩掉一个包袱,我不应该被过去束缚,有很多一直想做的事,外面的世界更加宽广。

两年里我看到一个初创企业在新零售领域所做的努力,不断产品迭代,不断组织结构调整,从背靠大树好乘凉的轻松到被迫独立运营的窘迫,这些真实发生的事情让我对商业的运行规则颇有兴趣。不过这篇文章不在于此,想聊一下我接触到的新零售终端设备的一些业务实现方式。它们并不复杂,也远达不到“商业秘密”,不同公司具体实现细节未必相同,但架构应该大体类似。

演进

我看到的大部分新零售终端,或者叫自动售货机,结构其实很简单,1台机器+1个大屏+1台Android工控机+1张物联网卡,稍微复杂点的,可以在工控机或机器主板上通过串口外接几台附加的售卖柜。其它差异性还会表现在机器的货道设计和出货方式上,有蛇形货道的饮料机、直通式货道的饮料机、依靠弹簧转动的综合机、依靠履带传动的综合机,还有那种用机械接货斗售卖易碎物品的综合机,后期也出现了咖啡机、啤酒机、现调饮料机等液体机型。

但这些都属于硬件层,我们关注的是上层Android工控机运行的售卖程序,它通过网络连接公司服务器,通过串口连接下层机器硬件,内部处理订单、指令机器动作并实时上报状态信息。简单的说,自动售货机就是一个大型Android手机,运行的就是普通Android软件,只是多了一条控制机器硬件的串口连接线。

自动售货机 架构

我负责维护的售卖App经历过两个阶段,从混沌到模块。

入职的1年左右,公司体量比较小,机型只有富士饮料机、澳柯玛饮料机和澳柯玛弹簧机三种,我和另外2个同事每人负责一种机型的更新迭代,零售终端依赖的售卖、补货、控制、广告等所有功能都集中在该机型的一个App里。

即使在机型较少的阶段,这种模式就已经暴露出明显问题。三个人每人维护一套代码,并且因为历史遗留,三份代码的结构差异非常大,使用的类库和软件架构并不相同。这意味着,当售货机要增加一个功能时,比如接入新的广告系统,每个人都要在自己的代码里实现一遍。看起来很可笑,明明只需写一个独立的广告模块来统一接口再分别集成,代码的复用性和维护性会更好,也能推动所用功能的模块化进程。但事实是,直到接入的机型越来越多以至于这种原始方式无法应对时才开始改变,走向真正的模块化尝试,即第二阶段。

自动售货机 架构

我们把售货机分为两种,基于货道基于配方。对于最常见的饮料机和综合机,不管它们的出货方式多么奇特,机器硬件通过串口向上层Android工控机显示的都是一个一个的货道,通过厂家串口通信协议可以控制每一个货道的补货和出货。对于咖啡机和现调饮料机,它们是没有货道概念的,只有不同口味的配方和原料存量,在软件设计上明显和基于货道的机型不同。所以需要为两种机器分别构建适用的售卖App,展示前台售卖和后台补货UI,统一处理订单和机器信息的上报。把广告、支付、串口分别构建为独立App,通过IPC进程间通信和售卖App进行数据连接。

同一机种不同机型的通用售卖上层App是同一个,广告App和工具App也是相同的,只有与串口通信协议相关的硬件控制部分需要根据厂家定义分别单独构建设备App。适配新机型只需依照硬件通信协议实现统一的通信接口,以模块形式加载,其它都无需改动。各个App单独升级,由后台根据机器编号控制具体细节,这种模块化已经足够应对未来可能接入的繁多机型了。

订单处理

在新架构里,订单的处理逻辑,包括生成、接收、校验、上报订单,是在通用售卖上层App里完成的。收到的订单确认合法后,它会通过IPC调用设备App,根据串口通信协议向底层机器硬件发送出货指令,硬件报告的出货结果会返回给上层售卖App,由其记录订单出货状态,报告给服务器。

自动售货机 订单处理

代码结构使用典型的生产者-消费者模式,创建一个阻塞队列存储待处理的订单,包括本地生成的现金支付订单、通过MQ推送收到的扫码支付订单。创建一个工作线程不断从队列获取订单,因为阻塞队列的特性,没有订单时线程处于被阻塞的等待状态,有订单时则会被唤醒,执行对该订单的出货处理。

外围设备

很多人应该见过,有的自动售货机旁边会外挂一台或多台售货柜,它们没有独立屏幕,需要在主售货机屏幕上购买其中的商品。相同业务场景下,外接柜子的实现其实有两种。

一种是柜子接在售货机主板上,由售货机自己和附加柜通信,收发轮询、出货指令,对于向上层Android工控机串口通信协议定义,会使用一种叫“箱号”或“柜号”的概念。比如,主售货机箱号是0,第一个附加柜箱号是1,第二个附加柜箱号是2,以此类推。工控机依然只通过一根串口线连接主售货机,发出的出货指令除指定货道号外还有机器箱号,以使主售货机能定位到具体的柜子和货道,完成硬件出货动作。

另一种是柜子接在Android工控机串口上,我们用的映翰通和四信工控机有多个串口,一个串口接主售货机,其它串口则可以外接很多这种附加柜,根据通信协议,由售卖软件处理与柜子的轮询、出货指令。

显然这两种方式对售卖软件的工作量定义是不同的,一种不需要售卖软件和附加柜通信,一种则需要。以兼容原则,售卖软件需要具备和附加柜的通信能力,对订单的定义需要扩充“箱号”概念,机器类型也要扩充“箱号柜”和“串口柜”概念。这些并非在售卖软件设计之初就能考虑到,我们先接触的都是直接和串口通信的附加柜,当后来出现接在售货机主板上的附加柜时,自然会修改内部数据结构来适应变化,软件功能就是这样一点点迭代完善,最终才能做出兼容所有机型的通用售卖上层App。

外接刷卡器

一些特殊场景会有独特需求,比如学校里投放的售货机,尤其限制学生使用手机的中小学,仅使用现金售卖会导致机器内硬币器的找零维护工作量很大。所以有些经销商想在售货机上外接一台学校使用的刷卡POS机,来方便学生用校园卡购买。

这样的功能需求具有合理性,但真正实施却有一个非常现实的问题,几乎每一所学校的刷卡系统都不相同,其使用的POS机也多种多样,意味着只能根据经销商机器投放的学校去联系建造刷卡系统的厂家,确认其产品是否支持接收外部设备发来的扣款指令,一家一家逐个对接。运气好的话,可能几个经销商提交的开发需求是同一个刷卡器厂家,那就只需对接一次,售货机就可以支持多个学校的刷卡购买,这样的事确实发生过。

自动售货机 刷卡器

刷卡功能以模块化实现,售卖软件具备连接所有已知POS机的能力,可以根据云端配置自动加载对应的通信库。实现方式是Java类加载器,定义好与POS机通信的方法接口,然后对每一种POS机单独根据通信协议构建Jar包。这些Jar包被放在云端,机器需要连接哪一种POS机,下载对应包加载即可。

关于公司的一些想法

作为离开校园加入的第一家公司,两年时间,我看到很多,接触很多,也学到很多,这些都会体现在我的成长历程中。而另一方面,我也看到一些存在的问题,有的已经存在很久,只是无人过问,也就一直存在下去。

我没有学过大型团体的管理和运营,但身为被管理的一员,可以谈一下我的个人理解。除去核心技术实力,标准化制度与清晰化流程在我看来是公司扩张时必须拥有并实行的两个基本原则。

人员增多、市场变大、需求递增,如果没有人知道如何正确、合规、严谨的连接市场和技术,不知道如何一步一步把市场需求变为实际产品,那么可想而知内部的沟通成本将会非常巨大,需求被曲解,与外部的对接也可能在无法确定具体承办责任人的情况下旷日持久的拖延。这些是真实发生的事情,我经历过几次,每次都在想,如果有标准化的制度和流程,接到需求,从市场到技术,每个人都按流程规定做自己该做的事,至少不会出现多方无法有效沟通的混乱局面。如果没有无意义的互相甩锅,也不会有人自己生闷气吧,工作中的心情确实会影响开发效率,这是管理层应该看到的。

arrow_upward