├── image ├── circuit.jpg └── framework.png ├── README.md ├── platformio.ini └── src └── main.cpp /image/circuit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HojinKuo/ESP32-FreeRTOS-BEM280-MQ5-0.96OLED-AliyunIoT/HEAD/image/circuit.jpg -------------------------------------------------------------------------------- /image/framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HojinKuo/ESP32-FreeRTOS-BEM280-MQ5-0.96OLED-AliyunIoT/HEAD/image/framework.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32环境检测器 2 | ## 简介 3 | 使用ESP32作为主控芯片,开发环境为 Arduino,嵌入式实时操作系统FreeRTOS,云平台为阿里云物联网(阿里生活物联网飞燕),服务端由Java实现,前端分别由微信小程序和NodeRed Dashboard 展示相关信息,最后实现一个简单的环境检测器。 4 | ## 硬件材料 5 | * ESP32主控芯片 6 | * BME280温湿度气压传感器 7 | * MQ-2 烟雾传感器 8 | * 0.96寸OLED屏幕 9 | * LED 发光二极管 10 | * 蜂鸣器 11 | * 电阻 12 | * 杜邦线 13 | * 面包板 14 | ## 硬件程序框架 15 | ![电路原理图](./image/circuit.jpg) 16 | ![系统框架图](./image/framework.png) 17 | ## 主要功能 18 | * WIFI配网:ESP32可以作为服务器提供配网页面实现配网 19 | * 天气API获取:ESP32发送HTTP请求,使用ArduinoJSON处理数据 20 | * MQTT客户端:连接阿里云平台,阿里云的封装了阿里云接入的函数(只需三元组信息) 21 | * Blinker客户端:主要通过点灯科技接入第三方语音,实现小米小爱同学联动 22 | * 环境数据读取:通过BME280、MQ-2获取温湿度等数据 23 | * OLED显示功能: 在OLED屏幕上面显示相关的信息 24 | ## 全部资料 25 | 链接:https://pan.xunlei.com/s/VN-YXMz8jSMzedzqGzchDagcA1 26 | 提取码:6rx8 27 | 复制这段内容后打开手机迅雷App,查看更方便 28 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp32dev] 12 | platform = espressif32 13 | board = esp32dev 14 | framework = arduino 15 | monitor_speed = 115200 16 | upload_speed = 921600 17 | board_build.partitions = huge_app.csv 18 | lib_deps = 19 | knolleary/PubSubClient@^2.8 20 | me-no-dev/ESP Async WebServer @ ^1.2.3 21 | rweather/Crypto @ ^0.2.0 22 | bblanchon/ArduinoJson@^6.16.1 23 | olikraus/U8g2@^2.28.7 24 | adafruit/Adafruit BMP280 Library@^2.1.0 25 | adafruit/DHT sensor library@^1.4.0 26 | adafruit/Adafruit BME280 Library@^2.1.2 27 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ================================================================================== 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * File_name : MQTTdemo.ino 7 | * Describe : MQTT使用模板 8 | * Author : GHJ 9 | * Date : 2020年07月05日 13:40:00 10 | * 11 | * PS: 12 | * 需要MQTT->PubSubClient库:https://github.com/knolleary/pubsubclient.git 13 | * 需要SHA256->Crypto库:https://github.com/OperatorFoundation/Crypto.git 14 | * 需要WebServer->ESP Async WebServer库:https://github.com/me-no-dev/ESPAsyncWebServer.git 15 | * 需要Json->ArduinoJson库:https://github.com/bblanchon/ArduinoJson.git 16 | * 需要OLED->U8g2库:https://github.com/olikraus/u8g2.git 17 | * X 需要BMP280->BMP280库:https://github.com/adafruit/Adafruit_BMP280_Library.git 18 | * 需要DHT11->DHT库:https://github.com/adafruit/DHT-sensor-library.git 19 | * 需要BME280->BME280库:https://github.com/adafruit/Adafruit_BME280_Library.git 20 | * 需要Blinker->Blinker库:https://github.com/blinker-iot/blinker-library.git 21 | * 22 | * Change Logs: 23 | * Date Author Notes 24 | * 2020年07月05日 GHJ the first version 25 | * 2020年07月14日 GHJ add mqtt to connect EMQX 26 | * 2020年10月05日 GHJ add Aliyun MQTT rules to connect Aliyun IoT 27 | * 2020年10月06日 GHJ add AliyunIoT function to connect Aliyun IoT 28 | * 2020年10月16日 GHJ add WebServer & freeRTOS 29 | * 2020年10月18日 GHJ add FileSystem & Tool of JSON & Alarm LED for TIME TASK 30 | * 2020年10月29日 GHJ add 0.96 inch OLED and BMP280 sensor 31 | * 2020年10月30日 GHJ add HTTP and DHT11 sensor 32 | * 2020年11月17日 GHJ add BME280 & remove BMP280 33 | * 2020年12月13日 GHJ add Blinker to connect Mi-IoT 34 | * 2020年12月30日 GHJ add two threads : Thread_OELD & Thead_HTTP 35 | * 36 | * =================================================================================== 37 | */ 38 | 39 | /*=========================== 头文件 =============================*/ 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #define BLINKER_WIFI 58 | #define BLINKER_MIOT_SENSOR 59 | #include 60 | 61 | // #include 62 | /*=========================== 全局变量及宏定义 =============================*/ 63 | #define port 1883 // port : 端口 通常 1883 不需要改 64 | #define DHTPIN 0 // DHTPIN : dht11 data pin 65 | String auth = "93b906890a38"; // Blinker 密钥 66 | String SSID = "heartbeats"; // ssid : WIFI名称 67 | String PASSWORD = "24682468"; // password : WIFI密码 68 | String content; // content : Web配网存放HTML页面 69 | WiFiClient espClient; // WiFiClient : 创建wifi 客户端对象,用于接入WIFI 70 | HTTPClient espHttp; // HTTP : HTTP请求 71 | AsyncWebServer server(80); // server : Web配网服务器 72 | PubSubClient mqttClient(espClient); // PubSubClient 创建mqtt 客户端对象,用于接入MQTT 73 | PubSubClient mClient(espClient); // PubSubClient 创建mqtt 客户端对象,用于接入MQTT 74 | File file; // File : 文件句柄 75 | StaticJsonDocument<20000> doc; // jSON数据处理 76 | Adafruit_BME280 bme(SS); // bme280 77 | int httpResponseCode; // http响应状态 78 | String httpBaseURL = "http://47.95.249.141:1880"; // http访问的地址 79 | String serverBath = "https://tianqiapi.com/api?version=v6&appid=29776943&appsecret=GtjmmR3Y"; //天气API地址 80 | 81 | float temperature_bme = 0; //BME280读取的温度 82 | float humidity_bme = 0; //BME280读取的湿度 83 | float pressure_bme = 0; //BME280读取的气压 84 | String date = "none"; // "日期:2020-12-21" 85 | const char *week = "none"; // "星期:星期一" 86 | const char *city = "none"; // "所在城市:杭州" 87 | const char *wea = "none"; // "天气:晴" 88 | const char *wea_img = "none"; // "天气 icon:晴" 89 | const char *humidity = "none"; // "当前湿度:32%" 90 | const char *pressure = "none"; // "当前气压:1023" 91 | const char *win = "none"; // "风向:东风" 92 | const char *win_speed = "none"; // "风速:2级" 93 | const char *air_level = "none"; // "空气质量:良" 94 | int air_pm25 = 0; // "PM2.5浓度:80" 95 | int tem = 0; // "当前气温:9" 96 | int tem1 = 0; // "最高温:8" 97 | int tem2 = 0; // "最低温:0" 98 | 99 | /* u8g2 constructer */ 100 | U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/SCL, /* data=*/SDA); // ESP32 Thing, HW I2C with pin remapping 101 | 102 | /** if you want to use Aliyun you can use the following instructions. 103 | * 104 | * STEP 1 定义宏定义 #define Aliyun_IoT 105 | * such as //#define Aliyun_IoT -> #define Aliyun_IoT 106 | * STEP 2 设置三元组信息 107 | * such as String productKey = "a1AiKMtUf57"; //产品Key 108 | * String deviceName = "demo"; //设备名 109 | * String deviceSecret = "77dcf17f5bf94e05f370a55ae2fc085b"; //设备密码 110 | * PS : 默认使用用户私人的云平台,请自行配置 111 | */ 112 | #define Aliyun_IoT 113 | #ifdef Aliyun_IoT 114 | /********************************* 阿里云IoT 物联网云平台 ********************************/ 115 | #define SHA256HMAC_SIZE 32 116 | /*三元组*/ 117 | String productKey = "a188WDNaBJg"; //产品Key 118 | String deviceName = "test"; //设备名 119 | String deviceSecret = "f2af06e21a62147b92127cdd0d25829e"; //设备密码 120 | /*以下信息由AliyunIoT()接口实现,不必手动修改*/ 121 | //${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com 122 | String aliyun_mqtt_server = "YourProductKey.iot-as-mqtt.cn-shanghai.aliyuncs.com"; 123 | //${clientId}|securemode=3,signmethod=hmacsha1| 124 | //${clientId}为设备的ID信息。可取任意值,长度在64字符以内。建议使用设备的MAC地址或SN码。 125 | String aliyun_clientID = "clientId|securemode=3,signmethod=hmacsha1|"; 126 | //${YourDeviceName}&${YourProductKey} 127 | String aliyun_clientName = "YourDeviceName&YourProductKey"; 128 | String aliyun_clientPwd = "3BE07969F6995653F4FB53A86878DF0BB0928576"; 129 | 130 | /* Alinker 上报消息 methods 规范 */ 131 | String POST_PROPERY = "thing.event.property.post"; //属性上报方法 132 | // String POST_EVENT = "thing.event."; //事件上报 133 | // String POST_TAGS = "thing.deviceinfo.update"; //设备标签上报方法 134 | // String DELETE_TAGS = "thing.deviceinfo.delete"; //设备标签删除方法 135 | // String GET_CONFIG = "thing.config.get"; //设备配置获取方法 136 | 137 | /* 物理模型 topic */ 138 | // 设备属性上报 publish topic 139 | String PROPERTY_POST_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/event/property/post"; 140 | // 云端响应属性上报 subscribe topic 141 | String PROPERTY_POST_REPLY_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/event/property/post_reply"; 142 | // 云端设备属性设置 subscribe topic 143 | String ONSET_PROPS_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/service/property/set"; 144 | 145 | // 设备服务调用 publish topic 146 | // String SERVICE_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/service/"; 147 | // 设备端响应服务调用 subscribe topic 148 | // String SERVICE_REPLY_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/service/"; 149 | 150 | // 设备事件上报 publish topic 151 | // String EVENT_POST_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/event/"; 152 | // 云端响应事件上报 subscribe topic 153 | // String EVENT_POST_REPLY_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/event/"; 154 | 155 | /* 156 | //设备标签上报topic。参数:{productKey}/{deviceName} 157 | String TAG_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/deviceinfo/update"; 158 | //设备标签上报reply的topic。参数:{productKey}/{deviceName} 159 | String TAG_REPLY_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/deviceinfo/update_reply"; 160 | //删除设备标签topic。参数:{productKey}/{deviceName} 161 | String TAG_DELETE_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/deviceinfo/delete"; 162 | //删除设备标签reply的topic。参数:{productKey}/{deviceName} 163 | String TAG_DELETE_REPLY_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/deviceinfo/delete_reply"; 164 | // 远程配置通用topic 165 | String CONFIG_WILDCARD_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/config/#"; 166 | // 远程配置topic 参数:{productKey}/{deviceName} 167 | String CONFIG_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/config/get"; 168 | // 远程配置reply topic 参数:{productKey}/{deviceName} 169 | String CONFIG_REPLY_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/config/get_reply"; 170 | // 远程配置订阅变化topic 参数:{productKey}/{deviceName} 171 | String CONFIG_SUBSCRIBE_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/config/push"; 172 | // 远程配置reply topic 参数:{productKey}/{deviceName} 173 | String CONFIG_SUBSCRIBE_RESP_TOPIC = "/sys/" + productKey + "/" + deviceName + "/thing/config/push_reply"; 174 | // 设备影子订阅topic 175 | String SHADOW_SUBSCRIBE_TOPIC = "/shadow/get/" + productKey + "/" + deviceName; 176 | // 设备影子获取topic 177 | String SHADOW_GET_TOPIC = "/shadow/update/" + productKey + "/" + deviceName; 178 | // 设备影子更新topic 179 | String SHADOW_POST_TOPIC = "/shadow/update/" + productKey + "/" + deviceName; 180 | */ 181 | 182 | /**点击了解更多**/ 183 | /**https://help.aliyun.com/document_detail/140507.html?spm=a2c4g.11186623.6.571.1b5a24dfCbOOFK**/ 184 | /********************************* 阿里云IoT 物联网云平台 ********************************/ 185 | #else 186 | /* 187 | * mqtt_server : MQTT服务器域名/IP地址 188 | * clientID : 接入服务器的MQTT客户端ID 189 | * clientName :接入服务器的用户 190 | * clientPwd :接入服务器的密码 191 | */ 192 | const char *mqtt_server = "47.95.249.141"; 193 | const char *clientID = "mqtt-31902342"; 194 | const char *clientName = "ESP32"; 195 | const char *clientPwd = "public"; 196 | #endif 197 | 198 | /*定义线程句柄*/ 199 | TaskHandle_t ThreadWiFi; //WIFI线程 200 | TaskHandle_t ThreadMQTT; //MQTT线程 201 | TaskHandle_t ThreadSensor; //Sensor线程 202 | TaskHandle_t ThreadWeather; //Weather线程 203 | TaskHandle_t ThreadOled; //OLED线程 204 | 205 | /*定义定时器句柄*/ 206 | TimerHandle_t TimeAlarmLED; 207 | 208 | /*定义信号量*/ 209 | SemaphoreHandle_t sem_WIFI; //信号量用于WIFI线程 210 | SemaphoreHandle_t sem_MQTT; //信号量用于MQTT 211 | SemaphoreHandle_t sem_Sensor; //信号量传感器用于上传数据 212 | SemaphoreHandle_t sem_HTTP; //信号量HTTP 213 | SemaphoreHandle_t sem_Oled; //信号量HTTP 214 | 215 | /*线程入口声明*/ 216 | void ThreadWiFiEntry(void *pvParameters); //WIFI线程入口 217 | void ThreadMqttEntry(void *pvParameters); //MQTT线程入口 218 | void ThreadSensorEntry(void *pvParameters); //Sensor线程入口 219 | void ThreadWeatherEntry(void *pvParameters); //HTTP线程入口 220 | void ThreadOledEntry(void *pvParameters); //OLED线程入口 221 | 222 | /*定时器入口声明*/ 223 | void TIMAlarmLEDEntry(TimerHandle_t xTimer); //LED警告定时器入口 224 | 225 | /*函数声明*/ 226 | void TaskAPPStart(); // 应用任务启动函数 227 | void wifi_connect(); // WiFi连接 228 | void webwifi(); // web服务器配置wifi 229 | void webmain(AsyncWebServerRequest *request); // web服务器监听配网主页面 230 | void webcheck(AsyncWebServerRequest *request); // web服务器监听用户请求页面 231 | void AliyunIoT(String productKey, String deviceName, String deviceSecret); // Aliyun IoT 连接 232 | void mqtt_connect(); // MQTT私有云平台连接 233 | void callback(char *topics, byte *payload, unsigned int length); // MQTT统一监听订阅主题回调函数 234 | String hmac256(const String signcontent, const String deviceSecret); // hmac256加密运算 235 | void FileSystem(); // 文件系统 236 | void OLEDInit(); // OLED初始化 237 | void OLEDprint(int x, int y, String text); // OLED打印 238 | void SensorInit(); // 传感器初始化 239 | void Weather(String icon); // 显示天气icon 240 | void BlinkerInit(); // Blinker初始化 241 | void miotQuery(int32_t queryCode); // 小米小爱查询返回接口 242 | void dataRead(const String &data); // Blinker数据绑定回调函数 243 | void drawScrollString(int16_t offset, const char *s); // 244 | /*=========================== 用户自定义全局变量&宏定义 =============================*/ 245 | #define LED 4 //GPIO4 电源指示灯 246 | #define Bee 13 //有源蜂鸣器 247 | // width: 128, height: 20 248 | // U8X8_PROGMEM 249 | const unsigned char col[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 250 | // width: 128, height: 32 251 | //const unsigned char col_clear[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 252 | 253 | /*=========================== 用户自定义全局变量&宏定义 =============================*/ 254 | 255 | /*====================================== 初始化 =========================================*/ 256 | /* 257 | * @brief:初始化 258 | * @param:none 259 | * @retval:none 260 | */ 261 | void setup() 262 | { 263 | Serial.begin(115200); //设置串口波特率 264 | pinMode(LED, OUTPUT); //电源、WIFI连接状态指示灯 265 | /*蜂鸣器*/ 266 | pinMode(Bee, OUTPUT); 267 | digitalWrite(Bee, HIGH); 268 | /*====================用户初始化=======================*/ 269 | /**如 IO口模式初始化**/ 270 | 271 | /*====================用户初始化=======================*/ 272 | OLEDInit(); //OLED初始化 273 | FileSystem(); //文件系统创建 274 | SensorInit(); //传感器初始化 275 | BlinkerInit(); //Blinker初始化 276 | TaskAPPStart(); //任务启动 277 | } 278 | 279 | /*===================================== 循环执行 不再使用 =================================*/ 280 | /* 281 | * @brief:需要循环执行的代码,上操作系统后,其内代码不再使用 282 | * @param:none 283 | * @retval:none 284 | */ 285 | void loop() 286 | { 287 | /** 288 | * 不放程序,所有代码放在线程任务中进行 289 | */ 290 | } 291 | 292 | /*======================================= TaskAPPStart ====================================*/ 293 | /* 294 | * @brief: 启动创建任务 295 | * @param:none 296 | * @retval:none 297 | */ 298 | void TaskAPPStart() 299 | { 300 | sem_WIFI = xSemaphoreCreateCounting(1, 0); 301 | if (sem_WIFI == NULL) 302 | { 303 | Serial.println("WIFI信号量创建失败......"); 304 | } 305 | else 306 | { 307 | Serial.println("WIFI信号量创建成功......"); 308 | } 309 | sem_MQTT = xSemaphoreCreateCounting(1, 0); 310 | if (sem_MQTT == NULL) 311 | { 312 | Serial.println("MQTT信号量创建失败......"); 313 | } 314 | else 315 | { 316 | Serial.println("MQTT信号量创建成功......"); 317 | } 318 | sem_Sensor = xSemaphoreCreateCounting(1, 0); 319 | if (sem_Sensor == NULL) 320 | { 321 | Serial.println("Sensor信号量创建失败......"); 322 | } 323 | else 324 | { 325 | Serial.println("Sensor信号量创建成功......"); 326 | } 327 | sem_HTTP = xSemaphoreCreateCounting(1, 0); 328 | if (sem_HTTP == NULL) 329 | { 330 | Serial.println("HTTP信号量创建失败......"); 331 | } 332 | else 333 | { 334 | Serial.println("HTTP信号量创建成功......"); 335 | } 336 | sem_Oled = xSemaphoreCreateCounting(1, 0); 337 | if (sem_Oled == NULL) 338 | { 339 | Serial.println("Oled信号量创建失败......"); 340 | } 341 | else 342 | { 343 | Serial.println("Oled信号量创建成功......"); 344 | } 345 | /*创建WiFi线程*/ 346 | BaseType_t status; 347 | status = xTaskCreatePinnedToCore( 348 | (TaskFunction_t)ThreadWiFiEntry, //WIFI线程入口 349 | (const char *const) "Thread_WIFI", //线程名称 350 | (const uint32_t)2048 * 2, //线程栈 351 | (void *const)NULL, //WIFI线程入口参数 352 | (UBaseType_t)15, //线程优先级 0-24 数值越大优先级越高 353 | (TaskHandle_t *)&ThreadWiFi, //线程句柄 354 | (const BaseType_t)APP_CPU_NUM); //指定内核1 355 | if (status == pdPASS) 356 | { 357 | Serial.println("WiFi线程创建成功..."); 358 | } 359 | else 360 | { 361 | Serial.println("WiFi线程创建失败..."); 362 | } 363 | /*创建MQTT线程*/ 364 | status = xTaskCreatePinnedToCore( 365 | (TaskFunction_t)ThreadMqttEntry, //MQTT线程入口 366 | (const char *const) "Thread_MQTT", //线程名称 367 | (const uint32_t)8192, //线程栈 368 | (void *const)NULL, //MQTT线程入口参数 369 | (UBaseType_t)13, //线程优先级 0-24 数值越大优先级越高 370 | (TaskHandle_t *)&ThreadMQTT, //线程句柄 371 | (const BaseType_t)APP_CPU_NUM); //指定内核1 372 | if (status == pdPASS) 373 | { 374 | Serial.println("MQTT线程创建成功..."); 375 | } 376 | else 377 | { 378 | Serial.println("MQTT线程创建失败..."); 379 | } 380 | /*创建Sensor线程*/ 381 | status = xTaskCreatePinnedToCore( 382 | (TaskFunction_t)ThreadSensorEntry, //Sensor线程入口 383 | (const char *const) "Thread_Sensor", //线程名称 384 | (const uint32_t)2048 * 2, //线程栈 385 | (void *const)NULL, //Sensor线程入口参数 386 | (UBaseType_t)10, //线程优先级 0-24 数值越大优先级越高 387 | (TaskHandle_t *)&ThreadSensor, //线程句柄 388 | (const BaseType_t)PRO_CPU_NUM); //指定内核1 389 | if (status == pdPASS) 390 | { 391 | Serial.println("Sensor线程创建成功..."); 392 | } 393 | else 394 | { 395 | Serial.println("Sensor线程创建失败..."); 396 | } 397 | /*创建Weather线程*/ 398 | status = xTaskCreatePinnedToCore( 399 | (TaskFunction_t)ThreadWeatherEntry, //Weather线程入口 400 | (const char *const) "Thread_HTTP", //线程名称 401 | (const uint32_t)4096 * 2, //线程栈 402 | (void *const)NULL, //Weather线程入口参数 403 | (UBaseType_t)8, //线程优先级 0-24 数值越大优先级越高 404 | (TaskHandle_t *)&ThreadWeather, //线程句柄 405 | (const BaseType_t)APP_CPU_NUM); //指定内核1 406 | if (status == pdPASS) 407 | { 408 | Serial.println("HTTP线程创建成功..."); 409 | } 410 | else 411 | { 412 | Serial.println("HTTP线程创建失败..."); 413 | } 414 | /*创建OLED线程*/ 415 | status = xTaskCreatePinnedToCore( 416 | (TaskFunction_t)ThreadOledEntry, //OLED线程 417 | (const char *const) "Thread_Oled", //线程名称 418 | (const uint32_t)4096 * 2, //线程栈 419 | (void *const)NULL, //OLED线程入口参数 420 | (UBaseType_t)6, //线程优先级 0-24 数值越大优先级越高 421 | (TaskHandle_t *)&ThreadOled, //线程句柄 422 | (const BaseType_t)APP_CPU_NUM); //指定内核1 423 | if (status == pdPASS) 424 | { 425 | Serial.println("Oled线程创建成功..."); 426 | } 427 | else 428 | { 429 | Serial.println("Oled线程创建失败..."); 430 | } 431 | 432 | /*连接网络提示定时器*/ 433 | TimeAlarmLED = xTimerCreate( 434 | "TIM_Alarm_LED", //定时器名称 435 | pdMS_TO_TICKS(100), //定时器定时时间 436 | pdTRUE, //pdTRUE = 周期性 , pdFALSE = 一次性 437 | 0, //定时器ID 438 | TIMAlarmLEDEntry); //定时器回调函数 439 | 440 | u8g2.clearBuffer(); 441 | OLEDprint(35, 32, "App Start"); 442 | xTimerStart(TimeAlarmLED, 0); 443 | xSemaphoreGive(sem_WIFI); 444 | delay(1000); 445 | } 446 | 447 | /*======================================= 线程 定时器 入口 ====================================*/ 448 | /* 449 | * @brief:WIFI线程入口 450 | * @param:none 451 | * @retval:none 452 | */ 453 | void ThreadWiFiEntry(void *pvParameters) 454 | { 455 | /*无限等待WIFI信号量*/ 456 | xSemaphoreTake(sem_WIFI, portMAX_DELAY); 457 | /*删除主线程*/ 458 | //vTaskDelete(ThreadMain); 459 | Serial.println("===WiFi连接任务启动==="); 460 | wifi_connect(); //wifi连接 461 | while (1) 462 | { 463 | /* code */ 464 | vTaskDelay(pdMS_TO_TICKS(1000)); 465 | } 466 | } 467 | 468 | /* 469 | * @brief:MQTT线程入口 470 | * @param:none 471 | * @retval:none 472 | */ 473 | void ThreadMqttEntry(void *pvParameters) 474 | { 475 | /*无限等待MQTT信号量*/ 476 | xSemaphoreTake(sem_MQTT, portMAX_DELAY); 477 | /*挂起WIFI线程*/ 478 | Serial.println("===MQTT连接任务启动==="); 479 | /*根据宏定义,判别 Aliyun 或 私有云 */ 480 | #ifdef Aliyun_IoT 481 | AliyunIoT(productKey, deviceName, deviceSecret); //Aliyun 连接 482 | #else 483 | mqtt_connect(); //mqtt连接 484 | #endif 485 | 486 | while (1) 487 | { 488 | if (!mqttClient.connected() || !WiFi.isConnected()) 489 | { 490 | /*检验MQTT和WIFI是否断连,断连芯片重启重新配网*/ 491 | 492 | u8g2.clearBuffer(); 493 | Serial.println("WIFI or MQTT has been disconnected"); 494 | OLEDprint(20, 32, "WIFI or MQTT"); 495 | OLEDprint(0, 48, "has been disconnected"); 496 | u8g2.sendBuffer(); 497 | delay(1500); 498 | OLEDprint(0, 64, "ESP32 will restart"); 499 | u8g2.sendBuffer(); 500 | delay(2500); 501 | ESP.restart(); 502 | } 503 | mqttClient.loop(); //MQTT客户端保活 504 | Blinker.run(); //Blinker客户端保活 505 | vTaskDelay(pdMS_TO_TICKS(20)); 506 | } 507 | } 508 | 509 | /* 510 | * @brief:Sensor线程入口 511 | * @param:none 512 | * @retval:none 513 | */ 514 | void ThreadSensorEntry(void *pvParameters) 515 | { 516 | /*等待获取传感器信号量*/ 517 | xSemaphoreTake(sem_Sensor, portMAX_DELAY); 518 | 519 | while (1) 520 | { 521 | temperature_bme = bme.readTemperature(); 522 | humidity_bme = bme.readHumidity(); 523 | pressure_bme = bme.readPressure(); 524 | 525 | if (analogRead(34) > 2000) 526 | { 527 | digitalWrite(Bee, LOW); 528 | Serial.println("BEE!!!!"); 529 | Serial.println(digitalRead(13)); 530 | } 531 | else 532 | { 533 | digitalWrite(Bee, HIGH); 534 | Serial.println("NO BEE!!!!"); 535 | Serial.println(digitalRead(13)); 536 | } 537 | String payload; //存放MQTT发送消息的变量 538 | doc.clear(); //清空原有存放JSON数据和释放内存 539 | /* Aliyun消息体格式 */ 540 | doc["id"] = esp_random(); //每个消息都有自己的ID 541 | doc["version"] = "1.0"; //消息的版本 542 | JsonObject params = doc.createNestedObject("params"); //JSON数据套娃 543 | params["carbon"] = analogRead(34); //烟雾浓度 544 | params["humidity"] = bme.readHumidity(); //BME280湿度 545 | params["altitude"] = bme.readAltitude(1013.0); //BME280高度(需要设置当前海平面高度) 546 | params["airPressure"] = bme.readPressure() / 100.0; //BME280气压 547 | params["temperature"] = bme.readTemperature(); //BEM280温度 548 | doc["method"] = POST_PROPERY; //消息的方法(根据阿里云Alinker协议) 549 | serializeJson(doc, payload); //封装JSON数据并且放入payload里面 550 | // Serial.println(payload); //串口查看 551 | mqttClient.publish(PROPERTY_POST_TOPIC.c_str(), payload.c_str()); //向阿里云进行属性数据上报 552 | vTaskDelay(pdMS_TO_TICKS(3000)); 553 | } 554 | } 555 | 556 | /* 557 | * @brief:HTTP线程入口 558 | * @param:none 559 | * @retval:none 560 | */ 561 | void ThreadWeatherEntry(void *pvParameters) 562 | { 563 | xSemaphoreTake(sem_HTTP, portMAX_DELAY); 564 | 565 | while (1) 566 | { 567 | 568 | /*GET请求*/ 569 | //Serial.println("===================== GET ====================="); 570 | // espHttp.begin(httpBaseURL + "/get"); 571 | // espHttp.begin(serverBath); 572 | espHttp.begin("http://47.95.249.141:1880/api/test"); 573 | httpResponseCode = espHttp.GET(); 574 | if (httpResponseCode > 0) 575 | { 576 | // Deserialize the JSON document 577 | doc.clear(); 578 | Serial.println(httpResponseCode); 579 | deserializeJson(doc, espHttp.getString()); 580 | week = doc["week"]; 581 | city = doc["city"]; 582 | wea = doc["wea"]; 583 | wea_img = doc["wea_img"]; 584 | tem = doc["tem"]; 585 | tem1 = doc["tem1"]; 586 | tem2 = doc["tem2"]; 587 | humidity = doc["humidity"]; 588 | pressure = doc["pressure"]; 589 | win = doc["win"]; 590 | win_speed = doc["win_speed"]; 591 | air_pm25 = doc["air_pm25"]; 592 | air_level = doc["air_level"]; 593 | String time = doc["date"]; 594 | date = time; 595 | espHttp.end(); 596 | } 597 | //打印测试 598 | // Serial.println("-------API获取数据打印------"); 599 | // Serial.print("日期:"); // "日期:2020-12-21" 600 | // Serial.println(date); 601 | // Serial.print("星期:"); // "星期:星期一" 602 | // Serial.println(week); 603 | // Serial.print("所在城市:"); // "所在城市:杭州" 604 | // Serial.println(city); 605 | // Serial.print("天气:"); // "天气:晴" 606 | // Serial.println(wea); 607 | // Serial.print("天气标志:"); // "天气:晴" 608 | // Serial.println(wea_img); 609 | // Serial.print("当前气温:"); // "当前气温:9" 610 | // Serial.println(tem); 611 | // Serial.print("最高温:"); // "最高温:8" 612 | // Serial.println(tem1); 613 | // Serial.print("最低温:"); // "最低温:0" 614 | // Serial.println(tem2); 615 | // Serial.print("当前湿度:"); // "当前湿度:32%" 616 | // Serial.println(humidity); 617 | // Serial.print("当前气压:"); // "当前气压:1023" 618 | // Serial.println(pressure); 619 | // Serial.print("风向:"); // "风向:东风" 620 | // Serial.println(win); 621 | // Serial.print("风速:"); // "风速:2级" 622 | // Serial.println(win_speed); 623 | // Serial.print("PM2.5浓度:"); // "PM2.5浓度:80" 624 | // Serial.println(air_pm25); 625 | // Serial.print("空气质量:"); // "空气质量:良" 626 | // Serial.println(air_level); 627 | // Serial.println("------------- -------------"); 628 | // Serial.println(""); 629 | 630 | //Serial.println("===================== GET ====================="); 631 | /*POST请求*/ 632 | // Serial.println("===================== POST ====================="); 633 | //espHttp.begin(httpBaseURL + "/sensor?"); 634 | //espHttp.begin("http://192.168.1.158:8888/v1/info"); 635 | 636 | espHttp.begin("http://47.95.249.141:1880/api/test"); 637 | espHttp.addHeader("Content-Type", "application/json"); 638 | doc.clear(); 639 | doc["stuNum"] = "31902342"; 640 | doc["temperature"] = (int)bme.readTemperature(); 641 | doc["humidity"] = (int)bme.readHumidity(); 642 | doc["airpressure"] = bme.readPressure() / 100.0; 643 | doc["carbon"] = analogRead(34); 644 | String params; 645 | serializeJson(doc, params); 646 | httpResponseCode = espHttp.POST(params); 647 | 648 | if (httpResponseCode > 0) 649 | { 650 | Serial.println("***********POST**********"); 651 | // Serial.println(httpResponseCode); 652 | Serial.println(espHttp.getString()); 653 | Serial.println("***********POST*********"); 654 | } 655 | espHttp.end(); 656 | 657 | // Serial.println("===================== POST ====================="); 658 | vTaskDelay(pdMS_TO_TICKS(1000)); 659 | } 660 | } 661 | 662 | /* 663 | * @brief:Oled线程入口 664 | * @param:none 665 | * @retval:none 666 | */ 667 | void ThreadOledEntry(void *pvParameters) 668 | { 669 | xSemaphoreTake(sem_Oled, portMAX_DELAY); 670 | while (1) 671 | { 672 | u8g2.clearBuffer(); //清屏 673 | u8g2.setFont(u8g2_font_open_iconic_embedded_2x_t); //设置字库 icon 674 | u8g2.drawGlyph(111, 16, 64); //显示电池 675 | u8g2.drawGlyph(0, 16, 80); //显示WIFI 676 | u8g2.setFont(u8g2_font_open_iconic_weather_4x_t); //设置天气状态 icon 677 | //u8g2.drawGlyph(10, 50, 69); //显示天气icon 678 | u8g2.setFont(u8g2_font_open_iconic_weather_4x_t); 679 | 680 | if (String(wea_img).equals("qing")) 681 | { 682 | u8g2.drawGlyph(10, 50, 69); //显示晴天 683 | } 684 | else if (String(wea_img).equals("yu") || String(wea_img).equals("lei")) 685 | { 686 | u8g2.drawGlyph(10, 50, 67); //显示雨天 687 | } 688 | else if (String(wea_img).equals("yun")) 689 | { 690 | u8g2.drawGlyph(10, 50, 65); //显示多云 691 | } 692 | else 693 | { 694 | u8g2.drawGlyph(10, 50, 64); //显示其它 695 | } 696 | 697 | u8g2.setFont(u8g2_font_logisoso20_tf); 698 | u8g2.setCursor(48 + 3, 48); 699 | float temp = bme.readTemperature(); 700 | u8g2.printf("%.1f", temp); 701 | u8g2.print("°C"); 702 | u8g2.setFont(u8g2_font_wqy13_t_gb2312); 703 | u8g2.sendBuffer(); //显示在屏幕上面 704 | vTaskDelay(pdMS_TO_TICKS(3000)); 705 | 706 | /*********************************OLED显示温湿度、气压--Page1*********************************/ 707 | /*固定图标:WIFI和电池图标*/ //length 128 (0-128) width 64(0-64) 708 | u8g2.clearBuffer(); //清除缓冲区 709 | u8g2.setFont(u8g2_font_open_iconic_embedded_2x_t); //设置中文或字母表或图标的字体 710 | // u8g2.setFont(u8g2_font_open_iconic_embedded_1x_t); //图标太小 711 | u8g2.drawGlyph(111, 16, 64); //绘制字符集的符号,显示电池 712 | u8g2.drawGlyph(0, 16, 80); //绘制字符集的符号,显示WIFI 713 | u8g2.setFont(u8g2_font_wqy12_t_gb2312a); 714 | 715 | u8g2.setCursor(10, 30); //OLED屏--Set the x,y coordinates 716 | u8g2.print("当前气温:"); 717 | u8g2.printf("%.2f", temperature_bme); 718 | u8g2.print("°C"); 719 | 720 | u8g2.setCursor(10, 45); 721 | u8g2.print("当前湿度:"); 722 | u8g2.printf("%.2f", humidity_bme); 723 | u8g2.print("%"); 724 | 725 | u8g2.setCursor(10, 60); 726 | u8g2.print("当前气压:"); 727 | u8g2.printf("%.2f", pressure_bme); 728 | u8g2.print("hPa"); 729 | u8g2.sendBuffer(); //绘制缓冲区内容 730 | Serial.println(); 731 | vTaskDelay(pdMS_TO_TICKS(3000)); 732 | /*****************************************************************************/ 733 | 734 | /************每10秒请求获取一次数据--API数据获取 + OLED-Page2、3显示************/ 735 | /*设置URL链接 Send an HTTP GET request*/ /*天气API获取数据*/ 736 | 737 | /*********************************OLED显示API数据部分--Page2*********************************/ 738 | 739 | u8g2.clearBuffer(); //清空缓存 740 | u8g2.setFont(u8g2_font_open_iconic_embedded_2x_t); //设置中文或字母表或图标的字体 741 | u8g2.drawGlyph(111, 16, 64); //绘制字符集的符号,显示电池 742 | u8g2.drawGlyph(0, 16, 80); //绘制字符集的符号,显示WIFI 743 | // u8g2.setFont(u8g2_font_open_iconic_weather_4x_t); 744 | // u8g2.drawGlyph(10, 55, 69); 745 | Weather(wea_img); //wea_img取自JSON解析的数据变量 746 | // u8g2.setFont(u8g2_font_wqy12_t_gb2312a); 747 | // u8g2.setCursor(30,16); 748 | // u8g2.print(date.c_str()); 749 | u8g2.setFont(u8g2_font_logisoso20_tf); 750 | u8g2.setFont(u8g2_font_wqy13_t_gb2312); 751 | u8g2.setCursor(43, 34); 752 | u8g2.print("室外天气:"); 753 | u8g2.print(tem); 754 | u8g2.print("°C"); 755 | u8g2.setFont(u8g2_font_wqy12_t_gb2312a); 756 | // u8g2.setFont(u8g2_font_wqy13_t_gb2312); 757 | // u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font 758 | u8g2.setCursor(43, 52); 759 | u8g2.print("今日:"); 760 | u8g2.print(tem2); 761 | // u8g2.print("%d",(int)tem); 762 | u8g2.print("°C"); 763 | u8g2.print("~"); 764 | u8g2.print(tem1); 765 | u8g2.print("°C"); 766 | u8g2.sendBuffer(); //绘制缓冲区内容 767 | vTaskDelay(pdMS_TO_TICKS(3000)); 768 | // /*********************************OLED显示API数据部分--Page3*********************************/ 769 | u8g2.clearBuffer(); //清除缓冲区 770 | u8g2.setFont(u8g2_font_open_iconic_embedded_2x_t); //设置中文或字母表或图标的字体 771 | // u8g2.setFont(u8g2_font_open_iconic_embedded_1x_t); //图标太小 772 | u8g2.drawGlyph(111, 16, 64); //绘制字符集的符号,显示电池 773 | u8g2.drawGlyph(0, 16, 80); //绘制字符集的符号,显示WIFI 774 | u8g2.setFont(u8g2_font_wqy13_t_gb2312); 775 | u8g2.setCursor(32, 14); 776 | u8g2.print(date); 777 | u8g2.setFont(u8g2_font_wqy12_t_gb2312a); 778 | u8g2.setCursor(20, 28); //OLED屏--Set the x,y coordinates 779 | u8g2.print("湿度: "); 780 | u8g2.printf(humidity); 781 | u8g2.print("%"); 782 | u8g2.setCursor(20, 44); 783 | u8g2.print("气压: "); 784 | u8g2.printf(pressure); 785 | u8g2.print("hPa"); 786 | u8g2.setCursor(20, 60); 787 | u8g2.print("空气质量: "); 788 | u8g2.printf(air_level); 789 | u8g2.sendBuffer(); //绘制缓冲区内容 790 | 791 | vTaskDelay(pdMS_TO_TICKS(3000)); 792 | } 793 | } 794 | 795 | /* 796 | * @brief:空闲线程入口 797 | * @param:none 798 | * @retval:none 799 | */ 800 | void TIMAlarmLEDEntry(TimerHandle_t xTimer) 801 | { 802 | digitalWrite(LED, !digitalRead(LED)); 803 | } 804 | /*======================================= 线程 定时器 入口 ====================================*/ 805 | 806 | /*======================================== WIFI =========================================*/ 807 | /* 808 | * @brief:连接WiFi 809 | * @param:none 810 | * @retval:none 811 | */ 812 | void wifi_connect() 813 | { 814 | //设置wifi station模式 815 | WiFi.mode(WIFI_STA); 816 | WiFi.disconnect(); 817 | /*判断是否存在wifi.txt文件*/ 818 | if (SPIFFS.exists("/root/wifi.txt")) 819 | { 820 | Serial.println("find /root/wifi.txt"); 821 | /*以只读的方式打开wifi.txt文件*/ 822 | file = SPIFFS.open("/root/wifi.txt", FILE_READ); 823 | /*定义临时变量存储wifi.txt的内容*/ 824 | String Temp = file.readString(); 825 | /*关闭文件*/ 826 | file.close(); 827 | /*对字符串解包生成所需要的json数据*/ 828 | DeserializationError error = deserializeJson(doc, Temp); 829 | if (error) 830 | { 831 | /*格式化失败*/ 832 | Serial.print(F("deserializeJson() failed: ")); 833 | Serial.println(error.c_str()); 834 | ESP.restart(); //重启 835 | } 836 | else 837 | { 838 | /*格式化成功*/ 839 | /*取出变量ssid & password的值*/ 840 | String temp_ssid = doc["ssid"]; 841 | String temp_pwd = doc["password"]; 842 | /*赋值给 SSID & PASSWORD */ 843 | SSID = temp_ssid; 844 | PASSWORD = temp_pwd; 845 | //Serial.println("ssid: " + SSID); 846 | //Serial.println("password: " + PASSWORD); 847 | } 848 | } 849 | /*WIFI连接*/ 850 | //WiFi.begin(SSID.c_str(), PASSWORD.c_str()); 851 | /*Blinker 连接上 及确保WIFI连接上*/ 852 | Blinker.begin(auth.c_str(), SSID.c_str(), PASSWORD.c_str()); 853 | //判断连接状态 854 | int count = 0; 855 | while (WiFi.status() != WL_CONNECTED) 856 | // while(!Blinker.connected()) 857 | { 858 | //vTaskDelay(pdMS_TO_TICKS(1000)); 859 | delay(1000); 860 | if (count >= 5) 861 | { 862 | /*超时5s 结束程序*/ 863 | break; 864 | } 865 | u8g2.clearBuffer(); 866 | OLEDprint(0, 40, "WIFI is connecting ..."); 867 | Serial.println("WIFI is connecting ..."); 868 | count++; 869 | } 870 | 871 | if (WiFi.isConnected()) 872 | { 873 | Serial.println("WIFI connected"); 874 | Serial.print("IP address: "); 875 | Serial.println(WiFi.localIP().toString()); 876 | u8g2.clearBuffer(); 877 | OLEDprint(0, 32, "WIFI connected"); 878 | OLEDprint(0, 48, "IP: " + WiFi.localIP().toString()); 879 | u8g2.setFont(u8g2_font_open_iconic_embedded_2x_t); 880 | u8g2.drawGlyph(0, 16, 80); 881 | u8g2.sendBuffer(); 882 | delay(1500); 883 | /*发送信号量MQTT,触发MQTT线程*/ 884 | xSemaphoreGive(sem_MQTT); 885 | } 886 | else 887 | { 888 | /*进入Web配网*/ 889 | Serial.println("Web配网....."); 890 | u8g2.clearBuffer(); 891 | OLEDprint(0, 32, "WIFI is connecting ..."); 892 | webwifi(); 893 | } 894 | } 895 | /* 896 | * @brief:Web配网主页,是url="/"根目录下的监听回调函数 897 | * @param:none 898 | * @retval:none 899 | */ 900 | void webmain(AsyncWebServerRequest *request) 901 | { 902 | /*设置配网Web页面*/ 903 | content = "WIFI配置"; 904 | content += "

Connect device to your WiFi

"; 905 | content += "
"; 906 | content += ""; 907 | content += ""; 908 | content += ""; 922 | content += ""; 923 | content += ""; 924 | content += "
扫描WIFI手动输入
SSID:
SSID:
Password:
"; 925 | content += ""; 935 | 936 | WiFi.scanDelete(); //清除扫描数据 937 | Serial.println(content); 938 | /*Web服务器返回状态码200,以及配置WiFi页面*/ 939 | request->send(200, "text/html", content); 940 | } 941 | else 942 | { 943 | content = "

The server is busy, please refresh the page.

"; 944 | request->send(200, "text/html", content); 945 | } 946 | } 947 | /* 948 | * @brief:获取wifi表单数据连接wifi,是url="/wifi"的监听回调函数 949 | * @param:none 950 | * @retval:none 951 | */ 952 | void webcheck(AsyncWebServerRequest *request) 953 | { 954 | /*获取ssid 以及 wifi 密码*/ 955 | /*WIFI扫描配网*/ 956 | if (request->arg("method") == "Auto") 957 | { 958 | SSID = request->arg("ssid"); 959 | PASSWORD = request->arg("password"); 960 | Serial.println("==========Auto==========="); 961 | } 962 | /*WIFI手动配网*/ 963 | if (request->arg("method") == "Manual") 964 | { 965 | SSID = request->arg("ssid_manual"); 966 | PASSWORD = request->arg("password"); 967 | Serial.println("==========manual==========="); 968 | } 969 | char buffer[64]; //临时变量 存放json字符串 970 | doc["ssid"] = SSID; //添加成员ssid 971 | doc["password"] = PASSWORD; //添加成员password 972 | serializeJson(doc, buffer); //格式化JSON 转存到 buffer 973 | file = SPIFFS.open("/root/wifi.txt", FILE_WRITE); //以写的方式打开wifi.txt文件,每次覆盖之前,没有就创建 974 | file.write((uint8_t *)buffer, strlen(buffer)); //把buffer里面的写入到wifi.txt 975 | file.close(); //关闭文件 976 | 977 | /*Web服务器返回状态码200,提示配网和Web服务器结束*/ 978 | request->send(200, "text/html", "

Successfully connected to wifi


Web servers will be shut down

"); 979 | //vTaskDelay(pdMS_TO_TICKS(1000)); 980 | /*关闭Web服务器,重新连接wifi*/ 981 | server.end(); 982 | delay(1000); 983 | /*重启ESP32*/ 984 | ESP.restart(); 985 | } 986 | /* 987 | * @brief:Web配网 988 | * @param:none 989 | * @retval:none 990 | */ 991 | void webwifi() 992 | { 993 | /*设置wifi为 AP热点*/ 994 | WiFi.mode(WIFI_AP); 995 | /*设置热点WIFI*/ 996 | WiFi.softAP("ESP32配网", ""); 997 | /*获取热点IP地址*/ 998 | IPAddress myIP = WiFi.softAPIP(); 999 | /*串口显示热点IP地址*/ 1000 | Serial.print("AP IP address: "); 1001 | Serial.println(myIP); 1002 | /*设置服务器监听 url 以及 服务器回应(回调函数) */ 1003 | server.on("/", webmain); 1004 | server.on("/wifi", webcheck); 1005 | /*设置服务器端口 并且开启*/ 1006 | server.begin(); 1007 | u8g2.clearBuffer(); 1008 | OLEDprint(0, 32, "WebServer Start"); 1009 | OLEDprint(0, 50, "Visit the website"); 1010 | delay(2000); 1011 | u8g2.clearBuffer(); 1012 | OLEDprint(0, 32, "Connect ESP32WIFI"); 1013 | OLEDprint(0, 50, "http://192.168.4.1"); 1014 | 1015 | //while(true); 1016 | } 1017 | 1018 | /*======================================== MQTT =========================================*/ 1019 | /* 1020 | * @brief:MQTT回调函数,用于获取订阅的消息 1021 | * @param:topics 订阅的主题 1022 | * @param:payload 订阅的主题的消息 注:byte 只能一个字节一个字节读 1023 | * @param:length 消息大小 1024 | * @retval:none 1025 | */ 1026 | void callback(char *topics, byte *payload, unsigned int length) 1027 | { 1028 | String topic = topics; //Stirng方便处理 1029 | String temp; //存放消息 1030 | /**打印消息**/ 1031 | Serial.print("Message arrived ["); 1032 | Serial.print(topics); 1033 | Serial.print("] "); 1034 | for (int i = 0; i < length; i++) 1035 | { 1036 | // Serial.print((char)payload[i]); 1037 | temp += (char)payload[i]; 1038 | } 1039 | Serial.println(temp); 1040 | 1041 | /**对消息进行处理,用户自己完成**/ 1042 | /**===================== Example ====================**/ 1043 | /* 1044 | * 可以对 topic 筛选 1045 | */ 1046 | 1047 | if (topic == "/LED_ON") 1048 | { 1049 | digitalWrite(LED, LOW); //开灯 1050 | } 1051 | if (topic == "/LED_OFF") 1052 | { 1053 | digitalWrite(LED, HIGH); //关灯 1054 | } 1055 | /**===================== Example ====================**/ 1056 | } 1057 | #ifdef Aliyun_IoT 1058 | /*====================================== Aliyun_IOT =========================================*/ 1059 | /* 1060 | * @brief:hmac256 加密 用于计算Aliyun接入密码 1061 | * @param: signcontent 加密对象 拼接规则 ${"clientId" + deviceName + "deviceName" + deviceName + "productKey" + productKey } 1062 | * @param: deviceSecret 设备密码用于加密 1063 | * @retval: Password 接入Aliyun的密码 1064 | */ 1065 | String hmac256(const String signcontent, const String deviceSecret) 1066 | { 1067 | byte hashCode[SHA256HMAC_SIZE]; 1068 | SHA256 sha256; 1069 | 1070 | const char *key = deviceSecret.c_str(); 1071 | size_t keySize = deviceSecret.length(); 1072 | 1073 | sha256.resetHMAC(key, keySize); 1074 | sha256.update((const byte *)signcontent.c_str(), signcontent.length()); 1075 | sha256.finalizeHMAC(key, keySize, hashCode, sizeof(hashCode)); 1076 | 1077 | String Password = ""; 1078 | for (byte i = 0; i < SHA256HMAC_SIZE; ++i) 1079 | { 1080 | Password += "0123456789ABCDEF"[hashCode[i] >> 4]; 1081 | Password += "0123456789ABCDEF"[hashCode[i] & 0xf]; 1082 | } 1083 | return Password; 1084 | } 1085 | 1086 | /* 1087 | * @brief:Aliyun_IoT 接入函数 1088 | * @param: productKey 产品Key 1089 | * @param: deviceName 设备名 1090 | * @param: deviceSecret 设备密码 1091 | * @retval: none 1092 | */ 1093 | void AliyunIoT(String productKey, String deviceName, String deviceSecret) 1094 | { 1095 | String signcontent; 1096 | /*拼接服务器地址(只针对华东2,其它地区需要修改cn-shanghai)*/ 1097 | aliyun_mqtt_server = productKey + ".iot-as-mqtt.cn-shanghai.aliyuncs.com"; 1098 | /*拼接MQTT客户端ID(只采用TCP直连和hmacsha256加密方式)*/ 1099 | aliyun_clientID = deviceName + "|securemode=3,signmethod=hmacsha256|"; 1100 | /*拼接MQTT客户端名*/ 1101 | aliyun_clientName = deviceName + "&" + productKey; 1102 | /*拼接MQTT客户端密码加密对象*/ 1103 | signcontent = "clientId" + deviceName + "deviceName" + deviceName + "productKey" + productKey; 1104 | /*获取MQTT客户端密码*/ 1105 | aliyun_clientPwd = hmac256(signcontent, deviceSecret); 1106 | /*设置mqtt服务器地址和端口*/ 1107 | mqttClient.setServer(aliyun_mqtt_server.c_str(), 1883); 1108 | /*设置mqtt保持活跃时间 ms*/ 1109 | mqttClient.setKeepAlive(60); 1110 | /*设置消息回调函数*/ 1111 | mqttClient.setCallback(callback); 1112 | OLEDprint(0, 62, "Aliyun is connecting ..."); 1113 | u8g2.sendBuffer(); 1114 | int count = 0; 1115 | while (!mqttClient.connect(aliyun_clientID.c_str(), aliyun_clientName.c_str(), aliyun_clientPwd.c_str())) 1116 | { 1117 | Serial.println("Aliyun_IoT is connecting ..."); 1118 | if (count == 1) 1119 | { 1120 | SPIFFS.format(); 1121 | break; 1122 | } 1123 | count++; 1124 | delay(1000); 1125 | } 1126 | if (mqttClient.connected()) 1127 | { 1128 | /*连接成功 关闭AlarmLED定时器*/ 1129 | xTimerStop(TimeAlarmLED, 0); 1130 | /*LED常亮示意正常工作*/ 1131 | digitalWrite(LED, LOW); 1132 | 1133 | /* 订阅云端响应属性上报 */ 1134 | mqttClient.subscribe(PROPERTY_POST_REPLY_TOPIC.c_str(), 0); 1135 | /* 订阅云端设备属性设置 */ 1136 | mqttClient.subscribe(ONSET_PROPS_TOPIC.c_str(), 0); 1137 | 1138 | /*O*/ 1139 | Serial.println("Aliyun_IoT is connected"); 1140 | Serial.println("MQTT is connected"); 1141 | OLEDprint(0, 62, "Aliyun is connecting ..."); 1142 | u8g2.drawXBM(0, 54, 128, 20, col); 1143 | OLEDprint(0, 62, "Aliyun connected"); 1144 | u8g2.sendBuffer(); 1145 | delay(1500); 1146 | 1147 | /* WIFI,MQTT 均连上之后 发送信号量 */ 1148 | xSemaphoreGive(sem_Sensor); //触发Sensor 传感器线程 1149 | xSemaphoreGive(sem_HTTP); //触发HTTP weather线程 1150 | xSemaphoreGive(sem_Oled); //触发OLED weather线程 1151 | } 1152 | } 1153 | /*====================================== Aliyun_IOT =========================================*/ 1154 | #else 1155 | /* 1156 | * @brief:MQTT连接 1157 | * @param:none 1158 | * @retval:none 1159 | */ 1160 | void mqtt_connect() 1161 | { 1162 | /*设置mqtt服务器地址和端口*/ 1163 | mqttClient.setServer(mqtt_server, 1883); 1164 | /*设置mqtt保持活跃时间 ms*/ 1165 | mqttClient.setKeepAlive(60); 1166 | /*设置消息回调函数*/ 1167 | mqttClient.setCallback(callback); 1168 | /** 1169 | * 连接服务器 1170 | * 1171 | * client.connect(ClientID,Name,Password) 1172 | * 1173 | * ClientID : 接入服务器的MQTT客户端ID 1174 | * Name :接入服务器的用户 1175 | * Password :接入服务器的密码 1176 | * 1177 | */ 1178 | OLEDprint(0, 62, "MQTT is connecting ..."); 1179 | u8g2.sendBuffer(); 1180 | int count = 0; 1181 | while (!mqttClient.connect(clientID, clientName, clientPwd)) 1182 | { 1183 | Serial.println("MQTT is connecting ..."); 1184 | if (count == 1) 1185 | { 1186 | SPIFFS.format(); 1187 | break; 1188 | } 1189 | count++; 1190 | delay(1000); 1191 | } 1192 | if (mqttClient.connected()) 1193 | { 1194 | /*连接成功 关闭AlarmLED定时器*/ 1195 | xTimerStop(TimeAlarmLED, 0); 1196 | /*LED常亮示意正常工作*/ 1197 | digitalWrite(LED, LOW); 1198 | Serial.println("MQTT is connected"); 1199 | 1200 | u8g2.drawXBM(0, 54, 128, 20, col); 1201 | OLEDprint(0, 62, "MQTT connected"); 1202 | u8g2.sendBuffer(); 1203 | /** 1204 | * 订阅主题 1205 | * 1206 | * client.subscribe(topic,qos) 1207 | * 1208 | * topic : 订阅的主题 1209 | * qos : 服务质量,Broker 与 Client 之间消息通信关系. 0 or 1 or 2 1210 | * 最多一次(0)只发不管收没收到 1211 | * 最少一次(1)至少接受到一次 1212 | * 只一次 (2)确保只接受一次,慢,安全最高 1213 | * 1214 | */ 1215 | mqttClient.subscribe("/LED_ON", 0); 1216 | mqttClient.subscribe("/LED_OFF", 0); 1217 | mqttClient.subscribe("/test", 0); 1218 | /** 1219 | * 发出消息 1220 | * 1221 | * client.publish(topic,payload,retained) 1222 | * 1223 | * topic : 发布的主题 1224 | * payload : 消息体 1225 | * retained :保留消息 true or false 1226 | */ 1227 | mqttClient.publish("/test", "... this is a test of mqtt ...", false); 1228 | /* WIFI,MQTT 均连上之后 发送信号量 */ 1229 | xSemaphoreGive(sem_Sensor); //触发Sensor 传感器线程 1230 | xSemaphoreGive(sem_HTTP); //触发HTTP weather线程 1231 | xSemaphoreGive(sem_Oled); //触发OLED weather线程 1232 | } 1233 | } 1234 | #endif 1235 | 1236 | /*======================================== 文件系统 =========================================*/ 1237 | /* 1238 | * @brief:文件系统挂载 1239 | * @param:none 1240 | * @retval:none 1241 | */ 1242 | void FileSystem() 1243 | { 1244 | //文件系统挂载 1245 | if (SPIFFS.begin(true, "/root", 3)) 1246 | { 1247 | Serial.println("The file system successfully mounts in /root"); 1248 | Serial.println(SPIFFS.totalBytes()); //文件系统总大小 1249 | Serial.println(SPIFFS.usedBytes()); //文件系统已使用 1250 | u8g2.clearBuffer(); 1251 | OLEDprint(0, 32, "The File System"); 1252 | OLEDprint(35, 50, "is initialized"); 1253 | delay(1500); 1254 | } 1255 | } 1256 | 1257 | /*======================================== OLED =========================================*/ 1258 | /* 1259 | * @brief: oled初始化 1260 | * @param:none 1261 | * @retval:none 1262 | */ 1263 | void OLEDInit() 1264 | { 1265 | u8g2.begin(); 1266 | u8g2.enableUTF8Print(); 1267 | u8g2.clearBuffer(); 1268 | u8g2.setFont(u8g2_font_open_iconic_embedded_2x_t); 1269 | u8g2.drawGlyph(111, 16, 64); //显示电池 1270 | u8g2.setFont(u8g2_font_Born2bSportyV2_tr); 1271 | u8g2.setCursor(35, 32); 1272 | u8g2.print("welcome"); 1273 | u8g2.setCursor(0, 60); 1274 | u8g2.print("System in Initialization"); 1275 | u8g2.sendBuffer(); 1276 | delay(1500); 1277 | } 1278 | 1279 | /* 1280 | * @brief: 天气icon 1281 | * @param: icon : 对应的icon的类型 1282 | * @retval:none 1283 | */ 1284 | void Weather(String icon) 1285 | { 1286 | //xue、lei、shachen、wu、bingbao、yun、yu、yin、qing 1287 | u8g2.setFont(u8g2_font_open_iconic_weather_4x_t); 1288 | if (icon.equals("qing")) 1289 | { 1290 | u8g2.drawGlyph(8, 55, 69); //显示晴天 1291 | } 1292 | else if (icon.equals("yu") || icon.equals("lei")) 1293 | { 1294 | u8g2.drawGlyph(8, 55, 67); //显示雨天 1295 | } 1296 | else if (icon.equals("yun")) 1297 | { 1298 | u8g2.drawGlyph(8, 55, 65); //显示多云 1299 | } 1300 | else 1301 | { 1302 | u8g2.drawGlyph(8, 55, 64); //显示其它 1303 | } 1304 | } 1305 | 1306 | /* 1307 | * @brief: OLED文字显示 1308 | * @param: text String 1309 | * @param: x 横坐标 像素 1310 | * @param: y 纵坐标 像素 1311 | * @retval:none 1312 | */ 1313 | void OLEDprint(int x, int y, String text) 1314 | { 1315 | //u8g2.clearBuffer(); 1316 | u8g2.setFont(u8g2_font_open_iconic_embedded_2x_t); 1317 | u8g2.drawGlyph(111, 16, 64); //显示电池 1318 | u8g2.setFont(u8g2_font_ncenB08_te); 1319 | u8g2.setCursor(x, y); 1320 | u8g2.print(text); 1321 | u8g2.sendBuffer(); 1322 | } 1323 | 1324 | /*======================================== Sensor =========================================*/ 1325 | /* 1326 | * @brief: 传感器初始化 1327 | * @param:none 1328 | * @retval:none 1329 | */ 1330 | void SensorInit() 1331 | { 1332 | 1333 | int count = 0; 1334 | /*bme280初始化*/ 1335 | while (!bme.begin()) 1336 | { 1337 | Serial.println("Can't find it "); 1338 | if (count == 3) 1339 | { 1340 | ESP.restart(); 1341 | } 1342 | count++; 1343 | delay(500); 1344 | } 1345 | } 1346 | 1347 | /*======================================== Blinker =========================================*/ 1348 | // void miotPowerState(const String &state) 1349 | // { 1350 | // BLINKER_LOG("need set power state: ", state); 1351 | 1352 | // if (state == BLINKER_CMD_ON) 1353 | // { 1354 | // digitalWrite(LED, HIGH); 1355 | 1356 | // BlinkerMIOT.powerState("on"); 1357 | // BlinkerMIOT.print(); 1358 | // } 1359 | // else if (state == BLINKER_CMD_OFF) 1360 | // { 1361 | // digitalWrite(LED, LOW); 1362 | 1363 | // BlinkerMIOT.powerState("off"); 1364 | // BlinkerMIOT.print(); 1365 | // } 1366 | // } 1367 | 1368 | /* 1369 | * @brief:Blinker 初始化 1370 | * @param:none 1371 | * @retval:none 1372 | */ 1373 | void BlinkerInit() 1374 | { 1375 | BLINKER_DEBUG.stream(Serial); //设置Blinker串口 1376 | Blinker.attachData(dataRead); //绑定回调函数 1377 | BlinkerMIOT.attachQuery(miotQuery); //小米小爱查询回调绑定 1378 | // BlinkerMIOT.attachPowerState(miotPowerState); 1379 | } 1380 | 1381 | /* 1382 | * @brief: 小米小爱查询 1383 | * @param: queryCode小爱查询状态码,Blinker已实现 1384 | * @retval:none 1385 | */ 1386 | void miotQuery(int32_t queryCode) 1387 | { 1388 | BLINKER_LOG("MIOT Query codes: ", queryCode); 1389 | Serial.printf("MIOT Query codes: %d", queryCode); 1390 | switch (queryCode) 1391 | { 1392 | case BLINKER_CMD_QUERY_ALL_NUMBER: 1393 | BLINKER_LOG("MIOT Query All"); 1394 | BlinkerMIOT.temp((int)temperature_bme); //小米小爱温度 1395 | BlinkerMIOT.humi((int)humidity_bme); //小米小爱湿度 1396 | BlinkerMIOT.pm25(air_pm25); //小米小爱PM2.5浓度 1397 | BlinkerMIOT.co2(analogRead(34)); 1398 | BlinkerMIOT.print(); 1399 | break; 1400 | default: 1401 | BlinkerMIOT.temp(20); 1402 | BlinkerMIOT.humi(20); 1403 | BlinkerMIOT.pm25(20); 1404 | BlinkerMIOT.co2(20); 1405 | BlinkerMIOT.print(); 1406 | break; 1407 | // case BLINKER_CMD_QUERY_ALL_NUMBER: 1408 | // // BLINKER_LOG("MIOT Query PM25"); 1409 | // // BlinkerMIOT.pm25((int)air_pm25); //小爱获取PM2.5浓度 1410 | // BlinkerMIOT.humi(bme.readHumidity()); //小爱获取温度 1411 | // BlinkerMIOT.temp(bme.readTemperature()); //小爱获取温度 1412 | // BlinkerMIOT.print(); 1413 | // break; 1414 | // // case BLINKER_CMD_QUERY_HUMI_NUMBER: 1415 | // // BLINKER_LOG("MIOT Query HUMI"); 1416 | // // BlinkerMIOT.humi(bme.readHumidity()); //小爱获取温度 1417 | // // BlinkerMIOT.print(); 1418 | // // break; 1419 | // // case BLINKER_CMD_QUERY_TEMP_NUMBER: 1420 | // // BLINKER_LOG("MIOT Query TEMP"); 1421 | 1422 | // // BlinkerMIOT.print(); 1423 | // // break; 1424 | // // case BLINKER_CMD_QUERY_TIME_NUMBER: 1425 | // // BLINKER_LOG("MIOT Query Time"); 1426 | 1427 | // // BlinkerMIOT.print(); 1428 | // // break; 1429 | // default: 1430 | // Serial.println("MiIoT error!!!"); 1431 | // BlinkerMIOT.print(); 1432 | // break; 1433 | } 1434 | } 1435 | 1436 | /* 1437 | * @brief: Blinker控制回调函数 1438 | * @param: data 发送事件,Blinker已实现 1439 | * @retval:none 1440 | */ 1441 | void dataRead(const String &data) 1442 | { 1443 | BLINKER_LOG("Blinker readString: ", data); 1444 | 1445 | Blinker.vibrate(); 1446 | 1447 | uint32_t BlinkerTime = millis(); 1448 | 1449 | Blinker.print("millis", BlinkerTime); 1450 | } --------------------------------------------------------------------------------