diff --git a/BUILDS.md b/BUILDS.md index fa412f8f0..65f34d5fe 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -168,6 +168,7 @@ Note: the `minimal` variant is not listed as it shouldn't be used outside of the | USE_GDK101 | - | - / - | - | - | - | - | | USE_TC74 | - | - / - | - | - | - | - | | USE_PCA9557 | - | - / - | - | - | - | - | +| USE_TCA9554 | - | - / - | - | - | - | - | | USE_AGS02MA | - | - / - | - | - | - | - | | | | | | | | | | **Feature or Sensor** | **l** | **t** | **k** | **s** | **i** | **d** | **Remarks** | diff --git a/CHANGELOG.md b/CHANGELOG.md index 65f13ae4d..a7ba3f130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [15.2.0.1] ### Added +- Support for TCA9554 8-bit I/O expander mutually exclusive with PCA9557 ### Breaking Changed diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 9eba84417..e8aee48d9 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -119,6 +119,7 @@ Index | Define | Driver | Device | Address(es) | Bus2 | Descrip 79 | USE_GDK101 | xsns_106 | GDK101 | 0x18 - 0x1B | | Gamma Radiation Sensor 80 | USE_TC74 | xsns_108 | TC74 | 0x48 - 0x4F | | Temperature sensor 81 | USE_PCA9557 | xdrv_69 | PCA95xx | 0x18 - 0x1F | | 8-bit I/O expander as virtual button/switch/relay + 81 | USE_TCA9554 | xdrv_69 | TCA95xx | 0x20 - 0x27 | | 8-bit I/O expander as virtual button/switch/relay 82 | USE_SGP4X | xsns_109 | SGP4X | 0x59 | | Gas (TVOC/NOx index) 83 | USE_MAX17043 | xsns_110 | MAX17043 | 0x36 | | Fuel-gauge for 3.7 Volt Lipo battery 84 | USE_ENS16x | xsns_111 | ENS16x | 0x52 - 0x53 | | Gas (TVOC, eCO2) and air quality sensor diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b86b34908..3173e14af 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -114,6 +114,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ## Changelog v15.2.0.1 ### Added +- Support for TCA9554 8-bit I/O expander mutually exclusive with PCA9557 ### Changed - Vid6608 library from v1.0.2 to v1.0.3 [#24218](https://github.com/arendst/Tasmota/issues/24218) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index c352fdb16..d2e7089bf 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -789,6 +789,7 @@ // #define TC74_I2C_PROBE_ADDRESSES { 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F } // Addresses to probe/support // #define TC74_MAX_FAILCOUNT 8 // Maximum failed polls before it's marked inactive until reprobing later // #define USE_PCA9557 // [I2cDriver81] Enable PCA9557 8-bit I/O Expander (I2C addresses 0x18 - 0x1F) (+2k5 code) +// #define USE_TCA9554 // [I2cDriver81] Enable TCA9554 8-bit I/O Expander (I2C addresses 0x20 - 0x27) (+2k5 code) // #define USE_MAX17043 // [I2cDriver83] Enable MAX17043 fuel-gauge systems Lipo batteries sensor (I2C address 0x36) (+0k9 code) // #define MAX17043_ALERT_THRESHOLD 32 // [I2cDriver83] Define the alert threshold for low battery level percentage 1-32 // #define USE_AMSX915 // [I2CDriver86] Enable AMS5915/AMS6915 pressure/temperature sensor (+1k2 code) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_69_pca9557.ino b/tasmota/tasmota_xdrv_driver/xdrv_69_pca9557.ino index 5d11d3160..3535386c0 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_69_pca9557.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_69_pca9557.ino @@ -1,5 +1,5 @@ /* - xdrv_69_pca9557.ino - PCA9557 GPIO Expander support for Tasmota + xdrv_69_pca9557.ino - PCA9557 or TCA9554 GPIO Expander support for Tasmota SPDX-FileCopyrightText: 2023 Theo Arends @@ -7,13 +7,17 @@ */ #ifdef USE_I2C -#ifdef USE_PCA9557 +#if defined(USE_PCA9557) || defined(USE_TCA9554) +#if defined(USE_PCA9557) && defined(USE_TCA9554) +#warning Dropped PCA9557 in favour of TCA9554 +#undef USE_PCA9557 +#endif /*********************************************************************************************\ - * 8-bit PCA9557 I2C GPIO Expander to be used as virtual relay + * 8-bit PCA9557/TCA9554 I2C GPIO Expander to be used as virtual relay * * Docs at https://www.nxp.com/products/interfaces/ic-spi-i3c-interface-devices/general-purpose-i-o-gpio/8-bit-ic-bus-and-smbus-i-o-port-with-reset:PCA9557 * - * I2C Addresses: 0x18 - 0x1F + * I2C Addresses: 0x18 - 0x1F (PCA9557), 0x20 - 0x27 (TCA9554) * * The goal of the driver is to provide a sequential list of pins configured as Tasmota template * and handle any input and output as configured GPIOs. @@ -39,8 +43,11 @@ * * Prepare a template to be loaded either by: * - a rule like: rule3 on file#pca9557.dat do {"NAME":"PCA9557","GPIO":[224,225,226,227,228,229,230,231]} endon + * - a rule like: rule3 on file#tca9554.dat do {"NAME":"TCA9554","GPIO":[224,225,226,227,228,229,230,231]} endon * - a script like: -y{"NAME":"PCA9557","GPIO":[224,225,226,227,228,229,230,231]} + * - a script like: -y{"NAME":"TCA9554","GPIO":[224,225,226,227,228,229,230,231]} * - file called pca9557.dat with contents: {"NAME":"PCA9557","GPIO":[224,225,226,227,228,229,230,231]} + * - file called tca9554.dat with contents: {"NAME":"TCA9554","GPIO":[224,225,226,227,228,229,230,231]} * * Inverted relays Ri1 Ri2 Ri3 Ri4 Ri5 Ri6 Ri7 Ri8 * {"NAME":"PCA9557","GPIO":[256,257,258,259,260,261,262,263]} @@ -54,7 +61,10 @@ * 16 relays R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 * {"NAME":"PCA9557","GPIO":[224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239]} * - * + * Waveshare ESP32-S3-POE-ETH-8DI-8RO TCA9554 configuration: + * 8 relays R1 R2 R3 R4 R5 R6 R7 R8 + * {"NAME":"TCA9554","GPIO":[224,225,226,227,228,229,230,231]} + * \*********************************************************************************************/ #define XDRV_69 69 @@ -62,10 +72,25 @@ #define PCA9557_ADDR_START 0x18 // 24 #define PCA9557_ADDR_END 0x20 // 32 (not included) +#define PCA9557_LOG "PCA: " +#define PCA9557_NAME "PCA9557" +#define PCA9557_NAME_LC "pca9557" + +#ifdef USE_TCA9554 +#undef PCA9557_ADDR_START +#undef PCA9557_ADDR_END +#undef PCA9557_LOG +#undef PCA9557_NAME +#undef PCA9557_NAME_LC +#define PCA9557_ADDR_START 0x20 // 32 +#define PCA9557_ADDR_END 0x28 // 40 (not included) +#define PCA9557_LOG "TCA: " +#define PCA9557_NAME "TCA9554" +#define PCA9557_NAME_LC "tca9554" +#endif #define PCA9557_MAX_DEVICES 8 - /*********************************************************************************************\ * PCA9557 support \*********************************************************************************************/ @@ -110,7 +135,7 @@ void PCA9557DumpRegs(void) { for (Pca9557.chip = 0; Pca9557.chip < Pca9557.max_devices; Pca9557.chip++) { uint32_t data_size = sizeof(data); I2cReadBuffer(Pca9557.device[Pca9557.chip].address, 0, data, data_size); - AddLog(LOG_LEVEL_DEBUG, PSTR("PCA: Intf %d, Address %02X, Regs %*_H"), Pca9557.device[Pca9557.chip].address, data_size, data); + AddLog(LOG_LEVEL_DEBUG, PSTR(PCA9557_LOG "Intf %d, Address %02X, Regs %*_H"), Pca9557.device[Pca9557.chip].address, data_size, data); } } @@ -242,11 +267,11 @@ uint32_t PCA9557GetPin(uint32_t lpin) { String PCA9557TemplateLoadFile(void) { String pcatmplt = ""; #ifdef USE_UFILESYS - pcatmplt = TfsLoadString("/pca9557.dat"); + pcatmplt = TfsLoadString("/" PCA9557_NAME_LC ".dat"); #endif // USE_UFILESYS #ifdef USE_RULES if (!pcatmplt.length()) { - pcatmplt = RuleLoadFile("PCA9557.DAT"); + pcatmplt = RuleLoadFile(PCA9557_NAME ".DAT"); } #endif // USE_RULES #ifdef USE_SCRIPT @@ -266,6 +291,7 @@ bool PCA9557LoadTemplate(void) { JsonParserObject root = parser.getRootObject(); if (!root) { return false; } + // rule3 on file#tca9554.dat do {"NAME":"TCA9554","GPIO":[224,225,226,227,228,229,230,231]} endon // rule3 on file#pca9557.dat do {"NAME":"PCA9557","GPIO":[32,33,34,35,36,37,38,39,224,225,226,227,228,229,230,231]} endon // rule3 on file#pca9557.dat do {"NAME":"PCA9557","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} endon // rule3 on file#pca9557.dat do {"NAME":"PCA9557 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} endon @@ -279,7 +305,7 @@ bool PCA9557LoadTemplate(void) { } val = root[PSTR(D_JSON_NAME)]; if (val) { - AddLog(LOG_LEVEL_DEBUG, PSTR("PCA: Base %d, Template '%s'"), Pca9557.base, val.getStr()); + AddLog(LOG_LEVEL_DEBUG, PSTR(PCA9557_LOG "Base %d, Template '%s'"), Pca9557.base, val.getStr()); } JsonParserArray arr = root[PSTR(D_JSON_GPIO)]; if (arr) { @@ -329,14 +355,14 @@ bool PCA9557LoadTemplate(void) { if ((Pca9557.switch_max >= MAX_SWITCHES_SET) || (Pca9557.button_max >= MAX_KEYS_SET) || (Pca9557.relay_max >= MAX_RELAYS_SET)) { - AddLog(LOG_LEVEL_INFO, PSTR("PCA: Max reached (S%d/B%d/R%d)"), Pca9557.switch_max, Pca9557.button_max, Pca9557.relay_max); + AddLog(LOG_LEVEL_INFO, PSTR(PCA9557_LOG "Max reached (S%d/B%d/R%d)"), Pca9557.switch_max, Pca9557.button_max, Pca9557.relay_max); break; } } Pca9557.max_pins = pin; // Max number of configured pins } -// AddLog(LOG_LEVEL_DEBUG, PSTR("PCA: Pins %d, Pca9557_gpio_pin %*_V"), Pca9557.max_pins, Pca9557.max_pins, (uint8_t*)Pca9557_gpio_pin); +// AddLog(LOG_LEVEL_DEBUG, PSTR(PCA9557_LOG "Pins %d, Pca9557_gpio_pin %*_V"), Pca9557.max_pins, Pca9557.max_pins, (uint8_t*)Pca9557_gpio_pin); return true; } @@ -360,7 +386,7 @@ uint32_t PCA9557TemplateGpio(void) { void PCA9557ModuleInit(void) { int32_t pins_needed = PCA9557TemplateGpio(); if (!pins_needed) { - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PCA: Invalid template")); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(PCA9557_LOG "Invalid template")); return; } @@ -373,7 +399,7 @@ void PCA9557ModuleInit(void) { uint8_t buffer; if (PCA9557ValidRead(PCA9557_R2, &buffer)) { - I2cSetActiveFound(pca9557_address, "PCA9557"); + I2cSetActiveFound(pca9557_address, PCA9557_NAME); Pca9557.device[Pca9557.chip].pins = 8; PCA9557Write(PCA9557_R2, 0b00000000); // disable polarity inversion Pca9557.max_devices++; @@ -396,7 +422,7 @@ void PCA9557ModuleInit(void) { if (!Pca9557_gpio_pin) { return; } if (!PCA9557LoadTemplate()) { - AddLog(LOG_LEVEL_INFO, PSTR("PCA: No valid template found")); // Too many GPIO's + AddLog(LOG_LEVEL_INFO, PSTR(PCA9557_LOG "No valid template found")); // Too many GPIO's Pca9557.max_devices = 0; return; } @@ -417,7 +443,7 @@ void PCA9557ServiceInput(void) { for (Pca9557.chip = 0; Pca9557.chip < Pca9557.max_devices; Pca9557.chip++) { gpio = PCA9557Read(PCA9557_R0); // Read PCA9557 gpio -// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PCA: Chip %d, State %02X"), Pca9557.chip, gpio); +// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(PCA9557_LOG "Chip %d, State %02X"), Pca9557.chip, gpio); uint32_t mask = 1; for (uint32_t pin = 0; pin < Pca9557.device[Pca9557.chip].pins; pin++) { @@ -535,5 +561,5 @@ bool Xdrv69(uint32_t function) { return result; } -#endif // USE_PCA9557_DRV +#endif // USE_PCA9557 or USE_TCA9554 #endif // USE_I2C