// #include "light_controller.hpp" // #include // // 构造函数 // LightController::LightController(std::string baseUrl, std::string token) // : baseUrl(baseUrl), token(token) { // // 可以在这里做全局初始化,或者在 main 中做 // } // LightController::~LightController() { // // 如果有需要释放的资源放在这里 // } // // 静态回调函数实现 // size_t LightController::WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { // ((std::string*)userp)->append((char*)contents, size * nmemb); // return size * nmemb; // } // // 核心控制逻辑 // bool LightController::ControlLight(std::string deviceId, std::string switchType) { // CURL* curl; // CURLcode res; // std::string readBuffer; // long httpCode = 0; // bool success = false; // curl = curl_easy_init(); // if (curl) { // // 拼接完整 URL // std::string url = this->baseUrl + "/hk_service/modbus/lightControl"; // // 设置 URL // curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // curl_easy_setopt(curl, CURLOPT_POST, 1L); // // 构造 Headers // struct curl_slist* headers = NULL; // std::string tokenHeader = "token: " + this->token; // headers = curl_slist_append(headers, tokenHeader.c_str()); // headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); // curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // // 构造 Body: deviceId=351&type=0 // std::string postData = "deviceId=" + deviceId + "&type=" + switchType; // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str()); // // 设置超时 (5秒) // curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L); // // 设置响应接收 // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); // curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); // // 执行请求 // res = curl_easy_perform(curl); // if (res != CURLE_OK) { // std::cerr << "[LightControl] 请求失败: " << curl_easy_strerror(res) << std::endl; // } else { // curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); // // 简单打印结果 // std::cout << "[LightControl] ID:" << deviceId // << " 动作:" << (switchType == "1" ? "开启" : "关闭") // << " -> 返回状态码: " << httpCode << std::endl; // // std::cout << "响应内容: " << readBuffer << std::endl; // 调试时可打开 // if (httpCode == 200) { // success = true; // } // } // // 清理 // curl_slist_free_all(headers); // curl_easy_cleanup(curl); // } // return success; // } #include "light_controller.hpp" #include #include #include "spdlog/spdlog.h" LightController::LightController(std::string baseUrl, std::string token) : baseUrl(baseUrl), token(token) {} LightController::~LightController() {} size_t LightController::WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } // 底层 HTTP 发送逻辑 bool LightController::SendHttpCommand(std::string deviceId, std::string switchType) { CURL* curl; CURLcode res; std::string readBuffer; long httpCode = 0; bool success = false; spdlog::info("Send Http Command:{}|{} ", deviceId, switchType); curl = curl_easy_init(); if (curl) { spdlog::info("Start Send"); std::string url = this->baseUrl + "/hk_service/modbus/lightControl"; curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1L); struct curl_slist* headers = NULL; std::string tokenHeader = "token: " + this->token; headers = curl_slist_append(headers, tokenHeader.c_str()); headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); std::string postData = "deviceId=" + deviceId + "&type=" + switchType; curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str()); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); res = curl_easy_perform(curl); if (res != CURLE_OK) { spdlog::error("[LightControl] Request failed: {}", curl_easy_strerror(res)); } else { curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); if (httpCode == 200) success = true; } curl_slist_free_all(headers); curl_easy_cleanup(curl); } return success; } // 手动控制:直接执行,并清空该设备的投票箱(打断自动逻辑) // 手动控制:强制覆盖,并清空该设备的投票箱 bool LightController::ControlLight(std::string deviceId, std::string switchType) { std::lock_guard lock(vote_mutex_); light_votes_.erase(deviceId); return SendHttpCommand(deviceId, switchType); } // [核心] 投票逻辑 void LightController::UpdateAutoLight(std::string deviceId, std::string sourceId, bool voteOn) { std::lock_guard lock(vote_mutex_); auto& votes = light_votes_[deviceId]; // "" bool was_on = !votes.empty(); // 之前有人吗? if (voteOn) { votes.insert(sourceId); // 投开灯票 } else { votes.erase(sourceId); // 撤销票 } bool is_on = !votes.empty(); // 现在还有人吗? // 只有状态改变才发请求 (去重) if (was_on != is_on) { std::string action = is_on ? "1" : "0"; spdlog::info("[AutoLight] Device {} State: {} -> {} (Votes: {})", deviceId, (was_on ? "ON" : "OFF"), (is_on ? "ON" : "OFF"), votes.size()); std::thread([this, deviceId, action]() { SendHttpCommand(deviceId, action); }).detach(); } } // [核心] 会话清理:摄像头掉线时自动撤票 void LightController::RemoveSession(std::string sourceId) { std::lock_guard lock(vote_mutex_); for (auto& pair : light_votes_) { std::string deviceId = pair.first; std::set& votes = pair.second; if (votes.count(sourceId)) { bool was_on = !votes.empty(); votes.erase(sourceId); // 强制撤票 bool is_on = !votes.empty(); // 如果撤票后没认了,关灯 if (was_on && !is_on) { spdlog::info("[AutoLight] Source {} disconnected. Turning OFF device {}.", sourceId, deviceId); std::thread([this, deviceId]() { SendHttpCommand(deviceId, "0"); }).detach(); } } } }