#include <WiFi.h>
#include <PubSubClient.h>
// WiFi和MQTT配置
const char *ssid = "mySSID";
const char *password = "";
const char *mqttbroker = "broker.hivemq.com";
const char *clientID = "condominium-monitor";
int portno = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
// 单元1: Blk 5, #05-200
struct Unit {
int lightPin; // 灯光控制引脚
int pirPin; // PIR传感器引脚
int light; // 灯光状态: 0 = OFF; 1 = ON
int prese; // 存在状态: 0 = ABSENT; 1 = PRESENT
const char* baseTopic;
unsigned long lastUpdate;
unsigned long lastMotionTime; // 上次检测到运动的时间
};
Unit units[2] = {
{2, 4, 0, 0, "v1/blk5/05/200/livingroom", 0, 0}, // 单元1: 灯光引脚2, PIR引脚4
{5, 14, 0, 0, "v1/blk5/05/201/livingroom", 0, 0} // 单元2: 灯光引脚5, PIR引脚14
};
// 存在检测超时时间(毫秒)
const unsigned long PRESENCE_TIMEOUT = 30000; // 30秒无人移动则认为无人
// MQTT消息回调函数
void callback(const char *topic, byte* payload, unsigned int length) {
// 处理灯光控制命令
String message = "";
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
// 解析主题: v1/blk5/05/200/livingroom/light/control
String topicStr = String(topic);
if (topicStr.endsWith("/light/control")) {
// 提取单元号
int unitIndex = -1;
if (topicStr.indexOf("200") != -1) unitIndex = 0;
if (topicStr.indexOf("201") != -1) unitIndex = 1;
if (unitIndex != -1) {
// 控制灯光
if (message == "ON") {
units[unitIndex].light = HIGH;
digitalWrite(units[unitIndex].lightPin, HIGH);
Serial.print("Unit ");
Serial.print(unitIndex+1);
Serial.println(": Light turned ON");
} else if (message == "OFF") {
units[unitIndex].light = LOW;
digitalWrite(units[unitIndex].lightPin, LOW);
Serial.print("Unit ");
Serial.print(unitIndex+1);
Serial.println(": Light turned OFF");
}
}
}
}
// 连接WiFi
void setup_wifi() {
Serial.begin(115200);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
// 连接MQTT代理
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(clientID)) {
Serial.println("connected");
// 订阅灯光控制主题
client.subscribe("v1/blk5/05/200/livingroom/light/control");
client.subscribe("v1/blk5/05/201/livingroom/light/control");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
setup_wifi();
client.setServer(mqttbroker, portno);
client.setCallback(callback);
// 初始化IO引脚
for (int i = 0; i < 2; i++) {
pinMode(units[i].lightPin, OUTPUT);
pinMode(units[i].pirPin, INPUT);
// 初始状态
digitalWrite(units[i].lightPin, LOW);
units[i].light = LOW;
units[i].prese = LOW;
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// 处理每个单元的数据
for (int i = 0; i < 2; i++) {
// 读取PIR传感器状态
int pirState = digitalRead(units[i].pirPin);
// 如果检测到运动
if (pirState == HIGH) {
units[i].prese = HIGH; // 标记为有人
units[i].lastMotionTime = millis(); // 记录最后运动时间
// 如果灯光是自动模式,可以在这里控制灯光开启
// 注意:实际应用中可能需要添加灯光控制逻辑
}
// 如果超时没有检测到运动
else if (millis() - units[i].lastMotionTime > PRESENCE_TIMEOUT) {
units[i].prese = LOW; // 标记为无人
}
// 每5秒更新一次MQTT数据
if (millis() - units[i].lastUpdate > 5000) {
units[i].lastUpdate = millis();
// 构建完整的主题
String lightTopic = String(units[i].baseTopic) + "/light/status";
String preseTopic = String(units[i].baseTopic) + "/prese/status";
// 发布数据
client.publish(lightTopic.c_str(), String(units[i].light).c_str());
client.publish(preseTopic.c_str(), String(units[i].prese).c_str());
Serial.print("Published - Unit ");
Serial.print(i+1);
Serial.print(": ");
Serial.print(lightTopic);
Serial.print(" = ");
Serial.print(units[i].light);
Serial.print(", ");
Serial.print(preseTopic);
Serial.print(" = ");
Serial.println(units[i].prese);
}
}
delay(100); // 减少CPU负载
}