Add support for analog buttons

Add support for analog buttons indexed within standard button range
This commit is contained in:
Theo Arends 2020-10-08 18:27:12 +02:00
parent 6b65f616d7
commit d5b8d6ae24
6 changed files with 76 additions and 44 deletions

View File

@ -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 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 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 stateful ACs using ``StateMode`` in tasmota-ir.bin by Arik Yavilevich (#9472)
- Add support for analog buttons indexed within standard button range

View File

@ -25,6 +25,7 @@
- Add PWM dimmer color/trigger on tap, SO88 led, DGR WITH_LOCAL flag by Paul Diem (#9474) - 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 stateful ACs using ``StateMode`` in tasmota-ir.bin by Arik Yavilevich (#9472)
- Add Zigbee ``ZbData`` command for better support of device specific data - Add Zigbee ``ZbData`` command for better support of device specific data
- Add support for analog buttons indexed within standard button range
## Released ## Released

View File

@ -49,7 +49,6 @@ struct BUTTON {
uint8_t touch_hits[MAX_KEYS] = { 0 }; // Hits in a row to filter out noise uint8_t touch_hits[MAX_KEYS] = { 0 }; // Hits in a row to filter out noise
#endif // ESP32 #endif // ESP32
uint8_t present = 0; // Number of buttons found flag uint8_t present = 0; // Number of buttons found flag
uint8_t adc = 99; // ADC0 button number
} Button; } Button;
#ifdef ESP32 #ifdef ESP32
@ -90,14 +89,11 @@ void ButtonInit(void)
Button.present++; Button.present++;
pinMode(Pin(GPIO_KEY1, i), bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_KEY1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); pinMode(Pin(GPIO_KEY1, i), bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_KEY1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP));
} }
#ifdef ESP8266 #ifdef USE_ADC
#ifndef USE_ADC_VCC else if (PinUsed(GPIO_ADC_BUTTON, i) || PinUsed(GPIO_ADC_BUTTON_INV, i)) {
else if ((99 == Button.adc) && AdcButtonPresent(0)) {
Button.present++; Button.present++;
Button.adc = i;
} }
#endif // USE_ADC_VCC #endif // USE_ADC
#endif // ESP8266
} }
} }
@ -157,22 +153,11 @@ void ButtonHandler(void)
} }
Button.dual_code = 0; Button.dual_code = 0;
} }
} } else
else { #endif // ESP8266
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
if (PinUsed(GPIO_KEY1, button_index)) { if (PinUsed(GPIO_KEY1, button_index)) {
button_present = 1; button_present = 1;
#ifdef ESP32
if (bitRead(Button.touch_mask, button_index)) { // Touch if (bitRead(Button.touch_mask, button_index)) { // Touch
uint32_t _value = touchRead(Pin(GPIO_KEY1, button_index)); uint32_t _value = touchRead(Pin(GPIO_KEY1, button_index));
button = NOT_PRESSED; button = NOT_PRESSED;
@ -192,11 +177,22 @@ void ButtonHandler(void)
if (bitRead(TOUCH_BUTTON.calibration, button_index+1)) { 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 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)); 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) { if (button_present) {
XdrvMailbox.index = button_index; XdrvMailbox.index = button_index;
XdrvMailbox.payload = button; XdrvMailbox.payload = button;

View File

@ -650,8 +650,8 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_ADC_INPUT) + MAX_ADCS, // Analog inputs AGPIO(GPIO_ADC_INPUT) + MAX_ADCS, // Analog inputs
AGPIO(GPIO_ADC_TEMP) + MAX_ADCS, // Thermistor AGPIO(GPIO_ADC_TEMP) + MAX_ADCS, // Thermistor
AGPIO(GPIO_ADC_LIGHT) + MAX_ADCS, // Light sensor AGPIO(GPIO_ADC_LIGHT) + MAX_ADCS, // Light sensor
AGPIO(GPIO_ADC_BUTTON) + MAX_ADCS, // Button AGPIO(GPIO_ADC_BUTTON) + MAX_KEYS, // Button
AGPIO(GPIO_ADC_BUTTON_INV) + MAX_ADCS, AGPIO(GPIO_ADC_BUTTON_INV) + MAX_KEYS,
AGPIO(GPIO_ADC_RANGE) + MAX_ADCS, // Range AGPIO(GPIO_ADC_RANGE) + MAX_ADCS, // Range
AGPIO(GPIO_ADC_CT_POWER) + MAX_ADCS, // Current AGPIO(GPIO_ADC_CT_POWER) + MAX_ADCS, // Current
AGPIO(GPIO_ADC_JOY) + MAX_ADCS, // Joystick 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_INPUT), // Analog inputs
AGPIO(GPIO_ADC_TEMP), // Thermistor AGPIO(GPIO_ADC_TEMP), // Thermistor
AGPIO(GPIO_ADC_LIGHT), // Light sensor AGPIO(GPIO_ADC_LIGHT), // Light sensor
AGPIO(GPIO_ADC_BUTTON), // Button AGPIO(GPIO_ADC_BUTTON) + MAX_KEYS, // Button
AGPIO(GPIO_ADC_BUTTON_INV), AGPIO(GPIO_ADC_BUTTON_INV) + MAX_KEYS,
AGPIO(GPIO_ADC_RANGE), // Range AGPIO(GPIO_ADC_RANGE), // Range
AGPIO(GPIO_ADC_CT_POWER), // Current AGPIO(GPIO_ADC_CT_POWER), // Current
AGPIO(GPIO_ADC_JOY), // Joystick AGPIO(GPIO_ADC_JOY), // Joystick

View File

@ -477,6 +477,7 @@ const char HTTP_SCRIPT_TEMPLATE2[] PROGMEM =
const char HTTP_SCRIPT_TEMPLATE3[] PROGMEM = const char HTTP_SCRIPT_TEMPLATE3[] PROGMEM =
"\";" "\";"
"sk(g[13]," STR(ADC0_PIN) ");"; // Set ADC0 "sk(g[13]," STR(ADC0_PIN) ");"; // Set ADC0
const char HTTP_SCRIPT_TEMPLATE4[] PROGMEM = const char HTTP_SCRIPT_TEMPLATE4[] PROGMEM =
"g=o.shift();" // FLAG "g=o.shift();" // FLAG
"for(i=0;i<" STR(GPIO_FLAG_USED) ";i++){" "for(i=0;i<" STR(GPIO_FLAG_USED) ";i++){"
@ -1800,13 +1801,23 @@ void HandleTemplateConfiguration(void)
first_done = true; 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(PSTR("];"));
WSContentSend_P(HTTP_SCRIPT_TEMPLATE2); WSContentSend_P(HTTP_SCRIPT_TEMPLATE2);
#ifdef ESP8266 #ifdef ESP8266
WSContentSend_P(PSTR("os=\"")); 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) { if (1 == i) {
WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX, AGPIO(GPIO_USER), D_SENSOR_USER); // }2'15'>User}3 WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX, AGPIO(GPIO_USER), D_SENSOR_USER); // }2'15'>User}3
} }

View File

@ -24,8 +24,15 @@
#define XSNS_02 2 #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 #define ANALOG_RESOLUTION 12 // 12 = 4095, 11 = 2047, 10 = 1023
#undef ANALOG_RANGE
#define ANALOG_RANGE 4095 // 4095 = 12, 2047 = 11, 1023 = 10 #define ANALOG_RANGE 4095 // 4095 = 12, 2047 = 11, 1023 = 10
#endif // ESP8266 or ESP32
#define TO_CELSIUS(x) ((x) - 273.15) #define TO_CELSIUS(x) ((x) - 273.15)
#define TO_KELVIN(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 #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 // Odroid joysticks
// ---- Up // ---- Up
// 3V3 ---| |------------ // 3V3 ---| |------------
@ -154,6 +172,7 @@ void AdcInitParams(uint8_t idx) {
} }
void AdcAttach(uint8_t pin, uint8_t type) { void AdcAttach(uint8_t pin, uint8_t type) {
if (Adcs.present == MAX_ADCS) { return; }
Adc[Adcs.present].pin = pin; Adc[Adcs.present].pin = pin;
if (adcAttachPin(Adc[Adcs.present].pin)) { if (adcAttachPin(Adc[Adcs.present].pin)) {
Adc[Adcs.present].type = type; Adc[Adcs.present].type = type;
@ -174,12 +193,6 @@ void AdcInit(void) {
if (PinUsed(GPIO_ADC_LIGHT, i)) { if (PinUsed(GPIO_ADC_LIGHT, i)) {
AdcAttach(Pin(GPIO_ADC_LIGHT, i), ADC_LIGHT); 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)) { if (PinUsed(GPIO_ADC_RANGE, i)) {
AdcAttach(Pin(GPIO_ADC_RANGE, i), ADC_RANGE); AdcAttach(Pin(GPIO_ADC_RANGE, i), ADC_RANGE);
} }
@ -190,6 +203,15 @@ void AdcInit(void) {
AdcAttach(Pin(GPIO_ADC_JOY, i), ADC_JOY); 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) { if (Adcs.present) {
#ifdef ESP32 #ifdef ESP32
analogSetClockDiv(1); // Default 1 analogSetClockDiv(1); // Default 1
@ -253,17 +275,18 @@ void AdcEvery250ms(void) {
} }
#endif // USE_RULES #endif // USE_RULES
bool AdcButtonPresent(uint32_t idx) { uint8_t AdcGetButton(uint32_t pin) {
return ((ADC_BUTTON == Adc[idx].type) || (ADC_BUTTON_INV == Adc[idx].type)); for (uint32_t idx = 0; idx < Adcs.present; idx++) {
} if (Adc[idx].pin == pin) {
if (ADC_BUTTON_INV == Adc[idx].type) {
uint8_t AdcGetButton(uint32_t idx) { return (AdcRead(Adc[idx].pin, 1) < ANALOG_BUTTON);
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) > ANALOG_BUTTON);
else if (ADC_BUTTON == Adc[idx].type) { }
return (AdcRead(Adc[idx].pin, 1) > 128); }
} }
return 0;
} }
uint16_t AdcGetLux(uint32_t idx) { uint16_t AdcGetLux(uint32_t idx) {