From 23ec00a452f1a0cd79f2674dfbb1dd9f4704ea2c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 12 Aug 2019 17:18:08 +0200 Subject: [PATCH] Add command Buzzer Add command Buzzer with optional parameters ,, enabled when a buzzer is configured (#5988) --- sonoff/_changelog.ino | 1 + sonoff/my_user_config.h | 1 + sonoff/sonoff.h | 2 +- sonoff/sonoff.ino | 28 ++---- sonoff/sonoff_template.h | 2 + sonoff/xdrv_22_sonoff_ifan.ino | 8 +- sonoff/xdrv_24_buzzer.ino | 175 +++++++++++++++++++++++++++++++++ sonoff/xdrv_interface.ino | 1 + sonoff/xsns_interface.ino | 1 + 9 files changed, 196 insertions(+), 23 deletions(-) create mode 100644 sonoff/xdrv_24_buzzer.ino diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 20c00952e..c67579844 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -5,6 +5,7 @@ * See DEBUG_CORE_LOG example in sonoff.ino and DEBUG_DRIVER_LOG example in xdrv_09_timers.ino * Add support for Solax X1 inverter by Pablo Zerón * Add ZigBee support phase 1 - low level MQTT ZNP messages for CC2530 devices + * Add command Buzzer with optional parameters ,, enabled when a buzzer is configured (#5988) * * 6.6.0.3 20190725 * Change filename of configuration backup from using FriendlyName1 to Hostname solving diacritic issues (#2422) diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 9a90b9282..d8bbd6130 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -304,6 +304,7 @@ // #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code) // -- Optional modules ---------------------------- +#define USE_BUZZER // Add support for a buzzer (+0k6 code) #define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) #define USE_TUYA_DIMMER // Add support for Tuya Serial Dimmer #define TUYA_DIMMER_ID 0 // Default dimmer Id diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 8da188db4..3912fee45 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -246,7 +246,7 @@ enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT enum LightSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX}; -enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT, +enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER, diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 7061675e1..172fe3bf5 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -132,7 +132,6 @@ uint8_t leds_present = 0; // Max number of LED supported uint8_t led_inverted = 0; // LED inverted flag (1 = (0 = On, 1 = Off)) uint8_t led_power = 0; // LED power state uint8_t ledlnk_inverted = 0; // Link LED inverted flag (1 = (0 = On, 1 = Off)) -uint8_t buzzer_inverted = 0; // Buzzer inverted flag (1 = (0 = On, 1 = Off)) uint8_t pwm_inverted = 0; // PWM inverted flag (1 = inverted) uint8_t counter_no_pullup = 0; // Counter input pullup flag (1 = No pullup) uint8_t energy_flg = 0; // Energy monitor configured @@ -144,7 +143,6 @@ uint8_t seriallog_level; // Current copy of Settings.seriallo uint8_t syslog_level; // Current copy of Settings.syslog_level uint8_t my_module_type; // Current copy of Settings.module or user template type uint8_t my_adc0; // Active copy of Module ADC0 -uint8_t buzzer_count = 0; // Number of buzzes //uint8_t mdns_delayed_start = 0; // mDNS delayed start bool serial_local = false; // Handle serial locally; bool fallback_topic_flag = false; // Use Topic or FallbackTopic @@ -816,16 +814,6 @@ void Every100mSeconds(void) if (backlog_pointer >= MAX_BACKLOG) { backlog_pointer = 0; } } } - - if ((pin[GPIO_BUZZER] < 99) && (Settings.flag3.buzzer_enable)) { - if (buzzer_count) { - buzzer_count--; - uint8_t state = buzzer_count & 1; - digitalWrite(pin[GPIO_BUZZER], (buzzer_inverted) ? !state : state); - } - } else { - buzzer_count = 0; - } } /*-------------------------------------------------------------------------------------------*\ @@ -1256,6 +1244,8 @@ void GpioInit(void) DEBUG_CORE_LOG(PSTR("INI: gpio pin %d, mpin %d"), i, mpin); if (mpin) { + XdrvMailbox.index = mpin; + if ((mpin >= GPIO_SWT1_NP) && (mpin < (GPIO_SWT1_NP + MAX_SWITCHES))) { SwitchPullupFlag(mpin - GPIO_SWT1_NP); mpin -= (GPIO_SWT1_NP - GPIO_SWT1); @@ -1285,10 +1275,6 @@ void GpioInit(void) ledlnk_inverted = 1; mpin -= (GPIO_LEDLNK_INV - GPIO_LEDLNK); } - else if (mpin == GPIO_BUZZER_INV) { - buzzer_inverted = 1; - mpin -= (GPIO_BUZZER_INV - GPIO_BUZZER); - } else if ((mpin >= GPIO_PWM1_INV) && (mpin < (GPIO_PWM1_INV + MAX_PWMS))) { bitSet(pwm_inverted, mpin - GPIO_PWM1_INV); mpin -= (GPIO_PWM1_INV - GPIO_PWM1); @@ -1307,6 +1293,12 @@ void GpioInit(void) } } #endif // USE_DHT + else if (XdrvCall(FUNC_PIN_STATE)) { + mpin = XdrvMailbox.index; + } + else if (XsnsCall(FUNC_PIN_STATE)) { + mpin = XdrvMailbox.index; + }; } if (mpin) pin[mpin] = i; } @@ -1422,10 +1414,6 @@ void GpioInit(void) pinMode(pin[GPIO_LEDLNK], OUTPUT); digitalWrite(pin[GPIO_LEDLNK], ledlnk_inverted); } - if (pin[GPIO_BUZZER] < 99) { - pinMode(pin[GPIO_BUZZER], OUTPUT); - digitalWrite(pin[GPIO_BUZZER], buzzer_inverted); // Buzzer Off - } ButtonInit(); SwitchInit(); diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 061174034..8da44f338 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -488,8 +488,10 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_CNTR4, GPIO_CNTR4_NP, #endif +#ifdef USE_BUZZER GPIO_BUZZER, // Buzzer GPIO_BUZZER_INV, // Inverted buzzer +#endif GPIO_TXD, // Serial interface GPIO_RXD, // Serial interface #ifdef USE_I2C diff --git a/sonoff/xdrv_22_sonoff_ifan.ino b/sonoff/xdrv_22_sonoff_ifan.ino index 45d37c977..b2d9838f8 100644 --- a/sonoff/xdrv_22_sonoff_ifan.ino +++ b/sonoff/xdrv_22_sonoff_ifan.ino @@ -124,7 +124,9 @@ void SonoffIfanReceived(void) if (action != GetFanspeed()) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_FANSPEED " %d"), action); ExecuteCommand(svalue, SRC_REMOTE); - buzzer_count = 2; // Beep once +#ifdef USE_BUZZER + BuzzerEnabledBeep(1); // Beep once +#endif } } else { // AA 55 01 04 00 01 04 0A - Light @@ -137,7 +139,9 @@ void SonoffIfanReceived(void) } if (7 == mode) { // AA 55 01 07 00 01 01 0A - Rf long press - forget RF codes - buzzer_count = 6; // Beep three times +#ifdef USE_BUZZER + BuzzerEnabledBeep(3); // Beep three times +#endif } // Send Acknowledge - Copy first 5 bytes, reset byte 6 and store crc in byte 7 diff --git a/sonoff/xdrv_24_buzzer.ino b/sonoff/xdrv_24_buzzer.ino new file mode 100644 index 000000000..7727355a7 --- /dev/null +++ b/sonoff/xdrv_24_buzzer.ino @@ -0,0 +1,175 @@ +/* + xdrv_24_buzzer.ino - buzzer support for Sonoff-Tasmota + + Copyright (C) 2019 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_BUZZER +/*********************************************************************************************\ + * Buzzer support +\*********************************************************************************************/ +#define XDRV_24 24 + +struct BUZZER { + uint32_t tune = 0; + bool active = true; + bool enable = false; + uint8_t inverted = 0; // Buzzer inverted flag (1 = (0 = On, 1 = Off)) + uint8_t count = 0; // Number of buzzes + uint8_t set[2]; + uint8_t duration; + uint8_t state = 0; +} buzzer; + +/*********************************************************************************************/ + +//void BuzzerBeep(uint32_t count = 1, uint32_t on = 1, uint32_t off = 1, uint32_t tune = 0); +void BuzzerBeep(uint32_t count, uint32_t on, uint32_t off, uint32_t tune) +{ + buzzer.set[0] = off; + buzzer.set[1] = on; + buzzer.duration = 1; // Start buzzer on first step + buzzer.tune = tune; + buzzer.count = count * 2; // Start buzzer + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BUZ: %d,%d,%d,0x%08X"), count, on, off, tune); + + buzzer.enable = true; +} + +void BuzzerBeep(uint32_t count) { + BuzzerBeep(count, 1, 1, 0); +} + +void BuzzerEnabledBeep(uint32_t count) +{ + if (Settings.flag3.buzzer_enable) { // SetOption67 + BuzzerBeep(count); + } +} + +/*********************************************************************************************/ + +bool BuzzerPinState() +{ + if (XdrvMailbox.index == GPIO_BUZZER_INV) { + buzzer.inverted = 1; + XdrvMailbox.index -= (GPIO_BUZZER_INV - GPIO_BUZZER); + return true; + } + return false; +} + +void BuzzerInit(void) +{ + if (pin[GPIO_BUZZER] < 99) { + pinMode(pin[GPIO_BUZZER], OUTPUT); + digitalWrite(pin[GPIO_BUZZER], buzzer.inverted); // Buzzer Off + } else { + buzzer.active = false; + } +} + +void BuzzerEvery100mSec(void) +{ + if (buzzer.enable) { + if (buzzer.count) { + uint8_t state = buzzer.count & 1; + if (buzzer.duration) { + buzzer.duration--; + if (!buzzer.duration) { + buzzer.count--; + state = buzzer.count & 1; + buzzer.duration = buzzer.set[state]; + } + } + digitalWrite(pin[GPIO_BUZZER], (buzzer.inverted) ? !state : state); + } else { + buzzer.enable = false; + } + } +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +const char kBuzzerCommands[] PROGMEM = "|" // No prefix + "Buzzer" ; + +void (* const BuzzerCommand[])(void) PROGMEM = { + &CmndBuzzer }; + +void CmndBuzzer(void) +{ + // Buzzer ,, + // All parameters are optional + // + // Buzzer = Buzzer 1,1,1 = Beep once with both duration and pause set to 100mS + // Buzzer 2 = Beep twice with duration 200mS and pause 100mS + // Buzzer 2,3 = Beep twice with duration 300mS and pause 100mS + // Buzzer 2,3,4 = Beep twice with duration 300mS and pause 400mS + + if (XdrvMailbox.data_len > 0) { + char *p; + uint32_t i = 0; + uint32_t parm[4] = { 0 }; + for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 4; str = strtok_r(nullptr, ", ", &p)) { + parm[i] = strtol(str, nullptr, 0); + i++; + } + for (uint32_t i = 0; i < 4; i++) { + if (i < 3) { + if (parm[i] < 1) { parm[i] = 1; } // Default Count, On time, Off time + } else { + if (parm[3] < 0) { parm[3] = 0; } // Default Tune bitmap + } + } + BuzzerBeep(parm[0], parm[1], parm[2], parm[3]); + } else { + BuzzerBeep(1); + } + ResponseCmndDone(); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv24(uint8_t function) +{ + bool result = false; + + if (buzzer.active) { + switch (function) { + case FUNC_EVERY_100_MSECOND: + BuzzerEvery100mSec(); + break; + case FUNC_COMMAND: + result = DecodeCommand(kBuzzerCommands, BuzzerCommand); + break; + case FUNC_PRE_INIT: + BuzzerInit(); + break; + case FUNC_PIN_STATE: + result = BuzzerPinState(); + break; + } + } + return result; +} + +#endif // USE_BUZZER \ No newline at end of file diff --git a/sonoff/xdrv_interface.ino b/sonoff/xdrv_interface.ino index 7dddf1353..25f1af58c 100644 --- a/sonoff/xdrv_interface.ino +++ b/sonoff/xdrv_interface.ino @@ -237,6 +237,7 @@ bool XdrvCall(uint8_t Function) (FUNC_SERIAL == Function) || (FUNC_MODULE_INIT == Function) || (FUNC_SET_CHANNELS == Function) || + (FUNC_PIN_STATE == Function) || (FUNC_SET_DEVICE_POWER == Function) )) { break; diff --git a/sonoff/xsns_interface.ino b/sonoff/xsns_interface.ino index 05078c010..9d4d87c46 100644 --- a/sonoff/xsns_interface.ino +++ b/sonoff/xsns_interface.ino @@ -469,6 +469,7 @@ bool XsnsCall(uint8_t Function) #endif // PROFILE_XSNS_SENSOR_EVERY_SECOND if (result && ((FUNC_COMMAND == Function) || + (FUNC_PIN_STATE == Function) || (FUNC_COMMAND_SENSOR == Function) )) { break;