偶然在家清理物品时发现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);
    }
}