2个小时0基础,手搓一个智能wifi温湿度计

复制代码
ESP8266 + SHT30
↓
连接 WiFi
↓
浏览器查看温湿度
↓
网页 OTA 更新固件
↓
后续再加信息推送


后续添加对接天猫精灵的功能和空调联动功能

南方天气阴冷潮湿,墙体发霉

上代码

复制代码
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#include <ESP8266mDNS.h>
#include <Wire.h>

#define SHT30_ADDR 0x44

const char* ssid = "home-wifi";
const char* password = "123456";

// 网页 OTA 登录账号密码
const char* otaUser = "admin";
const char* otaPass = "admin123456";

ESP8266WebServer server(80);
ESP8266HTTPUpdateServer httpUpdater;

float temperature = 0.0;
float humidity = 0.0;
bool sht30Ok = false;

uint8_t crc8(const uint8_t *data, int len) {
  uint8_t crc = 0xFF;
  for (int i = 0; i < len; i++) {
    crc ^= data[i];
    for (int j = 0; j < 8; j++) {
      if (crc & 0x80) {
        crc = (crc << 1) ^ 0x31;
      } else {
        crc <<= 1;
      }
    }
  }
  return crc;
}

bool readSHT30() {
  Wire.beginTransmission(SHT30_ADDR);
  Wire.write(0x2C);
  Wire.write(0x06);
  uint8_t error = Wire.endTransmission();

  if (error != 0) {
    return false;
  }

  delay(20);

  Wire.requestFrom(SHT30_ADDR, 6);

  if (Wire.available() != 6) {
    return false;
  }

  uint8_t data[6];
  for (int i = 0; i < 6; i++) {
    data[i] = Wire.read();
  }

  if (crc8(data, 2) != data[2] || crc8(data + 3, 2) != data[5]) {
    return false;
  }

  uint16_t rawTemp = (data[0] << 8) | data[1];
  uint16_t rawHum  = (data[3] << 8) | data[4];

  temperature = -45.0 + 175.0 * rawTemp / 65535.0;
  humidity = 100.0 * rawHum / 65535.0;

  return true;
}

void handleRoot() {
  readSHT30();

  String html = "";
  html += "<!DOCTYPE html><html><head>";
  html += "<meta charset='UTF-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
  html += "<meta http-equiv='refresh' content='5'>";
  html += "<title>ESP8266 SHT30</title>";
  html += "<style>";
  html += "body{font-family:Arial;background:#f4f4f4;text-align:center;padding:30px;}";
  html += ".card{background:white;padding:25px;border-radius:16px;display:inline-block;box-shadow:0 4px 16px #ccc;min-width:260px;}";
  html += ".value{font-size:36px;font-weight:bold;margin:15px;}";
  html += "a{display:block;margin-top:20px;color:#0366d6;text-decoration:none;}";
  html += "</style>";
  html += "</head><body>";
  html += "<div class='card'>";
  html += "<h2>ESP8266 SHT30</h2>";

  if (sht30Ok) {
    html += "<div>温度</div>";
    html += "<div class='value'>" + String(temperature, 2) + " ℃</div>";
    html += "<div>湿度</div>";
    html += "<div class='value'>" + String(humidity, 2) + " %RH</div>";
  } else {
    html += "<h3>SHT30 读取失败</h3>";
  }

  html += "<p>IP: " + WiFi.localIP().toString() + "</p>";
  html += "<p>每 5 秒自动刷新</p>";
  html += "<a href='/json'>查看 JSON 数据</a>";
  html += "<a href='/update'>网页 OTA 更新</a>";
  html += "</div>";
  html += "</body></html>";

  server.send(200, "text/html; charset=utf-8", html);
}

void handleJson() {
  readSHT30();

  String json = "{";
  json += "\"ok\":";
  json += sht30Ok ? "true" : "false";
  json += ",";
  json += "\"temperature\":";
  json += String(temperature, 2);
  json += ",";
  json += "\"humidity\":";
  json += String(humidity, 2);
  json += ",";
  json += "\"ip\":\"";
  json += WiFi.localIP().toString();
  json += "\"";
  json += "}";

  server.send(200, "application/json; charset=utf-8", json);
}

void setup() {
  Serial.begin(115200);
  delay(1000);

  Wire.begin(4, 5); // SDA=D2/GPIO4, SCL=D1/GPIO5

  Serial.println();
  Serial.println("Connecting WiFi...");

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  int retry = 0;
  while (WiFi.status() != WL_CONNECTED && retry < 60) {
    delay(500);
    Serial.print(".");
    retry++;
  }

  Serial.println();

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("WiFi connect failed");
  }

  if (MDNS.begin("sht30")) {
    Serial.println("mDNS started: http://sht30.local");
  }

  server.on("/", handleRoot);
  server.on("/json", handleJson);

  // 网页 OTA 地址:http://设备IP/update
  httpUpdater.setup(&server, "/update", otaUser, otaPass);

  server.begin();
  Serial.println("HTTP server started");

  Serial.println("Open:");
  Serial.print("http://");
  Serial.println(WiFi.localIP());
  Serial.println("or:");
  Serial.println("http://sht30.local");
  Serial.println("OTA:");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.println("/update");
}

void loop() {
  sht30Ok = readSHT30();

  server.handleClient();
  MDNS.update();

  static unsigned long lastPrint = 0;
  if (millis() - lastPrint > 3000) {
    lastPrint = millis();

    if (sht30Ok) {
      Serial.print("Temperature: ");
      Serial.print(temperature, 2);
      Serial.println(" °C");

      Serial.print("Humidity: ");
      Serial.print(humidity, 2);
      Serial.println(" %RH");

      Serial.print("IP: ");
      Serial.println(WiFi.localIP());

      Serial.println("------------------");
    } else {
      Serial.println("SHT30 read failed");
    }
  }
}

ota升级

www.jxzhiqu.cn

相关推荐
嵌入式ZYXC7 小时前
第4章:MCU最小系统设计——从一颗光杆芯片到它能跑起来
stm32·单片机·嵌入式硬件·物联网
2023自学中7 小时前
imx6ull 开发板,手机,MQTT 物联网通信实验。
linux·服务器·物联网·嵌入式·开发板·应用编程
KaMeidebaby10 小时前
卡梅德生物技术快报|生信实操:ChIP 染色质免疫共沉淀技术流程、短板与替代方案详解
前端·人工智能·物联网·百度·新浪微博
砍材农夫11 小时前
物联网实战:Spring Boot + Netty 搭建 MQTT | MQTT 设备模拟器
java·spring boot·后端·物联网·struts·spring·netty
TDengine (老段)12 小时前
TDengine Compaction 合并策略 — STT 整理、文件合并与后台调度
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
007张三丰12 小时前
AIoT与嵌入式系统深度解析:2026软考案例核心考点全攻略
物联网·mqtt·kafka·freertos·时序数据库·tdengine·aiot
JNX_SEMI1 天前
EG2226 全桥驱动芯片技术解析:600V/1A 耐压、SSOP16 封装,助力逆变器与无刷电机驱动设计
单片机·嵌入式硬件·物联网
Geometry Fu1 天前
《物联网安全》第3.2章 无线传感器网络安全
物联网·安全·物联网安全·无线传感器网络·wsn
TDengine (老段)1 天前
TDengine Commit 与 Flush 机制 — 从内存到磁盘的数据落盘全流程
大数据·数据库·物联网·架构·时序数据库·iot·tdengine
Yeats_Liao1 天前
好复杂的 IoT 世界:工业数据采集技术栈全景解析
java·物联网·struts