Files
2026-10-19 15:47:18 +08:00

220 lines
6.6 KiB
C

#include <stdio.h>
#include <string.h>
#include "led.h"
#include "beep.h"
#include "button.h"
#include "systick.h"
// #include "led_digital_tube.h"
#include "dht11.h"
#include "adc.h"
#include "usart1.h"
#include "eeprom.h"
#include "esp8266.h"
#include "beep.h"
// 配置:请替换为实际的 WiFi/服务器信息
#include "network_config.h"
// 发送与重连周期配置(毫秒)
#define SEND_INTERVAL_MS 200 // 设备发送间隔,减小此值可提高发送频率(注意网络与esp能力)
#define RECONNECT_PERIOD_MS 5000 // 每次重连尝试的时间窗
#include "oled.h"
#include "wfont.h"
// 中文
char buf[512];
int main(void)
{
// NVIC优先级分组, 2bit 用于表示抢断优先级,2bit为子优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
led_init(); // 初始化LED
beep_init(); // 初始化 蜂鸣器
// button_init();
systick_init(); // 初始化计时器
usart1_init(115200);
eeprom_init();
oled_init();
dht11_init();
adc1_init();
// 默认关闭蜂鸣器与 LED
beep_off();
led_set_status(0, 0);
led_set_status(1, 0);
led_set_status(2, 0);
// 初始化并尝试连接 WiFi 与服务器(如果需要可改为按键触发)
esp8266_init();
int tcp_connected = 0;
if (esp8266_connect_wifi(WIFI_SSID, WIFI_PASS)) {
printf("Connected to WiFi\r\n");
// 建立 TCP 连接到服务器
if (esp8266_tcp_connect(SERVER_IP, SERVER_PORT)) {
printf("TCP connect to %s:%d success\r\n", SERVER_IP, SERVER_PORT);
tcp_connected = 1;
// 发送设备注册消息
char reg_msg[128];
int reg_len = snprintf(reg_msg, sizeof(reg_msg),
"{\"type\":\"register\",\"device_id\":\"%s\",\"action\":\"connect\"}\n", DEVICE_ID);
if (reg_len > 0) {
int sent = esp8266_write(reg_msg, (uint16_t)reg_len);
if (sent > 0) {
printf("Device registration sent: %s\r\n", reg_msg);
} else {
printf("Device registration send failed\r\n");
}
}
} else {
printf("TCP connect failed\r\n");
tcp_connected = 0;
}
} else {
printf("WiFi connect failed\r\n");
tcp_connected = 0;
}
printf("OLED Demo\r\n");
// oled_draw_picture(elephant128x64);
// oled_draw_picture(gImage_1);
// oled_fill_rect(10, 10, 118, 54);
// oled_fill_rect(10, 10, 118, 54);
// oled_fill(0x05);
// oled_clear();
oled_draw_rect(0, 0, 127, 63);
// oled_draw_text8(0, 0, "hello world");
// oled_draw_text16(0, 16, "\xce\xc2\xb6\xc8: 36.5 \xa1\xe6");
// 将缓冲区内容刷新到屏幕
// oled_refresh_framebuffer();
while (1)
{
char buf[30];
u8 value[5];
dht11_get_values(value);
sprintf(buf, "\xce\xc2\xb6\xc8: %5.1f \xa1\xe6", (float)value[2]);
// 显示温度
oled_draw_text16(8, 8, buf);
sprintf(buf, "\xca\xaa\xb6\xc8: %5.1f%", (float)value[0]);
// 显示湿度
oled_draw_text16(8, 24, buf);
// 显示 ADC 的值(通道 10)
sprintf(buf, "ADC Value: %04d", adc1_get_value(10));
oled_draw_text8(8, 40, buf);
// 显示 LED 0 灯的状态(状态由服务器控制,固件不应自动切换)
sprintf(buf, "LED(0): %3s", led_get_status(0) ? "ON" : "OFF");
oled_draw_text8(8, 48, buf);
oled_refresh_framebuffer();
// 构造并发送 JSON 状态消息到后台服务器(TCP 行协议,每条消息以换行结束)
// 仅在 TCP 已连接时发送,避免在未连接时调用 CIPSEND 导致错误
static int reconnect_counter = 0; // 每次循环增长,达到阈值时尝试重连
reconnect_counter++;
int reconnect_threshold = RECONNECT_PERIOD_MS / SEND_INTERVAL_MS;
if (reconnect_threshold < 1) reconnect_threshold = 1;
if (!tcp_connected) {
if (reconnect_counter >= reconnect_threshold) {
reconnect_counter = 0;
printf("Attempting TCP reconnect...\r\n");
if (esp8266_tcp_connect(SERVER_IP, SERVER_PORT)) {
tcp_connected = 1;
printf("TCP reconnect success\r\n");
// 重新连接后发送设备注册消息
char reg_msg[128];
int reg_len = snprintf(reg_msg, sizeof(reg_msg),
"{\"type\":\"register\",\"device_id\":\"%s\",\"action\":\"reconnect\"}\n", DEVICE_ID);
if (reg_len > 0) {
int sent = esp8266_write(reg_msg, (uint16_t)reg_len);
if (sent > 0) {
printf("Device re-registration sent: %s\r\n", reg_msg);
} else {
printf("Device re-registration send failed\r\n");
}
}
} else {
printf("TCP reconnect failed\r\n");
}
} else {
// not connected, skip sending this round
printf("Not connected to TCP server, skipping send\r\n");
delay_ms(SEND_INTERVAL_MS);
continue;
}
}
char json[256];
int msg_len = snprintf(json, sizeof(json),
"{\"device_id\":\"%s\",\"temp\":%.1f,\"humidity\":%.1f,\"buzzer\":%d,\"led0\":%d,\"led1\":%d,\"led2\":%d}\n",
DEVICE_ID,
(float)value[2],
(float)value[0],
beep_get_status(),
led_get_status(0),
led_get_status(1),
led_get_status(2));
if (msg_len > 0) {
esp8266_clear_read_buf();
int sent = esp8266_write(json, (uint16_t)msg_len);
if (sent > 0) {
printf("Sent: %s\r\n", json);
} else {
printf("Send failed\r\n");
}
}
// 主动从服务器读取控制文件(轮询模式),避免依赖广播时序
if (tcp_connected) {
char getcmd[64];
snprintf(getcmd, sizeof(getcmd), "GET control %s\n", DEVICE_ID);
int gsent = esp8266_write(getcmd, (uint16_t)strlen(getcmd));
if (gsent > 0) {
printf("Sent GET control request\r\n");
} else {
printf("Send GET control failed\r\n");
}
}
// 发送后尝试读取来自服务器的控制命令(如果有)
char inbuf[256];
int rlen = esp8266_read(inbuf, sizeof(inbuf));
if (rlen > 0) {
// 简单解析 JSON 中的 buzzer 与 led0/led1/led2 字段
// 允许格式例如: {"buzzer":1,"led0":1,"led1":0,"led2":0}
inbuf[rlen] = '\0';
printf("Control recv: %s\r\n", inbuf);
// 查找 buzzer
char *p = NULL;
int val = 0;
p = strstr(inbuf, "\"buzzer\"");
if (p) {
p = strchr(p, ':');
if (p) {
if (sscanf(p+1, "%d", &val) == 1) {
if (val) { beep_on(); printf("Applied buzzer=1\r\n"); } else { beep_off(); printf("Applied buzzer=0\r\n"); }
}
}
}
// led0..led2
for (int i = 0; i < 3; i++) {
char key[16];
sprintf(key, "\"led%d\"", i);
p = strstr(inbuf, key);
if (p) {
p = strchr(p, ':');
if (p) {
if (sscanf(p+1, "%d", &val) == 1) {
led_set_status(i, val ? 1 : 0);
printf("Applied led%d=%d\r\n", i, val ? 1 : 0);
}
}
}
}
}
delay_ms(SEND_INTERVAL_MS);
}
}