bonus-edge-proxy/src/light_control/light_controller.cc

194 lines
6.2 KiB
C++
Raw Normal View History

// #include "light_controller.hpp"
// #include <iostream>
// // 构造函数
// 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;
// }
2026-01-21 11:04:34 +08:00
#include "light_controller.hpp"
#include <iostream>
#include <thread>
#include "spdlog/spdlog.h"
2026-01-21 11:04:34 +08:00
LightController::LightController(std::string baseUrl, std::string token)
: baseUrl(baseUrl), token(token) {}
2026-01-21 11:04:34 +08:00
LightController::~LightController() {}
2026-01-21 11:04:34 +08:00
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) {
2026-01-21 11:04:34 +08:00
CURL* curl;
CURLcode res;
std::string readBuffer;
long httpCode = 0;
bool success = false;
spdlog::info("Send Http Command:{}|{} ", deviceId, switchType);
2026-01-21 11:04:34 +08:00
curl = curl_easy_init();
if (curl) {
spdlog::info("Start Send");
2026-01-21 11:04:34 +08:00
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));
2026-01-21 11:04:34 +08:00
} else {
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
if (httpCode == 200)
2026-01-21 11:04:34 +08:00
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<std::mutex> 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<std::mutex> 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<std::mutex> lock(vote_mutex_);
for (auto& pair : light_votes_) {
std::string deviceId = pair.first;
std::set<std::string>& 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();
}
}
}
2026-01-21 11:04:34 +08:00
}