arduino core for ESP8266接入OneNET+SPIFFS+HTTPserver
本帖最后由 robert_jw 于 2016-2-15 10:20 编辑摸索ESP8266一段时间了,偶然间在网上发现了一个开源项目,在arduino IDE中,添加ESP8266的库,就可以实现利用arduino环境来对ESP8266进行固件开发的功能,利用其提供的wifi API,就可以很方便的进行物联网设备接入的开发了。同时,该项目还提供了文件系统工具,这样就可以实现配置参数的保存的功能。
项目地址: https://github.com/esp8266/Arduino下面我们将搭建开发环境,并利用该环境,通过WIFI 热点连接OneNET,搭建一个物联网设备原型。
step 1:搭建开发环境
硬件环境:ESP8266-01模块(如上图)
软件环境:arduino IDE 1.6.7
在GIT ( https://github.com/esp8266/Arduino )上有如何搭建并使用整个环境的详细文档,这里我们只做简单描述。
打开Arduino IDE,点击 文件->首选项 ,在“附加开发板管理器网址”一栏输入 http://wechat.doit.am/package_esp8266com_index.json 点击确认,重启arduino IDE,选择工具->开发板xxx->开发板管理器,可以在看到关于esp8266的相关信息:
点击安装,等待安装完成。重启arduino IDE后,设置 工具-> 开发板xxx -> Generic ESP8266 Module
step 2:硬件连接
由于ESP8266-01只有2个可以使用的GPIO管脚,所以我们这里只实现一个简单的功能,GPIO2用来采集DHT11温湿度传感器的数值,而GPIO0用来控制发光二极管的开关。
连接框图如下所示:
实物连接图如下:
step 3:软件编写 源代码如下:
arduino主程序#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <WiFiServer.h>
#include <WiFiUdp.h>
#include "FS.h"
#include "DHT.h"
#include "edp.c"
#define CONFIG_FILE"/config.txt" //config info about ssid & password & api-key & dev_id
#define BUILTIN_LED1 0 //GPIO0 control led
#define DHTPIN 2 //GPIO2 -> DHT11
#define DHTTYPE DHT11
#define PUSH_ID NULL
#define SERVER"jjfaedp.hedevice.com" //EDP server
#define PORT 876
char servername[] = "jjfaedp.hedevice.com"; // remote server we will connect to
String ssid = "", pass = "", key = "", id = "";
static boolean tcpConnected = false, edpConnected = false, wifiConnected = false;
IPAddress apIP(192, 168, 0, 1); //AP ip address
WiFiClient client; //connect to EDP server
WiFiClient client1; //connected by webclient
WiFiServer server(80); //HTTP server for configuration
DHT dht(DHTPIN, DHTTYPE);// Initialize DHT sensor.
/*
* packetSend: 发送包
*/
void packetSend(edp_pkt* pkt)
{
int16 len = pkt->len;
int16 i = 0;
if (pkt != NULL)
{
//client.write(pkt->data, pkt->len); //串口发送
while (len--) client.write(pkt->data); //串口发送
free(pkt); //回收内存
}
}
/*
*rcvDebug: 将接受数据按照十六进制打印
*/
void rcvDebug(unsigned char *rcv, int len)
{
int i;
Serial.print("rcv len: ");
Serial.println(len, DEC);
for (i = 0; i < len; i++)
{
Serial.print(rcv, HEX);
Serial.print(" ");
}
Serial.println("");
}
/*
* readTempHumi: 调用库函数,读取DHT11的温度和湿度值
*/
boolean readTempHumi(uint32 *temp, uint32 *humi)
{
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t))
{
Serial.println("Failed to read from DHT sensor!");
return false;
}
*temp = (uint32)t;
*humi = (uint32)h;
//Serial.print("Humidity: ");
//Serial.print(h);
//Serial.print(" %\t");
//Serial.print("Temperature: ");
//Serial.print(t);
//Serial.println(" *C ");
return true;
}
/*
readEdpPkt
从串口缓存中读数据到接收缓存
*/
bool readEdpPkt(edp_pkt *p)
{
int tmp;
if ((tmp = client.readBytes(p->data + p->len, sizeof(p->data))) > 0 )
{
rcvDebug(p->data + p->len, tmp);
p->len += tmp;
}
return true;
}
/*
* rsStart: 启动文件系统,打印当前保存的参数值
*/
void fsStart()
{
if (SPIFFS.begin())
{
Serial.println("FS mounted.");
if (SPIFFS.exists(CONFIG_FILE))
{
Serial.println("/config.txt exist.");
File f = SPIFFS.open(CONFIG_FILE, "r+");
if (!f) {
Serial.println("file open failed");
}
else { //print file's content
String config;
int iStart = 0, iEnd = 0;
while (f.available()) config = f.readString();
f.close();
/* 数据内容以 ssid,pass,key,id,的形式保存*/
/* 以逗号为分隔符,读取各部分信息 */
iEnd = config.indexOf(",");
ssid = config.substring(iStart, iEnd);
iStart = iEnd + 1;
iEnd = config.indexOf(",", iStart);
pass = config.substring(iStart, iEnd);
iStart = iEnd + 1;
iEnd = config.indexOf(",", iStart);
key = config.substring(iStart, iEnd);
iStart = iEnd + 1;
iEnd = config.indexOf(",", iStart);
id = config.substring(iStart, iEnd);
Serial.println("!!!!!!!!!");
Serial.println(ssid);
Serial.println(pass);
Serial.println(key);
Serial.println(id);
}
}
else
Serial.println("/test.txt not exist.");
}
else
Serial.println("FS mount error");
}
/*
* WiFiStart:根据读文件系统中的参数,连接到wifi热点
* 并且自身作为wifi热点存在,其ssid为“DHTMonitor http://192.168.0.1”
* IP地址为apIP:192.168.0.1
*/
void WiFiStart()
{
WiFi.mode(WIFI_AP_STA);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
WiFi.softAP("DHTMonitor http://192.168.0.1");//name
Serial.println("softAP: DHTMonitor http://192.168.0.1");
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid.c_str(), pass.c_str());//配置连接的wifi热点
uint32 time = millis() + 10000;//10s to connect
while (WiFi.status() != WL_CONNECTED && millis() < time) {
delay(500);
Serial.print(".");
}
if ( millis() >=time)//overtime
{
Serial.println("");
Serial.println("WiFi error");
}
else
{
wifiConnected = true;
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
}
void setup()
{
//ESP.wdtDisable();ESP.wdtEnable();ESP.wdtFeed().
pinMode(BUILTIN_LED1, OUTPUT); // Initialize the BUILTIN_LED1 pin as an output
Serial.begin(9600);
delay(10);
Serial.println();
Serial.println();
dht.begin();
fsStart();
/* We start by connecting to a WiFi network */
WiFiStart();
server.begin();
}
void loop()
{
uint32 temp, humi, tmp;
static unsigned long time = 0, timeOld = 0;
edp_pkt rcv_pkt;
uint8 pkt_type;
/* check wifi connection */
if (WiFi.status() != WL_CONNECTED)
{
if (wifiConnected == true)
Serial.println("wifi disconnected!");
wifiConnected = false;
tcpConnected = false;
edpConnected = false;
}
else
wifiConnected = true;
/* TCP connect */
if (wifiConnected)
{
if (!tcpConnected) client.connect(SERVER, PORT);//connect to edp server
if (!tcpConnected && client.connected())
{
Serial.print("connected to ");
Serial.println((String)SERVER);
tcpConnected = true;
}
else if (tcpConnected && !client.connected())//check TCP connnection
{
Serial.print("disconnected to ");
Serial.println((String)SERVER);
tcpConnected = false;
edpConnected = false;
}
//edp connect
if (tcpConnected && !edpConnected)
{
while (client.available()) client.read(); //清空接收缓存
packetSend(packetConnect(id.c_str(), key.c_str())); //发送EPD连接包
uint32 time = millis() + 5000;
while (!client.available() && millis() < time); //等待EDP连接应答
if ((tmp = client.readBytes(rcv_pkt.data, sizeof(rcv_pkt.data))) > 0 )
{
rcvDebug(rcv_pkt.data, tmp);
if (rcv_pkt.data == 0x20 && rcv_pkt.data == 0x00 && rcv_pkt.data == 0x00)
{
edpConnected = true;
Serial.println("EDP connected.");
}
else
Serial.println("EDP connect error.");
}
else
Serial.println("EDP connect no response.");
packetClear(&rcv_pkt);
}
/* rcv & do EDP command*/
while (client.available())
{
readEdpPkt(&rcv_pkt);
if (isEdpPkt(&rcv_pkt))
{
pkt_type = rcv_pkt.data;//根据EDP协议,byte为数据包类型
switch (pkt_type)
{
case CMDREQ: //命令请求
char edp_command;
char edp_cmd_id;
int32 id_len, cmd_len, rm_len;
char datastr;
char val;
char *p;
memset(edp_command, 0, sizeof(edp_command));
memset(edp_cmd_id, 0, sizeof(edp_cmd_id));
edpCommandReqParse(&rcv_pkt, edp_cmd_id, edp_command, &rm_len, &id_len, &cmd_len);
Serial.print("rm_len: ");
Serial.println(rm_len, DEC);
Serial.print("id_len: ");
Serial.println(id_len, DEC);
Serial.print("cmd_len: ");
Serial.println(cmd_len, DEC);
Serial.print("id: ");
Serial.println(edp_cmd_id);
Serial.print("cmd: ");
Serial.println(edp_command);
//数据处理与应用中EDP命令内容对应
//本例中格式为datastream:
//sscanf(edp_command, "%[^:]:%s", datastr, val);
p = strstr(edp_command, ":");
*p = '\0';
p++;
strcpy(datastr, edp_command);
strcpy(val, p);
if (atoi(val) == 1)
digitalWrite(BUILTIN_LED1, HIGH); // 使Led亮
else
digitalWrite(BUILTIN_LED1, LOW); // 使Led灭
packetSend(packetDataSaveTrans(NULL, datastr, val)); //将新数据值上传至数据流
break;
default:
Serial.print("unknown type: ");
Serial.println(pkt_type, HEX);
break;
}
}
}
if (rcv_pkt.len > 0)
packetClear(&rcv_pkt);
/* 每10s采集一次温湿度*/
time = millis() / 10000;//every 10s
if (time != timeOld)
{
timeOld = time;
if (readTempHumi(&temp, &humi))
{
Serial.print("temp: ");
Serial.print(temp);
Serial.print("\thumi: ");
Serial.println(humi);
char temp_val;
char humi_val;
sprintf(temp_val, "%d", temp);
sprintf(humi_val, "%d", humi);
if (edpConnected)
{
packetSend(packetDataSaveTrans(NULL, "temp", temp_val));
packetSend(packetDataSaveTrans(NULL, "humi", humi_val));
}
}
}
}
/* web server */
client1 = server.available();
if (client1)
{
Serial.println("new client connected!");
unsigned long ultimeout = millis() + 250;
while (!client1.available() && (millis() < ultimeout) )
{
delay(1);
}
if (millis() > ultimeout)
{
Serial.println("overtime!");
return;
}
String sRequest = client1.readStringUntil('\r');
client1.flush();
if (sRequest == "")
{
client1.stop();
Serial.println("client1 stop!");
return;
}
Serial.println(sRequest);
String sPath = "", sParam = "", sCmd = "";
String sGetstart = "GET ";
int iStart, iEndSpace, iEndQuest;
iStart = sRequest.indexOf(sGetstart);
if (iStart >= 0)
{
iStart += +sGetstart.length();
iEndSpace = sRequest.indexOf(" ", iStart);
iEndQuest = sRequest.indexOf("?", iStart);
if (iEndSpace > 0)
{
if (iEndQuest > 0)
{
sPath= sRequest.substring(iStart, iEndQuest);
sParam = sRequest.substring(iEndQuest, iEndSpace);
Serial.println("Returned Web Path"); // Use this to Verify the actions on returned data
Serial.println(sPath);
Serial.println("Returned Parameters");
Serial.println(sParam);
}
else
{
sPath= sRequest.substring(iStart, iEndSpace);
Serial.println("Returned Web Path"); // Use this to Verify the actions on returned data
Serial.println(sPath);
}
}
//参数配置,GET /para_inputs&ssid=1&pass=2&id=3&key=4&nocache=888.694
if (sPath.startsWith("/para_inputs"))
{
int iStart = 0, iEnd;
String ssid_tmp = "", pass_tmp = "", key_tmp = "", id_tmp = "", para = "";
iStart = sPath.indexOf("=", iStart) + 1;
iEnd = sPath.indexOf("&", iStart);
ssid_tmp = sPath.substring(iStart, iEnd);
iStart = sPath.indexOf("=", iStart) + 1;
iEnd = sPath.indexOf("&", iStart);
pass_tmp = sPath.substring(iStart, iEnd);
iStart = sPath.indexOf("=", iStart) + 1;
iEnd = sPath.indexOf("&", iStart);
key_tmp = sPath.substring(iStart, iEnd);
iStart = sPath.indexOf("=", iStart) + 1;
iEnd = sPath.indexOf("&", iStart);
id_tmp = sPath.substring(iStart, iEnd);
// Serial.println("!!!!!!!!!");
// Serial.println(ssid_tmp);
// Serial.println(pass_tmp);
// Serial.println(key_tmp);
// Serial.println(id_tmp);
if (ssid_tmp != "")
para += ssid_tmp;
else
para += ssid;
para += ",";
if (pass_tmp != "")
para += pass_tmp;
else
para += pass;
para += ",";
if (key_tmp != "")
para += key_tmp;
else
para += key;
para += ",";
if (id_tmp != "")
para += id_tmp;
else
para += id;
para += ",";
/* 保存新参数然后重启 */
if (ssid_tmp != "" | pass_tmp != "" | key_tmp != "" | id_tmp != "")
{
File f = SPIFFS.open(CONFIG_FILE, "r+");
f.print(para);
f.close();
Serial.println("save parameters!");
ESP.reset();
}
}
else if (sPath == "/") //客户端输入了 192.168.0.1 发送 GET / 报文
{
// send rest of HTTP header
client1.println("HTTP/1.1 200 OK");
client1.println("Content-Type: text/html");
client1.println("Connection: keep-alive");
client1.println();
// send web page
File webFile = SPIFFS.open("/index.html", "r"); // open web page file
if (webFile)
{
while (webFile.available())client1.print(webFile.readString()); // send web page to client
webFile.close();
}
else
Serial.println("open html error!");
Serial.println("Send html file");
delay(1);
}
}
client1.stop();
}
}
其中,需要edp.c文件共同编译,代码如下:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "arduino.h"
#define CONNREQ 0x10
#define CONNRESP 0x20
#define PUSHDATA 0x30
#define SAVEDATA 0x80
#define SAVEACK 0x90
#define CMDREQ 0xA0
#define CMDRESP 0xB0
#define PINGREQ 0xC0
#define PINGRESP 0xD0
#define ENCRYPTREQ 0xE0
#define ENCRYPTRESP 0xF0
#define MAX_LEN 200
#define PROTOCOL_NAME "EDP"
#define PROTOCOL_VERSION 1
//typedef unsigned char uint8;
//typedef char int8;
//typedef unsigned int uint16;
typedef int int16;
//typedef unsigned long uint32;
//typedef long int32;
typedef struct
{
uint8 data;
int16 len;
int16 read_p;
} edp_pkt;
/*
* packetCreate
* 创建一个EDP包缓存空间
*/
edp_pkt *packetCreate(void)
{
edp_pkt *p;
if((p = (edp_pkt *)malloc(sizeof(edp_pkt))) != NULL)
memset(p, 0, sizeof(edp_pkt));
return p;
}
/*
* writeRemainlen
* 向EDP包中写入剩余长度字段
* len_val: 剩余长度的值
*/
int8 writeRemainlen(edp_pkt* pkt, int16 len_val)
{
int8 remaining_count = 0;
int8 tmp = 0;
do {
tmp = len_val % 128;
len_val = len_val / 128;
/* If there are more digits to encode, set the top bit of this digit */
if (len_val > 0) {
tmp = tmp | 0x80;
}
pkt->data = tmp;
remaining_count++;
} while (len_val > 0 && remaining_count < 5);
return remaining_count;
}
/*
* writeByte
* 向EDP包中写入一个字节
*/
int16 writeByte(edp_pkt* pkt, int8 byte)
{
pkt->data = byte;
return 0;
}
/*
* writeBytes
* 向EDP包中写入多个字节
*/
int16 writeBytes(edp_pkt* pkt, const void* bytes, int16 count)
{
memcpy(pkt->data + pkt->len, bytes, count);
pkt->len += count;
return 0;
}
/*
* writeStr
* 向EDP包中写入字符串字段
* 首先写入两个字节的长度,随后紧跟字符串内容
*/
int16 writeStr(edp_pkt* pkt, const char* str)
{
short len = strlen(str);
writeByte(pkt, len >> 8);
writeByte(pkt, len & 0x00ff);
memcpy(pkt->data + pkt->len, str, len);
pkt->len += len;
return 0;
}
/*---------------------------------------------------------------------------*/
/*
* readUint8
* 从EDP包中读出一个字节
*/
uint8 readUint8(edp_pkt* pkt)
{
return pkt->data;
}
/*
* readUint16
* 从EDP包中读出16bit的字段
*/
uint16 readUint16(edp_pkt* pkt)
{
uint16 tmp;
uint8 msb, lsb;
msb = readUint8(pkt);
lsb = readUint8(pkt);
tmp = (msb<<8) | lsb;
return tmp;
}
/*
* readUint32
* 从EDP包中读出4个字节的字段
*/
uint32 readUint32(edp_pkt* pkt)
{
uint32 tmp = 0;
int i = 4;
while (--i >= 0)
{
tmp <<= 8;
tmp |= readUint8(pkt);
}
return tmp;
}
/*
* readStr
* 根据长度,从EDP包中读出字符串数据
* len : 字符串的长度
*/
void readStr(edp_pkt* pkt, char* str, uint16 len)
{
memcpy(str, pkt->data + pkt->read_p, len);
pkt->read_p += len;
}
/*
* readRemainlen
* 从EDP包中读出剩余长度
*/
int32 readRemainlen(edp_pkt* pkt)
{
uint32 multiplier = 1;
uint32 len_len = 0;
uint8 onebyte = 0;
int32 len_val = 0;
do
{
onebyte = readUint8(pkt);
len_val += (onebyte & 0x7f) * multiplier;
multiplier *= 0x80;
len_len++;
if (len_len > 4)
{
return -1; /*len of len more than 4;*/
}
} while((onebyte & 0x80) != 0);
return len_val;
}
/*
* packetConnect:组EDP连接包
* 首先创建EDP缓存空间,按照EDP协议组EDP连接包
* 分配的内存需要在发送之后free掉
* devid: 设备id
* key:APIKey
*/
edp_pkt *packetConnect(const char* devid, const char* key)
{
int32 remainlen;
edp_pkt* pkt;
if((pkt = packetCreate()) == NULL)
return NULL;
/* msg type */
writeByte(pkt, CONNREQ);
/* remain len */
remainlen = (2 + 3) + 1 + 1 + 2 + (2 + strlen(devid)) + (2 + strlen(key));
writeRemainlen(pkt, remainlen);
/* protocol desc */
writeStr(pkt, PROTOCOL_NAME);
/* protocol version */
writeByte(pkt, PROTOCOL_VERSION);
/* connect flag */
writeByte(pkt, 0x40);
/* keep time */
writeByte(pkt, 0);
writeByte(pkt, 0x80);
/* DEVID */
writeStr(pkt, devid);
/* auth key */
writeStr(pkt, key);
return pkt;
}
/*
* packetDataSaveTrans:组EDP数据存储转发包
* 首先创建EDP缓存空间,按照EDP协议组EDP数据存储转发包
* 分配的内存需要在发送之后free掉
* devid: 设备id
* streamId:数据流ID,即数据流名
* val: 字符串形式的数据值
*/
edp_pkt *packetDataSaveTrans(const char* destId, const char* streamId, const char *val)
{
int32 remainlen;
char tmp;
int16 str_len;
edp_pkt *pkt;
if((pkt = packetCreate()) == NULL)
return pkt;
/* 生成数据类型格式5的数据类型 */
sprintf(tmp, ",;%s,%s", streamId, val);
str_len = strlen(tmp);
/* msg type */
writeByte(pkt, SAVEDATA);
if (destId != NULL)
{
/* remain len */
remainlen = 1 + (2 + strlen(destId)) + 1 + (2 + str_len);
writeRemainlen(pkt, remainlen);
/* translate address flag */
writeByte(pkt, 0x80);
/* dst devid */
writeStr(pkt, destId);
}
else
{
/* remain len */
remainlen = 1 + 1 + (2 + str_len);
writeRemainlen(pkt, remainlen);
/* translate address flag */
writeByte(pkt, 0x00);
}
/* json flag */
writeByte(pkt, 5);
/* json */
writeStr(pkt, tmp);
return pkt;
}
void packetClear(edp_pkt* pkt)
{
memset(pkt, 0, sizeof(edp_pkt));
}
/*
* isEdpPkt
* 按照EDP数据格式,判断是否是完整数据包
*/
int16 isEdpPkt(edp_pkt* pkt)
{
uint32 data_len = 0;
uint32 multiplier = 1;
uint32 len_val = 0;
uint32 len_len = 1;
uint32 pkt_total_len = 0;
uint8* pdigit;
pdigit = pkt->data;
data_len = pkt->len;
if (data_len <= 1)
{
return 0; /* continue receive */
}
do {
if (len_len > 4)
{
return -1;/* protocol error; */
}
if (len_len > data_len - 1)
{
return 0; /* continue receive */
}
len_len++;
pdigit++;
len_val += ((*pdigit) & 0x7f) * multiplier;
multiplier *= 0x80;
} while (((*pdigit) & 0x80) != 0);
pkt_total_len = len_len + len_val;
/* receive payload */
if (pkt_total_len == data_len)
{
return 1; /* all data for this pkt is read */
}
else
{
return 0; /* continue receive */
}
}
/*
* edpCommandReqParse
* 按照EDP命令请求协议,解析数据
*/
int edpCommandReqParse(edp_pkt* pkt, char *id, char *cmd, int32 *rmlen, int32 *id_len, int32 *cmd_len)
{
readUint8(pkt); /* 包类型 */
*rmlen = readRemainlen(pkt); /* 剩余长度 */
*id_len = readUint16(pkt); /* ID长度 */
readStr(pkt, id, *id_len); /* 命令ID */
*cmd_len = readUint32(pkt); /* 命令长度 */
readStr(pkt, cmd, *cmd_len); /* 命令内容 */
}
/*
* edpPushDataParse
* 按照EDP透传数据格式,解析数据
*/
int edpPushDataParse(edp_pkt* pkt, char *srcId, char *data)
{
uint32 remain_len;
uint16 id_len;
readUint8(pkt); /* 包类型 */
remain_len = readRemainlen(pkt); /* 剩余长度 */
id_len = readUint16(pkt); /* 源ID长度 */
readStr(pkt, srcId, id_len); /* 源ID */
readStr(pkt, data, remain_len - 2 - id_len); /* 数据内容 */
}
接下来就是编译和烧写了,需要注意的是ESP8266模块,在烧写flash之前需要将GPIO_0接地才能进去正常的烧写模式,具体烧写方法请参考其他帖子。
烧写完成之后,还有一个重要的工作,即烧写文件系统
烧写方法如下:
Uploading files to file systemESP8266FS is a tool which integrates into the Arduino IDE. It adds a menu item to Tools menu for uploading the contents of sketch data directory into ESP8266 flash file system.
[*]Download the tool: https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.2.0/ESP8266FS-0.2.0.zip.
[*]In your Arduino sketchbook directory, create tools directory if it doesn't exist yet
[*]Unpack the tool into tools directory (the path will look like <home_dir>/Arduino/tools/ESP8266FS/tool/esp8266fs.jar)
[*]Restart Arduino IDE
[*]Open a sketch (or create a new one and save it)
[*]Go to sketch directory (choose Sketch > Show Sketch Folder)
[*]Create a directory named data and any files you want in the file system there
[*]Make sure you have selected a board, port, and closed Serial Monitor
[*]Select Tools > ESP8266 Sketch Data Upload. This should start uploading the files into ESP8266 flash file system. When done, IDE status bar will display SPIFFS Image Uploaded message
GIT上提供了详尽的方法,请参阅 https://github.com/esp8266/Arduino/blob/master/doc/filesystem.md ,
本例中烧写的内容有两部分:
一是config.txt文件,即参数保存与配置;
二是index.html文件,即通过访问192.168.0.1,服务器传给终端的显示页面(类似与登陆路由器之后的登陆界面)。
config.txt采用逗号将ssid / password / api-key / dev_id 分割开:
本例中内容为:360,12345678,60ejo9FrV2328GndsKbQvPURzfYA,762767,
index.html:
<!DOCTYPE html>
<html lang="ch">
<head>
<meta charset="utf-8">
<title>ESP8266 Management Terminal</title>
<script>
strLine1 = "";
strLine2 = "";
function SendText()
{
nocache = "&nocache=" + Math.random() * 1000000;
var request = new XMLHttpRequest();
strLine1 = "&ssid=" + document.getElementById("txt_form").SSID.value;
strLine2 = "&pass=" + document.getElementById("txt_form").PASS.value;
strLine3 = "&key=" + document.getElementById("txt_form").KEY.value;
strLine4 = "&id=" + document.getElementById("txt_form").DEV_ID.value;
request.open("GET", "para_inputs" + strLine1 + strLine2 + strLine3 + strLine4 + nocache, true);
request.send(null);
}
</script>
<body>
<h1>ESP8266 Management Terminal<BR></h1>
<body>
<h1><FONT SIZE=-1>Enter text to config ESP8266:</h1>
<form id="txt_form" name="frmText">
<label>SSID : <input type="text" name="SSID" size="32" maxlength="32" /></label><br /><br />
<label>;PASS : <input type="text" name="PASS" size="32" maxlength="32" /></label><br /><br />
<label>API_KEY : <input type="text" name="KEY" size="32" maxlength="32" /></label><br /><br />
<label>DEV_ID: <input type="text" name="DEV_ID" size="32" maxlength="32" /></label>
</form>
<br />
<input type="submit" value="config" />
<font color="#000000"><body bgcolor="#d0d0f0"><meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"><BR>LCD Text Input<BR>
<div style="clear:both;"><FONT SIZE=-1>environmental.monitor.log@gmail.com<BR><FONT SIZE=-2>ESP8266 With 1602 I2C LCD, DS1307 and DHT22 Peripherals Logging to SPIFFS<BR>Compiled using ver. 1.6.5-1160-gef26c5f, built on Sep 30, 2015<BR></body></html>
用浏览器打开该index.html文件,即为登陆界面:
将文件系统烧写到flash中,重新上电之后便可以进行正常使用了;
使用方法:
1、打开手机WIFI,搜索附近热点,可以看到一个名为DHTMonitor http://192.168.0.1 的热点,这便是我们在软件中编辑好的热点名称,连接到该热点上:
打开手机浏览器,在地址栏中输入192.168.0.1(就像访问家里的路由器一样),即可以看到登陆界面:
在SSID,和PASS栏中输入,模块需要连接的WIFI热点,API_KEY和DEV_ID分别为设备对应的参数,点击config,之后ESP8266会进行重启,在串口上会看到一些调试信息,如下所示:
在OneNET平台上,在对应的设备下可以看到已经连接的状态,同时会有温湿度的数据流数据产生:
可以利用应用编辑器中的开关控制LED灯,这里不再累述。具体控制方法参见代码部分和OneNET社区中的帖子:
http://open.iot.10086.cn/bbs/topics/410
强!!!!!!!!!!!!!!! Arduino:1.6.7 (Windows 7), 开发板:"Generic ESP8266 Module, Serial, 80 MHz, 40MHz, DIO, 115200, 512K (64K SPIFFS), ck, Disabled, None"
D:\Documents\Arduino\ESP8266__OneNET_SPIFFS_HTTPserver\ESP8266__OneNET_SPIFFS_HTTPserver.ino:8:17: fatal error: DHT.h: No such file or directory
#include "DHT.h"
^
compilation terminated.
exit status 1
编译有误。
报告将会包含更多的信息
"在编译时,输出详细信息"
在 文件>首选项 中启用
怎么办 没有"DHT.h" cavy 发表于 2016-2-17 17:38
Arduino:1.6.7 (Windows 7), 开发板:"Generic ESP8266 Module, Serial, 80 MHz, 40MHz, DIO, 115200, 512K ...
找到了:lol 本帖最后由 cavy 于 2016-2-18 16:38 编辑
这次真的烧录成功 谢谢楼主但config.txt文件和index.html文件;不知道怎么烧进去
终于烧录成功了 但烧了就像没烧前一样 连wifi名字都没改变其他功能更加没看到不知道哪里错了.......楼主 还有哪里要注意啊:( cavy 发表于 2016-2-17 22:38
这次真的烧录成功 谢谢楼主但config.txt文件和index.html文件;不知道怎么烧进去
...
哦 又看了一次楼主的教程 html烧进去了
但打开196.168.0.1后 输入密码后 按 config 8266并没有反应 今晚我再看看代码 cavy 发表于 2016-2-18 17:57
哦 又看了一次楼主的教程 html烧进去了
但打开196.168.0.1后 输入密码后 按 config 8266并没有反应 今晚 ...
没有反应,串口打印为什么内容呢? robert_jw 发表于 2016-2-19 09:12
没有反应,串口打印为什么内容呢?
FS mounted.
/config.txt exist.
!!!!!!!!!
1234567890
123456789
l6J3NMxrgJjOR52GbiO=Iw6O9Vw=
768880
softAP: DHTMonitor http://192.168.0.1
Connecting to 1234567890
....................
WiFi error
new client connected! //手机登陆192.168.0.1
GET / HTTP/1.1
Returned Web Path
/
Send html file
new client connected!
client1 stop!
new client connected!
client1 stop!
//填完账号密码按config 串口就什么都没收到 怎么在浏览器中写好配置信息按 config 没有反应