l1234564555 发表于 2014-9-23 09:24:41

两句UDP语句,实现跨内网外网实时控制设备(手机APP,网页)

两句UDP语句,实现跨内网外网实时控制设备(手机APP,网页),视频中用的是单片机+ENC28J60,其他什么硬件都无所谓。

响应速度极快:手机APP是1s以内响应,网页1-2s响应,大大提高了速度,而且带信息反馈哦。

演示视频:
http://v.youku.com/v_show/id_XNzgzNjI0MTYw.html

具体详情:fuhome/bbs/

视频:讲解如何接入平台,很简单,讲的废话有点啰嗦,不过适合不用阶层的伙计,大家要有一颗包容的心,哈哈

http://v.youku.com/v_show/id_XNzg4NDA0MDM2.html

wxws 发表于 2014-9-24 16:34:35

楼主太高深了,看我的arduino客户端吧:
简单来讲,只需要UDP通讯,就可以达到穿透外网的功能,并且速度飞快。
1:打开UDP通讯口,并且一直保持
2:定时(下面程序我用了30秒)向服务器发udp心跳包(格式见程序)
3:当收到服务器发来的包时,分析包属性(全在loop程序中)

要注意的:
1:先到fuhome.net注册帐号,增加设备
2:修改下面的设备ID与设备密码
3:修改arduino IP地址设定

/*
fuhome.ino:
by:wxwsqq:1103012

协议:
http://www.fuhome.net/api/must/

服务器IP:115.28.93.201
         udp端口:7001

30s
心跳发送: f=1设备id密码
心跳:f=1&d=设备id&m=密码&from=sb->server
心跳收到返回:f=1&d=设备id&from=server->sb1

远程收到命令:f=a&d=设备id&n=jyzhkj&com=open&from=server->sb
命令返回:f=b设备id密码 用户名响应消息(可自定义)
返回:f=b&d=设备id&m=密码&n=jyzhkj&com=open&from=sb->server

*/


#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
//#include "system.h"



EthernetUDP Udp;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 0, 46);
IPAddress ddns(192, 168, 0, 254);
IPAddress getway(192, 168, 0, 254);
IPAddress subnet(255, 255, 255, 0);



unsigned int localPort = 8888;      // 本地端口

IPAddress rip(115, 28, 93, 201); //远程ip
unsigned int rPort = 7001;      // 远程端口

String deviceid = "1234567890"; //设备ID
String deviceps = "1234567890"; //设备密码
String Heart = "f=1&d=%s1&m=%s2&from=sb->server";//心跳包模板
String ReplyTemp = "f=b&d=%s1&m=%s2&n=%s3&com=%s4&from=sb->server";      //命令包模板


String udpget = "";
String usename = "";
String command = "";
char ttc;

#define LED 27
int ledstate = 1;


void setup()
{
    // start the Ethernet and UDP:
    pinMode(LED, OUTPUT);
    digitalWrite(LED, 1);

    Ethernet.begin(mac, ip, ddns, getway, subnet);//当然也可以用DPCH具体请看 arduino例子

    Udp.begin(localPort);

    Serial.begin(115200);

    Heart.replace("%s1", deviceid);
    Heart.replace("%s2", deviceps);
    ReplyTemp.replace("%s1", deviceid);
    ReplyTemp.replace("%s2", deviceps);
}

void loop()
{
    // if there's data available, read a packet
    int packetSize = Udp.parsePacket();
    if (packetSize)
    {

      udpget = "";
      for (int i = 0; i < packetSize; i++)
      {
            udpget += (char)Udp.read();
      }


      Serial.print(getuptime());
      Serial.print(" R:");
      Serial.println(udpget);


      if (udpget.indexOf("f=a") >= 0)//心跳包不响应
      {

            usename = Findany("&n=");
            command = Findany("&com=");


            if (command == "open")
            {
                ledstate = 1;
                command="已"+command;

            }
            if (command == "close")
            {
                ledstate = 0;
                command="已"+command;
            }
            if (command == "flash")
            {
                ledstate = 2;
                command="已"+command;
            }

            udpget = ReplyTemp;
            udpget.replace("%s3", usename);
            udpget.replace("%s4", command);
            udpget.toCharArray(ttc, 100);


            Serial.print("   Send reply:");
            Serial.println(udpget);

            Udp.beginPacket(rip, rPort);
            Udp.write(ttc);   //状态响应回复包f=b&d=设备ID&m=设备密码&n=jyzhkj&com=命令&from=sb->server
            Udp.endPacket();


      }
      else
      {
            // if (udpget.indexOf("f=1") >= 0)//心跳包
            //   Serial.println("Recive f=1.");
            // if (udpget.indexOf("f=b") >= 0)//回复包
            //   Serial.println("Recive f=b.");

      }
    }

    LedControl();
    UdpHeart();
}

//灯状态切换
void LedControl()
{
    static long previousMillis = 0;
    static int currstate = 0;

    switch (ledstate)
    {
    case 0:
      currstate = 0;
      break;
    case 1:
      currstate = 1;
      break;
    case 2:
      if (millis() - previousMillis > 200)//200ms
      {
            previousMillis = millis();
            currstate = 1 - currstate;
      }
      break;
    }

    digitalWrite(LED, currstate);

}

//查找参数,下一个“&”为界
String Findany(String findstr)
{
    String ttv = "";
    int t1, t2;
    t1 = udpget.indexOf(findstr);
    if (t1 >= 0)
    {
      t2 = udpget.indexOf("&", t1 + 1);
      ttv = udpget.substring(t1 + findstr.length(), t2);
    }

    return ttv;
}

//UDP心跳包
void UdpHeart()
{
    static long previousMillis = 0;

    if (millis() - previousMillis > 30000)//30秒
    {

      previousMillis = millis();


      Serial.print(getuptime());
      Serial.print(" S:");
      Serial.println(Heart);

      Heart.toCharArray(ttc, 100);
      Udp.beginPacket(rip, rPort);
      Udp.write(ttc);   //心跳包   f=1&d=设备ID&m=设备密码&from=sb->server

      Udp.endPacket();


    }
}


Stringgetuptime() //从millis转换成 天数:小时:分:秒
{

    String tts = "";
    long days = 0;
    long hours = 0;
    long mins = 0;
    long secs = 0;
    char ccc;
    secs = millis() / 1000; //convect milliseconds to seconds
    mins = secs / 60; //convert seconds to minutes
    hours = mins / 60; //convert minutes to hours
    days = hours / 24; //convert hours to days
    secs = secs - (mins * 60); //subtract the coverted seconds to minutes in order to display 59 secs max
    mins = mins - (hours * 60); //subtract the coverted minutes to hours in order to display 59 minutes max
    hours = hours - (days * 24); //subtract the coverted hours to days in order to display 23 hours max

    sprintf(ccc, "%02d:%02d:%02d:%02d", int(days), int(hours), int(mins), int(secs));
    tts = String(ccc);
    return tts;
}

wxws 发表于 2014-9-24 16:37:51

我的程序已经可以直接调用了,只要修改本地网络参数与设备ID、密码。

注意LED脚 ,我用的是27脚 ,请自定义,注意不要用13脚 ,与SPI通讯冲突。

实现了3个状态:
close:关
open:开
flash:闪烁

附件是手机app,

wxws 发表于 2014-9-24 16:43:59

忘了说硬件:我用的是w5500,w5100也肯定没问题
enj修改修改也没问题的。

与yeelink比较:
非http协议,yeelink使用http,注定了会有延时。
udp联接属于实时联接,手机,web控制全实时。

我将arduino挂在网上,大家可以控制:
http://www.fuhome.net/home/?id=40



图中的“消息”,是由arduino反馈给服务器的。见loop函数。

wxws 发表于 2014-9-24 16:54:55

程序可能看着长,我已经全做完善了,232有调试信息。
页: [1]
查看完整版本: 两句UDP语句,实现跨内网外网实时控制设备(手机APP,网页)