智能家居通用管理平台(九) – 监控程序的设计

来源:互联网 发布:php 支付宝api接口 编辑:程序博客网 时间:2024/04/27 20:27


    智能家居监控程序SHM(SmartHomeMonitor),是真正与设备系统打交道的程序。它由服务程序SHS启动,以独立的进程运行。这也是PNP机制要求的。SHM需要动态加载设备系统的驱动程序(SHDD)来监控设备,SHDD再与“硬件设备”交互。也就是说SHM实际上由两个部分组成(监控管理线程SHMM,驱动程序SHDD);所以通信比较复杂。先理清楚通信的流程,根据不同的通信方式,有两种不同的通信结构。下图是用用串口、USB、PCI等方式直接与服务器电脑通信时的情况,所有信息都是在进程间交换数据。

    如果设备系统是通过TCP/IP方式如服务器交互,则使用下图所示的有些诡异的通信方式:

    为什么这样?因为设备系统运行在其他硬件系统上,无法与服务器进行直接的IPC通信。为减轻驱动程序的编写难度,我们把接收设备发来的数据,直接在SHMM中处理:首先把收到的信息转发给SHS(IPC方式),再把信息直接交给ISmartHome接口的ProcessDeviceStateData方法处理,由于ISmartHomes实现了事件响应机制,当数据有变化时,再通知SHM,否则不通知。而SHDD收到SHMM传来的通知时( json =smarthomeshareMemory.GetNotify();,ProcessNotifyData(json); ),用TCP/IP通信对象转发给设备系统:
public void ProcessNotifyData(stringJson json)  //★★驱动程序处理服务器发来的指令
{
if (json == null) return;
string cmd = json.GetValume("cmd");
  if (cmd == null) return;
  else if (cmd == SHProtocol.DEVSTATE) 
this.TCPNotifyDevice(json);     //直接转发给设备系统 
  else if (cmd == SHProtocol.SHACTRL)  
     this.TCPNotifyDevice(json);         //直接转发给设备系统
……
}
SHM业务类图相对简单,见下图:

    只增加了一个窗口通信对象CommParameter。IPC、TCP/IP 通信对象在接口说明的类库中定义了。编写SHM程序的困难之处有两个:处理三种不同的通信方式,动态使用驱动程序。大部分时间花在通信调试上,以及编写设备驱动程序。大约花了2个月时间,开始由于自己编写驱动不熟练,来回修改接口,耽误较多时间。
    这里介绍如何电台使用驱动程序。SHS启动SHM时,传递了驱动程序的文件名给SHM,所以SHM启动后,要负责加载驱动程序,获取设备系统的详细信息:设备状态信息和控制信息。
//★★动态加载智能家居程序集,事件响应机制!★★
Assembly asm = null;
ISmartHome SmartHome;  //智能家居程序集接口
string classType = "";
private bool LoadAssembly(string dll) //动态加载厂家的智能家居程序集
   {
   string fn = Application.StartupPath + "\\" + dll + ".dll";
   if (!File.Exists(fn)) return false;
   try
   {
     if (asm == null)
     asm = Assembly.LoadFrom(dll + ".dll");  //动态加载程序集
   }
   catch { return false; }
   if (asm == null) return false;
   classType = System.IO.Path.GetFileNameWithoutExtension(dll) + ".SmartHome"; //类名:EagleSmartHome.SmartHome
    Type smarthome = asm.GetType(classType);    //获取指定对象类型
    if (smarthome == null) Application.Exit();       //连接库不是合法驱动
     object obj = Activator.CreateInstance(smarthome, new object[] { AppDataDir + "\\SmartHome.smh" }); //创建SH对象,构造函数有两个参数
     SmartHome = (ISmartHome)obj;
     SetDeviceEvent();  //★★设置设备开始工作,并且设置每个设备的数据变化响应事件
   ShowDevices();     //显示所有设备
   return true;
}
    可以看到,关键之处在Activator.CreateInstance方法,创建了一个对象,正是该对象实现了ISmartHome接口,拿到了该接口,什么都知道了。事件响应机制,在该对象中实现了,但没有编写具体处理代码,这里编写一个通用的处理方法SetDeviceEvent:
   private void SetDeviceEvent()  //★★★设置每个设备的数据变化响应事件
        {
            if (SmartHome != null)
            {   //★★★初始化通信,不调用IninComm接口方法,驱动程序不开始工作工作,只有内存数据
                SmartHome.InitComm(new object[] { comm, Clients, smarthomeshareMemory2dev, smarthomechannel2dev });
                tbInfo.Text = SmartHome.HomeName;
                for (int n = 0; n < SmartHome.HomeDevices.Count; n++) //设置每个设备的数据变化响应事件
                {
                    #region 设置每个设备的数据变化响应事件
                    for (int i = 0; i < SmartHome.HomeDevices[n].DODevices.Count; i++) //每个DO子设备
                    {
                        IDeviceDO dv = (IDeviceDO)(SmartHome.HomeDevices[n].DODevices[i]);
                        dv.OnDigitalDataChanged += DigitalDataChanged;
                    }
                    for (int i = 0; i < SmartHome.HomeDevices[n].DIDevices.Count; i++) //每个DI子设备
                    {
                        IDeviceDI dv = (IDeviceDI)(SmartHome.HomeDevices[n].DIDevices[i]);
                        dv.OnDigitalDataChanged += DigitalDataChanged;
                    }
                    for (int i = 0; i < SmartHome.HomeDevices[n].AODevices.Count; i++) //每个AO子设备
                    {
                        IDeviceAO dv = (IDeviceAO)(SmartHome.HomeDevices[n].AODevices[i]);
                        dv.OnAnalogDataChanged += AnalogDataChanged;
                    }
                    for (int i = 0; i < SmartHome.HomeDevices[n].AIDevices.Count; i++) //每个AI子设备
                    {
                        IDeviceAI dv = (IDeviceAI)(SmartHome.HomeDevices[n].AIDevices[i]);
                        dv.OnAnalogDataChanged += AnalogDataChanged;
                    }
                    for (int i = 0; i < SmartHome.HomeDevices[n].SODevices.Count; i++) //每个SO子设备
                    {
                        IDeviceSO dv = (SmartHome.HomeDevices[n].SODevices[i]);
                        dv.OnStreamDataChanged += StreamDataChanged;
                    }
                    for (int i = 0; i < SmartHome.HomeDevices[n].SIDevices.Count; i++) //每个SI子设备
                    {
                        IDeviceSI dv = (SmartHome.HomeDevices[n].SIDevices[i]);
                        dv.OnStreamDataChanged += StreamDataChanged;
                    }
                    #endregion
                }
            }
        }
  就这么简单?确是就是这样。重担都落在驱动程序的编写上了。 SHM大部分时间在处理通信事件。只是想在SHM的UI界面显示和控制设备,所以程序才稍微变得复杂了。如果没有UI界面,那确实是一个很小的程序。
下篇介绍WindowsPhone客户端程序的设计。

0 0
原创粉丝点击