diff --git a/Bootload/AfterburnerV3.1.5.bin b/Bootload/AfterburnerV3.1.5.bin new file mode 100644 index 0000000..264c9a9 Binary files /dev/null and b/Bootload/AfterburnerV3.1.5.bin differ diff --git a/Bootload/COM.bat b/Bootload/COM.bat index 90f0e04..68bfca9 100644 --- a/Bootload/COM.bat +++ b/Bootload/COM.bat @@ -1,5 +1,5 @@ REM Firmware -esptool.exe --chip esp32 --port COM16 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 boot_app0.bin 0x1000 bootloader_qio_80m.bin 0x10000 AfterburnerV3.1.4.bin 0x8000 Afterburner.partitions.bin +esptool.exe --chip esp32 --port COM16 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 boot_app0.bin 0x1000 bootloader_qio_80m.bin 0x10000 AfterburnerV3.1.5.bin 0x8000 Afterburner.partitions.bin REM SPIFFS esptool.exe --chip esp32 --port COM16 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_size detect 0x3d0000 spiffs.bin diff --git a/Documentation/ScreenFlowV3.dia b/Documentation/ScreenFlowV3.dia index 7c99112..e7d3b52 100644 Binary files a/Documentation/ScreenFlowV3.dia and b/Documentation/ScreenFlowV3.dia differ diff --git a/Documentation/ScreenFlowV3.png b/Documentation/ScreenFlowV3.png index 32d9824..0936acd 100644 Binary files a/Documentation/ScreenFlowV3.png and b/Documentation/ScreenFlowV3.png differ diff --git a/lib/Adafruit_BME280_Library/.github/ISSUE_TEMPLATE.md b/lib/Adafruit_BME280_Library/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..f0e2614 --- /dev/null +++ b/lib/Adafruit_BME280_Library/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,46 @@ +Thank you for opening an issue on an Adafruit Arduino library repository. To +improve the speed of resolution please review the following guidelines and +common troubleshooting steps below before creating the issue: + +- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use + the forums at http://forums.adafruit.com to ask questions and troubleshoot why + something isn't working as expected. In many cases the problem is a common issue + that you will more quickly receive help from the forum community. GitHub issues + are meant for known defects in the code. If you don't know if there is a defect + in the code then start with troubleshooting on the forum first. + +- **If following a tutorial or guide be sure you didn't miss a step.** Carefully + check all of the steps and commands to run have been followed. Consult the + forum if you're unsure or have questions about steps in a guide/tutorial. + +- **For Arduino projects check these very common issues to ensure they don't apply**: + + - For uploading sketches or communicating with the board make sure you're using + a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes + very hard to tell the difference between a data and charge cable! Try using the + cable with other devices or swapping to another cable to confirm it is not + the problem. + + - **Be sure you are supplying adequate power to the board.** Check the specs of + your board and plug in an external power supply. In many cases just + plugging a board into your computer is not enough to power it and other + peripherals. + + - **Double check all soldering joints and connections.** Flakey connections + cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. + + - **Ensure you are using an official Arduino or Adafruit board.** We can't + guarantee a clone board will have the same functionality and work as expected + with this code and don't support them. + +If you're sure this issue is a defect in the code and checked the steps above +please fill in the following fields to provide enough troubleshooting information. +You may delete the guideline and text above to just leave the following details: + +- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** + +- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO + VERSION HERE** + +- List the steps to reproduce the problem below (if possible attach a sketch or + copy the sketch code in too): **LIST REPRO STEPS BELOW** diff --git a/lib/Adafruit_BME280_Library/.github/PULL_REQUEST_TEMPLATE.md b/lib/Adafruit_BME280_Library/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7b641eb --- /dev/null +++ b/lib/Adafruit_BME280_Library/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +Thank you for creating a pull request to contribute to Adafruit's GitHub code! +Before you open the request please review the following guidelines and tips to +help it be more easily integrated: + +- **Describe the scope of your change--i.e. what the change does and what parts + of the code were modified.** This will help us understand any risks of integrating + the code. + +- **Describe any known limitations with your change.** For example if the change + doesn't apply to a supported platform of the library please mention it. + +- **Please run any tests or examples that can exercise your modified code.** We + strive to not break users of the code and running tests/examples helps with this + process. + +Thank you again for contributing! We will try to test and integrate the change +as soon as we can, but be aware we have many GitHub repositories to manage and +can't immediately respond to every request. There is no need to bump or check in +on a pull request (it will clutter the discussion of the request). + +Also don't be worried if the request is closed or not integrated--sometimes the +priorities of Adafruit's GitHub code (education, ease of use) might not match the +priorities of the pull request. Don't fret, the open source community thrives on +forks and GitHub makes it easy to keep your changes in a forked repo. + +After reviewing the guidelines above you can delete this text from the pull request. diff --git a/lib/Adafruit_BME280_Library/.gitignore b/lib/Adafruit_BME280_Library/.gitignore new file mode 100644 index 0000000..542d266 --- /dev/null +++ b/lib/Adafruit_BME280_Library/.gitignore @@ -0,0 +1,8 @@ +# osx +.DS_Store + +# doxygen +Doxyfile* +doxygen_sqlite3.db +html +*.tmp diff --git a/lib/Adafruit_BME280_Library/.travis.yml b/lib/Adafruit_BME280_Library/.travis.yml new file mode 100644 index 0000000..bdf8cd1 --- /dev/null +++ b/lib/Adafruit_BME280_Library/.travis.yml @@ -0,0 +1,26 @@ +language: c +sudo: false +cache: + directories: + - ~/arduino_ide + - ~/.arduino15/packages/ +git: + depth: false + quiet: true +env: + global: + - PRETTYNAME="Adafruit BME280 Arduino Library" + +before_install: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) + +install: + - arduino --install-library "Adafruit Unified Sensor" + +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) diff --git a/lib/Adafruit_BME280_Library/Adafruit_BME280.cpp b/lib/Adafruit_BME280_Library/Adafruit_BME280.cpp new file mode 100644 index 0000000..87ce92a --- /dev/null +++ b/lib/Adafruit_BME280_Library/Adafruit_BME280.cpp @@ -0,0 +1,576 @@ +/*! + * @file Adafruit_BME280.cpp + * + * @mainpage Adafruit BME280 humidity, temperature & pressure sensor + * + * @section intro_sec Introduction + * + * Driver for the BME280 humidity, temperature & pressure sensor + * + * These sensors use I2C or SPI to communicate, 2 or 4 pins are required + * to interface. + * + * Designed specifically to work with the Adafruit BME280 Breakout + * ----> http://www.adafruit.com/products/2652 + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section author Author + * + * Written by Kevin "KTOWN" Townsend for Adafruit Industries. + * + * @section license License + * + * BSD license, all text here must be included in any redistribution. + * See the LICENSE file for details. + * + */ + +#include "Adafruit_BME280.h" +#include "Arduino.h" +#include +#include + +/*! + * @brief class constructor + */ +Adafruit_BME280::Adafruit_BME280() : _cs(-1), _mosi(-1), _miso(-1), _sck(-1) {} + +/*! + * @brief class constructor if using hardware SPI + * @param cspin the chip select pin to use + * @param *theSPI + * optional SPI object + */ +Adafruit_BME280::Adafruit_BME280(int8_t cspin, SPIClass *theSPI) { + _cs = cspin; + _mosi = _miso = _sck = -1; + _spi = theSPI; +} + +/*! + * @brief class constructor if using software SPI + * @param cspin the chip select pin to use + * @param mosipin the MOSI pin to use + * @param misopin the MISO pin to use + * @param sckpin the SCK pin to use + */ +Adafruit_BME280::Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin, + int8_t sckpin) + : _cs(cspin), _mosi(mosipin), _miso(misopin), _sck(sckpin) {} + +/*! + * @brief Initialise sensor with given parameters / settings + * @param theWire the I2C object to use + * @returns true on success, false otherwise + */ +bool Adafruit_BME280::begin(TwoWire *theWire) { + _wire = theWire; + _i2caddr = BME280_ADDRESS; + return init(); +} + +/*! + * @brief Initialise sensor with given parameters / settings + * @param addr the I2C address the device can be found on + * @returns true on success, false otherwise + */ +bool Adafruit_BME280::begin(uint8_t addr) { + _i2caddr = addr; + _wire = &Wire; + return init(); +} + +/*! + * @brief Initialise sensor with given parameters / settings + * @param addr the I2C address the device can be found on + * @param theWire the I2C object to use + * @returns true on success, false otherwise + */ +bool Adafruit_BME280::begin(uint8_t addr, TwoWire *theWire) { + _i2caddr = addr; + _wire = theWire; + return init(); +} + +/*! + * @brief Initialise sensor with given parameters / settings + * @returns true on success, false otherwise + */ +bool Adafruit_BME280::begin(void) { + bool status = false; + _i2caddr = BME280_ADDRESS; + _wire = &Wire; + status = init(); + if (!status) { + _i2caddr = BME280_ADDRESS_ALTERNATE; + status = init(); + } + return status; +} + +/*! + * @brief Initialise sensor with given parameters / settings + * @returns true on success, false otherwise + */ +bool Adafruit_BME280::init() { + // init I2C or SPI sensor interface + if (_cs == -1) { + // I2C + _wire->begin(); + } else { + digitalWrite(_cs, HIGH); + pinMode(_cs, OUTPUT); + if (_sck == -1) { + // hardware SPI + _spi->begin(); + } else { + // software SPI + pinMode(_sck, OUTPUT); + pinMode(_mosi, OUTPUT); + pinMode(_miso, INPUT); + } + } + + // check if sensor, i.e. the chip ID is correct + _sensorID = read8(BME280_REGISTER_CHIPID); + if (_sensorID != 0x60) + return false; + + // reset the device using soft-reset + // this makes sure the IIR is off, etc. + write8(BME280_REGISTER_SOFTRESET, 0xB6); + + // wait for chip to wake up. + delay(300); + + // if chip is still reading calibration, delay + while (isReadingCalibration()) + delay(100); + + readCoefficients(); // read trimming parameters, see DS 4.2.2 + + setSampling(); // use defaults + + delay(100); + + return true; +} + +/*! + * @brief setup sensor with given parameters / settings + * + * This is simply a overload to the normal begin()-function, so SPI users + * don't get confused about the library requiring an address. + * @param mode the power mode to use for the sensor + * @param tempSampling the temp samping rate to use + * @param pressSampling the pressure sampling rate to use + * @param humSampling the humidity sampling rate to use + * @param filter the filter mode to use + * @param duration the standby duration to use + */ +void Adafruit_BME280::setSampling(sensor_mode mode, + sensor_sampling tempSampling, + sensor_sampling pressSampling, + sensor_sampling humSampling, + sensor_filter filter, + standby_duration duration) { + _measReg.mode = mode; + _measReg.osrs_t = tempSampling; + _measReg.osrs_p = pressSampling; + + _humReg.osrs_h = humSampling; + _configReg.filter = filter; + _configReg.t_sb = duration; + + // making sure sensor is in sleep mode before setting configuration + // as it otherwise may be ignored + write8(BME280_REGISTER_CONTROL, MODE_SLEEP); + + + // you must make sure to also set REGISTER_CONTROL after setting the + // CONTROLHUMID register, otherwise the values won't be applied (see + // DS 5.4.3) + write8(BME280_REGISTER_CONTROLHUMID, _humReg.get()); + write8(BME280_REGISTER_CONFIG, _configReg.get()); + write8(BME280_REGISTER_CONTROL, _measReg.get()); +} + +/*! + * @brief Encapsulate hardware and software SPI transfer into one + * function + * @param x the data byte to transfer + * @returns the data byte read from the device + */ +uint8_t Adafruit_BME280::spixfer(uint8_t x) { + // hardware SPI + if (_sck == -1) + return _spi->transfer(x); + + // software SPI + uint8_t reply = 0; + for (int i = 7; i >= 0; i--) { + reply <<= 1; + digitalWrite(_sck, LOW); + digitalWrite(_mosi, x & (1 << i)); + digitalWrite(_sck, HIGH); + if (digitalRead(_miso)) + reply |= 1; + } + return reply; +} + +/*! + * @brief Writes an 8 bit value over I2C or SPI + * @param reg the register address to write to + * @param value the value to write to the register + */ +void Adafruit_BME280::write8(byte reg, byte value) { + if (_cs == -1) { + _wire->beginTransmission((uint8_t)_i2caddr); + _wire->write((uint8_t)reg); + _wire->write((uint8_t)value); + _wire->endTransmission(); + } else { + if (_sck == -1) + _spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg & ~0x80); // write, bit 7 low + spixfer(value); + digitalWrite(_cs, HIGH); + if (_sck == -1) + _spi->endTransaction(); // release the SPI bus + } +} + +/*! + * @brief Reads an 8 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the data byte read from the device + */ +uint8_t Adafruit_BME280::read8(byte reg) { + uint8_t value; + + if (_cs == -1) { + _wire->beginTransmission((uint8_t)_i2caddr); + _wire->write((uint8_t)reg); + _wire->endTransmission(); + _wire->requestFrom((uint8_t)_i2caddr, (byte)1); + value = _wire->read(); + } else { + if (_sck == -1) + _spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high + value = spixfer(0); + digitalWrite(_cs, HIGH); + if (_sck == -1) + _spi->endTransaction(); // release the SPI bus + } + return value; +} + +/*! + * @brief Reads a 16 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +uint16_t Adafruit_BME280::read16(byte reg) { + uint16_t value; + + if (_cs == -1) { + _wire->beginTransmission((uint8_t)_i2caddr); + _wire->write((uint8_t)reg); + _wire->endTransmission(); + _wire->requestFrom((uint8_t)_i2caddr, (byte)2); + value = (_wire->read() << 8) | _wire->read(); + } else { + if (_sck == -1) + _spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high + value = (spixfer(0) << 8) | spixfer(0); + digitalWrite(_cs, HIGH); + if (_sck == -1) + _spi->endTransaction(); // release the SPI bus + } + + return value; +} + +/*! + * @brief Reads a signed 16 bit little endian value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +uint16_t Adafruit_BME280::read16_LE(byte reg) { + uint16_t temp = read16(reg); + return (temp >> 8) | (temp << 8); +} + +/*! + * @brief Reads a signed 16 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +int16_t Adafruit_BME280::readS16(byte reg) { return (int16_t)read16(reg); } + +/*! + * @brief Reads a signed little endian 16 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +int16_t Adafruit_BME280::readS16_LE(byte reg) { + return (int16_t)read16_LE(reg); +} + +/*! + * @brief Reads a 24 bit value over I2C + * @param reg the register address to read from + * @returns the 24 bit data value read from the device + */ +uint32_t Adafruit_BME280::read24(byte reg) { + uint32_t value; + + if (_cs == -1) { + _wire->beginTransmission((uint8_t)_i2caddr); + _wire->write((uint8_t)reg); + _wire->endTransmission(); + _wire->requestFrom((uint8_t)_i2caddr, (byte)3); + + value = _wire->read(); + value <<= 8; + value |= _wire->read(); + value <<= 8; + value |= _wire->read(); + } else { + if (_sck == -1) + _spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high + + value = spixfer(0); + value <<= 8; + value |= spixfer(0); + value <<= 8; + value |= spixfer(0); + + digitalWrite(_cs, HIGH); + if (_sck == -1) + _spi->endTransaction(); // release the SPI bus + } + + return value; +} + +/*! + * @brief Take a new measurement (only possible in forced mode) + */ +void Adafruit_BME280::takeForcedMeasurement() { + // If we are in forced mode, the BME sensor goes back to sleep after each + // measurement and we need to set it to forced mode once at this point, so + // it will take the next measurement and then return to sleep again. + // In normal mode simply does new measurements periodically. + if (_measReg.mode == MODE_FORCED) { + // set to forced mode, i.e. "take next measurement" + write8(BME280_REGISTER_CONTROL, _measReg.get()); + // wait until measurement has been completed, otherwise we would read + // the values from the last measurement + while (read8(BME280_REGISTER_STATUS) & 0x08) + delay(1); + } +} + +/*! + * @brief Reads the factory-set coefficients + */ +void Adafruit_BME280::readCoefficients(void) { + _bme280_calib.dig_T1 = read16_LE(BME280_REGISTER_DIG_T1); + _bme280_calib.dig_T2 = readS16_LE(BME280_REGISTER_DIG_T2); + _bme280_calib.dig_T3 = readS16_LE(BME280_REGISTER_DIG_T3); + + Serial.printf("Temp Coeffs: %04X %04X %04X\r\n", _bme280_calib.dig_T1, _bme280_calib.dig_T2, _bme280_calib.dig_T3); + + _bme280_calib.dig_P1 = read16_LE(BME280_REGISTER_DIG_P1); + _bme280_calib.dig_P2 = readS16_LE(BME280_REGISTER_DIG_P2); + _bme280_calib.dig_P3 = readS16_LE(BME280_REGISTER_DIG_P3); + _bme280_calib.dig_P4 = readS16_LE(BME280_REGISTER_DIG_P4); + _bme280_calib.dig_P5 = readS16_LE(BME280_REGISTER_DIG_P5); + _bme280_calib.dig_P6 = readS16_LE(BME280_REGISTER_DIG_P6); + _bme280_calib.dig_P7 = readS16_LE(BME280_REGISTER_DIG_P7); + _bme280_calib.dig_P8 = readS16_LE(BME280_REGISTER_DIG_P8); + _bme280_calib.dig_P9 = readS16_LE(BME280_REGISTER_DIG_P9); + + _bme280_calib.dig_H1 = read8(BME280_REGISTER_DIG_H1); + _bme280_calib.dig_H2 = readS16_LE(BME280_REGISTER_DIG_H2); + _bme280_calib.dig_H3 = read8(BME280_REGISTER_DIG_H3); + _bme280_calib.dig_H4 = (read8(BME280_REGISTER_DIG_H4) << 4) | + (read8(BME280_REGISTER_DIG_H4 + 1) & 0xF); + _bme280_calib.dig_H5 = (read8(BME280_REGISTER_DIG_H5 + 1) << 4) | + (read8(BME280_REGISTER_DIG_H5) >> 4); + _bme280_calib.dig_H6 = (int8_t)read8(BME280_REGISTER_DIG_H6); +} + +/*! + * @brief return true if chip is busy reading cal data + * @returns true if reading calibration, false otherwise + */ +bool Adafruit_BME280::isReadingCalibration(void) { + uint8_t const rStatus = read8(BME280_REGISTER_STATUS); + + return (rStatus & (1 << 0)) != 0; +} + +/*! + * @brief Returns the temperature from the sensor + * @returns the temperature read from the device + */ +float Adafruit_BME280::readTemperature(void) { +// double var1, var2; + int32_t var1, var2; + + int32_t adc_T = read24(BME280_REGISTER_TEMPDATA); + if (adc_T == 0x800000) // value in case temp measurement was disabled + return NAN; + adc_T >>= 4; + +// first reads 2C high @24 +//second is based upon this python code https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/blob/master/MicroPython_BUILD/components/micropython/esp32/modules_examples/bme280.py +// var1 = ((((adc_T >> 3) - ((int32_t)_bme280_calib.dig_T1 << 1))) * ((int32_t)_bme280_calib.dig_T2)) >> 11; + + var1 = ((adc_T >> 3) - ((int32_t)_bme280_calib.dig_T1 << 1)) * ((int32_t)_bme280_calib.dig_T2 >> 11); + + var2 = (((((adc_T >> 4) - ((int32_t)_bme280_calib.dig_T1)) * + ((adc_T >> 4) - ((int32_t)_bme280_calib.dig_T1))) >> 12) * ((int32_t)_bme280_calib.dig_T3)) >> 14; + + /*var1 = ((double)adc_T) / 16384.0 - ((double)_bme280_calib.dig_T1) / 1024.0; + var1 = var1 * ((double)_bme280_calib.dig_T2); + var2 = (((double)adc_T) / 131072.0 - ((double)_bme280_calib.dig_T1) / 8192.0); + var2 = (var2 * var2) * ((double)_bme280_calib.dig_T3); +*/ + + t_fine = (int32_t)(var1 + var2); + // float T = (var1 + var2) / 5120.0; + // return T; + t_fine = var1 + var2; + + float T = (t_fine * 5 + 128) >> 8; + return T / 100; +} + +/*! + * @brief Returns the pressure from the sensor + * @returns the pressure value (in Pascal) read from the device + */ +float Adafruit_BME280::readPressure(void) { + int64_t var1, var2, p; + + readTemperature(); // must be done first to get t_fine + + int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA); + if (adc_P == 0x800000) // value in case pressure measurement was disabled + return NAN; + adc_P >>= 4; + + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6; + var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) << 17); + var2 = var2 + (((int64_t)_bme280_calib.dig_P4) << 35); + var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) >> 8) + + ((var1 * (int64_t)_bme280_calib.dig_P2) << 12); + var1 = + (((((int64_t)1) << 47) + var1)) * ((int64_t)_bme280_calib.dig_P1) >> 33; + + if (var1 == 0) { + return 0; // avoid exception caused by division by zero + } + p = 1048576 - adc_P; + p = (((p << 31) - var2) * 3125) / var1; + var1 = (((int64_t)_bme280_calib.dig_P9) * (p >> 13) * (p >> 13)) >> 25; + var2 = (((int64_t)_bme280_calib.dig_P8) * p) >> 19; + + p = ((p + var1 + var2) >> 8) + (((int64_t)_bme280_calib.dig_P7) << 4); + return (float)p / 256; +} + +/*! + * @brief Returns the humidity from the sensor + * @returns the humidity value read from the device + */ +float Adafruit_BME280::readHumidity(void) { + readTemperature(); // must be done first to get t_fine + + int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA); + if (adc_H == 0x8000) // value in case humidity measurement was disabled + return NAN; + + int32_t v_x1_u32r; + + v_x1_u32r = (t_fine - ((int32_t)76800)); + + v_x1_u32r = (((((adc_H << 14) - (((int32_t)_bme280_calib.dig_H4) << 20) - + (((int32_t)_bme280_calib.dig_H5) * v_x1_u32r)) + + ((int32_t)16384)) >> + 15) * + (((((((v_x1_u32r * ((int32_t)_bme280_calib.dig_H6)) >> 10) * + (((v_x1_u32r * ((int32_t)_bme280_calib.dig_H3)) >> 11) + + ((int32_t)32768))) >> + 10) + + ((int32_t)2097152)) * + ((int32_t)_bme280_calib.dig_H2) + + 8192) >> + 14)); + + v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * + ((int32_t)_bme280_calib.dig_H1)) >> + 4)); + + v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; + v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; + float h = (v_x1_u32r >> 12); + return h / 1024.0; +} + +/*! + * Calculates the altitude (in meters) from the specified atmospheric + * pressure (in hPa), and sea-level pressure (in hPa). + * @param seaLevel Sea-level pressure in hPa + * @returns the altitude value read from the device + */ +float Adafruit_BME280::readAltitude(float seaLevel) { + // Equation taken from BMP180 datasheet (page 16): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + + float atmospheric = readPressure() / 100.0F; + return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903)); +} + +/*! + * Calculates the pressure at sea level (in hPa) from the specified + * altitude (in meters), and atmospheric pressure (in hPa). + * @param altitude Altitude in meters + * @param atmospheric Atmospheric pressure in hPa + * @returns the pressure at sea level (in hPa) from the specified altitude + */ +float Adafruit_BME280::seaLevelForAltitude(float altitude, float atmospheric) { + // Equation taken from BMP180 datasheet (page 17): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + + return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255); +} + +/*! + * Returns Sensor ID found by init() for diagnostics + * @returns Sensor ID 0x60 for BME280, 0x56, 0x57, 0x58 BMP280 + */ +uint32_t Adafruit_BME280::sensorID(void) { return _sensorID; } diff --git a/lib/Adafruit_BME280_Library/Adafruit_BME280.h b/lib/Adafruit_BME280_Library/Adafruit_BME280.h new file mode 100644 index 0000000..2b10fe3 --- /dev/null +++ b/lib/Adafruit_BME280_Library/Adafruit_BME280.h @@ -0,0 +1,340 @@ +/*! + * @file Adafruit_BME280.h + * + * Designed specifically to work with the Adafruit BME280 Breakout + * ----> http://www.adafruit.com/products/2650 + * + * These sensors use I2C or SPI to communicate, 2 or 4 pins are required + * to interface. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Kevin "KTOWN" Townsend for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * See the LICENSE file for details. + * + */ + +#ifndef __BME280_H__ +#define __BME280_H__ + +#include "Arduino.h" + +//#include +#include "../Adafruit_Sensor/Adafruit_Sensor.h" +#include +#include + +/*! + * @brief default I2C address + */ +#define BME280_ADDRESS (0x77) // Primary I2C Address + /*! + * @brief alternate I2C address + */ +#define BME280_ADDRESS_ALTERNATE (0x76) // Alternate Address + +/*! + * @brief Register addresses + */ +enum { + BME280_REGISTER_DIG_T1 = 0x88, + BME280_REGISTER_DIG_T2 = 0x8A, + BME280_REGISTER_DIG_T3 = 0x8C, + + BME280_REGISTER_DIG_P1 = 0x8E, + BME280_REGISTER_DIG_P2 = 0x90, + BME280_REGISTER_DIG_P3 = 0x92, + BME280_REGISTER_DIG_P4 = 0x94, + BME280_REGISTER_DIG_P5 = 0x96, + BME280_REGISTER_DIG_P6 = 0x98, + BME280_REGISTER_DIG_P7 = 0x9A, + BME280_REGISTER_DIG_P8 = 0x9C, + BME280_REGISTER_DIG_P9 = 0x9E, + + BME280_REGISTER_DIG_H1 = 0xA1, + BME280_REGISTER_DIG_H2 = 0xE1, + BME280_REGISTER_DIG_H3 = 0xE3, + BME280_REGISTER_DIG_H4 = 0xE4, + BME280_REGISTER_DIG_H5 = 0xE5, + BME280_REGISTER_DIG_H6 = 0xE7, + + BME280_REGISTER_CHIPID = 0xD0, + BME280_REGISTER_VERSION = 0xD1, + BME280_REGISTER_SOFTRESET = 0xE0, + + BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0 + + BME280_REGISTER_CONTROLHUMID = 0xF2, + BME280_REGISTER_STATUS = 0XF3, + BME280_REGISTER_CONTROL = 0xF4, + BME280_REGISTER_CONFIG = 0xF5, + BME280_REGISTER_PRESSUREDATA = 0xF7, + BME280_REGISTER_TEMPDATA = 0xFA, + BME280_REGISTER_HUMIDDATA = 0xFD +}; + +/**************************************************************************/ +/*! + @brief calibration data +*/ +/**************************************************************************/ +typedef struct { + uint16_t dig_T1; ///< temperature compensation value + int16_t dig_T2; ///< temperature compensation value + int16_t dig_T3; ///< temperature compensation value + + uint16_t dig_P1; ///< pressure compensation value + int16_t dig_P2; ///< pressure compensation value + int16_t dig_P3; ///< pressure compensation value + int16_t dig_P4; ///< pressure compensation value + int16_t dig_P5; ///< pressure compensation value + int16_t dig_P6; ///< pressure compensation value + int16_t dig_P7; ///< pressure compensation value + int16_t dig_P8; ///< pressure compensation value + int16_t dig_P9; ///< pressure compensation value + + uint8_t dig_H1; ///< humidity compensation value + int16_t dig_H2; ///< humidity compensation value + uint8_t dig_H3; ///< humidity compensation value + int16_t dig_H4; ///< humidity compensation value + int16_t dig_H5; ///< humidity compensation value + int8_t dig_H6; ///< humidity compensation value +} bme280_calib_data; +/*=========================================================================*/ + +/* +class Adafruit_BME280_Unified : public Adafruit_Sensor +{ + public: + Adafruit_BME280_Unified(int32_t sensorID = -1); + + bool begin(uint8_t addr = BME280_ADDRESS); + void getTemperature(float *temp); + void getPressure(float *pressure); + float pressureToAltitude(float seaLevel, float atmospheric, float temp); + float seaLevelForAltitude(float altitude, float atmospheric, float temp); + void getEvent(sensors_event_t*); + void getSensor(sensor_t*); + + private: + uint8_t _i2c_addr; + int32_t _sensorID; +}; + +*/ + +/**************************************************************************/ +/*! + @brief Class that stores state and functions for interacting with BME280 IC +*/ +/**************************************************************************/ +class Adafruit_BME280 { +public: + /**************************************************************************/ + /*! + @brief sampling rates + */ + /**************************************************************************/ + enum sensor_sampling { + SAMPLING_NONE = 0b000, + SAMPLING_X1 = 0b001, + SAMPLING_X2 = 0b010, + SAMPLING_X4 = 0b011, + SAMPLING_X8 = 0b100, + SAMPLING_X16 = 0b101 + }; + + /**************************************************************************/ + /*! + @brief power modes + */ + /**************************************************************************/ + enum sensor_mode { + MODE_SLEEP = 0b00, + MODE_FORCED = 0b01, + MODE_NORMAL = 0b11 + }; + + /**************************************************************************/ + /*! + @brief filter values + */ + /**************************************************************************/ + enum sensor_filter { + FILTER_OFF = 0b000, + FILTER_X2 = 0b001, + FILTER_X4 = 0b010, + FILTER_X8 = 0b011, + FILTER_X16 = 0b100 + }; + + /**************************************************************************/ + /*! + @brief standby duration in ms + */ + /**************************************************************************/ + enum standby_duration { + STANDBY_MS_0_5 = 0b000, + STANDBY_MS_10 = 0b110, + STANDBY_MS_20 = 0b111, + STANDBY_MS_62_5 = 0b001, + STANDBY_MS_125 = 0b010, + STANDBY_MS_250 = 0b011, + STANDBY_MS_500 = 0b100, + STANDBY_MS_1000 = 0b101 + }; + + // constructors + Adafruit_BME280(); + Adafruit_BME280(int8_t cspin, SPIClass *theSPI = &SPI); + Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin, + int8_t sckpin); + + bool begin(); + bool begin(TwoWire *theWire); + bool begin(uint8_t addr); + bool begin(uint8_t addr, TwoWire *theWire); + bool init(); + + void setSampling(sensor_mode mode = MODE_NORMAL, + sensor_sampling tempSampling = SAMPLING_X16, + sensor_sampling pressSampling = SAMPLING_X16, + sensor_sampling humSampling = SAMPLING_X16, + sensor_filter filter = FILTER_OFF, + standby_duration duration = STANDBY_MS_0_5); + + void takeForcedMeasurement(); + float readTemperature(void); + float readPressure(void); + float readHumidity(void); + + float readAltitude(float seaLevel); + float seaLevelForAltitude(float altitude, float pressure); + uint32_t sensorID(void); + +protected: + TwoWire *_wire; //!< pointer to a TwoWire object + SPIClass *_spi; //!< pointer to SPI object + void readCoefficients(void); + bool isReadingCalibration(void); + uint8_t spixfer(uint8_t x); + + void write8(byte reg, byte value); + uint8_t read8(byte reg); + uint16_t read16(byte reg); + uint32_t read24(byte reg); + int16_t readS16(byte reg); + uint16_t read16_LE(byte reg); // little endian + int16_t readS16_LE(byte reg); // little endian + + uint8_t _i2caddr; //!< I2C addr for the TwoWire interface + int32_t _sensorID; //!< ID of the BME Sensor + int32_t t_fine; //!< temperature with high resolution, stored as an attribute + //!< as this is used for temperature compensation reading + //!< humidity and pressure + + int8_t _cs; //!< for the SPI interface + int8_t _mosi; //!< for the SPI interface + int8_t _miso; //!< for the SPI interface + int8_t _sck; //!< for the SPI interface + + bme280_calib_data _bme280_calib; //!< here calibration data is stored + + /**************************************************************************/ + /*! + @brief config register + */ + /**************************************************************************/ + struct config { + // inactive duration (standby time) in normal mode + // 000 = 0.5 ms + // 001 = 62.5 ms + // 010 = 125 ms + // 011 = 250 ms + // 100 = 500 ms + // 101 = 1000 ms + // 110 = 10 ms + // 111 = 20 ms + unsigned int t_sb : 3; ///< inactive duration (standby time) in normal mode + + // filter settings + // 000 = filter off + // 001 = 2x filter + // 010 = 4x filter + // 011 = 8x filter + // 100 and above = 16x filter + unsigned int filter : 3; ///< filter settings + + // unused - don't set + unsigned int none : 1; ///< unused - don't set + unsigned int spi3w_en : 1; ///< unused - don't set + + /// @return combined config register + unsigned int get() { return (t_sb << 5) | (filter << 2) | spi3w_en; } + }; + config _configReg; //!< config register object + + /**************************************************************************/ + /*! + @brief ctrl_meas register + */ + /**************************************************************************/ + struct ctrl_meas { + // temperature oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_t : 3; ///< temperature oversampling + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_p : 3; ///< pressure oversampling + + // device mode + // 00 = sleep + // 01 or 10 = forced + // 11 = normal + unsigned int mode : 2; ///< device mode + + /// @return combined ctrl register + unsigned int get() { return (osrs_t << 5) | (osrs_p << 2) | mode; } + }; + ctrl_meas _measReg; //!< measurement register object + + /**************************************************************************/ + /*! + @brief ctrl_hum register + */ + /**************************************************************************/ + struct ctrl_hum { + /// unused - don't set + unsigned int none : 5; + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_h : 3; ///< pressure oversampling + + /// @return combined ctrl hum register + unsigned int get() { return (osrs_h); } + }; + ctrl_hum _humReg; //!< hum register object +}; + +#endif diff --git a/lib/Adafruit_BME280_Library/LICENSE b/lib/Adafruit_BME280_Library/LICENSE new file mode 100644 index 0000000..f4db09c --- /dev/null +++ b/lib/Adafruit_BME280_Library/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2015, Limor Fried & Kevin Townsend for Adafruit Industries +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Adafruit Industries nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/lib/Adafruit_BME280_Library/README.md b/lib/Adafruit_BME280_Library/README.md new file mode 100644 index 0000000..2ba2668 --- /dev/null +++ b/lib/Adafruit_BME280_Library/README.md @@ -0,0 +1,31 @@ +# Adafruit BME280 Library [![Build Status](https://travis-ci.com/adafruit/Adafruit_BME280_Library.svg?branch=master)](https://travis-ci.com/adafruit/Adafruit_BME280_Library) + + + +This is a library for the Adafruit BME280 Humidity, Barometric Pressure + Temp sensor + +Designed specifically to work with the Adafruit BME280 Breakout + * http://www.adafruit.com/products/2652 + +These sensors use I2C or SPI to communicate, up to 4 pins are required to interface + +Use of this library also requires [Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor) +to be installed on your local system. + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Check out the links above for our tutorials and wiring diagrams + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, all text above must be included in any redistribution + +To download. click the DOWNLOAD ZIP button, rename the uncompressed folder Adafruit_BME280. +Check that the Adafruit_BME280 folder contains Adafruit_BME280.cpp and Adafruit_BME280.h + +Place the Adafruit_BME280 library folder your arduinosketchfolder/libraries/ folder. +You may need to create the libraries subfolder if its your first library. Restart the IDE. + +We also have a great tutorial on Arduino library installation at: +http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use diff --git a/lib/Adafruit_BME280_Library/assets/board.jpg b/lib/Adafruit_BME280_Library/assets/board.jpg new file mode 100644 index 0000000..581f4ba Binary files /dev/null and b/lib/Adafruit_BME280_Library/assets/board.jpg differ diff --git a/lib/Adafruit_BME280_Library/examples/advancedsettings/advancedsettings.ino b/lib/Adafruit_BME280_Library/examples/advancedsettings/advancedsettings.ino new file mode 100644 index 0000000..b4f0810 --- /dev/null +++ b/lib/Adafruit_BME280_Library/examples/advancedsettings/advancedsettings.ino @@ -0,0 +1,159 @@ +/*************************************************************************** + This is a library for the BME280 humidity, temperature & pressure sensor + + Designed specifically to work with the Adafruit BME280 Breakout + ----> http://www.adafruit.com/products/2650 + + These sensors use I2C or SPI to communicate, 2 or 4 pins are required + to interface. The device's I2C address is either 0x76 or 0x77. + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Written by Limor Fried & Kevin Townsend for Adafruit Industries. + BSD license, all text above must be included in any redistribution + See the LICENSE file for details. + ***************************************************************************/ + +#include +#include +#include +#include + +#define BME_SCK 13 +#define BME_MISO 12 +#define BME_MOSI 11 +#define BME_CS 10 + +#define SEALEVELPRESSURE_HPA (1013.25) + +Adafruit_BME280 bme; // I2C +//Adafruit_BME280 bme(BME_CS); // hardware SPI +//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI + +unsigned long delayTime; + +void setup() { + Serial.begin(9600); + Serial.println(F("BME280 test")); + + if (! bme.begin(&Wire)) { + Serial.println("Could not find a valid BME280 sensor, check wiring!"); + while (1); + } + + Serial.println("-- Default Test --"); + Serial.println("normal mode, 16x oversampling for all, filter off,"); + Serial.println("0.5ms standby period"); + delayTime = 5000; + + + // For more details on the following scenarious, see chapter + // 3.5 "Recommended modes of operation" in the datasheet + +/* + // weather monitoring + Serial.println("-- Weather Station Scenario --"); + Serial.println("forced mode, 1x temperature / 1x humidity / 1x pressure oversampling,"); + Serial.println("filter off"); + bme.setSampling(Adafruit_BME280::MODE_FORCED, + Adafruit_BME280::SAMPLING_X1, // temperature + Adafruit_BME280::SAMPLING_X1, // pressure + Adafruit_BME280::SAMPLING_X1, // humidity + Adafruit_BME280::FILTER_OFF ); + + // suggested rate is 1/60Hz (1m) + delayTime = 60000; // in milliseconds +*/ + +/* + // humidity sensing + Serial.println("-- Humidity Sensing Scenario --"); + Serial.println("forced mode, 1x temperature / 1x humidity / 0x pressure oversampling"); + Serial.println("= pressure off, filter off"); + bme.setSampling(Adafruit_BME280::MODE_FORCED, + Adafruit_BME280::SAMPLING_X1, // temperature + Adafruit_BME280::SAMPLING_NONE, // pressure + Adafruit_BME280::SAMPLING_X1, // humidity + Adafruit_BME280::FILTER_OFF ); + + // suggested rate is 1Hz (1s) + delayTime = 1000; // in milliseconds +*/ + +/* + // indoor navigation + Serial.println("-- Indoor Navigation Scenario --"); + Serial.println("normal mode, 16x pressure / 2x temperature / 1x humidity oversampling,"); + Serial.println("0.5ms standby period, filter 16x"); + bme.setSampling(Adafruit_BME280::MODE_NORMAL, + Adafruit_BME280::SAMPLING_X2, // temperature + Adafruit_BME280::SAMPLING_X16, // pressure + Adafruit_BME280::SAMPLING_X1, // humidity + Adafruit_BME280::FILTER_X16, + Adafruit_BME280::STANDBY_MS_0_5 ); + + // suggested rate is 25Hz + // 1 + (2 * T_ovs) + (2 * P_ovs + 0.5) + (2 * H_ovs + 0.5) + // T_ovs = 2 + // P_ovs = 16 + // H_ovs = 1 + // = 40ms (25Hz) + // with standby time that should really be 24.16913... Hz + delayTime = 41; + */ + + /* + // gaming + Serial.println("-- Gaming Scenario --"); + Serial.println("normal mode, 4x pressure / 1x temperature / 0x humidity oversampling,"); + Serial.println("= humidity off, 0.5ms standby period, filter 16x"); + bme.setSampling(Adafruit_BME280::MODE_NORMAL, + Adafruit_BME280::SAMPLING_X1, // temperature + Adafruit_BME280::SAMPLING_X4, // pressure + Adafruit_BME280::SAMPLING_NONE, // humidity + Adafruit_BME280::FILTER_X16, + Adafruit_BME280::STANDBY_MS_0_5 ); + + // Suggested rate is 83Hz + // 1 + (2 * T_ovs) + (2 * P_ovs + 0.5) + // T_ovs = 1 + // P_ovs = 4 + // = 11.5ms + 0.5ms standby + delayTime = 12; +*/ + + Serial.println(); +} + + +void loop() { + // Only needed in forced mode! In normal mode, you can remove the next line. + bme.takeForcedMeasurement(); // has no effect in normal mode + + printValues(); + delay(delayTime); +} + + +void printValues() { + Serial.print("Temperature = "); + Serial.print(bme.readTemperature()); + Serial.println(" *C"); + + Serial.print("Pressure = "); + + Serial.print(bme.readPressure() / 100.0F); + Serial.println(" hPa"); + + Serial.print("Approx. Altitude = "); + Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); + Serial.println(" m"); + + Serial.print("Humidity = "); + Serial.print(bme.readHumidity()); + Serial.println(" %"); + + Serial.println(); +} diff --git a/lib/Adafruit_BME280_Library/examples/bme280test/bme280test.ino b/lib/Adafruit_BME280_Library/examples/bme280test/bme280test.ino new file mode 100644 index 0000000..9fb8c43 --- /dev/null +++ b/lib/Adafruit_BME280_Library/examples/bme280test/bme280test.ino @@ -0,0 +1,89 @@ +/*************************************************************************** + This is a library for the BME280 humidity, temperature & pressure sensor + + Designed specifically to work with the Adafruit BME280 Breakout + ----> http://www.adafruit.com/products/2650 + + These sensors use I2C or SPI to communicate, 2 or 4 pins are required + to interface. The device's I2C address is either 0x76 or 0x77. + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Written by Limor Fried & Kevin Townsend for Adafruit Industries. + BSD license, all text above must be included in any redistribution + See the LICENSE file for details. + ***************************************************************************/ + +#include +#include +#include +#include + +#define BME_SCK 13 +#define BME_MISO 12 +#define BME_MOSI 11 +#define BME_CS 10 + +#define SEALEVELPRESSURE_HPA (1013.25) + +Adafruit_BME280 bme; // I2C +//Adafruit_BME280 bme(BME_CS); // hardware SPI +//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI + +unsigned long delayTime; + +void setup() { + Serial.begin(9600); + while(!Serial); // time to get serial running + Serial.println(F("BME280 test")); + + unsigned status; + + // default settings + // (you can also pass in a Wire library object like &Wire2) + status = bme.begin(); + if (!status) { + Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!"); + Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16); + Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n"); + Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n"); + Serial.print(" ID of 0x60 represents a BME 280.\n"); + Serial.print(" ID of 0x61 represents a BME 680.\n"); + while (1); + } + + Serial.println("-- Default Test --"); + delayTime = 1000; + + Serial.println(); +} + + +void loop() { + printValues(); + delay(delayTime); +} + + +void printValues() { + Serial.print("Temperature = "); + Serial.print(bme.readTemperature()); + Serial.println(" *C"); + + Serial.print("Pressure = "); + + Serial.print(bme.readPressure() / 100.0F); + Serial.println(" hPa"); + + Serial.print("Approx. Altitude = "); + Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); + Serial.println(" m"); + + Serial.print("Humidity = "); + Serial.print(bme.readHumidity()); + Serial.println(" %"); + + Serial.println(); +} diff --git a/lib/Adafruit_BME280_Library/library.properties b/lib/Adafruit_BME280_Library/library.properties new file mode 100644 index 0000000..20e1163 --- /dev/null +++ b/lib/Adafruit_BME280_Library/library.properties @@ -0,0 +1,10 @@ +name=Adafruit BME280 Library +version=1.0.10 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for BME280 sensors. +paragraph=Arduino library for BME280 humidity and pressure sensors. +category=Sensors +url=https://github.com/adafruit/Adafruit_BME280_Library +architectures=* +depends=Adafruit Unified Sensor diff --git a/lib/Adafruit_Sensor/.gitignore b/lib/Adafruit_Sensor/.gitignore new file mode 100644 index 0000000..d04184a --- /dev/null +++ b/lib/Adafruit_Sensor/.gitignore @@ -0,0 +1,108 @@ +# +# NOTE! Don't add files that are generated in specific +# subdirectories here. Add them in the ".gitignore" file +# in that subdirectory instead. +# +# NOTE! Please use 'git ls-files -i --exclude-standard' +# command after changing this file, to see if there are +# any tracked files which get ignored after the change. +# +# Normal rules +# +.* +*.o +*.o.* +*.a +*.s +*.ko +*.so +*.so.dbg +*.mod.c +*.i +*.lst +*.symtypes +*.order +modules.builtin +*.elf +*.bin +*.gz +*.bz2 +*.lzma +*.patch +*.gcno + +# +# Top-level generic files +# +/tags +/TAGS +/linux +/vmlinux +/vmlinuz +/System.map +/Module.markers +/Module.symvers + +# +# git files that we don't want to ignore even it they are dot-files +# +!.gitignore +!.mailmap + +# +# Generated include files +# +include/config +include/linux/version.h +include/generated + +# stgit generated dirs +patches-* + +# quilt's files +patches +series + +# cscope files +cscope.* +ncscope.* + +# gnu global files +GPATH +GRTAGS +GSYMS +GTAGS + +# QT-Creator files +Makefile.am.user +*.config +*.creator +*.creator.user +*.files +*.includes + +*.orig +*~ +\#*# +*.lo +*.la +Makefile +Makefile.in +aclocal.m4 +autoconfig.h +autoconfig.h.in +autom4te.cache/ +build-aux/ +config.log +config.status +configure +libtool +libupnp.pc +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +stamp-h1 +docs/doxygen + diff --git a/lib/Adafruit_Sensor/Adafruit_Sensor.h b/lib/Adafruit_Sensor/Adafruit_Sensor.h new file mode 100644 index 0000000..8ac638f --- /dev/null +++ b/lib/Adafruit_Sensor/Adafruit_Sensor.h @@ -0,0 +1,156 @@ +/* +* Copyright (C) 2008 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software< /span> +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and + * extended sensor support to include color, voltage and current */ + +#ifndef _ADAFRUIT_SENSOR_H +#define _ADAFRUIT_SENSOR_H + +#ifndef ARDUINO + #include +#elif ARDUINO >= 100 + #include "Arduino.h" + #include "Print.h" +#else + #include "WProgram.h" +#endif + +/* Intentionally modeled after sensors.h in the Android API: + * https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */ + +/* Constants */ +#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */ +#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */ +#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */ +#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH) +#define SENSORS_MAGFIELD_EARTH_MAX (60.0F) /**< Maximum magnetic field on Earth's surface */ +#define SENSORS_MAGFIELD_EARTH_MIN (30.0F) /**< Minimum magnetic field on Earth's surface */ +#define SENSORS_PRESSURE_SEALEVELHPA (1013.25F) /**< Average sea level pressure is 1013.25 hPa */ +#define SENSORS_DPS_TO_RADS (0.017453293F) /**< Degrees/s to rad/s multiplier */ +#define SENSORS_GAUSS_TO_MICROTESLA (100) /**< Gauss to micro-Tesla multiplier */ + +/** Sensor types */ +typedef enum +{ + SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */ + SENSOR_TYPE_MAGNETIC_FIELD = (2), + SENSOR_TYPE_ORIENTATION = (3), + SENSOR_TYPE_GYROSCOPE = (4), + SENSOR_TYPE_LIGHT = (5), + SENSOR_TYPE_PRESSURE = (6), + SENSOR_TYPE_PROXIMITY = (8), + SENSOR_TYPE_GRAVITY = (9), + SENSOR_TYPE_LINEAR_ACCELERATION = (10), /**< Acceleration not including gravity */ + SENSOR_TYPE_ROTATION_VECTOR = (11), + SENSOR_TYPE_RELATIVE_HUMIDITY = (12), + SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), + SENSOR_TYPE_VOLTAGE = (15), + SENSOR_TYPE_CURRENT = (16), + SENSOR_TYPE_COLOR = (17) +} sensors_type_t; + +/** struct sensors_vec_s is used to return a vector in a common format. */ +typedef struct { + union { + float v[3]; + struct { + float x; + float y; + float z; + }; + /* Orientation sensors */ + struct { + float roll; /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90°<=roll<=90° */ + float pitch; /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180°<=pitch<=180°) */ + float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359° */ + }; + }; + int8_t status; + uint8_t reserved[3]; +} sensors_vec_t; + +/** struct sensors_color_s is used to return color data in a common format. */ +typedef struct { + union { + float c[3]; + /* RGB color space */ + struct { + float r; /**< Red component */ + float g; /**< Green component */ + float b; /**< Blue component */ + }; + }; + uint32_t rgba; /**< 24-bit RGBA value */ +} sensors_color_t; + +/* Sensor event (36 bytes) */ +/** struct sensor_event_s is used to provide a single sensor event in a common format. */ +typedef struct +{ + int32_t version; /**< must be sizeof(struct sensors_event_t) */ + int32_t sensor_id; /**< unique sensor identifier */ + int32_t type; /**< sensor type */ + int32_t reserved0; /**< reserved */ + int32_t timestamp; /**< time is in milliseconds */ + union + { + float data[4]; + sensors_vec_t acceleration; /**< acceleration values are in meter per second per second (m/s^2) */ + sensors_vec_t magnetic; /**< magnetic vector values are in micro-Tesla (uT) */ + sensors_vec_t orientation; /**< orientation values are in degrees */ + sensors_vec_t gyro; /**< gyroscope values are in rad/s */ + float temperature; /**< temperature is in degrees centigrade (Celsius) */ + float distance; /**< distance in centimeters */ + float light; /**< light in SI lux units */ + float pressure; /**< pressure in hectopascal (hPa) */ + float relative_humidity; /**< relative humidity in percent */ + float current; /**< current in milliamps (mA) */ + float voltage; /**< voltage in volts (V) */ + sensors_color_t color; /**< color in RGB component values */ + }; +} sensors_event_t; + +/* Sensor details (40 bytes) */ +/** struct sensor_s is used to describe basic information about a specific sensor. */ +typedef struct +{ + char name[12]; /**< sensor name */ + int32_t version; /**< version of the hardware + driver */ + int32_t sensor_id; /**< unique sensor identifier */ + int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */ + float max_value; /**< maximum value of this sensor's value in SI units */ + float min_value; /**< minimum value of this sensor's value in SI units */ + float resolution; /**< smallest difference between two values reported by this sensor */ + int32_t min_delay; /**< min delay in microseconds between events. zero = not a constant rate */ +} sensor_t; + +class Adafruit_Sensor { + public: + // Constructor(s) + Adafruit_Sensor() {} + virtual ~Adafruit_Sensor() {} + + // These must be defined by the subclass + virtual void enableAutoRange(bool enabled) { (void)enabled; /* suppress unused warning */ }; + virtual bool getEvent(sensors_event_t*) = 0; + virtual void getSensor(sensor_t*) = 0; + + private: + bool _autoRange; +}; + +#endif diff --git a/lib/Adafruit_Sensor/README.md b/lib/Adafruit_Sensor/README.md new file mode 100644 index 0000000..fd99597 --- /dev/null +++ b/lib/Adafruit_Sensor/README.md @@ -0,0 +1,229 @@ +# Adafruit Unified Sensor Driver # + +Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing. + +One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road. + +Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement. + +By reducing all data to a single **sensors\_event\_t** 'type' and settling on specific, **standardised SI units** for each sensor family the same sensor types return values that are comparable with any other similar sensor. This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse. + +The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire. + +## Unified Sensor Drivers ## + +The following drivers are based on the Adafruit Unified Sensor Driver: + +**Accelerometers** + - [Adafruit\_ADXL345](https://github.com/adafruit/Adafruit_ADXL345) + - [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC) + - [Adafruit\_MMA8451\_Library](https://github.com/adafruit/Adafruit_MMA8451_Library) + +**Gyroscope** + - [Adafruit\_L3GD20\_U](https://github.com/adafruit/Adafruit_L3GD20_U) + +**Light** + - [Adafruit\_TSL2561](https://github.com/adafruit/Adafruit_TSL2561) + - [Adafruit\_TSL2591\_Library](https://github.com/adafruit/Adafruit_TSL2591_Library) + +**Magnetometers** + - [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC) + - [Adafruit\_HMC5883\_Unified](https://github.com/adafruit/Adafruit_HMC5883_Unified) + +**Barometric Pressure** + - [Adafruit\_BMP085\_Unified](https://github.com/adafruit/Adafruit_BMP085_Unified) + - [Adafruit\_BMP183\_Unified\_Library](https://github.com/adafruit/Adafruit_BMP183_Unified_Library) + +**Humidity & Temperature** + - [DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library) + +**Humidity, Temperature, & Barometric Pressure** + - [Adafruit_BME280_Library](https://github.com/adafruit/Adafruit_BME280_Library/) + +**Orientation** + - [Adafruit_BNO055](https://github.com/adafruit/Adafruit_BNO055) + +**All in one device** +- [Adafruit_LSM9DS0](https://github.com/adafruit/Adafruit_LSM9DS0_Library) (accelerometer, gyroscope, magnetometer) +- [Adafruit_LSM9DS1](https://github.com/adafruit/Adafruit_LSM9DS1/) (accelerometer, gyroscope, magnetometer) + + +## How Does it Work? ## + +Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit\_Sensor base class. There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to 'abstract' away the sensor details and values: + +**Sensor Types (sensors\_type\_t)** + +These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc. + +``` +/** Sensor types */ +typedef enum +{ + SENSOR_TYPE_ACCELEROMETER = (1), + SENSOR_TYPE_MAGNETIC_FIELD = (2), + SENSOR_TYPE_ORIENTATION = (3), + SENSOR_TYPE_GYROSCOPE = (4), + SENSOR_TYPE_LIGHT = (5), + SENSOR_TYPE_PRESSURE = (6), + SENSOR_TYPE_PROXIMITY = (8), + SENSOR_TYPE_GRAVITY = (9), + SENSOR_TYPE_LINEAR_ACCELERATION = (10), + SENSOR_TYPE_ROTATION_VECTOR = (11), + SENSOR_TYPE_RELATIVE_HUMIDITY = (12), + SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), + SENSOR_TYPE_VOLTAGE = (15), + SENSOR_TYPE_CURRENT = (16), + SENSOR_TYPE_COLOR = (17) +} sensors_type_t; +``` + +**Sensor Details (sensor\_t)** + +This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer. + +``` +/* Sensor details (40 bytes) */ +/** struct sensor_s is used to describe basic information about a specific sensor. */ +typedef struct +{ + char name[12]; + int32_t version; + int32_t sensor_id; + int32_t type; + float max_value; + float min_value; + float resolution; + int32_t min_delay; +} sensor_t; +``` + +The individual fields are intended to be used as follows: + +- **name**: The sensor name or ID, up to a maximum of twelve characters (ex. "MPL115A2") +- **version**: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver +- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network +- **type**: The sensor type, based on **sensors\_type\_t** in sensors.h +- **max\_value**: The maximum value that this sensor can return (in the appropriate SI unit) +- **min\_value**: The minimum value that this sensor can return (in the appropriate SI unit) +- **resolution**: The smallest difference between two values that this sensor can report (in the appropriate SI unit) +- **min\_delay**: The minimum delay in microseconds between two sensor events, or '0' if there is no constant sensor rate + +**Sensor Data/Events (sensors\_event\_t)** + +This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales. + +``` +/* Sensor event (36 bytes) */ +/** struct sensor_event_s is used to provide a single sensor event in a common format. */ +typedef struct +{ + int32_t version; + int32_t sensor_id; + int32_t type; + int32_t reserved0; + int32_t timestamp; + union + { + float data[4]; + sensors_vec_t acceleration; + sensors_vec_t magnetic; + sensors_vec_t orientation; + sensors_vec_t gyro; + float temperature; + float distance; + float light; + float pressure; + float relative_humidity; + float current; + float voltage; + sensors_color_t color; + }; +} sensors_event_t; +``` +It includes the following fields: + +- **version**: Contain 'sizeof(sensors\_event\_t)' to identify which version of the API we're using in case this changes in the future +- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor\_id value in the corresponding sensor\_t enum above!) +- **type**: the sensor type, based on **sensors\_type\_t** in sensors.h +- **timestamp**: time in milliseconds when the sensor value was read +- **data[4]**: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below) + +**Required Functions** + +In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions: + +``` +bool getEvent(sensors_event_t*); +``` +Calling this function will populate the supplied sensors\_event\_t reference with the latest available sensor data. You should call this function as often as you want to update your data. + +``` +void getSensor(sensor_t*); +``` +Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc. + +**Standardised SI values for sensors\_event\_t** + +A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors\_event\_t above. This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales: + +- **acceleration**: values are in **meter per second per second** (m/s^2) +- **magnetic**: values are in **micro-Tesla** (uT) +- **orientation**: values are in **degrees** +- **gyro**: values are in **rad/s** +- **temperature**: values in **degrees centigrade** (Celsius) +- **distance**: values are in **centimeters** +- **light**: values are in **SI lux** units +- **pressure**: values are in **hectopascal** (hPa) +- **relative\_humidity**: values are in **percent** +- **current**: values are in **milliamps** (mA) +- **voltage**: values are in **volts** (V) +- **color**: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format + +## The Unified Driver Abstraction Layer in Practice ## + +Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created. + +Every compliant sensor can now be read using a single, well-known 'type' (sensors\_event\_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor\_t). + +An example of reading the [TSL2561](https://github.com/adafruit/Adafruit_TSL2561) light sensor can be seen below: + +``` + Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345); + ... + /* Get a new sensor event */ + sensors_event_t event; + tsl.getEvent(&event); + + /* Display the results (light is measured in lux) */ + if (event.light) + { + Serial.print(event.light); Serial.println(" lux"); + } + else + { + /* If event.light = 0 lux the sensor is probably saturated + and no reliable data could be generated! */ + Serial.println("Sensor overload"); + } +``` + +Similarly, we can get the basic technical capabilities of this sensor with the following code: + +``` + sensor_t sensor; + + sensor_t sensor; + tsl.getSensor(&sensor); + + /* Display the sensor details */ + Serial.println("------------------------------------"); + Serial.print ("Sensor: "); Serial.println(sensor.name); + Serial.print ("Driver Ver: "); Serial.println(sensor.version); + Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id); + Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux"); + Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux"); + Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux"); + Serial.println("------------------------------------"); + Serial.println(""); +``` diff --git a/lib/Adafruit_Sensor/library.properties b/lib/Adafruit_Sensor/library.properties new file mode 100644 index 0000000..e0bcd3e --- /dev/null +++ b/lib/Adafruit_Sensor/library.properties @@ -0,0 +1,10 @@ +name=Adafruit Unified Sensor +version=1.0.3 +author=Adafruit +maintainer=Adafruit +sentence=Required for all Adafruit Unified Sensor based libraries. +paragraph=A unified sensor abstraction layer used by many Adafruit sensor libraries. +category=Sensors +url=https://github.com/adafruit/Adafruit_Sensor +architectures=* +includes=Adafruit_Sensor.h diff --git a/lib/esp32DHT/.gitignore b/lib/esp32DHT/.gitignore deleted file mode 100644 index a0f3ef4..0000000 --- a/lib/esp32DHT/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.pioenvs -.vscode -lib -.vscode/.browse.c_cpp.db* -.vscode/c_cpp_properties.json -.vscode/launch.json -platformio.ini -.piolibdeps diff --git a/lib/esp32DHT/.travis.yml b/lib/esp32DHT/.travis.yml deleted file mode 100644 index 0b066ee..0000000 --- a/lib/esp32DHT/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: python -python: - - "2.7" - -# Cache PlatformIO packages using Travis CI container-based infrastructure -sudo: false -cache: - directories: - - "~/.platformio" - -env: - - PLATFORMIO_CI_SRC=examples/DHT22/DHT22.ino - - CPPLINT=true - -install: - - pip install -U platformio - - pip install -U cpplint - -script: - - if [[ "$CPPLINT" ]]; then cpplint --repository=. --recursive --linelength=200 --filter=-build/include ./src; else platformio ci --lib="." --board=lolin32; fi - -notifications: - email: - on_success: change - on_failure: change \ No newline at end of file diff --git a/lib/esp32DHT/LICENSE b/lib/esp32DHT/LICENSE deleted file mode 100644 index 0163b80..0000000 --- a/lib/esp32DHT/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Bert Melis - -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. diff --git a/lib/esp32DHT/README.md b/lib/esp32DHT/README.md deleted file mode 100644 index 715ccb3..0000000 --- a/lib/esp32DHT/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# esp32DHT - -[![Build Status](https://travis-ci.com/bertmelis/esp32DHT.svg?branch=master)](https://travis-ci.com/bertmelis/esp32DHT) - -This is a DHT11/22 library for ESP32 using the RMT peripheral, for use in the Arduino framework. -For ESP8266, please look into this repo: [DHT](https://github.com/bertmelis/DHT) - -The library is non blocking, doesn't use delay and is usable in async frameworks. The library is kept simple on purpose. You are responsible yourself to follow the sensor's constraints (like polling frequency) and logical programming errors. Supplementary functions like dew point calculation are not included. - -## Installation - -* For Arduino IDE: see [the Arduino Guide](https://www.arduino.cc/en/Guide/Libraries#toc4) -* For Platformio: see the [Platfomio guide](http://docs.platformio.org/en/latest/projectconf/section_env_library.html) - -## Usage - -```C++ -#include -#include - -DHT22 sensor; - -void setup() { - Serial.begin(112500); - sensor.setup(23); - sensor.setCallback([](int8_t result) { - if (result > 0) { - Serial.printf("Temp: %.1f°C\nHumid: %.1f%%\n", sensor.getTemperature(), sensor.getHumidity()); - } else { - Serial.printf("Sensor error: %s", sensor.getError()); - } - }); -} - -void loop() { - static uint32_t lastMillis = 0; - if (millis() - lastMillis > 30000) { - lastMillis = millis(); - sensor.read(); - Serial.print("Read DHT...\n"); - } -} -``` - -> Note: `setup(uint8_t, rmt_channel_t channel = RMT_CHANNEL_0);` taks 2 arguments: the pin connected to the DHT sensor and the RMT channel[0-7]. The library uses 2 channels and defaults to (starting) channel 0. This means that by default channel 0 and channel 1 are occupied by the DHT and you should not use channel 7. If you're also using other RMT channels (for IR devices, extra DHT sensors, Neopixels...) you have to keep this in mind. -> -> Read more about RMT in the docs: [ESP-IDF documentation](https://esp-idf.readthedocs.io/en/latest/api-reference/peripherals/rmt.html) - -## History - -Whatever can be done using hardware should not be done by software. ESP32 has a RMT peripheral device which is remarkably versatile. As the DHT sensors rely on tight timing, the RMT device is perfect to accomplish reliable communication. I didn't find any other Arduino library that uses the RMT and/or doesn't block during communication. So I created my own one. - -> This library won't exist without the examples for RMT. Credits go to the team and contributors of ESP-IDF and @nkolban! diff --git a/lib/esp32DHT/buildexamples.bat b/lib/esp32DHT/buildexamples.bat deleted file mode 100644 index d0cd922..0000000 --- a/lib/esp32DHT/buildexamples.bat +++ /dev/null @@ -1 +0,0 @@ -platformio ci --lib="." --board=lolin32 examples/DHT22/DHT22.ino diff --git a/lib/esp32DHT/docs/DHT11.pdf b/lib/esp32DHT/docs/DHT11.pdf deleted file mode 100644 index 1246981..0000000 Binary files a/lib/esp32DHT/docs/DHT11.pdf and /dev/null differ diff --git a/lib/esp32DHT/docs/DHT22-AM2302.pdf b/lib/esp32DHT/docs/DHT22-AM2302.pdf deleted file mode 100644 index a2e3d52..0000000 Binary files a/lib/esp32DHT/docs/DHT22-AM2302.pdf and /dev/null differ diff --git a/lib/esp32DHT/examples/DHT22/DHT22.ino b/lib/esp32DHT/examples/DHT22/DHT22.ino deleted file mode 100644 index d572d69..0000000 --- a/lib/esp32DHT/examples/DHT22/DHT22.ino +++ /dev/null @@ -1,52 +0,0 @@ -/* - -Copyright 2018 Bert Melis - -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. - -*/ - - -#include -#include -#include - -Ticker ticker; -DHT22 sensor; -// DHT11 sensor; // DHT11 also works! - -void readDHT() { - sensor.read(); -} - -void setup() { - Serial.begin(74880); - sensor.setup(23); // pin 23 is DATA, RMT channel defaults to channel 0 and 1 - sensor.onData([](float humidity, float temperature) { - Serial.printf("Temp: %g°C\nHumid: %g%%\n", temperature,humidity); - }); - sensor.onError([](uint8_t error) { - Serial.printf("Sensor error: %s", sensor.getError()); - }); - ticker.attach(30, readDHT); -} - -void loop() { -} diff --git a/lib/esp32DHT/keywords.txt b/lib/esp32DHT/keywords.txt deleted file mode 100644 index 5f17284..0000000 --- a/lib/esp32DHT/keywords.txt +++ /dev/null @@ -1,24 +0,0 @@ -####################################### -# Datatypes (KEYWORD1) -####################################### - -DHT11 KEYWORD1 -DHT22 KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -setPin KEYWORD2 -setCallback KEYWORD2 -read KEYWORD2 -ready KEYWORD2 -getTemperature KEYWORD2 -getHumidity KEYWORD2 -getError KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### - -#yourLITERAL LITERAL1 diff --git a/lib/esp32DHT/library.json b/lib/esp32DHT/library.json deleted file mode 100644 index fdab61e..0000000 --- a/lib/esp32DHT/library.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "esp32DHT", - "version": "1.0.1", - "keywords": "DHT, DTH11, DHT22, RMT, callback, Arduino, ESP32", - "description": "DHT sensor library for ESP32 using the RMT peripheral", - "homepage": "https://github.com/bertmelis/esp32DHT", - "license": "MIT", - "authors": { - "name": "Bert Melis", - "url": "https://github.com/bertmelis", - "maintainer": true - }, - "repository": { - "type": "git", - "url": "https://github.com/bertmelis/esp32DHT.git", - "branch": "master" - }, - "frameworks": "arduino", - "platforms": [ - "espressif32" - ] -} \ No newline at end of file diff --git a/lib/esp32DHT/library.properties b/lib/esp32DHT/library.properties deleted file mode 100644 index eb529de..0000000 --- a/lib/esp32DHT/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=esp32DHT -version=1.0.1 -author=Bert Melis -maintainer=Bert Melis -sentence=DHT sensor library for ESP32 using the RMT pheripheral -paragraph= -category=Sensors -url=https://github.com/bertmelis/esp32DHT -architectures=esp32 diff --git a/lib/esp32DHT/src/esp32DHT.cpp b/lib/esp32DHT/src/esp32DHT.cpp deleted file mode 100644 index 7eab72c..0000000 --- a/lib/esp32DHT/src/esp32DHT.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - -Copyright 2018 Bert Melis - -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 CONDHTTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#include "esp32DHT.hpp" // NOLINT - -#define RMT_CLK_DIV 80 - -DHT::DHT() : - _status(0), - _data{0}, - _pin(0), - _channel(RMT_CHANNEL_0), - _onData(nullptr), - _onError(nullptr), - _timer(nullptr), - _task(nullptr) {} - -DHT::~DHT() { - if (_timer) { // if _timer is true, setup() has been called - // so RMT driver is loaded and the aux task is - // running - esp_timer_delete(_timer); - rmt_driver_uninstall(_channel); - vTaskDelete(_task); - } -} - -void DHT::setup(uint8_t pin, rmt_channel_t channel) { - _pin = pin; - _channel = channel; - esp_timer_create_args_t _timerConfig; - _timerConfig.arg = static_cast(this); - _timerConfig.callback = reinterpret_cast(_handleTimer); - _timerConfig.dispatch_method = ESP_TIMER_TASK; - _timerConfig.name = "esp32DHTTimer"; - esp_timer_create(&_timerConfig, &_timer); - rmt_config_t config; - config.rmt_mode = RMT_MODE_RX; - config.channel = _channel; - config.gpio_num = static_cast(_pin); - config.mem_block_num = 2; - config.rx_config.filter_en = 1; - config.rx_config.filter_ticks_thresh = 10; - config.rx_config.idle_threshold = 1000; - config.clk_div = RMT_CLK_DIV; - rmt_config(&config); - rmt_driver_install(_channel, 400, 0); // 400 words for ringbuffer containing pulse trains from DHT - rmt_get_ringbuf_handle(_channel, &_ringBuf); - xTaskCreate((TaskFunction_t)&_handleData, "esp32DHT", 2048, this, 5, &_task); - pinMode(_pin, OUTPUT); - digitalWrite(_pin, HIGH); -} - -void DHT::onData(esp32DHTInternals::OnData_CB callback) { - _onData = callback; -} - -void DHT::onError(esp32DHTInternals::OnError_CB callback) { - _onError = callback; -} - -void DHT::read() { - // _pin should be set to OUTPUT and HIGH - digitalWrite(_pin, LOW); - esp_timer_start_once(_timer, 18 * 1000); // timer is in microseconds - _data[0] = _data[1] = _data[2] = _data[3] = _data[4] = 0; - _status = 0; -} - -const char* DHT::getError() const { - if (_status == 0) { - return "OK"; - } else if (_status == 1) { - return "TO"; - } else if (_status == 2) { - return "NACK"; - } else if (_status == 3) { - return "DATA"; - } else if (_status == 4) { - return "CS"; - } else if (_status == 5) { - return "UNDERFLOW"; - } else if (_status == 6) { - return "OVERFLOW"; - } - return "UNKNOWN"; -} - -void DHT::_handleTimer(DHT* instance) { - pinMode(instance->_pin, INPUT); - rmt_rx_start(instance->_channel, 1); - rmt_set_pin(instance->_channel, RMT_MODE_RX, static_cast(instance->_pin)); // reset after using pin as output - xTaskNotifyGive(instance->_task); -} - -void DHT::_handleData(DHT* instance) { - size_t rx_size = 0; - while (1) { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // block and wait for notification - // blocks until data is available or timeouts after 1000 - rmt_item32_t* items = static_cast(xRingbufferReceive(instance->_ringBuf, &rx_size, 1000)); - if (items) { - instance->_decode(items, rx_size/sizeof(rmt_item32_t)); - vRingbufferReturnItem(instance->_ringBuf, static_cast(items)); - rmt_rx_stop(instance->_channel); - pinMode(instance->_pin, OUTPUT); - digitalWrite(instance->_pin, HIGH); - } else { - instance->_status = 1; // timeout error - rmt_rx_stop(instance->_channel); - pinMode(instance->_pin, OUTPUT); - digitalWrite(instance->_pin, HIGH); - } - instance->_tryCallback(); - } -} - -void DHT::_decode(rmt_item32_t* data, int numItems) { - if (numItems < 42) { - _status = 5; - } else if (numItems > 42) { - _status = 6; - } else if ((data[0].duration0 + data[0].duration1) < 140 && (data[0].duration0 + data[0].duration1) > 180) { - _status = 2; - } else { - for (uint8_t i = 1; i < numItems - 1; ++i) { // don't include tail - uint8_t pulse = data[i].duration0 + data[i].duration1; - if (pulse > 55 && pulse < 145) { - _data[(i - 1) / 8] <<= 1; // shift left - if (pulse > 120) { - _data[(i - 1) / 8] |= 1; - } - } else { - _status = 3; // DATA error - return; - } - } - if (_data[4] == ((_data[0] + _data[1] + _data[2] + _data[3]) & 0xFF)) { - _status = 0; - } else { - _status = 4; // checksum error - } - } -} - -void DHT::_tryCallback() { - if (_status == 0) { - if (_onData) _onData(_getHumidity(), _getTemperature()); - } else { - if (_onError) _onError(_status); - } -} - -float DHT11::_getTemperature() { - if (_status != 0) return NAN; - return static_cast(_data[2]); -} - -float DHT11::_getHumidity() { - if (_status != 0) return NAN; - return static_cast(_data[0]); -} - -float DHT22::_getTemperature() { - if (_status != 0) return NAN; - float temp = (((_data[2] & 0x7F) << 8) | _data[3]) * 0.1; - if (_data[2] & 0x80) { // negative temperature - temp = -temp; - } - return temp; -} - -float DHT22::_getHumidity() { - if (_status != 0) return NAN; - return ((_data[0] << 8) | _data[1]) * 0.1; -} diff --git a/lib/esp32DHT/src/esp32DHT.h b/lib/esp32DHT/src/esp32DHT.h deleted file mode 100644 index 3e82881..0000000 --- a/lib/esp32DHT/src/esp32DHT.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - -Copyright 2018 Bert Melis - -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. - -*/ - -#pragma once - -#include "esp32DHT.hpp" diff --git a/lib/esp32DHT/src/esp32DHT.hpp b/lib/esp32DHT/src/esp32DHT.hpp deleted file mode 100644 index e8dec4d..0000000 --- a/lib/esp32DHT/src/esp32DHT.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - -Copyright 2018 Bert Melis - -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. - -*/ - -#pragma once - -extern "C" { - #include - #include - #include - #include - #include -} -#include - -namespace esp32DHTInternals { - -typedef std::function OnData_CB; -typedef std::function OnError_CB; - -} // end namespace esp32DHTInternals - -class DHT { - public: - DHT(); - ~DHT(); - void setup(uint8_t pin, rmt_channel_t channel = RMT_CHANNEL_0); // setPin does complete setup of DHT lib - void onData(esp32DHTInternals::OnData_CB callback); - void onError(esp32DHTInternals::OnError_CB callback); - void read(); - const char* getError() const; - - protected: - uint8_t _status; - uint8_t _data[5]; - - private: - static void _handleTimer(DHT* instance); - static void _handleData(DHT* instance); - void _decode(rmt_item32_t* data, int numItems); - void _tryCallback(); - virtual float _getTemperature() = 0; - virtual float _getHumidity() = 0; - - private: - uint8_t _pin; - rmt_channel_t _channel; - esp32DHTInternals::OnData_CB _onData; - esp32DHTInternals::OnError_CB _onError; - esp_timer_handle_t _timer; - TaskHandle_t _task; - RingbufHandle_t _ringBuf; -}; - -class DHT11 : public DHT { - private: - float _getTemperature(); - float _getHumidity(); -}; - -class DHT22 : public DHT { - private: - float _getTemperature(); - float _getHumidity(); -}; diff --git a/src/Afterburner.cpp b/src/Afterburner.cpp index 3349f4e..0bd3781 100644 --- a/src/Afterburner.cpp +++ b/src/Afterburner.cpp @@ -124,8 +124,8 @@ #define RX_DATA_TIMOUT 50 const int FirmwareRevision = 31; -const int FirmwareSubRevision = 5; -const char* FirmwareDate = "19 Sep 2019"; +const int FirmwareSubRevision = 6; +const char* FirmwareDate = "18 Oct 2019"; #ifdef ESP32 @@ -160,6 +160,7 @@ void showMQTTmenu(); // DS18B20 temperature sensor support // Uses the RMT timeslot driver to operate as a one-wire bus +//CBME280Sensor BMESensor; CTempSense TempSensor; long lastTemperatureTime; // used to moderate DS18B20 access int DS18B20holdoff = 2; @@ -354,7 +355,7 @@ void setup() { // DebugPort.printf("Previous user ON = %d\r\n", bUserON); // state flag required for cyclic mode to persist properly after a WD reboot :-) // initialise DS18B20 sensor interface - TempSensor.begin(DS18B20_Pin); + TempSensor.begin(DS18B20_Pin, 0x76); TempSensor.startConvert(); // kick off initial temperature sample @@ -387,7 +388,7 @@ void setup() { initJSONTimermoderator(); // prevents JSON for timers unless requested initJSONSysModerator(); - + KeyPad.begin(keyLeft_pin, keyRight_pin, keyCentre_pin, keyUp_pin, keyDown_pin); KeyPad.setCallback(parentKeyHandler); @@ -487,15 +488,15 @@ void setup() { // This allows seamless standard operation, and marks the iniital sensor // as the primary if another is added later OneWireBus_ROMCode romCode; - TempSensor.getRomCodeIdx(0, romCode); - if(TempSensor.getNumSensors() == 1 && - memcmp(NVstore.getHeaterTuning().tempProbe[0].romCode.bytes, romCode.bytes, 8) != 0) + TempSensor.getDS18B20().getRomCodeIdx(0, romCode); + if(TempSensor.getDS18B20().getNumSensors() == 1 && + memcmp(NVstore.getHeaterTuning().DS18B20probe[0].romCode.bytes, romCode.bytes, 8) != 0) { sHeaterTuning tuning = NVstore.getHeaterTuning(); - tuning.tempProbe[0].romCode = romCode; - tuning.tempProbe[1].romCode = {0}; - tuning.tempProbe[2].romCode = {0}; - tuning.tempProbe[0].offset = 0; + tuning.DS18B20probe[0].romCode = romCode; + tuning.DS18B20probe[1].romCode = {0}; + tuning.DS18B20probe[2].romCode = {0}; + tuning.DS18B20probe[0].offset = 0; NVstore.setHeaterTuning(tuning); NVstore.save(); @@ -508,9 +509,21 @@ void setup() { romCode.fields.serial_number[0] ); } - TempSensor.mapSensor(0, NVstore.getHeaterTuning().tempProbe[0].romCode); - TempSensor.mapSensor(1, NVstore.getHeaterTuning().tempProbe[1].romCode); - TempSensor.mapSensor(2, NVstore.getHeaterTuning().tempProbe[2].romCode); + TempSensor.getDS18B20().mapSensor(0, NVstore.getHeaterTuning().DS18B20probe[0].romCode); + TempSensor.getDS18B20().mapSensor(1, NVstore.getHeaterTuning().DS18B20probe[1].romCode); + TempSensor.getDS18B20().mapSensor(2, NVstore.getHeaterTuning().DS18B20probe[2].romCode); + +/* bool status = bme.begin(0x76); + if (!status) { + DebugPort.println("Could not find a valid BME280 sensor, check wiring!"); + } + bme.setSampling(Adafruit_BME280::MODE_FORCED, + Adafruit_BME280::SAMPLING_X1, + Adafruit_BME280::SAMPLING_X1, + Adafruit_BME280::SAMPLING_X1, + Adafruit_BME280::FILTER_OFF, + Adafruit_BME280::STANDBY_MS_1000);*/ +// BMESensor.begin(0x76); delay(1000); // just to hold the splash screeen for while } @@ -830,7 +843,7 @@ void loop() lastTemperatureTime = millis(); // reset time to observe temeprature TempSensor.readSensors(); - if(TempSensor.getTemperature(0, fTemperature)) { // get Primary sensor temeprature + if(TempSensor.getTemperature(0, fTemperature)) { // get Primary sensor temperature if(DS18B20holdoff) { DS18B20holdoff--; DebugPort.printf("Skipped initial DS18B20 reading: %f\r\n", fTemperature); @@ -881,6 +894,8 @@ void loop() BlueWireData.reset(); // ensure we flush any used data + vTaskDelay(1); // give up for now - allow power lowering... + } // loop void DebugReportFrame(const char* hdr, const CProtocol& Frame, const char* ftr) @@ -1080,7 +1095,7 @@ bool getThermostatModeActive() bool getExternalThermostatModeActive() { - return GPIOin.usesExternalThermostat(); + return GPIOin.usesExternalThermostat() && (NVstore.getUserSettings().ThermostatMethod == 3); } bool getExternalThermostatOn() @@ -1147,17 +1162,38 @@ float getTemperatureDesired() return getHeaterInfo().getHeaterDemand(); } else { -// if(getThermostatModeActive()) + if(getThermostatModeActive()) return RTC_Store.getDesiredTemp(); -// else -// return RTC_Store.getDesiredPump(); + else + return RTC_Store.getDesiredPump(); } } -float getTemperatureSensor() +float getTemperatureSensor(int source) { + static long lasttime = millis(); + static float tempsave = 0; + long tDelta; // NVstore always holds primary sensor as index 0 - return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().tempProbe[0].offset; + float retval; + TempSensor.getTemperature(source, retval); + return retval; + +// switch (source) { +// case 0: +// return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().DS18B20probe[0].offset; +// case 1: +// BMESensor.getTemperature(tempsave); +// /* tDelta = millis() - lasttime; +// if(tDelta >= 0) { +// bme.takeForcedMeasurement(); +// tempsave = bme.readTemperature(); +// lasttime = millis() + 10000; +// }*/ +// return tempsave; +// default: +// return -100; +// } } void setPumpMin(float val) @@ -1427,11 +1463,9 @@ void checkDebugCommands() } else if(rxVal == '+') { TxManage.queueOnRequest(); -// HeaterData.setRefTime(); } else if(rxVal == '-') { TxManage.queueOffRequest(); -// HeaterData.setRefTime(); } else if(rxVal == 'r') { ESP.restart(); // reset the esp @@ -1512,7 +1546,7 @@ bool isCyclicActive() void setupGPIO() { - if(BoardRevision == 10 || BoardRevision == 20 || BoardRevision == 21) { + if(BoardRevision == 10 || BoardRevision == 20 || BoardRevision == 21 || BoardRevision == 30) { // some special considerations for GPIO inputs, depending upon PCB hardware // V1.0 PCBs only expose bare inputs, which are pulled high. Active state into ESP32 is LOW. // V2.0+ PCBs use an input transistor buffer. Active state into ESP32 is HIGH (inverted). @@ -1843,4 +1877,9 @@ void showMainmenu() void reloadScreens() { ScreenManager.reqReload(); -} \ No newline at end of file +} + +CTempSense& getTempSensor() +{ + return TempSensor; +} diff --git a/src/OLED/BasicScreen.cpp b/src/OLED/BasicScreen.cpp index 0a8cb45..4272adc 100644 --- a/src/OLED/BasicScreen.cpp +++ b/src/OLED/BasicScreen.cpp @@ -21,13 +21,14 @@ #include #include "fonts/Tahoma24.h" +#include "fonts/Arial.h" #include "BasicScreen.h" #include "KeyPad.h" #include "../Utility/helpers.h" #include "../Utility/UtilClasses.h" #include "../Utility/NVStorage.h" #include "../Protocol/Protocol.h" - +#include "../Utility/TempSense.h" #define MAXIFONT tahoma_24ptFontInfo @@ -45,6 +46,7 @@ CBasicScreen::CBasicScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen _showModeTime = 0; _feedbackType = 0; _nModeSel = 0; + _bShowOtherSensors = 0; } bool @@ -52,28 +54,10 @@ CBasicScreen::show() { CScreenHeader::show(false); - char msg[20]; + char msg[32]; int xPos, yPos; - - float fTemp = getTemperatureSensor(); - if(fTemp > -80) { - if(NVstore.getUserSettings().degF) { - fTemp = fTemp * 9 / 5 + 32; - sprintf(msg, "%.1f`F", fTemp); - } - else { - sprintf(msg, "%.1f`C", fTemp); - } - - { - CTransientFont AF(_display, &MAXIFONT); // temporarily use a large font - _printMenuText(_display.xCentre(), 23, msg, false, eCentreJustify); - } - } - else { - _printMenuText(_display.xCentre(), 25, "No Temperature Sensor", false, eCentreJustify); - } - + float fTemp; + bool bShowLargeTemp = true; // at bottom of screen show either: // Selection between Fixed or Thermostat mode @@ -104,6 +88,7 @@ CBasicScreen::show() // cancel selection mode, apply whatever is boxed _showModeTime = 0; _showSetModeTime = millis() + 5000; // then make the new mode setting be shown + _bShowOtherSensors = 0; _feedbackType = 0; _ScreenManager.reqUpdate(); } @@ -116,14 +101,19 @@ CBasicScreen::show() case 0: // Show current heat demand setting - if(getThermostatModeActive() && !getExternalThermostatModeActive()) { - float fTemp = getTemperatureDesired(); - if(NVstore.getUserSettings().degF) { - fTemp = fTemp * 9 / 5 + 32; - sprintf(msg, "Setpoint = %.0f`F", fTemp); + if(getThermostatModeActive()) { + if(getExternalThermostatModeActive()) { + sprintf(msg, "External @ %.1fHz", getHeaterInfo().getPump_Fixed()); } else { - sprintf(msg, "Setpoint = %.0f`C", fTemp); + float fTemp = getTemperatureDesired(); + if(NVstore.getUserSettings().degF) { + fTemp = fTemp * 9 / 5 + 32; + sprintf(msg, "Setpoint = %.0f`F", fTemp); + } + else { + sprintf(msg, "Setpoint = %.0f`C", fTemp); + } } } else { @@ -137,6 +127,46 @@ CBasicScreen::show() } // centre message at bottom of screen _printMenuText(_display.xCentre(), _display.height() - _display.textHeight(), msg, false, eCentreJustify); + + if(_bShowOtherSensors && getTempSensor().getNumSensors() > 1) { + bShowLargeTemp = false; + CTransientFont AF(_display, &arial_8ptFontInfo); + int yPos = 23; + if(getTempSensor().getTemperature(1, fTemp)) { +// fTemp += NVstore.getHeaterTuning().DS18B20probe[1].offset; + if(NVstore.getUserSettings().degF) { + fTemp = fTemp * 9 / 5 + 32; + sprintf(msg, "%.1fF", fTemp); + } + else { + sprintf(msg, "%.1fC", fTemp); + } + } + else { + strcpy(msg, "---"); + } + _printMenuText(68, yPos, "External:", false, eRightJustify); + _printMenuText(72, yPos, msg); + yPos += 13; + if(getTempSensor().getNumSensors() == 3) { + if(getTempSensor().getTemperature(2, fTemp)) { +// fTemp += NVstore.getHeaterTuning().DS18B20probe[2].offset; + if(NVstore.getUserSettings().degF) { + fTemp = fTemp * 9 / 5 + 32; + sprintf(msg, "%.1fF", fTemp); + } + else { + sprintf(msg, "%.1fC", fTemp); + } + } + else { + strcpy(msg, "---"); + } + _printMenuText(68, yPos, "Auxillary:", false, eRightJustify); + _printMenuText(72, yPos, msg); + } + } + } else { _showSetModeTime = 0; @@ -146,6 +176,30 @@ CBasicScreen::show() showRunState(); showHeaderDetail(false); } + + if(bShowLargeTemp) { + float fTemp = getTemperatureSensor(0); // Primary system sensor - the one used for thermostat modes +// float fTemp = getTemperatureSensor(0); // DHT22 or DS18B20 + // fTemp = getTemperatureSensor(1); // BMP180 + if(fTemp > -80) { + if(NVstore.getUserSettings().degF) { + fTemp = fTemp * 9 / 5 + 32; + sprintf(msg, "%.1f`F", fTemp); + } + else { + sprintf(msg, "%.1f`C", fTemp); + } + + { + CTransientFont AF(_display, &MAXIFONT); // temporarily use a large font + _printMenuText(_display.xCentre(), 23, msg, false, eCentreJustify); + } + } + else { + _printMenuText(_display.xCentre(), 25, "No Temperature Sensor", false, eCentreJustify); + } + } + return true; } @@ -170,7 +224,8 @@ CBasicScreen::keyHandler(uint8_t event) if(repeatCount > 2) { repeatCount = -1; // prevent double handling if(toggleGPIOout(0)) { // toggle GPIO output #1 - _showSetModeTime = millis() + 2000; + _showSetModeTime = millis() + 5000; + _bShowOtherSensors = 0; _feedbackType = 1; _ScreenManager.reqUpdate(); } @@ -181,7 +236,8 @@ CBasicScreen::keyHandler(uint8_t event) if(repeatCount > 2) { repeatCount = -1; // prevent double handling if(toggleGPIOout(1)) { // toggle GPIO output #2 - _showSetModeTime = millis() + 2000; + _showSetModeTime = millis() + 5000; + _bShowOtherSensors = 0; _feedbackType = 2; _ScreenManager.reqUpdate(); } @@ -241,7 +297,8 @@ CBasicScreen::keyHandler(uint8_t event) if(NVstore.getUserSettings().menuMode < 2) { if(event & key_Down) { if(reqDemandDelta(-1)) { - _showSetModeTime = millis() + 2000; + _showSetModeTime = millis() + 5000; + _bShowOtherSensors = 0; _feedbackType = 0; _ScreenManager.reqUpdate(); } @@ -251,7 +308,8 @@ CBasicScreen::keyHandler(uint8_t event) // release UP key to increase set demand, provided we are not in mode select if(event & key_Up) { if(reqDemandDelta(+1)) { - _showSetModeTime = millis() + 2000; + _showSetModeTime = millis() + 5000; + _bShowOtherSensors = 0; _feedbackType = 0; _ScreenManager.reqUpdate(); } @@ -302,7 +360,8 @@ CBasicScreen::keyHandler(uint8_t event) if(_showModeTime) { _showModeTime = millis(); // force immediate cancellation of showmode (via screen update) } - _showSetModeTime = millis() + 2000; + _showSetModeTime = millis() + 5000; + _bShowOtherSensors = 1; _feedbackType = 0; } _ScreenManager.reqUpdate(); diff --git a/src/OLED/BasicScreen.h b/src/OLED/BasicScreen.h index 73141a5..8dc41bf 100644 --- a/src/OLED/BasicScreen.h +++ b/src/OLED/BasicScreen.h @@ -29,8 +29,9 @@ class CProtocolPackage; class CBasicScreen : public CScreenHeader { unsigned long _showSetModeTime; - uint8_t _feedbackType; unsigned long _showModeTime; + uint8_t _bShowOtherSensors; + uint8_t _feedbackType; uint8_t _nModeSel; void showRunState(); public: diff --git a/src/OLED/DS18B20Screen.cpp b/src/OLED/DS18B20Screen.cpp index 95c5b1f..0355591 100644 --- a/src/OLED/DS18B20Screen.cpp +++ b/src/OLED/DS18B20Screen.cpp @@ -24,9 +24,7 @@ #include "KeyPad.h" #include "fonts/Icons.h" #include "fonts/MiniFont.h" -#include "Utility/TempSense.h" - -extern CTempSense TempSensor; +#include "../Utility/TempSense.h" CDS18B20Screen::CDS18B20Screen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr) @@ -44,7 +42,7 @@ CDS18B20Screen::onSelect() { CScreenHeader::onSelect(); _initUI(); - _nNumSensors = TempSensor.getNumSensors(); + _nNumSensors = getTempSensor().getDS18B20().getNumSensors(); _readNV(); } @@ -71,9 +69,9 @@ CDS18B20Screen::show() } else { if(_colSel == 0) - _showTitle("Temp Sensor Role"); + _showTitle("DS18B20 Sensor Role"); else - _showTitle("Temp Sensor Offset"); + _showTitle("DS18B20 Sensor Offset"); int baseLine = 16; switch(_nNumSensors) { @@ -91,7 +89,7 @@ CDS18B20Screen::show() _printMenuText(border, baseLine-sensor*12, msg, _rowSel == (sensor+1) && _colSel == 0); OneWireBus_ROMCode romCode; - if(!TempSensor.getRomCodeIdx(sensor, romCode)) { + if(!getTempSensor().getDS18B20().getRomCodeIdx(sensor, romCode)) { strcpy(msg, "missing?") ; } else { @@ -108,7 +106,7 @@ CDS18B20Screen::show() if(_colSel == 0) { float temperature; - TempSensor.getTemperatureIdx(sensor, temperature); + getTempSensor().getDS18B20().getTemperatureIdx(sensor, temperature, false); sprintf(msg, "%.01fC", temperature + _Offset[sensor]); } else { @@ -116,7 +114,6 @@ CDS18B20Screen::show() } _printMenuText(90, baseLine-sensor*12, msg, _rowSel == (sensor+1) && _colSel == 1); } - } } return true; @@ -183,8 +180,8 @@ CDS18B20Screen::keyHandler(uint8_t event) if(_keyHold == 2) { if(event & key_Up) { // rescan the one wire bus - TempSensor.find(); - _nNumSensors = TempSensor.getNumSensors(); + getTempSensor().getDS18B20().find(); + _nNumSensors = getTempSensor().getDS18B20().getNumSensors(); _readNV(); } if(event & key_Left) { @@ -216,11 +213,11 @@ CDS18B20Screen::keyHandler(uint8_t event) _enableStoringMessage(); _saveNV(); NVstore.save(); - TempSensor.mapSensor(-1); // reset existing mapping - TempSensor.mapSensor(0, NVstore.getHeaterTuning().tempProbe[0].romCode); - TempSensor.mapSensor(1, NVstore.getHeaterTuning().tempProbe[1].romCode); - TempSensor.mapSensor(2, NVstore.getHeaterTuning().tempProbe[2].romCode); - TempSensor.mapSensor(-2); // report mapping + getTempSensor().getDS18B20().mapSensor(-1); // reset existing mapping + getTempSensor().getDS18B20().mapSensor(0, NVstore.getHeaterTuning().DS18B20probe[0].romCode); + getTempSensor().getDS18B20().mapSensor(1, NVstore.getHeaterTuning().DS18B20probe[1].romCode); + getTempSensor().getDS18B20().mapSensor(2, NVstore.getHeaterTuning().DS18B20probe[2].romCode); + getTempSensor().getDS18B20().mapSensor(-2); // report mapping _rowSel = 0; } else { @@ -254,7 +251,12 @@ CDS18B20Screen::keyHandler(uint8_t event) // CENTRE press if(event & key_Centre) { if(_rowSel == 0) { - _ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu +// _ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu +// _ScreenManager.selectMenu(CScreenManager::SystemSettingsLoop, CScreenManager::TempSensorUI); // force return to user settings menu + if(getTempSensor().getBME280().getCount()) + _ScreenManager.returnMenu(); + else + _ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu } else { _rowSel = SaveConfirm; @@ -339,17 +341,17 @@ CDS18B20Screen::_readNV() const sHeaterTuning& tuning = NVstore.getHeaterTuning(); - for(int sensor = 0; sensor < TempSensor.getNumSensors(); sensor++) { + for(int sensor = 0; sensor < getTempSensor().getDS18B20().getNumSensors(); sensor++) { + _Offset[sensor] = tuning.DS18B20probe[sensor].offset; OneWireBus_ROMCode romCode; - TempSensor.getRomCodeIdx(sensor, romCode); // get rom code of each attached sensor + getTempSensor().getDS18B20().getRomCodeIdx(sensor, romCode); // get rom code of each attached sensor // NV storage indices are the sensor role // ie 0 is normal thermostat // scan the NV store and match the stored romCodes // if not matched, the sensor remains unmapped for(int i=0; i< 3; i++) { - if(memcmp(tuning.tempProbe[i].romCode.bytes, romCode.bytes, 8) == 0) { + if(memcmp(tuning.DS18B20probe[i].romCode.bytes, romCode.bytes, 8) == 0) { _sensorRole[sensor] = i; // assign role to sensor according to NV placement - _Offset[sensor] = tuning.tempProbe[i].offset; break; } } @@ -362,17 +364,17 @@ CDS18B20Screen::_saveNV() { sHeaterTuning tuning = NVstore.getHeaterTuning(); for(int i=0; i<3; i++) { - memset(tuning.tempProbe[i].romCode.bytes, 0, 8); - tuning.tempProbe[i].offset = 0; + memset(tuning.DS18B20probe[i].romCode.bytes, 0, 8); + tuning.DS18B20probe[i].offset = 0; } - for(int sensor = 0; sensor < TempSensor.getNumSensors(); sensor++) { + for(int sensor = 0; sensor < getTempSensor().getDS18B20().getNumSensors(); sensor++) { + tuning.DS18B20probe[sensor].offset = _Offset[sensor]; int role = _sensorRole[sensor]; // role of probe determines placement in NV storage if(role != -1) { - tuning.tempProbe[role].offset = _Offset[sensor]; OneWireBus_ROMCode romCode; - TempSensor.getRomCodeIdx(sensor, romCode); // get rom code of indexed sensor - memcpy(tuning.tempProbe[role].romCode.bytes, romCode.bytes, 8); + getTempSensor().getDS18B20().getRomCodeIdx(sensor, romCode); // get rom code of indexed sensor + memcpy(tuning.DS18B20probe[role].romCode.bytes, romCode.bytes, 8); } } NVstore.setHeaterTuning(tuning); diff --git a/src/OLED/FuelCalScreen.cpp b/src/OLED/FuelCalScreen.cpp index 9a12db2..cd715d6 100644 --- a/src/OLED/FuelCalScreen.cpp +++ b/src/OLED/FuelCalScreen.cpp @@ -48,7 +48,7 @@ CFuelCalScreen::onSelect() _initUI(); _mlPerStroke = NVstore.getHeaterTuning().pumpCal; _LVC = NVstore.getHeaterTuning().lowVolts; - _tOfs = NVstore.getHeaterTuning().tempProbe[0].offset; +// _tOfs = NVstore.getHeaterTuning().DS18B20probe[0].offset; } void @@ -69,7 +69,7 @@ CFuelCalScreen::show() if(!CPasswordScreen::show()) { // for showing "saving settings" - if(_rowSel == 4) { + if(_rowSel == 10) { _showConfirmMessage(); } else { @@ -92,11 +92,12 @@ CFuelCalScreen::show() else strcpy(msg, "OFF"); _printMenuText(col, yPos, msg, _rowSel == 2); - // temp offset +/* // temp offset yPos = Line3; _printMenuText(col, yPos, "\367C offset : ", false, eRightJustify); sprintf(msg, "%+.1f", _tOfs); _printMenuText(col, yPos, msg, _rowSel == 3); +*/ // navigation line yPos = 53; int xPos = _display.xCentre(); @@ -189,7 +190,7 @@ CFuelCalScreen::keyHandler(uint8_t event) case 3: _adjust(-1); break; - case 4: + case 10: _rowSel = 0; // abort save break; } @@ -205,7 +206,7 @@ CFuelCalScreen::keyHandler(uint8_t event) case 3: _adjust(+1); break; - case 4: + case 10: _rowSel = 0; // abort save break; } @@ -222,16 +223,17 @@ CFuelCalScreen::keyHandler(uint8_t event) case 2: case 3: _rowSel++; - UPPERLIMIT(_rowSel, 3); +// UPPERLIMIT(_rowSel, 3); + UPPERLIMIT(_rowSel, 2); break; - case 4: // confirmed save + case 10: // confirmed save _display.clearDisplay(); _animateCount = -1; _enableStoringMessage(); tuning = NVstore.getHeaterTuning(); tuning.pumpCal = _mlPerStroke; tuning.lowVolts = _LVC; - tuning.tempProbe[0].offset = _tOfs; +// tuning.DS18B20probe[0].offset = _tOfs; NVstore.setHeaterTuning(tuning); saveNV(); _rowSel = 0; @@ -249,7 +251,7 @@ CFuelCalScreen::keyHandler(uint8_t event) case 3: _animateCount = -1; _display.clearDisplay(); - _rowSel = 4; + _rowSel = 10; break; } } @@ -290,9 +292,10 @@ CFuelCalScreen::_adjust(int dir) } } break; - case 3: +/* case 3: _tOfs += dir * 0.1; BOUNDSLIMIT(_tOfs, -10, 10); break; +*/ } } diff --git a/src/OLED/GPIOSetupScreen.cpp b/src/OLED/GPIOSetupScreen.cpp index a037e00..62ecade 100644 --- a/src/OLED/GPIOSetupScreen.cpp +++ b/src/OLED/GPIOSetupScreen.cpp @@ -302,7 +302,7 @@ CGPIOSetupScreen::keyHandler(uint8_t event) _rowSel--; if((_rowSel == 3) && (_GPIOparams.in2Mode != CGPIOin2::Thermostat)) _rowSel--; // force skip if not set to external thermostat - if((_rowSel == 1) && (getBoardRevision() == BRD_V2_GPIO_NOALG)) // GPIO but NO analog support + if((_rowSel == 1) && ((getBoardRevision() == BRD_V2_GPIO_NOALG) || (getBoardRevision() == BRD_V3_GPIO_NOALG))) // GPIO but NO analog support _rowSel--; // force skip if analog input is not supported by PCB LOWERLIMIT(_rowSel, 0); } @@ -311,7 +311,7 @@ CGPIOSetupScreen::keyHandler(uint8_t event) if(event & key_Up) { switch(_rowSel) { case 0: - if(getBoardRevision() == BRD_V2_GPIO_NOALG) // GPIO but NO Analog support + if((getBoardRevision() == BRD_V2_GPIO_NOALG) || (getBoardRevision() == BRD_V3_GPIO_NOALG)) // GPIO but NO Analog support _rowSel++; // force skip if analog input is not supported by PCB case 1: case 2: diff --git a/src/OLED/ScreenManager.cpp b/src/OLED/ScreenManager.cpp index e680087..f0ab13d 100644 --- a/src/OLED/ScreenManager.cpp +++ b/src/OLED/ScreenManager.cpp @@ -47,6 +47,7 @@ #include "MenuTrunkScreen.h" #include "MQTTScreen.h" #include "DS18B20Screen.h" +#include "TempSensorScreen.h" #include #include "../cfg/pins.h" #include "../cfg/BTCConfig.h" @@ -487,7 +488,10 @@ CScreenManager::_loadScreens() menuloop.push_back(new CWiFiScreen(*_pDisplay, *this)); menuloop.push_back(new CMQTTScreen(*_pDisplay, *this)); menuloop.push_back(new CBTScreen(*_pDisplay, *this)); - menuloop.push_back(new CDS18B20Screen(*_pDisplay, *this)); + if(getTempSensor().getBME280().getCount()) + menuloop.push_back(new CTempSensorScreen(*_pDisplay, *this)); + else + menuloop.push_back(new CDS18B20Screen(*_pDisplay, *this)); _Screens.push_back(menuloop); } @@ -504,6 +508,7 @@ CScreenManager::_loadScreens() menuloop.push_back(new CInheritSettingsScreen(*_pDisplay, *this)); // inherit OEM settings branch screen menuloop.push_back(new CFontDumpScreen(*_pDisplay, *this)); // font dump branch screen menuloop.push_back(new CSettingsScreen(*_pDisplay, *this)); // Tuning info + menuloop.push_back(new CDS18B20Screen(*_pDisplay, *this)); _Screens.push_back(menuloop); _menu = 0; @@ -681,6 +686,17 @@ CScreenManager::_leaveScreen() { if(_menu >= 0) _Screens[_menu][_subMenu]->onExit(); + + _returnMenu = _menu; + _returnSubMenu = _subMenu; +} + +void +CScreenManager::returnMenu() +{ + _menu = _returnMenu; + _subMenu = _returnSubMenu; + _enterScreen(); } void diff --git a/src/OLED/ScreenManager.h b/src/OLED/ScreenManager.h index 2ab39ff..eb80d9c 100644 --- a/src/OLED/ScreenManager.h +++ b/src/OLED/ScreenManager.h @@ -36,6 +36,8 @@ class CScreenManager { int _menu; int _subMenu; int _rootMenu; + int _returnMenu; + int _returnSubMenu; bool _bDimmed; bool _bReload; unsigned long _DimTime_ms; @@ -53,8 +55,8 @@ public: enum eUITimerMenus { TimerOverviewUI, Timer1UI, Timer2UI, Timer3UI, Timer4UI, Timer5UI, Timer6UI, Timer7UI, Timer8UI, Timer9UI, Timer10UI, Timer11UI, Timer12UI, Timer13UI, Timer14UI }; enum eUITuningMenus { MixtureUI, HeaterSettingsUI, FuelCalUI }; - enum eUIUserSettingsMenus { ExThermostatUI, HomeMenuUI, TimeIntervalsUI, GPIOUI }; - enum eUIBranchMenus { SetClockUI, InheritSettingsUI, FontDumpUI, HtrSettingsUI }; + enum eUIUserSettingsMenus { ExThermostatUI, HomeMenuUI, TimeIntervalsUI, TempSensorUI, GPIOUI }; + enum eUIBranchMenus { SetClockUI, InheritSettingsUI, FontDumpUI, HtrSettingsUI, DS18B20UI }; enum eUISystemSettingsMenus { SysVerUI, SysHoursUI, SysWifiUI, SysBTUI }; public: CScreenManager(); @@ -68,6 +70,7 @@ public: void prevMenu(); void reqUpdate(); void selectMenu(eUIMenuSets menuset, int specific = -1); // use to select loop menus, including the root or branches + void returnMenu(); // use to select loop menus, including the root or branches void showRebootMsg(const char* content[2], long delayTime); void showOTAMessage(int percent, eOTAmodes updateType); void clearDisplay(); diff --git a/src/OLED/TempSensorScreen.cpp b/src/OLED/TempSensorScreen.cpp new file mode 100644 index 0000000..dd64f75 --- /dev/null +++ b/src/OLED/TempSensorScreen.cpp @@ -0,0 +1,306 @@ +/* + * This file is part of the "bluetoothheater" distribution + * (https://gitlab.com/mrjones.id.au/bluetoothheater) + * + * Copyright (C) 2019 Ray Jones + * + * 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 . + * + */ + +#include "128x64OLED.h" +#include "TempSensorScreen.h" +#include "KeyPad.h" +#include "fonts/Icons.h" +#include "fonts/MiniFont.h" +#include "../Utility/TempSense.h" + + +CTempSensorScreen::CTempSensorScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr) +{ + _bHasBME280 = false; + _bHasDS18B20 = false; + _bPrimary = false; + _Offset = 0; + _initUI(); +} + +void +CTempSensorScreen::onSelect() +{ + CScreenHeader::onSelect(); + _initUI(); + _bHasBME280 = getTempSensor().getBME280().getCount() != 0; + _bHasDS18B20 = getTempSensor().getNumSensors() != 0; + _bPrimary = NVstore.getHeaterTuning().BME280probe.bPrimary; + _readNV(); +} + +void +CTempSensorScreen::_initUI() +{ + _rowSel = 0; + _colSel = 0; + _keyHold = -1; + _scrollChar = 0; +} + +bool +CTempSensorScreen::show() +{ + char msg[32]; + + _display.clearDisplay(); + + if(!CPasswordScreen::show()) { // for showing "saving settings" + + if(_rowSel == SaveConfirm) { + _showConfirmMessage(); + } + else { + if(_colSel == 0) + _showTitle("Temp Sensor Role"); + else + _showTitle("Temp Sensor Offset"); + + // force BME280 as primary if the only sensor + if(!_bHasDS18B20 && _bHasBME280) + _bPrimary = true; + + strcpy(msg, "Nul"); + + if(_bHasBME280) { + if(!_bPrimary && _bHasDS18B20) { + strcpy(msg, "Lst"); + } + else { + strcpy(msg, "Pri"); + } + } + int baseLine = 36; + _printMenuText(border, baseLine, msg, _rowSel == 1 && _colSel == 0); + + _printMenuText(27, baseLine, "BME280"); + if(_colSel == 0) { + float temperature; + getTempSensor().getBME280().getTemperature(temperature, false); + sprintf(msg, "%.01fC", temperature + _Offset); + } + else { + sprintf(msg, "%+.01f", _Offset); + } + _printMenuText(90, baseLine, msg, _rowSel == 1 && _colSel == 1); + + if(_bHasDS18B20) { + if(_bPrimary) { + strcpy(msg, "Nxt"); // BME280 is primary + } + else { + strcpy(msg, "Pri"); // DS18B20(s) are primary + } + int baseLine = 24; + _printMenuText(border, baseLine, msg, _rowSel == 2 && _colSel == 0); + + _printMenuText(27, baseLine, "DS18B20"); + _printMenuText(90, baseLine, "Edit", _rowSel == 2 && _colSel == 1); + } + + } + } + return true; +} + +bool +CTempSensorScreen::animate() +{ + if(!CPasswordScreen::_busy() && !CPasswordScreen::isPasswordBusy()) { + if(_rowSel != SaveConfirm) { + const char* pMsg = NULL; + switch(_rowSel) { + case 0: + _printMenuText(_display.xCentre(), 52, " \021 \030Edit Exit \020 ", true, eCentreJustify); + break; + case 1: + case 2: + case 3: + if(_colSel == 0) + pMsg = " Hold Right to adjust probe offset. "; + else + pMsg = " Hold Left to select probe's role. "; + break; + } + if(pMsg != NULL) { + _display.drawFastHLine(0, 52, 128, WHITE); + _scrollMessage(56, pMsg, _scrollChar); + } + return true; + } + } + return false; +} + + +bool +CTempSensorScreen::keyHandler(uint8_t event) +{ + if(CPasswordScreen::keyHandler(event)) { + if(_isPasswordOK()) { + _rowSel = 1; + _keyHold = -1; + } + } + + else { + sUserSettings us; + if(event & keyPressed) { + _keyHold = 0; + // DOWN press + if(event & key_Down) { + if(_rowSel == SaveConfirm) + _rowSel = 0; + _rowSel--; + LOWERLIMIT(_rowSel, 0); + } + } + + + if(event & keyRepeat) { + if(_keyHold >= 0) { + _keyHold++; + if(_keyHold == 2) { + if(event & key_Up) { + } + if(event & key_Left) { + _colSel = 0; + _scrollChar = 0; + } + if(event & key_Right) { + _colSel = 1; + _scrollChar = 0; + } + if(event & key_Centre) { + if(_colSel == 1) + _Offset = 0; + } + _keyHold = -1; + } + } + } + + + if(event & keyReleased) { + if(_keyHold == 0) { + // UP release + if(event & key_Up) { + if(_rowSel == SaveConfirm) { + _enableStoringMessage(); + _saveNV(); + NVstore.save(); + _rowSel = 0; + } + else { + if(_rowSel == 0) { + _getPassword(); + if(_isPasswordOK()) { + _rowSel = 1; + } + } + else { + _rowSel++; + if(_rowSel == 3) + _ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::DS18B20UI); // force return to main menu + + UPPERLIMIT(_rowSel, 2); + } + } + } + // LEFT press + if(event & key_Left) { + if(_rowSel == 0) + _ScreenManager.prevMenu(); + else + adjust(-1); + } + // RIGHT press + if(event & key_Right) { + if(_rowSel == 0) + _ScreenManager.nextMenu(); + else + adjust(+1); + } + // CENTRE press + if(event & key_Centre) { + if(_rowSel == 0) { + _ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu + } + else { + _rowSel = SaveConfirm; + } + } + } + _keyHold = -1; + } + + _ScreenManager.reqUpdate(); + } + + return true; +} + +void +CTempSensorScreen::adjust(int dir) +{ + switch(_rowSel) { + case 1: + if(_colSel == 0) { + _bPrimary = !_bPrimary; + } + else { + _Offset += dir * 0.1; + BOUNDSLIMIT(_Offset, -10, +10); + } + break; + case 2: + if(_colSel == 0) { + _bPrimary = !_bPrimary; + } + else { + _Offset += dir * 0.1; + BOUNDSLIMIT(_Offset, -10, +10); + } + break; + } +} + + + +void +CTempSensorScreen::_readNV() +{ + const sHeaterTuning& tuning = NVstore.getHeaterTuning(); + + _bPrimary = tuning.BME280probe.bPrimary; + _Offset = tuning.BME280probe.offset; +} + +void +CTempSensorScreen::_saveNV() +{ + sHeaterTuning tuning = NVstore.getHeaterTuning(); + + tuning.BME280probe.bPrimary = _bPrimary; + tuning.BME280probe.offset = _Offset; + + NVstore.setHeaterTuning(tuning); +} \ No newline at end of file diff --git a/src/OLED/TempSensorScreen.h b/src/OLED/TempSensorScreen.h new file mode 100644 index 0000000..4268cf1 --- /dev/null +++ b/src/OLED/TempSensorScreen.h @@ -0,0 +1,54 @@ +/* + * This file is part of the "bluetoothheater" distribution + * (https://gitlab.com/mrjones.id.au/bluetoothheater) + * + * Copyright (C) 2019 Ray Jones + * + * 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 . + * + */ + +#ifndef __TEMPSENSORSCREEN_H__ +#define __TEMPSENSORSCREEN_H__ + +#include +#include "PasswordScreen.h" +#include "../Utility/NVStorage.h" + +class C128x64_OLED; +class CScreenManager; + +class CTempSensorScreen : public CPasswordScreen +{ + int _rowSel, _colSel; + int _keyHold; + int _scrollChar; +// int _nNumSensors; + bool _bHasBME280; + bool _bHasDS18B20; + bool _bPrimary; + float _Offset; + void _initUI(); + void _readNV(); + void _saveNV(); +public: + CTempSensorScreen(C128x64_OLED& display, CScreenManager& mgr); + bool show(); + bool animate(); + bool keyHandler(uint8_t event); + void onSelect(); + void adjust(int dir); +}; + +#endif diff --git a/src/OLED/ThermostatModeScreen.cpp b/src/OLED/ThermostatModeScreen.cpp index 19b4002..18fcdf5 100644 --- a/src/OLED/ThermostatModeScreen.cpp +++ b/src/OLED/ThermostatModeScreen.cpp @@ -25,6 +25,7 @@ #include "../Utility/helpers.h" #include "../Utility/UtilClasses.h" #include "fonts/Icons.h" +#include "../Utility/BTC_GPIO.h" /////////////////////////////////////////////////////////////////////////// @@ -328,7 +329,7 @@ CThermostatModeScreen::_adjust(int dir) break; case 4: // thermostat mode _thermoMode += dir; - wrap = getExternalThermostatModeActive() ? 3 : 2; + wrap = GPIOin.usesExternalThermostat() ? 3 : 2; WRAPLIMITS(_thermoMode, 0, wrap); break; } diff --git a/src/OLED/VersionInfoScreen.cpp b/src/OLED/VersionInfoScreen.cpp index 3fe90a8..98b5f55 100644 --- a/src/OLED/VersionInfoScreen.cpp +++ b/src/OLED/VersionInfoScreen.cpp @@ -86,14 +86,18 @@ CVersionInfoScreen::show() int newVer = isUpdateAvailable(); _drawBitmap(18, 34, HardwareIconInfo); int PCB = getBoardRevision(); - _printMenuText(41, 38, getBoardRevisionString(PCB)); - if(PCB == BRD_V2_GPIO_NOALG) { - _display.fillRect(70, 36, 57, 11, WHITE); - _printInverted(99, 38, "No Analog", true, eCentreJustify); +// _printMenuText(41, 38, getBoardRevisionString(PCB)); + if(PCB == BRD_V2_GPIO_NOALG || PCB == BRD_V3_GPIO_NOALG) { + _display.fillRect(41, 36, 57, 11, WHITE); + _printInverted(70, 38, "No Analog", true, eCentreJustify); } - if(PCB == BRD_V2_NOGPIO) { - _display.fillRect(82, 36, 45, 11, WHITE); - _printInverted(105, 38, "No GPIO", true, eCentreJustify); + else if(PCB == BRD_V2_NOGPIO) { + _display.fillRect(41, 36, 45, 11, WHITE); + _printInverted(76, 38, "No GPIO", true, eCentreJustify); + } + else { + _display.fillRect(41, 36, 57, 11, WHITE); + _printInverted(70, 38, "Full GPIO", true, eCentreJustify); } if(_rowSel == 1 && newVer) { diff --git a/src/Utility/BTC_GPIO.h b/src/Utility/BTC_GPIO.h index 80b27f1..353bff9 100644 --- a/src/Utility/BTC_GPIO.h +++ b/src/Utility/BTC_GPIO.h @@ -216,4 +216,7 @@ struct sGPIO { } }; +extern CGPIOin GPIOin; +extern CGPIOout GPIOout; + #endif // __BTCGPIO_H__ diff --git a/src/Utility/BTC_JSON.cpp b/src/Utility/BTC_JSON.cpp index ad29d1b..0eba2c3 100644 --- a/src/Utility/BTC_JSON.cpp +++ b/src/Utility/BTC_JSON.cpp @@ -36,9 +36,8 @@ #include "../Protocol/Protocol.h" #include #include "HourMeter.h" -#include "Utility/TempSense.h" +#include "TempSense.h" -extern CTempSense TempSensor; extern CModerator MQTTmoderator; char defaultJSONstr[64]; @@ -145,21 +144,26 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len) if(tidyTemp > -80) { bSend |= moderator.addJson("TempCurrent", tidyTemp, root); } - if(TempSensor.getNumSensors() > 1) { - TempSensor.getTemperature(1, tidyTemp); - tidyTemp += NVstore.getHeaterTuning().tempProbe[1].offset; + if(getTempSensor().getNumSensors() > 1) { + getTempSensor().getTemperature(1, tidyTemp); tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution if(tidyTemp > -80) { bSend |= moderator.addJson("Temp2Current", tidyTemp, root); } - if(TempSensor.getNumSensors() > 2) { - TempSensor.getTemperature(2, tidyTemp); - tidyTemp += NVstore.getHeaterTuning().tempProbe[2].offset; + if(getTempSensor().getNumSensors() > 2) { + getTempSensor().getTemperature(2, tidyTemp); tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution if(tidyTemp > -80) { bSend |= moderator.addJson("Temp3Current", tidyTemp, root); } } + if(getTempSensor().getNumSensors() > 3) { + getTempSensor().getTemperature(3, tidyTemp); + tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution + if(tidyTemp > -80) { + bSend |= moderator.addJson("Temp4Current", tidyTemp, root); + } + } } bSend |= moderator.addJson("TempDesired", getTemperatureDesired(), root); bSend |= moderator.addJson("TempMode", NVstore.getUserSettings().degF, root); @@ -216,13 +220,14 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len) bSend |= moderator.addJson("PumpCal", NVstore.getHeaterTuning().pumpCal, root); // mL/stroke bSend |= moderator.addJson("LowVoltCutout", NVstore.getHeaterTuning().getLVC(), root); // low voltage cutout } - bSend |= moderator.addJson("TempOffset", NVstore.getHeaterTuning().tempProbe[0].offset, root); // degC offset - if(TempSensor.getNumSensors() > 1) { - bSend |= moderator.addJson("Temp2Offset", NVstore.getHeaterTuning().tempProbe[1].offset, root); // degC offset - if(TempSensor.getNumSensors() > 2) - bSend |= moderator.addJson("Temp3Offset", NVstore.getHeaterTuning().tempProbe[2].offset, root); // degC offset + bSend |= moderator.addJson("TempOffset", getTempSensor().getOffset(0), root); // degC offset + if(getTempSensor().getNumSensors() > 1) { + bSend |= moderator.addJson("Temp2Offset", getTempSensor().getOffset(1), root); // degC offset + if(getTempSensor().getNumSensors() > 2) + bSend |= moderator.addJson("Temp3Offset", getTempSensor().getOffset(2), root); // degC offset + if(getTempSensor().getNumSensors() > 3) + bSend |= moderator.addJson("Temp4Offset", getTempSensor().getOffset(3), root); // degC offset } - if(bSend) { root.printTo(opStr, len); } @@ -274,6 +279,11 @@ bool makeJSONStringGPIO(CModerator& moderator, char* opStr, int len) bSend |= moderator.addJson("GPmodeOut2", GPIOout2Names[info.out2Mode], root); bSend |= moderator.addJson("GPmodeAnlg", GPIOalgNames[info.algMode], root); bSend |= moderator.addJson("ExtThermoTmout", (uint32_t)NVstore.getUserSettings().ExtThermoTimeout, root); + const char* stop = getExternalThermostatHoldTime(); + if(stop) + bSend |= moderator.addJson("ExtThermoStop", stop, root); + else + bSend |= moderator.addJson("ExtThermoStop", "Off", root); if(bSend) { root.printTo(opStr, len); @@ -297,7 +307,7 @@ bool makeJSONStringMQTT(CModerator& moderator, char* opStr, int len) bSend |= moderator.addJson("MUser", info.username, root); bSend |= moderator.addJson("MPasswd", info.password, root); bSend |= moderator.addJson("MQoS", info.qos, root); - bSend |= moderator.addJson("MTopic", info.topic, root); + bSend |= moderator.addJson("MTopic", info.topicPrefix, root); if(bSend) { root.printTo(opStr, len); diff --git a/src/Utility/BoardDetect.cpp b/src/Utility/BoardDetect.cpp index 3398097..ffb6c47 100644 --- a/src/Utility/BoardDetect.cpp +++ b/src/Utility/BoardDetect.cpp @@ -52,11 +52,12 @@ // Input state truth table // GPIO25 GPIO26 GPIO33 // ------ ------ ------ -// V1.0 HIGH HIGH HIGH -// unmodified V2.0 LOW HIGH LOW -// modified V2.0 LOW LOW HIGH -// V2.1 LOW LOW HIGH -// No GPIO V2.0 HIGH LOW HIGH +// V1.0 HIGH HIGH HIGH - green V1 PCB +// unmodified V2.0 LOW HIGH LOW - digital only (V2 PCB) +// modified V2.0 LOW LOW HIGH - full GPIO (V2 or V3 PCB) +// V2.1 LOW LOW HIGH - digital only (modified V2 PCB) +// No GPIO V2.0 HIGH LOW HIGH - no GPIO (V2 or V3 PCB, 0R in C6) +// V2.1 LOW LOW LOW - digital only (V3 PCB, 0R in C6) // // // **************************************************************************************** @@ -114,10 +115,10 @@ int BoardDetect() revision = BRD_V2_GPIO_NOALG; DebugPort.println("Board detect: digital input test reveals V2.0 PCB - Digital only GPIO (V2.1 userID)"); } - // original V2 PCB, no traces cut n shunted, pin 26 grounded via 0R instead of 100n cap, dig inputs pulled low by transistors + // V3 PCB, no traces cut n shunted, pin 26 grounded via 0R instead of 100n cap, dig inputs pulled low by transistors else if((pin33 == LOW) && (pin26 == LOW) && (pin25 == LOW)) { - revision = BRD_V2_GPIO_NOALG; - DebugPort.println("Board detect: digital input test reveals V2.0 PCB - Digital only GPIO (V2.1 userID)"); + revision = BRD_V3_GPIO_NOALG; + DebugPort.println("Board detect: digital input test reveals V3.0 PCB - Digital only GPIO (V2.1 userID)"); } // original V2 PCB, pin 26 grounded via 0R instead of 100n cap, digio transistors not fitted dig in pins pull high else if((pin33 == HIGH) && (pin26 == LOW) && (pin25 == HIGH)) { @@ -153,6 +154,7 @@ const char* getBoardRevisionString(int ID) case BRD_V2_FULLGPIO: return "V2.2"; case BRD_V2_NOGPIO: return "V2.0"; case BRD_V2_GPIO_NOALG: return "V2.1"; + case BRD_V3_GPIO_NOALG: return "V2.1"; default: return "???"; } } diff --git a/src/Utility/BoardDetect.h b/src/Utility/BoardDetect.h index c2cf380..47c3478 100644 --- a/src/Utility/BoardDetect.h +++ b/src/Utility/BoardDetect.h @@ -33,6 +33,7 @@ #define BRD_V2_GPIO_NOALG 20 // original V20 board - no cut traces - analog on wrong pin :-( #define BRD_V2_FULLGPIO 21 // V2 board cut traces tranposed GPIO1 & Analog #define BRD_V2_NOGPIO 22 // V2 board forced short on analog input - NO GPIO mode +#define BRD_V3_GPIO_NOALG 30 // V3 board - no cut traces - analog input grounded int BoardDetect(); void BoardRevisionReset(); diff --git a/src/Utility/MQTTsetup.cpp b/src/Utility/MQTTsetup.cpp index 3bd536d..98570cf 100644 --- a/src/Utility/MQTTsetup.cpp +++ b/src/Utility/MQTTsetup.cpp @@ -49,7 +49,7 @@ CMQTTsetup::showMQTTmenu(bool init) DebugPort.printf(" <2> - set port, currently %d\r\n", _MQTTsetup.port); DebugPort.printf(" <3> - set username, currently \"%s\"\r\n", _MQTTsetup.username); DebugPort.printf(" <4> - set password, currently \"%s\"\r\n", _MQTTsetup.password); - DebugPort.printf(" <5> - set root topic, currently \"%s\"\r\n", _MQTTsetup.topic); + DebugPort.printf(" <5> - set root topic, currently \"%s\"\r\n", _MQTTsetup.topicPrefix); DebugPort.printf(" <6> - set QoS, currently %d\r\n", _MQTTsetup.qos); DebugPort.printf(" <7> - set enabled, currently %s\r\n", _MQTTsetup.enabled ? "ON" : "OFF"); DebugPort.printf(" - save and exit\r\n"); @@ -92,7 +92,7 @@ CMQTTsetup::HandleMQTTsetup(char rxVal) case 2: DebugPort.printf("Enter MQTT broker's port (%d)", _MQTTsetup.port); break; case 3: DebugPort.printf("Enter MQTT broker's username (%s)", _MQTTsetup.username); break; case 4: DebugPort.printf("Enter MQTT broker's password (%s)", _MQTTsetup.password); break; - case 5: DebugPort.printf("Enter root topic name (%s)", _MQTTsetup.topic); break; + case 5: DebugPort.printf("Enter root topic name (%s)", _MQTTsetup.topicPrefix); break; case 6: DebugPort.printf("Enter QoS level (%d)", _MQTTsetup.qos); break; case 7: DebugPort.printf("Enable MQTT? (Y)es / (N)o (%s)", _MQTTsetup.enabled ? "YES" : "NO"); break; } @@ -145,7 +145,7 @@ CMQTTsetup::HandleMQTTsetup(char rxVal) } break; case 5: // enter root topic name - if(getMQTTstring(rxVal, 31, _MQTTsetup.topic)) { + if(getMQTTstring(rxVal, 31, _MQTTsetup.topicPrefix)) { bJumptoMQTTmenuRoot = true; } break; diff --git a/src/Utility/NVStorage.cpp b/src/Utility/NVStorage.cpp index d722c38..4c419bb 100644 --- a/src/Utility/NVStorage.cpp +++ b/src/Utility/NVStorage.cpp @@ -265,23 +265,25 @@ sHeaterTuning::load() else validatedLoad("lowVolts", lowVolts, 230, u8inBoundsOrZero, 200, 250); validatedLoad("pumpCal", pumpCal, 0.02, 0.001, 1); - validatedLoad("tempOffset0", tempProbe[0].offset, 0.0, -10.0, +10.0); - validatedLoad("tempOffset1", tempProbe[1].offset, 0.0, -10.0, +10.0); - validatedLoad("tempOffset2", tempProbe[2].offset, 0.0, -10.0, +10.0); - preferences.getBytes("probeSerial0", tempProbe[0].romCode.bytes, 8); - preferences.getBytes("probeSerial1", tempProbe[1].romCode.bytes, 8); - preferences.getBytes("probeSerial2", tempProbe[2].romCode.bytes, 8); + validatedLoad("tempOffset0", DS18B20probe[0].offset, 0.0, -10.0, +10.0); + validatedLoad("tempOffset1", DS18B20probe[1].offset, 0.0, -10.0, +10.0); + validatedLoad("tempOffset2", DS18B20probe[2].offset, 0.0, -10.0, +10.0); + preferences.getBytes("probeSerial0", DS18B20probe[0].romCode.bytes, 8); + preferences.getBytes("probeSerial1", DS18B20probe[1].romCode.bytes, 8); + preferences.getBytes("probeSerial2", DS18B20probe[2].romCode.bytes, 8); + validatedLoad("tempOffsetBME", BME280probe.offset, 0.0, -10.0, +10.0); + validatedLoad("probeBMEPrmy", BME280probe.bPrimary, 0, u8inBounds, 0, 1); preferences.end(); // for(int i=0; i<3; i++) { // DebugPort.printf("Rd Probe[%d] %02X:%02X:%02X:%02X:%02X:%02X\r\n", // i, - // tempProbe[i].romCode.fields.serial_number[5], - // tempProbe[i].romCode.fields.serial_number[4], - // tempProbe[i].romCode.fields.serial_number[3], - // tempProbe[i].romCode.fields.serial_number[2], - // tempProbe[i].romCode.fields.serial_number[1], - // tempProbe[i].romCode.fields.serial_number[0] + // DS18B20probe[i].romCode.fields.serial_number[5], + // DS18B20probe[i].romCode.fields.serial_number[4], + // DS18B20probe[i].romCode.fields.serial_number[3], + // DS18B20probe[i].romCode.fields.serial_number[2], + // DS18B20probe[i].romCode.fields.serial_number[1], + // DS18B20probe[i].romCode.fields.serial_number[0] // ); // } } @@ -301,23 +303,25 @@ sHeaterTuning::save() preferences.putUChar("glowDrive", glowDrive); preferences.putUChar("lowVolts", lowVolts); preferences.putFloat("pumpCal", pumpCal); - preferences.putFloat("tempOffset0", tempProbe[0].offset); - preferences.putFloat("tempOffset1", tempProbe[1].offset); - preferences.putFloat("tempOffset2", tempProbe[2].offset); - preferences.putBytes("probeSerial0", tempProbe[0].romCode.bytes, 8); - preferences.putBytes("probeSerial1", tempProbe[1].romCode.bytes, 8); - preferences.putBytes("probeSerial2", tempProbe[2].romCode.bytes, 8); + preferences.putFloat("tempOffset0", DS18B20probe[0].offset); + preferences.putFloat("tempOffset1", DS18B20probe[1].offset); + preferences.putFloat("tempOffset2", DS18B20probe[2].offset); + preferences.putBytes("probeSerial0", DS18B20probe[0].romCode.bytes, 8); + preferences.putBytes("probeSerial1", DS18B20probe[1].romCode.bytes, 8); + preferences.putBytes("probeSerial2", DS18B20probe[2].romCode.bytes, 8); + preferences.putFloat("tempOffsetBME", BME280probe.offset); + preferences.putUChar("probeBMEPrmy", BME280probe.bPrimary); preferences.end(); // for(int i=0; i<3; i++) { // DebugPort.printf("Wr Probe[%d] %02X:%02X:%02X:%02X:%02X:%02X\r\n", // i, - // tempProbe[i].romCode.fields.serial_number[5], - // tempProbe[i].romCode.fields.serial_number[4], - // tempProbe[i].romCode.fields.serial_number[3], - // tempProbe[i].romCode.fields.serial_number[2], - // tempProbe[i].romCode.fields.serial_number[1], - // tempProbe[i].romCode.fields.serial_number[0] + // DS18B20probe[i].romCode.fields.serial_number[5], + // DS18B20probe[i].romCode.fields.serial_number[4], + // DS18B20probe[i].romCode.fields.serial_number[3], + // DS18B20probe[i].romCode.fields.serial_number[2], + // DS18B20probe[i].romCode.fields.serial_number[1], + // DS18B20probe[i].romCode.fields.serial_number[0] // ); // } } @@ -471,7 +475,7 @@ sMQTTparams::load() validatedLoad("host", host, 127, ""); validatedLoad("username", username, 31, ""); validatedLoad("password", password, 31, ""); - validatedLoad("topic", topic, 31, "Afterburner"); + validatedLoad("topic", topicPrefix, 31, "Afterburner"); preferences.end(); } @@ -486,7 +490,7 @@ sMQTTparams::save() preferences.putString("host", host); preferences.putString("username", username); preferences.putString("password", password); - preferences.putString("topic", topic); + preferences.putString("topic", topicPrefix); preferences.end(); } diff --git a/src/Utility/NVStorage.h b/src/Utility/NVStorage.h index 9ede59a..73e46cc 100644 --- a/src/Utility/NVStorage.h +++ b/src/Utility/NVStorage.h @@ -24,19 +24,24 @@ #include "BTC_GPIO.h" #include "NVCore.h" -#include "../Utility/helpers.h" -#include "Utility/TempSense.h" +#include "helpers.h" +#include "TempSense.h" #include "../RTC/Timers.h" // for sTimer void toggle(bool& ref); void toggle(uint8_t& ref); -struct sProbeTuning { +struct sDS18B20ProbeTuning { float offset; OneWireBus_ROMCode romCode; }; +struct sBM280tuning { + float offset; + uint8_t bPrimary; +}; + struct sHeaterTuning : public CESP32_NVStorage { uint8_t Pmin; uint8_t Pmax; @@ -47,7 +52,8 @@ struct sHeaterTuning : public CESP32_NVStorage { uint8_t glowDrive; uint8_t lowVolts; // x10 float pumpCal; - sProbeTuning tempProbe[3]; // [0],[1],[2] - Primary, Secondary, Tertiary + sDS18B20ProbeTuning DS18B20probe[3]; // [0],[1],[2] - Primary, Secondary, Tertiary + sBM280tuning BME280probe; bool valid() { bool retval = true; @@ -63,9 +69,10 @@ struct sHeaterTuning : public CESP32_NVStorage { retval &= INBOUNDS(lowVolts, 100, 125) || (lowVolts == 0); else retval &= INBOUNDS(lowVolts, 200, 250 || (lowVolts == 0)); - retval &= INBOUNDS(tempProbe[0].offset, -10, +10); - retval &= INBOUNDS(tempProbe[1].offset, -10, +10); - retval &= INBOUNDS(tempProbe[2].offset, -10, +10); + retval &= INBOUNDS(DS18B20probe[0].offset, -10, +10); + retval &= INBOUNDS(DS18B20probe[1].offset, -10, +10); + retval &= INBOUNDS(DS18B20probe[2].offset, -10, +10); + retval &= INBOUNDS(BME280probe.offset, -10, +10); return retval; }; void init() { @@ -78,12 +85,14 @@ struct sHeaterTuning : public CESP32_NVStorage { glowDrive = 5; pumpCal = 0.02; lowVolts = 115; - tempProbe[0].offset = 0; - tempProbe[1].offset = 0; - tempProbe[2].offset = 0; - memset(tempProbe[0].romCode.bytes, 0, sizeof(tempProbe[0].romCode)); - memset(tempProbe[1].romCode.bytes, 0, sizeof(tempProbe[1].romCode)); - memset(tempProbe[2].romCode.bytes, 0, sizeof(tempProbe[1].romCode)); + DS18B20probe[0].offset = 0; + DS18B20probe[1].offset = 0; + DS18B20probe[2].offset = 0; + memset(DS18B20probe[0].romCode.bytes, 0, sizeof(DS18B20probe[0].romCode)); + memset(DS18B20probe[1].romCode.bytes, 0, sizeof(DS18B20probe[1].romCode)); + memset(DS18B20probe[2].romCode.bytes, 0, sizeof(DS18B20probe[2].romCode)); + BME280probe.offset = 0; + BME280probe.bPrimary = false; }; void load(); void save(); @@ -97,12 +106,14 @@ struct sHeaterTuning : public CESP32_NVStorage { glowDrive = rhs.glowDrive; pumpCal = rhs.pumpCal; lowVolts = rhs.lowVolts; - tempProbe[0].offset = rhs.tempProbe[0].offset; - tempProbe[1].offset = rhs.tempProbe[1].offset; - tempProbe[2].offset = rhs.tempProbe[2].offset; - memcpy(tempProbe[0].romCode.bytes, rhs.tempProbe[0].romCode.bytes, 8); - memcpy(tempProbe[1].romCode.bytes, rhs.tempProbe[1].romCode.bytes, 8); - memcpy(tempProbe[2].romCode.bytes, rhs.tempProbe[2].romCode.bytes, 8); + DS18B20probe[0].offset = rhs.DS18B20probe[0].offset; + DS18B20probe[1].offset = rhs.DS18B20probe[1].offset; + DS18B20probe[2].offset = rhs.DS18B20probe[2].offset; + memcpy(DS18B20probe[0].romCode.bytes, rhs.DS18B20probe[0].romCode.bytes, 8); + memcpy(DS18B20probe[1].romCode.bytes, rhs.DS18B20probe[1].romCode.bytes, 8); + memcpy(DS18B20probe[2].romCode.bytes, rhs.DS18B20probe[2].romCode.bytes, 8); + BME280probe.offset = rhs.BME280probe.offset; + BME280probe.bPrimary = rhs.BME280probe.bPrimary; return *this; } float getPmin() const; diff --git a/src/Utility/TempSense.cpp b/src/Utility/TempSense.cpp index 1307991..8c54c34 100644 --- a/src/Utility/TempSense.cpp +++ b/src/Utility/TempSense.cpp @@ -24,38 +24,120 @@ #include "TempSense.h" #include "DebugPort.h" #include "macros.h" +#include "NVStorage.h" -CTempSense::CTempSense() +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// DS18B20 probe support +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +CDS18B20probe::CDS18B20probe() +{ + pSensorInfo = NULL; + init(); +} + +void +CDS18B20probe::init() +{ + release(); + reading = -100; + error = DS18B20_ERROR_UNKNOWN; + holdoff = 3; + filter.reset(0); +} + +void +CDS18B20probe::release() +{ + if(pSensorInfo) + ds18b20_free(&pSensorInfo); + pSensorInfo = NULL; +} + +bool +CDS18B20probe::readSensor() +{ + bool retval = false; + + error = DS18B20_ERROR_UNKNOWN; + + error = ds18b20_read_temp(pSensorInfo, &reading); + if(error == DS18B20_OK) { + if(holdoff) { + holdoff--; + if(holdoff == 0) { + filter.reset(reading); + } + error = DS18B20_ERROR_DEVICE; // avoid allowing initial readings + } + else { + filter.update(reading); + retval = true; + } + } + else { + holdoff = 3; + filter.reset(-100); + } + + return retval; +} + +float +CDS18B20probe::getReading(bool filtered) +{ + if(filtered) + return filter.getValue(); + else + return reading; +} + +/*bool +CDS18B20probe::setROMcode(OneWireBus_ROMCode rom_code) +{ + if(pSensor) { + pSensor->rom_code = rom_code; + return true; + } + return false; +}*/ + +OneWireBus_ROMCode +CDS18B20probe::getROMcode() const +{ + if(pSensorInfo) + return pSensorInfo->rom_code; + else { + OneWireBus_ROMCode nullROM = {0}; + return nullROM; + } +} + +bool +CDS18B20probe::matchROMcode(uint8_t test[8]) +{ + if(pSensorInfo) + return memcmp(pSensorInfo->rom_code.bytes, test, 8) == 0; + return false; +} + +CDS18B20Sensor::CDS18B20Sensor() { _owb = NULL; _nNumSensors = 0; for(int i=0; i< MAX_DS18B20_DEVICES; i++) - _Sensors[i] = NULL; + _Sensors[i].init(); + for(int i=0; i<3; i++) _sensorMap[i] = -1; } -#ifdef SINGLE_DS18B20_SENSOR -void CTempSense::begin(int pin) -{ - // initialise DS18B20 sensor interface - // create one wire bus interface, using RMT peripheral - pinMode(pin, INPUT_PULLUP); - _owb = owb_rmt_initialize(&_rmt_driver_info, pin, RMT_CHANNEL_1, RMT_CHANNEL_0); - owb_use_crc(_owb, true); // enable CRC check for ROM code - -// bool found = find(); - delay(10); // couple of glitches take place during pin setup - give a bit of space to avoid no sensor issues? - - bool found = readROMcode(); - - // Create DS18B20 device on the 1-Wire bus - if(found) { - attach(); - } -} -#else -void CTempSense::begin(int pin) +void +CDS18B20Sensor::begin(int pin) { // initialise DS18B20 sensor interface @@ -65,47 +147,9 @@ void CTempSense::begin(int pin) find(); } -#endif -#ifdef SINGLE_DS18B20_SENSOR bool -CTempSense::readSensors(float& tempReading) -{ - if(_Sensors[0] == NULL) { - -// bool found = find(); - bool found = readROMcode(); - - if(found) { - DebugPort.println("Found DS18B20 device"); - -// readROMcode(); - - attach(); - - startConvert(); // request a new conversion, - waitConvertDone(); - } - } - - if(_Sensors[0] != NULL) { - DS18B20_ERROR error = ds18b20_read_temp(_Sensors[0], &tempReading); -// DebugPort.printf(">>>> DS18B20 = %f, error=%d\r\n", fTemperature, error); - - if(error == DS18B20_OK) { - return true; - } - else { - DebugPort.println("\007DS18B20 sensor removed?"); - ds18b20_free(&_Sensors[0]); - } - } - - return false; -} -#else -bool -CTempSense::readSensors() +CDS18B20Sensor::readSensors() { bool retval = false; @@ -123,18 +167,18 @@ CTempSense::readSensors() if(_nNumSensors) { for (int i = 0; i < MAX_DS18B20_DEVICES; ++i) { - _Errors[i] = DS18B20_ERROR_UNKNOWN; + _Sensors[i].setError(DS18B20_ERROR_UNKNOWN); } for (int i = 0; i < _nNumSensors; ++i) { - _Errors[i] = ds18b20_read_temp(_Sensors[i], &_Readings[i]); + _Sensors[i].readSensor(); } #ifdef REPORT_READINGS DebugPort.println("\nTemperature readings (degrees C)"); #endif for (int i = 0; i < _nNumSensors; ++i) { - if(_Errors[i] == DS18B20_OK) { + if(_Sensors[i].OK()) { #ifdef REPORT_READINGS DebugPort.printf(" %d: %.1f OK\r\n", i, _Readings[i]); #endif @@ -150,34 +194,15 @@ CTempSense::readSensors() return retval; } -#endif -#ifdef SINGLE_DS18B20_SENSOR bool -CTempSense::find() -{ - // Find all connected devices -// DebugPort.printf("Finding one wire bus devices..."); - _nNumSensors = 0; - OneWireBus_SearchState search_state = {0}; - bool found = false; - owb_search_first(_owb, &search_state, &found); - if(found) { - _nNumSensors = 1; - DebugPort.println("Found a one wire device"); - } - else - DebugPort.println("No one wire devices found!!"); - - return found; -} -#else -bool -CTempSense::find() +CDS18B20Sensor::find() { // Find all connected devices DebugPort.println("Finding one wire bus devices..."); - memset(_device_rom_codes, 0, sizeof(_device_rom_codes)); + OneWireBus_ROMCode rom_codes[MAX_DS18B20_DEVICES]; + memset(&rom_codes, 0, sizeof(rom_codes)); + _nNumSensors = 0; OneWireBus_SearchState search_state = {0}; @@ -188,33 +213,32 @@ CTempSense::find() owb_string_from_rom_code(search_state.rom_code, rom_code_s, sizeof(rom_code_s)); DebugPort.printf(" %d : %s\r\n", _nNumSensors, rom_code_s); - _device_rom_codes[_nNumSensors] = search_state.rom_code; + rom_codes[_nNumSensors] = search_state.rom_code; _nNumSensors++; owb_search_next(_owb, &search_state, &found); } - DebugPort.printf("Found %d device%s\r\n", _nNumSensors, _nNumSensors==1 ? "" : "s"); + DebugPort.printf("Found %d DS18B20 device%s\r\n", _nNumSensors, _nNumSensors==1 ? "" : "s"); // Create DS18B20 devices on the 1-Wire bus for (int i = 0; i < MAX_DS18B20_DEVICES; ++i) { - if(_Sensors[i]) { - ds18b20_free(&_Sensors[i]); - } - _Sensors[i] = NULL; + _Sensors[i].release(); } for (int i = 0; i < _nNumSensors; ++i) { DS18B20_Info * ds18b20_info = ds18b20_malloc(); // heap allocation - _Sensors[i] = ds18b20_info; + _Sensors[i].assign(ds18b20_info); if (_nNumSensors == 1) { - printf("Single device optimisations enabled\n"); - ds18b20_init_solo(ds18b20_info, _owb); // only one device on bus - ds18b20_info->rom_code = _device_rom_codes[i]; // added, for GUI setup!! + printf("DS18B20 Single device optimisations enabled\n"); + ds18b20_init_solo(ds18b20_info, _owb); // only one device on bus +// ds18b20_info->rom_code = _Sensors[i].getROMcode(); // added, for GUI setup!! + ds18b20_info->rom_code = rom_codes[0]; // added, for GUI setup!! } else { - ds18b20_init(ds18b20_info, _owb, _device_rom_codes[i]); // associate with bus and device +// ds18b20_init(ds18b20_info, _owb, _Sensors[i].getROMcode()); // associate with bus and device + ds18b20_init(ds18b20_info, _owb, rom_codes[i]); // associate with bus and device } ds18b20_use_crc(ds18b20_info, true); // enable CRC check for temperature readings ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION_12_BIT); @@ -222,61 +246,24 @@ CTempSense::find() return found; } -#endif - -#ifdef SINGLE_DS18B20_SENSOR -bool -CTempSense::readROMcode() -{ - // For a single device only: - OneWireBus_ROMCode rom_code; - owb_status status = owb_read_rom(_owb, &rom_code); - if (status == OWB_STATUS_OK) - { - char rom_code_s[OWB_ROM_CODE_STRING_LENGTH]; - owb_string_from_rom_code(rom_code, rom_code_s, sizeof(rom_code_s)); - DebugPort.printf("Device %s present\r\n", rom_code_s); - return true; - } - else - { - DebugPort.printf("Error #%d occurred attempting to read ROM code\r\n", status); - return false; - } -} - -bool -CTempSense::attach() -{ - if(_Sensors[0] == NULL) { - _Sensors[0] = ds18b20_malloc(); // heap allocation - - DebugPort.printf("Single device optimisations enabled\r\n"); - ds18b20_init_solo(_Sensors[0], _owb); // only one device on bus - ds18b20_use_crc(_Sensors[0], true); // enable CRC check for temperature readings - ds18b20_set_resolution(_Sensors[0], DS18B20_RESOLUTION_12_BIT); - } - return true; -} -#endif void -CTempSense::startConvert() +CDS18B20Sensor::startConvert() { // kick off the initial temperature conversion - if(_Sensors[0]) + if(_Sensors[0].getSensorInfo()) ds18b20_convert_all(_owb); } void -CTempSense::waitConvertDone() +CDS18B20Sensor::waitConvertDone() { - if(_Sensors[0]) - ds18b20_wait_for_conversion(_Sensors[0]); + if(_Sensors[0].getSensorInfo()) + ds18b20_wait_for_conversion(_Sensors[0].getSensorInfo()); } int -CTempSense::checkNumSensors() const +CDS18B20Sensor::checkNumSensors() const { long start = millis(); bool found = false; @@ -294,7 +281,7 @@ CTempSense::checkNumSensors() const } bool -CTempSense::mapSensor(int idx, OneWireBus_ROMCode romCode) +CDS18B20Sensor::mapSensor(int idx, OneWireBus_ROMCode romCode) { if(idx == -1) { _sensorMap[0] = _sensorMap[1] = _sensorMap[2] = -1; @@ -310,7 +297,7 @@ CTempSense::mapSensor(int idx, OneWireBus_ROMCode romCode) return false; for(int i = 0; i < _nNumSensors; i++) { - if(memcmp(_Sensors[i]->rom_code.bytes, romCode.bytes, 8) == 0) { + if(_Sensors[i].matchROMcode(romCode.bytes)) { _sensorMap[idx] = i; DebugPort.printf("Mapped DS18B20 %02X:%02X:%02X:%02X:%02X:%02X as role %d\r\n", romCode.fields.serial_number[5], @@ -328,28 +315,241 @@ CTempSense::mapSensor(int idx, OneWireBus_ROMCode romCode) } bool -CTempSense::getTemperature(int mapIdx, float& temperature) +CDS18B20Sensor::getTemperature(int usrIdx, float& temperature, bool filtered) { - int snsIdx = _sensorMap[mapIdx]; + int snsIdx = _sensorMap[usrIdx]; if(snsIdx < 0) snsIdx = 0; // default to sensor 0 if not mapped - return getTemperatureIdx(snsIdx, temperature); + return getTemperatureIdx(snsIdx, temperature, filtered); } bool -CTempSense::getTemperatureIdx(int snsIdx, float& temperature) +CDS18B20Sensor::getTemperatureIdx(int snsIdx, float& temperature, bool filtered) { - temperature = _Readings[snsIdx]; - return _Errors[snsIdx] == DS18B20_OK; + if(_Sensors[snsIdx].OK()) { + temperature = _Sensors[snsIdx].getReading(filtered); + temperature += NVstore.getHeaterTuning().DS18B20probe[snsIdx].offset; + return true; + } + else { + temperature = -100; + return false; + } } bool -CTempSense::getRomCodeIdx(int snsIdx, OneWireBus_ROMCode& romCode) +CDS18B20Sensor::getRomCodeIdx(int snsIdx, OneWireBus_ROMCode& romCode) const { if(snsIdx >= _nNumSensors) return false; - romCode = _Sensors[snsIdx]->rom_code; +// romCode = _Sensors[snsIdx].sensor->rom_code; + romCode = _Sensors[snsIdx].getROMcode(); return true; } + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// BME-280 probe support +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + +CBME280Sensor::CBME280Sensor() +{ + _count = 0; +} + +bool +CBME280Sensor::begin(int ID) +{ + _count = 0; + bool status = _bme.begin(ID); + if (!status) { + DebugPort.println("Could not find a valid BME280 sensor, check wiring!"); + return false; + } + _count = 1; + _bme.setSampling(Adafruit_BME280::MODE_FORCED, + Adafruit_BME280::SAMPLING_X1, + Adafruit_BME280::SAMPLING_X1, + Adafruit_BME280::SAMPLING_X1, + Adafruit_BME280::FILTER_OFF, + Adafruit_BME280::STANDBY_MS_1000); + + _lastSampleTime = millis(); + + return true; +} + +bool +CBME280Sensor::getTemperature(float& tempReading, bool filtered) +{ + if(_count == 0) { + tempReading = -100; + return false; + } + + long tDelta = millis() - _lastSampleTime; + if(tDelta >= 0) { + _bme.takeForcedMeasurement(); + _lastTemperature = _bme.readTemperature(); + _lastSampleTime = millis() + 1000; + } + if(filtered) + tempReading = _Filter.getValue(); + else + tempReading = _lastTemperature; + tempReading += NVstore.getHeaterTuning().BME280probe.offset;; + + return true; +} + +const char* +CBME280Sensor::getID() +{ + return "BME-280"; +} + + +CTempSense::CTempSense() +{ +} + +void +CTempSense::begin(int oneWirePin, int I2CID) +{ + DS18B20.begin(oneWirePin); + BME280.begin(I2CID); +} + +int +CTempSense::getNumSensors() const +{ + int retval = 0; + + retval += DS18B20.getNumSensors(); + retval += BME280.getCount(); + + return retval; +} + +void +CTempSense::startConvert() +{ + DS18B20.startConvert(); +} + +bool +CTempSense::readSensors() +{ + return DS18B20.readSensors(); +} + +float +CTempSense::getOffset(int usrIdx) +{ + // no BME280 sensor? extract from DS18B20 + if(BME280.getCount() == 0) { + if(INBOUNDS(usrIdx, 0, 2)) { + return NVstore.getHeaterTuning().DS18B20probe[usrIdx].offset; + } + } + + if(NVstore.getHeaterTuning().BME280probe.bPrimary) { + // BME is primary sensor, index 0 => use BME meta data + if(usrIdx == 0) { + return NVstore.getHeaterTuning().BME280probe.offset; + } + usrIdx--; + if(INBOUNDS(usrIdx, 0, 2)) { + return NVstore.getHeaterTuning().DS18B20probe[usrIdx].offset; + } + } + else { + // BME is after the DS18B20s + if(usrIdx >= DS18B20.getNumSensors()) { + // assume any more than connected DS18B20 is the BME + return NVstore.getHeaterTuning().BME280probe.offset; + } + if(INBOUNDS(usrIdx, 0, 2)) { + return NVstore.getHeaterTuning().DS18B20probe[usrIdx].offset; + } + } + return 0; // catch for invalid index +} + +void +CTempSense::setOffset(int usrIdx, float offset) +{ + if(!INBOUNDS(offset, -10.0, +10.0)) { + return; + } + + sHeaterTuning ht = NVstore.getHeaterTuning(); + + if(BME280.getCount() == 0) { + // no BME280 present - simply apply to DS18B20 list + if(INBOUNDS(usrIdx, 0, 2)) + ht.DS18B20probe[usrIdx].offset = offset; + } + else { + // BME280 present + // need to change behvaiour depending if the BME is primary + if(NVstore.getHeaterTuning().BME280probe.bPrimary) { + // BME is primary - usrIdx 0 is BME, 1 is first DS18B20 + if(usrIdx == 0) { + ht.BME280probe.offset = offset; + } + else { + usrIdx--; + if(INBOUNDS(usrIdx, 0, 2)) + ht.DS18B20probe[usrIdx].offset = offset; + } + } + else { + // BME is after DS18B20s + // note the index for the BME depends upon how many DS18B20s are connected! + if(usrIdx >= DS18B20.getNumSensors()) { + // assume any more than connected DS18B20 is the BME + ht.BME280probe.offset = offset; + } + else { + if(INBOUNDS(usrIdx, 0, 2)) + ht.DS18B20probe[usrIdx].offset = offset; + } + } + } + + NVstore.setHeaterTuning(ht); +} + + +bool +CTempSense::getTemperature(int usrIdx, float& temperature, bool filtered) +{ + if(BME280.getCount() == 0) + return DS18B20.getTemperature(usrIdx, temperature, filtered); + + if(NVstore.getHeaterTuning().BME280probe.bPrimary) { + if(usrIdx == 0) + return BME280.getTemperature(temperature, filtered); + + usrIdx--; + return DS18B20.getTemperature(usrIdx, temperature, filtered); + } + else { + + if(usrIdx >= DS18B20.getNumSensors()) { + return BME280.getTemperature(temperature, filtered); + } + + return DS18B20.getTemperature(usrIdx, temperature, filtered); + } +} + diff --git a/src/Utility/TempSense.h b/src/Utility/TempSense.h index 4fd141f..a4184d0 100644 --- a/src/Utility/TempSense.h +++ b/src/Utility/TempSense.h @@ -23,41 +23,99 @@ #define __BTC_TEMPSENSE_H__ #include "../../lib/esp32-ds18b20/ds18b20.h" +#include "../../lib/Adafruit_BME280_Library/Adafruit_BME280.h" +#include "DataFilter.h" //#define SINGLE_DS18B20_SENSOR const int MAX_DS18B20_DEVICES = 3; -class CTempSense { +class CSensor { +public: + CSensor() {}; + bool getTemperature(float& tempReading, bool filtered); + const char* getID(); +}; +class CDS18B20probe { + DS18B20_Info * pSensorInfo; + DS18B20_ERROR error; + int holdoff; + float reading; + CExpMean filter; +public: + CDS18B20probe(); + void init(); + void assign(DS18B20_Info *pInfo) { pSensorInfo = pInfo; }; + void release(); + bool readSensor(); + void setError(DS18B20_ERROR err) { error = err; }; + bool OK() { return error == DS18B20_OK; }; +// bool setROMcode(OneWireBus_ROMCode rom_code) ; + OneWireBus_ROMCode getROMcode() const; + DS18B20_Info* getSensorInfo() { return pSensorInfo; }; + float getReading(bool filtered); + bool matchROMcode(uint8_t test[8]); +}; + +class CDS18B20Sensor : public CSensor { OneWireBus * _owb; owb_rmt_driver_info _rmt_driver_info; - DS18B20_Info * _Sensors[MAX_DS18B20_DEVICES]; - OneWireBus_ROMCode _device_rom_codes[MAX_DS18B20_DEVICES]; - int _nNumSensors; - float _Readings[MAX_DS18B20_DEVICES]; - DS18B20_ERROR _Errors[MAX_DS18B20_DEVICES]; - + CDS18B20probe _Sensors[MAX_DS18B20_DEVICES]; + int _nNumSensors; + int _sensorMap[MAX_DS18B20_DEVICES]; bool _discover(); - int _sensorMap[3]; + public: - CTempSense(); + CDS18B20Sensor(); void begin(int pin); bool find(); -#ifdef SINGLE_DS18B20_SENSOR - bool readROMcode(); - bool attach(); -#endif bool readSensors(); void startConvert(); void waitConvertDone(); - bool getTemperature(int mapIdx, float& tempReading); // indexed as mapped by user - bool getTemperatureIdx(int sensIdx, float& tempReading); // index is sensor discovery order on one-wire bus - bool getRomCodeIdx(int sensIdx, OneWireBus_ROMCode& romCode); // index is sensor discovery order on one-wire bus int checkNumSensors() const; - int getNumSensors() const { return _nNumSensors; }; + bool getTemperature(int mapIdx, float& tempReading, bool filtered); + bool getTemperatureIdx(int sensIdx, float& tempReading, bool filtered) ; // index is sensor discovery order on one-wire bus + bool getRomCodeIdx(int sensIdx, OneWireBus_ROMCode& romCode) const; // index is sensor discovery order on one-wire bus bool mapSensor(int idx, OneWireBus_ROMCode romCode = { 0 } ); + int getNumSensors() const { return _nNumSensors; }; + const char* getID(); +}; + +class CBME280Sensor : public CSensor { + Adafruit_BME280 _bme; // I2C + long _lastSampleTime; + float _lastTemperature; + int _count; + CExpMean _Filter; +public: + CBME280Sensor(); + bool begin(int ID); + bool getTemperature(float& tempReading, bool filtered) ; + const char* getID(); + int getCount() const { return _count; }; +}; + +class CTempSense { + + CDS18B20Sensor DS18B20; + CBME280Sensor BME280; + + bool _discover(); +public: + CTempSense(); + void begin(int oneWirePin, int I2CID); + bool readSensors(); + void startConvert(); + bool getTemperature(int usrIdx, float& tempReading, bool filtered=true) ; // indexed as mapped by user + float getOffset(int usrIdx); + void setOffset(int usrIdx, float offset); + bool getTemperatureBME280(float& tempReading) ; // index is sensor discovery order on one-wire bus + bool getTemperatureDS18B20Idx(int sensIdx, float& tempReading) ; // index is sensor discovery order on one-wire bus + int getNumSensors() const; + CBME280Sensor& getBME280() { return BME280; }; + CDS18B20Sensor& getDS18B20() { return DS18B20; }; }; #endif diff --git a/src/Utility/UtilClasses.cpp b/src/Utility/UtilClasses.cpp index 232edd3..a1b0f46 100644 --- a/src/Utility/UtilClasses.cpp +++ b/src/Utility/UtilClasses.cpp @@ -290,8 +290,8 @@ void DecodeCmd(const char* cmd, String& payload) } else if(strcmp("MTopic", cmd) == 0) { sMQTTparams info = NVstore.getMQTTinfo(); - strncpy(info.topic, payload.c_str(), 31); - info.topic[31] = 0; + strncpy(info.topicPrefix, payload.c_str(), 31); + info.topicPrefix[31] = 0; NVstore.setMQTTinfo(info); } else if(strcmp("UploadSize", cmd) == 0) { @@ -339,25 +339,31 @@ void DecodeCmd(const char* cmd, String& payload) } } else if(strcmp("TempOffset", cmd) == 0) { - sHeaterTuning ht = NVstore.getHeaterTuning(); - ht.tempProbe[0].offset = payload.toFloat(); - if(INBOUNDS(ht.tempProbe[0].offset, -10.0, +10.0)) { + getTempSensor().setOffset(0, payload.toFloat()); +/* sHeaterTuning ht = NVstore.getHeaterTuning(); + ht.DS18B20probe[0].offset = payload.toFloat(); + if(INBOUNDS(ht.DS18B20probe[0].offset, -10.0, +10.0)) { NVstore.setHeaterTuning(ht); - } + }*/ } else if(strcmp("Temp2Offset", cmd) == 0) { - sHeaterTuning ht = NVstore.getHeaterTuning(); - ht.tempProbe[1].offset = payload.toFloat(); - if(INBOUNDS(ht.tempProbe[1].offset, -10.0, +10.0)) { + getTempSensor().setOffset(1, payload.toFloat()); +/* sHeaterTuning ht = NVstore.getHeaterTuning(); + ht.DS18B20probe[1].offset = payload.toFloat(); + if(INBOUNDS(ht.DS18B20probe[1].offset, -10.0, +10.0)) { NVstore.setHeaterTuning(ht); - } + }*/ } else if(strcmp("Temp3Offset", cmd) == 0) { - sHeaterTuning ht = NVstore.getHeaterTuning(); - ht.tempProbe[2].offset = payload.toFloat(); - if(INBOUNDS(ht.tempProbe[2].offset, -10.0, +10.0)) { + getTempSensor().setOffset(2, payload.toFloat()); +/* sHeaterTuning ht = NVstore.getHeaterTuning(); + ht.DS18B20probe[2].offset = payload.toFloat(); + if(INBOUNDS(ht.DS18B20probe[2].offset, -10.0, +10.0)) { NVstore.setHeaterTuning(ht); - } + }*/ + } + else if(strcmp("Temp4Offset", cmd) == 0) { + getTempSensor().setOffset(3, payload.toFloat()); } else if(strcmp("LowVoltCutout", cmd) == 0) { float fCal = payload.toFloat(); diff --git a/src/Utility/helpers.h b/src/Utility/helpers.h index 777f735..2de288f 100644 --- a/src/Utility/helpers.h +++ b/src/Utility/helpers.h @@ -25,6 +25,7 @@ #include "UtilClasses.h" +class CTempSense; struct sGPIO; extern void forceBootInit(); @@ -45,7 +46,7 @@ extern uint8_t getDemandDegC(); extern void setDemandDegC(uint8_t val); extern uint8_t getDemandPump(); -extern float getTemperatureSensor(); +extern float getTemperatureSensor(int source = 0); extern void setPumpMin(float); extern void setPumpMax(float); extern void setFanMin(uint16_t); @@ -88,6 +89,7 @@ extern int getFanSpeed(); extern int sysUptime(); extern void doJSONwatchdog(int topup); extern void reloadScreens(); +extern CTempSense& getTempSensor() ; void setSSID(const char* name); diff --git a/src/WiFi/ABMqtt.cpp b/src/WiFi/ABMqtt.cpp index d297f99..5cdfbeb 100644 --- a/src/WiFi/ABMqtt.cpp +++ b/src/WiFi/ABMqtt.cpp @@ -34,10 +34,9 @@ #include "../Utility/Moderator.h" #include "../Protocol/Protocol.h" #include "../Utility/BTC_JSON.h" -#include "Utility/TempSense.h" +#include "../Utility/TempSense.h" extern void DecodeCmd(const char* cmd, String& payload); -extern CTempSense TempSensor; #define USE_RTOS_MQTTTIMER //#define USE_LOCAL_MQTTSTRINGS @@ -348,30 +347,35 @@ void updateMQTT() pubTopic("RunString", getHeaterInfo().getRunStateStr()); float tidyTemp; - if(TempSensor.getTemperature(0, tidyTemp)) { - tidyTemp += NVstore.getHeaterTuning().tempProbe[0].offset; + if(getTempSensor().getTemperature(0, tidyTemp)) { tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution pubTopic("TempCurrent", tidyTemp); } else pubTopic("TempCurrent", "n/a"); - if(TempSensor.getNumSensors() > 1) { - if(TempSensor.getTemperature(1, tidyTemp)) { - tidyTemp += NVstore.getHeaterTuning().tempProbe[1].offset; + if(getTempSensor().getNumSensors() > 1) { + if(getTempSensor().getTemperature(1, tidyTemp)) { tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution pubTopic("Temp2Current", tidyTemp); } else pubTopic("Temp2Current", "n/a"); - if(TempSensor.getNumSensors() > 2) { - if(TempSensor.getTemperature(2, tidyTemp)) { - tidyTemp += NVstore.getHeaterTuning().tempProbe[2].offset; + if(getTempSensor().getNumSensors() > 2) { + if(getTempSensor().getTemperature(2, tidyTemp)) { tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution pubTopic("Temp3Current", tidyTemp); } else pubTopic("Temp3Current", "n/a"); } + if(getTempSensor().getNumSensors() > 3) { + if(getTempSensor().getTemperature(3, tidyTemp)) { + tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution + pubTopic("Temp4Current", tidyTemp); + } + else + pubTopic("Temp4Current", "n/a"); + } } pubTopic("TempDesired", getTemperatureDesired()); pubTopic("TempBody", getHeaterInfo().getTemperature_HeatExchg()); diff --git a/src/WiFi/BTCWifi.cpp b/src/WiFi/BTCWifi.cpp index 1f1a91b..9969c01 100644 --- a/src/WiFi/BTCWifi.cpp +++ b/src/WiFi/BTCWifi.cpp @@ -30,7 +30,7 @@ #include "../Utility/NVStorage.h" #include "../../lib/WiFiManager-dev/WiFiManager.h" -#define USE_AP +//#define USE_AP // function to control the behaviour upon reboot if no wifi manager credentials exist // or connection fails @@ -103,10 +103,12 @@ bool initWifi(int initpin,const char *failedssid, const char *failedpassword) int chnl = 1; bool retval = false; + bool startAP = false; if(!res) { // failed STA mode DebugPort.println("WiFimanager failed STA connection. Setting up AP..."); WiFi.disconnect(); // apparently needed for AP only OTA to reboot properly!!! + startAP = true; } else { // runs through here if STA connected OK @@ -120,16 +122,17 @@ bool initWifi(int initpin,const char *failedssid, const char *failedpassword) retval = true; } #ifdef USE_AP - // always setup an AP - for STA+AP mode we *must* use the same RF channel as STA - DebugPort.println("Starting AP mode"); -//REMOVED - UNSTABLE WHETHER WE GET 192.168.4.1 or 192.168.100.1 ???? -// REMOVED WiFi.softAPConfig(IPAddress(192, 168, 100, 1), IPAddress(192, 168, 100, 1), IPAddress(255,255,255,0)); - WiFi.softAP(failedssid, failedpassword, chnl); - WiFi.enableAP(true); - DebugPort.printf(" AP SSID: %s\r\n", WiFi.softAPgetHostname()); - DebugPort.printf(" AP IP address: %s\r\n", getWifiAPAddrStr()); - DebugPort.printf("WifiMode after initWifi = %d\r\n", WiFi.getMode()); + startAP = true; #endif + if(startAP) { + // for STA+AP mode we *must* use the same RF channel as STA + DebugPort.println("Starting AP mode"); + WiFi.softAP(failedssid, failedpassword, chnl); + WiFi.enableAP(true); + DebugPort.printf(" AP SSID: %s\r\n", WiFi.softAPgetHostname()); + DebugPort.printf(" AP IP address: %s\r\n", getWifiAPAddrStr()); + DebugPort.printf("WifiMode after initWifi = %d\r\n", WiFi.getMode()); + } // even though we may have started in STA mode - start the config portal if demanded via the NV flag if(shouldBootIntoConfigPortal()) {