极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 13396|回复: 1

应用教程2:Machtalk物联网平台控制开关量、数字量及监测环境温度

[复制链接]
发表于 2014-11-11 14:19:21 | 显示全部楼层 |阅读模式
本帖最后由 weijinhe 于 2014-11-13 08:43 编辑

        感谢dfrobot提供的wido wifi模块,还是比较容易上手的。通过这篇案例向大家介绍machtalk平台做为云平台如何存储展示采集数据,并向大家介绍如何通过socket长连接的方式上传数据、控制开关量及控制数字量
      相信很多人现在都了解如何通过云平台上传数据以及http方式控制开关量但却不知道如何通过云平台控制模拟量。首先说一下通过http方式控制开关量,这是采用轮询的方式查询云平台的数据来控制设备的开关量,有个缺点它并不是实时的,而且云平台并不知道是否真正的已经控制设备。Machtalk云平台采用socket长连接的方式,让服务器和设备之间通过心跳保持连接,这样云平台就可以知道设备是否在线,并且通过信息反馈的方式通知云平台在线设备是否真正得到了控制,只有设备真正得到了控制,云平台才会显示控制后的界面。
      另外Machtalk云平台采用的是服务器集群,这样避免了所有设备只连接一台服务器,服务器压力过大的危险。设备连接machtalk云平台需要先连接登录服务器,由登录服务器通过负载均衡分配给设备一个connect服务器的IP和端口,然后设备再去连接connect服务器,这样避免服务器压力过大而崩溃。
      进入主题,文档将详细介如何使用wido wifi模块(当然也可以采用其他硬件产品)上传数据、控制开关量及控制模拟量,为电子产品爱好者、开发者及做智能家居、可穿戴产品、家电产品的朋友提供一份参考。文档分为以下几个部分讲诉1、硬件准备连接 2、machtalk物联网平台配置 3、软件编程 4、物联网平台数据展示。
    一、硬件准备连接
     1、wido模块(由dfrobot提供,非常感谢哦)
     2、数据线(安卓手机上的数据线一根 也是dfrobot提供的)
     3、模拟量传感器一个,LM35 (5V GND OUT)分别与wido模块的5V GND A(0)连接。
     4、继电器(用于控制插座、灯开关)
     5、舵机(用于控制数字量)


程序中使用到的库及程序源码:
二、Machtalk物联网平台配置
1、注册帐号
访问注册地址:http://www.machtalk.net/user/registIndex 如下图,填写必填信息

注册后会有一个邮箱激活的信息,到注册邮箱激活就可以了。里面有一些machtalk平台的基本信息,还有一个技术交流群号300250166。
2、设备添加
登录machtalk平台,进入用户中心,在这里会看到自己的基本信息。

点击左边的“设备”,会进入到设备列表,如下图所示:

在这个地方可以看到自己帐号上的所有设备,点击 “增加设备”进入添加设备页面:



      其中有两项非常重要:值类型和值ID, 会在编程中用到。值类型是指你的数据是哪种类型的数据(1数值类, 2 开关类,3 GPS类,4 泛型类)值ID是指你这个设备中的第几个值。要记住这两个哦,编程中会用到。设备ID、值和值类型ID位置可以看下面的URL:
    /v1.0/device/device_id/device_value_id/device_value_type_id/datapoints/add
    还有一项PIN码也非常重要,是你这个设备的密码,在编程中会用到,是系统自动生成的。

    也可以添加动作、添加触发器,它的作用是当采集的数据值超出你设定的范围值 就会向你的邮箱发邮件报警等。
三、软件编程
1、首先下载wido使用库,以及一个json解析库,放置\Arduino\libraries库文件夹里。
2、下载已经写好的wido2machtalk456或wido2machtalk789程序,修改自己帐号设备ID、值ID、值类型ID以及pin码(这是这个设备的密码,是自动生成的),wido2machtalk789程序是断线自动重连。
3、程序流程:
(1)Wido模块连接自己家的无线路由器:
  1. Wido.begin();
  2.   if (!Wido.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
  3.     Serial.println(F("Failed!"));
  4.     while(1);
  5.   }
  6.   while (!Wido.checkDHCP())
  7.   {
  8.     delay(100); // ToDo: Insert a DHCP timeout!
  9.   }  
复制代码

(2)连接登录服务器并发送登录操作
消息格式:
{
    "cmd": "login",
    "mid":"1",//递增,记录在会话session中
    "type":"1",//用户1、设备2
    "usr": "liupeizhi", //用户代表用户名,设备代表设备ID
    "pwd": "dc483e80a7a0bd9ef71d8cf973673924"//MD5加密后的密码,用户代表密码,设备代表设备PIN
}
  1.   static unsigned long RetryMillis = 0;

  2. // lian jie ip
  3. delay(5000);
  4.   if(!WidoClient.connected() && millis() - RetryMillis > TCP_TIMEOUT)
  5.   {
  6.     RetryMillis = millis();
  7.     WidoClient.close();
  8.     ip =Wido.IP2U32(60,211,253,162);
  9.     WidoClient = Wido.connectTCP(ip, 7779);         
  10.   }
  11. //fa song deng lu cao zuo
  12.   delay(1000);
  13.   WidoClient.fastrprintln(F("{"cmd":"login","mid":"1","type":2,"usr":"87e4f47cc03347ee8382b24dfb1516c9","pwd":"4a71754c408fd009b522acd57f1dc39c"}"));
复制代码

返回信息:
登录成功则返回:
server->user/dev
{
    "cmd": "resp",
    "success": 1,
    "mid": "222",
    "apikey": "ssssss", //用户APIKey
    "ip": "192.168.0.1", //连接服务器IP
    "port": 6666//服务器端口
}
登录失败返回:
{"cmd":"resp","success":0,"errorcode":"10000","mid":"ddd222"}
(3)接收登录服务器发送的信息并解析接收的json
  1. recv();
  2.    JsonParser<32> parser;
  3.    JsonHashTable hashTable = parser.parseHashTable(json);
  4.    hashTable.success();

  5.     char* ipok = hashTable.getString("ip");  
  6.     uint8_t a,b,c,d;
  7.     sscanf(ipok,"%d.%d.%d.%d",&a,&b,&c,&d);
  8.     ip =Wido.IP2U32(a,b,c,d);
  9.    
  10.     char* port=hashTable.getString("port");
  11.     uint16_t portok=atoi(port);
  12.     WidoClient.close();
复制代码
  1. void recv(){
  2. unsigned long rTimer = millis();
  3. while(millis() - rTimer < 2000)
  4. {
  5.   while (WidoClient.connected() && WidoClient.available())
  6.    {
  7.         char c = WidoClient.read();
  8.         if(c =='{')
  9.         Response=true;
  10.         else if(c =='}')
  11.         {
  12.         Response=false;
  13.         Response+=c;
  14.         }
  15.         if (Response)
  16.         returnvalue +=c;        
  17.    }
  18. }   
  19.   if (returnvalue.length() !=0)
  20.   {        
  21.     int i;  
  22.     Serial.print(returnvalue);
  23.     for(i=0;i<returnvalue.length();i++)
  24.     json[i]=returnvalue[i];
  25.     json[i]='\0';
  26.     returnvalue="";   
  27.   }
  28. }  
复制代码

(4)连接connect服务器和端口,并发送连接信息
消息格式:
{
    "cmd": "connect",
    "mid": "222",
    "usr": "username/deviceid",
    "type": 1/2,//1:用户 2:设备
    "encode": ""//加密算法
}
返回信息:
成功时返回:
{"cmd":"resp","success":1,"mid":"222"}
失败时返回:
{"cmd":"resp","success":0,"errorcode":"10000","mid":"222"}
  1. WidoClient = Wido.connectTCP(ip, portok);     
  2.     delay(1000);
  3.   // que ren lian jie  
  4.     WidoClient.fastrprint(F("{"cmd":"connect","mid":""));
  5.     mid+=1;
  6.     itoa(mid,strmid,10);
  7.     WidoClient.fastrprint(strmid);
  8.     WidoClient.fastrprintln(F("","usr":"87e4f47cc03347ee8382b24dfb1516c9","type":2,"encode":""}"));  
复制代码

(5)接收云平台connect服务器发来的消息并向服务器发送心跳消息
  1. static unsigned long lasttime = 0;      
  2.     static unsigned long last = 0;
  3.     static unsigned long sensorstamp = 0;

  4.     if(WidoClient.available())
  5.      {
  6.         char c = WidoClient.read();
  7.         if(c=='{')
  8.         Response=true;
  9.         else if(c =='}')
  10.         {
  11.         Response=false;
  12.         returnvalue+=c;
  13.         }
  14.         if (Response)
  15.         returnvalue +=c;                  
  16.      }      
  17.     if(millis()-lasttime>10000)
  18.       {
  19.         lasttime=millis();
  20.         WidoClient.fastrprintln("{1}");
  21.       }
复制代码

(6)操作设备
云平台操作设备时接收到的消息格式
消息内容:
{
    "cmd": "opt",
    "mid": "ddd222",
    "to": "c95808d07d83430d919b3766cafc3ff3",
    "from": "username", //服务端拼加,根据sessionID确认from
    "dvid": 5,
    "value": "commandvaluestr"
}
返回信息:
操作设备成功,设备向服务器发送以下内容:
{
    "cmd": "post",
    "from": "c95808d07d83430d919b3766cafc3ff3",
    "values": [
        {
            "dvid": “5”,
            "value": "commandvaluestr"
        }
    ],
"needack": 1,
mid":"ddd222"//需要一个mid来确定是哪条消息
}
  1. if(returnvalue.length() !=0&&Response==false)
  2.      {      
  3.       Serial.println(returnvalue);      
  4.       int i;  

  5.       //jie xi
  6.       for(i=0;i<returnvalue.length();i++)
  7.       json[i]=returnvalue[i];
  8.       json[i]='\0';
  9.       returnvalue="";   
  10.       JsonParser<32> parser;
  11.       JsonHashTable hashTable = parser.parseHashTable(json);
  12.       hashTable.success();
  13.       char* scmd = hashTable.getString("cmd");
  14.       char* smid = hashTable.getString("mid");
  15.       char* svalue = hashTable.getString("value");  
  16.       char* sdvid=hashTable.getString("dvid");
  17.       int idvid = hashTable.getLong("dvid");


  18.       if(strcmp(scmd,"opt")==0)
  19.       {

  20.          WidoClient.fastrprint(F("{"cmd":"post","from":"87e4f47cc03347ee8382b24dfb1516c9","values":[{"dvid":"));
  21.          WidoClient.fastrprint(sdvid);
  22.          WidoClient.fastrprint(F(","value":""));
  23.          WidoClient.fastrprint(svalue);
  24.          WidoClient.fastrprint(F(""}],"needack":1,"mid":""));
  25.          WidoClient.fastrprint(smid);
  26.          WidoClient.fastrprintln(F(""}"));        
  27.        if(idvid==2)
  28.         {
  29.           int b;
  30.           b=atoi(svalue);
  31.           digitalWrite(13, b);         
  32.         }
  33.         
  34.       }
  35.       

  36.      }
复制代码

(7)数据上传
消息内容:
{
    "cmd": "post",
    "from": "c95808d07d83430d919b3766cafc3ff3",
    "values": [
        {
            "dvid": “5”,
            "value": "commandvaluestr"
        }
    ],
"needack": 1,
“mid”:”123”
}
返回消息:
成功返回:
{"cmd":"resp","success":1,“mid”:”123”}
失败返回:
{"cmd":"resp","success":0,"errorcode":"10000",“mid”:”123”}
  1. if(millis()-sensorstamp>10000)
  2.      {
  3.       sensorstamp=millis();
  4.       int reading = analogRead(0);
  5.   
  6.       
  7.       WidoClient.fastrprint(F("{"cmd":"post","from":"87e4f47cc03347ee8382b24dfb1516c9","values":[{"dvid":1,"value":""));
  8.       itoa(reading,strtemp,10);
  9.       WidoClient.fastrprint(strtemp);
  10.       WidoClient.fastrprint(F(""}],"needack":1,"mid":""));
  11.       mid+=1;  
  12.       itoa(mid,strmid,10);
  13.       WidoClient.fastrprint(strmid);
  14.       WidoClient.fastrprintln(F(""}"));
  15.       
  16.      }            
复制代码

       以上介绍完了machtalk定义的socket交互协议的消息内容,以及如果通过wido模块编码,会把源码及所使用到的库附在附件中,用户只要把使用库放在arduino的库文件中,并下载已经写好的代码,把代码中的ID替换成自己ID就可以实现设备控制了。
四、数据展示
OK 大功告成了
查看数据结果吧http://machtalk.net/device/dataview/87e4f47cc03347ee8382b24dfb1516c9
此图用于显示历史数据。

此数据是有点乱,是因为采集口没有放传感器,放个传感器就OK啦。
这是控制界面的图:

此数据是有点乱,是因为采集口没有放传感器,放个传感器就OK啦。
这是控制界面的图:

本帖子中包含更多资源

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

x
回复

使用道具 举报

发表于 2015-2-9 20:06:31 | 显示全部楼层
函数库都添加到arduino的libraries了,但是发现很多错误?以下列出一部分。
In file included from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\utility/evnt_handler.h:47:0,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:27:
C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\utility/socket.h:144:23: error: conflicting declaration 'typedef long unsigned int socklen_t'
typedef unsigned long socklen_t;
                       ^
In file included from G:\arduino-1.5.3-Intel.1.0.4\hardware\arduino\edison\variants\edison_fab_c/variant.h:9:0,
                 from G:\arduino-1.5.3-Intel.1.0.4\hardware\arduino\edison\cores\arduino/Arduino.h:33,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.h:24,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:23:
G:\arduino-1.5.3-Intel.1.0.4/hardware/tools/edison/sysroots/core2-32-poky-linux/usr/include/unistd.h:274:21: error: 'socklen_t' has a previous declaration as 'typedef __socklen_t socklen_t'
typedef __socklen_t socklen_t;
                     ^
In file included from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\utility/evnt_handler.h:47:0,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:27:
C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\utility/socket.h:163:3: error: conflicting declaration 'typedef struct fd_set fd_set'
} fd_set;
   ^
In file included from G:\arduino-1.5.3-Intel.1.0.4/hardware/tools/edison/sysroots/core2-32-poky-linux/usr/include/sys/types.h:219:0,
                 from G:\arduino-1.5.3-Intel.1.0.4/hardware/tools/edison/sysroots/core2-32-poky-linux/usr/include/stdlib.h:314,
                 from G:\arduino-1.5.3-Intel.1.0.4\hardware\arduino\edison\cores\arduino/Arduino.h:27,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.h:24,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:23:
G:\arduino-1.5.3-Intel.1.0.4/hardware/tools/edison/sysroots/core2-32-poky-linux/usr/include/sys/select.h:75:5: error: 'fd_set' has a previous declaration as 'typedef struct fd_set fd_set'
   } fd_set;
     ^
In file included from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\utility/evnt_handler.h:47:0,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:27:
C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\utility/socket.h:448:61: error: declaration of C function 'int select(long int, fd_set*, fd_set*, fd_set*, timeval*)' conflicts with
                   fd_set *exceptsds, struct timeval *timeout);
                                                             ^
In file included from G:\arduino-1.5.3-Intel.1.0.4/hardware/tools/edison/sysroots/core2-32-poky-linux/usr/include/sys/types.h:219:0,
                 from G:\arduino-1.5.3-Intel.1.0.4/hardware/tools/edison/sysroots/core2-32-poky-linux/usr/include/stdlib.h:314,
                 from G:\arduino-1.5.3-Intel.1.0.4\hardware\arduino\edison\cores\arduino/Arduino.h:27,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.h:24,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:23:
G:\arduino-1.5.3-Intel.1.0.4/hardware/tools/edison/sysroots/core2-32-poky-linux/usr/include/sys/select.h:106:12: error: previous declaration 'int select(int, fd_set*, fd_set*, fd_set*, timeval*)' here
extern int select (int __nfds, fd_set *__restrict __readfds,
            ^
In file included from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:35:0:
C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\utility/sntp.h:293:8: error: 'alarm' redeclared as different kind of symbol
        alarm
        ^
In file included from G:\arduino-1.5.3-Intel.1.0.4\hardware\arduino\edison\variants\edison_fab_c/variant.h:9:0,
                 from G:\arduino-1.5.3-Intel.1.0.4\hardware\arduino\edison\cores\arduino/Arduino.h:33,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.h:24,
                 from C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:23:
G:\arduino-1.5.3-Intel.1.0.4/hardware/tools/edison/sysroots/core2-32-poky-linux/usr/include/unistd.h:432:21: error: previous declaration of 'unsigned int alarm(unsigned int)'
extern unsigned int alarm (unsigned int __seconds) __THROW;
                     ^
C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp: In member function 'bool Adafruit_CC3000::scanSSIDs(uint32_t)':
C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:178:56: error: 'F' was not declared in this scope
       CC3KPrinter->println(F("Started AP/SSID scan\n\r"));
                                                        ^
C:\Users\jh\Documents\Arduino\libraries\AdafruitCC3000Librarymaster\Adafruit_CC3000.cpp:103:123: error: 'F' was not declared in this scope
#define CHECK_SUCCESS(func,Notify,errorCode)  {if ((func) != CC3000_SUCCESS) { CHECK_PRINTER CC3KPrinter->println(F(Notify)); return errorCode;}}
               
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-16 21:37 , Processed in 0.049931 second(s), 20 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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