在2018年折腾过一次用米家温湿度连接ESP32上用OLED显示,OLED显示是已经成功了.可是当时打算让EPS在读取到蓝牙温度计数值后上传到blynk,可是编译后提示空间不足(即使不要OLED驱动只接入blynk也一样)。由于我不是专业开发人员,也没时间去找解决方法。同时,觉得这功能大把东西可以取代,搞出来觉得没啥用,所以代码一直仍在硬盘里直到现在才记得.这里顺便发出来,大家觉得有用的话拿去研究参考,看能不能解决空间问题,运行效果如下:

  这个项目灵感主要来自于这位作者,https://github.com/turlvo/KuKuMi,有兴趣可以看看。

事前准备

  1. 软件和环境

    • PlatformIO 或者Arduino IDE配置好ESP32 Arduino架构板库
    • Adafruit SSD1306 OLED 库
    • Adafruit GFX 库
        以上库都可以在IDE内搜索到
  2. 硬件准备 项目名称 数量 单位 备注
    ESP32 1 这里用doit esp32 devkit v1
    0.96'OLED液晶模块 1 SSD1306主控,建议I2C版本,我这里用SPI接口版本
    小米米家蓝牙温湿度计 1 我这里使用的是旧版圆形那个版本,由于已经是3年前,现在新款的版本不知道行不行
    杜邦线 若干
    面包板 1

3.注意事项
在开始动手前,请你把周边所有蓝牙(如手机蓝牙等)设备关掉,以免影响ESP32的实验结果。

硬件接线

SPI版本

ESP32 15 2 4 5 GND 3.3V/5V GND
OLED CLK(SCK) MOSI(SCK) RESET(RES) DC CS VCC GND

I2C版本

  (省略,请自行看Adafruit SSD1306 OLED 库中的示例)

Arduino代码

  这里是SPI OLED的版本:

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_system.h"
#include <sstream>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

#define SCAN_TIME  10 //扫描的间隔10秒
#define SCREEN_WIDTH 128 
#define SCREEN_HEIGHT 64 

boolean METRIC = true; //不需要公制单位的话设为:false 

BLEScan *pBLEScan;

void IRAM_ATTR resetModule() {
  ets_printf("reboot\n");
  esp_restart();
}

#define OLED_CLK    15
#define OLED_MOSI   2
#define OLED_RESET  4
#define OLED_DC     5
#define OLED_CS     255

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

float  current_humidity = -100;
float  previous_humidity = -100;
float current_temperature = -100;
float previous_temperature = -100;

class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice)
    {
      if (advertisedDevice.haveName() && advertisedDevice.haveServiceData() && !advertisedDevice.getName().compare("MJ_HT_V1")) {
        std::string strServiceData = advertisedDevice.getServiceData();
        uint8_t cServiceData[100];
        char charServiceData[100];

        strServiceData.copy((char *)cServiceData, strServiceData.length(), 0);

        Serial.printf("\n\nAdvertised Device: %s\n", advertisedDevice.toString().c_str());

        for (int i = 0; i < strServiceData.length(); i++) {
          sprintf(&charServiceData[i * 2], "%02x", cServiceData[i]);
        }

        std::stringstream ss;
        ss << "fe95" << charServiceData;

        Serial.print("Payload:");
        Serial.println(ss.str().c_str());

        char eventLog[256];
        unsigned long value, value2;
        char charValue[5] = {0,};
        switch (cServiceData[11]) {
          case 0x04:
            sprintf(charValue, "%02X%02X", cServiceData[15], cServiceData[14]);
            value = strtol(charValue, 0, 16);
            if (METRIC)
            {
              current_temperature = (float)value / 10;
            } else
            {
              current_temperature = CelciusToFahrenheit((float)value / 10);
            }
            break;
          case 0x06:
            sprintf(charValue, "%02X%02X", cServiceData[15], cServiceData[14]);
            value = strtol(charValue, 0, 16);
            current_humidity = (float)value / 10;
            Serial.printf("HUMIDITY_EVENT:");
            Serial.printf(charValue, value);
            Serial.println();
            break;
          case 0x0A:
            sprintf(charValue, "%02X", cServiceData[14]);
            value = strtol(charValue, 0, 16);
            Serial.printf("BATTERY_EVENT:");
            Serial.printf(charValue, value);
            Serial.println();
            break;
          case 0x0D:
            sprintf(charValue, "%02X%02X", cServiceData[15], cServiceData[14]);
            value = strtol(charValue, 0, 16);
            if (METRIC)
            {
              current_temperature = (float)value / 10;
            } else
            {
              current_temperature = CelciusToFahrenheit((float)value / 10);
            }
            Serial.printf("TEMPERATURE_EVENT:");
            Serial.printf(charValue, value);
            Serial.println();
            sprintf(charValue, "%02X%02X", cServiceData[17], cServiceData[16]);
            value2 = strtol(charValue, 0, 16);
            current_humidity = (float)value2 / 10;
            Serial.printf("HUMIDITY_EVENT:" );
            Serial.printf(charValue, value2);
            Serial.println();
            break;
        }
      }
    }
};

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC);
  //清楚OLED屏幕缓存
  display.clearDisplay();
  display.display();

  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); 

  Serial.begin(115200);
  Serial.println("ESP32 XIAOMI DISPLAY");

  initBluetooth();
}

void loop() {
  char printLog[256];
  Serial.printf("Start BLE scan for %d seconds...\n", SCAN_TIME);
  BLEScanResults foundDevices = pBLEScan->start(SCAN_TIME);
  int count = foundDevices.getCount();
  printf("Found device count : %d\n", count);
  delay(100);

  displayTemperature();
}

void initBluetooth()
{
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
  pBLEScan->setInterval(0x50);
  pBLEScan->setWindow(0x30);
}

void displayTemperature() {
  if (current_temperature != previous_temperature) {
    previous_temperature = current_temperature;
    previous_humidity = current_humidity;
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    display.print("Tem:");
    display.print(convertFloatToString(current_temperature));
    if (METRIC) {
      display.setCursor(115, 0);
      display.print("C");
    } else {
      display.setCursor(115, 0);
      display.print("F");
    }
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(0, 40);
    display.print("Hum:");
    display.print(current_humidity, 1);
    display.print(" %");
    display.display();
  }
}

String convertFloatToString(float f)
{
  String s = String(f, 1);
  return s;
}

//转换成华氏的自定义函数
float CelciusToFahrenheit(float Celsius)
{
  float Fahrenheit = 0;
  Fahrenheit = Celsius * 9 / 5 + 32;
  return Fahrenheit;
}

一沙一世界,一花一天堂。君掌盛无边,刹那成永恒。