硬件管理平台-硬件网关-插件模块-集成(下)
硬件管理平台-硬件网关-插件模块-集成(下)
简介
通过以上的几篇文章说明了xml的相关配置信息和配置项,我们可以对插件模块的剩余部分进行说明了。当网关服务加载了本地的硬件插件后就产生了硬件类型的实例,通过该实例就可以去调用下位机了。而去调用哪个下位机,我们就需要通过xml的配置信息去指定,例如我们要调用IP为192.168.1.52的门禁,测试它的登录功能,HardwareInfo.xml
中就需要有该门禁的相关信息,包含了ip地址,用户名,密码以及端口号,还有相关的对外暴露的功能。当初始化了门禁类的实例后,再加上xml中特定的信息就可以对特定门禁的特定功能进行调用,这样的好处是可以动态的进行插拔更新,也可以很好的将硬件与网关解耦。
正文
完成RefreshHardware
方法后,开始为读取HardwareInfo.xml做准备:
-
HardwareServices
中申明HardwareOptXml 类并进行实例化:private HardwareOptXml xmlClient = new HardwareOptXml();
在RefresHardware下放增加一个OnStartByXml方法,该方法的功能是将
HardwareInfo.xml
文件的硬件信息进行读取并存放到HardwareXmlEntity列表中,然后通过获取TimeingFun
和initializationFun
的变了来分别完成各自的业务需求,其中InitializationFun为将该设备初始化,而TimeingFun功能涉及到了任务调度部分,因此本章不涉及,会在后续进行详细说明。public void OnStartByXml() { // 重新打开一次HardwareInfo文件-意味着刷新硬件实例列表 xmlClient.RefreshXml(); // 获取硬件实例 List<HardwareXmlEntity> hardwareDics = xmlClient.GetHardwareInfos(); // 调用插件类的开始方法,将硬件实例放置到该方法中进行相关的开始工作 Task.Factory.StartNew(async () => { await pluginManager.OnStartAsync(hardwareDics); }); }
插件模块的OnStart方法部分主要描述的是硬件实例的初始化和调用部分
public async Task OnStartAsync(List<HardwareXmlEntity> hardwareDics) { if (hardwareDics.Count > 0) { // 将反射的硬件类型实例与硬件实例合并,转换为以key为型号,value为设备实例的字典,便于后面使用 Dictionary<String, List<HardwareXmlEntity>> dic = new Dictionary<string, List<HardwareXmlEntity>>(); hardwareDics.ForEach(item => { String sbxh = item.Param["设备型号"]; if (hardwareDic.ContainsKey(sbxh)) { // 判断是否存在该类型,如果不存在就创建一个 if (!dic.ContainsKey(sbxh)) { dic.Add(sbxh, new List<HardwareXmlEntity>()); } dic[sbxh].Add(item); } }); foreach (var key in dic) { // 进行初始化方法操作,后期会将回调一个调度实例,然后继续调度任务的操作 await Initialization(key.Value, hardwareDic[key.Key], key.Key); // 该处将增加调用任务的相关代码 } } }
Initialization方法为调用硬件类型的初始化实例
public async Task<bool> Initialization(List<HardwareXmlEntity> item, HardwareAbstract @abstract, String sbxh) { // 设置一个初始化实例 InitHardwareEntity iInitClass = new InitHardwareEntity(item, @abstract, sbxh); bool v = await Task<bool>.Factory.StartNew(init => { // 获得到,之前怕传入的方法多,该实例会变 InitHardwareEntity initClass = (InitHardwareEntity)init; initClass.item.ForEach(t => { try { // 如果存在InitializationFun功能模块 if (null != t.InitializationFun) { t.InitializationFun.ForEach(fun => { try { // 调用InitializationFun中存储的功能模块 AjaxResult result = initClass.@abstract.Execute(fun, t.ParamJson, ""); } catch (Exception ex) { } }); } } catch (Exception ex) { _logerror.Error("hardwareDics.ForEach错误", ex); } }); return true; }, iInitClass); return v; }
-
创建
GetFunction
方法,该方法的主要作用是调用硬件的OperationFun
部分的功能码,为硬件网关主动调用下位机的操作。之前的设计为全是异步操作,硬件网关获取数据后通过上位机暴露的方法再进行传输,这样可完成上位机到硬件网关的异步操作。
在HardwareService中增加存储硬件实例的声明
readonly Dictionary<string, HardwareXmlEntity> hardwareXmlEntities = new Dictionary<string, HardwareXmlEntity>();
增加
OperationFun
调用的方法public AjaxResult GetFunction(String function, String hardwareInfo, String param) { String deviceId = ""; // 如果硬件实例为空,则刷新获得 if (hardwareXmlEntities.Count == 0) { RefreshHardwareDics(); } // 没有未找到该主键,则尝试获取 if (!String.IsNullOrEmpty(hardwareInfo) && hardwareXmlEntities.ContainsKey(hardwareInfo)) { deviceId = hardwareInfo; hardwareInfo = JSONUtils.SerializeObject(hardwareXmlEntities[hardwareInfo].Param); } //根据描述获得 Function fun = AssemblyUtil.GetEnumByDescription<Function>(function); if (fun == 0) { fun = AssemblyControl.GetEnumByName<Function>(function); } try { // 调用方法 return pluginManager.Function(fun, hardwareInfo, param); } catch (Exception ex) { String msg = $"GetFunction function:{function} hardwareInfo:{hardwareInfo} param:{param}"; _logerror.Error(msg, ex); return AjaxResult.error("报错", ex.Message); } }
结尾
本文章主要介绍了上次集成时遗留下来的尾巴,主要涵盖了如何将反射的硬件类实例与xml中存储的硬件实例进行处理,并进行初始化以及等待上位机调用所开放的接口,接下来我们将开始系统调度的说明。