diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4c8f3aca1..b4f5eee4b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -83,3 +83,4 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Add support for inverted NeoPixelBus data line by enabling ``#define USE_WS2812_INVERTED`` (#8988) - Add PWM dimmer color/trigger on tap, SO88 led, DGR WITH_LOCAL flag by Paul Diem (#9474) - Add support for stateful ACs using ``StateMode`` in tasmota-ir.bin by Arik Yavilevich (#9472) +- Add support for analog buttons indexed within standard button range diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index ab6194513..1f0481db9 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -25,6 +25,7 @@ - Add PWM dimmer color/trigger on tap, SO88 led, DGR WITH_LOCAL flag by Paul Diem (#9474) - Add support for stateful ACs using ``StateMode`` in tasmota-ir.bin by Arik Yavilevich (#9472) - Add Zigbee ``ZbData`` command for better support of device specific data +- Add support for analog buttons indexed within standard button range ## Released diff --git a/tasmota/support_button.ino b/tasmota/support_button.ino index 303de23ba..1e1192605 100644 --- a/tasmota/support_button.ino +++ b/tasmota/support_button.ino @@ -49,7 +49,6 @@ struct BUTTON { uint8_t touch_hits[MAX_KEYS] = { 0 }; // Hits in a row to filter out noise #endif // ESP32 uint8_t present = 0; // Number of buttons found flag - uint8_t adc = 99; // ADC0 button number } Button; #ifdef ESP32 @@ -90,14 +89,11 @@ void ButtonInit(void) Button.present++; pinMode(Pin(GPIO_KEY1, i), bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_KEY1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); } -#ifdef ESP8266 -#ifndef USE_ADC_VCC - else if ((99 == Button.adc) && AdcButtonPresent(0)) { +#ifdef USE_ADC + else if (PinUsed(GPIO_ADC_BUTTON, i) || PinUsed(GPIO_ADC_BUTTON_INV, i)) { Button.present++; - Button.adc = i; } -#endif // USE_ADC_VCC -#endif // ESP8266 +#endif // USE_ADC } } @@ -157,22 +153,11 @@ void ButtonHandler(void) } Button.dual_code = 0; } - } - else { - if (PinUsed(GPIO_KEY1, button_index)) { - button_present = 1; - button = (digitalRead(Pin(GPIO_KEY1, button_index)) != bitRead(Button.inverted_mask, button_index)); - } - } -#ifndef USE_ADC_VCC - if (Button.adc == button_index) { - button_present = 1; - button = AdcGetButton(0); - } -#endif // USE_ADC_VCC -#else // ESP32 + } else +#endif // ESP8266 if (PinUsed(GPIO_KEY1, button_index)) { button_present = 1; +#ifdef ESP32 if (bitRead(Button.touch_mask, button_index)) { // Touch uint32_t _value = touchRead(Pin(GPIO_KEY1, button_index)); button = NOT_PRESSED; @@ -192,11 +177,22 @@ void ButtonHandler(void) if (bitRead(TOUCH_BUTTON.calibration, button_index+1)) { AddLog_P2(LOG_LEVEL_INFO, PSTR("PLOT: %u, %u, %u,"), button_index+1, _value, Button.touch_hits[button_index]); // Button number (1..4), value, continuous hits under threshold } - } else { // Normal button + } else +#endif // ESP32 + { // Normal button button = (digitalRead(Pin(GPIO_KEY1, button_index)) != bitRead(Button.inverted_mask, button_index)); } } -#endif // ESP8266 or ESP32 +#ifdef USE_ADC + else if (PinUsed(GPIO_ADC_BUTTON, button_index)) { + button_present = 1; + button = AdcGetButton(Pin(GPIO_ADC_BUTTON, button_index)); + } + else if (PinUsed(GPIO_ADC_BUTTON_INV, button_index)) { + button_present = 1; + button = AdcGetButton(Pin(GPIO_ADC_BUTTON_INV, button_index)); + } +#endif // USE_ADC if (button_present) { XdrvMailbox.index = button_index; XdrvMailbox.payload = button; diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 0099a46e8..4457dc57f 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -650,8 +650,8 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_ADC_INPUT) + MAX_ADCS, // Analog inputs AGPIO(GPIO_ADC_TEMP) + MAX_ADCS, // Thermistor AGPIO(GPIO_ADC_LIGHT) + MAX_ADCS, // Light sensor - AGPIO(GPIO_ADC_BUTTON) + MAX_ADCS, // Button - AGPIO(GPIO_ADC_BUTTON_INV) + MAX_ADCS, + AGPIO(GPIO_ADC_BUTTON) + MAX_KEYS, // Button + AGPIO(GPIO_ADC_BUTTON_INV) + MAX_KEYS, AGPIO(GPIO_ADC_RANGE) + MAX_ADCS, // Range AGPIO(GPIO_ADC_CT_POWER) + MAX_ADCS, // Current AGPIO(GPIO_ADC_JOY) + MAX_ADCS, // Joystick @@ -668,8 +668,8 @@ const uint16_t kAdcNiceList[] PROGMEM = { AGPIO(GPIO_ADC_INPUT), // Analog inputs AGPIO(GPIO_ADC_TEMP), // Thermistor AGPIO(GPIO_ADC_LIGHT), // Light sensor - AGPIO(GPIO_ADC_BUTTON), // Button - AGPIO(GPIO_ADC_BUTTON_INV), + AGPIO(GPIO_ADC_BUTTON) + MAX_KEYS, // Button + AGPIO(GPIO_ADC_BUTTON_INV) + MAX_KEYS, AGPIO(GPIO_ADC_RANGE), // Range AGPIO(GPIO_ADC_CT_POWER), // Current AGPIO(GPIO_ADC_JOY), // Joystick diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index be71b3aad..5a792b58d 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -477,6 +477,7 @@ const char HTTP_SCRIPT_TEMPLATE2[] PROGMEM = const char HTTP_SCRIPT_TEMPLATE3[] PROGMEM = "\";" "sk(g[13]," STR(ADC0_PIN) ");"; // Set ADC0 + const char HTTP_SCRIPT_TEMPLATE4[] PROGMEM = "g=o.shift();" // FLAG "for(i=0;i<" STR(GPIO_FLAG_USED) ";i++){" @@ -1800,13 +1801,23 @@ void HandleTemplateConfiguration(void) first_done = true; } } +#ifdef ESP8266 + for (uint32_t i = 0; i < ARRAY_SIZE(kAdcNiceList); i++) { // hs=[36,68,100,132,168,200,232,264,292,324,356,388,421,453]; + uint32_t midx = pgm_read_word(kAdcNiceList + i); + if (midx & 0x001F) { + if (first_done) { WSContentSend_P(PSTR(",")); } + WSContentSend_P(PSTR("%d"), midx); + first_done = true; + } + } +#endif WSContentSend_P(PSTR("];")); WSContentSend_P(HTTP_SCRIPT_TEMPLATE2); #ifdef ESP8266 WSContentSend_P(PSTR("os=\"")); - for (uint32_t i = 0; i < ARRAY_SIZE(kAdcNiceList); i++) { // FLAG: }2'0'>None}3}2'17'>Analog}3... + for (uint32_t i = 0; i < ARRAY_SIZE(kAdcNiceList); i++) { // GPIO: }2'0'>None}3}2'17'>Analog}3... if (1 == i) { WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX, AGPIO(GPIO_USER), D_SENSOR_USER); // }2'15'>User}3 } diff --git a/tasmota/xsns_02_analog.ino b/tasmota/xsns_02_analog.ino index 09254d0a9..8e78c403f 100644 --- a/tasmota/xsns_02_analog.ino +++ b/tasmota/xsns_02_analog.ino @@ -24,8 +24,15 @@ #define XSNS_02 2 +#ifdef ESP8266 +#define ANALOG_RESOLUTION 10 // 12 = 4095, 11 = 2047, 10 = 1023 +#define ANALOG_RANGE 1023 // 4095 = 12, 2047 = 11, 1023 = 10 +#else // ESP32 +#undef ANALOG_RESOLUTION #define ANALOG_RESOLUTION 12 // 12 = 4095, 11 = 2047, 10 = 1023 +#undef ANALOG_RANGE #define ANALOG_RANGE 4095 // 4095 = 12, 2047 = 11, 1023 = 10 +#endif // ESP8266 or ESP32 #define TO_CELSIUS(x) ((x) - 273.15) #define TO_KELVIN(x) ((x) + 273.15) @@ -64,6 +71,17 @@ #define CT_FLAG_ENERGY_RESET (1 << 0) // Reset energy total +// Buttons +// ---- Inverted +// 3V3 ---| |----| +// | +// 3V3 --- R1 ----|--- R1 --- Gnd +// | +// |---| |--- Gnd +// | ---- +// ADC +#define ANALOG_BUTTON 128 // Add resistor tolerance + // Odroid joysticks // ---- Up // 3V3 ---| |------------ @@ -154,6 +172,7 @@ void AdcInitParams(uint8_t idx) { } void AdcAttach(uint8_t pin, uint8_t type) { + if (Adcs.present == MAX_ADCS) { return; } Adc[Adcs.present].pin = pin; if (adcAttachPin(Adc[Adcs.present].pin)) { Adc[Adcs.present].type = type; @@ -174,12 +193,6 @@ void AdcInit(void) { if (PinUsed(GPIO_ADC_LIGHT, i)) { AdcAttach(Pin(GPIO_ADC_LIGHT, i), ADC_LIGHT); } - if (PinUsed(GPIO_ADC_BUTTON, i)) { - AdcAttach(Pin(GPIO_ADC_BUTTON, i), ADC_BUTTON); - } - if (PinUsed(GPIO_ADC_BUTTON_INV, i)) { - AdcAttach(Pin(GPIO_ADC_BUTTON_INV, i), ADC_BUTTON_INV); - } if (PinUsed(GPIO_ADC_RANGE, i)) { AdcAttach(Pin(GPIO_ADC_RANGE, i), ADC_RANGE); } @@ -190,6 +203,15 @@ void AdcInit(void) { AdcAttach(Pin(GPIO_ADC_JOY, i), ADC_JOY); } } + for (uint32_t i = 0; i < MAX_KEYS; i++) { + if (PinUsed(GPIO_ADC_BUTTON, i)) { + AdcAttach(Pin(GPIO_ADC_BUTTON, i), ADC_BUTTON); + } + else if (PinUsed(GPIO_ADC_BUTTON_INV, i)) { + AdcAttach(Pin(GPIO_ADC_BUTTON_INV, i), ADC_BUTTON_INV); + } + } + if (Adcs.present) { #ifdef ESP32 analogSetClockDiv(1); // Default 1 @@ -253,17 +275,18 @@ void AdcEvery250ms(void) { } #endif // USE_RULES -bool AdcButtonPresent(uint32_t idx) { - return ((ADC_BUTTON == Adc[idx].type) || (ADC_BUTTON_INV == Adc[idx].type)); -} - -uint8_t AdcGetButton(uint32_t idx) { - if (ADC_BUTTON_INV == Adc[idx].type) { - return (AdcRead(Adc[idx].pin, 1) < 128); - } - else if (ADC_BUTTON == Adc[idx].type) { - return (AdcRead(Adc[idx].pin, 1) > 128); +uint8_t AdcGetButton(uint32_t pin) { + for (uint32_t idx = 0; idx < Adcs.present; idx++) { + if (Adc[idx].pin == pin) { + if (ADC_BUTTON_INV == Adc[idx].type) { + return (AdcRead(Adc[idx].pin, 1) < ANALOG_BUTTON); + } + else if (ADC_BUTTON == Adc[idx].type) { + return (AdcRead(Adc[idx].pin, 1) > ANALOG_BUTTON); + } + } } + return 0; } uint16_t AdcGetLux(uint32_t idx) {