diff --git a/CHANGELOG.md b/CHANGELOG.md index cad83cae6..6915df1c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ All notable changes to this project will be documented in this file. - Commands ``BuzzerActive``, ``BuzzerPwm`` as synonyms for ``SetOption67, 111`` respectively - Support for ESP32 ``Module 5`` Wireless Tag Eth01 (#9496) - Support trailing silence in buzzer tune (#10694) +- Command ``L1MusicSync <0|Off>|<1|On>|<2|Toggle>, 1..10, 1..100>`` to control Sonoff L1 Music Sync mode sensitivity and speed (#10722) +- Commands ``Speed2`` and ``Fade2`` to control a once off speed and/or fade (#10730) ### Changed - Maximum chars in ``AddLog_P`` logging restored from 128 to 700 (MAX_LOGSZ) to solve broken error messages diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4789e7bb6..c0eef30eb 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -61,10 +61,12 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Command ``CTRange`` to specify the visible CT range the bulb is capable of [#10311](https://github.com/arendst/Tasmota/issues/10311) - Command ``RuleTimer0`` to access all RuleTimers at once [#10352](https://github.com/arendst/Tasmota/issues/10352) - Command ``VirtualCT`` to simulate or fine tune CT bulbs with 3,4,5 channels [#10311](https://github.com/arendst/Tasmota/issues/10311) +- Command ``L1MusicSync <0|Off>|<1|On>|<2|Toggle>, 1..10, 1..100>`` to control Sonoff L1 Music Sync mode sensitivity and speed [#10722](https://github.com/arendst/Tasmota/issues/10722) - Command ``SetOption40 0..250`` to disable button functionality if activated for over 0.1 second re-introduced - Command ``SetOption43 1..255`` to control Rotary step (#10407) - Command ``SetOption118 1`` to move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default [#10353](https://github.com/arendst/Tasmota/issues/10353) - Command ``SetOption119 1`` to remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic [#10355](https://github.com/arendst/Tasmota/issues/10355) +- Commands ``Speed2`` and ``Fade2`` to control a once off speed and/or fade [#10730](https://github.com/arendst/Tasmota/issues/10730) - Commands ``ChannelRemap``, ``MultiPWM``, ``AlexaCTRange``, ``PowerOnFade``, ``PWMCT``, ``WhiteBlend``, ``VirtualCT`` as synonyms for ``SetOption37, 68, 82, 91, 92, 105 and 106`` respectively - Commands ``ZbNameKey``, ``ZbDeviceTopic``, ``ZbNoPrefix``, ``ZbEndpointSuffix``, ``ZbNoAutoBind``, ``ZbNameTopic`` as synonyms for ``SetOption83, 89, 100, 101, 110 and 112`` respectively - Commands ``BuzzerActive``, ``BuzzerPwm`` as synonyms for ``SetOption67, 111`` respectively diff --git a/tasmota/xlgt_05_sonoff_l1.ino b/tasmota/xlgt_05_sonoff_l1.ino index 4d70e6674..78248c896 100644 --- a/tasmota/xlgt_05_sonoff_l1.ino +++ b/tasmota/xlgt_05_sonoff_l1.ino @@ -25,11 +25,11 @@ #define XLGT_05 5 -//#define SONOFF_L1_START_DELAY // Sync Nuvotron power state with Tasmota on power up +#define SONOFF_L1_START_DELAY // Sync Nuvotron power state with Tasmota on power up //#define SONOFF_L1_ALLOW_REMOTE_INTERRUPT // During schemes 2..4 #define SONOFF_L1_DEBUG1 // Add send and receive logging -#define SONOFF_L1_BUFFER_SIZE 140 +#define SONOFF_L1_BUFFER_SIZE 170 #define SONOFF_L1_MODE_COLORFUL 1 // [Color key] Colorful (static color) #define SONOFF_L1_MODE_COLORFUL_GRADIENT 2 // [SMOOTH] Colorful Gradient @@ -45,19 +45,21 @@ #define SONOFF_L1_MODE_SYNC_TO_MUSIC 12 // Sync to music [Speed 1- 100, sensitivity 1 - 10] struct SNFL1 { + char *buffer; #ifdef SONOFF_L1_ALLOW_REMOTE_INTERRUPT uint32_t unlock = 0; bool receive_ready = true; -#endif -#ifdef SONOFF_L1_START_DELAY - char buffer[SONOFF_L1_BUFFER_SIZE]; #endif uint8_t color[3]; uint8_t dimmer; uint8_t power; + uint8_t old_music_sync = 0; + uint8_t music_sync = 0; + uint8_t sensitive; + uint8_t speed; } Snfl1; -const char kL1Commands[] PROGMEM = "L1|" // prefix +const char kL1Commands[] PROGMEM = "L1|" // Prefix "MusicSync"; void (* const L1Command[])(void) PROGMEM = { @@ -72,45 +74,24 @@ Ticker SnfL1StartDelay; void SnfL1SendDelayed(void) { SnfL1Send(); } +#endif // SONOFF_L1_START_DELAY -void SnfL1Send(void) -{ +void SnfL1Send(void) { #ifdef SONOFF_L1_DEBUG1 - AddLog(LOG_LEVEL_DEBUG, PSTR("SL1: Send %s"), Snfl1.buffer); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("SL1: Send %s"), Snfl1.buffer); #endif Serial.print(Snfl1.buffer); Serial.write(0x1B); Serial.flush(); } -void SnfL1SerialSendOk(void) -{ - snprintf_P(Snfl1.buffer, sizeof(Snfl1.buffer), PSTR("AT+SEND=ok")); +void SnfL1SerialSendOk(void) { + snprintf_P(Snfl1.buffer, SONOFF_L1_BUFFER_SIZE, PSTR("AT+SEND=ok")); SnfL1Send(); } -#else -void SnfL1Send(const char *buffer) -{ -#ifdef SONOFF_L1_DEBUG1 - AddLog(LOG_LEVEL_DEBUG, PSTR("SL1: Send %s"), buffer); -#endif - Serial.print(buffer); - Serial.write(0x1B); - Serial.flush(); -} -void SnfL1SerialSendOk(void) -{ - char buffer[16]; - snprintf_P(buffer, sizeof(buffer), PSTR("AT+SEND=ok")); - - SnfL1Send(buffer); -} -#endif // SONOFF_L1_START_DELAY - -bool SnfL1SerialInput(void) -{ +bool SnfL1SerialInput(void) { if (TasmotaGlobal.serial_in_byte != 0x1B) { if (TasmotaGlobal.serial_in_byte_counter >= SONOFF_L1_BUFFER_SIZE) { TasmotaGlobal.serial_in_byte_counter = 0; @@ -125,7 +106,7 @@ bool SnfL1SerialInput(void) // AT+UPDATE="sequence":"34906","switch":"on","light_type":1,"colorR":0,"colorG":16,"colorB":0,"bright":6,"mode":1 // AT+UPDATE="switch":"on","light_type":1,"colorR":255,"colorG":0,"colorB":0,"bright":6,"mode":1,"speed":100,"sensitive":10 #ifdef SONOFF_L1_DEBUG1 - AddLog(LOG_LEVEL_DEBUG, PSTR("SL1: Rcvd %s"), TasmotaGlobal.serial_in_buffer); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("SL1: Rcvd %s"), TasmotaGlobal.serial_in_buffer); #endif if (!strncmp(TasmotaGlobal.serial_in_buffer +3, "RESULT", 6)) { #ifdef SONOFF_L1_ALLOW_REMOTE_INTERRUPT @@ -246,8 +227,7 @@ bool SnfL1SerialInput(void) /********************************************************************************************/ -bool SnfL1SetChannels(void) -{ +bool SnfL1SetChannels(void) { #ifdef SONOFF_L1_ALLOW_REMOTE_INTERRUPT if (Snfl1.receive_ready || TimeReached(Snfl1.unlock)) { #endif @@ -269,34 +249,30 @@ bool SnfL1SetChannels(void) Snfl1.color[i] = scale_col[i]; } } - if (!power_changed && !dimmer_changed && !color_changed) { return true; } + if (!power_changed && !dimmer_changed && !color_changed && (Snfl1.old_music_sync == Snfl1.music_sync)) { return true; } -#ifdef SONOFF_L1_START_DELAY - snprintf_P(Snfl1.buffer, sizeof(Snfl1.buffer), PSTR("AT+UPDATE=\"sequence\":\"%d%03d\",\"switch\":\"%s\",\"light_type\":1,\"colorR\":%d,\"colorG\":%d,\"colorB\":%d,\"bright\":%d,\"mode\":%d"), + uint32_t mode = SONOFF_L1_MODE_COLORFUL; + if (Snfl1.music_sync) { + mode = SONOFF_L1_MODE_SYNC_TO_MUSIC; + } + + snprintf_P(Snfl1.buffer, SONOFF_L1_BUFFER_SIZE, PSTR("AT+UPDATE=\"sequence\":\"%d%03d\",\"switch\":\"%s\",\"light_type\":1,\"colorR\":%d,\"colorG\":%d,\"colorB\":%d,\"bright\":%d,\"mode\":%d,\"sensitive\":%d,\"speed\":%d"), LocalTime(), millis()%1000, Snfl1.power ? "on" : "off", Snfl1.color[0], Snfl1.color[1], Snfl1.color[2], Snfl1.dimmer, - SONOFF_L1_MODE_COLORFUL); + mode, + Snfl1.sensitive, + Snfl1.speed); +#ifdef SONOFF_L1_START_DELAY static bool first_call = true; if (first_call) { SnfL1StartDelay.once_ms(900, SnfL1SendDelayed); // Allow startup time for Nuvotron microcontroller first_call = false; - } else { - SnfL1Send(); - } -#else - char buffer[SONOFF_L1_BUFFER_SIZE]; - snprintf_P(buffer, sizeof(buffer), PSTR("AT+UPDATE=\"sequence\":\"%d%03d\",\"switch\":\"%s\",\"light_type\":1,\"colorR\":%d,\"colorG\":%d,\"colorB\":%d,\"bright\":%d,\"mode\":%d"), - LocalTime(), millis()%1000, - Snfl1.power ? "on" : "off", - Snfl1.color[0], Snfl1.color[1], Snfl1.color[2], - Snfl1.dimmer, - SONOFF_L1_MODE_COLORFUL); - - SnfL1Send(buffer); + } else #endif // SONOFF_L1_START_DELAY + SnfL1Send(); #ifdef SONOFF_L1_ALLOW_REMOTE_INTERRUPT Snfl1.unlock = millis() + 500; // Allow time for the RC @@ -306,60 +282,53 @@ bool SnfL1SetChannels(void) return true; } -bool SnfL1ModuleSelected(void) -{ +bool SnfL1ModuleSelected(void) { if (SONOFF_L1 == TasmotaGlobal.module_type) { if (PinUsed(GPIO_RXD) && PinUsed(GPIO_TXD)) { - SetSerial(19200, TS_SERIAL_8N1); + Snfl1.buffer = (char*)malloc(SONOFF_L1_BUFFER_SIZE); + if (Snfl1.buffer) { + SetSerial(19200, TS_SERIAL_8N1); - Snfl1.power = !Light.power; - Snfl1.dimmer = !light_state.getDimmer(); + Snfl1.power = !Light.power; + Snfl1.dimmer = !light_state.getDimmer(); + Snfl1.music_sync = 0; + Snfl1.sensitive = 1; // 1..10 + Snfl1.speed = 1; // 1..100 - TasmotaGlobal.light_type = LT_RGB; - TasmotaGlobal.light_driver = XLGT_05; - AddLog(LOG_LEVEL_DEBUG, PSTR("LGT: Sonoff L1 Found")); - return true; + TasmotaGlobal.light_type = LT_RGB; + TasmotaGlobal.light_driver = XLGT_05; + AddLog(LOG_LEVEL_DEBUG, PSTR("LGT: Sonoff L1 Found")); + return true; + } } } return false; } -// SONOFF_L1_MODE_SYNC_TO_MUSIC -void SnfL1ModeMusic(uint32_t sensitive, uint32_t speed) { - char buffer[SONOFF_L1_BUFFER_SIZE]; - snprintf_P(buffer, sizeof(buffer), PSTR("AT+UPDATE=\"sequence\":\"%d%03d\",\"mode\":%d,\"sensitive\":%d,\"speed\":%d"), - LocalTime(), millis()%1000, - SONOFF_L1_MODE_SYNC_TO_MUSIC, - sensitive, - speed - ); - - SnfL1Send(buffer); -} - -void CmndMusicSync(void) -{ - // Format is L1MusicSync sensitivity,speed +void CmndMusicSync(void) { + // Format is L1MusicSync on/off/toggle, sensitivity, speed // sensitivity 1..10, speed 1..100 - char *p; - strtok_r(XdrvMailbox.data, ",", &p); - if (0 == XdrvMailbox.payload) { - SnfL1SetChannels(); - - ResponseCmndDone(); - } - else if (p != nullptr) { - uint32_t sen = strtol(XdrvMailbox.data, nullptr, 0); - uint32_t spd = strtol(p, nullptr, 0); - if ( (sen >= 0) && (sen <= 10) && (spd >= 0) && (spd <= 100) ) { - SnfL1ModeMusic(sen, spd); - ResponseCmndDone(); - } - else { - return; // error + if (XdrvMailbox.data_len > 0) { + Snfl1.old_music_sync = Snfl1.music_sync; + uint32_t parm[3] = { 0 }; + ParseParameters(3, parm); + if (2 == parm[0]) { + Snfl1.music_sync ^= 1; // Toggle + } else { + Snfl1.music_sync = parm[0] & 1; // On or Off } - } + if ((parm[1] > 0) && (parm[1] < 11)) { + Snfl1.sensitive = parm[1]; // 1..10 + } + if ((parm[2] > 0) && (parm[2] < 101)) { + Snfl1.speed = parm[2]; // 1..100 + } + SnfL1SetChannels(); + } + Response_P(PSTR("{\"%s\":{\"Mode\":\"%s\",\"Sensitive\":%d,\"Speed\":%d}}"), + XdrvMailbox.command, GetStateText(Snfl1.music_sync), Snfl1.sensitive, Snfl1.speed); } + /*********************************************************************************************\ * Interface \*********************************************************************************************/