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 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/lib/Adafruit_CCS811-1.0.0.14/.travis.yml b/lib/Adafruit_CCS811-1.0.0.14/.travis.yml new file mode 100644 index 000000000..95efcfaef --- /dev/null +++ b/lib/Adafruit_CCS811-1.0.0.14/.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-1.0.0.14/Adafruit_CCS811.cpp b/lib/Adafruit_CCS811-1.0.0.14/Adafruit_CCS811.cpp new file mode 100644 index 000000000..c69cd41f9 --- /dev/null +++ b/lib/Adafruit_CCS811-1.0.0.14/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-1.0.0.14/LICENSE b/lib/Adafruit_CCS811-1.0.0.14/LICENSE new file mode 100644 index 000000000..860e3e285 --- /dev/null +++ b/lib/Adafruit_CCS811-1.0.0.14/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-1.0.0.14/README.md b/lib/Adafruit_CCS811-1.0.0.14/README.md new file mode 100644 index 000000000..04ff8b631 --- /dev/null +++ b/lib/Adafruit_CCS811-1.0.0.14/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-1.0.0.14/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino b/lib/Adafruit_CCS811-1.0.0.14/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino new file mode 100644 index 000000000..a67d0f1c4 --- /dev/null +++ b/lib/Adafruit_CCS811-1.0.0.14/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-1.0.0.14/examples/CCS811_test/CCS811_test.ino b/lib/Adafruit_CCS811-1.0.0.14/examples/CCS811_test/CCS811_test.ino new file mode 100644 index 000000000..d7503d2ea --- /dev/null +++ b/lib/Adafruit_CCS811-1.0.0.14/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-1.0.0.14/library.properties b/lib/Adafruit_CCS811-1.0.0.14/library.properties new file mode 100644 index 000000000..be5d61361 --- /dev/null +++ b/lib/Adafruit_CCS811-1.0.0.14/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/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 diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index bd6c1dd18..7e52e3404 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,12 @@ -/* 6.1.1b +/* 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 + * 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) * 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/language/bg-BG.h b/sonoff/language/bg-BG.h index 6d82a843c..5461883e4 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" @@ -379,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 cb93ad553..3c89518e9 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" @@ -379,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 4c0fde470..42730e9ec 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" @@ -379,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 702381ab1..1cc112b03 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" @@ -379,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 8858eea2f..dee89bd39 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -227,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" @@ -379,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 1c4b4924a..1cae4508a 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" @@ -379,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 ce1485513..c6653bd65 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.1.1b \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -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" @@ -241,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" @@ -321,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" @@ -379,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" @@ -405,7 +407,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" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 14fb2a08b..abd397abf 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ó" @@ -379,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 6f1c4db0f..763f2f912 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" @@ -379,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 cf1c2b3b0..d7ba586fa 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" @@ -379,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 e250e4c4d..6a1397218 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" @@ -379,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 a32a7b5c3..2d3f89b1f 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" @@ -379,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 393a74a87..38ba38911 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" @@ -379,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 79df5b2d4..a0284adcd 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" @@ -379,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 d925d13fb..dd5dffb23 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" @@ -379,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 9e5149125..0228e26e5 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设置" @@ -379,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 6d4154cdf..18becc2aa 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設置" @@ -379,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/settings.h b/sonoff/settings.h index 4a3dc415c..e527d74b7 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; @@ -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_ 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 old mode 100644 new mode 100755 index 3bb37c5e6..af68a4879 --- 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) @@ -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 diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h old mode 100644 new mode 100755 index 929d95558..faff45c05 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -80,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/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 diff --git a/sonoff/user_config.h b/sonoff/user_config.h index a0fdcfec2..dcbb7c9fe 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -237,7 +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 // 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) @@ -270,23 +271,26 @@ // -- 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_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_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/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); diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index 1631b5d4d..f74a8d28e 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++) { @@ -633,7 +637,9 @@ const char HTTP_TIMER_STYLE[] PROGMEM = ""; const char HTTP_FORM_TIMER[] PROGMEM = "
 " D_TIMER_PARAMETERS " 
" - "" + "
" D_TIMER_ENABLE "


" + "



" "

" @@ -679,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); @@ -702,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 @@ -713,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); } diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 1218b9854..3296a9560 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]); @@ -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]); @@ -609,25 +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* str, const char *delim, int index) { - char *act, *sub, *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 = LTrim(sub); - sub = RTrim(sub); - return sub; -} - - /*********************************************************************************************\ * Interface \*********************************************************************************************/ diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 2162fbcaa..710b63f66 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -196,9 +196,15 @@ 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" +#define D_CMND_KNX_PA "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_GA "|" D_CMND_KNX_CB ; byte KNX_GA_Search( byte param, byte start = 0 ) { @@ -517,14 +523,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 +567,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; @@ -697,6 +722,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 = @@ -1001,6 +1027,7 @@ void KNX_Save_Settings() } } +#endif // USE_KNX_WEB_MENU #endif // USE_WEBSERVER @@ -1010,14 +1037,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 ) { @@ -1035,12 +1060,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 ) { @@ -1062,13 +1089,173 @@ 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 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 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 - snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s\"}"), - command, index, XdrvMailbox.data ); - return true; } diff --git a/sonoff/xsns_09_bmp.ino b/sonoff/xsns_09_bmp.ino old mode 100644 new mode 100755 index 2ffe02ebe..8f46219c8 --- 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() diff --git a/sonoff/xsns_14_sht3x.ino b/sonoff/xsns_14_sht3x.ino old mode 100644 new mode 100755 index bef289aa3..c754bbab0 --- a/sonoff/xsns_14_sht3x.ino +++ b/sonoff/xsns_14_sht3x.ino @@ -101,9 +101,16 @@ void Sht3xShow(boolean json) char types[11]; for (byte i = 0; i < sht3x_count; i++) { if (Sht3xRead(t, h, sht3x_sensors[i].address)) { + + if (0 == i) { + glob_humidity = h; + glob_temperature = t; + } + 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 +166,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_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: diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino new file mode 100644 index 000000000..b6900d6ee --- /dev/null +++ b/sonoff/xsns_29_mcp230xx.ino @@ -0,0 +1,336 @@ +/* + xsns_29_mcp230xx.ino - Support for I2C MCP23008/MCP23017 GPIO Expander (INPUT ONLY!) + + Copyright (C) 2018 Andre Thomas and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_MCP230xx + +/*********************************************************************************************\ + MCP23008/17 - I2C GPIO EXPANDER + + Docs at https://www.microchip.com/wwwproducts/en/MCP23008 + https://www.microchip.com/wwwproducts/en/MCP23017 + + I2C Address: 0x20 - 0x27 + \*********************************************************************************************/ + +#define XSNS_29 29 + +#define MCP230xx_ADDRESS1 0x20 +#define MCP230xx_ADDRESS2 0x21 +#define MCP230xx_ADDRESS3 0x22 +#define MCP230xx_ADDRESS4 0x23 +#define MCP230xx_ADDRESS5 0x24 +#define MCP230xx_ADDRESS6 0x25 +#define MCP230xx_ADDRESS7 0x26 +#define MCP230xx_ADDRESS8 0x27 + +/* + Default register locations for MCP23008 - They change for MCP23017 in default bank mode +*/ + +uint8_t MCP230xx_IODIR = 0x00; +uint8_t MCP230xx_GPINTEN = 0x02; +uint8_t MCP230xx_IOCON = 0x05; +uint8_t MCP230xx_GPPU = 0x06; +uint8_t MCP230xx_INTF = 0x07; +uint8_t MCP230xx_INTCAP = 0x08; +uint8_t MCP230xx_GPIO = 0x09; + +uint8_t mcp230xx_type = 0; +uint8_t mcp230xx_address; +uint8_t mcp230xx_addresses[] = { MCP230xx_ADDRESS1, MCP230xx_ADDRESS2, MCP230xx_ADDRESS3, MCP230xx_ADDRESS4, MCP230xx_ADDRESS5, MCP230xx_ADDRESS6, MCP230xx_ADDRESS7, MCP230xx_ADDRESS8 }; +uint8_t mcp230xx_pincount = 0; +uint8_t mcp230xx_int_en = 0; + +const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29\":{\"D\":%i,\"MODE\":%i,\"PULL-UP\":%i}}"; + +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; + 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: + reg_iodir |= (1 << idx); + break; + case 2 ... 4: + reg_iodir |= (1 << idx); + reg_gpinten |= (1 << idx); + int_en=1; + break; + default: + break; + } + if (Settings.mcp230xx_config[idx].pullup) { + reg_gppu |= (1 << idx); + } + } + 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++) { + 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); + int_en=1; + break; + default: + break; + } + 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); + I2cWrite8(mcp230xx_address, MCP230xx_IODIR + 1, reg_iodir); + } + mcp230xx_int_en=int_en; +} + +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); + 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); + mcp230xx_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].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); + } + } + } + } + } + } + } + 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].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()); + 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); + } + } + } +} + +bool MCP230xx_Command(void) { + boolean serviced = true; + 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) { + pinmode = data.substring(_a+1, _b).toInt(); + pullup = data.substring(_b+1, XdrvMailbox.data_len).toInt(); + 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 { + serviced = false; + } + } else { + serviced = false; + } + } else { + serviced = false; + } + return serviced; +} + +/*********************************************************************************************\ + Interface + \*********************************************************************************************/ + +boolean Xsns29(byte function) +{ + boolean result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_EVERY_SECOND: + MCP230xx_Detect(); + break; + case FUNC_EVERY_50_MSECOND: + 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); + break; + case FUNC_COMMAND: + if (XSNS_29 == XdrvMailbox.index) { + result = MCP230xx_Command(); + } + break; + default: + break; + } + } + return result; +} + +#endif // USE_MCP230xx +#endif // USE_I2C diff --git a/sonoff/xsns_30_mpr121.ino b/sonoff/xsns_30_mpr121.ino new file mode 100644 index 000000000..cc4fba3ab --- /dev/null +++ b/sonoff/xsns_30_mpr121.ino @@ -0,0 +1,448 @@ +/** + * + * @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 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 */ + 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 diff --git a/sonoff/xsns_31_ccs811.ino b/sonoff/xsns_31_ccs811.ino new file mode 100644 index 000000000..8fb43d62a --- /dev/null +++ b/sonoff/xsns_31_ccs811.ino @@ -0,0 +1,132 @@ +/* + xsns_31_ccs811.ino - CCS811 gas and air quality sensor support for Sonoff-Tasmota + + 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 + 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: 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 = 0; +uint8_t ecnt = 0; + +/********************************************************************************************/ +#define EVERYNSECONDS 5 + +void CCS811Update() // Perform every n second +{ + tcnt++; + 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 * 4; + ccs.setEnvironmentalData(glob_humidity, gtmp / 4); + } + ecnt = 0; + } + } else { + // failed, count up + ecnt++; + 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 +#ifdef USE_WEBSERVER + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CCS811, mqtt_data, eCO2, TVOC); +#endif + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +#define XSNS_31 + +boolean Xsns31(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 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: