云端通信的坑 为了简化智能网关和采集器/智能终端的通信,采集器和智能终端对外统一物理接口为RS485,通信协议为Modbus。针对每一种传感器模块(内含采集器+传感器),都会独立封装成一个驱动,这样的好处是,相关的传感器数据自动会导入到YFIOs嵌入式组态软件中。 针对当前项目一共需要如下几个驱动:智能终端-8路开关量入模块驱动、智能终端-8路继电器输出模块驱动、水表驱动、电表驱动、综合传感器模块(温湿度、光照、氧气、二氧化碳等)驱动、温度传感器模块(多路温度)驱动、负压采集模块驱动和称重模块驱动等。 物联网智能网关具有一个以太网接口、四个RS485接口。以上几种设备分别连接在四个RS485接口上。物联网智能网关上运行了基于.NET Micro Framework系统的YFIOs组态运行时。通过配置自动获取各种传感器的数据,然后把采集到的数据自动上传到云端中间件。 YFIOs是YFSoft I/O Server的简称,由三大部分构成,图5所示,一是YFIOs运行时,包含内存数据库YFIODB、内存数据块YFIOBC、驱动引擎和策略引擎四部分;二是应用模块,包含驱动、策略和IO数据三部分;三是YFIOs IDE环境(YFIOs Manager),该工具和Microsoft Visual Studio开发工具共同完成驱动、策略的开发、配置及部署工作。 这个通信环节出现的“坑”,就出在采集器→智能网关环节上,用YFIOs Manager配置各种模块驱动时,发现最后添加了称重模块的驱动后,则整个YFIOs运行时会出现异常,部署的模块驱动反射时会出现异常,进一步追踪发现驱动文件的偏移地址变为0,百思不得其解,一度以为这个“坑”迈不过去了。 后来进一步发现,和称重驱动模块无关,最后添加其他驱动也会出现这样的问题。再进一步发现,是因为同一个RS485接口连接了多个传感器模块的原因,但是在以前的项目中,一个RS485接口曾经连接过若干个物联网智能模块,运行正常,没有发现类似问题。 图5 YFIOs架构 图6 YFCloud云端中间件客户端管理界面 由于这个功能很重要,无法回避,最后只好采用最费时间的办法,一一在线跟踪YFIOs Manager和YFIOs运行时代码,才发现问题出在当同一个通道加载不同驱动模块时,驱动程序计数出现了问题,没有累加,当同一个通道连接的都是同类的模块,则不会出现这个问题。但连接不同模块,由于需要多种驱动程序,则会出现这个问题。知道问题点,就好修改了,在YFIOs Manager中增加了一行计数累加代码,最终迈过了这个“坑”。 由于在网关→云端中间件这个环节的通信功能,已经在垃圾或污水处理等实际项目中已经运行3、4个月了,是经过实际验证过的,理论上应该不会在出现“坑”了,没有想到这个环节又出现了一个“坑”,一个更意想不到的“坑”。 具体的问题是发现用YFIOs Manager监控到的数据和云端YFCloud收到数据部分不一致,有错位现象。 重新从YFIOs Manager导出要上传的IO的XML文件,在云端后台导入,重复多次,数据依然错误。在以前实施的项目中,从未出现这种问题。 仔细分析也没有看出问题出在什么地方。不过要说区别,区别就是I/O变量名称中,出现了T和H两个一个字母的变量,根据这个信息盘查云端I/O操作的C++代码,发现原有嵌入式代码移植到云端平台时,在I/O变量名合法性判断时原来的小于号后面多加了一个等于号,所以变量名长度为1的时候,则判断为非法,获取该I/O变量类型时,就会出现错误,跳出本次循环,造成统计浮点数变量个数的时候漏记,从而导致数据填充错位。 迈过以上几个“坑”,各种传感器的数据终于可以正常的上传到云端了,并且通过网页和手机微信可以查看各种实时数据、历史数据、历史曲线和监控页面等等。微信界面如图7所示。 经历了四五天“激战”,以为终于可以松一口气了。没有想到微信的实时数据页面又出现了问题,即连续运行5-6个小时之后,微信实时数据页面上的数据将显示为空,更为致命的是,这个时候Web后台程序会崩溃。 图7 微信实时数据界面 最初在设计实时数据页面时,打算从历史数据报表中提取。虽然所有项目的I/O变量,都可以通过设置CRON表达式,来设定每一个I/O变量什么时候保存,或定时保存间隔。考虑到项目实际需求及保存的数据量大小,最小的存储间隔设定为5分钟。从用户体验上考虑,这个时间还是太久,盯着手机看,数据5分钟才变化,那感觉也太差了。 从现场网关把数据上传到云端中间件,根据现场实际,可以通过以太网进行数据上传,也可以通过GPRS、3G或4G进行数据上传,考虑到数据传输的即时性及流量限制,数据上传采用变化才上传的策略(对浮点数据,可以设置变化上传的阀值)。 所以实时数据页面最好可以直接显示上传的数据,这样用户的体验才可能比较好。 这次的“坑”就出现在实时数据页面的服务端程序读取YFCloud云端中间件的内存数据库(IODB)时候,会出现异常,并且该异常无法被捕捉,这真是一个棘手的问题。 后来仔细查看了相关的访问代码,感觉应该存在多线程同步访问的问题,添加了相关的同步代码后,就再也没有出现过类似的问题。
|