场景介绍
作为一个商业环境的重要配备,商用厕所的管理直接体现了服务商水平的高低。纸巾、热水、气味控制等等方面,甚至将占空比控制接入数据系统。在甲方的要求下,我们也进行了这样的项目实施。
但事实上维持厕所不缺纸更为重要。
传统模式
每个厕所或者厕格配备纸巾盒,要为其即时更新是代价非常高昂的,因为管理人员无法实时得知其消耗情况。
一般而言,超过200个厕纸分发点需要高频度巡检才能保证每个点位都能及时更换。但事实上,巡检的频率是固定的,只能按照最快消耗的频率进行工作安排。
对于纸巾盒数量超过1000个的大型园区、商场,服务人员只能划定区域进行工作分配,为了防止遗漏,还会在每个厕格配置定位联系卡。
管理要求较高的企业,都会进行表格登记,在运行一定时期后进行统计分析,以求调整巡检频度或采购计划。
2018年的数字化
我们在进行钉钉理想办公室共创建设的时候,把传统的管理过程引入到了数字化系统中,并集成在钉钉的工作流当中。
这让我们的项目仅有50个管理点位情况下也能在数字化系统的帮助下,不额外增加人手也可以实现大型商业厕所的管理要求。
但这还是原先的传统管理思路,人在驱动人去做事情,并非事件驱动人。一旦发生员工更新以及没有及时完成人员培训即上岗,对于这样的数据系统会因为数据没有持续更新而失效。
2022年的演进方向
我们进行了一系列尝试在每个纸巾盒中按照了传感器。
为了保障电力供应,我们采用了18650电池,每小时监测6秒。电力可以支持半年以上。
当数据反馈为准备状态时,会通过阿里云IoT触发事件,接着用函数计算调用钉钉的服务端API生成一个任务给执行人。执行人的钉钉会收到信息,只需要完成更换,当前任务就会自动更新状态。
将人员从数据系统中解放出来,重新关注业务本质。
数字化应用演进
回顾业务本质
缺纸就换纸,尽量保证任何运营期间所有的节点都有纸巾。所以需要巡检,而最小频度实际上取决于用纸最快的点位。这样就会造成大量的人力浪费或者服务缺位。
第一次数据化演进
为了保障耗材的供应和备货,大型的商业空间会对其进行数据采集,用最原始的手写表格,运行一定周期后进行数据分析。对于数据的利用往往取决于管理者的兴致。
数据可以优化巡检分区,按照高频区域、低频区域设置不同的巡检周期。
数据也可以优化耗材采购计划,有效控制库存和供应。
把纸面搬上电脑,把表格变成电子表格
办公室的行政工作人员逐渐官僚化,对于大量数据汇总感觉到厌倦,他们推动了让一线人员进行数据采集。让各个部门的工作人员制作各自采集的纸质数据,变成电子表格。
然而这些信息的数据化并没有解放行政人员,他们依然要处理来自各个信息孤岛的各类异构数据。
管理层对于数据化的执着,源自于掌控感,逼迫各个层级几乎每时每刻都在开始为数据忙碌,业务只不过是为了产生数据。
数据驱动业务
技术部门为了凸显自身价值,开始大规模的进行各方面的数据采集和分析,当然首先建设的是各种数据录入的终端和应用,之后是数据系统。
随着物联网技术的发展企业的技术部门或者行政部门选择的外部供应商开始将数据采集工作纳入到日常中。
管理层需要数据的时候,甚至可以看到每个区域的实时热力图,任意时间的回顾分析。
厕所运营数据这样边缘的信息已开始并没有在行政人员的计划中,随着各方面数据化的完成,部门出于对自身权力扩张的需要,将数据采集深入到商业区管理的方方面面。在他们的意识中,信息即权力。
业务自驱动
数据化所到之处,除了大量产生数据之外,也诞生了大量的数据汇总、可视化、一系列可供决策的数据分析。
然而企业为数据的采集投入了大量的人力,系统上了之后一线工作人员不但要关注业务本身,还需要关注自己在数据系统上留下的记录。
有些极端的企业,甚至规定没有在系统上记录的工作就认为没有进行过。
因为之前的数据化过程中,系统围绕着开发人员的思路进行设计,并没有把使用者当成自己的用户。在他们眼中,这些系统的使用者只不过是没有感情的机器。
数据化演进中人逐渐回到了业务的中心,人做了什么是因为岗位需要,而不是因为需要创造数据。系统负责帮助工作人员监测需要关注的节点和业务,数据的采集和系统流程应该留给系统本身去做。
阿里云技术栈介绍
钉钉开放平台
钉钉开放平台目前包含了常用API、酷应用、连接平台和企业网关构成。
在连接平台推出以前,需要实现任务创建需要调用钉钉服务端API。
主要是用创建任务的服务端API
参考代码如下:
publicvoidcreateTodo() throwsException { Configconfig=newConfig(); config.protocol="https"; config.regionId="central"; com.aliyun.dingtalktodo_1_0.Clientclient=newcom.aliyun.dingtalktodo_1_0.Client(config); CreateTodoTaskHeaderscreateTodoTaskHeaders=newCreateTodoTaskHeaders(); createTodoTaskHeaders.xAcsDingtalkAccessToken="accessToken"; CreateTodoTaskRequest.CreateTodoTaskRequestNotifyConfigsnotifyConfigs=newCreateTodoTaskRequest.CreateTodoTaskRequestNotifyConfigs() .setDingNotify("1"); CreateTodoTaskRequest.CreateTodoTaskRequestDetailUrldetailUrl=newCreateTodoTaskRequest.CreateTodoTaskRequestDetailUrl() .setAppUrl("https://www.dingtalk.com") .setPcUrl("https://www.dingtalk.com"); CreateTodoTaskRequestcreateTodoTaskRequest=newCreateTodoTaskRequest() .setSourceId("isv_dingtalkTodo1") .setSubject("钉钉企业待办") .setCreatorId("E9C********N7QiEiE") .setDescription("创建钉钉待办任务") .setDueTime(1661767200000L) .setExecutorIds(java.util.Arrays.asList( "tXg************RAiEiE" )) .setParticipantIds(java.util.Arrays.asList( "tXg************RAiEiE" )) .setDetailUrl(detailUrl) .setIsOnlyShowExecutor(true) .setPriority(40) .setNotifyConfigs(notifyConfigs); try { CreateTodoTaskResponsecreateTodo=client.createTodoTaskWithOptions("E9C********N7QiEiE", createTodoTaskRequest, createTodoTaskHeaders, newRuntimeOptions()); System.out.println(JSON.toJSONString(createTodo.getBody())); } catch (TeaExceptionerr) { if (!com.aliyun.teautil.Common.empty(err.code) &&!com.aliyun.teautil.Common.empty(err.message)) { // err 中含有 code 和 message 属性,可帮助开发定位问题System.out.println(err.code); System.out.println(err.message); } } catch (Exception_err) { TeaExceptionerr=newTeaException(_err.getMessage(), _err); if (!com.aliyun.teautil.Common.empty(err.code) &&!com.aliyun.teautil.Common.empty(err.message)) { // err 中含有 code 和 message 属性,可帮助开发定位问题System.out.println(err.code); System.out.println(err.message); } } }
更新任务的参考代码如下:
publicvoidupdateTodo() throwsException { Configconfig=newConfig(); config.protocol="https"; config.regionId="central"; com.aliyun.dingtalktodo_1_0.Clientclient=newcom.aliyun.dingtalktodo_1_0.Client(config); UpdateTodoTaskHeadersupdateTodoTaskHeaders=newUpdateTodoTaskHeaders(); updateTodoTaskHeaders.xAcsDingtalkAccessToken="accessToken"; UpdateTodoTaskRequestupdateTodoTaskRequest=newUpdateTodoTaskRequest() .setOperatorId("E9C********N7QiEiE") .setSubject("更新钉钉企业待办") .setDescription("更新钉钉企业待办") .setDueTime(1661767200000L) .setDone(true) .setExecutorIds(java.util.Arrays.asList( "tXg************RAiEiE" )) .setParticipantIds(java.util.Arrays.asList( "tXg************RAiEiE" )); try { UpdateTodoTaskResponseupdateTodoTaskResponse=client.updateTodoTaskWithOptions("E9C********N7QiEiE", "task6b9d*************316fe89acd", updateTodoTaskRequest, updateTodoTaskHeaders, newRuntimeOptions()); System.out.println(JSON.toJSONString(updateTodoTaskResponse.getBody())); } catch (TeaExceptionerr) { if (!com.aliyun.teautil.Common.empty(err.code) &&!com.aliyun.teautil.Common.empty(err.message)) { // err 中含有 code 和 message 属性,可帮助开发定位问题System.out.println(err.code); System.out.println(err.message); } } catch (Exception_err) { TeaExceptionerr=newTeaException(_err.getMessage(), _err); if (!com.aliyun.teautil.Common.empty(err.code) &&!com.aliyun.teautil.Common.empty(err.message)) { // err 中含有 code 和 message 属性,可帮助开发定位问题System.out.println(err.code); System.out.println(err.message); } } }
函数计算
直接使用内置运行时创建node.js的函数容器即可,用层的方式可以在没有预留实例的情况下,将启动速度降低到100ms以内,与钉钉的接口部分采用回调的方式可以避免响应超时。
阿里云IoT
通过HaaS Python接入阿里云IoT,使用MQTT推送状态到阿里云IoT,函数计算可以使用阿里云IoT的事件作为触发器。
硬件配置采用ESP32和意法半导体ToF传感器,通过Wi-Fi接入。
钉钉连接平台介绍
通过简单的低代码配置,快速实现钉钉官方应用与SaaS应用、企业自建应用及生态应用之间互联互通,集成多方能力,形成丰富自动化连接场景,降低人力成本。让企业工作更简单、更自动。
基于钉钉连接平台实施
配置硬件
钉钉连接平台极度简化了系统结构,不再需要接入阿里云IoT触发。只需要使用硬件接入网络后调用http模组访问webhook即可。
创建连接器
创建触发事件
创建执行动作
由于之前用API更复杂,在这样的低代码环境下非常迅速地完成了部署。大大降低了系统复杂度。
写在最后
作为一个工程师,所有地设计为用户服务,而不是给用户增加麻烦。很多时候客户、用户是分离的,不能只想着给钱的客户,而忽略的使用者。
同样,有效的数据化不单服务于管理。把业务本身还给业务,不要让数据化绑架业务,让数据化为业务服务。