diff --git a/wled00/alexa.cpp b/wled00/alexa.cpp index 81b9ec3469..f49a224f60 100644 --- a/wled00/alexa.cpp +++ b/wled00/alexa.cpp @@ -12,11 +12,29 @@ #ifndef WLED_DISABLE_ALEXA void onAlexaChange(EspalexaDevice* dev); +// index of the first segment device in the Espalexa device list (0 = no segment devices) +static unsigned alexaSegmentDeviceStart = 0; + +// map a segment device offset to an actual segment index, skipping inactive segments +// returns -1 if the offset is out of range +static int mapSegDevToSegIndex(unsigned segDevIdx) +{ + unsigned activeCount = 0; + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { + if (!strip.getSegment(i).isActive()) continue; + if (activeCount == segDevIdx) return i; + activeCount++; + } + return -1; +} + void alexaInit() { if (!alexaEnabled || !WLED_CONNECTED) return; espalexa.removeAllDevices(); + alexaSegmentDeviceStart = 0; + // the original configured device for on/off or macros (added first, i.e. index 0) espalexaDevice = new EspalexaDevice(alexaInvocationName, onAlexaChange, EspalexaDeviceType::extendedcolor); espalexa.addDevice(espalexaDevice); @@ -32,6 +50,21 @@ void alexaInit() espalexa.addDevice(dev); } } + + // segment devices are added after the main device and preset devices + // device IDs: 0 = main, 1..N = presets, (N+1).. = segments + if (alexaExposeSegments) { + alexaSegmentDeviceStart = espalexa.getDeviceCount(); // first segment device index + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { + Segment& seg = strip.getSegment(i); + if (!seg.isActive()) continue; + String segName(seg.name ? seg.name : ""); + if (!segName.length()) segName = String(F("Segment ")) + String(i); + EspalexaDevice* dev = new EspalexaDevice(segName.c_str(), onAlexaChange, EspalexaDeviceType::extendedcolor); + espalexa.addDevice(dev); + } + } + espalexa.begin(&server); } @@ -44,10 +77,80 @@ void handleAlexa() void onAlexaChange(EspalexaDevice* dev) { EspalexaDeviceProperty m = dev->getLastChangedProperty(); + unsigned devId = dev->getId(); + + // determine if this is a segment device + bool isSegmentDevice = alexaExposeSegments && alexaSegmentDeviceStart > 0 && devId >= alexaSegmentDeviceStart; + + if (isSegmentDevice) + { + int segIdx = mapSegDevToSegIndex(devId - alexaSegmentDeviceStart); + if (segIdx < 0) return; // segment was deactivated after discovery + Segment& seg = strip.getSegment(segIdx); + + if (m == EspalexaDeviceProperty::on) + { + seg.setOption(SEG_OPTION_ON, true); + if (!seg.opacity) seg.setOpacity(255); // ensure segment is visible when turned on + stateUpdated(CALL_MODE_ALEXA); + } + else if (m == EspalexaDeviceProperty::off) + { + seg.setOption(SEG_OPTION_ON, false); + dev->setValue(0); + stateUpdated(CALL_MODE_ALEXA); + } + else if (m == EspalexaDeviceProperty::bri) + { + seg.setOption(SEG_OPTION_ON, true); + seg.setOpacity(dev->getValue()); + stateUpdated(CALL_MODE_ALEXA); + } + else // color + { + if (dev->getColorMode() == EspalexaColorMode::ct) + { + byte rgbw[4]; + uint16_t ct = dev->getCt(); + if (!ct) return; + uint16_t k = 1000000 / ct; + if (seg.isCCT()) { + seg.setCCT(k); + if (seg.hasWhite()) { + rgbw[0] = 0; rgbw[1] = 0; rgbw[2] = 0; rgbw[3] = 255; + } else { + rgbw[0] = 255; rgbw[1] = 255; rgbw[2] = 255; rgbw[3] = 0; + dev->setValue(255); + } + } else if (seg.hasWhite()) { + switch (ct) { + case 199: rgbw[0]=255; rgbw[1]=255; rgbw[2]=255; rgbw[3]=255; break; + case 234: rgbw[0]=127; rgbw[1]=127; rgbw[2]=127; rgbw[3]=255; break; + case 284: rgbw[0]= 0; rgbw[1]= 0; rgbw[2]= 0; rgbw[3]=255; break; + case 350: rgbw[0]=130; rgbw[1]= 90; rgbw[2]= 0; rgbw[3]=255; break; + case 383: rgbw[0]=255; rgbw[1]=153; rgbw[2]= 0; rgbw[3]=255; break; + default : colorKtoRGB(k, rgbw); + } + } else { + colorKtoRGB(k, rgbw); + } + seg.setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); + } else { + uint32_t color = dev->getRGB(); + seg.setColor(0, color); + } + stateUpdated(CALL_MODE_ALEXA); + } + return; + } + + // boundary for preset device range (excludes segment devices) + unsigned presetEnd = alexaSegmentDeviceStart ? alexaSegmentDeviceStart : espalexa.getDeviceCount(); + // original behavior: main device and preset devices if (m == EspalexaDeviceProperty::on) { - if (dev->getId() == 0) // Device 0 is for on/off or macros + if (devId == 0) // Device 0 is for on/off or macros { if (!macroAlexaOn) { @@ -64,13 +167,13 @@ void onAlexaChange(EspalexaDevice* dev) } else // switch-on behavior for preset devices { // turn off other preset devices - for (unsigned i = 1; i < espalexa.getDeviceCount(); i++) + for (unsigned i = 1; i < presetEnd; i++) { - if (i == dev->getId()) continue; + if (i == devId) continue; espalexa.getDevice(i)->setValue(0); // turn off other presets } - applyPreset(dev->getId(), CALL_MODE_ALEXA); // in alexaInit() preset 1 device was added second (index 1), preset 2 third (index 2) etc. + applyPreset(devId, CALL_MODE_ALEXA); // in alexaInit() preset 1 device was added second (index 1), preset 2 third (index 2) etc. } } else if (m == EspalexaDeviceProperty::off) { @@ -87,7 +190,8 @@ void onAlexaChange(EspalexaDevice* dev) applyPreset(macroAlexaOff, CALL_MODE_ALEXA); // below for loop stops Alexa from complaining if macroAlexaOff does not actually turn off } - for (unsigned i = 0; i < espalexa.getDeviceCount(); i++) + // set main and preset devices to off, but not segment devices + for (unsigned i = 0; i < presetEnd; i++) { espalexa.getDevice(i)->setValue(0); } diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index d01f83ad54..917db1d439 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -623,6 +623,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(macroAlexaOn, interfaces["va"]["macros"][0]); CJSON(macroAlexaOff, interfaces["va"]["macros"][1]); CJSON(alexaNumPresets, interfaces["va"]["p"]); + CJSON(alexaExposeSegments, interfaces["va"]["seg"]); #endif #ifndef WLED_DISABLE_MQTT @@ -1145,6 +1146,7 @@ void serializeConfig(JsonObject root) { if_va_macros.add(macroAlexaOff); if_va["p"] = alexaNumPresets; + if_va["seg"] = alexaExposeSegments; #endif #ifndef WLED_DISABLE_MQTT diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 43baaf6718..ce9a272c91 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -195,7 +195,8 @@