Hello everyone, I'm Yassin. Under the trend of the intelligent connection of all things, I have designed and implemented a smart weather warning terminal system based on ESP32-P4. The system consists of two main parts: a meteorological data acquisition board and a display terminal. It can collect various environmental data in real time, including temperature and humidity, air pressure, light intensity, ultraviolet radiation, carbon dioxide concentration, wind speed and direction, as well as lightning warning information. All data is wirelessly transmitted to the display terminal via LoRa for visual presentation. Adopting a modular design concept, the system completes the whole development process from scheme design to physical realization, covering sensor selection, hardware circuit design, communication protocol formulation and software programming. It is a typical application of Internet of Things technology in the field of environmental monitoring.
This system is suitable for various scenarios requiring real-time meteorological monitoring and early warning, with broad application value:
The acquisition board is mainly responsible for collecting meteorological data. The main controller uses the STM32F103 chip, and the display panel is built with the M5STACK TAB5 development board. All key components are supported and supplied by DigiKey. The specific hardware selection is as follows:
-
Main Control Chip of Acquisition Board
STM32F103: A high-performance 32-bit microcontroller launched by STMicroelectronics based on the ARM Cortex-M3 core. It is widely used in embedded introductory learning and common embedded products, with abundant resources, massive tutorials and easy development.
-
Sensor Modules
Temperature and Humidity Sensor: The AHT20 is a high-precision, fully calibrated I2C digital output composite temperature and humidity sensor. It adopts a new-generation dedicated ASIC chip, improved MEMS capacitive humidity sensing element and integrated on-chip temperature sensing element. With reliable performance, plug-and-play feature and excellent cost performance, it is a mainstream option for temperature and humidity detection in embedded projects and consumer electronics.
Wind Speed and Direction Sensor: A sensor with 485 communication interface is selected. It adopts RS485 communication and supports the Modbus protocol, featuring high measurement accuracy and excellent stability. The wind speed measuring range is 0-60m/s, and the wind direction measuring range is 0-360°. It requires 12V power supply, which is converted by a boost module.
LoRa Module: A LoRa module equipped with the SX1278 chip is selected. Adopting LoRa modulation technology, it features long transmission distance (up to several kilometers), low power consumption and strong anti-interference ability, which is highly suitable for meteorological monitoring scenarios requiring long-distance and low-power data transmission.
- Display Board Hardware
The Tab5 is a highly expandable and portable intelligent IoT terminal development device for developers, integrating a dual-chip architecture and abundant hardware resources. Its main controller adopts the ESP32‑P4 SoC based on the RISC‑V architecture, equipped with 16MB Flash and 32MB PSRAM. The wireless module adopts ESP32-C6-MINI-1U with Wi-Fi 6 support. Its antenna system can be freely switched between the built-in 3D antenna and the external MMCX antenna interface, adapting to various deployment scenarios flexibly to guarantee stable data throughput and low-latency control.
Power Supply Unit: The AMS1117-3.3 voltage regulator chip is used to convert external 5V voltage to 3.3V, providing stable power for all rear-end sensors and display devices.
Schematic Design of Acquisition Board:
(The file exceeds 10MB and cannot be uploaded. I have no idea why it cannot be compressed further.)
The software part is developed based on the Arduino framework environment, adopting the modular programming concept to improve code readability and maintainability. The specific implementation is as follows:
- Development Environment Setup
The acquisition board is developed using STM32Cubemx + Keil5, the common tools for STM32.
- Firmware Design of Acquisition Board
Sensor Drivers: Independent driver functions are developed for each sensor, including initialization, data reading, and data conversion, achieving a modular design for easy maintenance and expansion.
//每0.5S获取传感器数据
if (CompareTime(&TimeSensor_Get))
{
SetTime(&TimeSensor_Get, 500); // 每500ms进来一次
AHT20_Get_Value(&Humiture);
bmp280_read_float(&bmp280_dev, &temperature, &pressure, &humidity);
Alt=data_conversion(pressure,temperature);
pressurehpa=pressure*2/100.0;
BH1750_ReadData(g_ucaDataBuff,2);/*获取照度数据*/
ftmp = (g_ucaDataBuff[0]<<8 | g_ucaDataBuff[1]) / 1.2f + 0.5f;/*转换照度数据*/
g_usLux = (uint16_t)ftmp;
ult_value = Get_ADC_Value();
UV_VALUE = Get_Ultraviolet_Intensity(ult_value);
//SGP30读取
if (sgp30_read(&CO2, &TVOC) == 0)
{
sgp30_data.CO2 = CO2;
sgp30_data.TVOC = TVOC;
// usartPrintf(huart1, "CO2: %d ppm, TVOC: %d ppb\r\n", CO2, TVOC);
}
else
{
// usartPrintf(huart1, "SGP30 read failed\r\n");
}
GET_Wind_Speed_Data();
GET_Wind_Direction_Data();
}
if (CompareTime(&TimeWiFi_Send))
{
SetTime(&TimeWiFi_Send, 500); // 每3000ms进来一次
static char jsonString[300]; // 假设 JSON 字符串不超过 512 字节
snprintf(jsonString, sizeof(jsonString),
"{\"T\":%.1f,\"H\":%.1f,\"P\":%.1f,\"L\":%u,"
"\"UV\":%d,\"TVOC\":%d,\"Ws\":%.1f,\"Wl\":%.1f,"
"\"Fx\":\"%s\",\"Wa\":%.1f,\"Ld\":%d}",
Humiture.Temp,
Humiture.RH,
pressurehpa,
g_usLux,
UV_VALUE,
TVOC,
windSpeed,
windLevel,
fengxiang,
Wind_Angle,
lightning_distance
);
usartPrintf(huart1, "%s\r\n", jsonString);
}
- Firmware Design of Display Board
LoRa Reception: The data frames sent by the acquisition board are received through the LoRa module. JSON parsing is adopted to extract sensor data, and unit conversion and data processing are performed.
void parseSerialJSON() {
while (mySerial.available()) {
char c = mySerial.read();
if (c == '\n') {
StaticJsonDocument<512> doc;
DeserializationError err = deserializeJson(doc, serialBuffer);
if (!err) {
// ===== 温湿度 & 气压 =====
if (doc.containsKey("T"))
sensorData.temperature = doc["T"].as<float>();
if (doc.containsKey("H"))
sensorData.humidity = doc["H"].as<float>();
if (doc.containsKey("P"))
sensorData.pressure = doc["P"].as<float>();
// ===== 光照 =====
if (doc.containsKey("L"))
sensorData.lightLux = doc["L"].as<uint32_t>();
// ===== UV =====
if (doc.containsKey("UV"))
sensorData.uv = doc["UV"].as<int>();
// ===== TVOC =====
if (doc.containsKey("TVOC"))
sensorData.tvoc = doc["TVOC"].as<int>();
// ===== 风速 & 风力 =====
if (doc.containsKey("Ws"))
sensorData.windSpeed = doc["Ws"].as<float>();
if (doc.containsKey("Wl"))
sensorData.windLevel = doc["Wl"].as<float>();
// ===== 风向字符串 =====
if (doc.containsKey("Fx")) {
const char* fx = doc["Fx"];
strncpy(sensorData.windDirStr, fx,
sizeof(sensorData.windDirStr) - 1);
sensorData.windDirStr[sizeof(sensorData.windDirStr) - 1] = '\0';
}
// ===== 风向角 =====
if (doc.containsKey("Wa"))
sensorData.windAngle = doc["Wa"].as<float>();
// ===== 雷电距离=====
if (doc.containsKey("Ld")) {
sensorData.lightningDistance = doc["Ld"].as<float>();
sensorData.lightning = (sensorData.lightningDistance > 0);
}
drawUI();
}
serialBuffer = "";
}
else {
if (serialBuffer.length() < 512)
serialBuffer += c;
else
serialBuffer = "";
}
}
}
void drawUI() {
canvas.fillScreen(TFT_WHITE);
uint16_t greenColor = display.color565(120, 180, 70);
// ===== 顶部标题条 =====
canvas.fillRoundRect(0, 0, screenWidth, 60, 4, greenColor);
canvas.setTextDatum(TL_DATUM);
canvas.setTextSize(3);
canvas.setTextColor(TFT_WHITE);
canvas.drawString("Weather IOT Platform", 20, 20);
char buf[16];
int row = 0;
// ================= 第 1 行 =================
// 温度
snprintf(buf, sizeof(buf), "%.1f", sensorData.temperature);
drawCard(marginSide + 0 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "TEMP", buf, "C");
// 湿度
snprintf(buf, sizeof(buf), "%.0f", sensorData.humidity);
drawCard(marginSide + 1 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "HUMID", buf, "%");
// 气压
snprintf(buf, sizeof(buf), "%.0f", sensorData.pressure);
drawCard(marginSide + 2 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "PRESS", buf, "hPa");
// 光照
snprintf(buf, sizeof(buf), "%u", sensorData.lightLux);
drawCard(marginSide + 3 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "LIGHT", buf, "Lux");
// ================= 第 2 行 =================
row = 1;
// UV
snprintf(buf, sizeof(buf), "%d", sensorData.uv);
drawCard(marginSide + 0 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "UV", buf, "UV");
// TVOC
snprintf(buf, sizeof(buf), "%d", sensorData.tvoc);
drawCard(marginSide + 1 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "CO2", buf, "ppb");
// 雷电距离
snprintf(buf, sizeof(buf), "%.1f", sensorData.lightningDistance);
drawCard(marginSide + 2 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "LIGHT DIST", buf, "km");
// 雷电状态
if (sensorData.lightning) {
strcpy(buf, "ALERT");
} else {
strcpy(buf, "NORMAL");
}
drawCard(marginSide + 3 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "LIGHT STATE", buf, "");
// ================= 第 3 行 =================
row = 2;
// 风速
snprintf(buf, sizeof(buf), "%.1f", sensorData.windSpeed);
drawCard(marginSide + 0 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "WIND SPD", buf, "m/s");
// 风等级
snprintf(buf, sizeof(buf), "%.1f", sensorData.windLevel);
drawCard(marginSide + 1 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "WIND LV", buf, "");
// 风向
snprintf(buf, sizeof(buf), "%s", sensorData.windDirStr);
drawCard(marginSide + 2 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "WIND DIR", buf, "");
// 风向角
snprintf(buf, sizeof(buf), "%.1f", sensorData.windAngle);
drawCard(marginSide + 3 * (cardWidth + spacingX),
marginTop + row * (cardHeight + spacingY),
cardWidth, cardHeight, "WIND ANG", buf, "o");
canvas.pushSprite(0, 0);
}
In the upgraded version, all external modules will be replaced with on-board components to reduce the overall size. Meanwhile, lithium battery management and solar power supply modules will be added to realize independent data collection and self-sustaining power management.
Yassin
Yassin | Building Compact, High-Current Connections for Drones & Robots
Yassin | Building Compact, High-Current Connections for Drones & Robots
Hello @yassin, I will be working on a project on solar energy output forecasting and IOT monitoring, I notice you used the BH1750 light sensor to get the value of solar irradiance, although the BH1750 give it output in lux and not W/m^2,
I will be converting it value in lux to W/m^2 by multiplying by a factor of 0.0079 OR dividing by a range from 210-220.
My current challenge comes from the max lux output of the BH1750 light sensor(65355) I need to be able to get up to 120,000 LUX: what can i do?
I saw a software fix by setting the value of MTReg() to a lower value from it default value of 69 to 31...
i don't know how this would work out though as I haven't tested it out.
Yassin | Building Compact, High-Current Connections for Drones & Robots
@yassin
Great to know! Then neutral density filter option is a bit confusing to know which filter resolution or type to use.
I also saw the "red BH1750 module" that comes with a white plastic dome that can vary the light sensed by the sensor and reduces the chance of it maxing out at direct sunlight(noon).
Yassin | Building Compact, High-Current Connections for Drones & Robots


















