Add support for Kasa Smart LED light strips

This commit is contained in:
mfletcher_2 2024-06-02 00:18:35 +00:00 committed by Adam Honse
parent 1526cbec6c
commit a7e76b5869
3 changed files with 123 additions and 16 deletions

View file

@ -111,6 +111,32 @@ bool KasaSmartController::Initialize()
return is_initialized;
}
std::string model;
if(system_information["system"]["get_sysinfo"].contains("model"))
{
model = system_information["system"]["get_sysinfo"]["model"];
}
else
{
/*-----------------------*\
| Can't find device model |
\*-----------------------*/
return is_initialized;
}
if(model.find("KL420") != std::string::npos)
{
kasa_type = KASA_SMART_TYPE_KL420;
}
else if(model.find("KL4") != std::string::npos)
{
kasa_type = KASA_SMART_TYPE_OTHER_LEDSTRIP;
}
else
{
kasa_type = KASA_SMART_TYPE_LIGHT;
}
firmware_version = system_information["system"]["get_sysinfo"]["sw_ver"];
module_name = system_information["system"]["get_sysinfo"]["model"];
device_id = system_information["system"]["get_sysinfo"]["deviceId"];
@ -152,7 +178,12 @@ std::string KasaSmartController::GetUniqueID()
return(device_id);
}
void KasaSmartController::SetColor(unsigned char red, unsigned char green, unsigned char blue)
int KasaSmartController::GetKasaType()
{
return(kasa_type);
}
void KasaSmartController::SetColor(unsigned char red, unsigned char green, unsigned char blue, int device_type)
{
if(!is_initialized)
{
@ -192,14 +223,22 @@ void KasaSmartController::SetColor(unsigned char red, unsigned char green, unsig
\*----------------------------*/
if(normalized_saturation == 0 && normalized_value == 0)
{
TurnOff();
TurnOff(device_type);
return;
}
/*------------------------------*\
| Format set light state command |
\*------------------------------*/
const std::string set_lightstate_command_format(KASA_SMART_SET_LIGHT_STATE_COMMAND_FORMAT);
std::string set_lightstate_command_format;
if(device_type == DEVICE_TYPE_LIGHT)
{
set_lightstate_command_format = KASA_SMART_LIGHT_SET_LIGHT_STATE_COMMAND_FORMAT;
}
else if(device_type == DEVICE_TYPE_LEDSTRIP)
{
set_lightstate_command_format = KASA_SMART_LEDSTRIP_SET_LIGHT_STATE_COMMAND_FORMAT;
}
int size = std::snprintf(nullptr, 0, set_lightstate_command_format.c_str(), normalized_hue, normalized_saturation, normalized_value) + 1;
if(size <= 0)
{
@ -219,14 +258,43 @@ void KasaSmartController::SetColor(unsigned char red, unsigned char green, unsig
port.tcp_close();
}
void KasaSmartController::TurnOff()
void KasaSmartController::SetEffect(std::string effect)
{
if(!is_initialized)
{
return;
}
const std::string turn_off_command(KASA_SMART_OFF_COMMAND);
/*-------------------*\
| Open TCP connection |
\*-------------------*/
if(!port.connected && !port.tcp_client_connect() && ++retry_count >= KASA_SMART_MAX_CONNECTION_ATTEMPTS)
{
is_initialized = false;
return;
}
std::string response;
KasaSmartController::SendCommand(effect, response);
port.tcp_close();
}
void KasaSmartController::TurnOff(int device_type)
{
if(!is_initialized)
{
return;
}
std::string turn_off_command;
if(device_type == DEVICE_TYPE_LIGHT)
{
turn_off_command = KASA_SMART_LIGHT_OFF_COMMAND;
}
else if(device_type == DEVICE_TYPE_LEDSTRIP)
{
turn_off_command = KASA_SMART_LEDSTRIP_OFF_COMMAND;
}
if(!port.connected && !port.tcp_client_connect() && ++retry_count >= KASA_SMART_MAX_CONNECTION_ATTEMPTS)
{

View file

@ -19,8 +19,16 @@
enum
{
KASA_SMART_MODE_DIRECT = 0x00,
KASA_SMART_MODE_OFF = 0x01
KASA_SMART_MODE_DIRECT = 0x00,
KASA_SMART_MODE_OFF = 0x01,
KASA_SMART_MODE_RAINBOW = 0x02
};
enum
{
KASA_SMART_TYPE_KL420 = 0x00,
KASA_SMART_TYPE_OTHER_LEDSTRIP = 0x01,
KASA_SMART_TYPE_LIGHT = 0x02
};
#define KASA_SMART_INITIALIZATION_VECTOR 0xAB
@ -31,9 +39,14 @@ enum
| Kasa Smart Light Commands |
\*-------------------------*/
#define KASA_SMART_SYSTEM_INFO_QUERY "{\"system\": {\"get_sysinfo\": {}}}"
#define KASA_SMART_OFF_COMMAND "{\"smartlife.iot.smartbulb.lightingservice\": {\"transition_light_state\": {\"transition_period\": 0, \"on_off\":0, \"mode\":\"normal\"}}}"
const char KASA_SMART_SET_LIGHT_STATE_COMMAND_FORMAT[] = "{\"smartlife.iot.smartbulb.lightingservice\": {\"transition_light_state\": {\"transition_period\": 0, \"on_off\""
#define KASA_SMART_LIGHT_OFF_COMMAND "{\"smartlife.iot.smartbulb.lightingservice\": {\"transition_light_state\": {\"transition_period\": 0, \"on_off\":0, \"mode\":\"normal\"}}}"
const char KASA_SMART_LIGHT_SET_LIGHT_STATE_COMMAND_FORMAT[] = "{\"smartlife.iot.smartbulb.lightingservice\": {\"transition_light_state\": {\"transition_period\": 0, \"on_off\""
":1, \"mode\":\"normal\", \"hue\": %u, \"saturation\": %u, \"brightness\": %u, \"color_temp\": 0}}}";
#define KASA_SMART_LEDSTRIP_OFF_COMMAND "{\"smartlife.iot.lightStrip\": {\"set_light_state\": {\"transition\": 0, \"on_off\":0, \"mode\":\"normal\"}}}"
const char KASA_SMART_LEDSTRIP_SET_LIGHT_STATE_COMMAND_FORMAT[] = "{\"smartlife.iot.lightStrip\": {\"set_light_state\": {\"transition\": 0, \"on_off\""
":1, \"mode\":\"normal\", \"hue\": %u, \"saturation\": %u, \"brightness\": %u, \"color_temp\": 0}}}";
#define KASA_SMART_EFFECT_RAINBOW_COMMAND "{\"smartlife.iot.lighting_effect\":{\"set_lighting_effect\":{\"custom\":0,\"direction\":1,\"duration\":0,\"enable\":1,\"expansion_strategy\":1,\"name\":\"Rainbow\",\"repeat_times\":0,\"segments\":[0],\"sequence\":[[0,100,100],[100,100,100],[200,100,100],[300,100,100]],\"spread\":12,\"transition\":1500,\"type\":\"sequence\"}}}}"
class KasaSmartController
{
@ -46,10 +59,12 @@ public:
std::string GetVersion();
std::string GetManufacturer();
std::string GetUniqueID();
int GetKasaType();
bool Initialize();
void SetColor(unsigned char red, unsigned char green, unsigned char blue);
void TurnOff();
void SetColor(unsigned char red, unsigned char green, unsigned char blue, int device_type);
void SetEffect(std::string effect);
void TurnOff(int device_type);
private:
net_port port;
@ -60,6 +75,7 @@ private:
std::string module_name;
std::string device_id;
std::string location;
int kasa_type;
bool SendCommand(std::string command, std::string &response);
static unsigned char* Encrypt(const std::string request);
static std::string Decrypt(const unsigned char*, int length, std::string &response);

View file

@ -28,12 +28,21 @@ RGBController_KasaSmart::RGBController_KasaSmart(KasaSmartController* controller
name = controller->GetManufacturer() + " " + controller->GetName();
vendor = controller->GetManufacturer();
type = DEVICE_TYPE_LIGHT;
version = controller->GetVersion();
description = "Kasa Smart Device";
serial = controller->GetUniqueID();
location = controller->GetLocation();
if(controller->GetKasaType() == KASA_SMART_TYPE_LIGHT)
{
type = DEVICE_TYPE_LIGHT;
}
else if(controller->GetKasaType() == KASA_SMART_TYPE_OTHER_LEDSTRIP
|| controller->GetKasaType() == KASA_SMART_TYPE_KL420)
{
type = DEVICE_TYPE_LEDSTRIP;
}
mode Direct;
Direct.name = "Direct";
Direct.value = KASA_SMART_MODE_DIRECT;
@ -41,6 +50,16 @@ RGBController_KasaSmart::RGBController_KasaSmart(KasaSmartController* controller
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
if(controller->GetKasaType() == KASA_SMART_TYPE_KL420)
{
mode Rainbow;
Rainbow.name = "Rainbow";
Rainbow.value = KASA_SMART_MODE_RAINBOW;
Rainbow.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Rainbow.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Rainbow);
}
mode Off;
Off.name = "Off";
Off.value = KASA_SMART_MODE_OFF;
@ -93,7 +112,7 @@ void RGBController_KasaSmart::DeviceUpdateLEDs()
unsigned char grn = RGBGetGValue(colors[0]);
unsigned char blu = RGBGetBValue(colors[0]);
controller->SetColor(red, grn, blu);
controller->SetColor(red, grn, blu, type);
}
void RGBController_KasaSmart::UpdateZoneLEDs(int /*zone*/)
@ -108,9 +127,13 @@ void RGBController_KasaSmart::UpdateSingleLED(int /*led*/)
void RGBController_KasaSmart::DeviceUpdateMode()
{
if(modes[active_mode].value == KASA_SMART_MODE_OFF)
switch(modes[active_mode].value)
{
controller->TurnOff();
return;
case KASA_SMART_MODE_OFF:
controller->TurnOff(type);
break;
case KASA_SMART_MODE_RAINBOW:
controller->SetEffect(KASA_SMART_EFFECT_RAINBOW_COMMAND);
break;
}
}