From 055331d2ab1a1aedaab4f4385ffbed9cadd39b40 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 6 Feb 2023 15:57:27 +0100 Subject: [PATCH] Breaking change TM1638 button and led support Breaking change TM1638 button and led support are handled as virtual switches and relays (#11031) --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + tasmota/tasmota_support/support_features.ino | 2 +- tasmota/tasmota_support/support_tasmota.ino | 4 - tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino | 4 - .../tasmota_xdrv_driver/xdrv_66_tm1638.ino | 269 ++++++++++++++++++ .../tasmota_xsns_sensor/xsns_28_tm1638.ino | 228 --------------- 7 files changed, 272 insertions(+), 237 deletions(-) create mode 100644 tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino delete mode 100644 tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d791e59780f..c6f83fd81236 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - Basic support for Shelly Pro 4PM ### Breaking Changed +- TM1638 button and led support are handled as virtual switches and relays (#11031) ### Changed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d78f13e59fe0..f7394926325b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -134,6 +134,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger ### Breaking Changed +- TM1638 button and led support are handled as virtual switches and relays [#11031](https://github.com/arendst/Tasmota/issues/11031) ### Changed - ESP32 Framework (Core) from v2.0.5.3 to v2.0.6 (IPv6 support) diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index bae2916b3ebe..c576f5d07686 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -319,7 +319,7 @@ void ResponseAppendFeatures(void) feature3 |= 0x40000000; // xsns_27_apds9960.ino #endif #ifdef USE_TM1638 - feature3 |= 0x80000000; // xsns_28_tm1638.ino + feature3 |= 0x80000000; // xdrv_66_tm1638.ino #endif } diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index 54ecd4a29e54..416ee8c0e584 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -963,11 +963,7 @@ bool MqttShowSensor(bool call_show_sensor) { int json_data_start = ResponseLength(); for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { -#ifdef USE_TM1638 - if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB))) { -#else if (SwitchUsed(i)) { -#endif // USE_TM1638 ResponseAppend_P(PSTR(",\"%s\":\"%s\""), GetSwitchText(i).c_str(), GetStateText(SwitchState(i))); } } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino index 6ad3cc6465b1..d8ad9eed2797 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino @@ -965,11 +965,7 @@ void RulesEvery50ms(void) } // Boot time SWITCHES Status for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { -#ifdef USE_TM1638 - if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB))) { -#else if (SwitchUsed(i)) { -#endif // USE_TM1638 snprintf_P(json_event, sizeof(json_event), PSTR("{\"%s\":{\"Boot\":%d}}"), GetSwitchText(i).c_str(), (SwitchState(i))); RulesProcessEvent(json_event); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino new file mode 100644 index 000000000000..145122472e9c --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino @@ -0,0 +1,269 @@ +/* + xdrv_66_tm1638.ino - TM1638 8 switch, led and 7 segment unit support for Tasmota + + Copyright (C) 2021 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_TM1638 +/*********************************************************************************************\ + * TM1638 8 switch, led and 7 segment + * + * Uses GPIO TM1638 DIO, TM1638 CLK and TM1638 STB +\*********************************************************************************************/ + +#define XDRV_66 66 + +#ifdef TM1638_USE_AS_BUTTON +#define TM1638_USE_BUTTONS // Use keys as buttons +#endif +#ifdef TM1638_USE_AS_SWITCH +#undef TM1638_USE_BUTTONS // Use keys as switches +#endif +#ifndef TM1638_MAX_DISPLAYS +#define TM1638_MAX_DISPLAYS 8 +#endif +#ifndef TM1638_MAX_KEYS +#define TM1638_MAX_KEYS 8 +#endif +#ifndef TM1638_MAX_LEDS +#define TM1638_MAX_LEDS 8 +#endif + +#define TM1638_COLOR_NONE 0 +#define TM1638_COLOR_RED 1 +#define TM1638_COLOR_GREEN 2 + +#define TM1638_CLOCK_DELAY 1 // uSec + +struct TM1638 { + int8_t clock_pin = 0; + int8_t data_pin = 0; + int8_t strobe_pin = 0; + int8_t key_offset; + int8_t led_offset; + uint8_t displays; + uint8_t power; + + uint8_t active_display = 1; + uint8_t intensity = 0; + bool detected = false; +} Tm1638; + +/*********************************************************************************************\ + * Pieces from library https://github.com/rjbatista/tm1638-library + * and from library https://github.com/MartyMacGyver/TM1638-demos-and-examples +\*********************************************************************************************/ + +void Tm16XXSend(uint8_t data) { + for (uint32_t i = 0; i < 8; i++) { + digitalWrite(Tm1638.data_pin, !!(data & (1 << i))); + digitalWrite(Tm1638.clock_pin, LOW); + delayMicroseconds(TM1638_CLOCK_DELAY); + digitalWrite(Tm1638.clock_pin, HIGH); + } +} + +void Tm16XXSendCommand(uint8_t cmd) { + digitalWrite(Tm1638.strobe_pin, LOW); + Tm16XXSend(cmd); + digitalWrite(Tm1638.strobe_pin, HIGH); +} + +void TM16XXSendData(uint8_t address, uint8_t data) { + Tm16XXSendCommand(0x44); + digitalWrite(Tm1638.strobe_pin, LOW); + Tm16XXSend(0xC0 | address); + Tm16XXSend(data); + digitalWrite(Tm1638.strobe_pin, HIGH); +} + +uint8_t Tm16XXReceive(void) { + uint8_t temp = 0; + + // Pull-up on + pinMode(Tm1638.data_pin, INPUT); + digitalWrite(Tm1638.data_pin, HIGH); + + for (uint32_t i = 0; i < 8; ++i) { + digitalWrite(Tm1638.clock_pin, LOW); + delayMicroseconds(TM1638_CLOCK_DELAY); + temp |= digitalRead(Tm1638.data_pin) << i; + digitalWrite(Tm1638.clock_pin, HIGH); + } + + // Pull-up off + pinMode(Tm1638.data_pin, OUTPUT); + digitalWrite(Tm1638.data_pin, LOW); + + return temp; +} + +/*********************************************************************************************/ + +void Tm16XXClearDisplay(void) { + for (uint32_t i = 0; i < Tm1638.displays; i++) { + TM16XXSendData(i << 1, 0); + } +} + +void Tm1638SetLED(uint8_t color, uint8_t pos) { + TM16XXSendData((pos << 1) + 1, color); +} + +void Tm1638SetLEDs(word leds) { + for (uint32_t i = 0; i < Tm1638.displays; i++) { + uint8_t color = 0; + + if ((leds & (1 << i)) != 0) { + color |= TM1638_COLOR_RED; + } + + if ((leds & (1 << (i + 8))) != 0) { + color |= TM1638_COLOR_GREEN; + } + + Tm1638SetLED(color, i); + } +} + +uint8_t Tm1638GetButtons(void) { + uint8_t keys = 0; + + digitalWrite(Tm1638.strobe_pin, LOW); + Tm16XXSend(0x42); + for (uint32_t i = 0; i < 4; i++) { + keys |= Tm16XXReceive() << i; + } + digitalWrite(Tm1638.strobe_pin, HIGH); + + return keys; +} + +/*********************************************************************************************/ + +void TmInit(void) { + if (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB)) { + Tm1638.clock_pin = Pin(GPIO_TM1638CLK); + Tm1638.data_pin = Pin(GPIO_TM1638DIO); + Tm1638.strobe_pin = Pin(GPIO_TM1638STB); + + pinMode(Tm1638.data_pin, OUTPUT); + pinMode(Tm1638.clock_pin, OUTPUT); + pinMode(Tm1638.strobe_pin, OUTPUT); + + digitalWrite(Tm1638.strobe_pin, HIGH); + digitalWrite(Tm1638.clock_pin, HIGH); + + Tm16XXSendCommand(0x40); + Tm16XXSendCommand(0x80 | (Tm1638.active_display ? 8 : 0) | tmin(7, Tm1638.intensity)); + + digitalWrite(Tm1638.strobe_pin, LOW); + Tm16XXSend(0xC0); + for (uint32_t i = 0; i < 16; i++) { + Tm16XXSend(0x00); + } + digitalWrite(Tm1638.strobe_pin, HIGH); + + // Dirty hack to offset TM1638 leds from GPIO relays + // At this time in code sequence the number of GPIO relays has not been established + uint32_t bi_device = 0; + uint32_t devices_present = 0; + for (uint32_t i = 0; i < MAX_RELAYS; i++) { + if (PinUsed(GPIO_REL1, i)) { + devices_present++; + if (bitRead(TasmotaGlobal.rel_bistable, i)) { + if (bi_device &1) { devices_present--; } + bi_device++; + } + } + } + + Tm1638.led_offset = devices_present; + TasmotaGlobal.devices_present += TM1638_MAX_LEDS; + Tm1638.key_offset = -1; + Tm1638.displays = TM1638_MAX_DISPLAYS; + Tm1638.detected = true; + } +} + +void TmLoop(void) { + uint8_t buttons = Tm1638GetButtons(); + for (uint32_t i = 0; i < TM1638_MAX_KEYS; i++) { + uint32_t state = buttons &1; +#ifdef TM1638_USE_BUTTONS + ButtonSetVirtualPinState(Tm1638.key_offset +i, state); +#else + SwitchSetVirtualPinState(Tm1638.key_offset +i, state ^1); +#endif + buttons >>= 1; + } +} + +void TmPower(void) { + power_t rpower = XdrvMailbox.index >> Tm1638.led_offset; + for (uint32_t i = 0; i < TM1638_MAX_LEDS; i++) { + uint32_t state = rpower &1; + uint8_t color = (state) ? TM1638_COLOR_RED : TM1638_COLOR_NONE; + Tm1638SetLED(color, i); + rpower >>= 1; // Select next power + } +} + +bool TmAddKey(void) { + // XdrvMailbox.index = button/switch index + if (Tm1638.key_offset < 0) { Tm1638.key_offset = XdrvMailbox.index; } + uint32_t index = XdrvMailbox.index - Tm1638.key_offset; + if (index >= TM1638_MAX_KEYS) { return false; } + uint8_t buttons = Tm1638GetButtons(); + uint32_t state = bitRead(buttons, index); +#ifdef TM1638_USE_BUTTONS + XdrvMailbox.index = state | BUTTON_INVERT; // Invert - default is 0 +#else + XdrvMailbox.index = state ^1; // Invert - default is 0 +#endif + return true; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv66(uint32_t function) { + bool result = false; + + if (FUNC_MODULE_INIT == function) { + TmInit(); + } else if (Tm1638.detected) { + switch (function) { + case FUNC_EVERY_50_MSECOND: + TmLoop(); + break; + case FUNC_SET_POWER: + TmPower(); + break; +#ifdef TM1638_USE_BUTTONS + case FUNC_ADD_BUTTON: +#else + case FUNC_ADD_SWITCH: +#endif + result = TmAddKey(); + break; + } + } + return result; +} + +#endif // USE_TM1638 \ No newline at end of file diff --git a/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino b/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino deleted file mode 100644 index 8a0cdb8f8fa1..000000000000 --- a/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino +++ /dev/null @@ -1,228 +0,0 @@ -/* - xsns_28_tm1638.ino - TM1638 8 switch, led and 7 segment unit support for Tasmota - - Copyright (C) 2021 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_TM1638 -/*********************************************************************************************\ - * TM1638 8 switch, led and 7 segment - * - * Uses GPIO TM1638 DIO, TM1638 CLK and TM1638 STB -\*********************************************************************************************/ - -#define XSNS_28 28 - -#define TM1638_COLOR_NONE 0 -#define TM1638_COLOR_RED 1 -#define TM1638_COLOR_GREEN 2 - -#define TM1638_CLOCK_DELAY 1 // uSec - -uint8_t tm1638_type = 1; -int8_t tm1638_clock_pin = 0; -int8_t tm1638_data_pin = 0; -int8_t tm1638_strobe_pin = 0; -uint8_t tm1638_displays = 8; -uint8_t tm1638_active_display = 1; -uint8_t tm1638_intensity = 0; -uint8_t tm1638_state = 0; - -/*********************************************************************************************\ - * Pieces from library https://github.com/rjbatista/tm1638-library - * and from library https://github.com/MartyMacGyver/TM1638-demos-and-examples -\*********************************************************************************************/ - -void Tm16XXSend(uint8_t data) -{ - for (uint32_t i = 0; i < 8; i++) { - digitalWrite(tm1638_data_pin, !!(data & (1 << i))); - digitalWrite(tm1638_clock_pin, LOW); - delayMicroseconds(TM1638_CLOCK_DELAY); - digitalWrite(tm1638_clock_pin, HIGH); - } -} - -void Tm16XXSendCommand(uint8_t cmd) -{ - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(cmd); - digitalWrite(tm1638_strobe_pin, HIGH); -} - -void TM16XXSendData(uint8_t address, uint8_t data) -{ - Tm16XXSendCommand(0x44); - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(0xC0 | address); - Tm16XXSend(data); - digitalWrite(tm1638_strobe_pin, HIGH); -} - -uint8_t Tm16XXReceive(void) -{ - uint8_t temp = 0; - - // Pull-up on - pinMode(tm1638_data_pin, INPUT); - digitalWrite(tm1638_data_pin, HIGH); - - for (uint32_t i = 0; i < 8; ++i) { - digitalWrite(tm1638_clock_pin, LOW); - delayMicroseconds(TM1638_CLOCK_DELAY); - temp |= digitalRead(tm1638_data_pin) << i; - digitalWrite(tm1638_clock_pin, HIGH); - } - - // Pull-up off - pinMode(tm1638_data_pin, OUTPUT); - digitalWrite(tm1638_data_pin, LOW); - - return temp; -} - -/*********************************************************************************************/ - -void Tm16XXClearDisplay(void) -{ - for (uint32_t i = 0; i < tm1638_displays; i++) { - TM16XXSendData(i << 1, 0); - } -} - -void Tm1638SetLED(uint8_t color, uint8_t pos) -{ - TM16XXSendData((pos << 1) + 1, color); -} - -void Tm1638SetLEDs(word leds) -{ - for (uint32_t i = 0; i < tm1638_displays; i++) { - uint8_t color = 0; - - if ((leds & (1 << i)) != 0) { - color |= TM1638_COLOR_RED; - } - - if ((leds & (1 << (i + 8))) != 0) { - color |= TM1638_COLOR_GREEN; - } - - Tm1638SetLED(color, i); - } -} - -uint8_t Tm1638GetButtons(void) -{ - uint8_t keys = 0; - - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(0x42); - for (uint32_t i = 0; i < 4; i++) { - keys |= Tm16XXReceive() << i; - } - digitalWrite(tm1638_strobe_pin, HIGH); - - return keys; -} - -/*********************************************************************************************/ - -void TmInit(void) -{ - tm1638_type = 0; - if (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB)) { - tm1638_clock_pin = Pin(GPIO_TM1638CLK); - tm1638_data_pin = Pin(GPIO_TM1638DIO); - tm1638_strobe_pin = Pin(GPIO_TM1638STB); - - pinMode(tm1638_data_pin, OUTPUT); - pinMode(tm1638_clock_pin, OUTPUT); - pinMode(tm1638_strobe_pin, OUTPUT); - - digitalWrite(tm1638_strobe_pin, HIGH); - digitalWrite(tm1638_clock_pin, HIGH); - - Tm16XXSendCommand(0x40); - Tm16XXSendCommand(0x80 | (tm1638_active_display ? 8 : 0) | tmin(7, tm1638_intensity)); - - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(0xC0); - for (uint32_t i = 0; i < 16; i++) { - Tm16XXSend(0x00); - } - digitalWrite(tm1638_strobe_pin, HIGH); - - tm1638_type = 1; - tm1638_state = 1; - } -} - -void TmLoop(void) -{ - if (tm1638_state) { - uint8_t buttons = Tm1638GetButtons(); - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - SwitchSetVirtual(i, (buttons &1) ^1); - uint8_t color = (SwitchGetVirtual(i)) ? TM1638_COLOR_NONE : TM1638_COLOR_RED; - Tm1638SetLED(color, i); - buttons >>= 1; - } - SwitchHandler(1); - } -} - -/* -void TmShow(bool json) -{ - if (tm1638_type) { - - } -} -*/ - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xsns28(uint32_t function) -{ - bool result = false; - - if (tm1638_type) { - switch (function) { - case FUNC_INIT: - TmInit(); - break; - case FUNC_EVERY_50_MSECOND: - TmLoop(); - break; -/* - case FUNC_JSON_APPEND: - TmShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - TmShow(0); - break; -#endif // USE_WEBSERVER -*/ - } - } - return result; -} - -#endif // USE_TM1638 \ No newline at end of file