27
2019
04

Arduino开源智能家居01《网关》升级版网关正式教程(zigbee)

这篇开始,我们就真正做《网关》升级版教程了,采用arduino+zigbee哦。
arduino简单易学,zigbee自组网(如果不懂c语言,直接用就好,我们已经刷好自组网代码)!


这次我们的教程是通过以下配件实现《网关》功能,并在手机端点击按钮,使zigbee模块上的灯闪亮(实现是发送真正的命令了{ckxxxxxxxxx}的格式)!
通过不同的格式命令就可以操作开、关、接收、发送数据!之后《温湿传感器》《zigbee插座》等就可以直接连上了!


上面就是arduino开源网关的配件。

1、SMARTRF04EB(ZIGBEE下载器)35元
2、CP2102(arduino下载器)15元
3、电源供电 10元
4、arduino板(含w5100、zigbee插槽、SD卡座)100元
5、zigbee开发板 30元 (如果只想学zigbee只需要两块开发板和zigbee模块,自组网学习哦)
6、zigbee模块 45元

淘配件:https://item.taobao.com/item.htm?id=576067599077

本帖隐藏的内容

一共是235元,实现自己的arduino开源网关吧(自己有arduino和w5100是可以代替我们的arduino板的)。






第一部份:arduino板刷上代码。

一、安装CP2102驱动(USB驱动)
http://pan.baidu.com/s/1o6iDLcm(下载后直接安装或发现有新硬件就更新驱动)。


二、将CP2102连上arduino板底下的插槽的一定要一一对应哦。
DTR->DTR
GND->GND
TX->RXI
RX->TXO
VDD3.3->VCC









三、刷arduino代码
大家可以直接在这里下载源代码:
http://pan.baidu.com/s/1i386zPV(包含arduino软件和所有的库)



下面我们就贴上代码(都有注释哦)


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
#include <iBoardRF24Network.h>
#include <iBoardRF24.h>
#include <digitalWriteFast.h>
#include <SPI.h>
#include <Ethernet.h>
  
   
  
//请到m.znck007.com申请登陆-》家中环境-》网关,里可以看到!
#define APIKEY "xxxxxxxxxxxxxxxx" //设置apikey
 
uint16_t sid=001;//设置sid(设备号)
  
  
 
//NRF24l01发送接收节点
const uint16_t this_node = 0;
const uint16_t other_node = 1;
  
//NRF24l01收发数据
struct payload_t
{
  uint32_t ms;
  uint32_t data;
  char sendchar[20];
};
 
//NRF24l01脚针设置
iBoardRF24 radioSend(3,8,5,6,7,2);
iBoardRF24Network networkSend(radioSend);
 
bool ispayload=false;//NRF24l01收发判断
uint16_t sendChannel=1;//NRF24l01发送频道
uint32_t sendCount=0;//NRF24l01发送次数
 
char incomingData[20]={0};//NRF24l01接收到的字符(其它设置发过来)
 
 
 
 
 
//设置MAC地址,如果有二个请改为不同(随意)
static byte mymac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
   
EthernetClient client;//声明网关类
 
char server[] = "api.znck007.com";//声明API网址
//char urlBuf[] = "/index.php";
 
static long timer;//用于规定时间间隔
unsigned long last_http;//记录http时间,用于http超时判断,目前20秒无响应则重新GET。
bool ishttpget=false;//标示http是否已经结束
 
 
 
bool isUpdate=false;//成功则更新服务器数据为正常
char updateData[20]={0};//更新的字符(服务器通过字符分析指定某个设备)
 
//串口通信处理(主要用于zigbee通信)
unsigned long serialnowlast;
char serialbuff[80]={0};
char serialData;
int seriali=0;
 
 
  
void setup(void)
{
  //设置串口波特率
  Serial.begin(115200);
  Serial.println("IBOARD_GATEWAY_ZIGBEE/RF24Network");
   
  //NRF24l01初始化
  SPI.begin();
  radioSend.begin();
   
  //获取IP DNS等
  Serial.println("\n[getDHCPandDNS]");
  if (Ethernet.begin(mymac) == 0)
  {
        Serial.print(F("Failed to configure Ethernet using DHCP\n"));
        while(1);
   }
   else
   {
        Serial.print("My IP address: ");
        for (byte thisByte = 0; thisByte < 4; thisByte++) {
       // print the value of each byte of the IP address:
        Serial.print(Ethernet.localIP()[thisByte], DEC);
        Serial.print("."); }
        Serial.println("Ethernet configuration OK");
  }
  
  //连接web服务器
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected");   
    client.println("GET /index.php HTTP/1.1");
    client.println("Host: api.znck007.com");
    client.println("Connection: close");         
    client.println();
  }
  else {
    // kf you didn't get a connection to the server:
    Serial.println("connection failed");
    client.stop();
  }
   
  //判断web服务器是否正常
  timer=millis();
  while ((!client.available()) && (millis()-timer)<2000);
 
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
    client.stop();
  }
  timer = millis(); 
  
  //完成setup
  Serial.println("setup success");   
   
}
 
 
void loop(void)
{
//  //NRF24l01检测接收数处理
//  //如果使用NRF24l01,请启动这里(并删除ZIGBEE检测接收数据处理)
//  networkSend.begin(/*channel*/ sid, /*node address*/ this_node);
//  // Pump the network regularly
//  networkSend.update();
//
//  // Is there anything ready for us?
//  timer=millis();
//  //while ((!networkSend.available())  && (millis()-timer)<2000);
//  while(networkSend.available())
//  {
//    // If so, grab it and print it out
//    RF24NetworkHeader header;
//    payload_t payload;
//    memset(payload.sendchar, 0, 20);
//    networkSend.read(header,&payload,sizeof(payload));
//    Serial.print("Received packet #");
//    Serial.print(payload.data);
//    Serial.print(" at ");
//    Serial.print(payload.ms);
//    Serial.print(" getchar ");
//    Serial.println(payload.sendchar);
//
//    ispayload = true;
//   
//    get_html_body(payload.sendchar,incomingData);
//    Serial.println(incomingData);
//  }
// 
//  if(!ishttpget)
//  {
//        if(ispayload)
//        {
//          ispayload = false;
//
//      if(strstr(incomingData,"{ck") && strstr(incomingData,"}") )
//        {
//          last_http = millis();         
//          ishttpget=true; 
//                   
//          Serial.println("\n>>> POST");
//          static char buf[20]={0};
//          sprintf(buf,"%s",incomingData);
//
//          client_post(server,APIKEY,buf);
//          my_result_cb();
//               
//          return;
//        }               
//       
//        }
// 
// 
//  }
 
 
  //ZIGBEE检测接收数据处理
  if(!ishttpget)
  {  
       
      unsigned long serialnow = millis();//获取现在的时间
      if(serialnow - serialnowlast >= 5000)//如果数据间隔超过5秒而清空字符(为了防止数据错乱)
      {
        serialnowlast = millis();
        memset(serialbuff, 0, 80);
        seriali=0;
      }
       
      bool isSerial=false;
      while( Serial.available() )//如果串口有数据(ZIGBEE或电脑发过来的)
      {
        if(seriali==0)
        {
          Serial.println("Serial->");//打印出来方便调试
        }      
        serialData=(char)Serial.read();//读取串口数据
        //Serial.print(serialData);////这里不打印,否则ZIGBEE检测到{ckxxxx}就认为是命令
        serialbuff[seriali]=serialData;////保存到数组
        seriali++;////数组长度+1
        if(serialData=='}' || seriali>=80)//如果发现}而说明命令结束(并少于80个字符,太长会出错)
        {
          isSerial=true;
          break;
        }
      }
       
      //开始处理{ckxxxxx}字符,如POST上传到web服务器
      if(isSerial)
      {
        serialnowlast = millis(); //更新当前时间,不然5秒就超时了
         
        //Serial.println(serialbuff);
        char body[81]={0};
        get_html_body(serialbuff,body);//获取只是{ckxxxxxx}的字符,因为这是我们的命令格式
        //Serial.println(body);   
        
        Serial.println("-------------------");
        
       //如果命令格式真确则POST到web服务器了
        if(strstr(body,"{ck") && strstr(body,"}") )
        {         
          last_http = millis();
          ishttpget=true;
          timer = millis();
           
          Serial.println("\n>>> POST");
          //static char buf[81]={0};
          //sprintf(buf,"%s",body);
           
          client_post(server,APIKEY,body);//POST到网址,APIKEY,字符
          my_result_cb();//接收web服务器返回的字符
           
        }
        
        memset(serialbuff, 0, 80);//清空字符
        seriali=0;//字符长度为0
         
        return;
      }
  }
  //delay(200);
 
  //更新web服务器命令的状态(比如发送成功还是失败还是异常等,NRF24l01用到,ZIGBEE不用这里而是直接发送{ck00xxxxxxupdate}命令就行)
  if( isUpdate )
  {
      isUpdate=false;
     
      last_http = millis();
      ishttpget=true;     
       
      Serial.println("\n>>> UPDATE");
 
      static char buf[20]={0};
      sprintf(buf,"%s",updateData);
      //Serial.println(buf); 
    
      client_post(server,APIKEY,buf);//POST到网址,APIKEY,字符
      my_result_cb();//接收web服务器返回的字符       
      isUpdate=false;
       
      return;
  }
 
  //每2秒钟查看web服务器是有命令数据
  unsigned long now = millis();  
  if(now - last_http >= 2000)
  {
    if(!ishttpget || (now - last_http) >= 20000)//20秒超时会执行,为了防卡死问题
    {
       last_http = millis();
       ishttpget=true;     
             
         
      Serial.println("\n>>> REQ");
      static char buf[20]={0};
      sprintf(buf,"{ck001000000000}"); //这个字符串代表获取新命令数据
      client_post(server,APIKEY,buf);//POST到网址,APIKEY,字符
      my_result_cb();//接收web服务器返回的字符       
       
      timer = millis();
 
    }
    
  }  
   
 
}
 
//接收web服务器返回的字符       
static void my_result_cb(){
  char eth_buffer[350];
  timer=millis();
  while ((!client.available()) && (millis()-timer)<1000);
 
  if (client.available()) {
   
   for(int j=0;client.available()>0;j++)
   {
    char c = client.read();
    eth_buffer[j]=c;
    Serial.print(c);
   }
   client.stop();
  }
  Serial.println();
   
    char body[81]={0};
    get_html_body(eth_buffer,body);//获取只是{ckxxxxxx}的字符,因为这是我们的命令格式
    //Serial.println(body);
         
    sendChannel=get_channel(body);//获取是哪个sid,这是m.znck007.com手机客服端里的sid
 
//  //如果使用NRF24l01,请启动这里
//   if(  sendChannel>0 )
//   {
//      networkSend.begin(/*channel*/ sendChannel, /*node address*/ other_node);
//        
//      networkSend.update();
//      Serial.println("");
//      Serial.print("Sending...");
//      if(sendCount>1000000) sendCount=0;
//      payload_t payload = { sendChannel, sendCount++, "{ck000000000000}" };//millis()   
//      sprintf(payload.sendchar,"%s",body);
//      RF24NetworkHeader header(/*to node*/ this_node);
//      bool ok = networkSend.write(header,&payload,sizeof(payload));
//      if (ok)
//      {
//        Serial.println("ok."); 
//       
//        isUpdate=true;       
//        char front[10]={0};
//        memcpy(front,body,9);      
//        sprintf(updateData,"%supdate}",front);
//        Serial.println(updateData);
//      
//      }
//      else
//      {
//        Serial.println("failed.");
//      }
//    } 
     
    ishttpget=false;   
    last_http = millis();
       
 
    networkSend.begin(/*channel*/ sid, /*node address*/ this_node);        
    networkSend.update();       
         
}
 
 
//获取只是{ckxxxxxx}的字符,因为这是我们的命令格式
void get_html_body(char *p,char *s){
   
  char rechar[81]={0};
  int bufi=0;
   
  bool isend=false;
  int charnum=0;   
   
  for(bufi=0;bufi<strlen(p);bufi++){
    //Serial.print(p[bufi]);
     
    if(p[bufi]=='{'){
      isend=true;
    }
    if(p[bufi]=='}' && isend==true){
      isend=false;
      rechar[charnum]=p[bufi];
      break;
    }
    if(isend){
      if(charnum<80)
      {
        rechar[charnum]=p[bufi];//Serial.print(rechar[charnum]);
        charnum++;       
      }
    }
     
  }
  Serial.println("");
  //memcpy(s,rechar,17);
  sprintf(s,"%s",rechar);
}
 
//获取是哪个sid,这是m.znck007.com手机客服端里的sid
int get_channel(char *buff){
     
  if( strstr(buff,"{ck") && strstr(buff,"}") && strlen(buff)>10)
    {
      char charChannel[4]={0};
      memcpy(charChannel,buff+3,3);
      Serial.println(charChannel);
      int intChannel=atoi(charChannel);
      Serial.println(intChannel);
      return intChannel;     
    }
    else
    {
      return 0;
    }
   
}
 
//W5100芯片POST字符数据到web服务器
int client_post(char *server, char *apikey, char *buf){
 
  if (client.connect(server, 80))
  {
      Serial.println("connecting...");
      // send the HTTP PUT request:
      client.print("POST /index.php");
      client.println(" HTTP/1.1");
      client.println("Host: api.znck007.com");
      client.print("apikey: ");
      client.println(APIKEY);
      client.print("Accept: *");
      client.print("/");
      client.println("*");
      client.print("Content-Length: ");
      // calculate the length of the sensor reading in bytes:
      // 8 bytes for {"value":} + number of digits of the data:
      size_t thisLength = strlen(buf);
      client.println(thisLength);
       
      client.println("Content-Type: application/x-www-form-urlencoded");
      client.println("Connection: close");
      client.println();
       
      client.println(buf);
      client.println();
  }
  else
  {
      // kf you didn't get a connection to the server:
      Serial.println("connection failed");
      Serial.println();
      Serial.println("disconnecting.");
      client.stop();
  }
 
}





四、插上网线,打开串口就可以测试联网是否成功了!


串口波特率设置115200(否则会有乱码的哦)




第二部份:刷zigbee模块代码


一、将zigbee模块插到zigbee开发板上





二、连上SMARTRF04EB下载器。
将一边有凸出来的一端与(VDD、RES、NC、DC、GND的NC对应就正确了!


三、安装SMARTRF04EB驱动
http://pan.baidu.com/s/1dDH1ZX3(安装SmartRFStudio后里面包含有驱动)
提示:如果刷不成功,点击一下SMARTRF04EB上的RESET(凹进去就用笔撮)。


四、安装IAR 8.1,软件比较大,安装后看说明破解就好。
http://pan.baidu.com/s/1eQ7WP3s(下载解压里面有安装说明)

五、下载zigbee自组网代码。
http://pan.baidu.com/s/1COxT8(最新ZStack-CC2530-2.5.1自组网代码,已经写好了按键、LED灯功能)
解压后目录里运行:Projects\zstack\Utilities\SerialApp\CC2530DB\SerialApp.eww

六、点击编译并下载。

七、插个LED到zigbee开发板的P1.0和-。

八、安到arduino板上。






第三步:使用手机测试



一、手机打开m.znck007.com手机控制端。



二、新建一个开关。


三、点击开关,如果发现LED灯闪,说明《网关工作正常了》!



OK,《网关》部份已经搞定了,下期我们就来上《温湿传感器》《Zigbee插座》《红外控制》!
因为我们还未使用Wifi,所以都需要与《网关》交互数据哦!
等我们Wifi产品出来就可以单独使用了!


« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。