偶然在家清理物品时发现esp d1 mini,由于经常一年只回家一两次,所以将家中的esp d1 mini进行改造,接入SH1106 和dht22模块,通过mqtt通信记录温湿度。并增加ota在线升级,方便不在家的时候通过跳板机升级固件。
配置好arduino环境开发板地址
https://arduino.esp8266.com/stable/package_esp8266com_index.json
D1 mini芯片 选择板子LOLIN(WE) D1 R2 如果不正确选择板子可能会遇到编译时无法识别引脚的问题。
下面开始先贴代码
#include <dummy.h>
#include <SimpleDHT.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "SSD1306Wire.h"
#include "SH1106.h"
#include "OLEDDisplayUi.h"
#include "OTA.h"
const char* ssid = "xx-xx";
const char* password = "xxxxxx";
const char* mqtt_server = "xxxxx";
const char* mqtt_username = "xx-xxx";
const char* mqtt_password = "xxxx";
const int mqtt_port = 1883;
const char* mqtt_topic = "dht22";
unsigned long last_send = 0;
const int I2C_DISPLAY_ADDRESS = 0x3C;
const int SDA_PIN = D2;
const int SDC_PIN = D1;
#define DHTPIN D5
SimpleDHT22 dht22(DHTPIN);
SH1106 display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);
OLEDDisplayUi ui(&display);
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
Serial.begin(115200);
Serial.println("init ...");
display.init();
display.setFont(ArialMT_Plain_10);
display.flipScreenVertically();
drawSplash(&display, "HELLO WORLD");
setupWifi();
startOTA();
client.setServer(mqtt_server, mqtt_port);
}
void drawSplash(OLEDDisplay *display, String label){
display->clear();
display->setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
display->setFont(ArialMT_Plain_10);
display->drawString(64, 32, label);
display->display();
}
void setupWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
WiFi.setAutoReconnect(true);
WiFi.persistent(true);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop()
{
if ( !client.connected() ) {
reconnect();
}
if ( millis() - last_send > 5000 ) {
getData();
last_send = millis();
}
client.loop();
otaHandler();
}
void reconnect() {
while (!client.connected()) {
Serial.println("MQTT re connection");
if (client.connect(mqtt_topic, mqtt_username, mqtt_password)) {
Serial.println("MQTT connected");
} else {
Serial.println("MQTT connect fail");
delay(5000);
}
}
}
void getData() {
float temperature = 0;
float humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht22.read2(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("Read DHT22 failed, err="); Serial.print(SimpleDHTErrCode(err));
Serial.print(","); Serial.println(SimpleDHTErrDuration(err)); delay(2000);
return;
}
char data[20];
sprintf(data, "%c&%.2f&%.2f&cube-01", 0x01,(float)temperature, (float)humidity);
client.publish(mqtt_topic,data);
}
OTA.h
#include <ESP8266LLMNR.h>
#include <ESP8266HTTPUpdateServer.h>
#include <ESP8266WebServer.h>
ADC_MODE(ADC_VCC);
const char *host = "LT";
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;
void handleRoot() {
IPAddress local_ip;
String message = "<!DOCTYPE HTML>";
message += "<html><head><meta charset=\"UTF-8\"><title>OTA</title>";
message += "</head><body><div align=\"center\">";
message += "<div id=\"container\" style=\"width:800px\">";
message += "<div id=\"header\" style=\"background-color:#FFB3B3;\">";
message += "<h2 style=\"margin-bottom:0;\">OTA UPDATE</h2></div>";
message += "<div id=\"hoststatus\" style=\"background-color:#FFE5E5;height:160px;width:800px;float:left;\"><form><br>";
message += "<br><br><div id=\"SSID\">SSID:";
message += WiFi.SSID();
message += "</div><div id=\"IP_Address\">IP 地址:";
local_ip = WiFi.localIP();
for (uint8_t i = 0; i < 4; i++) {
message += String(local_ip[i]) + ".";
}
message.remove(message.length()-1, 1);
message += "<br><br><a href=\"/update\">点击这里</a> OTA升级";
message += "</div></div></body></html>";
httpServer.send(200, "text/html", message);
}
void handleNotFound(){
String message = "File Not Found\n\n";
message += "URI: ";
message += httpServer.uri();
message += "\nMethod: ";
message += (httpServer.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += httpServer.args();
message += "\n";
for (uint8_t i=0; i<httpServer.args(); i++){
message += " " + httpServer.argName(i) + ": " + httpServer.arg(i) + "\n";
}
httpServer.send(404, "text/plain", message);
}
void startOTA(){
LLMNR.begin(host);
httpServer.on("/", handleRoot);
httpServer.onNotFound(handleNotFound);
httpUpdater.setup(&httpServer);
httpServer.begin();
Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host);
Serial.println("Wait for WiFi connection.");
}
void otaHandler(){
httpServer.handleClient();
}
MQTT服务端部分我使用的是EMQX,并通过java服务监听topic
老样子,贴代码
先是MQTT连接部分
@Component
public class LocalMQTT {
final static String SUB_TOPIC = "xxx/#";
final static String PUB_TOPIC = "xxxx/1";
final static String CONTENT = "Hello World";
final static int QOS = 0;
final static String BROKER = "tcp://xxxx:1883";
final static String CLIENT_ID = "emqx_java";
final static MemoryPersistence PERSISTENCE = new MemoryPersistence();
public static MqttClient mqttClient = null;
public static ConcurrentLinkedQueue<String> message = new ConcurrentLinkedQueue<>();
public static MqttClient getMqttClient() {
MqttClient client = null;
try {
client = new MqttClient(BROKER, CLIENT_ID, PERSISTENCE);
// MQTT 连接选项
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName("xxx-xxxx");
connOpts.setPassword("xxxx".toCharArray());
// 保留会话
connOpts.setCleanSession(true);
// 设置回调
client.setCallback(new OnMessageCallback());
// 建立连接
System.out.println("Connecting to broker: " + BROKER);
client.connect(connOpts);
System.out.println("Connected");
System.out.println("Publishing message: " + CONTENT);
// 订阅
client.subscribe(SUB_TOPIC, QOS);
} catch (MqttException me) {
System.out.println("reason " + me.getReasonCode());
System.out.println("msg " + me.getMessage());
System.out.println("loc " + me.getLocalizedMessage());
System.out.println("cause " + me.getCause());
System.out.println("excep " + me);
me.printStackTrace();
}
return client;
}
@PostConstruct
public void init() {
LocalMQTT.mqttClient = getMqttClient();
}
MQTT回调监听部分
public class OnMessageCallback implements MqttCallback {
@Override
public void connectionLost(Throwable cause) {
if (LocalMQTT.mqttClient == null) {
LocalMQTT.mqttClient = LocalMQTT.getMqttClient();
System.out.println("连接断开,重连");
} else {
System.out.println("连接断开??");
}
}
@Override
public void messageArrived(String topic, MqttMessage message) {
// subscribe后得到的消息会执行到这里面
String msg = new String(message.getPayload());
LocalMQTT.message.add(msg);
System.out.println("接收消息主题:" + topic);
System.out.println("接收消息Qos:" + message.getQos());
System.out.println("接收消息内容:" + msg);
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println("deliveryComplete---------" + token.isComplete());
}
}
最后是数据处理部分
@Component
public class ScheduledTasks {
@Resource
TemperatureHumidityService temperatureHumidityService;
@Scheduled(cron = "0/3 * * * * ? ")
public void cronTask() {
System.out.println("Cron task - " + System.currentTimeMillis() / 1000);
if (!LocalMQTT.message.isEmpty()) {
List<String[]> list = new ArrayList<>(LocalMQTT.message.size());
for (int i = 0; i < LocalMQTT.message.size(); i++) {
String msg = LocalMQTT.message.poll();
String[] data = msg.split("&");
if (data[0].charAt(0) == 0x01) {
list.add(data);
}
}
if (!list.isEmpty()) {
saveTemperatureHumidity(list);
}
}
}
private void saveTemperatureHumidity(List<String[]> data) {
List<TemperatureHumidity> temperatureHumidityList = new ArrayList<>(data.size());
data.forEach(v -> temperatureHumidityList.add(new TemperatureHumidity(null, new Date(), new BigDecimal(v[1]), new BigDecimal(v[2]), v[3])));
temperatureHumidityService.saveBatch(temperatureHumidityList);
}
}