diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 2040ecfb3..2da23ab80 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -290,6 +290,8 @@ #define USE_LM75AD // Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) // #define USE_APDS9960 // Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) // #define USE_MCP230xx // Enable MCP23008/MCP23017 for GP INPUT ONLY (I2C addresses 0x20 - 0x27) providing command Sensor29 for configuration (+2k2 code) +// #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+1k code) +// #define USE_MCP230xx_DISPLAYOUTPUT // Enable MCP23008/MCP23017 to display state of OUTPUT pins on Web UI (+0k2 code) // #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) // #define USE_CCS811 // Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) // #define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 1b959f771..9d9e7f989 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -58,7 +58,15 @@ uint8_t mcp230xx_addresses[] = { MCP230xx_ADDRESS1, MCP230xx_ADDRESS2, MCP230xx_ uint8_t mcp230xx_pincount = 0; uint8_t mcp230xx_int_en = 0; -const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29D%i\":{\"MODE\":%i,\"PULL-UP\":%i,\"STATE\":%i}}"; +#ifdef USE_MCP230xx_OUTPUT +uint16_t mcp230xx_tele_count = 0; +#endif + +const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29-D%i\":{\"MODE\":%i,\"PULL-UP\":%i,\"STATE\":%i}}"; + +#ifdef USE_MCP230xx_OUTPUT +const char MCP230XX_CMND_RESPONSE[] PROGMEM = "{\"S29cmnd-D%i\":{\"C\":\"%s\",\"R\":%i}}"; +#endif // USE_MCP230xx_OUTPUT uint8_t MCP230xx_readGPIO(uint8_t port) { return I2cRead8(mcp230xx_address, MCP230xx_GPIO + port); @@ -70,6 +78,9 @@ void MCP230xx_ApplySettings(void) { uint8_t reg_gppu = 0; uint8_t reg_gpinten = 0; uint8_t reg_iodir = 0xFF; +#ifdef USE_MCP230xx_OUTPUT + uint8_t reg_portpins = 0x00; +#endif for (uint8_t idx = 0; idx < 8; idx++) { switch (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pinmode) { case 0 ... 1: @@ -80,16 +91,37 @@ void MCP230xx_ApplySettings(void) { reg_gpinten |= (1 << idx); int_en=1; break; +#ifdef USE_MCP230xx_OUTPUT + case 5: + reg_iodir &= ~(1 << idx); + if (Settings.flag.save_state) { // Firmware configuration wants us to use the last pin state + reg_portpins |= (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].b4 << idx); + } else { + if (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pullup) { + reg_portpins |= (1 << idx); + } + } + break; +#endif // USE_MCP230xx_OUTPUT default: break; } +#ifdef USE_MCP230xx_OUTPUT + if (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pullup && (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pinmode != 5)) { + reg_gppu |= (1 << idx); + } +#else if (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pullup) { reg_gppu |= (1 << idx); } +#endif } I2cWrite8(mcp230xx_address, MCP230xx_GPPU+mcp230xx_port, reg_gppu); I2cWrite8(mcp230xx_address, MCP230xx_GPINTEN+mcp230xx_port, reg_gpinten); I2cWrite8(mcp230xx_address, MCP230xx_IODIR+mcp230xx_port, reg_iodir); +#ifdef USE_MCP230xx_OUTPUT + I2cWrite8(mcp230xx_address, MCP230xx_GPIO+mcp230xx_port, reg_portpins); +#endif } mcp230xx_int_en=int_en; } @@ -196,6 +228,41 @@ void MCP230xx_Show(boolean json) } } +#ifdef USE_MCP230xx_OUTPUT + +void MCP230xx_SetOutPin(uint8_t pin,uint8_t pinstate) { + uint8_t portpins; + uint8_t port = 0; + char cmnd[7]; + if (pin > 7) port=1; + portpins = MCP230xx_readGPIO(port); + if (pinstate < 2) { + if (pinstate) portpins |= (1 << pin-(port*8)); else portpins &= ~(1 << pin-(port*8)); + } else { + portpins ^= (1 << pin-(port*8)); + } + I2cWrite8(mcp230xx_address, MCP230xx_GPIO + port, portpins); + if (Settings.flag.save_state) { // Firmware configured to save last known state in settings + Settings.mcp230xx_config[pin].b4=portpins>>(pin-(port*8))&1; + } + switch (pinstate) { + case 0: + sprintf(cmnd,"OFF"); + break; + case 1: + sprintf(cmnd,"ON"); + break; + case 2: + sprintf(cmnd,"TOGGLE"); + break; + default: + break; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_CMND_RESPONSE, pin, cmnd,(portpins >> (pin-(port*8)))&1); +} + +#endif // USE_MCP230xx_OUTPUT + void MCP230xx_Reset(uint8_t pinmode) { uint8_t pullup = 0; if ((pinmode > 1) && (pinmode < 5)) pullup=1; @@ -222,6 +289,9 @@ bool MCP230xx_Command(void) { if (data == "RESET2") { MCP230xx_Reset(2); return serviced; } if (data == "RESET3") { MCP230xx_Reset(3); return serviced; } if (data == "RESET4") { MCP230xx_Reset(4); return serviced; } +#ifdef USE_MCP230xx_OUTPUT + if (data == "RESET5") { MCP230xx_Reset(5); return serviced; } +#endif _a = data.indexOf(","); pin = data.substring(0, _a).toInt(); if (pin < mcp230xx_pincount) { @@ -233,13 +303,33 @@ bool MCP230xx_Command(void) { snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_SENSOR_RESPONSE,pin,Settings.mcp230xx_config[pin].pinmode,Settings.mcp230xx_config[pin].pullup,portdata>>(pin-(port*8))&1); return serviced; } +#ifdef USE_MCP230xx_OUTPUT + if (Settings.mcp230xx_config[pin].pinmode == 5) { + if (cmnd == "ON") { + MCP230xx_SetOutPin(pin,1); + return serviced; + } + if (cmnd == "OFF") { + MCP230xx_SetOutPin(pin,0); + return serviced; + } + if (cmnd == "T") { + MCP230xx_SetOutPin(pin,2); + return serviced; + } + } +#endif // USE_MCP230xx_OUTPUT } _b = data.indexOf(",", _a + 1); if (_a < XdrvMailbox.data_len) { if (_b < XdrvMailbox.data_len) { pinmode = data.substring(_a+1, _b).toInt(); pullup = data.substring(_b+1, XdrvMailbox.data_len).toInt(); +#ifdef USE_MCP230xx_OUTPUT + if ((pin < mcp230xx_pincount) && (pinmode < 6) && (pullup < 2)) { +#else // not USE_MCP230xx_OUTPUT if ((pin < mcp230xx_pincount) && (pinmode < 5) && (pullup < 2)) { +#endif // USE_MCP230xx_OUTPUT Settings.mcp230xx_config[pin].pinmode=pinmode; Settings.mcp230xx_config[pin].pullup=pullup; MCP230xx_ApplySettings(); @@ -259,6 +349,55 @@ bool MCP230xx_Command(void) { return serviced; } +#ifdef USE_MCP230xx_DISPLAYOUTPUT + +const char HTTP_SNS_MCP230xx_OUTPUT[] PROGMEM = "%s{s}MCP230XX D%d{m}%d{e}"; // {s} =