查看: 22199|回复: 10

飞比物联网培训教程--"玩转物联网"之四、web网页控制Zigbee电灯(B/S模式)

[复制链接]
outman 发表于 2012-10-23 00:59:08 | 显示全部楼层 |阅读模式
飞比物联网培训教程--"玩转物联网"之四、web网页控制Zigbee电灯(B/S模式)


该系列文章已经全部更新至“飞比云百科知识库(FBee Cloud WIKI)”中,建议到以下网址阅读:http://www.fbeecloud.com/wiki



  这是很好玩的一步:把自己的传感器用网页画出来,放在自己的服务器上,别人可以登录你的网站,查看你传感器的值;或者把自己的“电灯”放在网页上,别人可以来开关。当然,“别人”一定事先要征求你的同意才可以这样做,否则你卧室的灯,一会就有人来开一下,这样的“高科技”估计没人愿意要!

  而且这种B/S模式的最大好处就是只要有一个浏览器(Brower)就可以了,不需要装别的软件,而且不管你用的是电脑,PAD还是手机,是windows、iOS或者是Android的操作系统。

  我们重新来回顾下“飞比云”平台的拓扑结构中,用户自建服务器的位置(注意下图红色边框部分):


  也就是说,您自己的web服务器需要和“飞比云服务平台”建立双向的通信:将传感器数据反映在网页上;同时将用户通过网页发送的控制指令传递给飞比云。要实现这个功能,需要借助html语言与java script脚本,另外需要用到Ajax与JSON技术。作为网页编程技术在物联网中的应用,这里我们不过分地深入到细节,仅了解下基本的原理和实现技巧。

  步骤和以前一样,对于我们这些“画家”,第一步仍然是构思,然后只是用不同的画笔画相同的图而已。

  注:以下内容需要在保证您已经完成了前面的硬件安装与C/S模式的实验,并打开节点的前提下进行。

一、用html语言实现基本的界面

  1、构思中的界面--http://fbeecloud.svfree.net
  

  2、基本界面的html实现
  1. <!DOCTYPE html>

  2. <html>
  3. <head>
  4. </head>

  5. <body>
  6. <script type="text/javascript">
  7. //界面加载时初始化界面
  8. window.onload=function()
  9. {
  10. //电灯状态
  11.   document.getElementById("IMG").src="on.png";
  12.   document.getElementById("txtHint").innerHTML = "电灯状态";
  13.   //控制指令发送状态
  14.   document.getElementById("ctRspStr").innerHTML = "控制指令发送状态";
  15. }
  16. </script>
  17. <div id="D">
  18. <img  id="IMG"/>
  19. <br />
  20. </div>

  21. <div id="txtHint"><b></b></div>
  22. <p></p>
  23. <button type="button1" style="background:#FFFF99;width:100px; height:40px" onclick="">开灯</button>
  24. <button type="button2" style="background:#FFFF99;width:100px; height:40px" onclick="">关灯</button>
  25. <div id="ctRspStr"><b></b></div>
  26. </body>

  27. </html>
复制代码
把这段代码保存成index.html,并且将on.png和off.png两个文件放到同一目录下。

  这里面除了一个加载时运行到的java script函数外,其它的都是最基本的html代码,这里不再赘述,仅强调这里的三个变量的传递:
  1. //界面加载时初始化界面
  2. window.onload=function()
  3. {
  4. //电灯状态
  5.   document.getElementById("IMG").src="on.png";
  6.   document.getElementById("txtHint").innerHTML = "电灯状态";
  7.   //控制指令发送状态
  8.   document.getElementById("ctRspStr").innerHTML = "控制指令发送状态";
  9. }
复制代码
这里做了三个事情:设置了电灯的图片(IMG);“电灯状态”字符(txtHint)与“控制指令发送状态”字符(ctRspStr)。这里之所以没有直接写到html代码中,是因为后续的代码中,我们需要让它们“动”起来。

  3、自建web服务器,并上传代码
  这段内容实际上如果展开来讲,内容蛮复杂。但这类的教程随处可见,我们不去重复了,仅说明几个关键点:

  首先,需要自建一个可供别人浏览的web服务器,可以用IIS等工具用自己的电脑来搭建;但更容易的方式是找一个空间服务商,把网页内容通过FTP上传即可实现浏览。由于我们暂时只是拿来演示,这里推荐一个国内的免费空间-http://www.3v.cm/(免费的空间现在越来越难找了,截止笔者发稿时,这个空间经测试可用,但如果想做一个稳定的网站,这点钱还是应该花的)。

  在上述网站申请了免费空间后,会得到FTP 的地址、用户名、密码,还有一个xxxx.svfree.net这样一个二级域名。然后,找一个FTP软件(比如FlashFXP),将前面的index.html, on.png, off.png等三个文件上传至空间根目录。

  在浏览器中输入您的二级域名,是不是就可以看到构想中的界面了?这实际上已经成功为我们后面的功能做了一个“外壳”。

二、如何让自建web服务器从飞比云服务平台上获取传感器数据

  1、首先,看下飞比云的数据下载API

  http://www.feibit.com/get.php?us ... 11111&upDataCur
  这条指令将返回当前一条数据的内容,其中userID和userKey要替换成您自己的。

  如果您在上述章节“B/S与C/S模式下网络控制Zigbee电灯(二)-C/S模式”中已经实现的相关的实验内容,并且把灯的状态每几秒种向飞比云汇报成功后,通过在浏览器输入这个地址,则可以每几秒钟看到这个数据在更新。

  2、在自己的web服务器中获取传感器数据
  这里涉及到两个不同域名的服务器之间访问的问题,比较常见的作法是使用jQuery进行交互,当然jQuery的内容此处也不进行详解,仅分析下如下交互代码:
  1. //从飞比云服务器获取JSON格式的传感数据
  2. function getFBeeCloudMsg()
  3. {
  4. $.getJSON("http://www.feibit.com/get.php?userID=40&userKey=111111111111111&upDataCur&callback=?",
  5.   {
  6.     foo: "bar",
  7.     format: "json"
  8.   },

  9.   function(data) {
  10.     FBee_cloud_data = data.format;
  11.     //进行界面更新
  12.     document.getElementById("txtHint").innerHTML = FBee_cloud_data;

  13.   });
  14.   
  15. //1秒钟刷新
  16. window.setTimeout(getFBeeCloudMsg, 1000);
  17. }
复制代码
此处,每运行一次getFBeeCloudMsg函数,则向飞比云获取了一次userID为40的用户的当前传感器数据,采用的指令中:
$.getJSON("http://www.feibit.com/get.php?userID=40&userKey=111111111111111&upDataCur&callback=?",
最后的callback为“回调函数”,即“用户web服务器”收到“飞比云服务器”的回应数据后,所调用的函数。此函数实体为:
  1.     FBee_cloud_data = data.format;        //获取飞比云回馈数据
  2.     //进行界面更新
  3.     document.getElementById("txtHint").innerHTML = FBee_cloud_data;
复制代码
另外,window.setTimeout(getFBeeCloudMsg, 1000);这句代码保证了web服务器每秒钟向飞比云请求一次数据。

  完整代码如下:
  1. <!DOCTYPE html>

  2. <html>
  3. <head>
  4. <script src="http://code.jquery.com/jquery-1.5.js"></script>

  5. <script type="text/javascript">
  6. //全局变量
  7. var FBee_cloud_data;        //传感数据

  8. //从飞比云服务器获取JSON格式的传感数据
  9. function getFBeeCloudMsg()
  10. {
  11. $.getJSON("http://www.feibit.com/get.php?userID=40&userKey=111111111111111&upDataCur&callback=?",
  12.   {
  13.     foo: "bar",
  14.     format: "json"
  15.   },

  16.   function(data) {
  17.     FBee_cloud_data = data.format;
  18.     //进行界面更新
  19.     document.getElementById("txtHint").innerHTML = FBee_cloud_data;

  20.   });
  21.   
  22. //1秒钟刷新
  23. window.setTimeout(getFBeeCloudMsg, 1000);
  24. }
  25. </script>
  26.        
  27. </head>

  28. <body>
  29. <script type="text/javascript">
  30. //界面加载时初始化界面
  31. window.onload=function()
  32. {
  33.         //电灯状态
  34.   document.getElementById("IMG").src="on.png";
  35.   //document.getElementById("txtHint").innerHTML = "电灯状态";
  36.   //控制指令发送状态
  37.   //document.getElementById("ctRspStr").innerHTML = "控制指令发送状态";
  38.   getFBeeCloudMsg();
  39. }
  40. </script>
  41. <div id="D">
  42. <img  id="IMG"/>
  43. <br />
  44. </div>

  45. <div id="txtHint"><b></b></div>
  46. <p></p>
  47. <button type="button1" style="background:#FFFF99;width:100px; height:40px" onclick="">开灯</button>
  48. <button type="button2" style="background:#FFFF99;width:100px; height:40px" onclick="">关灯</button>
  49. <div id="ctRspStr"><b></b></div>
  50. </body>

  51. </html>
复制代码
同样,保存为index.html并上传至您个人服务器,更新后发现网页中的数据,已经可以随着传感节点的变化在发生变化。


三、如何对获取的源数据进行解码,并更新界面

  1、首先按“飞比云传感协议V2.0”文档,分析一下上述步骤二中所下载到的数据格式,并相应确认解码算法。以FB0799C0010130000323D065这组数据为例:
  FB:协议头
  07:数据长度(红色)
  99C0:短地址
  0101:一个开关量,值为1
  300003:userID号为0003
  23D0:rssi值为D0
  65:“异或”检验和

  为简化起见,我们仅采用在整个数据包中搜索是否有“0101”确认电灯为“打开”状态;搜索“0100”代表“关闭”状态。当然这种算法不够严谨,此处仅为演示如何来实现功能,用户可自行深入Java Script的编程部分。

  2、获取传感数据后,进行处理:
  1. function processData()
  2. {
  3. var IndexOfData;
  4. var sensorData;
  5. var dataLen;

  6.     IndexOfData = FBee_cloud_data.indexOf("=")+1; //查找数据开始位
  7.    
  8.     //process data, eg: FB05DED03000030101C3(DK) FB0799C0010130000323D065(FBee)
  9.     sensorData = FBee_cloud_data.substring(IndexOfData);
  10.     dataLen = sensorData.substr(3,1);
  11.     node_shortAddr = sensorData.substr(4,4);
  12.     sensorData = sensorData.substr(8,dataLen*2);
  13.    
  14.     if (sensorData.indexOf("0100")>=0)
  15.     {
  16.       document.getElementById("IMG").src="off.png";      
  17.       document.getElementById("txtHint").innerHTML = "The light is OFF.";
  18.     }
  19.     else if (sensorData.indexOf("0101")>=0)
  20.     {
  21.       document.getElementById("IMG").src="on.png";
  22.       document.getElementById("txtHint").innerHTML = "The light is ON.";
  23.     }
  24.     else
  25.     {
  26.       document.getElementById("txtHint").innerHTML = sensorData;
  27.     }
  28. }
复制代码
3、完整代码
  更新至服务器后,可以观察到界面中的电灯的状态图片会随着送上来的“反馈”数据不同而变化。可以通过FIT Explorer软件,本地控制灯的开关后,通过网页来观察其变化。
  1. <!DOCTYPE html>

  2. <html>
  3. <head>
  4. <script src="http://code.jquery.com/jquery-1.5.js"></script>

  5. <script type="text/javascript">
  6. //全局变量
  7. var FBee_cloud_data;        //传感数据
  8. var node_shortAddr;

  9. //获取传感数据后,进行处理
  10. function processData()
  11. {
  12. var IndexOfData;
  13. var sensorData;
  14. var dataLen;

  15.     IndexOfData = FBee_cloud_data.indexOf("=")+1;
  16.    
  17.     //process data, eg: FB05DED03000030101C3(DK) FB0799C0010130000323D065(FBee)
  18.     sensorData = FBee_cloud_data.substring(IndexOfData);
  19.     dataLen = sensorData.substr(3,1);
  20.     node_shortAddr = sensorData.substr(4,4);
  21.     sensorData = sensorData.substr(8,dataLen*2);
  22.    
  23.     if (sensorData.indexOf("0100")>=0)
  24.     {
  25.       document.getElementById("IMG").src="off.png";      
  26.       document.getElementById("txtHint").innerHTML = "The light is OFF.";
  27.     }
  28.     else if (sensorData.indexOf("0101")>=0)
  29.     {
  30.       document.getElementById("IMG").src="on.png";
  31.       document.getElementById("txtHint").innerHTML = "The light is ON.";
  32.     }
  33.     else
  34.     {
  35.       document.getElementById("txtHint").innerHTML = sensorData;
  36.     }
  37. }

  38. //从飞比云服务器获取JSON格式的传感数据
  39. function getFBeeCloudMsg()
  40. {
  41. $.getJSON("http://www.feibit.com/get.php?userID=40&userKey=111111111111111&upDataCur&callback=?",
  42.   {
  43.     foo: "bar",
  44.     format: "json"
  45.   },

  46.   function(data) {
  47.     FBee_cloud_data = data.format;
  48.     //进行界面更新
  49.     processData();

  50.   });
  51.   
  52. //1秒钟刷新
  53. window.setTimeout(getFBeeCloudMsg, 1000);
  54. }
  55. </script>
  56.        
  57. </head>

  58. <body>
  59. <script type="text/javascript">
  60. //界面加载时初始化界面
  61. window.onload=function()
  62. {
  63.         //电灯状态
  64.   document.getElementById("IMG").src="on.png";
  65.   //document.getElementById("txtHint").innerHTML = "电灯状态";
  66.   //控制指令发送状态
  67.   //document.getElementById("ctRspStr").innerHTML = "控制指令发送状态";
  68.   getFBeeCloudMsg();
  69. }
  70. </script>
  71. <div id="D">
  72. <img  id="IMG"/>
  73. <br />
  74. </div>

  75. <div id="txtHint"><b></b></div>
  76. <p></p>
  77. <button type="button1" style="background:#FFFF99;width:100px; height:40px" onclick="">开灯</button>
  78. <button type="button2" style="background:#FFFF99;width:100px; height:40px" onclick="">关灯</button>
  79. <div id="ctRspStr"><b></b></div>
  80. </body>

  81. </html>
复制代码
至此,B/S模式下的采集部分已经完成!

四、关于反向控制

  1、首先,通过API模式测试下飞比云服务平台的反控功能:
  http://www.feibit.com/ctput.php? ... nData=CTO1%2099C000
这条指令控制短地址为99C0的节点,第一个可控IO口的电平状态为0,其中userID和userKey要替换成您自己的,%20代表空格。

  分别用CTO1 99C001与CTO1 99C000两条指令试一下,是否在输入不同的参数并确认后,节点LED灯的状态发生了变化?

  注:采用开发板和FBee模块底板,这里的LED控制状态有所不同,开发板为低有效,即发送CTO1 xxxx00时打开LED灯,相反为关;而FBee模块底板状态刚好相反,所以在设置发送指令时,此处应该尤为注意!

  2、如何通过web页向飞比云服务器发送控制指令
  实际上原理与采集数据的获取完全相同,只是API的参数做了小小的修改,换成了下行控制指令API,核心处理函数如下:
  1. //向飞比云服务器发送控制指令
  2. function sendFBeeCloudCmd(cmdStr)
  3. {
  4. FBee_cloud_cmd = cmdStr;
  5. $.getJSON("http://www.feibit.com/ctput.php?userID=40&userKey=111111111111111&downData="+cmdStr+"&callback=?",
  6.   {
  7.     foo: "bar",
  8.     format: "json"
  9.   },

  10.   function(data) {
  11.     FBee_cloud_cmd_rsp = data.format;
  12.     //返回控制结果
  13.     displayCtrlRsp();
  14.   });
  15. }
复制代码
然后,设置不同的按钮对应发出的控制指令:
  1. <button type="button1" style="background:#FFFF99;width:100px; height:40px" onclick="sendFBeeCloudCmd('CTO1%20'+node_shortAddr+'00')">开灯</button>
  2. <button type="button2" style="background:#FFFF99;width:100px; height:40px" onclick="sendFBeeCloudCmd('CTO1%20'+node_shortAddr+'01')">关灯</button>
复制代码
注:此处node_shortAddr为从采集数据中所获取的“短地址”数据,所以即使短地址发生变化,控制指令仍可准确地控制相应的节点。

  3、完整代码如下:
  1. <!DOCTYPE html>

  2. <html>
  3. <head>
  4. <script src="http://code.jquery.com/jquery-1.5.js"></script>

  5. <script type="text/javascript">

  6. //全局变量
  7. var FBee_cloud_data;        //传感数据
  8. var FBee_cloud_cmd;        //控制指令
  9. var FBee_cloud_cmd_rsp;        //控制指令回复
  10. var node_shortAddr;

  11. //获取传感数据后,进行处理
  12. function processData()
  13. {
  14. var IndexOfData;
  15. var sensorData;
  16. var dataLen;

  17.     IndexOfData = FBee_cloud_data.indexOf("=")+1;
  18.    
  19.     //process data, eg: FB05DED03000030101C3(DK) FB0799C0010130000323D065(FBee)
  20.     sensorData = FBee_cloud_data.substring(IndexOfData);
  21.     dataLen = sensorData.substr(3,1);
  22.     node_shortAddr = sensorData.substr(4,4);
  23.     sensorData = sensorData.substr(8,dataLen*2);
  24.    
  25.     if (sensorData.indexOf("0100")>=0)
  26.     {
  27.         document.getElementById("IMG").src="off.png";      
  28.         document.getElementById("txtHint").innerHTML = "The light is OFF.";
  29.     }
  30.     else if (sensorData.indexOf("0101")>=0)
  31.     {
  32.         document.getElementById("IMG").src="on.png";
  33.         document.getElementById("txtHint").innerHTML = "The light is ON.";
  34.     }
  35.     else
  36.     {
  37.         document.getElementById("txtHint").innerHTML = sensorData;
  38.     }
  39. }

  40. //显示控制指令发送结果
  41. function displayCtrlRsp()
  42. {
  43.   var command = FBee_cloud_cmd.substr(11,2);
  44.   //CTO1 XXXX01
  45.   if (command=="01")
  46.   {
  47.     document.getElementById("ctRspStr").innerHTML = "Successfully send TURN OFF command to FBee Cloud!";
  48.   }
  49.   else if (command=="00")
  50.   {
  51.     document.getElementById("ctRspStr").innerHTML = "Successfully send TURN ON command to FBee Cloud!";
  52.   }
  53.   else
  54.   {
  55.     document.getElementById("ctRspStr").innerHTML = FBee_cloud_cmd_rsp;
  56.   }
  57. }
  58. </script>

  59. <script>
  60. //从飞比云服务器获取JSON格式的传感数据
  61. function getFBeeCloudMsg()
  62. {
  63. $.getJSON("http://www.feibit.com/get.php?userID=40&userKey=111111111111111&upDataCur&callback=?",
  64.   {
  65.     foo: "bar",
  66.     format: "json"
  67.   },

  68.   function(data) {
  69.     FBee_cloud_data = data.format;
  70.     //进行界面更新
  71.     processData();
  72.   });
  73.   
  74. //1秒钟刷新
  75. window.setTimeout(getFBeeCloudMsg, 1000);
  76. }

  77. //向飞比云服务器发送控制指令
  78. function sendFBeeCloudCmd(cmdStr)
  79. {
  80. FBee_cloud_cmd = cmdStr;
  81. $.getJSON("http://www.feibit.com/ctput.php?userID=40&userKey=111111111111111&downData="+cmdStr+"&callback=?",
  82.   {
  83.     foo: "bar",
  84.     format: "json"
  85.   },

  86.   function(data) {
  87.     FBee_cloud_cmd_rsp = data.format;
  88.     //返回控制结果
  89.     displayCtrlRsp();
  90.   });
  91. }
  92. </script>
  93. </head>

  94. <body>

  95. <script type="text/javascript">
  96. //界面加载时即周期性获取传感数据
  97. window.onload=function()
  98. {
  99.   getFBeeCloudMsg();
  100. }
  101. </script>

  102. <div id="D">
  103. <img  id="IMG"/>
  104. <br />
  105. </div>

  106. <div id="txtHint"><b></b></div>
  107. <p></p>
  108. <button type="button1" style="background:#FFFF99;width:100px; height:40px" onclick="sendFBeeCloudCmd('CTO1%20'+node_shortAddr+'00')">开灯</button>
  109. <button type="button2" style="background:#FFFF99;width:100px; height:40px" onclick="sendFBeeCloudCmd('CTO1%20'+node_shortAddr+'01')">关灯</button>
  110. <div id="ctRspStr"><b></b></div>
  111. </body>

  112. </html>
复制代码
更新至服务器中,用电脑、PAD或者手机不同的方式,享受您的“Zigbee远程电灯”之旅吧!

  好了,只剩下最后一个疑点没有揭开了,那就是为什么我们一直把Zigbee电灯的userID号设为0003?如果您有Android的平板电脑或者手机,到www.feibit.com/fit.apk这个地址下载一个“飞比云客户端”的软件,输入用户名、密码,打开界面后,点击里面的电灯,再看下您节点上的LED灯是否也跟着变化了呢?

  

  


  这就是userID=0003的原因:我们已经做过一个基于android的客户端软件,但目前还不能用户自行更改设置,还只是一个demo,但它的功能会慢慢向电脑版的FIT靠拢!

<<小记>>:至此,一个小小的电灯已经完成了它从“采集”到“控制”,从“本地”到“互联网”,从“电脑”到“移动嵌入式设备”各个方面的功能。当然,这只是“飞比云服务平台”的B/S与C/S模式下的一个小的侧面,但是它打开了潘多拉的盒子,因为互联网的应用可以说是无限的:短信、微博、微信,各种各样的已经成熟的互联网服务都可以与其进行接轨,在打通这个“物”联到“网”的通道后,接下来的故事才刚刚开始… …

  飞比物联网培训教程--"玩转物联网"之一、前言及目录

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
我的生活 发表于 2012-10-23 11:00:33 | 显示全部楼层
顶过再看
Bonnie.Liang 发表于 2012-10-31 17:17:48 | 显示全部楼层
又可以为自己充电了……顶起先……
梦之缘工作坊 发表于 2012-11-4 20:38:58 | 显示全部楼层
非常不错,不知道是否还有后续教程呢,很是期待呀。最近考完试,把实验室的物联网实训箱用起来,试试效果,迫不及待了,哈哈~
逍遥子 发表于 2012-12-8 19:40:29 | 显示全部楼层
这个很重要,有一定的实用价值!!
逍遥子 发表于 2012-12-8 19:40:29 | 显示全部楼层
这个很重要,有一定的实用价值!!
星夜 发表于 2012-12-29 09:02:39 | 显示全部楼层
顶一下 太棒了 使用
mm531865840 发表于 2013-7-8 10:02:18 | 显示全部楼层
太牛逼了,好好学,多拉风啊
冰芷ice 发表于 2013-8-5 16:48:09 | 显示全部楼层
有意思{:soso_e142:}
uoudio 发表于 2014-4-8 21:44:20 | 显示全部楼层
为什么文中的链接打不开?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表