From 05cc738b7f2491b7e3457cff3a43bace0783139e Mon Sep 17 00:00:00 2001 From: Rene Bartsch Date: Fri, 6 Jul 2018 15:34:15 +0200 Subject: [PATCH 01/46] #define USE_MPR121 added for MPR121 touch button controller. --- sonoff/user_config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 0c4aa66f5..4b45118b8 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -277,6 +277,8 @@ // #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) +// #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons + #endif // USE_I2C // -- SPI sensors --------------------------------- From a01edf6fd2152f12f541cf47f4ab4afc70272a4a Mon Sep 17 00:00:00 2001 From: Rene Bartsch Date: Fri, 6 Jul 2018 15:41:16 +0200 Subject: [PATCH 02/46] MPR121 touch button driver added. The Freescale MPR121 is a 12-channel proximity capacitive touch sensor Controller. It can handle 12 electrodes as touch buttons. --- sonoff/xsns_30_mpr121.ino | 447 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 sonoff/xsns_30_mpr121.ino diff --git a/sonoff/xsns_30_mpr121.ino b/sonoff/xsns_30_mpr121.ino new file mode 100644 index 000000000..0f27ccc59 --- /dev/null +++ b/sonoff/xsns_30_mpr121.ino @@ -0,0 +1,447 @@ +/** + * + * @file xsns_30_mpr121.ino + * + * @package Sonoff-Tasmota + * @subpackage Sensors + * @name MPR121 + * + * @description Driver for up to 4x Freescale MPR121 Proximity Capacitive Touch Sensor Controllers (Only touch buttons). + * + * @author Rene 'Renne' Bartsch, B.Sc. Informatics, + * @copyright Rene 'Renne' Bartsch 2018 + * @date $Date$ + * @version $Id$ + * + * @link https://github.com/arendst/Sonoff-Tasmota/wiki/MPR121 \endlink + * @link https://www.sparkfun.com/datasheets/Components/MPR121.pdf \endlink + * @link http://cache.freescale.com/files/sensors/doc/app_note/AN3891.pdf \endlink + * @link http://cache.freescale.com/files/sensors/doc/app_note/AN3892.pdf \endlink + * @link http://cache.freescale.com/files/sensors/doc/app_note/AN3893.pdf \endlink + * @link http://cache.freescale.com/files/sensors/doc/app_note/AN3894.pdf \endlink + * @link http://cache.freescale.com/files/sensors/doc/app_note/AN3895.pdf \endlink + * + * @license GNU GPL v.3 + */ + + /* + * 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_MPR121 + +/** @defgroup group1 MPR121 + * MPR121 preprocessor directives + * @{ + */ + +/** Electrodes Status Register. */ +#define MPR121_ELEX_REG 0x00 + +/** ELEC0-11 Maximum Half Delta Rising Register. */ +#define MPR121_MHDR_REG 0x2B + +/** ELEC0-11 Maximum Half Delta Rising Value. */ +#define MPR121_MHDR_VAL 0x01 + +/** ELEC0-11 Noise Half Delta Falling Register. */ +#define MPR121_NHDR_REG 0x2C + +/** ELEC0-11 Noise Half Delta Falling Value. */ +#define MPR121_NHDR_VAL 0x01 + +/** ELEC0-11 Noise Count Limit Rising Register. */ +#define MPR121_NCLR_REG 0x2D + +/** ELEC0-11 Noise Count Limit Rising Value. */ +#define MPR121_NCLR_VAL 0x0E + +/** ELEC0-11 Maximum Half Delta Falling Register. */ +#define MPR121_MHDF_REG 0x2F + +/** ELEC0-11 Maximum Half Delta Falling Value. */ +#define MPR121_MHDF_VAL 0x01 + +/** ELEC0-11 Noise Half Delta Falling Register. */ +#define MPR121_NHDF_REG 0x30 + +/** ELEC0-11 Noise Half Delta Falling Value. */ +#define MPR121_NHDF_VAL 0x05 + +/** ELEC0-11 Noise Count Limit Falling Register. */ +#define MPR121_NCLF_REG 0x31 + +/** ELEC0-11 Noise Count Limit Falling Value. */ +#define MPR121_NCLF_VAL 0x01 + +/** Proximity Maximum Half Delta Rising Register. */ +#define MPR121_MHDPROXR_REG 0x36 + +/** Proximity Maximum Half Delta Rising Value. */ +#define MPR121_MHDPROXR_VAL 0x3F + +/** Proximity Noise Half Delta Rising Register. */ +#define MPR121_NHDPROXR_REG 0x37 + +/** Proximity Noise Half Delta Rising Value. */ +#define MPR121_NHDPROXR_VAL 0x5F + +/** Proximity Noise Count Limit Rising Register. */ +#define MPR121_NCLPROXR_REG 0x38 + +/** Proximity Noise Count Limit Rising Value. */ +#define MPR121_NCLPROXR_VAL 0x04 + +/** Proximity Filter Delay Count Limit Rising Register. */ +#define MPR121_FDLPROXR_REG 0x39 + +/** Proximity Filter Delay Count Limit Rising Value. */ +#define MPR121_FDLPROXR_VAL 0x00 + +/** Proximity Maximum Half Delta Falling Register. */ +#define MPR121_MHDPROXF_REG 0x3A + +/** Proximity Maximum Half Delta Falling Value. */ +#define MPR121_MHDPROXF_VAL 0x01 + +/** Proximity Noise Half Delta Falling Register. */ +#define MPR121_NHDPROXF_REG 0x3B + +/** Proximity Noise Half Delta Falling Value. */ +#define MPR121_NHDPROXF_VAL 0x01 + +/** Proximity Noise Count Limit Falling Register. */ +#define MPR121_NCLPROXF_REG 0x3C + +/** Proximity Noise Count Limit Falling Value. */ +#define MPR121_NCLPROXF_VAL 0x1F + +/** Proximity Filter Delay Count Limit Falling Register. */ +#define MPR121_FDLPROXF_REG 0x3D + +/** Proximity Filter Delay Count Limit Falling Value. */ +#define MPR121_FDLPROXF_VAL 0x04 + +/** First Electrode Touch Threshold Register. */ +#define MPR121_E0TTH_REG 0x41 + +/** First Electrode Touch Threshold Value. */ +#define MPR121_E0TTH_VAL 12 + +/** First Electrode Release Threshold Register. */ +#define MPR121_E0RTH_REG 0x42 + +/** First Electrode Release Threshold Value. */ +#define MPR121_E0RTH_VAL 6 + +/** Global CDC/CDT Configuration Register. */ +#define MPR121_CDT_REG 0x5D + +/** Global CDC/CDT Configuration Value. */ +#define MPR121_CDT_VAL 0x20 + +/** Enable electrodes Register. */ +#define MPR121_ECR_REG 0x5E + +/** Enable electrodes Value. */ +#define MPR121_ECR_VAL 0x8F // Start ELE0-11 with first 5 bits of baseline tracking +//#define MPR121_ECR_VAL 0xBF // Start ELE0-11 + proximity with first 5 bits of baseline tracking + +/** Soft-reset Register. */ +#define MPR121_SRST_REG 0x80 + +/** Soft-reset Value. */ +#define MPR121_SRST_VAL 0x63 + +/** Get bit of variable 'current' of sensor at position. */ +#define BITC(sensor, position) ((pS->current[sensor] >> position) & 1) + +/** Get bit of variable 'previous' of sensor at position. */ +#define BITP(sensor, position) ((pS->previous[sensor] >> position) & 1) + +/**@}*/ + + +/** + * MPR121 sensors status and data struct. + * + * The struct mpr121 uses the indices of i2c_addr and id to link the specific sensors to an I2C address and a human-readable ID + * and the indices of the arrays connected, running, current and previous to store sensor status and data of a specific sensor. + * + */ +typedef struct mpr121 { + const uint8_t i2c_addr[4] = { 0x5A, 0x5B, 0x5C, 0x5D }; /** I2C addresses of MPR121 controller */ + const char id[4] = { 'A', 'B', 'C', 'D' }; /** Human-readable sensor IDs*/ + bool connected[4] = { false, false, false, false }; /** Status if sensor is connected at I2C address */ + bool running[4] = { false, false, false, false }; /** Running state of sensor */ + uint16_t current[4] = { 0x0000, 0x0000, 0x0000, 0x0000 }; /** Current values in electrode register of sensor */ + uint16_t previous[4] = { 0x0000, 0x0000, 0x0000, 0x0000 }; /** Current values in electrode register of sensor */ +}; + + +/** + * The function Mpr121Init() soft-resets, detects and configures up to 4x MPR121 sensors. + * + * @param struct *pS Struct with MPR121 status and data. + * @return void + * @pre None. + * @post None. + * + */ +void Mpr121Init(struct mpr121 *pS) +{ + + // Loop through I2C addresses + for (uint8_t i = 0; i < sizeof(pS->i2c_addr[i]); i++) { + + // Soft reset sensor and check if connected at I2C address + pS->connected[i] = (I2cWrite8(pS->i2c_addr[i], MPR121_SRST_REG, MPR121_SRST_VAL) + && (0x24 == I2cRead8(pS->i2c_addr[i], 0x5D))); + if (pS->connected[i]) { + + // Log sensor found + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121(%c) " D_FOUND_AT " 0x%X"), pS->id[i], pS->i2c_addr[i]); + AddLog(LOG_LEVEL_INFO); + + // Set thresholds for registers 0x41 - 0x5A (ExTTH and ExRTH) + for (uint8_t j = 0; j < 13; j++) { + + // Touch + I2cWrite8(pS->i2c_addr[i], MPR121_E0TTH_REG + 2 * j, MPR121_E0TTH_VAL); + + // Release + I2cWrite8(pS->i2c_addr[i], MPR121_E0RTH_REG + 2 * j, MPR121_E0RTH_VAL); + } + + // ELEC0-11 Maximum Half Delta Rising + I2cWrite8(pS->i2c_addr[i], MPR121_MHDR_REG, MPR121_MHDR_VAL); + + // ELEC0-11 Noise Half Delta Rising + I2cWrite8(pS->i2c_addr[i], MPR121_NHDR_REG, MPR121_NHDR_VAL); + + // ELEC0-11 Noise Count Limit Rising + I2cWrite8(pS->i2c_addr[i], MPR121_NCLR_REG, MPR121_NCLR_VAL); + + // ELEC0-11 Maximum Half Delta Falling + I2cWrite8(pS->i2c_addr[i], MPR121_MHDF_REG, MPR121_MHDF_VAL); + + // ELEC0-11 Noise Half Delta Falling + I2cWrite8(pS->i2c_addr[i], MPR121_NHDF_REG, MPR121_NHDF_VAL); + + // ELEC0-11 Noise Count Limit Falling + I2cWrite8(pS->i2c_addr[i], MPR121_NCLF_REG, MPR121_NCLF_VAL); + + // Proximity Maximum Half Delta Rising + I2cWrite8(pS->i2c_addr[i], MPR121_MHDPROXR_REG, MPR121_MHDPROXR_VAL); + + // Proximity Noise Half Delta Rising + I2cWrite8(pS->i2c_addr[i], MPR121_NHDPROXR_REG, MPR121_NHDPROXR_VAL); + + // Proximity Noise Count Limit Rising + I2cWrite8(pS->i2c_addr[i], MPR121_NCLPROXR_REG, MPR121_NCLPROXR_VAL); + + // Proximity Filter Delay Count Limit Rising + I2cWrite8(pS->i2c_addr[i], MPR121_FDLPROXR_REG, MPR121_FDLPROXR_VAL); + + // Proximity Maximum Half Delta Falling + I2cWrite8(pS->i2c_addr[i], MPR121_MHDPROXF_REG, MPR121_MHDPROXF_VAL); + + // Proximity Noise Half Delta Falling + I2cWrite8(pS->i2c_addr[i], MPR121_NHDPROXF_REG, MPR121_NHDPROXF_VAL); + + // Proximity Noise Count Limit Falling + I2cWrite8(pS->i2c_addr[i], MPR121_NCLPROXF_REG, MPR121_NCLPROXF_VAL); + + // Proximity Filter Delay Count Limit Falling + I2cWrite8(pS->i2c_addr[i], MPR121_FDLPROXF_REG, MPR121_FDLPROXF_VAL); + + // Global CDC/CDT Configuration + I2cWrite8(pS->i2c_addr[i], MPR121_CDT_REG, MPR121_CDT_VAL); + + // Enable sensor + I2cWrite8(pS->i2c_addr[i], MPR121_ECR_REG, MPR121_ECR_VAL); + + // Check if sensor is running + pS->running[i] = (0x00 != I2cRead8(pS->i2c_addr[i], MPR121_ECR_REG)); + if (pS->running[i]) { + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121%c: Running"), pS->id[i]); + } else { + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121%c: NOT Running"), pS->id[i]); + } + AddLog(LOG_LEVEL_INFO); + } else { + + // Make sure running is false + pS->running[i] = false; + } + } // for-loop + + // Display no sensor found message + if (!(pS->connected[0] || pS->connected[1] || pS->connected[2] + || pS->connected[3])) { + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121: No sensors found")); + AddLog(LOG_LEVEL_DEBUG); + } +} // void Mpr121Init(struct mpr121 *s) + + +/** + * Publishes the sensor information. + * + * The function Mpr121Show() reads sensor data, checks for over-current exceptions and + * creates strings with button states for the web-interface and near real-time/ telemetriy MQTT. + * + * @param struct *pS Struct with MPR121 status and data. + * @param byte function Tasmota function ID. + * @return void + * @pre Call Mpr121Init() once. + * @post None. + * + */ +void Mpr121Show(struct mpr121 *pS, byte function) +{ + + // Loop through sensors + for (uint8_t i = 0; i < sizeof(pS->i2c_addr[i]); i++) { + + // Check if sensor is connected + if (pS->connected[i]) { + + // Read data + if (!I2cValidRead16LE(&pS->current[i], pS->i2c_addr[i], MPR121_ELEX_REG)) { + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121%c: ERROR: Cannot read data!"), pS->id[i]); + AddLog(LOG_LEVEL_ERROR); + Mpr121Init(pS); + return; + } + // Check if OVCF bit is set + if (BITC(i, 15)) { + + // Clear OVCF bit + I2cWrite8(pS->i2c_addr[i], MPR121_ELEX_REG, 0x00); + snprintf_P(log_data, sizeof(log_data), + PSTR(D_LOG_I2C "MPR121%c: ERROR: Excess current detected! Fix circuits if it happens repeatedly! Soft-resetting MPR121 ..."), pS->id[i]); + AddLog(LOG_LEVEL_ERROR); + Mpr121Init(pS); + return; + } + } + // Check if sensor is running + if (pS->running[i]) { + + // Append sensor to JSON message string + if (FUNC_JSON_APPEND == function) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MPR121%c\":{"), mqtt_data, pS->id[i]); + } + // Loop through buttons + for (uint8_t j = 0; j < 13; j++) { + + // Add sensor, button and state to MQTT JSON message string + if ((FUNC_EVERY_50_MSECOND == function) + && (BITC(i, j) != BITP(i, j))) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"MPR121%c\":{\"Button%i\":%i}}"), pS->id[i], j, BITC(i, j)); + MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data); + } + // Add buttons to web string +#ifdef USE_WEBSERVER + if (FUNC_WEB_APPEND == function) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{s}MPR121%c Button%d{m}%d{e}"), mqtt_data, pS->id[i], j, BITC(i, j)); + } +#endif // USE_WEBSERVER + + // Append JSON message string + if (FUNC_JSON_APPEND == function) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"Button%i\":%i,"), mqtt_data, j, BITC(i, j)); + } + } // for-loop j + + // Save sensor data + pS->previous[i] = pS->current[i]; + + // Append JSON message string + if (FUNC_JSON_APPEND == function) { + snprintf_P(mqtt_data, sizeof(mqtt_data), "%s}", mqtt_data); + } + } // if->running + } // for-loop i +} // void Mpr121Show(byte function) + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +/** + * @ingroup group1 + * Assign Tasmota sensor model ID + */ +#define XSNS_30 + +/** + * The function Xsns30() interfaces Tasmota with the driver. + * + * It provides the function IDs + * FUNC_INIT to initialize a driver, + * FUNC_EVERY_50_MSECOND for near real-time operation, + * FUNC_JSON_APPEND for telemetry data and + * FUNC_WEB_APPEND for displaying data in the Tasmota web-interface + * + * @param byte function Tasmota function ID. + * @return boolean ??? + * @pre None. + * @post None. + * + */ +boolean Xsns30(byte function) +{ + // ??? + boolean result = false; + + // Sensor state/data struct + static struct mpr121 mpr121; + + // Check if I2C is enabled + if (i2c_flg) { + switch (function) { + + // Initialize Sensors + case FUNC_INIT: + Mpr121Init(&mpr121); + break; + + // Run ever 50 milliseconds (near real-time functions) + case FUNC_EVERY_50_MSECOND: + Mpr121Show(&mpr121, FUNC_EVERY_50_MSECOND); + break; + + // Generate JSON telemetry string + case FUNC_JSON_APPEND: + Mpr121Show(&mpr121, FUNC_JSON_APPEND); + break; + +#ifdef USE_WEBSERVER + // Show sensor data on main web page + case FUNC_WEB_APPEND: + Mpr121Show(&mpr121, FUNC_WEB_APPEND); + break; +#endif // USE_WEBSERVER + } + } + // Return boolean result + return result; +} + +#endif // USE_MPR121 +#endif // USE_I2C From 401ee8f87db70a38d7df444f401f2977cfb246c8 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Wed, 11 Jul 2018 21:16:37 +0200 Subject: [PATCH 03/46] Updated MCP230xx driver --- sonoff/language/en-GB.h | 1 + sonoff/user_config.h | 1 + sonoff/xdrv_02_webserver.ino | 25 +++ sonoff/xsns_29_mcp230xx.ino | 392 +++++++++++++++++++++++++++++++++++ 4 files changed, 419 insertions(+) create mode 100644 sonoff/xsns_29_mcp230xx.ino 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 f54cf865f..792780545 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -277,6 +277,7 @@ // #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) +// #define USE_MCP230xx // Add I2C code for MCP23008/MCP23017 for GP INPUT ONLY #endif // USE_I2C // -- SPI sensors --------------------------------- diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index 12ed741ac..a6cd2d4fc 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -202,6 +202,12 @@ const char HTTP_BTN_MENU_MQTT[] PROGMEM = "
" #endif // USE_DOMOTICZ ""; +#ifdef USE_I2C +#ifdef USE_MCP230xx + const char HTTP_BTN_MCP230XX[] PROGMEM = + "
"; +#endif // USE_MCP230xx +#endif // USE_I2C const char HTTP_BTN_MENU4[] PROGMEM = #ifdef USE_KNX "
" @@ -376,6 +382,11 @@ 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 + WebServer->on("/mcp230xx", handleMCP230xx); +#endif // USE_MCP230xx +#endif // USE_I2C #ifndef BE_MINIMAL WebServer->on("/cn", HandleConfiguration); WebServer->on("/md", HandleModuleConfiguration); @@ -695,6 +706,13 @@ 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 + if (MCP230xx_Type()) { // Configuration button will only show if MCP23008/MCP23017 was detected on I2C + page += FPSTR(HTTP_BTN_MCP230XX); + } +#endif // USE_MCP230xx +#endif // USE_I2C page += FPSTR(HTTP_BTN_MENU4); page += FPSTR(HTTP_BTN_MAIN); ShowPage(page); @@ -1124,6 +1142,13 @@ void HandleSaveSettings() } AddLog(LOG_LEVEL_INFO); break; +#ifdef USE_I2C +#ifdef USE_MCP230xx + case 8: // MCP230xx_SaveSettings + MCP230xx_SaveSettings(); + break; +#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..872a447c3 --- /dev/null +++ b/sonoff/xsns_29_mcp230xx.ino @@ -0,0 +1,392 @@ +/* + 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 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; + +#ifdef USE_WEBSERVER +const char HTTP_SNS_MCP230xx_GPIO[] PROGMEM = "%s{s}%s MCP230XX D%d{m}%d{e}"; // {s} = , {m} = , {e} = + +const char HTTP_FORM_I2C_MCP230XX_T[] PROGMEM = ""; +const char HTTP_FORM_I2C_MCP230XX_TE[] PROGMEM = "
"; + +const char HTTP_FORM_MCP230XX[] PROGMEM = + "
 MCP230xx settings  
"; + +const char HTTP_FORM_I2C_MCP230XX[] PROGMEM = + "{b0
" + "Enable Pullup" + "" + ""; + +void handleMCP230xx() +{ + if (HttpUser()) { + return; + } + + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_MCP230XX)); + + String page = FPSTR(HTTP_HEAD); + + page.replace(F("{v}"), D_CONFIGURE_MCP230XX); + + page += FPSTR(HTTP_HEAD_STYLE); + page += FPSTR(HTTP_FORM_MCP230XX); + + page += FPSTR(HTTP_FORM_I2C_MCP230XX_T); + + for (uint8_t idx = 0; idx < mcp280xx_pincount; idx++) { + page += FPSTR(HTTP_FORM_I2C_MCP230XX); + page.replace(F("{b0"), "MCP230XX D" + String(idx)); + page.replace(F("{b1"), "D" + String(idx)); + + // determine correct dropdown state + + uint8_t bitsetting = 0; // Default to disabled + if (Settings.mcp230xx_config[idx].enable) { + bitsetting = 1; // Default to normal enable (floating without interrupt) + if (Settings.mcp230xx_config[idx].inten) { // Int choice + bitsetting = 2; // Default to INT on Change (LOW to HIGH, and HIGH to LOW) + if (Settings.mcp230xx_config[idx].intmode) { // On comparison + bitsetting = 3; // On comparison default to LOW + if (Settings.mcp230xx_config[idx].intcomp) { + bitsetting = 4; // On comparison default to HIGH + } + } + } + } + switch (bitsetting) { + case 0 : page.replace(F("{s0"), PSTR(" selected")); break; + case 1 : page.replace(F("{s1"), PSTR(" selected")); break; + case 2 : page.replace(F("{s2"), PSTR(" selected")); break; + case 3 : page.replace(F("{s3"), PSTR(" selected")); break; + case 4 : page.replace(F("{s4"), PSTR(" selected")); break; + } + // replace remaining unselected options - if one was replaced above it will be ignored + page.replace(F("{s0"), PSTR("")); + page.replace(F("{s1"), PSTR("")); + page.replace(F("{s2"), PSTR("")); + page.replace(F("{s3"), PSTR("")); + page.replace(F("{s4"), PSTR("")); + + if (Settings.mcp230xx_config[idx].pullup) { + page.replace(F("{b2"), PSTR(" checked")); + } else { + page.replace(F("{b2"), PSTR("")); + } + } + + page += FPSTR(HTTP_FORM_I2C_MCP230XX_TE); + + page += FPSTR(HTTP_FORM_END); + page += FPSTR(HTTP_BTN_CONF); + ShowPage(page); +} + +void MCP230xx_SaveSettings() +{ + char stemp[8]; + for (uint8_t idx = 0; idx < mcp280xx_pincount; idx++) { + snprintf_P(stemp, sizeof(stemp), PSTR("D%d"), idx); + uint8_t _pinvalue = (!strlen(WebServer->arg(stemp).c_str() )) ? 0 : atoi(WebServer->arg(stemp).c_str() ); + if (_pinvalue) { + Settings.mcp230xx_config[idx].enable = 1; + if (_pinvalue >= 2) { + Settings.mcp230xx_config[idx].inten = 1; + if (_pinvalue >= 3) { + Settings.mcp230xx_config[idx].intmode = 1; + if (_pinvalue >= 4) { + Settings.mcp230xx_config[idx].intcomp = 1; + } else { + Settings.mcp230xx_config[idx].intcomp = 0; + } + } else { + Settings.mcp230xx_config[idx].intmode = 0; + Settings.mcp230xx_config[idx].intcomp = 0; + } + } else { + Settings.mcp230xx_config[idx].inten = 0; + Settings.mcp230xx_config[idx].intmode = 0; + Settings.mcp230xx_config[idx].intcomp = 0; + } + } else { + Settings.mcp230xx_config[idx].enable = 0; + Settings.mcp230xx_config[idx].inten = 0; + Settings.mcp230xx_config[idx].intmode = 0; + Settings.mcp230xx_config[idx].intcomp = 0; + } + Settings.mcp230xx_config[idx].b5 = 0; + Settings.mcp230xx_config[idx].b6 = 0; + Settings.mcp230xx_config[idx].b7 = 0; + if (Settings.mcp230xx_config[idx].enable) { + snprintf_P(stemp, sizeof(stemp), PSTR("epuD%d"), idx); + Settings.mcp230xx_config[idx].pullup = (!strlen(WebServer->arg(stemp).c_str() )) ? 0 : atoi(WebServer->arg(stemp).c_str() ); + } else { + Settings.mcp230xx_config[idx].pullup = 0; + } + } + MCP230xx_ApplySettings(); +} + +#endif // USE_WEBSERVER + +uint8_t MCP230xx_Type(void) { + return mcp230xx_type; +} + +uint8_t MCP230xx_readGPIO(uint8_t port) { + return I2cRead8(mcp230xx_address, MCP230xx_GPIO + port); +} + +void MCP230xx_ApplySettings(void) { + uint8_t reg_gppu = 0; + uint8_t reg_gpinten = 0; + for (uint8_t idx = 0; idx < 8; idx++) { + if (Settings.mcp230xx_config[idx].enable) { + if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another + reg_gpinten |= (1 << idx); + } + if (Settings.mcp230xx_config[idx].pullup) { + reg_gppu |= (1 << idx); + } + } + } + I2cWrite8(mcp230xx_address, MCP230xx_GPPU, reg_gppu); + I2cWrite8(mcp230xx_address, MCP230xx_GPINTEN, reg_gpinten); + if (mcp230xx_type == 2) { // We have a MCP23017 + reg_gppu = 0; + reg_gpinten = 0; + for (uint8_t idx = 8; idx < 16; idx++) { + if (Settings.mcp230xx_config[idx].enable) { + if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another + reg_gpinten |= (1 << idx - 8); + } + if (Settings.mcp230xx_config[idx].pullup) { + reg_gppu |= (1 << idx - 8); + } + } + } + I2cWrite8(mcp230xx_address, MCP230xx_GPPU + 1, reg_gppu); + I2cWrite8(mcp230xx_address, MCP230xx_GPINTEN + 1, reg_gpinten); + } +} + +void MCP230xx_Detect() +{ + uint8_t buffer; + + if (mcp230xx_type) { + return; + } + + for (byte i = 0; i < sizeof(mcp230xx_addresses); i++) { + mcp230xx_address = mcp230xx_addresses[i]; + I2cWrite8(mcp230xx_address, MCP230xx_IOCON, 0x80); // attempt to set bank mode - this will only work on MCP23017, so its the best way to detect the different chips 23008 vs 23017 + if (I2cValidRead8(&buffer, mcp230xx_address, MCP230xx_IOCON)) { + if (buffer == 0x00) { + mcp230xx_type = 1; // We have a MCP23008 + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23008", mcp230xx_address); + AddLog(LOG_LEVEL_DEBUG); + mcp280xx_pincount = 8; + MCP230xx_ApplySettings(); + } else { + if (buffer == 0x80) { + mcp230xx_type = 2; // We have a MCP23017 + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23017", mcp230xx_address); + AddLog(LOG_LEVEL_DEBUG); + mcp280xx_pincount = 16; + // Reset bank mode to 0 + I2cWrite8(mcp230xx_address, MCP230xx_IOCON, 0x00); + // Update register locations for MCP23017 + MCP230xx_GPINTEN = 0x04; + MCP230xx_GPPU = 0x0C; + MCP230xx_INTF = 0x0E; + MCP230xx_INTCAP = 0x10; + MCP230xx_GPIO = 0x12; + MCP230xx_ApplySettings(); + } + } + break; + } + } +} + +bool MCP230xx_CheckForInterrupt(void) { + uint8_t intf; + uint8_t mcp230xx_intcap = 0; + uint8_t report_int; + + if (I2cValidRead8(&intf, mcp230xx_address, MCP230xx_INTF)) { + if (intf > 0) { + if (I2cValidRead8(&mcp230xx_intcap, mcp230xx_address, MCP230xx_INTCAP)) { + for (uint8_t intp = 0; intp < 8; intp++) { + if ((intf >> intp) & 0x01) { // we know which pin caused interrupt + report_int = 0; + if (Settings.mcp230xx_config[intp].intmode) { // change on INT + if (((mcp230xx_intcap >> intp) & 0x01) == Settings.mcp230xx_config[intp].intcomp) report_int = 1; + } else { + report_int = 1; + } + if (report_int) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP230XX_INT\":{\"Pin\":\"D%i\", \"State\":%i}"), mqtt_data, intp, ((mcp230xx_intcap >> intp) & 0x01)); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data); + } + } + } + } + } + } + if (mcp230xx_type == 2) { // We have a MCP23017 so we need to check the other 8 bits also + if (I2cValidRead8(&intf, mcp230xx_address, MCP230xx_INTF+1)) { + if (intf > 0) { + if (I2cValidRead8(&mcp230xx_intcap, mcp230xx_address, MCP230xx_INTCAP+1)) { + for (uint8_t intp = 0; intp < 8; intp++) { + if ((intf >> intp) & 0x01) { // we know which pin caused interrupt + report_int = 0; + if (Settings.mcp230xx_config[intp+8].intmode) { // change on INT + if (((mcp230xx_intcap >> intp) & 0x01) == Settings.mcp230xx_config[intp+8].intcomp) report_int = 1; + } else { + report_int = 1; + } + if (report_int) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP230XX_INT\":{\"Pin\":\"D%i\", \"State\":%i}"), mqtt_data, intp+8, ((mcp230xx_intcap >> intp) & 0x01)); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data); + } + } + } + } + } + } + } +} + +void MCP230xx_Show(boolean json) +{ + if (mcp230xx_type) { + if (json) { + if (mcp230xx_type == 1) { + uint8_t gpio = MCP230xx_readGPIO(0); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP23008\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i}"), + mqtt_data,(gpio>>0)&1,(gpio>>1)&1,(gpio>>2)&1,(gpio>>3)&1,(gpio>>4)&1,(gpio>>5)&1,(gpio>>6)&1,(gpio>>7)&1); + } + if (mcp230xx_type == 2) { + uint8_t gpio1 = MCP230xx_readGPIO(0); + uint8_t gpio2 = MCP230xx_readGPIO(1); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP23017\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i,\"D8\":%i,\"D9\":%i,\"D10\":%i,\"D11\":%i,\"D12\":%i,\"D13\":%i,\"D14\":%i,\"D15\":%i}"), + mqtt_data, (gpio1>>0)&1,(gpio1>>1)&1,(gpio1>>2)&1,(gpio1>>3)&1,(gpio1>>4)&1,(gpio1>>5)&1,(gpio1>>6)&1,(gpio1>>7)&1,(gpio2>>0)&1,(gpio2>>1)&1,(gpio2>>2)&1,(gpio2>>3)&1,(gpio2>>4)&1,(gpio2>>5)&1,(gpio2>>6)&1,(gpio2>>7)&1); + } + +#ifdef USE_WEBSERVER + } else { + uint8_t gpio1 = MCP230xx_readGPIO(0); + uint8_t gpio2 = 0; + if (mcp230xx_type == 2) { + gpio2=MCP230xx_readGPIO(1); + } + uint16_t gpio = (gpio2 << 8) + gpio1; + + for (uint8_t pin = 0; pin < mcp280xx_pincount; pin++) { + if (Settings.mcp230xx_config[pin].enable) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_MCP230xx_GPIO, mqtt_data, "", pin, (gpio>>pin)&1); + } + } +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + Interface + \*********************************************************************************************/ + +#define XSNS_29 + +boolean Xsns29(byte function) +{ + boolean result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_PREP_BEFORE_TELEPERIOD: + MCP230xx_Detect(); + break; + case FUNC_EVERY_50_MSECOND: + MCP230xx_CheckForInterrupt(); + break; + case FUNC_JSON_APPEND: + MCP230xx_Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_APPEND: + MCP230xx_Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_MCP230xx +#endif // USE_I2C From aafeca8afcacbf9ef1ea274c53300ab6d40c3b7d Mon Sep 17 00:00:00 2001 From: andrethomas Date: Thu, 12 Jul 2018 23:12:01 +0200 Subject: [PATCH 04/46] Update MCP230xx to make web config optional and added sensor29 command parameters --- sonoff/user_config.h | 7 +++- sonoff/xdrv_02_webserver.ino | 8 ++++ sonoff/xsns_29_mcp230xx.ino | 75 ++++++++++++++++++++++++++++++++++-- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 792780545..269e21a24 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -277,7 +277,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) -// #define USE_MCP230xx // Add I2C code for MCP23008/MCP23017 for GP INPUT ONLY + + // 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 a6cd2d4fc..ec6423e6b 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -204,8 +204,10 @@ const char HTTP_BTN_MENU_MQTT[] PROGMEM = ""; #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 = @@ -384,7 +386,9 @@ void StartWebserver(int type, IPAddress ipweb) 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 @@ -708,9 +712,11 @@ void HandleConfiguration() 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); @@ -1144,9 +1150,11 @@ void HandleSaveSettings() 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: diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 872a447c3..1fdb8a863 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -29,6 +29,8 @@ I2C Address: 0x20 - 0x27 \*********************************************************************************************/ +#define XSNS_29 29 + #define MCP230xx_ADDRESS1 0x20 #define MCP230xx_ADDRESS2 0x21 #define MCP230xx_ADDRESS3 0x22 @@ -56,8 +58,10 @@ uint8_t mcp230xx_addresses[] = { MCP230xx_ADDRESS1, MCP230xx_ADDRESS2, MCP230xx_ uint8_t mcp280xx_pincount = 0; #ifdef USE_WEBSERVER +#ifdef USE_MCP230xx_displaymain const char HTTP_SNS_MCP230xx_GPIO[] PROGMEM = "%s{s}%s MCP230XX D%d{m}%d{e}"; // {s} = , {m} = , {e} = - +#endif // USE_MCP230xx_displaymain +#ifdef USE_MCP230xx_webconfig const char HTTP_FORM_I2C_MCP230XX_T[] PROGMEM = ""; const char HTTP_FORM_I2C_MCP230XX_TE[] PROGMEM = "
"; @@ -186,6 +190,8 @@ void MCP230xx_SaveSettings() MCP230xx_ApplySettings(); } +#endif // USE_MCP230xx_webconfig + #endif // USE_WEBSERVER uint8_t MCP230xx_Type(void) { @@ -339,6 +345,7 @@ void MCP230xx_Show(boolean json) } #ifdef USE_WEBSERVER +#ifdef USE_MCP230xx_displaymain } else { uint8_t gpio1 = MCP230xx_readGPIO(0); uint8_t gpio2 = 0; @@ -352,17 +359,74 @@ void MCP230xx_Show(boolean json) snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_MCP230xx_GPIO, mqtt_data, "", pin, (gpio>>pin)&1); } } +#endif // USE_MCP230xx_displaymain #endif // USE_WEBSERVER } } } +bool MCP230xx_Command(void) { + boolean serviced = true; + uint8_t _a, _b = 0; + uint8_t pin, pinmode, pullup = 0; + String data = XdrvMailbox.data; + _a = data.indexOf(","); + _b = data.indexOf(",", _a + 1); + if (_a < XdrvMailbox.data_len) { + if (_b < XdrvMailbox.data_len) { + pin = data.substring(0, _a).toInt(); + pinmode = data.substring(_a+1, _b).toInt(); + pullup = data.substring(_b+1, XdrvMailbox.data_len).toInt(); + data = "MCP D" + String(pin) + " mode=" + String(pinmode) + " pullup=" + String(pullup); + if (pinmode) { + Settings.mcp230xx_config[pin].enable = 1; + if (pinmode >= 2) { + Settings.mcp230xx_config[pin].inten = 1; + if (pinmode >= 3) { + Settings.mcp230xx_config[pin].intmode = 1; + if (pinmode >= 4) { + Settings.mcp230xx_config[pin].intcomp = 1; + } else { + Settings.mcp230xx_config[pin].intcomp = 0; + } + } else { + Settings.mcp230xx_config[pin].intmode = 0; + Settings.mcp230xx_config[pin].intcomp = 0; + } + } else { + Settings.mcp230xx_config[pin].inten = 0; + Settings.mcp230xx_config[pin].intmode = 0; + Settings.mcp230xx_config[pin].intcomp = 0; + } + } else { + Settings.mcp230xx_config[pin].enable = 0; + Settings.mcp230xx_config[pin].inten = 0; + Settings.mcp230xx_config[pin].intmode = 0; + Settings.mcp230xx_config[pin].intcomp = 0; + } + Settings.mcp230xx_config[pin].b5 = 0; + Settings.mcp230xx_config[pin].b6 = 0; + Settings.mcp230xx_config[pin].b7 = 0; + if (Settings.mcp230xx_config[pin].enable) { + Settings.mcp230xx_config[pin].pullup = pullup; + } else { + Settings.mcp230xx_config[pin].pullup = 0; + } + MCP230xx_ApplySettings(); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_29, data.c_str()); + } else { + serviced = false; + } + } else { + serviced = false; + } + return serviced; +} + /*********************************************************************************************\ Interface \*********************************************************************************************/ -#define XSNS_29 - boolean Xsns29(byte function) { boolean result = false; @@ -378,10 +442,15 @@ boolean Xsns29(byte function) case FUNC_JSON_APPEND: MCP230xx_Show(1); break; + case FUNC_COMMAND: + result = MCP230xx_Command(); + break; #ifdef USE_WEBSERVER +#ifdef USE_MCP230xx_displaymain case FUNC_WEB_APPEND: MCP230xx_Show(0); break; +#endif // USE_MCP230xx_displaymain #endif // USE_WEBSERVER } } From 79fb392e45030de964e4af47d63ab922ef6a55e6 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Fri, 13 Jul 2018 08:27:33 +0200 Subject: [PATCH 05/46] Added XdrvMailbox.index validation for FUNC_COMMAND --- sonoff/xsns_29_mcp230xx.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 1fdb8a863..faf193d42 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -443,7 +443,9 @@ boolean Xsns29(byte function) MCP230xx_Show(1); break; case FUNC_COMMAND: - result = MCP230xx_Command(); + if (XSNS_29 == XdrvMailbox.index) { + result = MCP230xx_Command(); + } break; #ifdef USE_WEBSERVER #ifdef USE_MCP230xx_displaymain From a48c251be0c84225fa15270b019a8749d3ad813b Mon Sep 17 00:00:00 2001 From: andrethomas Date: Fri, 13 Jul 2018 10:04:08 +0200 Subject: [PATCH 06/46] Fixed sensor23 JSON output and moved it to progmem --- sonoff/xsns_29_mcp230xx.ino | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index faf193d42..0995d1b04 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -57,9 +57,11 @@ 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}%s MCP230XX D%d{m}%d{e}"; // {s} = , {m} = , {e} = +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 HTTP_FORM_I2C_MCP230XX_T[] PROGMEM = ""; @@ -249,14 +251,14 @@ void MCP230xx_Detect() if (I2cValidRead8(&buffer, mcp230xx_address, MCP230xx_IOCON)) { if (buffer == 0x00) { mcp230xx_type = 1; // We have a MCP23008 - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23008", mcp230xx_address); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, PSTR("MCP23008"), mcp230xx_address); AddLog(LOG_LEVEL_DEBUG); mcp280xx_pincount = 8; MCP230xx_ApplySettings(); } else { if (buffer == 0x80) { mcp230xx_type = 2; // We have a MCP23017 - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23017", mcp230xx_address); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, PSTR("MCP23017"), mcp230xx_address); AddLog(LOG_LEVEL_DEBUG); mcp280xx_pincount = 16; // Reset bank mode to 0 @@ -356,7 +358,7 @@ void MCP230xx_Show(boolean json) for (uint8_t pin = 0; pin < mcp280xx_pincount; pin++) { if (Settings.mcp230xx_config[pin].enable) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_MCP230xx_GPIO, mqtt_data, "", pin, (gpio>>pin)&1); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_MCP230xx_GPIO, mqtt_data, pin, (gpio>>pin)&1); } } #endif // USE_MCP230xx_displaymain @@ -377,7 +379,6 @@ bool MCP230xx_Command(void) { pin = data.substring(0, _a).toInt(); pinmode = data.substring(_a+1, _b).toInt(); pullup = data.substring(_b+1, XdrvMailbox.data_len).toInt(); - data = "MCP D" + String(pin) + " mode=" + String(pinmode) + " pullup=" + String(pullup); if (pinmode) { Settings.mcp230xx_config[pin].enable = 1; if (pinmode >= 2) { @@ -413,7 +414,7 @@ bool MCP230xx_Command(void) { Settings.mcp230xx_config[pin].pullup = 0; } MCP230xx_ApplySettings(); - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_29, data.c_str()); + snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_SENSOR_RESPONSE,pin,pinmode,pullup); } else { serviced = false; } From 8089c8630c8fedbca1a51afb606c45d4dc6576da Mon Sep 17 00:00:00 2001 From: andrethomas Date: Fri, 13 Jul 2018 10:28:55 +0200 Subject: [PATCH 07/46] Fixed some progmem attempts --- sonoff/xsns_29_mcp230xx.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 0995d1b04..8b2554a97 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -251,14 +251,14 @@ void MCP230xx_Detect() if (I2cValidRead8(&buffer, mcp230xx_address, MCP230xx_IOCON)) { if (buffer == 0x00) { mcp230xx_type = 1; // We have a MCP23008 - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, PSTR("MCP23008"), mcp230xx_address); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23008", mcp230xx_address); AddLog(LOG_LEVEL_DEBUG); mcp280xx_pincount = 8; MCP230xx_ApplySettings(); } else { if (buffer == 0x80) { mcp230xx_type = 2; // We have a MCP23017 - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, PSTR("MCP23017"), mcp230xx_address); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23017", mcp230xx_address); AddLog(LOG_LEVEL_DEBUG); mcp280xx_pincount = 16; // Reset bank mode to 0 From 616c6669a93e23aac2d7609e48e14a02b7396170 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 14 Jul 2018 00:33:42 +0200 Subject: [PATCH 08/46] Remove unwanted %s Remove unwanted %s from const char HTTP_SNS_MCP230xx_GPIO[] --- sonoff/xsns_29_mcp230xx.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 8b2554a97..77c3d1a62 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -61,7 +61,7 @@ const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29\":{\"D\":%i,\"MODE\ #ifdef USE_WEBSERVER #ifdef USE_MCP230xx_displaymain -const char HTTP_SNS_MCP230xx_GPIO[] PROGMEM = "%s{s}MCP230XX D%d{m}%d{e}"; // {s} = +const char HTTP_SNS_MCP230xx_GPIO[] PROGMEM = "{s}MCP230XX D%d{m}%d{e}"; // {s} = #endif // USE_MCP230xx_displaymain #ifdef USE_MCP230xx_webconfig const char HTTP_FORM_I2C_MCP230XX_T[] PROGMEM = "
, {m} = , {e} =
, {m} = , {e} =
"; From 1c1436d7ed9286caf1f093aef863272426054d54 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 14 Jul 2018 01:04:46 +0200 Subject: [PATCH 09/46] Put back the %s --- sonoff/xsns_29_mcp230xx.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 77c3d1a62..8b2554a97 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -61,7 +61,7 @@ const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29\":{\"D\":%i,\"MODE\ #ifdef USE_WEBSERVER #ifdef USE_MCP230xx_displaymain -const char HTTP_SNS_MCP230xx_GPIO[] PROGMEM = "{s}MCP230XX D%d{m}%d{e}"; // {s} = +const char HTTP_SNS_MCP230xx_GPIO[] PROGMEM = "%s{s}MCP230XX D%d{m}%d{e}"; // {s} = #endif // USE_MCP230xx_displaymain #ifdef USE_MCP230xx_webconfig const char HTTP_FORM_I2C_MCP230XX_T[] PROGMEM = "
, {m} = , {e} =
, {m} = , {e} =
"; From d8c4f8bb7e53fdc5f92c6573f268cb6ba25607d2 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 14 Jul 2018 14:46:09 +0200 Subject: [PATCH 10/46] Remove F() from page.replace() and reference PROGMEM const's for replacement content --- sonoff/xsns_29_mcp230xx.ino | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 8b2554a97..47e7c2008 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -64,6 +64,9 @@ const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29\":{\"D\":%i,\"MODE\ const char HTTP_SNS_MCP230xx_GPIO[] PROGMEM = "%s{s}MCP230XX D%d{m}%d{e}"; // {s} = #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 = "
, {m} = , {e} =
"; const char HTTP_FORM_I2C_MCP230XX_TE[] PROGMEM = "
"; @@ -92,7 +95,7 @@ void handleMCP230xx() String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), D_CONFIGURE_MCP230XX); + page.replace("{v}", D_CONFIGURE_MCP230XX); page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_FORM_MCP230XX); @@ -101,8 +104,8 @@ void handleMCP230xx() for (uint8_t idx = 0; idx < mcp280xx_pincount; idx++) { page += FPSTR(HTTP_FORM_I2C_MCP230XX); - page.replace(F("{b0"), "MCP230XX D" + String(idx)); - page.replace(F("{b1"), "D" + String(idx)); + page.replace("{b0", "MCP230XX D" + String(idx)); + page.replace("{b1", "D" + String(idx)); // determine correct dropdown state @@ -120,23 +123,23 @@ void handleMCP230xx() } } switch (bitsetting) { - case 0 : page.replace(F("{s0"), PSTR(" selected")); break; - case 1 : page.replace(F("{s1"), PSTR(" selected")); break; - case 2 : page.replace(F("{s2"), PSTR(" selected")); break; - case 3 : page.replace(F("{s3"), PSTR(" selected")); break; - case 4 : page.replace(F("{s4"), PSTR(" selected")); break; + case 0 : page.replace("{s0",MCP230XX_OPTION_SELECTED); break; + case 1 : page.replace("{s1",MCP230XX_OPTION_SELECTED); break; + case 2 : page.replace("{s2",MCP230XX_OPTION_SELECTED); break; + case 3 : page.replace("{s3",MCP230XX_OPTION_SELECTED); break; + case 4 : page.replace("{s4",MCP230XX_OPTION_SELECTED); break; } // replace remaining unselected options - if one was replaced above it will be ignored - page.replace(F("{s0"), PSTR("")); - page.replace(F("{s1"), PSTR("")); - page.replace(F("{s2"), PSTR("")); - page.replace(F("{s3"), PSTR("")); - page.replace(F("{s4"), PSTR("")); + page.replace("{s0",MCP230XX_OPTION_BLANK); + page.replace("{s1",MCP230XX_OPTION_BLANK); + page.replace("{s2",MCP230XX_OPTION_BLANK); + page.replace("{s3",MCP230XX_OPTION_BLANK); + page.replace("{s4",MCP230XX_OPTION_BLANK); if (Settings.mcp230xx_config[idx].pullup) { - page.replace(F("{b2"), PSTR(" checked")); + page.replace("{b2",MCP230XX_OPTION_CHECKED); } else { - page.replace(F("{b2"), PSTR("")); + page.replace("{b2",MCP230XX_OPTION_BLANK); } } From 9be31ab6054a3030e4dc44e56a4eada6cfb4c2a9 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 14 Jul 2018 15:07:01 +0200 Subject: [PATCH 11/46] Added FPSTR to constants --- sonoff/xsns_29_mcp230xx.ino | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 47e7c2008..9aa0bc260 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -95,7 +95,7 @@ void handleMCP230xx() String page = FPSTR(HTTP_HEAD); - page.replace("{v}", D_CONFIGURE_MCP230XX); + page.replace("{v}", FPSTR(D_CONFIGURE_MCP230XX)); page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_FORM_MCP230XX); @@ -123,23 +123,23 @@ void handleMCP230xx() } } switch (bitsetting) { - case 0 : page.replace("{s0",MCP230XX_OPTION_SELECTED); break; - case 1 : page.replace("{s1",MCP230XX_OPTION_SELECTED); break; - case 2 : page.replace("{s2",MCP230XX_OPTION_SELECTED); break; - case 3 : page.replace("{s3",MCP230XX_OPTION_SELECTED); break; - case 4 : page.replace("{s4",MCP230XX_OPTION_SELECTED); break; + case 0 : page.replace("{s0", FPSTR(MCP230XX_OPTION_SELECTED)); break; + case 1 : page.replace("{s1", FPSTR(MCP230XX_OPTION_SELECTED)); break; + case 2 : page.replace("{s2", FPSTR(MCP230XX_OPTION_SELECTED)); break; + case 3 : page.replace("{s3", FPSTR(MCP230XX_OPTION_SELECTED)); break; + case 4 : page.replace("{s4", FPSTR(MCP230XX_OPTION_SELECTED)); break; } // replace remaining unselected options - if one was replaced above it will be ignored - page.replace("{s0",MCP230XX_OPTION_BLANK); - page.replace("{s1",MCP230XX_OPTION_BLANK); - page.replace("{s2",MCP230XX_OPTION_BLANK); - page.replace("{s3",MCP230XX_OPTION_BLANK); - page.replace("{s4",MCP230XX_OPTION_BLANK); + page.replace("{s0", FPSTR(MCP230XX_OPTION_BLANK)); + page.replace("{s1", FPSTR(MCP230XX_OPTION_BLANK)); + page.replace("{s2", FPSTR(MCP230XX_OPTION_BLANK)); + page.replace("{s3", FPSTR(MCP230XX_OPTION_BLANK)); + page.replace("{s4", FPSTR(MCP230XX_OPTION_BLANK)); if (Settings.mcp230xx_config[idx].pullup) { - page.replace("{b2",MCP230XX_OPTION_CHECKED); + page.replace("{b2", FPSTR(MCP230XX_OPTION_CHECKED)); } else { - page.replace("{b2",MCP230XX_OPTION_BLANK); + page.replace("{b2", FPSTR(MCP230XX_OPTION_BLANK)); } } From b56961c528b47dbe41950ea080f86a98885c7ef4 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Mon, 16 Jul 2018 11:34:44 +0200 Subject: [PATCH 12/46] Fix rules once regression Fix rules once regression from v6.1.0 (#3198, #3226) --- sonoff/_changelog.ino | 1 + sonoff/xdrv_10_rules.ino | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index bd6c1dd18..2983ee9de 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,5 @@ /* 6.1.1b + * Fix rules once regression from v6.1.0 (#3198, #3226) * Add default Wifi Configuration tool as define WIFI_CONFIG_NO_SSID in user_config.h if no SSID is configured (#3224) * Add user selection of Wifi Smartconfig as define USE_SMARTCONFIG in user_config.h * Add user selection of WPS as define USE_WPS in user_config.h in preparation for core v2.4.2 (#3221) diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 1218b9854..54a04fbc6 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -253,7 +253,7 @@ bool RulesRuleMatch(byte rule_set, String &event, String &rule) } } else match = true; - if (Settings.flag.rules_once) { + if (bitRead(Settings.rule_once, rule_set)) { if (match) { // Only allow match state changes if (!bitRead(rules_triggers[rule_set], rules_trigger_count[rule_set])) { bitSet(rules_triggers[rule_set], rules_trigger_count[rule_set]); @@ -610,20 +610,21 @@ double map_double(double x, double in_min, double in_max, double out_min, double } // Function to return a substring defined by a delimiter at an index -char* subStr (char* str, const char *delim, int index) { - char *act, *sub, *ptr; +char* subStr (char* str, const char *delim, int index) +{ + char *act; + char *sub; + char *ptr; static char copy[10]; int i; // Since strtok consumes the first arg, make a copy strcpy(copy, str); - for (i = 1, act = copy; i <= index; i++, act = NULL) { - sub = strtok_r(act, delim, &ptr); - if (sub == NULL) break; + sub = strtok_r(act, delim, &ptr); + if (sub == NULL) break; } - sub = LTrim(sub); - sub = RTrim(sub); + sub = Trim(sub); return sub; } From 9ef10f24d2194af5a88f43ed4b798a8d5d47823d Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Mon, 16 Jul 2018 12:37:49 +0200 Subject: [PATCH 13/46] Fix command Scale buffer overflow Fix command Scale buffer overflow (#3236) --- sonoff/_changelog.ino | 1 + sonoff/xdrv_10_rules.ino | 44 ++++++++++++++++------------------------ 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 2983ee9de..2f2a7b1c2 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,5 @@ /* 6.1.1b + * Fix command Scale buffer overflow (#3236) * Fix rules once regression from v6.1.0 (#3198, #3226) * Add default Wifi Configuration tool as define WIFI_CONFIG_NO_SSID in user_config.h if no SSID is configured (#3224) * Add user selection of Wifi Smartconfig as define USE_SMARTCONFIG in user_config.h diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 54a04fbc6..2129fdbbe 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -557,44 +557,38 @@ boolean RulesCommand() snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]); } else if ((CMND_ADD == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) { - if ( XdrvMailbox.data_len > 0 ) { + if (XdrvMailbox.data_len > 0) { double tempvar = CharToDouble(vars[index -1]) + CharToDouble(XdrvMailbox.data); - dtostrfd(tempvar,2,vars[index -1]); + dtostrfd(tempvar, 2, vars[index -1]); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]); } else if ((CMND_SUB == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) { - if ( XdrvMailbox.data_len > 0 ){ + if (XdrvMailbox.data_len > 0) { double tempvar = CharToDouble(vars[index -1]) - CharToDouble(XdrvMailbox.data); - dtostrfd(tempvar,2,vars[index -1]); + dtostrfd(tempvar, 2, vars[index -1]); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]); } else if ((CMND_MULT == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) { - if ( XdrvMailbox.data_len > 0 ){ + if (XdrvMailbox.data_len > 0) { double tempvar = CharToDouble(vars[index -1]) * CharToDouble(XdrvMailbox.data); - dtostrfd(tempvar,2,vars[index -1]); + dtostrfd(tempvar, 2, vars[index -1]); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]); } else if ((CMND_SCALE == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) { - if ( XdrvMailbox.data_len > 0 ) { + if (XdrvMailbox.data_len > 0) { if (strstr(XdrvMailbox.data, ",")) { // Process parameter entry - double value = 0; - double valueIN = 0; - double fromLow = 0; - double fromHigh = 0; - double toLow = 0; - double toHigh = 0; + char sub_string[XdrvMailbox.data_len +1]; - valueIN = CharToDouble(subStr(XdrvMailbox.data, ",", 1)); - fromLow = CharToDouble(subStr(XdrvMailbox.data, ",", 2)); - fromHigh = CharToDouble(subStr(XdrvMailbox.data, ",", 3)); - toLow = CharToDouble(subStr(XdrvMailbox.data, ",", 4)); - toHigh = CharToDouble(subStr(XdrvMailbox.data, ",", 5)); - - value = map_double(valueIN, fromLow, fromHigh, toLow, toHigh); - dtostrfd(value,2,vars[index -1]); + double valueIN = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 1)); + double fromLow = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 2)); + double fromHigh = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 3)); + double toLow = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 4)); + double toHigh = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 5)); + double value = map_double(valueIN, fromLow, fromHigh, toLow, toHigh); + dtostrfd(value, 2, vars[index -1]); } } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]); @@ -610,17 +604,16 @@ double map_double(double x, double in_min, double in_max, double out_min, double } // Function to return a substring defined by a delimiter at an index -char* subStr (char* str, const char *delim, int index) +char* subStr(char* dest, char* str, const char *delim, int index) { char *act; char *sub; char *ptr; - static char copy[10]; int i; // Since strtok consumes the first arg, make a copy - strcpy(copy, str); - for (i = 1, act = copy; i <= index; i++, act = NULL) { + strncpy(dest, str, strlen(str)); + for (i = 1, act = dest; i <= index; i++, act = NULL) { sub = strtok_r(act, delim, &ptr); if (sub == NULL) break; } @@ -628,7 +621,6 @@ char* subStr (char* str, const char *delim, int index) return sub; } - /*********************************************************************************************\ * Interface \*********************************************************************************************/ From f10b92a99591f1759c72bf37c467bf3b95ec5bf9 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Tue, 17 Jul 2018 11:05:31 +0200 Subject: [PATCH 14/46] Add support for MCP230xx Add support for MCP230xx for general purpose input expansion and command Sensor29 (#3188) --- sonoff/_changelog.ino | 1 + sonoff/language/bg-BG.h | 1 + sonoff/language/cs-CZ.h | 1 + sonoff/language/de-DE.h | 1 + sonoff/language/el-GR.h | 1 + sonoff/language/en-GB.h | 2 +- sonoff/language/es-AR.h | 1 + sonoff/language/fr-FR.h | 1 + sonoff/language/hu-HU.h | 1 + sonoff/language/it-IT.h | 1 + sonoff/language/nl-NL.h | 1 + sonoff/language/pl-PL.h | 1 + sonoff/language/pt-BR.h | 1 + sonoff/language/pt-PT.h | 1 + sonoff/language/ru-RU.h | 1 + sonoff/language/uk-UK.h | 1 + sonoff/language/zh-CN.h | 1 + sonoff/language/zh-TW.h | 1 + sonoff/user_config.h | 9 +++---- sonoff/xdrv_02_webserver.ino | 46 ++++++++++++------------------------ sonoff/xsns_29_mcp230xx.ino | 12 +++++----- 21 files changed, 42 insertions(+), 44 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 2f2a7b1c2..c603f826f 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,5 @@ /* 6.1.1b + * Add support for MCP230xx for general purpose input expansion and command Sensor29 (#3188) * Fix command Scale buffer overflow (#3236) * Fix rules once regression from v6.1.0 (#3198, #3226) * Add default Wifi Configuration tool as define WIFI_CONFIG_NO_SSID in user_config.h if no SSID is configured (#3224) diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index 6d82a843c..6f03fcf55 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Подтвърдете рестартирането" #define D_CONFIGURE_MODULE "Конфигурация на модула" +#define D_CONFIGURE_MCP230XX "Конфигурация на MCP230xx" #define D_CONFIGURE_WIFI "Конфигурация на WiFi" #define D_CONFIGURE_MQTT "Конфигурация на MQTT" #define D_CONFIGURE_DOMOTICZ "Конфигурация на Domoticz" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index cb93ad553..03bc4b8cd 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Potvrzení restartu" #define D_CONFIGURE_MODULE "Nastavení modulu" +#define D_CONFIGURE_MCP230XX "Nastavení MCP230xx" #define D_CONFIGURE_WIFI "Nastavení WiFi" #define D_CONFIGURE_MQTT "Nastavení MQTT" #define D_CONFIGURE_DOMOTICZ "Nastavení Domoticz" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 4c0fde470..71d9ae65e 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Wirklich neustarten?" #define D_CONFIGURE_MODULE "Gerät konfigurieren" +#define D_CONFIGURE_MCP230XX "MCP230xx konfigurieren" #define D_CONFIGURE_WIFI "WLAN konfigurieren" #define D_CONFIGURE_MQTT "MQTT konfigurieren" #define D_CONFIGURE_DOMOTICZ "Domoticz konfigurieren" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index 702381ab1..e45efd5ba 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Επιβεβαίωση Επανεκκίνησης" #define D_CONFIGURE_MODULE "Ρύθμιση Module" +#define D_CONFIGURE_MCP230XX "Ρύθμιση MCP230xx" #define D_CONFIGURE_WIFI "Ρύθμιση WiFi" #define D_CONFIGURE_MQTT "Ρύθμιση MQTT" #define D_CONFIGURE_DOMOTICZ "Ρύθμιση Domoticz" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 016e62e41..5a85abba3 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -166,7 +166,6 @@ #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" @@ -228,6 +227,7 @@ #define D_CONFIRM_RESTART "Confirm Restart" #define D_CONFIGURE_MODULE "Configure Module" +#define D_CONFIGURE_MCP230XX "Configure MCP230xx" #define D_CONFIGURE_WIFI "Configure WiFi" #define D_CONFIGURE_MQTT "Configure MQTT" #define D_CONFIGURE_DOMOTICZ "Configure Domoticz" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 1c4b4924a..82451d205 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Confirmar Reinicio" #define D_CONFIGURE_MODULE "Configuración del Módulo" +#define D_CONFIGURE_MCP230XX "Configuración MCP230xx" #define D_CONFIGURE_WIFI "Configuración WiFi" #define D_CONFIGURE_MQTT "Configuración MQTT" #define D_CONFIGURE_DOMOTICZ "Configuración Domoticz" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index ce1485513..a5aed67c1 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Confirmer redémarrage" #define D_CONFIGURE_MODULE "Configuration du Module" +#define D_CONFIGURE_MCP230XX "Configuration MCP230xx" #define D_CONFIGURE_WIFI "Configuration WiFi" #define D_CONFIGURE_MQTT "Configuration MQTT" #define D_CONFIGURE_DOMOTICZ "Configuration Domoticz" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 14fb2a08b..a4ac7cea2 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Újraindítás megerősítése" #define D_CONFIGURE_MODULE "Eszköz konfiguráció" +#define D_CONFIGURE_MCP230XX "MCP230xx konfiguráció" #define D_CONFIGURE_WIFI "WiFi konfiguráció" #define D_CONFIGURE_MQTT "MQTT konfiguráció" #define D_CONFIGURE_DOMOTICZ "Domoticz konfiguráció" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 6f1c4db0f..2a60abaf0 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Conferma Riavvio" #define D_CONFIGURE_MODULE "Configurazione Modulo" +#define D_CONFIGURE_MCP230XX "Configurazione MCP230xx" #define D_CONFIGURE_WIFI "Configurazione WiFi" #define D_CONFIGURE_MQTT "Configurazione MQTT" #define D_CONFIGURE_DOMOTICZ "Configurazione Domoticz" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index cf1c2b3b0..936d14861 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Bevestig herstart" #define D_CONFIGURE_MODULE "Configureer Module" +#define D_CONFIGURE_MCP230XX "Configureer MCP230xx" #define D_CONFIGURE_WIFI "Configureer WiFi" #define D_CONFIGURE_MQTT "Configureer MQTT" #define D_CONFIGURE_DOMOTICZ "Configureer Domoticz" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index e250e4c4d..ce29dde07 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Potwierdź restart" #define D_CONFIGURE_MODULE "Konfiguruj moduł" +#define D_CONFIGURE_MCP230XX "Konfiguruj MCP230xx" #define D_CONFIGURE_WIFI "Konfiguruj WiFi" #define D_CONFIGURE_MQTT "Konfiguruj MQTT" #define D_CONFIGURE_DOMOTICZ "Konfiguruj Domoticz" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index a32a7b5c3..0e6f82342 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Confirmar o reinicio" #define D_CONFIGURE_MODULE "Configurar Módulo" +#define D_CONFIGURE_MCP230XX "Configurar MCP230xx" #define D_CONFIGURE_WIFI "Configurar WiFi" #define D_CONFIGURE_MQTT "Configurar MQTT" #define D_CONFIGURE_DOMOTICZ "Configurar Domoticz" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index 393a74a87..e6d56ba1d 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Confirmar o reinicio" #define D_CONFIGURE_MODULE "Configurar Módulo" +#define D_CONFIGURE_MCP230XX "Configurar MCP230xx" #define D_CONFIGURE_WIFI "Configurar WiFi" #define D_CONFIGURE_MQTT "Configurar MQTT" #define D_CONFIGURE_DOMOTICZ "Configurar Domoticz" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index 79df5b2d4..e4bc30ea2 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Подтвердить перезагрузку" #define D_CONFIGURE_MODULE "Конфигурация Модуля" +#define D_CONFIGURE_MCP230XX "Конфигурация MCP230xx" #define D_CONFIGURE_WIFI "Конфигурация WiFi" #define D_CONFIGURE_MQTT "Конфигурация MQTT" #define D_CONFIGURE_DOMOTICZ "Конфигурация Domoticz" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index d925d13fb..fda5d2e46 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "Підтвердити перезавантаження" #define D_CONFIGURE_MODULE "Конфігурація модуля" +#define D_CONFIGURE_MCP230XX "Конфігурація MCP230xx" #define D_CONFIGURE_WIFI "Конфігурація WiFi" #define D_CONFIGURE_MQTT "Конфігурація MQTT" #define D_CONFIGURE_DOMOTICZ "Конфігурація Domoticz" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 9e5149125..203e5ac08 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "确认重启" #define D_CONFIGURE_MODULE "模块设置" +#define D_CONFIGURE_MCP230XX "MCP230xx设置" #define D_CONFIGURE_WIFI "WiFi设置" #define D_CONFIGURE_MQTT "MQTT设置" #define D_CONFIGURE_DOMOTICZ "Domoticz设置" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 6d4154cdf..22f35f924 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -227,6 +227,7 @@ #define D_CONFIRM_RESTART "確認重啟" #define D_CONFIGURE_MODULE "模塊設置" +#define D_CONFIGURE_MCP230XX "MCP230xx設置" #define D_CONFIGURE_WIFI "WiFi設置" #define D_CONFIGURE_MQTT "MQTT設置" #define D_CONFIGURE_DOMOTICZ "Domoticz設置" diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 12a4924b1..1550383fb 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -287,12 +287,9 @@ // #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) - +// #define USE_MCP230xx // Add I2C code for MCP23008/MCP23017 for GP INPUT ONLY providing command Sensor29 for configuration (+2k2 code) +// #define USE_MCP230xx_displaymain // Display pin status on Tasmota main page (+0k2 code) +// #define USE_MCP230xx_webconfig // Enable web config button and form to Tasmota web interface (+2k1 code) #endif // USE_I2C // -- SPI sensors --------------------------------- diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index ec6423e6b..3f6a7b628 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -190,6 +190,10 @@ const char HTTP_BTN_RSTRT[] PROGMEM = "
"; const char HTTP_BTN_MENU_MODULE[] PROGMEM = "
"; +#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig) +const char HTTP_BTN_MCP230XX[] PROGMEM = + "
"; +#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig #if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) const char HTTP_BTN_MENU_TIMER[] PROGMEM = "
"; @@ -202,14 +206,6 @@ 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 "
" @@ -384,16 +380,12 @@ 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); +#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig) + WebServer->on("/mc", HandleMCP230xxConfiguration); +#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig #if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) WebServer->on("/tm", HandleTimerConfiguration); #endif // USE_TIMERS and USE_TIMERS_WEB @@ -701,6 +693,11 @@ void HandleConfiguration() page.replace(F("{v}"), FPSTR(S_CONFIGURATION)); page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_BTN_MENU_MODULE); +#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(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_I2C and USE_MCP230xx and USE_MCP230xx_webconfig #if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) #ifdef USE_RULES page += FPSTR(HTTP_BTN_MENU_TIMER); @@ -710,15 +707,6 @@ 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); @@ -1148,15 +1136,11 @@ void HandleSaveSettings() } AddLog(LOG_LEVEL_INFO); break; -#ifdef USE_I2C -#ifdef USE_MCP230xx -#ifdef USE_MCP230xx_webconfig - case 8: // MCP230xx_SaveSettings +#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig) + case 8: MCP230xx_SaveSettings(); break; -#endif // USE_MCP230xx_webconfig -#endif // USE_MCP230xx -#endif // USE_I2C +#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig 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 index 9aa0bc260..aa1a44fad 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -85,7 +85,7 @@ const char HTTP_FORM_I2C_MCP230XX[] PROGMEM = "" ""; -void handleMCP230xx() +void HandleMCP230xxConfiguration() { if (HttpUser()) { return; @@ -348,7 +348,7 @@ void MCP230xx_Show(boolean json) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP23017\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i,\"D8\":%i,\"D9\":%i,\"D10\":%i,\"D11\":%i,\"D12\":%i,\"D13\":%i,\"D14\":%i,\"D15\":%i}"), mqtt_data, (gpio1>>0)&1,(gpio1>>1)&1,(gpio1>>2)&1,(gpio1>>3)&1,(gpio1>>4)&1,(gpio1>>5)&1,(gpio1>>6)&1,(gpio1>>7)&1,(gpio2>>0)&1,(gpio2>>1)&1,(gpio2>>2)&1,(gpio2>>3)&1,(gpio2>>4)&1,(gpio2>>5)&1,(gpio2>>6)&1,(gpio2>>7)&1); } - + #ifdef USE_WEBSERVER #ifdef USE_MCP230xx_displaymain } else { @@ -358,13 +358,13 @@ void MCP230xx_Show(boolean json) gpio2=MCP230xx_readGPIO(1); } uint16_t gpio = (gpio2 << 8) + gpio1; - + for (uint8_t pin = 0; pin < mcp280xx_pincount; pin++) { if (Settings.mcp230xx_config[pin].enable) { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_MCP230xx_GPIO, mqtt_data, pin, (gpio>>pin)&1); } } -#endif // USE_MCP230xx_displaymain +#endif // USE_MCP230xx_displaymain #endif // USE_WEBSERVER } } @@ -450,13 +450,13 @@ boolean Xsns29(byte function) if (XSNS_29 == XdrvMailbox.index) { result = MCP230xx_Command(); } - break; + break; #ifdef USE_WEBSERVER #ifdef USE_MCP230xx_displaymain case FUNC_WEB_APPEND: MCP230xx_Show(0); break; -#endif // USE_MCP230xx_displaymain +#endif // USE_MCP230xx_displaymain #endif // USE_WEBSERVER } } From 3b46ba2ace6c0be6f41479d9959806391a8b4acd Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Tue, 17 Jul 2018 12:51:55 +0200 Subject: [PATCH 15/46] Add support for MPR121 Add support for MPR121 controller in input mode for touch buttons (#3142) --- sonoff/_changelog.ino | 1 + sonoff/user_config.h | 39 ++++++++++++++++++--------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index c603f826f..2f8e54b41 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,5 @@ /* 6.1.1b + * Add support for MPR121 controller in input mode for touch buttons (#3142) * Add support for MCP230xx for general purpose input expansion and command Sensor29 (#3188) * Fix command Scale buffer overflow (#3236) * Fix rules once regression from v6.1.0 (#3198, #3226) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 7414fed78..63aa88e6f 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -270,30 +270,27 @@ // -- I2C sensors --------------------------------- #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) #ifdef USE_I2C - #define USE_SHT // Add I2C emulating code for SHT1X sensor (+1k4 code) - #define USE_SHT3X // Add I2C code for SHT3x or SHTC3 sensor (+0k7 code) - #define USE_HTU // Add I2C code for HTU21/SI7013/SI7020/SI7021 sensor (+1k5 code) - #define USE_LM75AD // Add I2C code for LM75AD sensor (+0k5 code) - #define USE_BMP // Add I2C code for BMP085/BMP180/BMP280/BME280 sensor (+4k code) -// #define USE_BME680 // Add additional support for BME680 sensor using Bosch BME680 library (+4k code) - #define USE_SGP30 // Add I2C code for SGP30 sensor (+1k1 code) - #define USE_BH1750 // Add I2C code for BH1750 sensor (+0k5 code) -// #define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0k5 code) -// #define USE_TSL2561 // Add I2C code for TSL2561 sensor using library Joba_Tsl2561 (+2k3 code) -// #define USE_SI1145 // Add I2C code for SI1145/46/47 sensor (+1k code) -// #define USE_ADS1115 // Add I2C code for ADS1115 16 bit A/D converter based on Adafruit ADS1x15 library (no library needed) (+0k7 code) -// #define USE_ADS1115_I2CDEV // Add I2C code for ADS1115 16 bit A/D converter using library i2cdevlib-Core and i2cdevlib-ADS1115 (+2k code) -// #define USE_INA219 // Add I2C code for INA219 Low voltage and current sensor (+1k code) -// #define USE_MGS // Add I2C code for Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code) + #define USE_SHT // Enable SHT1X sensor (+1k4 code) + #define USE_HTU // Enable HTU21/SI7013/SI7020/SI7021 sensor (I2C address 0x40) (+1k5 code) + #define USE_BMP // Enable BMP085/BMP180/BMP280/BME280 sensor (I2C address 0x76 or 0x77) (+4k code) + #define USE_BME680 // Enable support for BME680 sensor using Bosch BME680 library (+4k code) + #define USE_BH1750 // Enable BH1750 sensor (I2C address 0x23 or 0x5C) (+0k5 code) +// #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+0k5 code) +// #define USE_ADS1115 // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) based on Adafruit ADS1x15 library (no library needed) (+0k7 code) +// #define USE_ADS1115_I2CDEV // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) using library i2cdevlib-Core and i2cdevlib-ADS1115 (+2k code) +// #define USE_INA219 // Enable INA219 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+1k code) + #define USE_SHT3X // Enable SHT3x (I2C address 0x44 or 0x45) or SHTC3 (I2C address 0x70) sensor (+0k7 code) +// #define USE_TSL2561 // Enable TSL2561 sensor (I2C address 0x29, 0x39 or 0x49) using library Joba_Tsl2561 (+2k3 code) +// #define USE_MGS // Enable 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) - -// #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons - -// #define USE_MCP230xx // Add I2C code for MCP23008/MCP23017 for GP INPUT ONLY providing command Sensor29 for configuration (+2k2 code) + #define USE_SGP30 // Enable SGP30 sensor (I2C address 0x58) (+1k1 code) +// #define USE_SI1145 // Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) + #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_displaymain // Display pin status on Tasmota main page (+0k2 code) // #define USE_MCP230xx_webconfig // Enable web config button and form to Tasmota web interface (+2k1 code) - +// #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) #endif // USE_I2C // -- SPI sensors --------------------------------- From 9a3a834d1b9ceb9c768b5f57abcb07f4240cd70d Mon Sep 17 00:00:00 2001 From: Xavier MULLER <33861984+localhost61@users.noreply.github.com> Date: Tue, 17 Jul 2018 15:14:25 +0200 Subject: [PATCH 16/46] Update fr-FR.h --- sonoff/language/fr-FR.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index a5aed67c1..0e1b2ba81 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v5.14.0a + * Updated until v6.01.1b \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -242,8 +242,8 @@ #define D_MODULE_PARAMETERS "Paramètres module" #define D_MODULE_TYPE "Type de module" #define D_GPIO "GPIO" -#define D_SERIAL_IN "Serial In" -#define D_SERIAL_OUT "Serial Out" +#define D_SERIAL_IN "Entrée série" +#define D_SERIAL_OUT "Sortie série" #define D_WIFI_PARAMETERS "Paramètres Wifi" #define D_SCAN_FOR_WIFI_NETWORKS "Scan des réseaux wifi" @@ -322,10 +322,10 @@ #define D_UPLOAD_ERR_7 "Téléchargement annulé" #define D_UPLOAD_ERR_8 "Fichier invalide" #define D_UPLOAD_ERR_9 "Fichier trop grand" -#define D_UPLOAD_ERR_10 "Failed to init RF chip" -#define D_UPLOAD_ERR_11 "Failed to erase RF chip" -#define D_UPLOAD_ERR_12 "Failed to write to RF chip" -#define D_UPLOAD_ERR_13 "Failed to decode RF firmware" +#define D_UPLOAD_ERR_10 "Erreur d'initialisation du chip RF" +#define D_UPLOAD_ERR_11 "Erreur d'effacement du chip RF" +#define D_UPLOAD_ERR_12 "Erreur d'accès en écriture au chip RF" +#define D_UPLOAD_ERR_13 "Erreur de décodage du firmware RF" #define D_UPLOAD_ERROR_CODE "Code d'erreur téléchargement" #define D_ENTER_COMMAND "Saisir une commande" @@ -406,7 +406,7 @@ #define D_KNX_COMMAND_OTHER "Autre" #define D_SENT_TO "envoyé à" #define D_KNX_WARNING "L'Adresse de Groupe ( 0 / 0 / 0 ) est réservée et ne peut être utilisée." -#define D_KNX_ENHANCEMENT "Communication Enhancement" +#define D_KNX_ENHANCEMENT "Amélioration de la communication" #define D_KNX_TX_SLOT "KNX TX" #define D_KNX_RX_SLOT "KNX RX" From cdb4a0612bd6ffe303a72fd67ea93c108765b687 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Tue, 17 Jul 2018 15:27:19 +0200 Subject: [PATCH 17/46] Update fr-FR.h --- sonoff/language/fr-FR.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 0e1b2ba81..f36f4ce92 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v6.01.1b + * Updated until v6.1.1b \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) From dbf84d78130d5c30b26ebdfc8b47b3eeb84b275b Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Tue, 17 Jul 2018 16:07:03 +0200 Subject: [PATCH 18/46] Add checks Add checks --- tools/decode-status.py | 64 ++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/tools/decode-status.py b/tools/decode-status.py index 60f69853d..3adc8e707 100644 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -146,41 +146,45 @@ else: def StartDecode(): # print("Decoding\n{}".format(obj)) - if ("Time" in obj["StatusSNS"]): - time = str(" from status report taken at {}".format(obj["StatusSNS"]["Time"])) - if ("FriendlyName" in obj["Status"]): - print("\nDecoding information for device {}{}".format(obj["Status"]["FriendlyName"][0], time)) + if ("StatusSNS" in obj): + if ("Time" in obj["StatusSNS"]): + time = str(" from status report taken at {}".format(obj["StatusSNS"]["Time"])) - if ("SetOption" in obj["StatusLOG"]): - options = [] - option = obj["StatusLOG"]["SetOption"][0] - i_option = int(option,16) - for i in range(len(a_setoption)): - if (a_setoption[i]): - state = (i_option >> i) & 1 - options.append(str("{0:2d} ({1}) {2}".format(i, a_on_off[state], a_setoption[i]))) + if ("Status" in obj): + if ("FriendlyName" in obj["Status"]): + print("\nDecoding information for device {}{}".format(obj["Status"]["FriendlyName"][0], time)) - print("\nOptions") - for i in range(len(options)): - print(" {}".format(options[i])) + if ("StatusLOG" in obj): + if ("SetOption" in obj["StatusLOG"]): + options = [] + option = obj["StatusLOG"]["SetOption"][0] + i_option = int(option,16) + for i in range(len(a_setoption)): + if (a_setoption[i]): + state = (i_option >> i) & 1 + options.append(str("{0:2d} ({1}) {2}".format(i, a_on_off[state], a_setoption[i]))) + print("\nOptions") + for i in range(len(options)): + print(" {}".format(options[i])) - if ("Features" in obj["StatusMEM"]): - features = [] - for f in range(5): - feature = obj["StatusMEM"]["Features"][f] - i_feature = int(feature,16) - if (f == 0): - features.append(str("Language LCID = {}".format(i_feature & 0xFFFF))) - else: - for i in range(len(a_features[f -1])): - if ((i_feature >> i) & 1): - features.append(a_features[f -1][i]) + if ("StatusMEM" in obj): + if ("Features" in obj["StatusMEM"]): + features = [] + for f in range(5): + feature = obj["StatusMEM"]["Features"][f] + i_feature = int(feature,16) + if (f == 0): + features.append(str("Language LCID = {}".format(i_feature & 0xFFFF))) + else: + for i in range(len(a_features[f -1])): + if ((i_feature >> i) & 1): + features.append(a_features[f -1][i]) - features.sort() - print("\nFeatures") - for i in range(len(features)): - print(" {}".format(features[i])) + features.sort() + print("\nFeatures") + for i in range(len(features)): + print(" {}".format(features[i])) if __name__ == "__main__": try: From e6c55530595d995d2ee9d0a44a3e2638d5fbef5c Mon Sep 17 00:00:00 2001 From: andrethomas Date: Tue, 17 Jul 2018 21:18:26 +0200 Subject: [PATCH 19/46] Move MCP230xx_Detect() from FUNC_PREP_BEFORE_TELEPERIOD to FUNC_EVERY_SECOND --- sonoff/xsns_29_mcp230xx.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index aa1a44fad..01895be16 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -437,7 +437,7 @@ boolean Xsns29(byte function) if (i2c_flg) { switch (function) { - case FUNC_PREP_BEFORE_TELEPERIOD: + case FUNC_EVERY_SECOND: MCP230xx_Detect(); break; case FUNC_EVERY_50_MSECOND: From 370cbf064c4beb6e84a29700567c05244f6db8d4 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Wed, 18 Jul 2018 09:43:49 +0200 Subject: [PATCH 20/46] Move LM75ADDetect() to FUNC_EVERY_SECOND Move LM75ADDetect() from FUNC_PREP_BEFORE_TELEPERIOD to FUNC_EVERY_SECOND to comply with FUNC_PREP_BEFORE_TELEPERIOD marked as deprecated. --- sonoff/xsns_26_lm75ad.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_26_lm75ad.ino b/sonoff/xsns_26_lm75ad.ino index df1c8c578..c1bb8b2b3 100644 --- a/sonoff/xsns_26_lm75ad.ino +++ b/sonoff/xsns_26_lm75ad.ino @@ -108,7 +108,7 @@ boolean Xsns26(byte function) if (i2c_flg) { switch (function) { - case FUNC_PREP_BEFORE_TELEPERIOD: + case FUNC_EVERY_SECOND: LM75ADDetect(); break; case FUNC_JSON_APPEND: From c3c4f89efdd7be765c36877a9989fd32b88ea533 Mon Sep 17 00:00:00 2001 From: Rene 'Renne' Bartsch Date: Thu, 19 Jul 2018 21:18:20 +0200 Subject: [PATCH 21/46] Visual Studio specific compiler warning fixed. This commit fixes the Visual Studio compiler warning ``` D:/Sonoff-Tasmota-development.6.1.1b/sonoff/xsns_30_mpr121.ino:192:2: warning: 'typedef' was ignored in this declaration [enabled by default] }; ^ ``` --- sonoff/xsns_30_mpr121.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sonoff/xsns_30_mpr121.ino b/sonoff/xsns_30_mpr121.ino index 0f27ccc59..cc4fba3ab 100644 --- a/sonoff/xsns_30_mpr121.ino +++ b/sonoff/xsns_30_mpr121.ino @@ -182,7 +182,8 @@ * and the indices of the arrays connected, running, current and previous to store sensor status and data of a specific sensor. * */ -typedef struct mpr121 { +typedef struct mpr121 mpr121; +struct mpr121 { const uint8_t i2c_addr[4] = { 0x5A, 0x5B, 0x5C, 0x5D }; /** I2C addresses of MPR121 controller */ const char id[4] = { 'A', 'B', 'C', 'D' }; /** Human-readable sensor IDs*/ bool connected[4] = { false, false, false, false }; /** Status if sensor is connected at I2C address */ From 612374cfbf36bfd68f8960f6e2a73e433d6c1616 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Fri, 20 Jul 2018 16:12:37 +0200 Subject: [PATCH 22/46] Revisit Timers off/on 6.1.1c * Add command Timers 0/1 to globally disable or enable armed timers (#3270) --- README.md | 2 +- sonoff/_changelog.ino | 5 ++++- sonoff/settings.h | 2 +- sonoff/settings.ino | 3 +++ sonoff/sonoff.ino | 2 +- sonoff/xdrv_09_timers.ino | 12 ++++++++---- 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b0a864cb5..2496aa320 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ If you like **Sonoff-Tasmota**, give it a star, or fork it and contribute! ### Development [![Build Status](https://img.shields.io/travis/arendst/Sonoff-Tasmota.svg)](https://travis-ci.org/arendst/Sonoff-Tasmota) -Current version is **6.1.1b** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for release information and [sonoff/_changelog.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_changelog.ino) for change information. +Current version is **6.1.1c** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for release information and [sonoff/_changelog.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_changelog.ino) for change information. ### Disclaimer :warning: **DANGER OF ELECTROCUTION** :warning: diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 2f8e54b41..5c5d7ba6a 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,7 @@ -/* 6.1.1b +/* 6.1.1c + * Add command Timers 0/1 to globally disable or enable armed timers (#3270) + * + * 6.1.1b * Add support for MPR121 controller in input mode for touch buttons (#3142) * Add support for MCP230xx for general purpose input expansion and command Sensor29 (#3188) * Fix command Scale buffer overflow (#3236) diff --git a/sonoff/settings.h b/sonoff/settings.h index 4a3dc415c..4d4192e34 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -63,7 +63,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu typedef union { // Restricted by MISRA-C Rule 18.4 but so usefull... uint32_t data; // Allow bit manipulation using SetOption struct { // SetOption50 .. SetOption81 - uint32_t spare00 : 1; + uint32_t timers_enable : 1; // bit 0 (v6.1.1b) uint32_t spare01 : 1; uint32_t spare02 : 1; uint32_t spare03 : 1; diff --git a/sonoff/settings.ino b/sonoff/settings.ino index d39c4e7a3..d5541298d 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -782,6 +782,9 @@ void SettingsDelta() Settings.flag.rules_once = 0; Settings.flag3.data = 0; } + if (Settings.version < 0x06010103) { + Settings.flag3.timers_enable = 1; + } Settings.version = VERSION; SettingsSave(1); diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 3bb37c5e6..7818d8170 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,7 +25,7 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x06010102 // 6.1.1b +#define VERSION 0x06010103 // 6.1.1c // Location specific includes #include // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0) diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index 1631b5d4d..a7fae894a 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -262,7 +262,7 @@ void TimerEverySecond() { if (RtcTime.valid) { if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second) { TimerSetRandomWindows(); } // Midnight - if ((uptime > 60) && (RtcTime.minute != timer_last_minute)) { // Execute from one minute after restart every minute only once + if (Settings.flag3.timers_enable && (uptime > 60) && (RtcTime.minute != timer_last_minute)) { // Execute from one minute after restart every minute only once timer_last_minute = RtcTime.minute; int16_t time = (RtcTime.hour *60) + RtcTime.minute; uint8_t days = 1 << (RtcTime.day_of_week -1); @@ -451,11 +451,15 @@ boolean TimerCommand() } } else if (CMND_TIMERS == command_code) { - if (XdrvMailbox.data_len && (XdrvMailbox.payload == 0)) { - for (byte i = 0; i < MAX_TIMERS; i++) { - Settings.timer[i].arm = 0; // Disable all timers + if (XdrvMailbox.data_len) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings.flag3.timers_enable = XdrvMailbox.payload; } } + + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag3.timers_enable)); + MqttPublishPrefixTopic_P(RESULT_OR_STAT, command); + byte jsflg = 0; byte lines = 1; for (byte i = 0; i < MAX_TIMERS; i++) { From 4f86c5d6f1664549c11943d39be442c379cb2b5e Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 21 Jul 2018 14:17:48 +0200 Subject: [PATCH 23/46] Bugfix on MCP230xx driver --- sonoff/xsns_29_mcp230xx.ino | 54 ++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 01895be16..46846a7a0 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -210,10 +210,12 @@ uint8_t MCP230xx_readGPIO(uint8_t port) { void MCP230xx_ApplySettings(void) { uint8_t reg_gppu = 0; uint8_t reg_gpinten = 0; + uint8_t reg_iodir = 0xFF; for (uint8_t idx = 0; idx < 8; idx++) { if (Settings.mcp230xx_config[idx].enable) { if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another reg_gpinten |= (1 << idx); + reg_iodir |= (1 << idx); // Force pin to input state if enabled } if (Settings.mcp230xx_config[idx].pullup) { reg_gppu |= (1 << idx); @@ -222,13 +224,16 @@ void MCP230xx_ApplySettings(void) { } I2cWrite8(mcp230xx_address, MCP230xx_GPPU, reg_gppu); I2cWrite8(mcp230xx_address, MCP230xx_GPINTEN, reg_gpinten); + I2cWrite8(mcp230xx_address, MCP230xx_IODIR, reg_iodir); if (mcp230xx_type == 2) { // We have a MCP23017 reg_gppu = 0; reg_gpinten = 0; + reg_iodir = 0xFF; for (uint8_t idx = 8; idx < 16; idx++) { if (Settings.mcp230xx_config[idx].enable) { if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another reg_gpinten |= (1 << idx - 8); + reg_iodir |= (1 << idx - 8); // Force pin to input state if enabled } if (Settings.mcp230xx_config[idx].pullup) { reg_gppu |= (1 << idx - 8); @@ -237,6 +242,7 @@ void MCP230xx_ApplySettings(void) { } I2cWrite8(mcp230xx_address, MCP230xx_GPPU + 1, reg_gppu); I2cWrite8(mcp230xx_address, MCP230xx_GPINTEN + 1, reg_gpinten); + I2cWrite8(mcp230xx_address, MCP230xx_IODIR + 1, reg_iodir); } } @@ -382,42 +388,46 @@ bool MCP230xx_Command(void) { pin = data.substring(0, _a).toInt(); pinmode = data.substring(_a+1, _b).toInt(); pullup = data.substring(_b+1, XdrvMailbox.data_len).toInt(); - if (pinmode) { - Settings.mcp230xx_config[pin].enable = 1; - if (pinmode >= 2) { - Settings.mcp230xx_config[pin].inten = 1; - if (pinmode >= 3) { - Settings.mcp230xx_config[pin].intmode = 1; - if (pinmode >= 4) { - Settings.mcp230xx_config[pin].intcomp = 1; + if ((pin >= 0) && (pin < mcp280xx_pincount)) { + if (pinmode) { + Settings.mcp230xx_config[pin].enable = 1; + if (pinmode >= 2) { + Settings.mcp230xx_config[pin].inten = 1; + if (pinmode >= 3) { + Settings.mcp230xx_config[pin].intmode = 1; + if (pinmode >= 4) { + Settings.mcp230xx_config[pin].intcomp = 1; + } else { + Settings.mcp230xx_config[pin].intcomp = 0; + } } else { + Settings.mcp230xx_config[pin].intmode = 0; Settings.mcp230xx_config[pin].intcomp = 0; } } else { + Settings.mcp230xx_config[pin].inten = 0; Settings.mcp230xx_config[pin].intmode = 0; Settings.mcp230xx_config[pin].intcomp = 0; } } else { + Settings.mcp230xx_config[pin].enable = 0; Settings.mcp230xx_config[pin].inten = 0; Settings.mcp230xx_config[pin].intmode = 0; Settings.mcp230xx_config[pin].intcomp = 0; + } + Settings.mcp230xx_config[pin].b5 = 0; + Settings.mcp230xx_config[pin].b6 = 0; + Settings.mcp230xx_config[pin].b7 = 0; + if (Settings.mcp230xx_config[pin].enable) { + Settings.mcp230xx_config[pin].pullup = pullup; + } else { + Settings.mcp230xx_config[pin].pullup = 0; } + MCP230xx_ApplySettings(); + snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_SENSOR_RESPONSE,pin,pinmode,pullup); } else { - Settings.mcp230xx_config[pin].enable = 0; - Settings.mcp230xx_config[pin].inten = 0; - Settings.mcp230xx_config[pin].intmode = 0; - Settings.mcp230xx_config[pin].intcomp = 0; + serviced = false; } - Settings.mcp230xx_config[pin].b5 = 0; - Settings.mcp230xx_config[pin].b6 = 0; - Settings.mcp230xx_config[pin].b7 = 0; - if (Settings.mcp230xx_config[pin].enable) { - Settings.mcp230xx_config[pin].pullup = pullup; - } else { - Settings.mcp230xx_config[pin].pullup = 0; - } - MCP230xx_ApplySettings(); - snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_SENSOR_RESPONSE,pin,pinmode,pullup); } else { serviced = false; } From 55691affaa961acb02df0c26a50ac2cd98b04cba Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 21 Jul 2018 14:24:34 +0200 Subject: [PATCH 24/46] Bugfix on MCP230xx driver --- sonoff/xsns_29_mcp230xx.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 46846a7a0..2df5f80da 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -213,9 +213,9 @@ void MCP230xx_ApplySettings(void) { uint8_t reg_iodir = 0xFF; for (uint8_t idx = 0; idx < 8; idx++) { if (Settings.mcp230xx_config[idx].enable) { + reg_iodir |= (1 << idx); // Force pin to input state if enabled if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another reg_gpinten |= (1 << idx); - reg_iodir |= (1 << idx); // Force pin to input state if enabled } if (Settings.mcp230xx_config[idx].pullup) { reg_gppu |= (1 << idx); @@ -231,9 +231,9 @@ void MCP230xx_ApplySettings(void) { reg_iodir = 0xFF; for (uint8_t idx = 8; idx < 16; idx++) { if (Settings.mcp230xx_config[idx].enable) { + reg_iodir |= (1 << idx - 8); // Force pin to input state if enabled if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another reg_gpinten |= (1 << idx - 8); - reg_iodir |= (1 << idx - 8); // Force pin to input state if enabled } if (Settings.mcp230xx_config[idx].pullup) { reg_gppu |= (1 << idx - 8); From a4eddcb518ebb7358ce9b5fdf79abceeae1d7617 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Sat, 21 Jul 2018 16:47:44 +0200 Subject: [PATCH 25/46] Add global timer cntrl to webpage Add command Timers 0/1 to globally disable or enable armed timers (#3270) --- sonoff/language/bg-BG.h | 1 + sonoff/language/cs-CZ.h | 1 + sonoff/language/de-DE.h | 1 + sonoff/language/el-GR.h | 1 + sonoff/language/en-GB.h | 1 + sonoff/language/es-AR.h | 1 + sonoff/language/fr-FR.h | 1 + sonoff/language/hu-HU.h | 1 + sonoff/language/it-IT.h | 1 + sonoff/language/nl-NL.h | 1 + sonoff/language/pl-PL.h | 1 + sonoff/language/pt-BR.h | 1 + sonoff/language/pt-PT.h | 1 + sonoff/language/ru-RU.h | 1 + sonoff/language/uk-UK.h | 1 + sonoff/language/zh-CN.h | 1 + sonoff/language/zh-TW.h | 1 + sonoff/xdrv_09_timers.ino | 10 +++++++--- 18 files changed, 24 insertions(+), 3 deletions(-) diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index 6f03fcf55..5461883e4 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Конфигуриране на таймер" #define D_TIMER_PARAMETERS "Параметри на таймера" +#define D_TIMER_ENABLE "Активиране на таймера" #define D_TIMER_ARM "Arm" #define D_TIMER_TIME "Време" #define D_TIMER_DAYS "Дни" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 03bc4b8cd..3c89518e9 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Nastavení Časovače" #define D_TIMER_PARAMETERS "Časovač" +#define D_TIMER_ENABLE "Povol Časovače" #define D_TIMER_ARM "Aktivní" #define D_TIMER_TIME "Čas" #define D_TIMER_DAYS "Dny" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 71d9ae65e..42730e9ec 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Zeitplan konfigurieren" #define D_TIMER_PARAMETERS "Zeitplan-Einstellungen" +#define D_TIMER_ENABLE "Zeitpläne aktivieren" #define D_TIMER_ARM "Aktiv" #define D_TIMER_TIME "Uhrzeit" #define D_TIMER_DAYS "Wochentage" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index e45efd5ba..1cc112b03 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Ρυθμίσεις Χρόνου" #define D_TIMER_PARAMETERS "Χρονικοί παράμετροι" +#define D_TIMER_ENABLE "Ενεργοποιημένο Χρονικοί" #define D_TIMER_ARM "Arm" #define D_TIMER_TIME "Ωρα" #define D_TIMER_DAYS "Μέρες" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 5a85abba3..dee89bd39 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configure Timer" #define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ENABLE "Enable Timers" #define D_TIMER_ARM "Arm" #define D_TIMER_TIME "Time" #define D_TIMER_DAYS "Days" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 82451d205..1cae4508a 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configuración Temporizadores" #define D_TIMER_PARAMETERS "Parámetros de Temporizadores" +#define D_TIMER_ENABLE "Habilitar Temporizadores" #define D_TIMER_ARM "Activo" #define D_TIMER_TIME "Hora" #define D_TIMER_DAYS "Días" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index f36f4ce92..c6653bd65 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configuration des Timers" #define D_TIMER_PARAMETERS "Paramètres Timer" +#define D_TIMER_ENABLE "Activer des Timers" #define D_TIMER_ARM "Armer" #define D_TIMER_TIME "Temps" #define D_TIMER_DAYS "Jours" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index a4ac7cea2..abd397abf 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configure Timer" #define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ENABLE "Enable Timers" #define D_TIMER_ARM "Arm" #define D_TIMER_TIME "Time" #define D_TIMER_DAYS "Days" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 2a60abaf0..763f2f912 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configura Timer" #define D_TIMER_PARAMETERS "Parametri Timer" +#define D_TIMER_ENABLE "Abilita Timers" #define D_TIMER_ARM "Attiva" #define D_TIMER_TIME "Ora" #define D_TIMER_DAYS "Giorni" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 936d14861..d7ba586fa 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configureer Tijdschakelaar" #define D_TIMER_PARAMETERS "Tijdschakelaar parameters" +#define D_TIMER_ENABLE "Tijdschakelaars inschakelen" #define D_TIMER_ARM "Actief" #define D_TIMER_TIME "Tijd" #define D_TIMER_DAYS "Dagen" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index ce29dde07..6a1397218 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configure Timer" #define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ENABLE "Enable Timers" #define D_TIMER_ARM "Arm" #define D_TIMER_TIME "Time" #define D_TIMER_DAYS "Days" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index 0e6f82342..2d3f89b1f 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configurar temporizador" #define D_TIMER_PARAMETERS "Parâmetros" +#define D_TIMER_ENABLE "Habilitar temporizadores" #define D_TIMER_ARM "Habilitar" #define D_TIMER_TIME "Horário" #define D_TIMER_DAYS "Dias" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index e6d56ba1d..38ba38911 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configure Timer" #define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ENABLE "Enable Timers" #define D_TIMER_ARM "Arm" #define D_TIMER_TIME "Time" #define D_TIMER_DAYS "Days" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index e4bc30ea2..a0284adcd 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configure Timer" #define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ENABLE "Enable Timers" #define D_TIMER_ARM "Arm" #define D_TIMER_TIME "Time" #define D_TIMER_DAYS "Days" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index fda5d2e46..dd5dffb23 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Конфігурація таймеру" #define D_TIMER_PARAMETERS "Налаштування таймеру" +#define D_TIMER_ENABLE "Увімкнений таймеру" #define D_TIMER_ARM "Увімкнений" #define D_TIMER_TIME "Час" #define D_TIMER_DAYS "Дні" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 203e5ac08..0228e26e5 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "定时器设置" #define D_TIMER_PARAMETERS "定时器参数" +#define D_TIMER_ENABLE "启用定时器" #define D_TIMER_ARM "启用" #define D_TIMER_TIME "时间" #define D_TIMER_DAYS "天" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 22f35f924..18becc2aa 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -380,6 +380,7 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Configure Timer" #define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ENABLE "Enable Timers" #define D_TIMER_ARM "Arm" #define D_TIMER_TIME "Time" #define D_TIMER_DAYS "Days" diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index a7fae894a..f74a8d28e 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -637,7 +637,9 @@ const char HTTP_TIMER_STYLE[] PROGMEM = ""; const char HTTP_FORM_TIMER[] PROGMEM = "
 " D_TIMER_PARAMETERS " 
" - "" + "
" D_TIMER_ENABLE "


" + "



" "

" @@ -683,6 +685,7 @@ void HandleTimerConfiguration() page += FPSTR(HTTP_HEAD_STYLE); page.replace(F(""), FPSTR(HTTP_TIMER_STYLE)); page += FPSTR(HTTP_FORM_TIMER); + page.replace(F("{e0"), (Settings.flag3.timers_enable) ? F(" checked") : F("")); for (byte i = 0; i < MAX_TIMERS; i++) { if (i > 0) { page += F(","); } page += String(Settings.timer[i].data); @@ -706,9 +709,10 @@ void TimerSaveSettings() char tmp[MAX_TIMERS *12]; // Need space for MAX_TIMERS x 10 digit numbers separated by a comma Timer timer; + Settings.flag3.timers_enable = WebServer->hasArg("e0"); WebGetArg("t0", tmp, sizeof(tmp)); char *p = tmp; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_TIMERS " ")); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_TIMERS " %d"), Settings.flag3.timers_enable); for (byte i = 0; i < MAX_TIMERS; i++) { timer.data = strtol(p, &p, 10); p++; // Skip comma @@ -717,7 +721,7 @@ void TimerSaveSettings() Settings.timer[i].data = timer.data; if (flag) TimerSetRandomWindow(i); } - snprintf_P(log_data, sizeof(log_data), PSTR("%s%s0x%08X"), log_data, (i > 0)?",":"", Settings.timer[i].data); + snprintf_P(log_data, sizeof(log_data), PSTR("%s,0x%08X"), log_data, Settings.timer[i].data); } AddLog(LOG_LEVEL_DEBUG); } From 9731b13fd6bfe7a359e5bb3622ea96ab1c6d7c39 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 21 Jul 2018 18:04:36 +0200 Subject: [PATCH 26/46] Removed WEB CONFIG option and extended sensor29 commands --- sonoff/user_config.h | 2 - sonoff/xdrv_02_webserver.ino | 17 -- sonoff/xsns_29_mcp230xx.ino | 292 ++++++++--------------------------- 3 files changed, 67 insertions(+), 244 deletions(-) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 63aa88e6f..6d80fff83 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -288,8 +288,6 @@ #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_displaymain // Display pin status on Tasmota main page (+0k2 code) -// #define USE_MCP230xx_webconfig // Enable web config button and form to Tasmota web interface (+2k1 code) // #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) #endif // USE_I2C diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index 3f6a7b628..12ed741ac 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -190,10 +190,6 @@ const char HTTP_BTN_RSTRT[] PROGMEM = "
"; const char HTTP_BTN_MENU_MODULE[] PROGMEM = "
"; -#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig) -const char HTTP_BTN_MCP230XX[] PROGMEM = - "
"; -#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig #if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) const char HTTP_BTN_MENU_TIMER[] PROGMEM = "
"; @@ -383,9 +379,6 @@ void StartWebserver(int type, IPAddress ipweb) #ifndef BE_MINIMAL WebServer->on("/cn", HandleConfiguration); WebServer->on("/md", HandleModuleConfiguration); -#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig) - WebServer->on("/mc", HandleMCP230xxConfiguration); -#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig #if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) WebServer->on("/tm", HandleTimerConfiguration); #endif // USE_TIMERS and USE_TIMERS_WEB @@ -693,11 +686,6 @@ void HandleConfiguration() page.replace(F("{v}"), FPSTR(S_CONFIGURATION)); page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_BTN_MENU_MODULE); -#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(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_I2C and USE_MCP230xx and USE_MCP230xx_webconfig #if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) #ifdef USE_RULES page += FPSTR(HTTP_BTN_MENU_TIMER); @@ -1136,11 +1124,6 @@ void HandleSaveSettings() } AddLog(LOG_LEVEL_INFO); break; -#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig) - case 8: - MCP230xx_SaveSettings(); - break; -#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig 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 index 2df5f80da..5d1667abe 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -55,154 +55,10 @@ 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; +uint8_t mcp230xx_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 = - "
 MCP230xx settings  
"; - -const char HTTP_FORM_I2C_MCP230XX[] PROGMEM = - "{b0
" - "Enable Pullup" - "" - ""; - -void HandleMCP230xxConfiguration() -{ - if (HttpUser()) { - return; - } - - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_MCP230XX)); - - String page = FPSTR(HTTP_HEAD); - - page.replace("{v}", FPSTR(D_CONFIGURE_MCP230XX)); - - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_MCP230XX); - - page += FPSTR(HTTP_FORM_I2C_MCP230XX_T); - - for (uint8_t idx = 0; idx < mcp280xx_pincount; idx++) { - page += FPSTR(HTTP_FORM_I2C_MCP230XX); - page.replace("{b0", "MCP230XX D" + String(idx)); - page.replace("{b1", "D" + String(idx)); - - // determine correct dropdown state - - uint8_t bitsetting = 0; // Default to disabled - if (Settings.mcp230xx_config[idx].enable) { - bitsetting = 1; // Default to normal enable (floating without interrupt) - if (Settings.mcp230xx_config[idx].inten) { // Int choice - bitsetting = 2; // Default to INT on Change (LOW to HIGH, and HIGH to LOW) - if (Settings.mcp230xx_config[idx].intmode) { // On comparison - bitsetting = 3; // On comparison default to LOW - if (Settings.mcp230xx_config[idx].intcomp) { - bitsetting = 4; // On comparison default to HIGH - } - } - } - } - switch (bitsetting) { - case 0 : page.replace("{s0", FPSTR(MCP230XX_OPTION_SELECTED)); break; - case 1 : page.replace("{s1", FPSTR(MCP230XX_OPTION_SELECTED)); break; - case 2 : page.replace("{s2", FPSTR(MCP230XX_OPTION_SELECTED)); break; - case 3 : page.replace("{s3", FPSTR(MCP230XX_OPTION_SELECTED)); break; - case 4 : page.replace("{s4", FPSTR(MCP230XX_OPTION_SELECTED)); break; - } - // replace remaining unselected options - if one was replaced above it will be ignored - page.replace("{s0", FPSTR(MCP230XX_OPTION_BLANK)); - page.replace("{s1", FPSTR(MCP230XX_OPTION_BLANK)); - page.replace("{s2", FPSTR(MCP230XX_OPTION_BLANK)); - page.replace("{s3", FPSTR(MCP230XX_OPTION_BLANK)); - page.replace("{s4", FPSTR(MCP230XX_OPTION_BLANK)); - - if (Settings.mcp230xx_config[idx].pullup) { - page.replace("{b2", FPSTR(MCP230XX_OPTION_CHECKED)); - } else { - page.replace("{b2", FPSTR(MCP230XX_OPTION_BLANK)); - } - } - - page += FPSTR(HTTP_FORM_I2C_MCP230XX_TE); - - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); -} - -void MCP230xx_SaveSettings() -{ - char stemp[8]; - for (uint8_t idx = 0; idx < mcp280xx_pincount; idx++) { - snprintf_P(stemp, sizeof(stemp), PSTR("D%d"), idx); - uint8_t _pinvalue = (!strlen(WebServer->arg(stemp).c_str() )) ? 0 : atoi(WebServer->arg(stemp).c_str() ); - if (_pinvalue) { - Settings.mcp230xx_config[idx].enable = 1; - if (_pinvalue >= 2) { - Settings.mcp230xx_config[idx].inten = 1; - if (_pinvalue >= 3) { - Settings.mcp230xx_config[idx].intmode = 1; - if (_pinvalue >= 4) { - Settings.mcp230xx_config[idx].intcomp = 1; - } else { - Settings.mcp230xx_config[idx].intcomp = 0; - } - } else { - Settings.mcp230xx_config[idx].intmode = 0; - Settings.mcp230xx_config[idx].intcomp = 0; - } - } else { - Settings.mcp230xx_config[idx].inten = 0; - Settings.mcp230xx_config[idx].intmode = 0; - Settings.mcp230xx_config[idx].intcomp = 0; - } - } else { - Settings.mcp230xx_config[idx].enable = 0; - Settings.mcp230xx_config[idx].inten = 0; - Settings.mcp230xx_config[idx].intmode = 0; - Settings.mcp230xx_config[idx].intcomp = 0; - } - Settings.mcp230xx_config[idx].b5 = 0; - Settings.mcp230xx_config[idx].b6 = 0; - Settings.mcp230xx_config[idx].b7 = 0; - if (Settings.mcp230xx_config[idx].enable) { - snprintf_P(stemp, sizeof(stemp), PSTR("epuD%d"), idx); - Settings.mcp230xx_config[idx].pullup = (!strlen(WebServer->arg(stemp).c_str() )) ? 0 : atoi(WebServer->arg(stemp).c_str() ); - } else { - Settings.mcp230xx_config[idx].pullup = 0; - } - } - MCP230xx_ApplySettings(); -} - -#endif // USE_MCP230xx_webconfig - -#endif // USE_WEBSERVER - -uint8_t MCP230xx_Type(void) { - return mcp230xx_type; -} - uint8_t MCP230xx_readGPIO(uint8_t port) { return I2cRead8(mcp230xx_address, MCP230xx_GPIO + port); } @@ -212,9 +68,9 @@ void MCP230xx_ApplySettings(void) { uint8_t reg_gpinten = 0; uint8_t reg_iodir = 0xFF; for (uint8_t idx = 0; idx < 8; idx++) { - if (Settings.mcp230xx_config[idx].enable) { + if (Settings.mcp230xx_config[idx].pinmode > 0) { reg_iodir |= (1 << idx); // Force pin to input state if enabled - if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another + if (Settings.mcp230xx_config[idx].pinmode > 1) { // Int is enabled in some form or another reg_gpinten |= (1 << idx); } if (Settings.mcp230xx_config[idx].pullup) { @@ -230,9 +86,9 @@ void MCP230xx_ApplySettings(void) { reg_gpinten = 0; reg_iodir = 0xFF; for (uint8_t idx = 8; idx < 16; idx++) { - if (Settings.mcp230xx_config[idx].enable) { + if (Settings.mcp230xx_config[idx].pinmode > 0) { reg_iodir |= (1 << idx - 8); // Force pin to input state if enabled - if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another + if (Settings.mcp230xx_config[idx].pinmode > 1) { // Int is enabled in some form or another reg_gpinten |= (1 << idx - 8); } if (Settings.mcp230xx_config[idx].pullup) { @@ -262,14 +118,14 @@ void MCP230xx_Detect() mcp230xx_type = 1; // We have a MCP23008 snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23008", mcp230xx_address); AddLog(LOG_LEVEL_DEBUG); - mcp280xx_pincount = 8; + mcp230xx_pincount = 8; MCP230xx_ApplySettings(); } else { if (buffer == 0x80) { mcp230xx_type = 2; // We have a MCP23017 snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23017", mcp230xx_address); AddLog(LOG_LEVEL_DEBUG); - mcp280xx_pincount = 16; + mcp230xx_pincount = 16; // Reset bank mode to 0 I2cWrite8(mcp230xx_address, MCP230xx_IOCON, 0x00); // Update register locations for MCP23017 @@ -297,16 +153,26 @@ bool MCP230xx_CheckForInterrupt(void) { for (uint8_t intp = 0; intp < 8; intp++) { if ((intf >> intp) & 0x01) { // we know which pin caused interrupt report_int = 0; - if (Settings.mcp230xx_config[intp].intmode) { // change on INT - if (((mcp230xx_intcap >> intp) & 0x01) == Settings.mcp230xx_config[intp].intcomp) report_int = 1; - } else { - report_int = 1; - } - if (report_int) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP230XX_INT\":{\"Pin\":\"D%i\", \"State\":%i}"), mqtt_data, intp, ((mcp230xx_intcap >> intp) & 0x01)); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data); + if (Settings.mcp230xx_config[intp].pinmode > 1) { + switch (Settings.mcp230xx_config[intp].pinmode) { + case 2: + report_int = 1; + break; + case 3: + if (((mcp230xx_intcap >> intp) & 0x01) == 0) report_int = 1; // Int on LOW + break; + case 4: + if (((mcp230xx_intcap >> intp) & 0x01) == 1) report_int = 1; // Int on HIGH + break; + default: + break; + } + if (report_int) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP230XX_INT\":{\"Pin\":\"D%i\", \"State\":%i}"), mqtt_data, intp, ((mcp230xx_intcap >> intp) & 0x01)); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data); + } } } } @@ -320,10 +186,20 @@ bool MCP230xx_CheckForInterrupt(void) { for (uint8_t intp = 0; intp < 8; intp++) { if ((intf >> intp) & 0x01) { // we know which pin caused interrupt report_int = 0; - if (Settings.mcp230xx_config[intp+8].intmode) { // change on INT - if (((mcp230xx_intcap >> intp) & 0x01) == Settings.mcp230xx_config[intp+8].intcomp) report_int = 1; - } else { - report_int = 1; + if (Settings.mcp230xx_config[intp+8].pinmode > 1) { // change on INT + switch (Settings.mcp230xx_config[intp+8].pinmode) { + case 2: + report_int = 1; + break; + case 3: + if (((mcp230xx_intcap >> intp) & 0x01) == 0) report_int = 1; // Int on LOW + break; + case 4: + if (((mcp230xx_intcap >> intp) & 0x01) == 1) report_int = 1; // Int on HIGH + break; + default: + break; + } } if (report_int) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); @@ -354,24 +230,6 @@ void MCP230xx_Show(boolean json) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP23017\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i,\"D8\":%i,\"D9\":%i,\"D10\":%i,\"D11\":%i,\"D12\":%i,\"D13\":%i,\"D14\":%i,\"D15\":%i}"), mqtt_data, (gpio1>>0)&1,(gpio1>>1)&1,(gpio1>>2)&1,(gpio1>>3)&1,(gpio1>>4)&1,(gpio1>>5)&1,(gpio1>>6)&1,(gpio1>>7)&1,(gpio2>>0)&1,(gpio2>>1)&1,(gpio2>>2)&1,(gpio2>>3)&1,(gpio2>>4)&1,(gpio2>>5)&1,(gpio2>>6)&1,(gpio2>>7)&1); } - -#ifdef USE_WEBSERVER -#ifdef USE_MCP230xx_displaymain - } else { - uint8_t gpio1 = MCP230xx_readGPIO(0); - uint8_t gpio2 = 0; - if (mcp230xx_type == 2) { - gpio2=MCP230xx_readGPIO(1); - } - uint16_t gpio = (gpio2 << 8) + gpio1; - - for (uint8_t pin = 0; pin < mcp280xx_pincount; pin++) { - if (Settings.mcp230xx_config[pin].enable) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_MCP230xx_GPIO, mqtt_data, pin, (gpio>>pin)&1); - } - } -#endif // USE_MCP230xx_displaymain -#endif // USE_WEBSERVER } } } @@ -381,48 +239,37 @@ bool MCP230xx_Command(void) { uint8_t _a, _b = 0; uint8_t pin, pinmode, pullup = 0; String data = XdrvMailbox.data; + data.toUpperCase(); + if (data == "RESET") { // we need to reset all pins to input + for (uint8_t pinx=0;pinx<16;pinx++) { + Settings.mcp230xx_config[pinx].pinmode=1; + Settings.mcp230xx_config[pinx].pullup=0; + Settings.mcp230xx_config[pinx].b4=0; + Settings.mcp230xx_config[pinx].b5=0; + Settings.mcp230xx_config[pinx].b6=0; + Settings.mcp230xx_config[pinx].b7=0; + } + MCP230xx_ApplySettings(); + snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_SENSOR_RESPONSE,99,99,99); + return serviced; + } _a = data.indexOf(","); + pin = data.substring(0, _a).toInt(); + if (pin < mcp230xx_pincount) { + String cmnd = data.substring(_a+1); + if (cmnd == "?") { + snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_SENSOR_RESPONSE,pin,Settings.mcp230xx_config[pin].pinmode,Settings.mcp230xx_config[pin].pullup); + return serviced; + } + } _b = data.indexOf(",", _a + 1); if (_a < XdrvMailbox.data_len) { if (_b < XdrvMailbox.data_len) { - pin = data.substring(0, _a).toInt(); pinmode = data.substring(_a+1, _b).toInt(); pullup = data.substring(_b+1, XdrvMailbox.data_len).toInt(); - if ((pin >= 0) && (pin < mcp280xx_pincount)) { - if (pinmode) { - Settings.mcp230xx_config[pin].enable = 1; - if (pinmode >= 2) { - Settings.mcp230xx_config[pin].inten = 1; - if (pinmode >= 3) { - Settings.mcp230xx_config[pin].intmode = 1; - if (pinmode >= 4) { - Settings.mcp230xx_config[pin].intcomp = 1; - } else { - Settings.mcp230xx_config[pin].intcomp = 0; - } - } else { - Settings.mcp230xx_config[pin].intmode = 0; - Settings.mcp230xx_config[pin].intcomp = 0; - } - } else { - Settings.mcp230xx_config[pin].inten = 0; - Settings.mcp230xx_config[pin].intmode = 0; - Settings.mcp230xx_config[pin].intcomp = 0; - } - } else { - Settings.mcp230xx_config[pin].enable = 0; - Settings.mcp230xx_config[pin].inten = 0; - Settings.mcp230xx_config[pin].intmode = 0; - Settings.mcp230xx_config[pin].intcomp = 0; - } - Settings.mcp230xx_config[pin].b5 = 0; - Settings.mcp230xx_config[pin].b6 = 0; - Settings.mcp230xx_config[pin].b7 = 0; - if (Settings.mcp230xx_config[pin].enable) { - Settings.mcp230xx_config[pin].pullup = pullup; - } else { - Settings.mcp230xx_config[pin].pullup = 0; - } + if ((pin < mcp230xx_pincount) && (pinmode < 5) && (pullup < 2)) { + Settings.mcp230xx_config[pin].pinmode=pinmode; + Settings.mcp230xx_config[pin].pullup=pullup; MCP230xx_ApplySettings(); snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_SENSOR_RESPONSE,pin,pinmode,pullup); } else { @@ -461,13 +308,8 @@ boolean Xsns29(byte function) result = MCP230xx_Command(); } break; -#ifdef USE_WEBSERVER -#ifdef USE_MCP230xx_displaymain - case FUNC_WEB_APPEND: - MCP230xx_Show(0); + default: break; -#endif // USE_MCP230xx_displaymain -#endif // USE_WEBSERVER } } return result; From 6a4d4503f66ffe756d5d8ac2549848fcbf6fc2e7 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 21 Jul 2018 18:06:24 +0200 Subject: [PATCH 27/46] Changed mcp230xx_config structure --- sonoff/settings.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sonoff/settings.h b/sonoff/settings.h index 4d4192e34..e527d74b7 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -155,11 +155,9 @@ typedef union { typedef union { uint8_t data; struct { - uint8_t enable : 1; // Enable INPUT + uint8_t pinmode : 3; // Enable INPUT uint8_t pullup : 1; // Enable internal weak pull-up resistor - uint8_t inten : 1; // Enable Interrupt on PIN - uint8_t intmode : 1; // Change on STATE or match COMPARATOR - uint8_t intcomp : 1; // Interrupt COMPARATOR + uint8_t b4 : 1; uint8_t b5 : 1; uint8_t b6 : 1; uint8_t b7 : 1; @@ -413,4 +411,4 @@ typedef union { ADC_MODE(ADC_VCC); // Set ADC input for Power Supply Voltage usage #endif -#endif // _SETTINGS_H_ \ No newline at end of file +#endif // _SETTINGS_H_ From 4d1981dca3d387ccfee5fef5b8295b1665ee8299 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 21 Jul 2018 22:04:18 +0200 Subject: [PATCH 28/46] Simplify MCP230xx_ApplySettings --- sonoff/xsns_29_mcp230xx.ino | 38 +++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 5d1667abe..83949614e 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -68,14 +68,19 @@ void MCP230xx_ApplySettings(void) { uint8_t reg_gpinten = 0; uint8_t reg_iodir = 0xFF; for (uint8_t idx = 0; idx < 8; idx++) { - if (Settings.mcp230xx_config[idx].pinmode > 0) { - reg_iodir |= (1 << idx); // Force pin to input state if enabled - if (Settings.mcp230xx_config[idx].pinmode > 1) { // Int is enabled in some form or another + switch (Settings.mcp230xx_config[idx].pinmode) { + case 0 ... 1: + reg_iodir |= (1 << idx); + break; + case 2 ... 4: + reg_iodir |= (1 << idx); reg_gpinten |= (1 << idx); - } - if (Settings.mcp230xx_config[idx].pullup) { - reg_gppu |= (1 << idx); - } + break; + default: + break; + } + if (Settings.mcp230xx_config[idx].pullup) { + reg_gppu |= (1 << idx); } } I2cWrite8(mcp230xx_address, MCP230xx_GPPU, reg_gppu); @@ -86,14 +91,19 @@ void MCP230xx_ApplySettings(void) { reg_gpinten = 0; reg_iodir = 0xFF; for (uint8_t idx = 8; idx < 16; idx++) { - if (Settings.mcp230xx_config[idx].pinmode > 0) { - reg_iodir |= (1 << idx - 8); // Force pin to input state if enabled - if (Settings.mcp230xx_config[idx].pinmode > 1) { // Int is enabled in some form or another + switch (Settings.mcp230xx_config[idx].pinmode) { + case 0 ... 1: + reg_iodir |= (1 << idx - 8); + break; + case 2 ... 4: + reg_iodir |= (1 << idx - 8); reg_gpinten |= (1 << idx - 8); - } - if (Settings.mcp230xx_config[idx].pullup) { - reg_gppu |= (1 << idx - 8); - } + break; + default: + break; + } + if (Settings.mcp230xx_config[idx].pullup) { + reg_gppu |= (1 << idx - 8); } } I2cWrite8(mcp230xx_address, MCP230xx_GPPU + 1, reg_gppu); From 7285aa356f8bf4629c3caeec1ee820a617ab4072 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sun, 22 Jul 2018 22:40:26 +0200 Subject: [PATCH 29/46] MCP23008/MCP23017 bugfix - Only check for interrupts if enabled on at least one pin --- sonoff/xsns_29_mcp230xx.ino | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 83949614e..b6900d6ee 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -56,6 +56,7 @@ 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 mcp230xx_pincount = 0; +uint8_t mcp230xx_int_en = 0; const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29\":{\"D\":%i,\"MODE\":%i,\"PULL-UP\":%i}}"; @@ -67,6 +68,7 @@ void MCP230xx_ApplySettings(void) { uint8_t reg_gppu = 0; uint8_t reg_gpinten = 0; uint8_t reg_iodir = 0xFF; + uint8_t int_en = 0; for (uint8_t idx = 0; idx < 8; idx++) { switch (Settings.mcp230xx_config[idx].pinmode) { case 0 ... 1: @@ -75,6 +77,7 @@ void MCP230xx_ApplySettings(void) { case 2 ... 4: reg_iodir |= (1 << idx); reg_gpinten |= (1 << idx); + int_en=1; break; default: break; @@ -98,6 +101,7 @@ void MCP230xx_ApplySettings(void) { case 2 ... 4: reg_iodir |= (1 << idx - 8); reg_gpinten |= (1 << idx - 8); + int_en=1; break; default: break; @@ -110,6 +114,7 @@ void MCP230xx_ApplySettings(void) { I2cWrite8(mcp230xx_address, MCP230xx_GPINTEN + 1, reg_gpinten); I2cWrite8(mcp230xx_address, MCP230xx_IODIR + 1, reg_iodir); } + mcp230xx_int_en=int_en; } void MCP230xx_Detect() @@ -308,7 +313,9 @@ boolean Xsns29(byte function) MCP230xx_Detect(); break; case FUNC_EVERY_50_MSECOND: - MCP230xx_CheckForInterrupt(); + if (mcp230xx_int_en) { // Only check for interrupts if its enabled on one of the pins + MCP230xx_CheckForInterrupt(); + } break; case FUNC_JSON_APPEND: MCP230xx_Show(1); From 29c7e409eefe4ef4899ac997f2673b26bf86ee21 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Sun, 22 Jul 2018 22:37:22 -0300 Subject: [PATCH 30/46] ESP-KNX-IP Library - Correct invalid keywords.txt KEYWORD_TOKENTYPE --- lib/esp-knx-ip-0.5.1/keywords.txt | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/esp-knx-ip-0.5.1/keywords.txt b/lib/esp-knx-ip-0.5.1/keywords.txt index bc4989bd4..ec1f4c78c 100644 --- a/lib/esp-knx-ip-0.5.1/keywords.txt +++ b/lib/esp-knx-ip-0.5.1/keywords.txt @@ -1,14 +1,14 @@ # datatypes -address_t DATA_TYPE -message_t DATA_TYPE -callback_id_t DATA_TYPE -callback_assignment_id_t DATA_TYPE -option_entry_t DATA_TYPE -config_id_t DATA_TYPE -enable_condition_t DATA_TYPE -callback_fptr_t DATA_TYPE -feedback_action_fptr_t DATA_TYPE -knx_command_type_t DATA_TYPE +address_t KEYWORD1 DATA_TYPE +message_t KEYWORD1 DATA_TYPE +callback_id_t KEYWORD1 DATA_TYPE +callback_assignment_id_t KEYWORD1 DATA_TYPE +option_entry_t KEYWORD1 DATA_TYPE +config_id_t KEYWORD1 DATA_TYPE +enable_condition_t KEYWORD1 DATA_TYPE +callback_fptr_t KEYWORD1 DATA_TYPE +feedback_action_fptr_t KEYWORD1 DATA_TYPE +knx_command_type_t KEYWORD1 DATA_TYPE # methods setup KEYWORD2 @@ -92,13 +92,13 @@ answer_4byte_int KEYWORD2 answer_4byte_uint KEYWORD2 answer_4byte_float KEYWORD2 -data_to_1byte_int KEYWORD 2 -data_to_2byte_int KEYWORD 2 -data_to_2byte_float KEYWORD 2 -data_to_4byte_float KEYWORD 2 -data_to_3byte_color KEYWORD 2 -data_to_3byte_time KEYWORD 2 -data_to_3byte_data KEYWORD 2 +data_to_1byte_int KEYWORD2 +data_to_2byte_int KEYWORD2 +data_to_2byte_float KEYWORD2 +data_to_4byte_float KEYWORD2 +data_to_3byte_color KEYWORD2 +data_to_3byte_time KEYWORD2 +data_to_3byte_data KEYWORD2 # constants -knx LITERAL1 \ No newline at end of file +knx LITERAL1 From bc6195e4928bfaa881b817ab18a7389d859edcaa Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Sun, 22 Jul 2018 22:40:28 -0300 Subject: [PATCH 31/46] KNX: Added the EVENT knxrx_val1..5 Added the EVENT KNXRX_VAL1...5 when receiving values from the KNX Network or another Tasmota with KNX Now, sensor values (for example) can be sent from one device to another. --- sonoff/xdrv_11_knx.ino | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 2162fbcaa..06cfa6171 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -517,14 +517,27 @@ void KNX_INIT() void KNX_CB_Action(message_t const &msg, void *arg) { device_parameters_t *chan = (device_parameters_t *)arg; - if (!(Settings.flag.knx_enabled)) { return; } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_RECEIVED_FROM " %d.%d.%d " D_COMMAND " %s: %d " D_TO " %s"), - msg.received_on.ga.area, msg.received_on.ga.line, msg.received_on.ga.member, - (msg.ct == KNX_CT_WRITE) ? D_KNX_COMMAND_WRITE : (msg.ct == KNX_CT_READ) ? D_KNX_COMMAND_READ : D_KNX_COMMAND_OTHER, - msg.data[0], - device_param_cb[(chan->type)-1]); + char tempchar[25]; + + if (msg.data_len == 1) { + // COMMAND + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_RECEIVED_FROM " %d.%d.%d " D_COMMAND " %s: %d " D_TO " %s"), + msg.received_on.ga.area, msg.received_on.ga.line, msg.received_on.ga.member, + (msg.ct == KNX_CT_WRITE) ? D_KNX_COMMAND_WRITE : (msg.ct == KNX_CT_READ) ? D_KNX_COMMAND_READ : D_KNX_COMMAND_OTHER, + msg.data[0], + device_param_cb[(chan->type)-1]); + } else { + // VALUE + float tempvar = knx.data_to_2byte_float(msg.data); + dtostrfd(tempvar,2,tempchar); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_RECEIVED_FROM " %d.%d.%d " D_COMMAND " %s: %s " D_TO " %s"), + msg.received_on.ga.area, msg.received_on.ga.line, msg.received_on.ga.member, + (msg.ct == KNX_CT_WRITE) ? D_KNX_COMMAND_WRITE : (msg.ct == KNX_CT_READ) ? D_KNX_COMMAND_READ : D_KNX_COMMAND_OTHER, + tempchar, + device_param_cb[(chan->type)-1]); + } AddLog(LOG_LEVEL_INFO); switch (msg.ct) @@ -548,7 +561,13 @@ void KNX_CB_Action(message_t const &msg, void *arg) { if (!toggle_inhibit) { char command[25]; - snprintf_P(command, sizeof(command), PSTR("event KNXRX_CMND%d=%d"), ((chan->type) - KNX_SLOT1 + 1 ), msg.data[0]); + if (msg.data_len == 1) { + // Command received + snprintf_P(command, sizeof(command), PSTR("event KNXRX_CMND%d=%d"), ((chan->type) - KNX_SLOT1 + 1 ), msg.data[0]); + } else { + // Value received + snprintf_P(command, sizeof(command), PSTR("event KNXRX_VAL%d=%s"), ((chan->type) - KNX_SLOT1 + 1 ), tempchar); + } ExecuteCommand(command, SRC_KNX); if (Settings.flag.knx_enable_enhancement) { toggle_inhibit = TOGGLE_INHIBIT_TIME; From a6f27db9103dcac49267ddc311d55785e032942a Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Sun, 22 Jul 2018 23:14:33 -0300 Subject: [PATCH 32/46] Make KNX WEB MENU optional --- sonoff/user_config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 6d80fff83..5ba122be4 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -238,6 +238,7 @@ // -- KNX IP Protocol ----------------------------- //#define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem) + #define USE_KNX_WEB_MENU // Enable KNX WEB MENU // -- HTTP ---------------------------------------- #define USE_WEBSERVER // Enable web server and Wifi Manager (+66k code, +8k mem) From 9c5d3f501d4cd065b3987eb5395e0a0cafdcbf2e Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Sun, 22 Jul 2018 23:16:05 -0300 Subject: [PATCH 33/46] Make KNX WEB MENU Optional --- sonoff/xdrv_02_webserver.ino | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index 12ed741ac..8418f3ce9 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -204,7 +204,9 @@ const char HTTP_BTN_MENU_MQTT[] PROGMEM = ""; const char HTTP_BTN_MENU4[] PROGMEM = #ifdef USE_KNX +#ifdef USE_KNX_WEB_MENU "
" +#endif // USE_KNX_WEB_MENU #endif // USE_KNX "
" "
" @@ -391,7 +393,9 @@ void StartWebserver(int type, IPAddress ipweb) #endif // USE_DOMOTICZ } #ifdef USE_KNX +#ifdef USE_KNX_WEB_MENU WebServer->on("/kn", HandleKNXConfiguration); +#endif // USE_KNX_WEB_MENU #endif // USE_KNX WebServer->on("/lg", HandleLoggingConfiguration); WebServer->on("/co", HandleOtherConfiguration); From 552ac7d5451c437ff19433a0be99b8e4984e1584 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Sun, 22 Jul 2018 23:16:46 -0300 Subject: [PATCH 34/46] Make KNX WEB MENU Optional --- sonoff/xdrv_11_knx.ino | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 06cfa6171..5aadbc6c0 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -716,6 +716,7 @@ void KnxSensor(byte sensor_type, float value) \*********************************************************************************************/ #ifdef USE_WEBSERVER +#ifdef USE_KNX_WEB_MENU const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX; const char HTTP_FORM_KNX[] PROGMEM = @@ -1020,6 +1021,7 @@ void KNX_Save_Settings() } } +#endif // USE_KNX_WEB_MENU #endif // USE_WEBSERVER From 99eb3362aa784b252326116e6cf963b5650b548b Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Mon, 23 Jul 2018 00:54:25 -0300 Subject: [PATCH 35/46] Make KNX WEB MENU optional --- sonoff/user_config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 5ba122be4..173ed8684 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -237,8 +237,8 @@ //#define USE_MQTT_TLS // Use TLS for MQTT connection (+53k code, +15k mem) // -- KNX IP Protocol ----------------------------- -//#define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem) - #define USE_KNX_WEB_MENU // Enable KNX WEB MENU +//#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem) + #define USE_KNX_WEB_MENU // Enable KNX WEB MENU (+8.3k code, +144 mem) // -- HTTP ---------------------------------------- #define USE_WEBSERVER // Enable web server and Wifi Manager (+66k code, +8k mem) From 77181854a7bfd33897809cbc4a7efebdafa64071 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Mon, 23 Jul 2018 01:01:52 -0300 Subject: [PATCH 36/46] Added KNX commands * KNX_ENABLED 0/1 * KNX_ENHANCED 0/1 --- sonoff/xdrv_11_knx.ino | 55 +++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 5aadbc6c0..35fa559ad 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -196,8 +196,10 @@ const char *device_param_cb[] = { // Commands #define D_CMND_KNXTXCMND "KnxTx_Cmnd" #define D_CMND_KNXTXVAL "KnxTx_Val" -enum KnxCommands { CMND_KNXTXCMND, CMND_KNXTXVAL }; -const char kKnxCommands[] PROGMEM = D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL ; +#define D_CMND_KNX_ENABLED "Knx_Enabled" +#define D_CMND_KNX_ENHANCED "Knx_Enhanced" +enum KnxCommands { CMND_KNXTXCMND, CMND_KNXTXVAL, CMND_KNX_ENABLED, CMND_KNX_ENHANCED } ; +const char kKnxCommands[] PROGMEM = D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" D_CMND_KNX_ENHANCED ; byte KNX_GA_Search( byte param, byte start = 0 ) @@ -1031,14 +1033,12 @@ boolean KnxCommand() uint8_t index = XdrvMailbox.index; int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kKnxCommands); - if (!(Settings.flag.knx_enabled)) { return false; } - if (-1 == command_code) { return false; } // Unknown command else if ((CMND_KNXTXCMND == command_code) && (index > 0) && (index <= MAX_KNXTX_CMNDS) && (XdrvMailbox.data_len > 0)) { // index <- KNX SLOT to use // XdrvMailbox.payload <- data to send - + if (!(Settings.flag.knx_enabled)) { return false; } // Search all the registered GA that has that output (variable: KNX SLOTx) as parameter byte i = KNX_GA_Search(index + KNX_SLOT1 -1); while ( i != KNX_Empty ) { @@ -1056,12 +1056,14 @@ boolean KnxCommand() i = KNX_GA_Search(index + KNX_SLOT1 -1, i + 1); } + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s\"}"), + command, index, XdrvMailbox.data ); } else if ((CMND_KNXTXVAL == command_code) && (index > 0) && (index <= MAX_KNXTX_CMNDS) && (XdrvMailbox.data_len > 0)) { // index <- KNX SLOT to use // XdrvMailbox.payload <- data to send - + if (!(Settings.flag.knx_enabled)) { return false; } // Search all the registered GA that has that output (variable: KNX SLOTx) as parameter byte i = KNX_GA_Search(index + KNX_SLOT1 -1); while ( i != KNX_Empty ) { @@ -1083,13 +1085,48 @@ boolean KnxCommand() i = KNX_GA_Search(index + KNX_SLOT1 -1, i + 1); } + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s\"}"), + command, index, XdrvMailbox.data ); + } + + else if (CMND_KNX_ENABLED == command_code) { + if (!XdrvMailbox.data_len) { + if (Settings.flag.knx_enabled) { + snprintf_P(XdrvMailbox.data, sizeof(XdrvMailbox.data), PSTR("1")); + } else { + snprintf_P(XdrvMailbox.data, sizeof(XdrvMailbox.data), PSTR("0")); + } + } else { + if (XdrvMailbox.payload == 1) { + Settings.flag.knx_enabled = 1; + } else if (XdrvMailbox.payload == 0) { + Settings.flag.knx_enabled = 0; + } else { return false; } // Incomplete command + } + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\"}"), + command, XdrvMailbox.data ); + } + + else if (CMND_KNX_ENHANCED == command_code) { + if (!XdrvMailbox.data_len) { + if (Settings.flag.knx_enable_enhancement) { + snprintf_P(XdrvMailbox.data, sizeof(XdrvMailbox.data), PSTR("1")); + } else { + snprintf_P(XdrvMailbox.data, sizeof(XdrvMailbox.data), PSTR("0")); + } + } else { + if (XdrvMailbox.payload == 1) { + Settings.flag.knx_enable_enhancement = 1; + } else if (XdrvMailbox.payload == 0) { + Settings.flag.knx_enable_enhancement = 0; + } else { return false; } // Incomplete command + } + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\"}"), + command, XdrvMailbox.data ); } else { return false; } // Incomplete command - snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s\"}"), - command, index, XdrvMailbox.data ); - return true; } From 96fb23737dd142077c1494874542256762ef00f2 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Mon, 23 Jul 2018 01:29:50 -0300 Subject: [PATCH 37/46] Move subStr Function to Support.ino --- sonoff/xdrv_10_rules.ino | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 2129fdbbe..3296a9560 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -603,24 +603,6 @@ double map_double(double x, double in_min, double in_max, double out_min, double return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } -// Function to return a substring defined by a delimiter at an index -char* subStr(char* dest, char* str, const char *delim, int index) -{ - char *act; - char *sub; - char *ptr; - int i; - - // Since strtok consumes the first arg, make a copy - strncpy(dest, str, strlen(str)); - for (i = 1, act = dest; i <= index; i++, act = NULL) { - sub = strtok_r(act, delim, &ptr); - if (sub == NULL) break; - } - sub = Trim(sub); - return sub; -} - /*********************************************************************************************\ * Interface \*********************************************************************************************/ From 754955cd4886a9796dcf67fddc03b5301291b106 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Mon, 23 Jul 2018 01:32:54 -0300 Subject: [PATCH 38/46] Move subStr Function to Support.ino --- sonoff/support.ino | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sonoff/support.ino b/sonoff/support.ino index 4930f8e4b..a5d6e9e4e 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -130,6 +130,24 @@ size_t strchrspn(const char *str1, int character) return ret; } +// Function to return a substring defined by a delimiter at an index +char* subStr(char* dest, char* str, const char *delim, int index) +{ + char *act; + char *sub; + char *ptr; + int i; + + // Since strtok consumes the first arg, make a copy + strncpy(dest, str, strlen(str)); + for (i = 1, act = dest; i <= index; i++, act = NULL) { + sub = strtok_r(act, delim, &ptr); + if (sub == NULL) break; + } + sub = Trim(sub); + return sub; +} + double CharToDouble(char *str) { // simple ascii to double, because atof or strtod are too large From a294a9179dd8bb03d89cccdbda455ef0f736eb4f Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Mon, 23 Jul 2018 02:15:44 -0300 Subject: [PATCH 39/46] Added Command KNX_PA Added Command KNX_PA for changing the device KNX Physical Address --- sonoff/xdrv_11_knx.ino | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 35fa559ad..5016393c8 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -198,9 +198,10 @@ const char *device_param_cb[] = { #define D_CMND_KNXTXVAL "KnxTx_Val" #define D_CMND_KNX_ENABLED "Knx_Enabled" #define D_CMND_KNX_ENHANCED "Knx_Enhanced" -enum KnxCommands { CMND_KNXTXCMND, CMND_KNXTXVAL, CMND_KNX_ENABLED, CMND_KNX_ENHANCED } ; -const char kKnxCommands[] PROGMEM = D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" D_CMND_KNX_ENHANCED ; - +#define D_CMND_KNX_PA "Knx_PA" +enum KnxCommands { CMND_KNXTXCMND, CMND_KNXTXVAL, CMND_KNX_ENABLED, CMND_KNX_ENHANCED, CMND_KNX_PA } ; +const char kKnxCommands[] PROGMEM = D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" + D_CMND_KNX_ENHANCED "|" D_CMND_KNX_PA ; byte KNX_GA_Search( byte param, byte start = 0 ) { @@ -1125,6 +1126,33 @@ boolean KnxCommand() command, XdrvMailbox.data ); } + else if (CMND_KNX_PA == command_code) { + if (XdrvMailbox.data_len) { + if (strstr(XdrvMailbox.data, ".")) { // Process parameter entry + char sub_string[XdrvMailbox.data_len +1]; + + int pa_area = atoi(subStr(sub_string, XdrvMailbox.data, ".", 1)); + int pa_line = atoi(subStr(sub_string, XdrvMailbox.data, ".", 2)); + int pa_member = atoi(subStr(sub_string, XdrvMailbox.data, ".", 3)); + + if ( ((pa_area == 0) && (pa_line == 0) && (pa_member == 0)) + || (pa_area > 15) || (pa_line > 15) || (pa_member > 255) ) { + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"" D_ERROR "\"}"), + command ); + return true; + } // Invalid command + + KNX_addr.pa.area = pa_area; + KNX_addr.pa.line = pa_line; + KNX_addr.pa.member = pa_member; + Settings.knx_physsical_addr = KNX_addr.value; + } + } + KNX_addr.value = Settings.knx_physsical_addr; + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%d.%d.%d\"}"), + command, KNX_addr.pa.area, KNX_addr.pa.line, KNX_addr.pa.member ); + } + else { return false; } // Incomplete command return true; From 3373fff9eb40d6a367ceb6eba216b3bf6eb9ec7c Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Mon, 23 Jul 2018 04:03:57 -0300 Subject: [PATCH 40/46] Added Commands KNX_GA and KNX_CB * Added command KNX_GA so as to setup Group Address to Send Data/Commands Usage: KNX_GA (return the amount of GA configured) KNX_GA 1 (return the configuration of the GA#1 KNX_GAx option, area, line, member (Set the configuration of the GA#x) example: KNX_GA3 1, 2,2,4 For the GA#3, the status of Relay 1 is sent to 2.2.4 * Added command KNX_CB so as to setup Group Address to Receive Data/Commands KNX_CBx option, area, line, member example: KNX_CB2 1, 2,2,4 For the CB#2, listen to 2.2.4 to set the status of the Relay 1 Posible values of the parameter OPTION: 1 - Relay 1 2 - Relay 2 3 - Relay 3 4 - Relay 4 5 - Relay 5 6 - Relay 6 7 - Relay 7 8 - Relay 8 9 - Button 1 10 - Button 2 11 - Button 3 12 - Button 4 13 - Button 5 14 - Button 6 15 - Button 7 16 - Button 8 17 - TEMPERATURE 18 - HUMIDITY 19 - ENERGY_VOLTAGE 20 - ENERGY_CURRENT 21 - ENERGY_POWER 22 - ENERGY_POWERFACTOR 23 - ENERGY_DAILY 24 - ENERGY_START 25 - ENERGY_TOTAL 26 - KNX_SLOT1 27 - KNX_SLOT2 28 - KNX_SLOT3 29 - KNX_SLOT4 30 - KNX_SLOT5 255 - EMPTY --- sonoff/xdrv_11_knx.ino | 105 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 5016393c8..710b63f66 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -199,9 +199,12 @@ const char *device_param_cb[] = { #define D_CMND_KNX_ENABLED "Knx_Enabled" #define D_CMND_KNX_ENHANCED "Knx_Enhanced" #define D_CMND_KNX_PA "Knx_PA" -enum KnxCommands { CMND_KNXTXCMND, CMND_KNXTXVAL, CMND_KNX_ENABLED, CMND_KNX_ENHANCED, CMND_KNX_PA } ; +#define D_CMND_KNX_GA "Knx_GA" +#define D_CMND_KNX_CB "Knx_CB" +enum KnxCommands { CMND_KNXTXCMND, CMND_KNXTXVAL, CMND_KNX_ENABLED, CMND_KNX_ENHANCED, CMND_KNX_PA, + CMND_KNX_GA, CMND_KNX_CB } ; const char kKnxCommands[] PROGMEM = D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" - D_CMND_KNX_ENHANCED "|" D_CMND_KNX_PA ; + D_CMND_KNX_ENHANCED "|" D_CMND_KNX_PA "|" D_CMND_KNX_GA "|" D_CMND_KNX_CB ; byte KNX_GA_Search( byte param, byte start = 0 ) { @@ -1153,6 +1156,104 @@ boolean KnxCommand() command, KNX_addr.pa.area, KNX_addr.pa.line, KNX_addr.pa.member ); } + else if ((CMND_KNX_GA == command_code) && (index > 0) && (index <= MAX_KNX_GA)) { + if (XdrvMailbox.data_len) { + if (strstr(XdrvMailbox.data, ",")) { // Process parameter entry + char sub_string[XdrvMailbox.data_len +1]; + + int ga_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1)); + int ga_area = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); + int ga_line = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); + int ga_member = atoi(subStr(sub_string, XdrvMailbox.data, ",", 4)); + + if ( ((ga_area == 0) && (ga_line == 0) && (ga_member == 0)) + || (ga_area > 31) || (ga_line > 7) || (ga_member > 255) + || (ga_option < 0) || ((ga_option > KNX_MAX_device_param ) && (ga_option != KNX_Empty)) + || (!device_param[ga_option-1].show) ) { + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"" D_ERROR "\"}"), command ); + return true; + } // Invalid command + + KNX_addr.ga.area = ga_area; + KNX_addr.ga.line = ga_line; + KNX_addr.ga.member = ga_member; + + if ( index > Settings.knx_GA_registered ) { + Settings.knx_GA_registered ++; + index = Settings.knx_GA_registered; + } + + Settings.knx_GA_addr[index -1] = KNX_addr.value; + Settings.knx_GA_param[index -1] = ga_option; + } else { + if ( (XdrvMailbox.payload <= Settings.knx_GA_registered) && (XdrvMailbox.payload > 0) ) { + index = XdrvMailbox.payload; + } else { + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"" D_ERROR "\"}"), command ); + return true; + } + } + if ( index <= Settings.knx_GA_registered ) { + KNX_addr.value = Settings.knx_GA_addr[index -1]; + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s, %d/%d/%d\"}"), + command, index, device_param_ga[Settings.knx_GA_param[index-1]-1], + KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member ); + } + } else { + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%d\"}"), + command, Settings.knx_GA_registered ); + } + } + + else if ((CMND_KNX_CB == command_code) && (index > 0) && (index <= MAX_KNX_CB)) { + if (XdrvMailbox.data_len) { + if (strstr(XdrvMailbox.data, ",")) { // Process parameter entry + char sub_string[XdrvMailbox.data_len +1]; + + int cb_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1)); + int cb_area = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); + int cb_line = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); + int cb_member = atoi(subStr(sub_string, XdrvMailbox.data, ",", 4)); + + if ( ((cb_area == 0) && (cb_line == 0) && (cb_member == 0)) + || (cb_area > 31) || (cb_line > 7) || (cb_member > 255) + || (cb_option < 0) || ((cb_option > KNX_MAX_device_param ) && (cb_option != KNX_Empty)) + || (!device_param[cb_option-1].show) ) { + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"" D_ERROR "\"}"), command ); + return true; + } // Invalid command + + KNX_addr.ga.area = cb_area; + KNX_addr.ga.line = cb_line; + KNX_addr.ga.member = cb_member; + + if ( index > Settings.knx_CB_registered ) { + Settings.knx_CB_registered ++; + index = Settings.knx_CB_registered; + } + + Settings.knx_CB_addr[index -1] = KNX_addr.value; + Settings.knx_CB_param[index -1] = cb_option; + } else { + if ( (XdrvMailbox.payload <= Settings.knx_CB_registered) && (XdrvMailbox.payload > 0) ) { + index = XdrvMailbox.payload; + } else { + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"" D_ERROR "\"}"), command ); + return true; + } + } + if ( index <= Settings.knx_CB_registered ) { + KNX_addr.value = Settings.knx_CB_addr[index -1]; + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s, %d/%d/%d\"}"), + command, index, device_param_cb[Settings.knx_CB_param[index-1]-1], + KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member ); + } + } else { + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%d\"}"), + command, Settings.knx_CB_registered ); + } + } + else { return false; } // Incomplete command return true; From adc781b8fcfb173787c192763a3046412c0dd783 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Mon, 23 Jul 2018 12:11:04 +0200 Subject: [PATCH 41/46] Remove Travis deploy Removed Travis deploy as it fails to properly byte align resulting in corrupted binaries. --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index c57f2e523..8e950a42e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,12 +12,3 @@ script: - platformio run before_deploy: - for file in .pioenvs/*/firmware.bin; do cp $file ${file%/*}.bin; done -deploy: - provider: releases - api_key: - secure: I5x8qJ5+229qJv5jSnNPGERQHl0NSKvrVHdpVzr/HOo2zeZ/Q5sMhHWo3IBD3AKjGdSlpyNApDwYTaGvenMe+xtUWSSxYIy2ptWAWfkpOtUMx3lI3brZJRt8s98xS5m972SC9mlNT2ZU+i6hZ6srYv2w4nDuyX+j7Q6IGqvYtabxUWzza/Zg0yNpPScvvzscW1CVhdEd5qYH6OKfBfuVOj3ZG4pCycvbejhkUJwbCQ5m8+DEXUol8BKeh92+TPC3jDHXWIStdgLIrmkZ3YWxMQBgQ41QIkaf6X1/0WYEcY0DFW6hlDzg2GbJ8tPRRPC9dfgMs3ZMKJkc7e4x7wMvG2QXQ0aO6e7xTMw41JZ/OrIit0JDHB1M8bWDPUhHwjiCht4W77n7KWFk9sIUDzOdMdd69BIMt5IohtkjnIT2dXekB4xiNvfPLYUa70aOuSHWi3HXVSE1R7RX0brmNf/mH1Pm91uun3UqtIwhrpD0gteQnc0EAlHoOJOazdn3cohrtmECZJo+f+EiqFfEHT2hBrHPEvWknNfxAyPS7jYWKQ7pTMk+y/BUkLyIQkimvNz41azA6sA75nnQrZ+ZJQa+KP2cEObMBs/ekzA45nds1UXpolI1W8QIOxJ/Y10C1yxr6V5a3WWg1H8EbF0HaqiyIeQx/UCz7gl62CbLEDui9PA= - file_glob: true - file: ".pioenvs/*.bin" - skip_cleanup: true - on: - tags: true \ No newline at end of file From d21a04e8721e9d8b54f31854e8ff31b0e435a604 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Mon, 23 Jul 2018 16:27:15 +0200 Subject: [PATCH 42/46] ccs811 completely new from arends/development --- lib/Adafruit_CCS811-master/.travis.yml | 27 ++ .../Adafruit_CCS811.cpp | 280 ++++++++++++++++++ lib/Adafruit_CCS811-master/Adafruit_CCS811.h | 231 +++++++++++++++ lib/Adafruit_CCS811-master/LICENSE | 21 ++ lib/Adafruit_CCS811-master/README.md | 13 + .../CCS811_OLED_Demo/CCS811_OLED_Demo.ino | 80 +++++ .../examples/CCS811_test/CCS811_test.ino | 56 ++++ lib/Adafruit_CCS811-master/library.properties | 9 + sonoff/sonoff.ino | 5 + sonoff/sonoff_post.h | 4 + sonoff/xsns_09_bmp.ino | 6 + sonoff/xsns_14_sht3x.ino | 11 +- sonoff/xsns_31_ccs811.ino | 131 ++++++++ 13 files changed, 873 insertions(+), 1 deletion(-) create mode 100755 lib/Adafruit_CCS811-master/.travis.yml create mode 100755 lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp create mode 100755 lib/Adafruit_CCS811-master/Adafruit_CCS811.h create mode 100755 lib/Adafruit_CCS811-master/LICENSE create mode 100755 lib/Adafruit_CCS811-master/README.md create mode 100755 lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino create mode 100755 lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino create mode 100755 lib/Adafruit_CCS811-master/library.properties mode change 100644 => 100755 sonoff/sonoff.ino mode change 100644 => 100755 sonoff/sonoff_post.h mode change 100644 => 100755 sonoff/xsns_09_bmp.ino mode change 100644 => 100755 sonoff/xsns_14_sht3x.ino create mode 100644 sonoff/xsns_31_ccs811.ino diff --git a/lib/Adafruit_CCS811-master/.travis.yml b/lib/Adafruit_CCS811-master/.travis.yml new file mode 100755 index 000000000..95efcfaef --- /dev/null +++ b/lib/Adafruit_CCS811-master/.travis.yml @@ -0,0 +1,27 @@ +language: c +sudo: false + +# Blacklist +branches: + except: + - gh-pages + +env: + global: + - PRETTYNAME="Adafruit CCS811 Arduino Library" +# Optional, will default to "$TRAVIS_BUILD_DIR/Doxyfile" +# - DOXYFILE: $TRAVIS_BUILD_DIR/Doxyfile + +before_install: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) + +install: + - arduino --install-library "Adafruit SSD1306","Adafruit GFX Library" + +script: + - build_main_platforms + +# Generate and deploy documentation +after_success: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/library_check.sh) + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/doxy_gen_and_deploy.sh) \ No newline at end of file diff --git a/lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp b/lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp new file mode 100755 index 000000000..c69cd41f9 --- /dev/null +++ b/lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp @@ -0,0 +1,280 @@ +#include "Adafruit_CCS811.h" + +/**************************************************************************/ +/*! + @brief Setups the I2C interface and hardware and checks for communication. + @param addr Optional I2C address the sensor can be found on. Default is 0x5A + @returns True if device is set up, false on any failure +*/ +/**************************************************************************/ +sint8_t Adafruit_CCS811::begin(uint8_t addr) +{ + _i2caddr = addr; + + _i2c_init(); + + SWReset(); + delay(100); + + //check that the HW id is correct + if(this->read8(CCS811_HW_ID) != CCS811_HW_ID_CODE) { + return -1; + } + + //try to start the app + this->write(CCS811_BOOTLOADER_APP_START, NULL, 0); + delay(100); + + //make sure there are no errors and we have entered application mode + if(checkError()) { + return -2; + } + if(!_status.FW_MODE) { + return -3; + } + + disableInterrupt(); + + //default to read every second + setDriveMode(CCS811_DRIVE_MODE_1SEC); + + return 0; +} + +/**************************************************************************/ +/*! + @brief sample rate of the sensor. + @param mode one of CCS811_DRIVE_MODE_IDLE, CCS811_DRIVE_MODE_1SEC, CCS811_DRIVE_MODE_10SEC, CCS811_DRIVE_MODE_60SEC, CCS811_DRIVE_MODE_250MS. +*/ +void Adafruit_CCS811::setDriveMode(uint8_t mode) +{ + _meas_mode.DRIVE_MODE = mode; + this->write8(CCS811_MEAS_MODE, _meas_mode.get()); +} + +/**************************************************************************/ +/*! + @brief enable the data ready interrupt pin on the device. +*/ +/**************************************************************************/ +void Adafruit_CCS811::enableInterrupt() +{ + _meas_mode.INT_DATARDY = 1; + this->write8(CCS811_MEAS_MODE, _meas_mode.get()); +} + +/**************************************************************************/ +/*! + @brief disable the data ready interrupt pin on the device +*/ +/**************************************************************************/ +void Adafruit_CCS811::disableInterrupt() +{ + _meas_mode.INT_DATARDY = 0; + this->write8(CCS811_MEAS_MODE, _meas_mode.get()); +} + +/**************************************************************************/ +/*! + @brief checks if data is available to be read. + @returns True if data is ready, false otherwise. +*/ +/**************************************************************************/ +bool Adafruit_CCS811::available() +{ + _status.set(read8(CCS811_STATUS)); + if(!_status.DATA_READY) + return false; + else return true; +} + +/**************************************************************************/ +/*! + @brief read and store the sensor data. This data can be accessed with getTVOC() and geteCO2() + @returns 0 if no error, error code otherwise. +*/ +/**************************************************************************/ +uint8_t Adafruit_CCS811::readData() +{ + if(!available()) + return false; + else{ + uint8_t buf[8]; + this->read(CCS811_ALG_RESULT_DATA, buf, 8); + + _eCO2 = ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]); + _TVOC = ((uint16_t)buf[2] << 8) | ((uint16_t)buf[3]); + + if(_status.ERROR) + return buf[5]; + + else return 0; + } +} + +/**************************************************************************/ +/*! + @brief set the humidity and temperature compensation for the sensor. + @param humidity the humidity data as a percentage. For 55% humidity, pass in integer 55. + @param temperature the temperature in degrees C as a decimal number. For 25.5 degrees C, pass in 25.5 +*/ +/**************************************************************************/ +void Adafruit_CCS811::setEnvironmentalData(uint8_t humidity, double temperature) +{ + /* Humidity is stored as an unsigned 16 bits in 1/512%RH. The + default value is 50% = 0x64, 0x00. As an example 48.5% + humidity would be 0x61, 0x00.*/ + + /* Temperature is stored as an unsigned 16 bits integer in 1/512 + degrees; there is an offset: 0 maps to -25°C. The default value is + 25°C = 0x64, 0x00. As an example 23.5% temperature would be + 0x61, 0x00. + The internal algorithm uses these values (or default values if + not set by the application) to compensate for changes in + relative humidity and ambient temperature.*/ + + uint8_t hum_perc = humidity << 1; + + float fractional = modf(temperature, &temperature); + uint16_t temp_high = (((uint16_t)temperature + 25) << 9); + uint16_t temp_low = ((uint16_t)(fractional / 0.001953125) & 0x1FF); + + uint16_t temp_conv = (temp_high | temp_low); + + uint8_t buf[] = {hum_perc, 0x00, + (uint8_t)((temp_conv >> 8) & 0xFF), (uint8_t)(temp_conv & 0xFF)}; + + this->write(CCS811_ENV_DATA, buf, 4); + +} + +/**************************************************************************/ +/*! + @brief calculate the temperature using the onboard NTC resistor. + @returns temperature as a double. +*/ +/**************************************************************************/ +double Adafruit_CCS811::calculateTemperature() +{ + uint8_t buf[4]; + this->read(CCS811_NTC, buf, 4); + + uint32_t vref = ((uint32_t)buf[0] << 8) | buf[1]; + uint32_t vntc = ((uint32_t)buf[2] << 8) | buf[3]; + + //from ams ccs811 app note + uint32_t rntc = vntc * CCS811_REF_RESISTOR / vref; + + double ntc_temp; + ntc_temp = log((double)rntc / CCS811_REF_RESISTOR); // 1 + ntc_temp /= 3380; // 2 + ntc_temp += 1.0 / (25 + 273.15); // 3 + ntc_temp = 1.0 / ntc_temp; // 4 + ntc_temp -= 273.15; // 5 + return ntc_temp - _tempOffset; + +} + +/**************************************************************************/ +/*! + @brief set interrupt thresholds + @param low_med the level below which an interrupt will be triggered. + @param med_high the level above which the interrupt will ge triggered. + @param hysteresis optional histeresis level. Defaults to 50 +*/ +/**************************************************************************/ +void Adafruit_CCS811::setThresholds(uint16_t low_med, uint16_t med_high, uint8_t hysteresis) +{ + uint8_t buf[] = {(uint8_t)((low_med >> 8) & 0xF), (uint8_t)(low_med & 0xF), + (uint8_t)((med_high >> 8) & 0xF), (uint8_t)(med_high & 0xF), hysteresis}; + + this->write(CCS811_THRESHOLDS, buf, 5); +} + +/**************************************************************************/ +/*! + @brief trigger a software reset of the device +*/ +/**************************************************************************/ +void Adafruit_CCS811::SWReset() +{ + //reset sequence from the datasheet + uint8_t seq[] = {0x11, 0xE5, 0x72, 0x8A}; + this->write(CCS811_SW_RESET, seq, 4); +} + +/**************************************************************************/ +/*! + @brief read the status register and store any errors. + @returns the error bits from the status register of the device. +*/ +/**************************************************************************/ +bool Adafruit_CCS811::checkError() +{ + _status.set(read8(CCS811_STATUS)); + return _status.ERROR; +} + +/**************************************************************************/ +/*! + @brief write one byte of data to the specified register + @param reg the register to write to + @param value the value to write +*/ +/**************************************************************************/ +void Adafruit_CCS811::write8(byte reg, byte value) +{ + this->write(reg, &value, 1); +} + +/**************************************************************************/ +/*! + @brief read one byte of data from the specified register + @param reg the register to read + @returns one byte of register data +*/ +/**************************************************************************/ +uint8_t Adafruit_CCS811::read8(byte reg) +{ + uint8_t ret; + this->read(reg, &ret, 1); + + return ret; +} + +void Adafruit_CCS811::_i2c_init() +{ + Wire.begin(); + #ifdef ESP8266 + Wire.setClockStretchLimit(1000); + #endif +} + +void Adafruit_CCS811::read(uint8_t reg, uint8_t *buf, uint8_t num) +{ + uint8_t value; + uint8_t pos = 0; + + //on arduino we need to read in 32 byte chunks + while(pos < num){ + + uint8_t read_now = min((uint8_t)32, (uint8_t)(num - pos)); + Wire.beginTransmission((uint8_t)_i2caddr); + Wire.write((uint8_t)reg + pos); + Wire.endTransmission(); + Wire.requestFrom((uint8_t)_i2caddr, read_now); + + for(int i=0; i= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include + +/*========================================================================= + I2C ADDRESS/BITS + -----------------------------------------------------------------------*/ + #define CCS811_ADDRESS (0x5A) +/*=========================================================================*/ + +/*========================================================================= + REGISTERS + -----------------------------------------------------------------------*/ + enum + { + CCS811_STATUS = 0x00, + CCS811_MEAS_MODE = 0x01, + CCS811_ALG_RESULT_DATA = 0x02, + CCS811_RAW_DATA = 0x03, + CCS811_ENV_DATA = 0x05, + CCS811_NTC = 0x06, + CCS811_THRESHOLDS = 0x10, + CCS811_BASELINE = 0x11, + CCS811_HW_ID = 0x20, + CCS811_HW_VERSION = 0x21, + CCS811_FW_BOOT_VERSION = 0x23, + CCS811_FW_APP_VERSION = 0x24, + CCS811_ERROR_ID = 0xE0, + CCS811_SW_RESET = 0xFF, + }; + + //bootloader registers + enum + { + CCS811_BOOTLOADER_APP_ERASE = 0xF1, + CCS811_BOOTLOADER_APP_DATA = 0xF2, + CCS811_BOOTLOADER_APP_VERIFY = 0xF3, + CCS811_BOOTLOADER_APP_START = 0xF4 + }; + + enum + { + CCS811_DRIVE_MODE_IDLE = 0x00, + CCS811_DRIVE_MODE_1SEC = 0x01, + CCS811_DRIVE_MODE_10SEC = 0x02, + CCS811_DRIVE_MODE_60SEC = 0x03, + CCS811_DRIVE_MODE_250MS = 0x04, + }; + +/*=========================================================================*/ + +#define CCS811_HW_ID_CODE 0x81 + +#define CCS811_REF_RESISTOR 100000 + +/**************************************************************************/ +/*! + @brief Class that stores state and functions for interacting with CCS811 gas sensor chips +*/ +/**************************************************************************/ +class Adafruit_CCS811 { + public: + //constructors + Adafruit_CCS811(void) {}; + ~Adafruit_CCS811(void) {}; + + sint8_t begin(uint8_t addr = CCS811_ADDRESS); + + void setEnvironmentalData(uint8_t humidity, double temperature); + + //calculate temperature based on the NTC register + double calculateTemperature(); + + void setThresholds(uint16_t low_med, uint16_t med_high, uint8_t hysteresis = 50); + + void SWReset(); + + void setDriveMode(uint8_t mode); + void enableInterrupt(); + void disableInterrupt(); + + /**************************************************************************/ + /*! + @brief returns the stored total volatile organic compounds measurement. This does does not read the sensor. To do so, call readData() + @returns TVOC measurement as 16 bit integer + */ + /**************************************************************************/ + uint16_t getTVOC() { return _TVOC; } + + /**************************************************************************/ + /*! + @brief returns the stored estimated carbon dioxide measurement. This does does not read the sensor. To do so, call readData() + @returns eCO2 measurement as 16 bit integer + */ + /**************************************************************************/ + uint16_t geteCO2() { return _eCO2; } + + /**************************************************************************/ + /*! + @brief set the temperature compensation offset for the device. This is needed to offset errors in NTC measurements. + @param offset the offset to be added to temperature measurements. + */ + /**************************************************************************/ + void setTempOffset(float offset) { _tempOffset = offset; } + + //check if data is available to be read + bool available(); + uint8_t readData(); + + bool checkError(); + + private: + uint8_t _i2caddr; + float _tempOffset; + + uint16_t _TVOC; + uint16_t _eCO2; + + void write8(byte reg, byte value); + void write16(byte reg, uint16_t value); + uint8_t read8(byte reg); + + void read(uint8_t reg, uint8_t *buf, uint8_t num); + void write(uint8_t reg, uint8_t *buf, uint8_t num); + void _i2c_init(); + +/*========================================================================= + REGISTER BITFIELDS + -----------------------------------------------------------------------*/ + // The status register + struct status { + + /* 0: no error + * 1: error has occurred + */ + uint8_t ERROR: 1; + + // reserved : 2 + + /* 0: no samples are ready + * 1: samples are ready + */ + uint8_t DATA_READY: 1; + uint8_t APP_VALID: 1; + + // reserved : 2 + + /* 0: boot mode, new firmware can be loaded + * 1: application mode, can take measurements + */ + uint8_t FW_MODE: 1; + + void set(uint8_t data){ + ERROR = data & 0x01; + DATA_READY = (data >> 3) & 0x01; + APP_VALID = (data >> 4) & 0x01; + FW_MODE = (data >> 7) & 0x01; + } + }; + status _status; + + //measurement and conditions register + struct meas_mode { + // reserved : 2 + + /* 0: interrupt mode operates normally + * 1: Interrupt mode (if enabled) only asserts the nINT signal (driven low) if the new + ALG_RESULT_DATA crosses one of the thresholds set in the THRESHOLDS register + by more than the hysteresis value (also in the THRESHOLDS register) + */ + uint8_t INT_THRESH: 1; + + /* 0: int disabled + * 1: The nINT signal is asserted (driven low) when a new sample is ready in + ALG_RESULT_DATA. The nINT signal will stop being driven low when + ALG_RESULT_DATA is read on the I²C interface. + */ + uint8_t INT_DATARDY: 1; + + uint8_t DRIVE_MODE: 3; + + uint8_t get(){ + return (INT_THRESH << 2) | (INT_DATARDY << 3) | (DRIVE_MODE << 4); + } + }; + meas_mode _meas_mode; + + struct error_id { + /* The CCS811 received an I²C write request addressed to this station but with + invalid register address ID */ + uint8_t WRITE_REG_INVALID: 1; + + /* The CCS811 received an I²C read request to a mailbox ID that is invalid */ + uint8_t READ_REG_INVALID: 1; + + /* The CCS811 received an I²C request to write an unsupported mode to + MEAS_MODE */ + uint8_t MEASMODE_INVALID: 1; + + /* The sensor resistance measurement has reached or exceeded the maximum + range */ + uint8_t MAX_RESISTANCE: 1; + + /* The Heater current in the CCS811 is not in range */ + uint8_t HEATER_FAULT: 1; + + /* The Heater voltage is not being applied correctly */ + uint8_t HEATER_SUPPLY: 1; + + void set(uint8_t data){ + WRITE_REG_INVALID = data & 0x01; + READ_REG_INVALID = (data & 0x02) >> 1; + MEASMODE_INVALID = (data & 0x04) >> 2; + MAX_RESISTANCE = (data & 0x08) >> 3; + HEATER_FAULT = (data & 0x10) >> 4; + HEATER_SUPPLY = (data & 0x20) >> 5; + } + }; + error_id _error_id; + +/*=========================================================================*/ +}; + +#endif diff --git a/lib/Adafruit_CCS811-master/LICENSE b/lib/Adafruit_CCS811-master/LICENSE new file mode 100755 index 000000000..860e3e285 --- /dev/null +++ b/lib/Adafruit_CCS811-master/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Adafruit Industries + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/lib/Adafruit_CCS811-master/README.md b/lib/Adafruit_CCS811-master/README.md new file mode 100755 index 000000000..04ff8b631 --- /dev/null +++ b/lib/Adafruit_CCS811-master/README.md @@ -0,0 +1,13 @@ +# Adafruit CCS811 Library [![Build Status](https://travis-ci.org/adafruit/Adafruit_CCS811.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_CCS811) + + + +This is a library for the Adafruit CCS811 gas sensor breakout board: + * https://www.adafruit.com/product/3566 + +Check out the links above for our tutorials and wiring diagrams. This chip uses I2C to communicate + +Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! + +Written by Dean Miller for Adafruit Industries. +MIT license, all text above must be included in any redistribution diff --git a/lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino b/lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino new file mode 100755 index 000000000..a67d0f1c4 --- /dev/null +++ b/lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino @@ -0,0 +1,80 @@ +/* This demo shows how to display the CCS811 readings on an Adafruit I2C OLED. + * (We used a Feather + OLED FeatherWing) + */ + +#include +#include +#include + +#include +#include "Adafruit_CCS811.h" + +Adafruit_CCS811 ccs; +Adafruit_SSD1306 display = Adafruit_SSD1306(); + +void setup() { + Serial.begin(115200); + + if(!ccs.begin()){ + Serial.println("Failed to start sensor! Please check your wiring."); + while(1); + } + + // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) + display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32) + + // Show image buffer on the display hardware. + // Since the buffer is intialized with an Adafruit splashscreen + // internally, this will display the splashscreen. + display.display(); + delay(500); + + // Clear the buffer. + display.clearDisplay(); + display.display(); + + //calibrate temperature sensor + while(!ccs.available()); + float temp = ccs.calculateTemperature(); + ccs.setTempOffset(temp - 25.0); + + Serial.println("IO test"); + + // text display tests + display.setTextSize(1); + display.setTextColor(WHITE); +} + + +void loop() { + display.setCursor(0,0); + if(ccs.available()){ + display.clearDisplay(); + float temp = ccs.calculateTemperature(); + if(!ccs.readData()){ + display.print("eCO2: "); + Serial.print("eCO2: "); + float eCO2 = ccs.geteCO2(); + display.print(eCO2); + Serial.print(eCO2); + + display.print(" ppm\nTVOC: "); + Serial.print(" ppm, TVOC: "); + float TVOC = ccs.getTVOC(); + display.print(TVOC); + Serial.print(TVOC); + + Serial.print(" ppb Temp:"); + display.print(" ppb\nTemp: "); + Serial.println(temp); + display.println(temp); + display.display(); + } + else{ + Serial.println("ERROR!"); + while(1); + } + } + delay(500); +} + diff --git a/lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino b/lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino new file mode 100755 index 000000000..d7503d2ea --- /dev/null +++ b/lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino @@ -0,0 +1,56 @@ +/*************************************************************************** + This is a library for the CCS811 air + + This sketch reads the sensor + + Designed specifically to work with the Adafruit CCS811 breakout + ----> http://www.adafruit.com/products/3566 + + These sensors use I2C to communicate. The device's I2C address is 0x5A + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Written by Dean Miller for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ***************************************************************************/ + +#include "Adafruit_CCS811.h" + +Adafruit_CCS811 ccs; + +void setup() { + Serial.begin(9600); + + Serial.println("CCS811 test"); + + if(!ccs.begin()){ + Serial.println("Failed to start sensor! Please check your wiring."); + while(1); + } + + //calibrate temperature sensor + while(!ccs.available()); + float temp = ccs.calculateTemperature(); + ccs.setTempOffset(temp - 25.0); +} + +void loop() { + if(ccs.available()){ + float temp = ccs.calculateTemperature(); + if(!ccs.readData()){ + Serial.print("CO2: "); + Serial.print(ccs.geteCO2()); + Serial.print("ppm, TVOC: "); + Serial.print(ccs.getTVOC()); + Serial.print("ppb Temp:"); + Serial.println(temp); + } + else{ + Serial.println("ERROR!"); + while(1); + } + } + delay(500); +} \ No newline at end of file diff --git a/lib/Adafruit_CCS811-master/library.properties b/lib/Adafruit_CCS811-master/library.properties new file mode 100755 index 000000000..be5d61361 --- /dev/null +++ b/lib/Adafruit_CCS811-master/library.properties @@ -0,0 +1,9 @@ +name=Adafruit CCS811 Library +version=1.0.0 +author=Adafruit +maintainer=Adafruit +sentence=This is a library for the Adafruit CCS811 I2C gas sensor breakout. +paragraph=This is a library for the Adafruit CCS811 I2C gas sensor breakou. +category=Sensors +url=https://github.com/adafruit/Adafruit_CCS811 +architectures=* diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino old mode 100644 new mode 100755 index 7818d8170..211c03c13 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -198,6 +198,11 @@ char log_data[LOGSZ]; // Logging char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer String backlog[MAX_BACKLOG]; // Command backlog +#ifdef USE_CCS811 +uint8_t glob_humidity=0; +sint16_t glob_temperature=-9999; +#endif + /********************************************************************************************/ char* Format(char* output, const char* input, int size) diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h old mode 100644 new mode 100755 index 929d95558..926da7b13 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -58,6 +58,9 @@ void KNX_CB_Action(message_t const &msg, void *arg); * Provide an image with all supported sensors enabled \*********************************************************************************************/ + +#define USE_CCS811 // Add I2C code for CCS811 sensor (+2k2 code) + #ifdef USE_ALL_SENSORS #define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices @@ -71,6 +74,7 @@ void KNX_CB_Action(message_t const &msg, void *arg); #define USE_BMP // Add I2C code for BMP085/BMP180/BMP280/BME280 sensor (+4k code) #define USE_BME680 // Add additional support for BME680 sensor using Bosch BME680 library (+4k code) #define USE_SGP30 // Add I2C code for SGP30 sensor (+1k1 code) +#define USE_CCS811 // Add I2C code for CCS811 sensor (+2k2 code) #define USE_BH1750 // Add I2C code for BH1750 sensor (+0k5 code) #define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0k5 code) #define USE_TSL2561 // Add I2C code for TSL2561 sensor using library Adafruit TSL2561 Arduino (+1k2 code) diff --git a/sonoff/xsns_09_bmp.ino b/sonoff/xsns_09_bmp.ino old mode 100644 new mode 100755 index 2ffe02ebe..d86bb453e --- a/sonoff/xsns_09_bmp.ino +++ b/sonoff/xsns_09_bmp.ino @@ -495,6 +495,12 @@ void BmpShow(boolean json) dtostrfd(bmp_gas_resistance, 2, gas_resistance); #endif // USE_BME680 + +#ifdef USE_CCS811 + glob_humidity=bmp_humidity; + glob_temperature=(bmp_temperature*4); +#endif + if (json) { char json_humidity[40]; snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); diff --git a/sonoff/xsns_14_sht3x.ino b/sonoff/xsns_14_sht3x.ino old mode 100644 new mode 100755 index bef289aa3..8356fa4cb --- a/sonoff/xsns_14_sht3x.ino +++ b/sonoff/xsns_14_sht3x.ino @@ -101,9 +101,18 @@ void Sht3xShow(boolean json) char types[11]; for (byte i = 0; i < sht3x_count; i++) { if (Sht3xRead(t, h, sht3x_sensors[i].address)) { + + #ifdef USE_CCS811 + if (i==0) { + glob_humidity=h; + glob_temperature=(t*4); + } + #endif + dtostrfd(t, Settings.flag2.temperature_resolution, temperature); dtostrfd(h, Settings.flag2.humidity_resolution, humidity); snprintf_P(types, sizeof(types), PSTR("%s-0x%02X"), sht3x_sensors[i].types, sht3x_sensors[i].address); // "SHT3X-0xXX" + if (json) { snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, types, temperature, humidity); #ifdef USE_DOMOTICZ @@ -159,4 +168,4 @@ boolean Xsns14(byte function) } #endif // USE_SHT3X -#endif // USE_I2C \ No newline at end of file +#endif // USE_I2C diff --git a/sonoff/xsns_31_ccs811.ino b/sonoff/xsns_31_ccs811.ino new file mode 100644 index 000000000..e4794a954 --- /dev/null +++ b/sonoff/xsns_31_ccs811.ino @@ -0,0 +1,131 @@ +/* + xsns_31_cc811.ino - CCS811 gas and air quality sensor support for Sonoff-Tasmota + + Copyright (C) 2018 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_CCS811 +/*********************************************************************************************\ + * SGP30 - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2) + * + * Source: Gerhard Mutz and Adafruit + * + * I2C Address: 0x5A assumes ADDR connected to Gnd, Wake also must be grounded +\*********************************************************************************************/ + +#include "Adafruit_CCS811.h" + +Adafruit_CCS811 ccs; +uint8_t CCS811_ready; +uint8_t CCS811_type; +uint16_t eCO2; +uint16_t TVOC; +uint8_t tcnt,ecnt; + +/********************************************************************************************/ +#define EVERYNSECONDS 5 + +void CCS811Update() // Perform every n second +{ + tcnt+=1; + if (tcnt>=EVERYNSECONDS) { + tcnt=0; + CCS811_ready = 0; + if (!CCS811_type) { + sint8_t res=ccs.begin(CCS811_ADDRESS); + if (!res) { + CCS811_type = 1; + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "CCS811", 0x5A); + AddLog(LOG_LEVEL_DEBUG); + } else { + //snprintf_P(log_data, sizeof(log_data), "CCS811 init failed: %d",res); + //AddLog(LOG_LEVEL_DEBUG); + } + } else { + if (ccs.available()) { + if (!ccs.readData()){ + TVOC=ccs.getTVOC(); + eCO2=ccs.geteCO2(); + CCS811_ready = 1; + if (glob_humidity!=0 && glob_temperature!=-9999) { + double gtmp=glob_temperature; + ccs.setEnvironmentalData(glob_humidity,gtmp/4); + } + ecnt=0; + } + } else { + // failed, count up + ecnt+=1; + if (ecnt>6) { + // after 30 seconds, restart + ccs.begin(CCS811_ADDRESS); + } + } + } + } +} + +const char HTTP_SNS_CCS811[] PROGMEM = "%s" + "{s}CCS811 " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}" // {s} = , {m} = , {e} = + "{s}CCS811 " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}"; + +void CCS811Show(boolean json) +{ + if (CCS811_ready) { + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"CCS811\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d}"), mqtt_data,eCO2,TVOC); +#ifdef USE_DOMOTICZ + if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, eCO2); +#endif // USE_DOMOTICZ + } else { +#ifdef USE_WEBSERVER + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CCS811, mqtt_data, eCO2, TVOC); +#endif + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +#define XSNS_29 + +boolean Xsns29(byte function) +{ + boolean result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_EVERY_SECOND: + CCS811Update(); + break; + case FUNC_JSON_APPEND: + CCS811Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_APPEND: + CCS811Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_CCS811 +#endif // USE_I2C From 5493766bdafc3a0f16f95899606f6936c9f147ba Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Mon, 23 Jul 2018 17:17:40 +0200 Subject: [PATCH 43/46] Update xsns_31_ccs811.ino --- sonoff/xsns_31_ccs811.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sonoff/xsns_31_ccs811.ino b/sonoff/xsns_31_ccs811.ino index e4794a954..63610ddce 100644 --- a/sonoff/xsns_31_ccs811.ino +++ b/sonoff/xsns_31_ccs811.ino @@ -91,8 +91,8 @@ void CCS811Show(boolean json) #ifdef USE_DOMOTICZ if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, eCO2); #endif // USE_DOMOTICZ - } else { #ifdef USE_WEBSERVER + } else { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CCS811, mqtt_data, eCO2, TVOC); #endif } @@ -103,9 +103,9 @@ void CCS811Show(boolean json) * Interface \*********************************************************************************************/ -#define XSNS_29 +#define XSNS_31 -boolean Xsns29(byte function) +boolean Xsns31(byte function) { boolean result = false; From 07f70f890f81a94f6bcc8c551d2fba2250ea82e0 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Mon, 23 Jul 2018 17:19:09 +0200 Subject: [PATCH 44/46] Update xsns_31_ccs811.ino --- sonoff/xsns_31_ccs811.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sonoff/xsns_31_ccs811.ino b/sonoff/xsns_31_ccs811.ino index 63610ddce..d955e325d 100644 --- a/sonoff/xsns_31_ccs811.ino +++ b/sonoff/xsns_31_ccs811.ino @@ -1,7 +1,7 @@ /* - xsns_31_cc811.ino - CCS811 gas and air quality sensor support for Sonoff-Tasmota + xsns_31_ccs811.ino - CCS811 gas and air quality sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2018 Gerhard Mutz 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 @@ -22,7 +22,7 @@ /*********************************************************************************************\ * SGP30 - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2) * - * Source: Gerhard Mutz and Adafruit + * Source: Adafruit * * I2C Address: 0x5A assumes ADDR connected to Gnd, Wake also must be grounded \*********************************************************************************************/ From b7b87f55240c23fb9548c85118b51fdddb4efe35 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Mon, 23 Jul 2018 17:25:50 +0200 Subject: [PATCH 45/46] Add CCS811 library version Add CCS811 library version --- .../.travis.yml | 0 .../Adafruit_CCS811.cpp | 0 .../Adafruit_CCS811.h | 0 lib/{Adafruit_CCS811-master => Adafruit_CCS811-1.0.0.14}/LICENSE | 0 .../README.md | 0 .../examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino | 0 .../examples/CCS811_test/CCS811_test.ino | 0 .../library.properties | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename lib/{Adafruit_CCS811-master => Adafruit_CCS811-1.0.0.14}/.travis.yml (100%) mode change 100755 => 100644 rename lib/{Adafruit_CCS811-master => Adafruit_CCS811-1.0.0.14}/Adafruit_CCS811.cpp (100%) mode change 100755 => 100644 rename lib/{Adafruit_CCS811-master => Adafruit_CCS811-1.0.0.14}/Adafruit_CCS811.h (100%) mode change 100755 => 100644 rename lib/{Adafruit_CCS811-master => Adafruit_CCS811-1.0.0.14}/LICENSE (100%) mode change 100755 => 100644 rename lib/{Adafruit_CCS811-master => Adafruit_CCS811-1.0.0.14}/README.md (100%) mode change 100755 => 100644 rename lib/{Adafruit_CCS811-master => Adafruit_CCS811-1.0.0.14}/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino (100%) mode change 100755 => 100644 rename lib/{Adafruit_CCS811-master => Adafruit_CCS811-1.0.0.14}/examples/CCS811_test/CCS811_test.ino (100%) mode change 100755 => 100644 rename lib/{Adafruit_CCS811-master => Adafruit_CCS811-1.0.0.14}/library.properties (100%) mode change 100755 => 100644 diff --git a/lib/Adafruit_CCS811-master/.travis.yml b/lib/Adafruit_CCS811-1.0.0.14/.travis.yml old mode 100755 new mode 100644 similarity index 100% rename from lib/Adafruit_CCS811-master/.travis.yml rename to lib/Adafruit_CCS811-1.0.0.14/.travis.yml diff --git a/lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp b/lib/Adafruit_CCS811-1.0.0.14/Adafruit_CCS811.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp rename to lib/Adafruit_CCS811-1.0.0.14/Adafruit_CCS811.cpp diff --git a/lib/Adafruit_CCS811-master/Adafruit_CCS811.h b/lib/Adafruit_CCS811-1.0.0.14/Adafruit_CCS811.h old mode 100755 new mode 100644 similarity index 100% rename from lib/Adafruit_CCS811-master/Adafruit_CCS811.h rename to lib/Adafruit_CCS811-1.0.0.14/Adafruit_CCS811.h diff --git a/lib/Adafruit_CCS811-master/LICENSE b/lib/Adafruit_CCS811-1.0.0.14/LICENSE old mode 100755 new mode 100644 similarity index 100% rename from lib/Adafruit_CCS811-master/LICENSE rename to lib/Adafruit_CCS811-1.0.0.14/LICENSE diff --git a/lib/Adafruit_CCS811-master/README.md b/lib/Adafruit_CCS811-1.0.0.14/README.md old mode 100755 new mode 100644 similarity index 100% rename from lib/Adafruit_CCS811-master/README.md rename to lib/Adafruit_CCS811-1.0.0.14/README.md diff --git a/lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino b/lib/Adafruit_CCS811-1.0.0.14/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino rename to lib/Adafruit_CCS811-1.0.0.14/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino diff --git a/lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino b/lib/Adafruit_CCS811-1.0.0.14/examples/CCS811_test/CCS811_test.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino rename to lib/Adafruit_CCS811-1.0.0.14/examples/CCS811_test/CCS811_test.ino diff --git a/lib/Adafruit_CCS811-master/library.properties b/lib/Adafruit_CCS811-1.0.0.14/library.properties old mode 100755 new mode 100644 similarity index 100% rename from lib/Adafruit_CCS811-master/library.properties rename to lib/Adafruit_CCS811-1.0.0.14/library.properties From cdae4f3f467be1cd9f5e05a4d1e154f9b19cf0ad Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Mon, 23 Jul 2018 17:42:12 +0200 Subject: [PATCH 46/46] Add support for CCS811 Add support for CCS811 sensor (#3309) --- sonoff/_changelog.ino | 1 + sonoff/sonoff.ino | 8 +++----- sonoff/sonoff_post.h | 5 +---- sonoff/user_config.h | 1 + sonoff/xsns_09_bmp.ino | 9 +++------ sonoff/xsns_14_sht3x.ino | 8 +++----- sonoff/xsns_31_ccs811.ino | 27 ++++++++++++++------------- 7 files changed, 26 insertions(+), 33 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 5c5d7ba6a..7e52e3404 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,5 @@ /* 6.1.1c + * Add support for CCS811 sensor (#3309) * Add command Timers 0/1 to globally disable or enable armed timers (#3270) * * 6.1.1b diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 211c03c13..af68a4879 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -188,6 +188,9 @@ uint8_t ntp_force_sync = 0; // Force NTP sync StateBitfield global_state; RulesBitfield rules_flag; +uint8_t glob_humidity = 0; +sint16_t glob_temperature = -9999; + char my_version[33]; // Composed version string char my_hostname[33]; // Composed Wifi hostname char mqtt_client[33]; // Composed MQTT Clientname @@ -198,11 +201,6 @@ char log_data[LOGSZ]; // Logging char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer String backlog[MAX_BACKLOG]; // Command backlog -#ifdef USE_CCS811 -uint8_t glob_humidity=0; -sint16_t glob_temperature=-9999; -#endif - /********************************************************************************************/ char* Format(char* output, const char* input, int size) diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index 926da7b13..faff45c05 100755 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -58,9 +58,6 @@ void KNX_CB_Action(message_t const &msg, void *arg); * Provide an image with all supported sensors enabled \*********************************************************************************************/ - -#define USE_CCS811 // Add I2C code for CCS811 sensor (+2k2 code) - #ifdef USE_ALL_SENSORS #define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices @@ -74,7 +71,6 @@ void KNX_CB_Action(message_t const &msg, void *arg); #define USE_BMP // Add I2C code for BMP085/BMP180/BMP280/BME280 sensor (+4k code) #define USE_BME680 // Add additional support for BME680 sensor using Bosch BME680 library (+4k code) #define USE_SGP30 // Add I2C code for SGP30 sensor (+1k1 code) -#define USE_CCS811 // Add I2C code for CCS811 sensor (+2k2 code) #define USE_BH1750 // Add I2C code for BH1750 sensor (+0k5 code) #define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0k5 code) #define USE_TSL2561 // Add I2C code for TSL2561 sensor using library Adafruit TSL2561 Arduino (+1k2 code) @@ -84,6 +80,7 @@ void KNX_CB_Action(message_t const &msg, void *arg); #define USE_INA219 // Add I2C code for INA219 Low voltage and current sensor (+1k code) #define USE_MGS // Add I2C code for Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code) //#define USE_APDS9960 // Add I2C code for APDS9960 Proximity Sensor. Disables SHT and VEML6070 (+4k7 code) +//#define USE_CCS811 // Add I2C code for CCS811 sensor (+2k2 code) #define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code) #define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code) #ifndef CO2_LOW diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 173ed8684..dcbb7c9fe 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -290,6 +290,7 @@ // #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_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) #endif // USE_I2C // -- SPI sensors --------------------------------- diff --git a/sonoff/xsns_09_bmp.ino b/sonoff/xsns_09_bmp.ino index d86bb453e..8f46219c8 100755 --- a/sonoff/xsns_09_bmp.ino +++ b/sonoff/xsns_09_bmp.ino @@ -459,6 +459,9 @@ void BmpRead() #endif // USE_BME680 } if (bmp_temperature != 0.0) { bmp_temperature = ConvertTemp(bmp_temperature); } + + glob_humidity = bmp_humidity; + glob_temperature = bmp_temperature; } void BmpEverySecond() @@ -495,12 +498,6 @@ void BmpShow(boolean json) dtostrfd(bmp_gas_resistance, 2, gas_resistance); #endif // USE_BME680 - -#ifdef USE_CCS811 - glob_humidity=bmp_humidity; - glob_temperature=(bmp_temperature*4); -#endif - if (json) { char json_humidity[40]; snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); diff --git a/sonoff/xsns_14_sht3x.ino b/sonoff/xsns_14_sht3x.ino index 8356fa4cb..c754bbab0 100755 --- a/sonoff/xsns_14_sht3x.ino +++ b/sonoff/xsns_14_sht3x.ino @@ -102,12 +102,10 @@ void Sht3xShow(boolean json) for (byte i = 0; i < sht3x_count; i++) { if (Sht3xRead(t, h, sht3x_sensors[i].address)) { - #ifdef USE_CCS811 - if (i==0) { - glob_humidity=h; - glob_temperature=(t*4); + if (0 == i) { + glob_humidity = h; + glob_temperature = t; } - #endif dtostrfd(t, Settings.flag2.temperature_resolution, temperature); dtostrfd(h, Settings.flag2.humidity_resolution, humidity); diff --git a/sonoff/xsns_31_ccs811.ino b/sonoff/xsns_31_ccs811.ino index d955e325d..8fb43d62a 100644 --- a/sonoff/xsns_31_ccs811.ino +++ b/sonoff/xsns_31_ccs811.ino @@ -34,19 +34,20 @@ uint8_t CCS811_ready; uint8_t CCS811_type; uint16_t eCO2; uint16_t TVOC; -uint8_t tcnt,ecnt; +uint8_t tcnt = 0; +uint8_t ecnt = 0; /********************************************************************************************/ #define EVERYNSECONDS 5 void CCS811Update() // Perform every n second { - tcnt+=1; - if (tcnt>=EVERYNSECONDS) { - tcnt=0; + tcnt++; + if (tcnt >= EVERYNSECONDS) { + tcnt = 0; CCS811_ready = 0; if (!CCS811_type) { - sint8_t res=ccs.begin(CCS811_ADDRESS); + sint8_t res = ccs.begin(CCS811_ADDRESS); if (!res) { CCS811_type = 1; snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "CCS811", 0x5A); @@ -58,19 +59,19 @@ void CCS811Update() // Perform every n second } else { if (ccs.available()) { if (!ccs.readData()){ - TVOC=ccs.getTVOC(); - eCO2=ccs.geteCO2(); + TVOC = ccs.getTVOC(); + eCO2 = ccs.geteCO2(); CCS811_ready = 1; - if (glob_humidity!=0 && glob_temperature!=-9999) { - double gtmp=glob_temperature; - ccs.setEnvironmentalData(glob_humidity,gtmp/4); + if ((glob_humidity != 0) && (glob_temperature != -9999)) { + double gtmp = glob_temperature * 4; + ccs.setEnvironmentalData(glob_humidity, gtmp / 4); } - ecnt=0; + ecnt = 0; } } else { // failed, count up - ecnt+=1; - if (ecnt>6) { + ecnt++; + if (ecnt > 6) { // after 30 seconds, restart ccs.begin(CCS811_ADDRESS); }