Implement direct control for v2 protocol (Canvas and Shapes), clean up some formatting with v1 to match.

This commit is contained in:
Adam Honse 2022-05-03 00:17:22 -05:00
parent 7276d254d6
commit e61b6cd3d7
3 changed files with 107 additions and 46 deletions

View file

@ -159,30 +159,77 @@ void NanoleafController::UpdateLEDs(std::vector<RGBColor>& colors)
if(model == NANOLEAF_LIGHT_PANELS_MODEL)
{
/*---------------------------------------------------------*\
| Protocol V1 - https://forum.nanoleaf.me/docs |
| |
| Size Description |
| --------------------------------------------------------- |
| 1 nPanels Number of panels |
| |
| 1 panelId ID of panel |
| 1 nFrames Number of frames (always 1) |
| 1 R Red channel |
| 1 G Green channel |
| 1 B Blue channel |
| 1 W White channel (ignored) |
| 1 transitionTime Transition time (x 100ms) |
\*---------------------------------------------------------*/
uint8_t size = panel_ids.size();
uint8_t* message = (uint8_t*)malloc(size*7+6+1);
uint8_t* message = (uint8_t*)malloc((size * 7) + 1);
message[0] = (uint8_t)size;
message[0] = (uint8_t)size; /* nPanels */
for(int i = 0; i < size; i++)
{
message[( 7 * i) + 0 + 1] = (uint8_t)panel_ids[i];
message[( 7 * i) + 1 + 1] = (uint8_t)1;
message[( 7 * i) + 2 + 1] = (uint8_t)RGBGetRValue(colors[i]);
message[( 7 * i) + 3 + 1] = (uint8_t)RGBGetGValue(colors[i]);
message[( 7 * i) + 4 + 1] = (uint8_t)RGBGetBValue(colors[i]);
message[( 7 * i) + 5 + 1] = (uint8_t)0;
message[( 7 * i) + 6 + 1] = (uint8_t)0;
message[(7 * i) + 0 + 1] = (uint8_t)panel_ids[i]; /* panelId */
message[(7 * i) + 1 + 1] = (uint8_t)1; /* nFrames */
message[(7 * i) + 2 + 1] = (uint8_t)RGBGetRValue(colors[i]); /* R */
message[(7 * i) + 3 + 1] = (uint8_t)RGBGetGValue(colors[i]); /* G */
message[(7 * i) + 4 + 1] = (uint8_t)RGBGetBValue(colors[i]); /* B */
message[(7 * i) + 5 + 1] = (uint8_t)0; /* W */
message[(7 * i) + 6 + 1] = (uint8_t)0; /* transitionTime */
}
external_control_socket.udp_write(reinterpret_cast<char*>(message), size*7+6+1);
external_control_socket.udp_write((char*)message, (size * 7) + 1);
}
else if(model == NANOLEAF_CANVAS_MODEL)
else if((model == NANOLEAF_CANVAS_MODEL)
|| (model == NANOLEAF_SHAPES_MODEL))
{
/*---------------------------------------------------------*\
| Insert V2 protocol implementation here. |
| Protocol V2 - https://forum.nanoleaf.me/docs |
| |
| Size Description |
| --------------------------------------------------------- |
| 2 nPanels Number of panels |
| |
| 2 panelId ID of panel |
| 1 R Red channel |
| 1 G Green channel |
| 1 B Blue channel |
| 1 W White channel (ignored) |
| 2 transitionTime Transition time (x 100ms) |
\*---------------------------------------------------------*/
uint8_t size = panel_ids.size();
uint8_t* message = (uint8_t*)malloc((size * 8) + 2);
message[0] = (uint8_t)(size >> 8); /* nPanels H */
message[1] = (uint8_t)(size & 0xFF); /* nPanels L */
for(int i = 0; i < size; i++)
{
message[(8 * i) + 0 + 2] = (uint8_t)(panel_ids[i] >> 8); /* panelId H */
message[(8 * i) + 1 + 2] = (uint8_t)(panel_ids[i] & 0xFF); /* panelId L */
message[(8 * i) + 2 + 2] = (uint8_t)RGBGetRValue(colors[i]); /* R */
message[(8 * i) + 3 + 2] = (uint8_t)RGBGetGValue(colors[i]); /* G */
message[(8 * i) + 4 + 2] = (uint8_t)RGBGetBValue(colors[i]); /* B */
message[(8 * i) + 5 + 2] = (uint8_t)0; /* W */
message[(8 * i) + 6 + 2] = (uint8_t)0; /* transitionTime H */
message[(8 * i) + 7 + 2] = (uint8_t)0; /* transitionTime L */
}
external_control_socket.udp_write((char *)message, (size * 8) + 2);
}
}
@ -192,21 +239,40 @@ void NanoleafController::StartExternalControl()
request["write"]["command"] = "display";
request["write"]["animType"] = "extControl";
/*-------------------------------------------------------------*\
| Determine whether to use v1 or v2 extControl protocol based |
| on model string |
\*-------------------------------------------------------------*/
if(model == NANOLEAF_LIGHT_PANELS_MODEL)
{
/*---------------------------------------------------------*\
| Protocol v1 returns IP and port for UDP communication |
\*---------------------------------------------------------*/
request["write"]["extControlVersion"] = "v1";
json response;
if((APIRequest("PUT", location, "/api/v1/"+auth_token+"/effects", &request, &response) / 100) == 2)
{
external_control_socket.udp_client(response["streamControlIpAddr"].get<std::string>().c_str(), std::to_string(response["streamControlPort"].get<int>()).c_str());
selectedEffect = NANOLEAF_DIRECT_MODE_EFFECT_NAME;
}
}
else if(model == NANOLEAF_CANVAS_MODEL)
else if((model == NANOLEAF_CANVAS_MODEL)
|| (model == NANOLEAF_SHAPES_MODEL))
{
/*---------------------------------------------------------*\
| Protocol v2 does not return anything, use device IP and |
| port 60222 |
\*---------------------------------------------------------*/
request["write"]["extControlVersion"] = "v2";
}
json response;
if((APIRequest("PUT", location, "/api/v1/"+auth_token+"/effects", &request, &response) / 100) == 2)
{
external_control_socket.udp_client(response["streamControlIpAddr"].get<std::string>().c_str(), std::to_string(response["streamControlPort"].get<int>()).c_str());
if((APIRequest("PUT", location, "/api/v1/"+auth_token+"/effects", &request) / 100) == 2)
{
external_control_socket.udp_client(address.c_str(), "60222");
selectedEffect = NANOLEAF_DIRECT_MODE_EFFECT_NAME;
selectedEffect = NANOLEAF_DIRECT_MODE_EFFECT_NAME;
}
}
}
@ -280,4 +346,4 @@ std::string NanoleafController::GetSelectedEffect()
int NanoleafController::GetBrightness()
{
return brightness;
};
};

View file

@ -14,6 +14,7 @@
#define NANOLEAF_DIRECT_MODE_EFFECT_NAME "*Dynamic*"
#define NANOLEAF_LIGHT_PANELS_MODEL "NL22"
#define NANOLEAF_CANVAS_MODEL "NL29"
#define NANOLEAF_SHAPES_MODEL "NL42"
class NanoleafController
{

View file

@ -25,28 +25,25 @@ RGBController_Nanoleaf::RGBController_Nanoleaf(std::string a_address, int a_port
type = DEVICE_TYPE_LIGHT;
/*-------------------------------------------------------------*\
| Direct mode currently only supported for Nanoleaf Panels. |
| Direct mode uses external control protocol. |
\*-------------------------------------------------------------*/
if(controller.GetModel() == NANOLEAF_LIGHT_PANELS_MODEL)
{
mode Direct;
Direct.name = "Direct";
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mode Direct;
Direct.name = "Direct";
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
/*---------------------------------------------------------*\
| Set this effect as current if the name is selected. |
\*---------------------------------------------------------*/
if(controller.GetSelectedEffect() == NANOLEAF_DIRECT_MODE_EFFECT_NAME)
{
/*-----------------------------------------------------*\
| If the direct mode is active, we need to call this |
| method to open the socket. |
\*-----------------------------------------------------*/
controller.StartExternalControl();
active_mode = 0;
}
/*---------------------------------------------------------*\
| Set this effect as current if the name is selected. |
\*---------------------------------------------------------*/
if(controller.GetSelectedEffect() == NANOLEAF_DIRECT_MODE_EFFECT_NAME)
{
/*-----------------------------------------------------*\
| If the direct mode is active, we need to call this |
| method to open the socket. |
\*-----------------------------------------------------*/
controller.StartExternalControl();
active_mode = 0;
}
/*-------------------------------------------------------------*\
@ -89,7 +86,7 @@ void RGBController_Nanoleaf::SetupZones()
for(std::vector<int>::const_iterator it = controller.GetPanelIds().begin(); it != controller.GetPanelIds().end(); ++it)
{
led new_led;
new_led.name = std::to_string(*it);
new_led.name = std::to_string(*it);
leds.push_back(new_led);
}
@ -107,10 +104,7 @@ void RGBController_Nanoleaf::ResizeZone(int /*zone*/, int /*new_size*/)
void RGBController_Nanoleaf::DeviceUpdateLEDs()
{
if(controller.GetModel() == NANOLEAF_LIGHT_PANELS_MODEL)
{
controller.UpdateLEDs(colors);
}
controller.UpdateLEDs(colors);
}
void RGBController_Nanoleaf::UpdateZoneLEDs(int /*zone*/)
@ -133,7 +127,7 @@ void RGBController_Nanoleaf::DeviceUpdateMode()
/*---------------------------------------------------------*\
| Mode 0 is reserved for Direct mode |
\*---------------------------------------------------------*/
if(active_mode == 0 && controller.GetModel() == NANOLEAF_LIGHT_PANELS_MODEL)
if(active_mode == 0)
{
controller.StartExternalControl();
}