Blinker 开发实例介绍——温室大棚
申请免费成为认证开发者硬件:ESP8266-D1-mini,光照传感器BH1750;温湿度传感器DHT11或22,土壤水份检测模块
平台:Arduino, Blinker 2.5.0
实现功能:
1)驱动继电器进而控制门禁、风机、阀门、灯光等设备
2)根据土壤墒情自动浇水
3)按钮及时反映控制状态
问题:
1)不能实时反馈时间数据,比如我要实现设备动作的倒计时显示在Button6.text("set_time")
2)MQTT经常掉线,WiFi经常会离线状态
3)ESP有时会重启
4)开关按钮有时会返回press而不是on
5)最近1周数据为啥只有4天?
6) 在callback函数中用了Blinker.delay()就会出现很多问题
#define BLINKER_WIFI
#include <Blinker.h>
#include <Wire.h>
#include <BH1750.h>
#include <DHT.h>
#include <Ticker.h>
#define DHTPIN D3//0~D3
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22(AM2302), AM2321
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
BH1750 lightMeter;
DHT dht(DHTPIN, DHTTYPE);
char auth[] = "ae800518f46e";//Your Device Secret Key";
char ssid[] = "TP-LINK_2F98";//Your WiFi network SSID or name";
char pswd[] = "xxxxxxxx";//Your WiFi network WPA password or WEP key";
bool switch_state = false; //开关状态
bool b6_state= false;
int jscs=0; //浇水次数
int jsq=0;//计时器
int set_time=0; //用滑块设定浇水时间
int last_time=0;
uint32_t read_time = 0;
uint8_t wet=0; //土壤湿度,显示在APP中
uint8_t wet2=0;//土壤湿度,用于控制
uint8_t soil_read=0;
uint16_t light_read=0;
float humi_read=0, temp_read=0;
int8_t ihour=0 ; //小时
int8_t imin=0 ;//分钟
int8_t isec=0 ;//秒
char buf1[]="开";
char buf2;
char buf3="s";
char dsk; //定时开几秒
Ticker flipper; //创建定时器对象
BlinkerNumber HUMI("humi"); //创建数据按钮对象,并赋初值humi
BlinkerNumber TEMP("temp");
BlinkerNumber LIGHT("light");
BlinkerNumber SOIL("soil");
BlinkerNumber Number1("num-1");
BlinkerButton Button1("btn-door");//实例化开关按钮对象,值btn-door与手机APP对应按钮名称一致
BlinkerButton Button2("btn-lamp");//照明
//BlinkerButton Button3("btn-ac");//备用
BlinkerButton Button4("btn-fan"); //风机
BlinkerButton Button5("btn-auto");//自动浇
BlinkerButton Button6("btn-valv1"); //手动浇,定时
BlinkerSlider Slider1("set-time");//设置滑块对象
void slider1_callback(int32_t value){
set_time=value;//自定义,单位毫秒
BLINKER_LOG("get slider value:",value*1000," s");
}
void switch_callback(const String & state){//设备总开关
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));//总是让LED灯发生明灭变化
BLINKER_LOG("get builtin switch state: ", state);
if (state == BLINKER_CMD_ON) {
switch_state = true;
digitalWrite(D7, HIGH);//实验用D7引脚,实际可能会用别的
BUILTIN_SWITCH.print("on");
}
else if (state == BLINKER_CMD_OFF) {
switch_state = false;
digitalWrite(D7, LOW);
BUILTIN_SWITCH.print("off");
}
}
//门禁控制
void button1_callback(const String & state){
BLINKER_LOG("get door switch state: ", state);
if (state == "on") {
digitalWrite(D5,HIGH);
Button1.icon("fas fa-door-open");
Button1.text("打开啦");
Button1.print("on");// 返回状态信息,在手机调试窗口会显示
}
else if (state=="off"){
digitalWrite(D5, LOW);
Button1.icon("fas fa-door-closed");
Button1.text("门已闭");
Button1.print("off");
}
}
//灯光控制
void button2_callback(const String & state){
BLINKER_LOG("get lamp switch state: ", state);
if (state == "on") {
digitalWrite(D6,HIGH);
Button2.text("照亮梦想");
Button2.print("on");
}
else {
digitalWrite(D6, LOW);
Button2.text("黑黢黢");
Button2.icon("fas fa-lightbulb");
Button2.print("off");
}
}
//风机控制
void button4_callback(const String & state){
BLINKER_LOG("get fan switch state: ", state);
if (state == "on") {
digitalWrite(D6,HIGH);
Button4.icon("fa fa-fan fa-spin");//使用 fa-spin类,使任意图标旋转,还可以使用fa-pulse使其进行8方位旋转
Button4.text("转晕了"); //尤其适合 fa-spinner,fa-fan,fa-refresh,fa-cog
Button4.print("on");
}
else {
digitalWrite(D6, LOW);
Button4.text("休息中");
Button4.print("off");
}
}
//自动运行模式按钮
void button5_callback(const String & state){
BLINKER_LOG("get btn5 state: ", state);
if (state == "on") {
Button5.icon("fa fa-cog fa-spin");
autodrip(); //调用水份监测控制函数
Button5.text("自动运行");
Button5.print("on");
}
else {
digitalWrite(D7,LOW);
Button5.text("停用自动");
Button5.print("off");
}
}
//手动控制,并设定了时间变量
void button6_callback( const String & state){
BLINKER_LOG("get switch state: ", state);
if (state == "on" ){
digitalWrite(D8, HIGH);
sprintf(buf2,"%d",set_time); //滑块返回设定时间
sprintf(dsk,"%s%s%s",buf1,buf2,buf3);//buf1=开,buf3=s
Button6.text(dsk);
Button6.icon("far fa-faucet-drip");
Button6.print("on"); //第一次调用显示龙头状态
Blinker.delay(set_time*1000);
digitalWrite(D8, LOW); //延时set_time*1000秒后自动停止D8控制的对象
sprintf(buf2,"%d",0);
sprintf(dsk,"%s%s%s",buf1,buf2,buf3);
Button6.text(dsk);
Button6.icon("fad fa-faucet-drip");
Button6.print("on"); //第二次调状态
b6_state= true;
}
else if (state == "off"){
digitalWrite(D8, LOW);
Button6.icon("fas fa-faucet");
Button6.text("阀门关");
Button6.print("off");
b6_state= false;
}
}
// 如果未绑定的组件(没有定义的按钮,输入框)被触发,则会执行dataRead()函数
void dataRead(const String & data){
BLINKER_LOG("Blinker readString: ", data);//在串口显示为 Blingker readString:
Blinker.vibrate(255);//发送手机振动指令, 震动时间, 单位ms, 数值范围0-1000, 默认为500
uint32_t BlinkerTime = millis();
Blinker.print("millis", BlinkerTime);//在手机monitor显示
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));//当有按钮动作发生时,总是让LED发生明灭的变化
/*
if (data=="123"){//如果在输入框输入“123”,本例没用到,因为屏幕被别的元素占满了
//autodrip();
digitalWrite(D7,HIGH);
Blinker.delay(1500);
digitalWrite(D7,LOW);
}
else
digitalWrite(D7,LOW);
*/
BLINKER_LOG("input=",data);
}
//心跳包使得我们每次打开APP都可以看到实时的最新数据
//WiFi设备每59秒会返回一次心跳包;Ble设备每29秒返回一次心跳包
void heartbeat(){
if (switch_state) BUILTIN_SWITCH.print("on");
else BUILTIN_SWITCH.print("off");
//Number1.print(WiFi.RSSI()); //把信号强度发送给APP端
Number1.print(jsq); //获取开机运行到现在的时间
Number1.icon("fas fa-clock fa-spin");//定义一个旋转的时钟
TEMP.print(temp_read); //免费用户最多分配5个数据显示BlinkerNumber对象.print()
HUMI.print(humi_read); //反馈湿度数据给APP
SOIL.print(soil_read);
LIGHT.print(light_read);
//HUMI.icon("fas fa-tint"); //设置ui组件图标,在图标库 (https://fontawesome.com) 中找到要使用的图标
//HUMI.color("#0099FF"); //也可以在APP中进行配置
TEMP.icon("fas fa-thermometer");
//TEMP.color("#FF3300");
LIGHT.icon("fas fa-cloud-sun");
}
//储存数据在ui中以图表显示,最多显示3个图表
void dataStorage() {
Blinker.dataStorage("temp", temp_read);
Blinker.dataStorage("humi", humi_read);
Blinker.dataStorage("light",light_read);
//Blinker.dataStorage("soil",soil_read);
}
/*
void flip(){
int senVal=constrain(analogRead(A0),50,500);
wet = map(senVal,50,500,0,100); //获取湿度
BLINKER_LOG("senVal=",senVal,", wet=",wet);
}
*/
void autodrip(){
ihour = Blinker.hour(); //获取当前时间小时数, 单位为小时(h), 获取成功时值: 0-23, 获取失败时值: -1
if (ihour==23 && imin == 15 && isec <= 30){//每到晚上23:15分,模块自动重启.
ESP.restart(); //重启后jscs会重置为零,实现每天最多浇水两次
}
BLINKER_LOG("今日第 <",ihour,"> 小时");
wet2=analogRead(A0);
if ( wet2 <= 80 && jscs <= 2 ) { //水份含量设定,jscs自动浇水次数
jscs++;
digitalWrite(D7,HIGH);
Button5.text("自动浇灌");
Button5.print("on");
BLINKER_LOG("水分含量", wet2, "%,开始自动浇水");
BLINKER_LOG("这是第 <",jscs,"> 次浇水");
Blinker.delay(10000);//每次自动浇水10秒或者别的时间
digitalWrite(D7,LOW);
Button5.text("自动停止");
Button5.print("off");
}
BLINKER_LOG("今日总浇水次数为:",jscs);
}
void setup(){
Wire.begin(D2,D1);
Serial.begin(115200);
BLINKER_DEBUG.stream(Serial);
//BLINKER_DEBUG.debugAll();
pinMode(LED_BUILTIN, OUTPUT);
pinMode(D5,OUTPUT);//door
pinMode(D6,OUTPUT);//lamp
pinMode(D7,OUTPUT);//manu
pinMode(D8,OUTPUT);//auto
digitalWrite(LED_BUILTIN, LOW);
Blinker.begin(auth, ssid, pswd);
Blinker.attachData(dataRead);
Blinker.attachHeartbeat(heartbeat);
Blinker.attachDataStorage(dataStorage);
BUILTIN_SWITCH.attach(switch_callback);//设备总开关
Slider1.attach(slider1_callback);
Button1.attach(button1_callback);//当app中组件触发并发送到设备端时将触发该组件注册的回调函数
Button2.attach(button2_callback);
Button4.attach(button4_callback);
Button5.attach(button5_callback);
Button6.attach(button6_callback);
//flipper.attach(5, flip); //定时器每5秒调用一次flip函数
dht.begin();
lightMeter.begin();//(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23, &Wire);
BLINKER_LOG("BH1750 light sensor test begin...");
if (lightMeter.begin()) {
BLINKER_LOG("BH1750 light sensor initialised 光照传感器初始化完成!");
}
else {
BLINKER_LOG("Error initialising BH1750");
}
Blinker.setTimezone(8.0);
BLINKER_LOG("Now ntp time: ", Blinker.time());
//ihour = Blinker.hour();
//imin = Blinker.minute();
//isec = Blinker.second();
//BLINKER_LOG("当前时间:",ihour,"-",imin,"-",isec);
}
void loop(){
Blinker.run();//此函数需要频繁调用以保持设备间连接及处理收到的数据
if (last_time==0 || (millis()-last_time) >= 60000){
//imin=Blinker.minute();
last_time=millis();
jsq++;
}
//开机取一次,以后 3s 间隔取一次数据.但是间隔 59s APP更新一次
uint16_t data_time;
data_time= 3000;
if (read_time == 0 || (millis() - read_time) >= data_time) {
read_time = millis();
int wet = analogRead(A0); //获取湿度值
uint16_t lux = lightMeter.readLightLevel();
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
BLINKER_LOG("Failed to read from DHT sensor!");
return;
}
float hic = dht.computeHeatIndex(t, h, false);
humi_read = h;
temp_read = t;
light_read = lux;
soil_read = wet;
BLINKER_LOG("Temp: ", t, " *C\tHumi: ", h, " %\tLight: ",lux," lux\tWet:",wet," %");
//BLINKER_LOG("Temperature: ", t, " *C");
BLINKER_LOG("Heat index体感温度: ", hic, " *C");
}
//Blinker.delay(2000);
}
1)不能实时反馈时间数据,比如我要实现设备动作的倒计时显示在Button6.text("set_time")
目前设计就是这样的,倒计时定时可以通过定时页面显示
2)MQTT经常掉线,WiFi经常会离线状态
8266 ram不够,在上传数据到云端时会断开MQTT,再切换到http进行,上传完成后,即会从新连接mqtt
3)ESP有时会重启
看报错信息,程序问题,ram不足,供电问题都可能导致设备重启
4)开关按钮有时会返回press而不是on
长按就会触发press
5)最近1周数据为啥只有4天?
不清楚,建议过几天再看,如果还是只有近4天的,再联系我
6) 在callback函数中用了Blinker.delay()就会出现很多问题
回调函数中,不能有耗时的操作,任何单片机上都是如此 谢谢回复。回调函数的问题我正在解决中。
图表里面只能显示4个时间点,一直是这样。 修改后:
bool b5_state=false;
bool b6_state=false;
void button6_callback( const String & state){
BLINKER_LOG("get switch state: ", state);
if (state == "on" ){
b6_state=true;
}
else if (state == "off"){
b6_state=false;
digitalWrite(D8, LOW);
Button6.icon("fas fa-faucet");
Button6.text("阀门关");
Button6.print("off");
}
}
void loop(){
Blinker.run();
if (b5_state==true){
autodrip();
b5_state=false;
}
if (b6_state==true){
manudrip();
b6_state=false;
}
......
}
void manudrip(){
digitalWrite(D8, HIGH);
for (int i=set_time; i>=0; i--){ //增加for循环,b6按钮的时间实现倒计时显示
sprintf(buf2,"%d",i); //滑块返回设定时间
sprintf(dsk,"%s%s%s",buf1,buf2,buf3); //buf1=开,buf3=s
Button6.text(dsk);
Button6.icon("far fa-faucet-drip");
Button6.print("on"); //第一次调用显示龙头状态
Blinker.delay(1000);
if (b6_state==false)
break;
}
//Blinker.delay(set_time*1000);
digitalWrite(D8, LOW); //延时set_time*1000秒后自动停止D8控制的对象
sprintf(buf2,"%d",0);
sprintf(dsk,"%s%s%s",buf1,buf2,buf3);
Button6.text(dsk);
Button6.icon("fad fa-faucet-drip");
Blinker.delay(1000);
Button6.text("再按复位");
Button6.print("on");//第二次调状态
}
倒计时一旦开始(滑块set_time=10s),总是出现MQTT 不稳问题。
Connecting to MQTT...
reconnect_time: 0
MQTT Connected!
Freeheap: 6720
Temp: 22.20 *C Humi: 42.00 % Light: 39 lux Wet:536 %
Heat index体感温度: 21.57 *C
Temp: 22.20 *C Humi: 44.00 % Light: 36 lux Wet:532 %
Heat index体感温度: 21.62 *C
get switch state: on
ERROR: MQTT NOT ALIVE OR MSG LIMIT
ERROR: MQTT NOT ALIVE OR MSG LIMIT
ERROR: MQTT NOT ALIVE OR MSG LIMIT
ERROR: MQTT NOT ALIVE OR MSG LIMIT
ERROR: MQTT NOT ALIVE OR MSG LIMIT
ERROR: MQTT NOT ALIVE OR MSG LIMIT
Temp: 22.20 *C Humi: 43.00 % Light: 37 lux Wet:489 %
Heat index体感温度: 21.60 *C
Temp: 22.10 *C Humi: 41.00 % Light: 37 lux Wet:488 %
Heat index体感温度: 21.44 *C
页:
[1]