【本文正在參與"2021愛智先行者-征文大賽"活動】https://mp.weixin.qq.com/s/I2s99dZpbP0QpMiKFneYJA
前言
之前做了兩個傳感器2021愛智先行者—人體存在傳感器-CSDN社區 和 從零開始的DIY智能家居 - 基於 ESP32 的智能光照傳感器_靈感桌面的博客-CSDN博客,結果就控制一下燈?那也太浪費了吧,這次我准備把我出門忘記關閉頻率第二名!浪費電第一名的 空調 給整一下,免得回家發現空調沒關,那就更加炸裂了!
不過我空調開關是同一個按鍵,並且沒辦法直接獲取空調狀態,空調太貴了我也不敢拆了改造(秒慫(/ω\))
於是就用到了我之前做的紅外測溫槍,超進化!--智能溫度傳感器!基於 arduino 的智能測溫模塊_靈感桌面的博客-CSDN博客 通過溫度來判斷我到底有沒有關空調。
我算過,我這破空調一小時一塊多錢,開一天就夠我吃頓飯了。對於我這種窮逼來說,這是不可接受的!(•́へ•́╬)
不過現在這種手動開關也挺蠢的,之后寫一個智能控制的應用,自動控制試試。當然,我絲毫不介意大佬有時間幫我寫一個更加NB的。|ू・ω・` )
硬件選擇
首先,就是翼輝的 邊緣計算機 Spirit 1 邊緣計算機,這套環境都是建立在這個玩意的基礎上。
還有祖傳的安信可 ESP32S 。安信可看到了能不能給我點贊助啊?給我報銷一下板子錢也行啊,你看愛智都給我這機會了!
紅外學習模塊 就是花20淘寶買的玩意,可以學習並儲存16個鍵值,不過我就用了一個。
管腳使用 UART 控制(P16-Tx、P17-Rx、3V3-3V3、GND-GND)
注意!:這個紅外二極管得放平,要不然會被旁邊的接收模塊擋住,影響信號角度。我這就是焊的時候沒注意,后面硬掰的。
代碼解析
獲取代碼
為了方便講解邏輯,我會打亂代碼的順序可能還會進行裁剪,要是想直接拿代碼跑的朋友可以直接去 靈感桌面的秘密寶庫 獲取代碼,或者直接 clone:
https://gitee.com/inspiration-desktop/DEV-lib-arduino.git
其實看過我之前文章的朋友應該已經發現了,基本上就是套我的那套 SDK 的模板,看過之前的朋友可以直接去看設備控制命令 和 設備控制流程。
如果對我寫的 SDK 開發不是很清楚的朋友可以繼續看下去。
下載或者 clone代碼后這次會用到這個三個文件夾:
cjson:我移植的 cjson 庫,就是標准的 cjson 庫,放到 arduino 安裝目錄下的 libraries 文件夾里,百度一下 cjson 的函數使用就行了。
libsddc:是我移植自官方的SDDC庫和自己寫的 SDK,也是放入 libraries 文件夾里就行。里面是 SDDC 協議的處理函數,我們不用管。
demo 文件夾里面就是我們各種傳感器的 demo 代碼了:
紅圈的 infrared_learning_sddc_sdk_demo文件夾里面就是我們代碼,點進去就能看見 infrared_learning_sddc_sdk_demo.ino 文件,雙擊文件會自動啟動 arduino-IDE 打開代碼。在工具 -> 端口 選擇對應的 COM 口然后點擊上傳就可以把代碼燒錄到板子里:
具體 arduino 使用教程可以看我之前的文章 arduino開發指導 和 手把手帶你 arduino 開發:基於ESP32S 的第一個應用-紅外測溫槍(帶引腳圖)
通過 Spirit 1 的應用程序或者嗅探器 向傳感器設備發送的命令:
{
"method": "set",
"air_conditioning_switch": "ON" // 因為我空調遙控器開和關是同一個按鍵,所以一個命令就控制開和關。通過之前溫度傳感器判斷空調是否
}
{
"method": "set",
"air_conditioning_switch": "study" // 讓傳感器啟動學習功能
}
設備和協議初始化流程:
基於官方 demo 寫的不需要做什么修改,主要是設備初始化,管腳配置,和協議初始化部分。
/*
* 初始化傳感器
*/
void sensor_init()
{
// 傳感器使用串口初始化
Serial2.begin(9600);
Serial2.setDebugOutput(true);
Serial2.println();
}
void setup() {
byte mac[6];
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
// 初始化控制模塊
sensor_init();
// 清除一下按鍵狀態機的狀態
button.reset();
// 創建按鍵掃描線程,長按 IO0 按鍵,松開后ESP32 將會進入 SmartConfig 模式
sddc_printf("長按按鍵進入 Smartconfig...\n");
button.attachLongPressStop(esp_io0_key_task);
xTaskCreate(esp_tick_task, "button_tick", ESP_TASK_STACK_SIZE, NULL, ESP_TASK_PRIO, NULL);
// 啟動 WiFi 並且連接網絡
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
// 獲取並打印 IP 地址
Serial.println("");
Serial.println("WiFi connected");
Serial.print("'ip :");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
// sddc協議初始化
sddc_lib_main(&sys_cfg);
// 獲取並打印網卡 mac 地址
WiFi.macAddress(mac);
sddc_printf("MAC addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
// 使用網卡 mac 地址設置設備唯一標識 UID
sddc_set_uid(G_sddc, mac);
}
void loop() {
// 運行 SDDC 協議循環
while (1)
{
sddc_printf("SDDC running...\n");
sddc_run(G_sddc);
sddc_printf("SDDC quit!\n");
}
// 銷毀 SDDC 協議
sddc_destroy(G_sddc);
}
配置設備信息
這部分代碼可以配置 WiFi 名字和 WiFi 密碼,要使用的引腳,並且配置設備在 Spirit 1 上顯示的信息:
#define SDDC_CFG_PORT 680U // SDDC 協議使用的端口號
#define PIN_INPUT 0 // 選擇 IO0 進行控制
#define ESP_TASK_STACK_SIZE 4096
#define ESP_TASK_PRIO 25
static const char* ssid = "EOS-Tenda"; // WiFi 名
static const char* password = "1234567890"; // WiFi 密碼
/*
* 當前設備的信息定義
*/
DEV_INFO dev_info = {
.name = "空調控制開關",
.type = "device.hwyk",
.excl = SDDC_FALSE,
.desc = "ESP-32S",
.model = "IDHWYK01B",
.vendor = "inspiration-desktop",
};
/*
* 系統注冊對象匯聚
*/
SDDC_CONFIG_INFO sys_cfg = {
.token = "1234567890", // 設備密碼
.devinfo = &dev_info,
.io_dev_reg = io_dev,
.io_dev_reg_num = ARRAY_SIZE(io_dev),
.num_dev_reg = num_dev,
.num_dev_reg_num = ARRAY_SIZE(num_dev),
.state_get_reg = dev_state_get_reg,
.state_get_reg_num = ARRAY_SIZE(dev_state_get_reg),
.dis_dev_reg = dis_dev,
.dis_dev_num = ARRAY_SIZE(dis_dev),
};
回調函數注冊
這是收到命令后回調函數注冊的位置,在這里注冊的函數才能被 SDK 正確的調用,執行正確的動作。
具體 SDK 的解析可以參考 同人逼死官方系列!基於sddc 協議的SDK框架 sddc_sdk_lib 解析 和 同人逼死官方系列!從 DDC 嗅探器到 sddc_sdk_lib 的數據解析
/*
* 數字量設備對象函數與處理方法注冊
*/
NUM_DEV_REGINFO num_dev[] = {
// {"set_num_demo", demo}, // 字符串為輸入命令,demo為命令處理函數
};
/*
* 顯示設備對象函數與處理方法注冊
*/
DIS_DEV_REGINFO dis_dev[] = {
// {"set_dis_demo", demo}, // 字符串為輸入命令,demo為命令處理函數
};
/*
* IO設備對象設置函數與處理方法注冊
*/
IO_DEV_REGINFO io_dev[] = {
{"air_conditioning_switch",air_conditioning_switch_set},
// {"set_io_demo", demo}, // 字符串為輸入命令,demo為命令處理函數
};
/*
* 系統對象狀態獲取注冊
*/
DEV_STATE_GET dev_state_get_reg[] = {
// {"demo", DEV_NUM_TYPE, num_get_demo}, // demo為輸入命令,字符串為命令處理函數
// {"demo", DEV_IO_TYPE, io_get_demo},
// {"demo", DEV_DISPLAY_TYPE, dis_get_demo},
};
設備控制流程
這里是我們自己編寫的處理流程 ,可以根據你的需求自己更改,收到 set 或者 get 后根據前面的注冊的函數,進入對應的處理函數。 設備會檢測傳感器輸出,然后根據設置的上報間隔定時上報光照強度數據,還可以主動發送 get 命令主動查詢傳感器當前數據:
static unsigned char command_buf[] = {0X55, 0XAA, 0X03, 0X00, 0X02}; // 發送命令
static unsigned char study_buf[] = {0X55, 0XAA, 0X02, 0X00, 0X01}; // 學習命令
/*
* 紅外學習模塊控制函數
*/
sddc_bool_t air_conditioning_switch_set(const char* value) {
if(strcmp(value,"study"))
{
Serial2.write(study_buf, 5);
return SDDC_TRUE;
} else
{
Serial2.write(command_buf, 5);
return SDDC_TRUE;
}
}
總結
OK!到目前為止,溫度傳感器,光照傳感器,人體存在傳感器,遠程控燈,遠程控空調都搭建完成了!接下來再把這些通過愛智的應用整合到一起就完事!一個超級牛逼的超級省錢的節能降耗場景就完成了!!!````