本項目中的郵件報警模塊在用戶在網頁激活後會自動監測當前的溫度,並且與用戶設置的溫度閾值做比較,一旦檢測到當前溫度超過用戶設定的溫度閾值,系統便會向用戶所指定的郵箱發送一封報警郵件。當然,你也可以接入各種各樣的監測模塊,實現更多狀態的監測與報警。
目錄
SMTP 軟件包的使用
郵件使用的是SMTP_CLIENT軟件包,查看軟件包鏈接。
該軟件包實現了基於SMTP協議的郵件發送功能,並且支持加密端口,但其對用戶提供的接口非常簡潔易懂,使用者並不需要了解SMTP協議的具體內容便可非常方便地使用。在本項目中,使用到了如下接口:
smtp_client_init() //初始化 smtp_client 客戶端
smtp_set_server_addr() //設置服務器的地址及端口
smtp_set_auth() //設置服務器認證信息
smtp_add_receiver() //添加收件人地址
smtp_send_mail() //發送郵件
以上接口順序執行就是一個完整的smtp郵件發送流程。在本項目中,雖然對其中的幾個接口進行了進一步的封裝從而實現更加高級的功能,但底層的邏輯還是上述接口。
郵件報警模塊源碼詳解
模塊結構體
郵件模塊結構體如下所示:
typedef struct
{
uint8_t enable; //郵件功能使能
uint32_t cold_time; //報警冷卻時間
char server_addr[100]; //郵件服務器地址
char server_port[10]; //郵件服務器端口
char username[50]; //用戶名
char password[50]; //密碼
char receiver[100]; //收件人地址
} smtp_module_t;
enable成員是郵件功能的開啓標誌,cold_time存儲了報警冷卻時間,即兩個連續的報警之間的最小間隔,若在這個間隔內模塊不會進行第二次報警。server_addr爲郵件服務器地址,server_port爲郵件服務器端口,普通端口一般爲 25,同時該軟件包也支持465/587兩個加密端口,需要注意的是,使用加密端口前應開啓軟件包加密功能,在env工具中的配置如下:
username與password分別爲所要使用的發件人的用戶名及密碼,receiver是收件人的郵箱地址。
模塊函數簡介
函數名 | 函數簡介 |
smtp_module_init | 郵件模塊初始化 |
prepare_content | 生成報警內容 |
smtp_thread | 郵件核心處理線程 |
smtp_data_config | 配置郵件參數 |
smtp_enable&smtp_disable | 郵件報警功能啓用/禁用 |
json_create_smtp_data | 生成郵件參數json字符串 |
模塊函數詳解
smtp_module_init
該函數爲smtp模塊初始化函數,該函數實現了郵件工作線程的創建與開啓。
int smtp_module_init(void)
{
rt_thread_t smtp_client_tid;
//創建郵件發送線程(如果選擇在主函數中直接調用郵件發送函數,需要注意主函數堆棧大小,必要時調大)
smtp_client_tid = rt_thread_create("smtp", smtp_thread, RT_NULL, SMTP_CLIENT_THREAD_STACK_SIZE, 20, 5);
if (smtp_client_tid != RT_NULL)
{
rt_thread_startup(smtp_client_tid);
}
return RT_EOK;
}
prepare_content
該函數實現了郵件內容的拼接,將當前溫溼度加入到報警字符串中。
//準備郵件內容
static void prepare_content(void)
{
sprintf(content,
"W601監測系統報警\r\n-------------------------\r\n當前溫度:%.2f C\r\n當前溼度:%.2f%% \r\n",
w601_aht10.cur_temp,
w601_aht10.cur_humi);
}
smtp_thread
該函數爲郵件工作的主線程,在該線程的一開始對smtp客戶端進行初始化。在線程中,首先會檢測郵件報警功能是否開啓,若開啓了該功能,系統會比對當前溫度和報警閾值溫度,若當前溫度超出了報警閾值溫度,同時報警冷卻時間已到(最近一段時間內沒有產生過報警),系統便會生成報警字符串並且發送報警郵件。
void smtp_thread(void *param)
{
//初始化smtp客戶端
smtp_client_init();
//清空設置
rt_memset(&w601_smtp, 0, sizeof(smtp_module_t));
while (1)
{
if (w601_smtp.cold_time)
{
w601_smtp.cold_time--;
}
if (w601_smtp.enable) //使能郵件功能
{
if (w601_aht10.cur_temp > w601_aht10.temp_warn) //有報警
{
//冷卻時間內不重複報警
if (w601_smtp.cold_time)
{
}
else
{
//設置報警冷卻時間
w601_smtp.cold_time = WARNING_COLD_TIME;
LOG_W("system warning,smtp send!");
prepare_content();
smtp_send_mail(SMTP_SUBJECT, content);
}
}
}
rt_thread_mdelay(1000);
}
}
smtp_data_config
該函數實現了郵件參數的設置功能,當接收到前端傳來的設置請求時,系統會提取相對應的設置參數,並且將參數傳入該函數,在該函數中進行參數的配置。需要注意的是,由於本項目只支持一個收件人(軟件包本身支持多收件人),所以在函數開頭會刪除原先已保存的收件人,並且在下面添加新的收件人。當然你也可以通過修改模塊源碼使其支持多收件人。
int smtp_data_config(char *server_addr, char *server_port,
char *username, char *password,
char *receiver, char *temp_warn)
{
if (w601_smtp.receiver[0] != '\0')
{
smtp_delete_receiver(w601_smtp.receiver);
}
strcpy(w601_smtp.server_addr, server_addr);
strcpy(w601_smtp.server_port, server_port);
strcpy(w601_smtp.username, username);
strcpy(w601_smtp.password, password);
strcpy(w601_smtp.receiver, receiver);
smtp_set_server_addr(w601_smtp.server_addr,
ADDRESS_TYPE_DOMAIN,
w601_smtp.server_port);
smtp_set_auth(w601_smtp.username, w601_smtp.password);
smtp_add_receiver(receiver);
w601_aht10.temp_warn = atof(temp_warn);
return 0;
}
smtp_enable&smtp_disable
這兩個函數非常簡單,通過給模塊結構體的使能成員賦值來實現郵件功能的開關。用戶通過網頁進行開關設置。
void smtp_enable(void)
{
w601_smtp.enable = 1;
}
void smtp_disable(void)
{
w601_smtp.enable = 0;
}
json_create_smtp_data
該函數是將郵件模塊的參數轉換爲json格式的字符串,主要用於與網頁的通信。將當前郵件參數傳輸給網頁顯示。
char *json_create_smtp_data(void)
{
char *json_data = RT_NULL;
char value[10] = "";
cJSON *root = cJSON_CreateObject();
snprintf(value, sizeof(value), "%.2f", w601_aht10.temp_warn);
cJSON_AddItemToObject(root, "server_addr", cJSON_CreateString(w601_smtp.server_addr));
cJSON_AddItemToObject(root, "server_port", cJSON_CreateString(w601_smtp.server_port));
cJSON_AddItemToObject(root, "username", cJSON_CreateString(w601_smtp.username));
cJSON_AddItemToObject(root, "password", cJSON_CreateString(w601_smtp.password));
cJSON_AddItemToObject(root, "receiver", cJSON_CreateString(w601_smtp.receiver));
cJSON_AddItemToObject(root, "temp_warn", cJSON_CreateString(value));
cJSON_AddItemToObject(root, "enable", cJSON_CreateNumber(w601_smtp.enable));
json_data = cJSON_PrintUnformatted(root);
cJSON_Delete(root);
return json_data;
}