Files
Smart-granary-code/README.md

447 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Smart Granary Code
基于 ESP-IDF 的智能粮仓监测与联动控制固件,运行于 ESP32-S3。项目集成了光照、温湿度、气体、火焰、人体/门磁、重量等多类传感器,支持本地 UI、语音交互SU-03T以及 MQTT 远程上报与控制。
## 1. 项目概览
### 1.1 核心能力
- 多传感器采集BH1750、AHT30、MQ-2、JW01、火焰传感器、HX711、人体/门磁
- 本地显示LVGL + ST7789
- 两种控制模式:`manual`(手动)/`auto`(自动联动)
- 四路继电器执行:风扇、照明、制冷、加热
- 语音模块SU-03T 查询与告警播报
- 网络能力Wi-Fi AP 配网 + STA 联网 + MQTT 双向通信
### 1.2 默认运行行为
- 上电默认 `manual` 模式
- MQTT 上报周期1 秒
- 门未关告警阈值60 秒
- 粮食“变质”判定阈值:`co2 >= 1500 ppm`
- 火焰危险阈值:`fire_percent >= 35%`
## 2. 硬件连接说明
以下为当前代码中的实际引脚定义。
### 2.1 I2C 设备
BH1750 与 AHT30 共享同一 I2C 总线:
| 设备 | SCL | SDA |
| --- | --- | --- |
| BH1750 | GPIO1 | GPIO2 |
| AHT30 | GPIO1 | GPIO2 |
### 2.2 继电器4 路)
| 继电器编号 | 功能 | GPIO |
| --- | --- | --- |
| 1 | 风扇 | GPIO12 |
| 2 | 照明灯 | GPIO11 |
| 3 | 制冷片 | GPIO10 |
| 4 | 加热器 | GPIO9 |
### 2.3 ADC 传感器
| 设备 | GPIO | 说明 |
| --- | --- | --- |
| 火焰传感器 | GPIO3 | 百分比采样 + 危险判定 |
| MQ-2 | GPIO8 | 有害气体/烟雾百分比 |
### 2.4 UART 设备
| 设备 | UART | TX | RX | 波特率 |
| --- | --- | --- | --- | --- |
| JW01TVOC/HCHO/CO2 | UART0 | GPIO43 | GPIO44 | 9600 |
| SU-03T语音 | UART2 | GPIO42 | GPIO41 | 115200 |
### 2.5 IO 输入
| 设备 | GPIO | 说明 |
| --- | --- | --- |
| HC-SR312 人体感应 | GPIO16 | 高电平表示检测到人体 |
| 门磁开关 | GPIO17 | 低电平表示门关闭 |
### 2.6 称重模块
| 设备 | SCK | DOUT |
| --- | --- | --- |
| HX711 | GPIO13 | GPIO14 |
## 3. 软件架构
### 3.1 主要任务
- `sensor_task`:周期读取多传感器并更新共享环境数据
- `ui_task`:驱动 UI 刷新与界面变量更新
- `status_task`:人体/门磁状态与开门超时告警
- `relay_status_task`:同步继电器状态到 UI 与上报数据
- `hx711_task`:称重采样、滤波、去皮与稳定显示
- `mqtt_publish_task`:每秒打包 JSON 并发布 MQTT
- `su03t_auto_alert_task`:语音告警节流上报(默认 3 分钟)
- `sntp_task`:联网后 SNTP 对时
### 3.2 模式逻辑
- `manual`:接收 MQTT 下发的继电器开关命令,自动联动逻辑不接管
- `auto`:按阈值自动控制制冷/制热/风扇,照明不参与自动控制
## 4. 开发环境要求
### 4.1 基础要求
- Linux 开发环境
- ESP-IDF建议与当前工程一致版本需包含 `idf.py`
- USB 驱动与串口权限正常
### 4.2 目标芯片与分区
- Target`esp32s3`
- Flash Size16MB工程当前配置
- 分区表:自定义 `partitions.csv`
`partitions.csv` 当前配置:
- `nvs`0x9000, 0x6000
- `phy_init`0xF000, 0x1000
- `factory`0x10000, 4M
## 5. 快速开始
### 5.1 拉起工程
```bash
idf.py set-target esp32s3
idf.py build
```
### 5.2 烧录并查看日志
```bash
idf.py -p /dev/ttyUSB0 flash monitor
```
如果你使用的是 USB Serial/JTAG可根据实际端口替换 `-p` 参数。
### 5.3 VS CodeESP-IDF 插件)建议流程
1. 先执行 Build
2. 再执行 Flash
3. 最后打开 Monitor 查看日志
## 6. menuconfig 关键配置
```bash
idf.py menuconfig
```
### 6.1 Wi-Fi 连接参数
菜单位置:`WiFi 连接`
| 配置项 | 说明 | 默认值 |
| --- | --- | --- |
| WIFI_CONNECT_CONNECT_TIMEOUT_SEC | 连接超时(秒) | 30 |
| WIFI_CONNECT_MAX_SCAN_RESULTS | 扫描结果上限 | 20 |
| WIFI_CONNECT_AP_MAX_CONNECTIONS | 配网 AP 最大连接数 | 4 |
### 6.2 MQTT 参数
菜单位置:`MQTT 配置参数`
| 配置项 | 说明 | 默认值 |
| --- | --- | --- |
| AGRI_ENV_MQTT_BROKER_URI | MQTT 服务器地址 | 空 |
| AGRI_ENV_MQTT_USERNAME | MQTT 用户名 | 空 |
| AGRI_ENV_MQTT_PASSWORD | MQTT 密码 | 空 |
| AGRI_ENV_MQTT_CLIENT_ID | 客户端 ID | agri-env-monitor |
| AGRI_ENV_MQTT_PUBLISH_TOPIC | 发布主题 | agri/env/data |
| AGRI_ENV_MQTT_SUBSCRIBE_TOPIC | 订阅主题 | agri/env/cmd |
## 7. 配网说明
工程内置 AP 配网 + HTTP 控制台 + DNS 劫持流程:
1. 设备启动 APSTA开启配网热点
2. 手机连接热点后访问 `http://192.168.4.1`
3. 页面扫描附近 Wi-Fi提交 `SSID + 密码`
4. 设备连上路由后,页面可显示分配到的 STA IP
配网页面 API
- `GET /api/scan`:扫描 AP 列表
- `POST /api/connect`:提交联网参数
- `GET /api/status`:查询连接状态
- `POST /api/clear`:清除保存的 Wi-Fi 配置
- `GET /api/sysinfo`:查看运行时信息
## 8. MQTT 协议说明(上位机对接)
### 8.1 协议与连接行为
- MQTT 协议版本MQTT v3.1
- 连接成功后自动订阅 `AGRI_ENV_MQTT_SUBSCRIBE_TOPIC`
- 若 Broker URI 无协议头,内部会补全为 `mqtt://`,默认端口 1883
- 当前发布参数QoS=0Retain=0每秒上报一次
### 8.2 主题定义
| 方向 | 主题 | 用途 |
| --- | --- | --- |
| 设备 -> 上位机 | `agri/env/data` | 周期上报环境数据、状态、阈值 |
| 上位机 -> 设备 | `agri/env/cmd` | 模式切换、阈值更新、手动控制 |
### 8.3 上报 JSON 字段agri/env/data
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| time | string | 设备本地时间,格式 `YYYY-MM-DD HH:MM:SS` |
| lux | number | 光照lux |
| temp | number | 温度(摄氏度) |
| humidity | number | 湿度(%RH |
| gas_percent | number | MQ-2 百分比(% |
| tvoc | number | JW01 TVOC |
| hcho | number | JW01 HCHO |
| co2 | number | JW01 CO2ppm |
| ice_weight | number | HX711 重量g |
| fire_percent | number | 火焰百分比(% |
| fire_danger | boolean | 火焰危险判定 |
| human_present | boolean | 人体存在 |
| door_closed | boolean | 门是否关闭true=关) |
| door_alarm | boolean | 门未关超时告警 |
| door_open_seconds | number | 连续开门时长(秒) |
| fan_on | boolean | 风扇继电器状态 |
| light_on | boolean | 照明继电器状态 |
| cool_on | boolean | 制冷继电器状态 |
| hot_on | boolean | 制热继电器状态 |
| su03t_last_msgno | number | SU-03T 最近消息号 |
| su03t_rx_count | number | SU-03T 累计收包次数 |
| mode | string | `auto``manual` |
| th_temp_h | number | 制冷阈值 |
| th_temp_l | number | 制热阈值 |
| th_hum_h | number | 湿度阈值 |
| th_gas_h | number | 气体阈值 |
| ip_address | string | 当前 IP |
| food_status | string | `good` / `spoilage` |
| uptime_s | number | 运行时长(秒) |
| free_heap_kb | number | 剩余堆内存KB |
上报示例:
```json
{
"time": "2026-04-22 16:24:39",
"lux": 5,
"temp": 30.8,
"humidity": 65.4,
"gas_percent": 9.7,
"tvoc": 0,
"hcho": 0,
"co2": 350,
"ice_weight": 0,
"fire_percent": 0,
"fire_danger": false,
"human_present": false,
"door_closed": false,
"door_alarm": false,
"door_open_seconds": 4,
"fan_on": false,
"light_on": false,
"cool_on": false,
"hot_on": false,
"su03t_last_msgno": 0,
"su03t_rx_count": 0,
"mode": "manual",
"th_temp_h": 35,
"th_temp_l": 15,
"th_hum_h": 70,
"th_gas_h": 20,
"ip_address": "192.168.1.12",
"food_status": "good",
"uptime_s": 1234,
"free_heap_kb": 182
}
```
### 8.4 下发命令agri/env/cmd
字段按需携带,未携带字段保持原值。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| mode | string | `auto` / `manual` |
| th_temp_h | number | 更新制冷阈值 |
| th_temp_l | number | 更新制热阈值 |
| th_hum_h | number | 更新湿度阈值 |
| th_gas_h | number | 更新气体阈值 |
| fan | boolean | 手动控制风扇 |
| light | boolean | 手动控制照明 |
| cool | boolean | 手动控制制冷 |
| hot | boolean | 手动控制制热 |
下发示例(自动模式):
```json
{
"mode": "auto",
"th_temp_h": 28.5,
"th_temp_l": 16.0,
"th_hum_h": 65.0,
"th_gas_h": 18.0
}
```
下发示例(手动模式):
```json
{
"mode": "manual",
"fan": true,
"cool": true,
"hot": false,
"light": false
}
```
### 8.5 SU-03T 语音命令协议
说明:
- 串口为 UART2RX=GPIO41TX=GPIO42115200 波特率。
- 语音模块上报命令时,固件按 msgno 匹配语义并立即回包。
- 数值类回包使用 8 字节 little-endian double 作为参数区。
- 状态类回包使用“仅 msgno、无参数”格式。
#### 8.5.1 查询命令映射(模块 -> 设备)
| 命令词label | key | 请求 msgno |
| --- | --- | --- |
| 温度是多少 | ask_temp | 0x00 |
| 湿度是多少 | ask_humi | 0x01 |
| 光照强度是多少 | ask_lux | 0x02 |
| 烟雾浓度是多少 | ask_mq2 | 0x03 |
| 二氧化碳浓度是多少 | ask_co2 | 0x04 |
| 粮食重量是多少 | ask_weight | 0x05 |
| 有人在吗 | ask_hum | 0x06 |
| 门磁状态 | ask_door | 0x07 |
| 风扇继电器状态 | ask_fan | 0x08 |
| 照明继电器状态 | ask_light | 0x09 |
| 制冷继电器状态 | ask_cool | 0x0A |
| 制热继电器状态 | ask_hot | 0x0B |
| 当前控制模式 | ask_control | 0x0C |
| 粮食状态 | ask_rice | 0x0D |
#### 8.5.2 回包映射(设备 -> 模块)
| 场景 | 回包 msgno | 参数 |
| --- | --- | --- |
| 温度查询返回 | 0x01 | double温度 |
| 湿度查询返回 | 0x02 | double湿度 |
| 光照查询返回 | 0x03 | doublelux |
| 烟雾查询返回 | 0x04 | doublegas_percent |
| CO2 查询返回 | 0x05 | doubleco2 |
| 重量查询返回 | 0x06 | doubleice_weight |
| 人体状态:有人 | 0x1A | 无参数 |
| 人体状态:无人 | 0x1B | 无参数 |
| 门磁状态:关门 | 0x0D | 无参数 |
| 门磁状态:开门 | 0x0C | 无参数 |
| 风扇:开 | 0x14 | 无参数 |
| 风扇:关 | 0x15 | 无参数 |
| 照明:开 | 0x20 | 无参数 |
| 照明:关 | 0x21 | 无参数 |
| 制冷:开 | 0x16 | 无参数 |
| 制冷:关 | 0x17 | 无参数 |
| 制热:开 | 0x18 | 无参数 |
| 制热:关 | 0x19 | 无参数 |
| 控制模式:自动 | 0x1C | 无参数 |
| 控制模式:手动 | 0x1D | 无参数 |
| 粮食状态:良好 | 0x1E | 无参数 |
| 粮食状态:变质 | 0x1F | 无参数 |
#### 8.5.3 主动告警(设备周期上报)
说明:语音主动告警任务每 1 秒检查一次条件,同一类告警最小间隔为 180 秒。
| 触发条件 | 告警 msgno | 参数 |
| --- | --- | --- |
| temp >= th_temp_h | 0x10 | double当前温度 |
| humidity >= th_hum_h | 0x11 | double当前湿度 |
| fire_danger = true | 0x12 | 无参数 |
| door_closed = false | 0x13 | 无参数 |
## 9. 自动联动规则
仅在 `mode=auto` 时生效:
- 制冷:`temp >= th_temp_h` 时开,否则关
- 制热:`temp <= th_temp_l` 时开,否则关
- 风扇:`humidity >= th_hum_h``gas_percent >= th_gas_h` 时开,否则关
- 照明:当前自动逻辑不控制照明
上电默认值:
- `mode = manual`
- `th_temp_h = 35.0`
- `th_temp_l = 15.0`
- `th_hum_h = 70.0`
- `th_gas_h = 20.0`
- `door_open_alarm_seconds = 60`
## 10. 目录结构(核心)
```text
.
├── main/
│ └── main.cpp # 系统入口与任务编排
├── components/
│ ├── wifi-connect/ # AP 配网、HTTP 控制台、STA 联网
│ ├── agri_env/ # MQTT 封装
│ ├── bh1750/ # 光照传感器
│ ├── MQ-2/ # 气体传感器
│ ├── JW01/ # TVOC/HCHO/CO2 传感器
│ ├── fire_sensor/ # 火焰传感器
│ ├── human_door/ # 人体/门磁检测
│ ├── relay_ctrl/ # 四路继电器控制
│ ├── su-03t/ # 语音模块协议
│ ├── lvgl_st7789_use/ # LCD + LVGL 显示
│ └── ui/ # UI 页面与变量绑定
├── partitions.csv # 分区表
├── sdkconfig # 当前工程配置
└── update_sdkconfig.sh # 常用 sdkconfig 修补脚本
```
## 11. 常见问题与排障
### 11.1 设备始终无法联网
- 检查是否连上设备热点并访问了 `http://192.168.4.1`
- 检查路由器频段ESP32-S3 常用 2.4GHz
- 在串口日志中观察 `wifi_connect` 状态机输出
### 11.2 MQTT 无法上报
- 确认 `AGRI_ENV_MQTT_BROKER_URI` 是否有效
- 确认设备已获取 STA IP且可访问 Broker
- 检查鉴权参数(用户名/密码/Client ID
### 11.3 JW01 与日志冲突
JW01 使用 UART0GPIO43/44建议保持控制台输出为 USB Serial/JTAG避免 UART0 日志与传感器数据冲突。
### 11.4 HX711 波动大
- 检查供电稳定性与接线
- 系统已内置去皮、低通与稳定锁定逻辑,仍异常时优先排查硬件噪声
## 12. 开发建议
- 新增组件时先补齐 `components/<name>/include` 对外接口,再在 `main.cpp` 挂接任务
- MQTT 字段建议保持向后兼容:新增字段不删除旧字段
- 上位机建议以 `agri/env/data` 最新数据作为控制确认(当前无独立 ACK 主题)
## 13. 许可证
当前仓库未提供独立 LICENSE 文件,如需对外发布,请补充开源许可证并在此处声明。