2026-01-23 16:41:00 +08:00
|
|
|
// #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>
|
2026-01-23 16:41:00 +08:00
|
|
|
#include <thread>
|
|
|
|
|
|
|
|
|
|
#include "spdlog/spdlog.h"
|
2026-01-21 11:04:34 +08:00
|
|
|
|
|
|
|
|
LightController::LightController(std::string baseUrl, std::string token)
|
2026-01-23 16:41:00 +08:00
|
|
|
: baseUrl(baseUrl), token(token) {}
|
2026-01-21 11:04:34 +08:00
|
|
|
|
2026-01-23 16:41:00 +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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-23 16:41:00 +08:00
|
|
|
// 底层 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;
|
2026-01-23 16:41:00 +08:00
|
|
|
spdlog::info("Send Http Command:{}|{} ", deviceId, switchType);
|
2026-01-21 11:04:34 +08:00
|
|
|
curl = curl_easy_init();
|
|
|
|
|
if (curl) {
|
2026-01-23 16:41:00 +08:00
|
|
|
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) {
|
2026-01-23 16:41:00 +08:00
|
|
|
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);
|
2026-01-23 16:41:00 +08:00
|
|
|
if (httpCode == 200)
|
2026-01-21 11:04:34 +08:00
|
|
|
success = true;
|
|
|
|
|
}
|
|
|
|
|
curl_slist_free_all(headers);
|
|
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
|
}
|
|
|
|
|
return success;
|
2026-01-23 16:41:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 手动控制:直接执行,并清空该设备的投票箱(打断自动逻辑)
|
|
|
|
|
// 手动控制:强制覆盖,并清空该设备的投票箱
|
|
|
|
|
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
|
|
|
}
|