Commit 96051595 authored by DESKTOP-MC5UL36\dell's avatar DESKTOP-MC5UL36\dell

增加扫码配wifi功能

parent 1ff4fcfc
#include "main.h"
#include "wifi_autoconfig.h"
int main()
{
......@@ -25,6 +26,20 @@ int main()
return -4;
}
// 初始化音频,确保配网时的提示音能听到
if (audio_config_init() != 0)
{
my_zlog_warn("音频配置初始化失败");
}
if (audio_init() == 0)
{
my_zlog_info("音频命令执行初始化成功");
}
// 3. 在这里检查网络。如果没网 -> 进入扫码配网 (死循环直到成功)
check_and_autoconfig_wifi();
if (request_date() != 0)
{
my_zlog_error("请求数据失败");
......@@ -50,10 +65,7 @@ int main()
return -8;
}
if (audio_config_init() != 0)
{
my_zlog_warn("音频配置初始化失败");
}
// 音频初始化已移至开头
if (hardware_iic_init() != 0)
{
......@@ -66,10 +78,7 @@ int main()
my_zlog_warn("该设备没有冷却");
}
if (audio_init() == 0)
{
my_zlog_info("音频命令执行初始化成功");
}
int thread_rc = thread_start_init(thread_exit_time, thread_mqtt_beat,
thread_open_browser, thread_mqtt_reconnect, thread_time_calculation, thread_play_mp3);
......@@ -79,6 +88,9 @@ int main()
return -7;
}
// 初始化全部完成,播放“连接成功”提示音,作为系统就绪的标志
play_audio_file("connectionSuccessful.mp3");
thread_end_close();
device_end_close(g_device_type);
self_control_thread_close(); // 销毁自控的线程
......
#include "wifi_autoconfig.h"
#include "main.h"
#include "cJSON.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#define AUDIO_BASE_URL "https://fcrs-1367068685.cos.ap-guangzhou.myqcloud.com/car/audio/"
static const char *AUDIO_FILES[] = {
"noCameraDetected.mp3",
"connectionFailed.mp3",
"connectionSuccessful.mp3",
"scanSuccessful.mp3",
"toScanQRCode.mp3"
};
// 检查命令是否存在 (前置声明)
static int is_command_available(const char *cmd);
// 播放 ~/audio/ 下的音频文件
// 播放 ~/audio/ 下的音频文件,如果不存在则回退系统音
void play_audio_file(const char *filename) {
char cmd[512];
const char *audio_dir = "/home/orangepi/audio"; // 固定路径
char filepath[256];
snprintf(filepath, sizeof(filepath), "%s/%s", audio_dir, filename);
my_zlog_debug("尝试播放音频: %s", filename);
// 1. 检查自定义文件是否存在
if (access(filepath, F_OK) == 0) {
// 文件存在,优先使用 ffplay
if (is_command_available("ffplay")) {
snprintf(cmd, sizeof(cmd), "ffplay -nodisp -autoexit -loglevel quiet \"%s\"", filepath);
if (system(cmd) == 0) {
my_zlog_debug("ffplay 播放成功");
return;
}
}
// 其次 paplay
if (is_command_available("paplay")) {
snprintf(cmd, sizeof(cmd), "paplay \"%s\"", filepath);
if (system(cmd) == 0) {
my_zlog_debug("paplay 播放成功");
return;
}
}
my_zlog_warn("自定义音频播放失败,尝试回退系统音...");
} else {
my_zlog_warn("音频文件 %s 不存在,准备播放系统回退音。", filepath);
}
// 2. 文件不存在,或者播放工具缺失 -> 回退到系统默认声音
// 根据文件名映射一下大概的系统音
const char *sys_sound = "dialog-information"; // 默认
if (strstr(filename, "noCamera")) sys_sound = "software-error";
else if (strstr(filename, "Failed")) sys_sound = "dialog-error";
else if (strstr(filename, "Success")) sys_sound = "service-login";
else if (strstr(filename, "toScan")) sys_sound = "dialog-question";
// 尝试播放系统音
if (is_command_available("paplay")) {
snprintf(cmd, sizeof(cmd), "paplay /usr/share/sounds/ubuntu/stereo/%s.ogg", sys_sound);
if (system(cmd) == 0) {
my_zlog_debug("系统音 (paplay-ubuntu) 播放成功: %s", sys_sound);
return;
}
snprintf(cmd, sizeof(cmd), "paplay /usr/share/sounds/freedesktop/stereo/%s.oga", sys_sound);
if (system(cmd) == 0) {
my_zlog_debug("系统音 (paplay-freedesktop) 播放成功: %s", sys_sound);
return;
}
}
if (is_command_available("ffplay")) {
snprintf(cmd, sizeof(cmd), "ffplay -nodisp -autoexit -loglevel quiet /usr/share/sounds/ubuntu/stereo/%s.ogg", sys_sound);
if (system(cmd) == 0) {
my_zlog_debug("系统音 (ffplay) 播放成功: %s", sys_sound);
return;
}
}
my_zlog_error("所有播放尝试均失败!");
}
// 下载音频文件
static void download_audio_files() {
const char *audio_dir = "/home/orangepi/audio"; // 固定路径
// 1. 检查并创建目录
struct stat st = {0};
if (stat(audio_dir, &st) == -1) {
my_zlog_info("正在创建音频目录: %s", audio_dir);
mkdir(audio_dir, 0755);
}
// 2. 检查并下载每个文件
for (int i = 0; i < 5; i++) {
char filepath[512];
snprintf(filepath, sizeof(filepath), "%s/%s", audio_dir, AUDIO_FILES[i]);
if (access(filepath, F_OK) != 0) {
my_zlog_info("正在下载音频文件: %s", AUDIO_FILES[i]);
char cmd[1024];
// 使用 wget -q (安静模式) -P (指定目录)
snprintf(cmd, sizeof(cmd), "wget -q -P \"%s\" \"%s%s\"", audio_dir, AUDIO_BASE_URL, AUDIO_FILES[i]);
if (system(cmd) != 0) {
my_zlog_warn("下载失败: %s", AUDIO_FILES[i]);
}
} else {
// my_zlog_debug("文件已存在: %s", AUDIO_FILES[i]);
}
}
}
// 检查命令是否存在
static int is_command_available(const char *cmd) {
char check_cmd[256];
snprintf(check_cmd, sizeof(check_cmd), "which %s > /dev/null 2>&1", cmd);
return system(check_cmd) == 0;
}
// 检查并安装依赖
static void check_and_install_dependencies() {
int need_install = 0;
char packages[256] = "";
// 检查拍照工具
if (!is_command_available("fswebcam")) {
my_zlog_warn("未检测到 fswebcam,准备安装...");
strcat(packages, " fswebcam");
need_install = 1;
}
// 检查扫码工具 (zbarimg 包含在 zbar-tools 中)
if (!is_command_available("zbarimg")) {
my_zlog_warn("未检测到 zbar-tools,准备安装...");
strcat(packages, " zbar-tools");
need_install = 1;
}
// 检查音频工具
int has_audio_tool = 0;
if (is_command_available("paplay") || is_command_available("ffplay")) {
has_audio_tool = 1;
}
if (!has_audio_tool) {
my_zlog_warn("未检测到 paplay 或 ffplay,准备安装 pulseaudio-utils...");
// 只有在没音频工具时才安装
strcat(packages, " pulseaudio-utils");
need_install = 1;
}
if (need_install) {
my_zlog_info("正在尝试自动安装依赖: %s (需要 sudo 权限)...", packages);
char install_cmd[512];
snprintf(install_cmd, sizeof(install_cmd), "sudo apt-get update && sudo apt-get install -y %s", packages);
int ret = system(install_cmd);
if (ret == 0) {
my_zlog_info("依赖安装成功!");
} else {
my_zlog_error("依赖安装失败,自动配网功能可能无法正常使用。");
}
} else {
my_zlog_info("所需依赖 (fswebcam, zbar-tools, audio) 已就绪。");
}
}
// 检测是否有互联网连接 (只检查百度)
static int has_internet_connection() {
// -c 1: 发送1个包, -W 2: 超时2秒
int ret = system("ping -c 1 -W 2 baidu.com > /dev/null 2>&1");
// ret == 0 表示 ping 成功
return (ret == 0);
}
// 尝试连接 WiFi
static int try_connect_wifi(const char *ssid, const char *password) {
char cmd[512];
// 使用 nmcli 连接,成功会自动保存为默认
snprintf(cmd, sizeof(cmd), "nmcli dev wifi connect \"%s\" password \"%s\"", ssid, password);
my_zlog_info("正在尝试连接 WiFi: %s ...", ssid);
return system(cmd) == 0;
}
// 自动配网主逻辑
void check_and_autoconfig_wifi() {
my_zlog_info("开始检查网络连接状态...");
// 1. 检查并处理依赖
check_and_install_dependencies();
// 2. 检查网络
if (has_internet_connection()) {
my_zlog_info("网络连接正常,正在检查音频资源...");
download_audio_files();
return;
}
my_zlog_warn("无法连接互联网,进入扫码配网模式 (拍照方案)。");
my_zlog_info("进入扫码循环,将每隔几秒提示一次...");
const char *img_path = "/tmp/wifi_scan.jpg";
time_t last_prompt_time = 0;
// 首次播放
// play_audio_file("toScanQRCode.mp3"); // 改为进入循环后由定时逻辑触发(且会先检查网络)
last_prompt_time = 0; // 设为 0,确保进入循环第一次就会满足 difftime > 10.0 并触发播放逻辑
while (1) {
// 0. 优先检查网络是否已恢复 (比如插上了网线)
if (has_internet_connection()) {
my_zlog_info("检测到网络已恢复,退出扫码模式。");
// 补一声连接成功的提示,让用户知道好了
play_audio_file("connectionSuccessful.mp3");
download_audio_files();
break;
}
// 1. 周期性播放提示音 (每 10 秒)
time_t now = time(NULL);
if (difftime(now, last_prompt_time) >= 10.0) {
// 再检查一次,如果有网就不播了,避免干扰
if (!has_internet_connection()) {
play_audio_file("toScanQRCode.mp3");
}
last_prompt_time = now;
}
// 2. 调用 fswebcam 拍照
// -r 640x480: 分辨率
// --no-banner: 不加时间戳条
// -S 2: 跳过前2帧(预热), 防止黑屏
// -q: 静默模式
char cap_cmd[256];
snprintf(cap_cmd, sizeof(cap_cmd), "fswebcam -r 1280x720 --no-banner -S 2 -q %s > /dev/null 2>&1", img_path);
int cap_ret = system(cap_cmd);
if (cap_ret != 0) {
// 拍照失败,通常意味着没插摄像头或设备忙
my_zlog_error("摄像头拍照失败 (fswebcam 返回 %d),请检查设备连接。", cap_ret);
play_audio_file("noCameraDetected.mp3");
sleep(10); // 失败后多睡一会儿
continue;
}
// 3. 调用 zbarimg 识别图片
char scan_cmd[256];
snprintf(scan_cmd, sizeof(scan_cmd), "zbarimg --raw -q %s", img_path);
FILE *pipe = popen(scan_cmd, "r");
if (!pipe) {
my_zlog_error("无法执行 zbarimg!");
sleep(2);
continue;
}
char buffer[1024];
int scan_success = 0;
// zbarimg 输出即为识别结果 (可能有多行,我们只读第一行有效的)
while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
buffer[strcspn(buffer, "\r\n")] = 0;
if (strlen(buffer) == 0) continue;
my_zlog_debug("识别到内容: %s", buffer);
cJSON *json = cJSON_Parse(buffer);
if (!json) continue;
cJSON *ssid_item = cJSON_GetObjectItemCaseSensitive(json, "s");
cJSON *pwd_item = cJSON_GetObjectItemCaseSensitive(json, "p");
if (cJSON_IsString(ssid_item) && ssid_item->valuestring &&
cJSON_IsString(pwd_item) && pwd_item->valuestring) {
my_zlog_info("解析成功,SSID: %s", ssid_item->valuestring);
play_audio_file("scanSuccessful.mp3");
if (try_connect_wifi(ssid_item->valuestring, pwd_item->valuestring)) {
my_zlog_info("WiFi 连接成功!");
download_audio_files();
play_audio_file("connectionSuccessful.mp3");
cJSON_Delete(json);
scan_success = 1;
break;
} else {
my_zlog_warn("WiFi 连接失败");
play_audio_file("connectionFailed.mp3");
}
}
cJSON_Delete(json);
}
pclose(pipe);
if (scan_success) break;
// 没扫到码,等待一小会儿再拍下一张,避免 CPU 占用过高
// 不需要 sleep 太久,因为 fswebcam 启动本身就有开销(约0.5-1s),这就已经是天然的延迟了
usleep(500000); // 0.5秒
}
// 清理临时文件
unlink(img_path);
my_zlog_info("配网流程结束。");
}
#ifndef WIFI_AUTOCONFIG_H__
#define WIFI_AUTOCONFIG_H__
// 启动断网自动配网流程
void check_and_autoconfig_wifi();
// 播放指定名称的音频文件 (位于 ~/audio/ 目录下)
void play_audio_file(const char *filename);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment