更新日志:
2023年3月25日
统一从ArduinoIDE转移到PlatformIO
时效性以github版本为准,这个版本已经做出模块化PCB,点击这里查看
实现功能
本例将OTA/WIFIManager/Blynk整合到一起.V3版本之前做过两个版本,而且比这个版本精度更高,不过库有点问题,还没有时间研究.这个版本是最稳定最适合入手的版本,外壳以找淘宝蓝控电子,都开好孔的,12一个.最后发一张图,我就笑笑不说话,你懂的手动滑稽
功能:
- 采集大气压/温湿度/光照度
- 增加按钮开关用作复位WIFI设置功能(例如:当你需要更换设备所连接WIFI热点可以重新选择)
- 增加WIFI连接管理界面可以更改TOKEN KEY功能(设备自身绑定后也能更改)
- 实时显示网络信息
- OTA更新固件
材料准备
- ESP8266 X 1
- BMP180 X 1
- SHT-30 X 1
- BH1750 - FVI X 1
- 按钮开关 X 1
传感器用到的程序库
需要注意的编译环境(亲测高版本会出错,未解决)
ArduinoIDE编译通过的库版本:
- ESP8266板库:2.4.2
- Blynk版本:0.6.1
- IDE版本:1.8.10
- ArduinoJson:5.13.3
- WiFiManager:0.14.4
PlatformIO编译通过的库版本:
- Blynk:0.6.1
- ArduinoJson:5.13.4
- WifiManager:0.14
- ESP8266板库:2.0.4、2.1.1、2.2.0
接线
懒得画图了,没啥难度都,是I2C接口,注意全部模块VCC接到3.3V,
设备 | 引脚 | ||||
---|---|---|---|---|---|
ESP8266 | 3.3 | GND | SDA | SCL | D5 |
SHT30 | Vcc | GND | SDA | SCL | / |
BMP180 | Vcc | GND | SDA | SCL | / |
BH1750 | Vcc | GND | SDA | SCL | / |
开关 | COM | NO |
设备端代码
(如果手机端网页显示不正常,点击左上角三个点点)
#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG //详细DEBUG
//#include <Arduino.h> //PlatformIO必须
#include <FS.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <WEMOS_SHT3X.h>
#include <BH1750FVI.h>
Adafruit_BMP085 bmp;
SHT3X sht30(0x44);
BH1750FVI LightSensor(BH1750FVI::k_DevModeContLowRes);
const int ResetButton = D5;
const int LedPin = D4;
//这里声明"参数"的预设值, 如果和值不同,则会将他们覆盖
char blynk_token[34] = "你的Blynk Token KEY";
//用于保存数据的标志
bool shouldSaveConfig = false;
BlynkTimer timer;
//回调通知我们需要保存配置
void saveConfigCallback ()
{
Serial.println("Should save config");
shouldSaveConfig = true;
}
void sendSensor()
{
sht30.get();
uint16_t lux = LightSensor.GetLightIntensity();
float h = sht30.humidity;
float t = sht30.cTemp;
float p = bmp.readPressure() ;
float l = lux;
Blynk.virtualWrite(V0, h);
Blynk.virtualWrite(V1, t);
Blynk.virtualWrite(V2, p / 100);
Blynk.virtualWrite(V3, l);
}
void setup() {
Serial.begin(115200);
int ResetButtonState = digitalRead(ResetButton);
digitalWrite(LedPin, HIGH);
pinMode(ResetButton, INPUT);
pinMode(LedPin, OUTPUT);
bmp.begin();
LightSensor.begin();
//读取FS json的配置
Serial.println("mounting FS...");
if (SPIFFS.begin()) {
Serial.println("mounted file system");
if (SPIFFS.exists("/config.json")) {
//文件存在,读取和加载
Serial.println("reading config file");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println("opened config file");
size_t size = configFile.size();
// 分配缓冲区以存储文件的内容。
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());
json.printTo(Serial);
if (json.success()) {
Serial.println("\nparsed json");
strcpy(blynk_token, json["blynk_token"]);
} else {
Serial.println("failed to load json config");
}
configFile.close();
}
}
} else {
Serial.println("failed to mount FS");
}
//结束
// 要配置的额外参数(可以是全局的,也可以只是在设置中)
// 连接后,parameter.getValue()将获得配置的值//After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt 的默认长度
WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 34);
//WiFiManager
//本地初始化。一旦业务完成,就没有必要保留它
WiFiManager wifiManager;
//设置配置保存通知回调
wifiManager.setSaveConfigCallback(saveConfigCallback);
//在这里添加所有参数
wifiManager.addParameter(&custom_blynk_token);
//设置重置按钮的功能,这里代码可以简化,我懒得写....
if (ResetButtonState == LOW)
{
Serial.println("Getting Reset ESP Wifi-Setting.......");
digitalWrite(LedPin, LOW);
delay(3000);
digitalWrite(LedPin, HIGH);
delay(300);
digitalWrite(LedPin, LOW);
delay(3000);
digitalWrite(LedPin, HIGH);
delay(300);
digitalWrite(LedPin, LOW);
delay(3000);
digitalWrite(LedPin, HIGH);
wifiManager.resetSettings();
delay(10000);
Serial.println("Formatting FS......");
SPIFFS.format();
delay(10000);
Serial.println("Done Reboot In 5 seconds");
digitalWrite(LedPin, LOW);
delay(5000);
digitalWrite(LedPin, HIGH);
ESP.restart();
}
//获取ssid并传递并尝试连接
//如果它没有连接,它将启动具有指定名称的访问点,"AutoConnectAP",并进入等待配置的阻塞循环
if (!wifiManager.autoConnect("4合1气象采集仪V3", "")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
//重置并重试,或者让它深入睡眠
ESP.reset();
delay(5000);
}
//如果已经连接
Serial.println("connected...yeey :)");
//读取更新的参数
strcpy(blynk_token, custom_blynk_token.getValue());
//j将自定义参数保存到FS
if (shouldSaveConfig) {
Serial.println("saving config");
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["blynk_token"] = blynk_token;
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("failed to open config file for writing");
}
json.printTo(Serial);
json.printTo(configFile);
configFile.close();
//end save
}
Serial.println("local ip");
Serial.println(WiFi.localIP());
///////////////////////OTA部分///////////////////////////////////////////////
// 默认主机名为:esp8266-[ChipID]
ArduinoOTA.setHostname("4合1气象采集仪V3");
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_SPIFFS
type = "filesystem";
}
//注意:如果更新SPIFFS,这将是使用SPIFFS.end()卸载SPIFFS的地方
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Auth Failed");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
} else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
}
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Blynk.config(blynk_token, "chrisxs.top", 8080);
timer.setInterval(1000L, sendSensor);
}
void loop() {
ArduinoOTA.handle();
Blynk.run();
timer.run();
Blynk.virtualWrite(V4, WiFi.localIP().toString());
Blynk.virtualWrite(V5, WiFi.macAddress());
Blynk.virtualWrite(V6, "RSSI:", WiFi.RSSI(), " ", "SSID: ", WiFi.SSID());
}
程序运行效果图
上传后,你会看见一个热点名为"4合1气象采集仪V3
",代码中我没设密码,请自行修改.具体流程如下图,图中不是采集仪的,操作一样,不具体说了,就是连接你路由或者手机热点WIFI-SSID就行:
一般手机连接后会自动弹出验证界面,如果连接后没有弹出,就手动打开你的浏览器,输入192.168.4.1
进入验证界面