diff --git a/CHANGELOG.md b/CHANGELOG.md index ca6a6c0ce..99b943e51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,14 +14,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### ✨ Added +- Support of RGBW in **e1.31** led devices. - HTTPS support for homeassistant LED devices (#1886) - Hue Bridge - Use https and certificates for all API calls, support Bridge Pro (V3) - Hue Bridge - Alternate certificate support - Linux: New DRM/KMS screen grabber with plane-based capture - not feature complete yet - Logging/Tracing: Introduced qlogging categories to enable dynamic tracing ---- - ### 🔧 Changed - Hue Bridge - Wizard updates to support bridge-ids, overall code refactoring diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json index 3c14ccbb6..f46e9b5af 100644 --- a/assets/webconfig/i18n/en.json +++ b/assets/webconfig/i18n/en.json @@ -689,6 +689,7 @@ "edt_dev_spec_devices_discovery_inprogress": "Discovery in progress", "edt_dev_spec_dithering_title": "Dithering", "edt_dev_spec_dmaNumber_title": "DMA channel", + "edt_dev_spec_dmx_max_title": "DMX maximum channels supported", "edt_dev_spec_fullBrightnessAtStart_title": "Full brightness at start", "edt_dev_spec_gamma_title": "Gamma", "edt_dev_spec_globalBrightnessControlMaxLevel_title": "Max Current Level", diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp index 1be48dc3e..526699026 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp @@ -39,6 +39,8 @@ const int DMX_MAX = 512; // 512 usable slots LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig) : ProviderUdp(deviceConfig) + , _whiteAlgorithm(RGBW::WhiteAlgorithm::INVALID) + , _dmxChannelCount(0) { } @@ -58,9 +60,24 @@ bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig) _port = deviceConfig[CONFIG_PORT].toInt(E131_DEFAULT_PORT); _e131_universe = deviceConfig["universe"].toInt(1); + _e131_dmx_max = deviceConfig["dmx-max"].toInt(DMX_MAX); _e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName()); QString _json_cid = deviceConfig["cid"].toString(""); + // Initialize white algorithm + QString whiteAlgorithmStr = deviceConfig["whiteAlgorithm"].toString("white_off"); + _whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithmStr); + if (_whiteAlgorithm == RGBW::WhiteAlgorithm::INVALID) + { + QString errortext = QString("unknown whiteAlgorithm: %1").arg(whiteAlgorithmStr); + this->setInError(errortext); + return false; + } + Debug(_log, "whiteAlgorithm : %s", QSTRING_CSTR(whiteAlgorithmStr)); + + _dmxChannelCount = (_whiteAlgorithm == RGBW::WhiteAlgorithm::WHITE_OFF) ? _ledRGBCount : _ledRGBWCount; + _ledBuffer.resize(_dmxChannelCount); + if (_json_cid.isEmpty()) { _e131_cid = QUuid::createUuid(); @@ -138,35 +155,54 @@ void LedDeviceUdpE131::prepare(unsigned this_universe, unsigned this_dmxChannelC int LedDeviceUdpE131::write(const std::vector &ledValues) { - int retVal = 0; + int retVal = 0; int thisChannelCount = 0; - int dmxChannelCount = _ledRGBCount; - const uint8_t * rawdata = reinterpret_cast(ledValues.data()); + + uint8_t* rawDataPtr = _ledBuffer.data(); + + int currentChannel = 0; + for (const ColorRgb& color : ledValues) + { + if (_whiteAlgorithm == RGBW::WhiteAlgorithm::WHITE_OFF) + { + rawDataPtr[currentChannel++] = color.red; + rawDataPtr[currentChannel++] = color.green; + rawDataPtr[currentChannel++] = color.blue; + } + else + { + RGBW::Rgb_to_Rgbw(color, &_temp_rgbw, _whiteAlgorithm); + rawDataPtr[currentChannel++] = _temp_rgbw.red; + rawDataPtr[currentChannel++] = _temp_rgbw.green; + rawDataPtr[currentChannel++] = _temp_rgbw.blue; + rawDataPtr[currentChannel++] = _temp_rgbw.white; + } + } _e131_seq++; - for (int rawIdx = 0; rawIdx < dmxChannelCount; rawIdx++) + for (int rawIdx = 0; rawIdx < _dmxChannelCount; rawIdx++) { - if (rawIdx % DMX_MAX == 0) // start of new packet + if (rawIdx % _e131_dmx_max == 0) // start of new packet { - thisChannelCount = (dmxChannelCount - rawIdx < DMX_MAX) ? dmxChannelCount % DMX_MAX : DMX_MAX; -// is this the last packet? ? ^^ last packet : ^^ earlier packets + thisChannelCount = (_dmxChannelCount - rawIdx < _e131_dmx_max) ? _dmxChannelCount % _e131_dmx_max : _e131_dmx_max; + // is this the last packet? ? ^^ last packet : ^^ earlier packets - prepare(_e131_universe + rawIdx / DMX_MAX, thisChannelCount); + prepare(_e131_universe + rawIdx / _e131_dmx_max, thisChannelCount); e131_packet.sequence_number = _e131_seq; } - e131_packet.property_values[1 + rawIdx%DMX_MAX] = rawdata[rawIdx]; + e131_packet.property_values[1 + rawIdx % _e131_dmx_max] = rawDataPtr[rawIdx]; -// is this the last byte of last packet || last byte of other packets - if ( (rawIdx == dmxChannelCount-1) || (rawIdx %DMX_MAX == DMX_MAX-1) ) + // is this the last byte of last packet || last byte of other packets + if ((rawIdx == _dmxChannelCount - 1) || (rawIdx % _e131_dmx_max == _e131_dmx_max - 1)) { #undef e131debug #if e131debug Debug (_log, "send packet: rawidx %d dmxchannelcount %d universe: %d, packetsz %d" , rawIdx - , dmxChannelCount - , _e131_universe + rawIdx / DMX_MAX + , _dmxChannelCount + , _e131_universe + rawIdx / _e131_dmx_max , E131_DMP_DATA + 1 + thisChannelCount ); #endif diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpE131.h b/libsrc/leddevice/dev_net/LedDeviceUdpE131.h index 0397eeda7..c239ed9b3 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpE131.h +++ b/libsrc/leddevice/dev_net/LedDeviceUdpE131.h @@ -3,8 +3,11 @@ // hyperion includes #include "ProviderUdp.h" +#include "utils/ColorRgbw.h" +#include "utils/RgbToRgbw.h" #include +#include /** * @@ -139,9 +142,16 @@ class LedDeviceUdpE131 : public ProviderUdp e131_packet_t e131_packet; uint8_t _e131_seq = 0; uint8_t _e131_universe = 1; + int _e131_dmx_max = 512; uint8_t _acn_id[12] = {0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00 }; QString _e131_source_name; QUuid _e131_cid; + + // RGBW specific members + RGBW::WhiteAlgorithm _whiteAlgorithm; + ColorRgbw _temp_rgbw; + int _dmxChannelCount; + std::vector _ledBuffer; }; #endif // LEDEVICEUDPE131_H diff --git a/libsrc/leddevice/schemas/schema-e131.json b/libsrc/leddevice/schemas/schema-e131.json index 027407272..779381aed 100644 --- a/libsrc/leddevice/schemas/schema-e131.json +++ b/libsrc/leddevice/schemas/schema-e131.json @@ -22,6 +22,15 @@ "default": 1, "propertyOrder": 3 }, + "dmx-max": { + "type": "integer", + "title": "edt_dev_spec_dmx_max_title", + "minimum": 1, + "maximum": 512, + "default": 512, + "access": "advanced", + "propertyOrder": 4 + }, "latchTime": { "type": "integer", "title": "edt_dev_spec_latchtime_title", @@ -30,13 +39,43 @@ "minimum": 0, "maximum": 1000, "access": "expert", - "propertyOrder": 4 + "propertyOrder": 5 }, "cid": { "type": "string", "title": "edt_dev_spec_cid_title", - "propertyOrder": 5 + "propertyOrder": 6 + }, + "whiteAlgorithm": { + "type": "string", + "title": "edt_dev_spec_whiteLedAlgor_title", + "enum": [ + "subtract_minimum", + "sub_min_cool_adjust", + "sub_min_warm_adjust", + "cold_white", + "neutral_white", + "auto", + "auto_max", + "auto_accurate", + "white_off" + ], + "default": "white_off", + "options": { + "enum_titles": [ + "edt_dev_enum_subtract_minimum", + "edt_dev_enum_sub_min_cool_adjust", + "edt_dev_enum_sub_min_warm_adjust", + "edt_dev_enum_cold_white", + "edt_dev_enum_neutral_white", + "edt_dev_enum_auto", + "edt_dev_enum_auto_max", + "edt_dev_enum_auto_accurate", + "edt_dev_enum_white_off" + ] + }, + "propertyOrder": 7 } }, "additionalProperties": true -} +} \ No newline at end of file