Stabilised BME280 with DS18B20 coexistence

This commit is contained in:
Ray Jones 2019-10-18 12:55:16 +11:00
commit aabe6a54b3
59 changed files with 3018 additions and 909 deletions

Binary file not shown.

View File

@ -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

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 297 KiB

View File

@ -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**

View File

@ -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.

View File

@ -0,0 +1,8 @@
# osx
.DS_Store
# doxygen
Doxyfile*
doxygen_sqlite3.db
html
*.tmp

View File

@ -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)

View File

@ -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 <SPI.h>
#include <Wire.h>
/*!
* @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; }

View File

@ -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 <Adafruit_Sensor.h>
#include "../Adafruit_Sensor/Adafruit_Sensor.h"
#include <SPI.h>
#include <Wire.h>
/*!
* @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

View File

@ -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.

View File

@ -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)
<a href="http://www.adafruit.com/products/2652"><img src="./assets/board.jpg" width="500"/></a>
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

View File

@ -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 <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#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();
}

View File

@ -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 <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#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();
}

View File

@ -0,0 +1,10 @@
name=Adafruit BME280 Library
version=1.0.10
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
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

108
lib/Adafruit_Sensor/.gitignore vendored Normal file
View File

@ -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

View File

@ -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 <stdint.h>
#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

View File

@ -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("");
```

View File

@ -0,0 +1,10 @@
name=Adafruit Unified Sensor
version=1.0.3
author=Adafruit <info@adafruit.com>
maintainer=Adafruit <info@adafruit.com>
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

View File

@ -1,8 +0,0 @@
.pioenvs
.vscode
lib
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
platformio.ini
.piolibdeps

View File

@ -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

View File

@ -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.

View File

@ -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 <Arduino.h>
#include <esp32DHT.h>
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!

View File

@ -1 +0,0 @@
platformio ci --lib="." --board=lolin32 examples/DHT22/DHT22.ino

Binary file not shown.

Binary file not shown.

View File

@ -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 <Arduino.h>
#include <Ticker.h>
#include <esp32DHT.h>
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() {
}

View File

@ -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

View File

@ -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"
]
}

View File

@ -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

View File

@ -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<void*>(this);
_timerConfig.callback = reinterpret_cast<esp_timer_cb_t>(_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<gpio_num_t>(_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<gpio_num_t>(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<rmt_item32_t*>(xRingbufferReceive(instance->_ringBuf, &rx_size, 1000));
if (items) {
instance->_decode(items, rx_size/sizeof(rmt_item32_t));
vRingbufferReturnItem(instance->_ringBuf, static_cast<void*>(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<float>(_data[2]);
}
float DHT11::_getHumidity() {
if (_status != 0) return NAN;
return static_cast<float>(_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;
}

View File

@ -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"

View File

@ -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 <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp32-hal-gpio.h>
#include <driver/rmt.h>
#include <esp_timer.h>
}
#include <functional>
namespace esp32DHTInternals {
typedef std::function<void(float, float)> OnData_CB;
typedef std::function<void(uint8_t)> 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();
};

View File

@ -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();
}
}
CTempSense& getTempSensor()
{
return TempSensor;
}

View File

@ -21,13 +21,14 @@
#include <Arduino.h>
#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();

View File

@ -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:

View File

@ -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);

View File

@ -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;
*/
}
}

View File

@ -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:

View File

@ -47,6 +47,7 @@
#include "MenuTrunkScreen.h"
#include "MQTTScreen.h"
#include "DS18B20Screen.h"
#include "TempSensorScreen.h"
#include <Wire.h>
#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

View File

@ -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();

View File

@ -0,0 +1,306 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
*
* 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 <https://www.gnu.org/licenses/>.
*
*/
#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);
}

View File

@ -0,0 +1,54 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
*
* 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 <https://www.gnu.org/licenses/>.
*
*/
#ifndef __TEMPSENSORSCREEN_H__
#define __TEMPSENSORSCREEN_H__
#include <stdint.h>
#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

View File

@ -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;
}

View File

@ -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) {

View File

@ -216,4 +216,7 @@ struct sGPIO {
}
};
extern CGPIOin GPIOin;
extern CGPIOout GPIOout;
#endif // __BTCGPIO_H__

View File

@ -36,9 +36,8 @@
#include "../Protocol/Protocol.h"
#include <string.h>
#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);

View File

@ -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 "???";
}
}

View File

@ -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();

View File

@ -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(" <ENTER> - 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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -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());

View File

@ -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()) {