摘要:针对智能家居远程控制问题,结合Android终端设备,设计了一套控制信息对用户透明的远程空调控制系统。系统底层控制信息通过基于GSM的短消息方式传输,实现了对由6台空调组成系统的远程控制。系统采用自定义通信协议,在Android端讨论并实现了两种接收返回信息方式——BroadcastReceiver和ContentObserver方式,对Android中的Handler机制进行讲解应用。测试结果表明,系统结构设计合理,操作简单,性能稳定。
引言
远程控制作为智能家居的一种标志性技术,被广泛应用于各种智能家居系统中。本文设计并实现了一种智能家居中远程空调控制方案。本系统基于Android系统客户端用户友好型界面和GSM模块,屏蔽控制信息传输处理细节,客户端采用控件绑定号码的方式,用户只需根据终端Android界面提示,即可完成远程空调控制。相比于以往方案中GSM模块采用PDU方式进行通信,用户端需要手动输入具体命令的模式,本系统采用text文本方式进行通信,传输的控制命令仅为数字即可。
本文实现了两种Android应用中接收短消息的方式BroadcastReceiver(广播接收者)方式和ContentObserver(内容观察者)方式,采用Hand ler机制将接收到信息显示,且对安卓中SQLite数据库的操作进行阐述及应用。本系统通过接收GSM控制消息的基于LPC1766芯片的集中器传输控制消息到各个分控制器,可以同时控制6台空调,每台空调对应一个分控制器,具体系统控制端架构见图1。
1 系统控制端设计
1.1 硬件设计
本系统采用NXP公司的LPC1766芯片作为集中器的SoC。系统GSM模块采用华为公司的GTM900-B型号无线模块,该模块具有标准的AT命令接口,并提供无线接口用于短消息的收发,且可通过串口通信和嵌入式MCU相连。
本系统叶GSM模块和集中器通过串口相连。GTM900-B模块的串口与LPC1766的UART0相连,具体连接见图2。
1.2 AT指令
GTM900-B模块使用了GSM Rec.07.07中规定的标准AT命令,本系统需要使用到的AT命令如表1所列。
1.3 通信协议
本系统主要通过GSM短消息的方式完成对每个房间的温度获取(通过分控制器上的温度传感器)和每个房间空调工作模式、温度的设置,以及关闭房间空调的功能。从安卓终端的角度包括两个方面的通信——发送和接收。
从安卓终端发送到GSM模块的控制信息包括三个方面:获取温度值,设置某个房间空涮参数,关闭某个房间李调。GSM模块采用text方式通信,系统将发送的三种控制信息数字化为相同规格:
其中Sent1表示控制信息类型:“1”表示获取温度,“2”表示设置某个房间空调,“3”表示关闭某个房间空调。Sent2表示房间号,取值1~6对应相应房间。Sent3表示当Sent1为“2”时,设置号码为Sent2的房间空调的工作模式:“1”表示制热,“2”表示制冷,“3”表示送风,“4”表示除湿。Sent4表示当Sent1为“2”时,设置号码为Sent2房间的工作温度。分隔符用冒号表示,主要作为区别控制信息与初始化返回信息的标识符。所以,Android发送端发送的控制信息格式表示为“Sent1:Sent2:Sent3:Sent4”。
对安卓终端接收的反馈消息也包括三个方面:集中器从分控制器得到的温度信息,设置某个房间空调成功的返回消息,某个房间空调关闭的返回消息。因为这三种消息长度不一致,处理方式不同,系统只对接收消息的前两位格式化即可完成系统功能,具体如下:
其中:Rec1表示反馈信息类型:“1”表示温度信息,“2”表示设置空调返回信息,“3”表示关闭空调返回信息。Rec2表示当Rec1为“2”或“3”时空调返回信息,“1”表示设置或者关闭成功,“0”表示失败。所以,Android接收端接收的由系统控制端返回的信息中,首先会判断第1位(即Rec1位),如果是“1”,则表示返回的是各个房间的温度;如果是“2”,表示的是设置空调(Sent1等于“2”时)的返回消息;如果是“3”,表示的是关闭空调(Sent1等于“3”时)的返回消息;对于Rce1等于“2”或者“3”,再根据Rce2来判断相应的返回消息状态。
1.4 集中器软件设计
集中器上的程序主要完成系统模块和GSM模块初始化,判断控制信息类型及作相应的处理,向终端用户返回消息。具体程序流程见图3。
其中GucRcvNew=1表示集中器从UART0接收到来自GSM模块的返回消息,recvfg用来对GSM模块进行初始化,其初值为0。集中器发送命令at到GSM模块,如果接收到GSM模块的“at ok”返回消息,则设置recvfg=1,然后进入switch语句,当recvfg=1时,向GSM模块发送命令at+cmgf =1,如果返回值为“at+cmgf=1 ok”,设置recvfg=2。当recvfg=2时,向GSM模块发送命令“at+cnmi=2,2,,1”,如果返回值为“at+cnmi =2,2,,1 ok”,设置recvfg=3,到此GSM模块初始化结束。如果初始化过程中当集中器发送AT命令后,接收到的不是正确返回值,则设置recvfg=0,重新开始初始化。
根据控制信息类型设置flag子程序和根据flag值进行相应处理的子程序主要是在初始化结束后完成系统功能,程序流程见图4、图5。
本系统集中器采用UART中断方式和GSM模块通信,当有数据返回集中器时,会触发UART中断,在UART中断处理程序中从U0RBR寄存器读数据到GucRcvBur[Gu1Num]数组中。因为每次通信返回的字节数不相等,本系统在UART中断处理函数中引入定时器中断,在定时器中断处理函数中设置GucRcvNew==1。即每次进入UART中断处理函数时,开启定时器,UART在初始化时设定的中断触发点是1个字节,当所有返回字节都接收完成时,定时器超时会触发定时器中断处理函数,设置GucRcvNew==1,主程序检测到有数据返回。系统中设置定时器的触发时间是0.5 s。
2 Android端设计
本系统采用Android应用程序的用户友好型界面作为与用户的接口,Android终端程序通过控件绑定方式对固定号码进行短信接收与发送,用户只需通过点击控件方式即可传递和接收控制信息,具体根据系统自定义通信协议发送的控制信息则完全被程序屏蔽,对用户完全透明。其中发送短信和接收短息都会对Android系统的SQLite数据库作出改动,需要对数据库中的相关信息进行删除来保证对用户透明。另外对于控件之间消息传递采用Android中的Handler机制。
2.1 发送控制信息
Android中发送消息主要通过SmsManager类来实现,它继承自java.lang.Object类。其主要的方法说明略——编者注。
发送短信程序首先调用SmsManager. getDefault()获取SmsManager对象,然后通过PendingIntent的getActivity方法获得一个Pending Intent对象。根据短信长度Message.length()与短信长度最大值比较来判断是否需要调用smsManager.divideMessage(Message)将短信分割,然后再调用smsManager的sendTextMessage方法发送短信。代码略——编者注。
发送短信模块需要在清单文件AndroidManifest.xml中加入允许发送短信的权限:
2.2 接收返回信息
在Android端接收消息,可以采用两种方式,一种通过BroadcastReceiver广播接收器的方式,另外一种是通过观察数据库变化的内容观察者类ContentObserver来实现。
2.2.1 BroadcastReceiver接收短信
Android中的广播是一种在应用程序之间传递信息的机制,在Android中有多种广播,基于GSM短信的接收会产生一个广播,应用程序可以监听这些广播并根据广播类型作出相应的处理。BroadcastReceiver就是对接收到的广播进行过滤并响应的一类组件。
当应用程序接收到广播发送来的intent对象,BroadcastReceiver类根据其注册的广播地址与接收到的intent对象进行比较,如果匹配则调用BroadcastReceiver的onReceive()方法。
BroadcastReceiver类的注册有两种方式,第一种是静态注册方式,即在AndroidManifest.xml文件中利用intent—filter指明需要过滤的广播地址。静态注册方式会使程序始终监听广播消息,并自动调用程序继承自BroadcastReceiver的类。第二种是动态注册方式,其在activity中调用函数registerReceiver来注册,当应用程序关闭后,就不在进行监听。在动态注册的activity被销毁前,需要调用unregist er Receiver解除注册。
短消息广播是一个有序广播,即每次只被优先级最高的接收者处理,然后由优先级高的接收者传递到优先级低的接收者。优先级高的接收者可以终止这个广播。对于有序广播而言,动态注册的优先级高于静态注册。
系统中定义SmsReceiver类继承自BroadcastReceiver类,采用动态注册的方式,在activity中用于动态注册的代码略——编者注。
接收短信模块需要在清单文件AndroidManifest.xml中加入允许发送短信的权限:。
2.2.2 ContentObserver接收短信
系统实际使用中,对于用BroadcastReceiver接收短信往往效果不好,主要因为用户在Android终端安装的第三方软件,比如接收短信软件、安全软件等,这类软件从底层获取系统权限,优先级始终高于应用层软件,导致应用层软件不能优先接收到广播消息,所以在设计短信接收客户端时一般采用监听数据库方式。
当客户端接收到短信后会将其插入SQLite数据库,数据库发生变化会触发内容观察者——ContentObserver。
ContentObserver类似于一个触发器,当其所观察的Uri发生变化,这个触发器就会触发来执行相应的处理。主要方法的说明略——编者注。
本系统在onChange的方法中,利用Context实例对象的getContentResolver方法获得一个ContentResolver对象,然后调用Content Reso lver的query方法获取当前数据库中的短消息。具体代码略——编者注。
对于得到的短消息通过Cursor对象的getColumnIndexOrThrow方法获取其thread_id,id和body内容。对于在数据库中的短消息,为了保证对用户的透明传输,要调用ContentResolver对象的delete方法将收件箱中的短消息删除。具体代码略——编者注。
ContentObserver接收短信模块需要在清单文件AndroidManifest.xml中加入允许接收短信的权限:
2.3 Handler机制
对于使用ContentObserver接收到房间温度信息后,通过Android的Handler机制将信息传送到主activity显示。在Android中,主程序会创建一个Looper对象,在Looper对象初始化时候会创建一个消息队列Message Queue用来存放线程放入的消息。用户可以构造一个Handler对象与Looper沟通,以便将消息push到消息队列中。当主线程检测到有新消息进入消息队列后,首先判断该消息对应的Handler,然后将消息分发到指定的Handler处理。
系统中通过ContentObserver继承类SMSContentObserver的构造函数将在activity中定义的Handler对象传入SMSContentObserver中,然后调用Handler对象的obtainMessage方法获得一个message对象,最后调用message对象的sendToTarget方法将控制消息发送到消息队列,在activity中定义了handleMessage函数用来处理得到的控制消息。具体代码略——编者注。
2.4 Android终端效果
Android客户端控制界面见图6,当点击“获取温度”按钮,Android端会自动向系统控制端发送短信“1:O:O:00”,这样系统控制端会检测到是1类控制信息,则返回每个房间温度。
当需要设置某个房间空调的丁作方式,则通过点击“设置空调”按钮左侧的“房间号”、“空调模式”和“设置温度”等三个下拉列表(Spinner)来设置。如设置房间号为“房间二”,空调模式为“制冷”,设置温度为“25℃”,然后点击“设置空调”按钮,安卓端会自动发送2类控制信息“2:2:2:25”到系统控制端,系统接收到控制信息会处理后返回设置是否成功消息。安卓端解析后将其显示。当需要关闭某个房间空调,可以通过“关闭空渊”按钮左侧的“要关闭空调所在房间号”下拉列表实现,比如选择“房间五”,然后点击“关闭空调”按钮,Android端即把3类控制信息“3:5:0:00”发送到系统控制端,系统控制端处理后将空调关闭状态返回。
结语
智能家居中的远程控制方式有很多,本系统结合Androld终端的用户友好型界面,采用自定义协议方式,设计了一套基于短消息的空调控制系统。在Android终端接收返回信息的两种方式中,ContentObserver因其稳定性在工程实践中使用较多,本系统最终也是采用了Cont entOb—server的方式,并取得很好的效果。本系统设计合理,性能稳定,对其他工程设计也具有一定参考价值。