#define CPPHTTPLIB_OPENSSL_SUPPORT
#include <TuyaBulbBaciImpl.h>
#include <stdexcept>
// Extras
#define SHA256_HASH_SIZE 32
using json = nlohmann::json;
TuyaBulbBaciImpl::TuyaBulbBaciImpl(const ACE_CString& name, maci::ContainerServices* containerServices) : CharacteristicComponentImpl(name, containerServices),
api_region("us"),
client_id("..."),
api_secret("..."),
device_id("..."),
base_url("https://openapi.tuyaus.com"),
m_status_p(0)
{
std::cout << "Constructing TuyaBulbBaciImpl object." << std::endl;
token = getToken();
TuyaBulbBaciDevIO<bool>* m_booleanDevIO = new TuyaBulbBaciDevIO<bool>(this);
m_status_p = new baci::ROboolean(name + ":status", getComponent(), m_booleanDevIO);
CHARACTERISTIC_COMPONENT_PROPERTY(status, m_status_p);
// std::cout << "API Region: " << this->api_region << std::endl;
// std::cout << "Client ID: " << this->client_id << std::endl;
// std::cout << "API Secret: " << this->api_secretExtras
#define SHA256_HASH_SIZE 32
using json = nlohmann::json;
TuyaBulbBaciImpl::TuyaBulbBaciImpl(const ACE_CString& name, maci::ContainerServices* containerServices) : CharacteristicComponentImpl(name, containerServices),
api_region("us"),
client_id("..."),
api_secret("..."),
device_id("..."),
base_url("https://openapi.tuyaus.com"),
m_status_p(0)
{
std::cout << "Constructing TuyaBulbBaciImpl object." << std::endl;
token = getToken();
m_status_p = new baci::ROboolean(name + ":status", getComponent());
CHARACTERISTIC_COMPONENT_PROPERTY(status, m_status_p);
// std::cout << "API Region: " << this->api_region << std::endl;
// std::cout << "Client ID: " << this->client_id << std::endl;
// std::cout << "API Secret: " << this->api_secret << std::endl;
// std::cout << "Device ID: " << this->device_id << std::endl;
// std::cout << "API Token: " << this->token << std::endl;
}
TuyaBulbBaciImpl::~TuyaBulbBaciImpl() {
if (m_status_p != 0) {
m_status_p->destroy();
m_status_p=0;
}
}
void TuyaBulbBaciImpl::turnOn() {
std::cout << "Turning smart bulb ON..." << std::endl;
// Set request parameters
const std::string uri = "/iot-03/devices/" + this->device_id + "/commands";
const std::string action = "POST";
const std::string headers_str = "";
const std::string body = "{\"commands\":[{\"code\":\"switch_led\",\"value\":true}]}";
const std::string body_sha256 = "8479c9c60cd5d531054c49333c7b361a9ce41b9b313ab8eb6bc9df4141f658ef";
std::map<std::string, std::string> headers_map;
headers_map = {
{"Content-type", "application/json"},
{"access_token", this->token}
};
// Send request and print response
httplib::Result response = this->sendRequest(uri, action, headers_map, headers_str, body, body_sha256);
std::cout << "Response status:\n";
std::cout << response->status << std::endl;
// std::cout << "ResponseDevice bodyID:\n" " << this->device_id << std::endl;
// std::cout << response->body"API Token: " << this->token << std::endl;
}
// Check API response
if (response->status == 200) {
json body = json::parse(response->body);
TuyaBulbBaciImpl::~TuyaBulbBaciImpl() {
if (m_status_p != 0) {
m_status_p->destroy();
m_status_p=0;
}
}
void TuyaBulbBaciImpl::turnOn() {
std::cout << "Turning smart if (body["success"].dump() == "true") {bulb ON..." << std::endl;
// Set request parameters
m_status_p = new baci::ROboolean(true);
} else {const std::string uri = "/iot-03/devices/" + this->device_id + "/commands";
const std::string action = "POST";
throwconst std::runtime_error("Error while turning smart bulb ON.\n")string headers_str = "";
const std::string body = "{\"commands\":[{\"code\":\"switch_led\",\"value\":true}]}";
const std::string body_sha256 = }"8479c9c60cd5d531054c49333c7b361a9ce41b9b313ab8eb6bc9df4141f658ef";
}
}
void TuyaBulbBaciImpl::turnOff() {
std::cout << "Turning smart bulb OFF..." << std::endl;
std::map<std::string, std::string> headers_map;
// Set request parametersheaders_map = {
const std::string uri = {"/iot-03/devices/" + this->device_id + "/commands";Content-type", "application/json"},
const std::string action = {"POST";
const std::stringaccess_token", this->token}
};
// Send request and print response
httplib::Result response = this->sendRequest(uri, action, headers_map, headers_str, = ""body, body_sha256);
const// std::stringcout body<< = "{\"commands\":[{\"code\":\"switch_led\",\"value\":false}]}""Response status:\n";
// std::cout << response->status << std::endl;
const// std::stringcout body_sha256 = "c9df53ad98d9c9be68680613d9ece634a27f102c5e40c7b5f60c11f6b944b6a9"<< "Response body:\n";
std::map<std::string,// std::string> headers_map;
cout << response->body << std::endl;
headers_map = {// Check API response
if (response->status == 200) {"Content-type", "application/json"},
{"access_token", this->token}
};
json body = json::parse(response->body);
// Send request and print response
httplib::Result response = this->sendRequest(uri, action, headers_map, headers_str, body, body_sha256);
if (body["success"].dump() == "true") {
std::cout << "Response status:\n";
std::cout << response->statusDevice turned ON successfully." << std::endl;
std::cout << "Response body:\n";
} else {
throw std::cout << response->body << std::endl;
runtime_error("Error while turning smart bulb ON.\n");
// Check API response}
if (response->status == 200}
}
void TuyaBulbBaciImpl::turnOff() {
json body = json::parse(response->body);
std::cout << "Turning smart bulb OFF..." << std::endl;
// Set request parameters
const if (body["success"].dump() == "true") {
std::string uri = "/iot-03/devices/" + this->device_id + "/commands";
const std::string m_status_p = new baci::ROboolean(false)action = "POST";
const std::string headers_str } else {= "";
throw const std::runtime_error("Error while turning smart bulb OFF.\n");
}string body = "{\"commands\":[{\"code\":\"switch_led\",\"value\":false}]}";
}
}
httplib::Result TuyaBulbBaciImpl::sendRequest(
constconst std::string body_sha256 = "c9df53ad98d9c9be68680613d9ece634a27f102c5e40c7b5f60c11f6b944b6a9";
std::map<std::string, std::string uri,string> headers_map;
headers_map = {
const std::string action,
const std::map<std::string, std::string> headers_map{"Content-type", "application/json"},
const std::string headers_str,{"access_token", this->token}
};
const std::string body,
// Send request and print response
const std::stringhttplib::Result response = this->sendRequest(uri, action, headers_map, headers_str, body, body_sha256,
);
// std::cout << "Response status:\n";
const// std::stringcout version
<< response->status ) {<< std::endl;
// https://developer.tuya.com/en/docs/iot/api-request?id=Ka4a8uuo1j4t4
// https://developer.tuya.com/en/docs/iot/singnature?id=Ka43a5mtx1gscstd::cout << "Response body:\n";
// std::cout << "Sending request to Tuya API " << uri response->body << std::endl;
// StringCheck stringToSignAPI = response
// HTTPMethod + "\n" +
// Content-SHA256 + "\n" +
// Headers + "\n" +
// Url
const std::string url = "/" + version + uriif (response->status == 200) {
json body = json::parse(response->body);
if (body["success"].dump() == "true") {
std::cout << "Device turned OFF successfully." << std::endl;
const std::string string_to_sign = action} + "\n" + body_sha256 + "\n" + headers_str + "\n" + url;
// Get time in milliseconds since epoch, with 13 digits
std::time_t t = std::time(nullptr) * 1000;
// str = client_id + access_token + t + nonce + stringToSign
// sign = HMAC-SHA256(str, secret).toUpperCase()
std::string str_data;
if (this->token.empty()) {
str_data = this->client_id + std::to_string(t) + string_to_sign;
} else {else {
throw std::runtime_error("Error while turning smart bulb OFF.\n");
}
}
}
httplib::Result TuyaBulbBaciImpl::sendRequest(
const std::string uri,
const std::string action,
const std::map<std::string, std::string> headers_map,
const std::string headers_str,
const std::string body,
const std::string body_sha256,
str_data = this->client_id + this->token + const std::to_string(t) + string_to_sign;
version
) }
{
// Allocate memory for the HMAC
std::vector<uint8_t> out(SHA256_HASH_SIZE);
// Call hmac-sha256 function and parse result to string stream
hmac_sha256(this->api_secret.data(), this->api_secret.size(), str_data.data(), str_data.size(),
out.data(), out.size());
std::stringstream ss_result;
for (uint8_t i : out) {
ss_result << std::hex << std::setfill('0') << std::setw(2) << (int)i;
}
// to uppercase
std::string sign = ss_result.str();
transform(sign.begin(), sign.end(), sign.begin(), ::toupper)https://developer.tuya.com/en/docs/iot/api-request?id=Ka4a8uuo1j4t4
// https://developer.tuya.com/en/docs/iot/singnature?id=Ka43a5mtx1gsc
std::cout << "Sending request to Tuya API " << uri << std::endl;
// String stringToSign =
// HTTPMethod + "\n" +
// Content-SHA256 + "\n" +
// Headers + "\n" +
// Url
const std::string url = "/" + version + uri;
const std::string string_to_sign = action + "\n" + body_sha256 + "\n" + headers_str + "\n" + url;
// CreateGet base headerstime in milliseconds since epoch, with 13 digits
httplibstd::Headers request_headerstime_t t = {
std::time(nullptr) * 1000;
// str {= "client_id", this->client_id },
+ access_token + t + nonce + stringToSign
{// "sign_method", "sign = HMAC-SHA256" },(str, secret).toUpperCase()
std::string str_data;
{ "sign", sign },
if (this->token.empty()) {
str_data = { "t",this->client_id + std::to_string(t) }+ string_to_sign;
};
else {
// Add extra headers
str_data std::map<std::string, std::string>::const_iterator it;
for (it = headers_map.begin(); it != headers_map.end(); it++) {
request_headers.insert({ it->first, it->second });
}
// Create HTTPS client
httplib::Client cli(this->base_url);
// Send request
if (action.compare("GET") == 0) {
= this->client_id + this->token + std::to_string(t) + string_to_sign;
}
// Allocate memory for the HMAC
std::vector<uint8_t> out(SHA256_HASH_SIZE);
// Call hmac-sha256 function and parse result to string stream
hmac_sha256(this->api_secret.data(), this->api_secret.size(), str_data.data(), str_data.size(),
return cliout.Get(url.c_str(), request_headersdata(), out.size());
}
else {
std::stringstream ss_result;
returnfor cli.Post(url.c_str(), request_headers, body.c_str(), "application/json");
}
}
std::string TuyaBulbBaciImpl::getToken() {(uint8_t i : out) {
ss_result << std::hex << std::setfill('0') << std::setw(2) << (int)i;
}
// https://openapi.tuyaus.com/v1.0/token?grant_type=1 to uppercase
const std::string urisign = "/token?grant_type=1"ss_result.str();
httplib::Result response = this->sendRequest(uritransform(sign.begin(), sign.end(), sign.begin(), ::toupper);
// CheckCreate APIbase responseheaders
if (response->statushttplib::Headers request_headers == 200) {
json body = json::parse(response->body);
{ "client_id", this->client_id },
{ "sign_method", "HMAC-SHA256" },
if{ (body["success"].dump() == "true") {sign", sign },
{ const "t", std::to_string token = body["result"]["access_token"];
(t) }
};
// Add extra headers
return tokenstd::map<std::string, std::string>::const_iterator it;
for (it = }
}
headers_map.begin(); it != headers_map.end(); it++) {
throw std::runtime_error("Error while getting API token.\n");
}
ACS::ROboolean_ptr TuyaBulbBaciImpl::status () {
if(m_status_prequest_headers.insert({ it->first, it->second });
}
// Create HTTPS client
httplib::Client cli(this->base_url);
// Send request
if (action.compare("GET") == 0) {
return ACS::ROboolean::_nil();
}
ACS::ROboolean_var prop = ACS::ROboolean::_narrow(m_status_p->getCORBAReference());
return prop._retn();
}
/* --------------- [ MACI DLL support functions ] -----------------*/
#include <maciACSComponentDefines.h>
MACI_DLL_SUPPORT_FUNCTIONS(TuyaBulbBaciImpl)
/* ----------------------------------------------------------------*/ |