diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h
index 8858eea2f..016e62e41 100644
--- a/sonoff/language/en-GB.h
+++ b/sonoff/language/en-GB.h
@@ -166,6 +166,7 @@
#define D_VOLTAGE "Voltage"
#define D_WARMLIGHT "Warm"
#define D_WEB_SERVER "Web Server"
+#define D_CONFIGURE_MCP230XX "Configure MCP230xx"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "WARNING This version does not support persistent settings"
diff --git a/sonoff/user_config.h b/sonoff/user_config.h
index a0fdcfec2..12a4924b1 100644
--- a/sonoff/user_config.h
+++ b/sonoff/user_config.h
@@ -287,6 +287,12 @@
// #define USE_MGS // Add I2C code for Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code)
#define MGS_SENSOR_ADDR 0x04 // Default Mutichannel Gas sensor i2c address
// #define USE_APDS9960 // Add I2C code for APDS9960 Proximity Sensor. Disables SHT and VEML6070 (+4k7 code)
+
+ // If only USE_MCP230xx then device can be configured using sensor29 command
+// #define USE_MCP230xx // Add I2C code for MCP23008/MCP23017 for GP INPUT ONLY (+2260 bytes)
+// #define USE_MCP230xx_displaymain // Display pin status on Tasmota main page (+188 bytes)
+// #define USE_MCP230xx_webconfig // Enable web config button and form to Tasmota web interface (+2444)
+
#endif // USE_I2C
// -- SPI sensors ---------------------------------
diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino
index 12ed741ac..ec6423e6b 100644
--- a/sonoff/xdrv_02_webserver.ino
+++ b/sonoff/xdrv_02_webserver.ino
@@ -202,6 +202,14 @@ const char HTTP_BTN_MENU_MQTT[] PROGMEM =
"
"
#endif // USE_DOMOTICZ
"";
+#ifdef USE_I2C
+#ifdef USE_MCP230xx
+#ifdef USE_MCP230xx_webconfig
+ const char HTTP_BTN_MCP230XX[] PROGMEM =
+ "
";
+#endif // USE_MCP230xx_webconfig
+#endif // USE_MCP230xx
+#endif // USE_I2C
const char HTTP_BTN_MENU4[] PROGMEM =
#ifdef USE_KNX
"
"
@@ -376,6 +384,13 @@ void StartWebserver(int type, IPAddress ipweb)
WebServer->on("/u2", HTTP_OPTIONS, HandlePreflightRequest);
WebServer->on("/cm", HandleHttpCommand);
WebServer->on("/rb", HandleRestart);
+#ifdef USE_I2C
+#ifdef USE_MCP230xx
+#ifdef USE_MCP230xx_webconfig
+ WebServer->on("/mcp230xx", handleMCP230xx);
+#endif // USE_MCP230xx_webconfig
+#endif // USE_MCP230xx
+#endif // USE_I2C
#ifndef BE_MINIMAL
WebServer->on("/cn", HandleConfiguration);
WebServer->on("/md", HandleModuleConfiguration);
@@ -695,6 +710,15 @@ void HandleConfiguration()
#endif // USE_TIMERS and USE_TIMERS_WEB
page += FPSTR(HTTP_BTN_MENU_WIFI);
if (Settings.flag.mqtt_enabled) { page += FPSTR(HTTP_BTN_MENU_MQTT); }
+#ifdef USE_I2C
+#ifdef USE_MCP230xx
+#ifdef USE_MCP230xx_webconfig
+ if (MCP230xx_Type()) { // Configuration button will only show if MCP23008/MCP23017 was detected on I2C
+ page += FPSTR(HTTP_BTN_MCP230XX);
+ }
+#endif // USE_MCP230xx_webconfig
+#endif // USE_MCP230xx
+#endif // USE_I2C
page += FPSTR(HTTP_BTN_MENU4);
page += FPSTR(HTTP_BTN_MAIN);
ShowPage(page);
@@ -1124,6 +1148,15 @@ void HandleSaveSettings()
}
AddLog(LOG_LEVEL_INFO);
break;
+#ifdef USE_I2C
+#ifdef USE_MCP230xx
+#ifdef USE_MCP230xx_webconfig
+ case 8: // MCP230xx_SaveSettings
+ MCP230xx_SaveSettings();
+ break;
+#endif // USE_MCP230xx_webconfig
+#endif // USE_MCP230xx
+#endif // USE_I2C
case 6:
WebGetArg("g99", tmp, sizeof(tmp));
byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp);
diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino
new file mode 100644
index 000000000..9aa0bc260
--- /dev/null
+++ b/sonoff/xsns_29_mcp230xx.ino
@@ -0,0 +1,467 @@
+/*
+ xsns_29_mcp230xx.ino - Support for I2C MCP23008/MCP23017 GPIO Expander (INPUT ONLY!)
+
+ Copyright (C) 2018 Andre Thomas and 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_I2C
+#ifdef USE_MCP230xx
+
+/*********************************************************************************************\
+ MCP23008/17 - I2C GPIO EXPANDER
+
+ Docs at https://www.microchip.com/wwwproducts/en/MCP23008
+ https://www.microchip.com/wwwproducts/en/MCP23017
+
+ I2C Address: 0x20 - 0x27
+ \*********************************************************************************************/
+
+#define XSNS_29 29
+
+#define MCP230xx_ADDRESS1 0x20
+#define MCP230xx_ADDRESS2 0x21
+#define MCP230xx_ADDRESS3 0x22
+#define MCP230xx_ADDRESS4 0x23
+#define MCP230xx_ADDRESS5 0x24
+#define MCP230xx_ADDRESS6 0x25
+#define MCP230xx_ADDRESS7 0x26
+#define MCP230xx_ADDRESS8 0x27
+
+/*
+ Default register locations for MCP23008 - They change for MCP23017 in default bank mode
+*/
+
+uint8_t MCP230xx_IODIR = 0x00;
+uint8_t MCP230xx_GPINTEN = 0x02;
+uint8_t MCP230xx_IOCON = 0x05;
+uint8_t MCP230xx_GPPU = 0x06;
+uint8_t MCP230xx_INTF = 0x07;
+uint8_t MCP230xx_INTCAP = 0x08;
+uint8_t MCP230xx_GPIO = 0x09;
+
+uint8_t mcp230xx_type = 0;
+uint8_t mcp230xx_address;
+uint8_t mcp230xx_addresses[] = { MCP230xx_ADDRESS1, MCP230xx_ADDRESS2, MCP230xx_ADDRESS3, MCP230xx_ADDRESS4, MCP230xx_ADDRESS5, MCP230xx_ADDRESS6, MCP230xx_ADDRESS7, MCP230xx_ADDRESS8 };
+uint8_t mcp280xx_pincount = 0;
+
+const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29\":{\"D\":%i,\"MODE\":%i,\"PULL-UP\":%i}}";
+
+#ifdef USE_WEBSERVER
+#ifdef USE_MCP230xx_displaymain
+const char HTTP_SNS_MCP230xx_GPIO[] PROGMEM = "%s{s}MCP230XX D%d{m}%d{e}"; // {s} = , {m} = | , {e} = |
+#endif // USE_MCP230xx_displaymain
+#ifdef USE_MCP230xx_webconfig
+const char MCP230XX_OPTION_SELECTED[] PROGMEM = " selected";
+const char MCP230XX_OPTION_BLANK[] PROGMEM = "";
+const char MCP230XX_OPTION_CHECKED[] PROGMEM = " checked";
+const char HTTP_FORM_I2C_MCP230XX_T[] PROGMEM = "";
+const char HTTP_FORM_I2C_MCP230XX_TE[] PROGMEM = "
";
+
+const char HTTP_FORM_MCP230XX[] PROGMEM =
+ "