Added Temp Probe selection screen, mapping sensors to user preferences

This commit is contained in:
Ray Jones 2019-09-22 09:03:42 +10:00
parent de9417ff73
commit 8fb1981552
12 changed files with 762 additions and 63 deletions

View file

@ -482,6 +482,10 @@ void setup() {
pHourMeter->init(bESP32PowerUpInit || RTC_Store.getBootInit()); // ensure persistent memory variable are reset after powerup, or OTA update
RTC_Store.setBootInit(false);
TempSensor.mapSensor(0, NVstore.getHeaterTuning().tempProbe[0].romCode);
TempSensor.mapSensor(1, NVstore.getHeaterTuning().tempProbe[1].romCode);
TempSensor.mapSensor(2, NVstore.getHeaterTuning().tempProbe[2].romCode);
delay(1000); // just to hold the splash screeen for while
}
@ -799,7 +803,9 @@ void loop()
if(tDelta > MIN_TEMPERATURE_INTERVAL) { // maintain a minimum holdoff period
lastTemperatureTime = millis(); // reset time to observe temeprature
if(TempSensor.readTemperature(fTemperature)) {
TempSensor.readSensors();
// TempSensor.checkNumSensors();
if(TempSensor.getTemperature(fTemperature)) { // get Primary sensor temeprature
if(DS18B20holdoff) {
DS18B20holdoff--;
DebugPort.printf("Skipped initial DS18B20 reading: %f\r\n", fTemperature);
@ -1125,7 +1131,8 @@ float getTemperatureDesired()
float getTemperatureSensor()
{
return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().tempOfs;
// NVstore always holds primary sensor as index 0
return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().tempProbe[0].offset;
}
void setPumpMin(float val)

371
src/OLED/DS18B20Screen.cpp Normal file
View file

@ -0,0 +1,371 @@
/*
* 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 "DS18B20Screen.h"
#include "KeyPad.h"
#include "fonts/Icons.h"
#include "fonts/MiniFont.h"
#include "Utility/TempSense.h"
extern CTempSense TempSensor;
CDS18B20Screen::CDS18B20Screen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_nNumSensors = 0;
for(int i=0; i<3; i++) {
_sensorRole[i] = -1;
_Offset[i] = 0;
}
_initUI();
}
void
CDS18B20Screen::onSelect()
{
CScreenHeader::onSelect();
_initUI();
_nNumSensors = TempSensor.getNumSensors();
_readNV();
}
void
CDS18B20Screen::_initUI()
{
_rowSel = 0;
_colSel = 0;
_keyHold = -1;
_scrollChar = 0;
}
bool
CDS18B20Screen::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");
int baseLine = 40;
switch(_nNumSensors) {
case 1: baseLine = 18; break;
case 2: baseLine = 30; break;
}
for(int i = 0; i<_nNumSensors; i++) {
switch(_sensorRole[i]) {
case 0: strcpy(msg, "Pri"); break;
case 1: strcpy(msg, "Sec"); break;
case 2: strcpy(msg, "Ter"); break;
default: strcpy(msg, " ? "); break;
}
_printMenuText(border, baseLine-i*12, msg, _rowSel == (i+1) && _colSel == 0);
OneWireBus_ROMCode romCode;
if(!TempSensor.getRomCodeIdx(romCode, i)) {
strcpy(msg, "missing?") ;
}
else {
char* buffer = msg;
for (int j = 5; j >= 0; j--) {
sprintf(buffer, "%02X%s", romCode.fields.serial_number[j], j ? ":" : "");
buffer += 3;
}
}
{
CTransientFont AF(_display, &miniFontInfo);
_printMenuText(27, baseLine+2-i*12, msg);
}
if(_colSel == 0) {
float temperature;
TempSensor.getTemperatureIdx(temperature, i);
sprintf(msg, "%.01fC", temperature + _Offset[i]);
}
else {
sprintf(msg, "%+.01f", _Offset[i]);
}
_printMenuText(90, baseLine-i*12, msg, _rowSel == (i+1) && _colSel == 1);
}
}
}
return true;
}
bool
CDS18B20Screen::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
CDS18B20Screen::keyHandler(uint8_t event)
{
if(CPasswordScreen::keyHandler(event)) {
if(_isPasswordOK()) {
_rowSel = 1;
_keyHold = -1;
}
}
else {
sUserSettings us;
if(event & keyPressed) {
_keyHold = 0;
// UP press
if(event & key_Up) {
if(_rowSel == SaveConfirm) {
_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
_rowSel = 0;
}
else {
if(_rowSel == 0) {
_getPassword();
if(_isPasswordOK()) {
_rowSel = 1;
}
}
else {
_testCancel();
_rowSel++;
UPPERLIMIT(_rowSel, 3);
}
}
}
// DOWN press
if(event & key_Down) {
_testCancel();
if(_rowSel == SaveConfirm)
_rowSel = 0;
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
}
if(event & keyRepeat) {
if(_keyHold >= 0) {
_keyHold++;
if(_keyHold == 2) {
if(event & key_Left) {
_colSel = 0;
_scrollChar = 0;
}
if(event & key_Right) {
_colSel = 1;
_scrollChar = 0;
}
if(event & key_Centre) {
if(_colSel == 0)
_sensorRole[_rowSel-1] = -1;
else
_Offset[_rowSel-1] = 0;
}
_keyHold = -1;
}
}
}
if(event & keyReleased) {
if(_keyHold == 0) {
// 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
CDS18B20Screen::adjust(int dir)
{
switch(_rowSel) {
case 1:
if(_colSel == 0) {
_sensorRole[0] += dir;
WRAPLIMITS(_sensorRole[0], 0, _nNumSensors-1);
if(_nNumSensors == 2)
_sensorRole[1] = _sensorRole[0] == 0 ? 1 : 0;
}
else {
_Offset[0] += dir * 0.1;
BOUNDSLIMIT(_Offset[0], -10, +10);
}
break;
case 2:
if(_colSel == 0) {
_sensorRole[1] += dir;
WRAPLIMITS(_sensorRole[1], 0, _nNumSensors-1);
if(_nNumSensors == 2)
_sensorRole[0] = _sensorRole[1] == 0 ? 1 : 0;
}
else {
_Offset[1] += dir * 0.1;
BOUNDSLIMIT(_Offset[1], -10, +10);
}
break;
case 3:
if(_colSel == 0) {
_sensorRole[2] += dir;
WRAPLIMITS(_sensorRole[2], 0, _nNumSensors-1);
}
else {
_Offset[2] += dir * 0.1;
BOUNDSLIMIT(_Offset[2], -10, +10);
}
break;
}
}
void
CDS18B20Screen::_testCancel()
{
switch(_rowSel) {
case 1:
if(_sensorRole[1] == _sensorRole[0]) _sensorRole[1] = -1;
if(_sensorRole[2] == _sensorRole[0]) _sensorRole[2] = -1;
break;
case 2:
if(_sensorRole[0] == _sensorRole[1]) _sensorRole[0] = -1;
if(_sensorRole[2] == _sensorRole[1]) _sensorRole[2] = -1;
break;
case 3:
if(_sensorRole[0] == _sensorRole[2]) _sensorRole[0] = -1;
if(_sensorRole[1] == _sensorRole[2]) _sensorRole[1] = -1;
break;
}
}
void
CDS18B20Screen::_readNV()
{
_sensorRole[0] = _sensorRole[1] = _sensorRole[2] = -1;
const sHeaterTuning& tuning = NVstore.getHeaterTuning();
for(int sensor = 0; sensor < TempSensor.getNumSensors(); sensor++) {
OneWireBus_ROMCode romCode;
TempSensor.getRomCodeIdx(romCode, sensor); // 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) {
_sensorRole[sensor] = i; // assign role to sensor according to NV placement
_Offset[sensor] = tuning.tempProbe[i].offset;
continue;
}
}
}
DebugPort.printf("Sensor roles: %d, %d, %d\r\n", _sensorRole[0], _sensorRole[1], _sensorRole[2]);
}
void
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;
}
for(int sensor = 0; sensor < TempSensor.getNumSensors(); 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(romCode, sensor); // get rom code of indexed sensor
memcpy(tuning.tempProbe[role].romCode.bytes, romCode.bytes, 8);
}
}
NVstore.setHeaterTuning(tuning);
}

53
src/OLED/DS18B20Screen.h Normal file
View file

@ -0,0 +1,53 @@
/*
* 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 __DS18B20SCREEN_H__
#define __DS18B20SCREEN_H__
#include <stdint.h>
#include "PasswordScreen.h"
#include "../Utility/NVStorage.h"
class C128x64_OLED;
class CScreenManager;
class CDS18B20Screen : public CPasswordScreen
{
int _rowSel, _colSel;
int _keyHold;
int _scrollChar;
int _nNumSensors;
int _sensorRole[3];
float _Offset[3];
void _initUI();
void _testCancel();
void _readNV();
void _saveNV();
public:
CDS18B20Screen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool animate();
bool keyHandler(uint8_t event);
void onSelect();
void adjust(int dir);
};
#endif

View file

@ -48,7 +48,7 @@ CFuelCalScreen::onSelect()
_initUI();
_mlPerStroke = NVstore.getHeaterTuning().pumpCal;
_LVC = NVstore.getHeaterTuning().lowVolts;
_tOfs = NVstore.getHeaterTuning().tempOfs;
_tOfs = NVstore.getHeaterTuning().tempProbe[0].offset;
}
void
@ -231,7 +231,7 @@ CFuelCalScreen::keyHandler(uint8_t event)
tuning = NVstore.getHeaterTuning();
tuning.pumpCal = _mlPerStroke;
tuning.lowVolts = _LVC;
tuning.tempOfs = _tOfs;
tuning.tempProbe[0].offset = _tOfs;
NVstore.setHeaterTuning(tuning);
saveNV();
_rowSel = 0;

View file

@ -46,6 +46,7 @@
#include "BTScreen.h"
#include "MenuTrunkScreen.h"
#include "MQTTScreen.h"
#include "DS18B20Screen.h"
#include <Wire.h>
#include "../cfg/pins.h"
#include "../cfg/BTCConfig.h"
@ -486,6 +487,7 @@ 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));
_Screens.push_back(menuloop);
}

View file

@ -168,6 +168,16 @@ const uint8_t miniFontBitmaps[] PROGMEM =
// @81 ':' (1 pixel wide)
0x50, // # #
// @82 'b' (3 pixels wide)
0x38, // ###
0x28, // # #
0xf8, // #####
// @85 'd' (3 pixels wide)
0xf8, // #####
0x28, // # #
0x38, // ###
};
// Character descriptors for a 3x5 font
@ -194,9 +204,9 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{0, 0, 0}, // '?'
{0, 0, 0}, // '@'
{3, 5, 33}, // 'A'
{0, 0, 0}, // 'B'
{3, 5, 82}, // 'B'
{3, 5, 36}, // 'C'
{0, 0, 0}, // 'D'
{3, 5, 85}, // 'D'
{3, 5, 72}, // 'E'
{3, 5, 39}, // 'F'
{3, 5, 42}, // 'G'

View file

@ -36,7 +36,9 @@
#include "../Protocol/Protocol.h"
#include <string.h>
#include "HourMeter.h"
#include "Utility/TempSense.h"
extern CTempSense TempSensor;
extern CModerator MQTTmoderator;
char defaultJSONstr[64];
@ -143,6 +145,22 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len)
if(tidyTemp > -80) {
bSend |= moderator.addJson("TempCurrent", tidyTemp, root);
}
if(TempSensor.getNumSensors() > 1) {
TempSensor.getTemperature(tidyTemp, 1);
tidyTemp += NVstore.getHeaterTuning().tempProbe[1].offset;
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(tidyTemp, 2);
tidyTemp += NVstore.getHeaterTuning().tempProbe[2].offset;
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
if(tidyTemp > -80) {
bSend |= moderator.addJson("Temp3Current", tidyTemp, root);
}
}
}
bSend |= moderator.addJson("TempDesired", getTemperatureDesired(), root);
bSend |= moderator.addJson("TempMode", NVstore.getUserSettings().degF, root);
if(NVstore.getUserSettings().menuMode < 2) {
@ -196,9 +214,14 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
bSend |= moderator.addJson("CyclicOn", NVstore.getUserSettings().cyclic.Start, root); // threshold of under temp for cyclic mode
bSend |= moderator.addJson("PumpCount", RTC_Store.getFuelGauge(), root); // running count of pump strokes
bSend |= moderator.addJson("PumpCal", NVstore.getHeaterTuning().pumpCal, root); // mL/stroke
bSend |= moderator.addJson("LowVoltCutout", NVstore.getHeaterTuning().getLVC(), root); // low volatge cutout
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", NVstore.getHeaterTuning().tempOfs, root); // degC offset
if(bSend) {
root.printTo(opStr, len);

View file

@ -265,8 +265,25 @@ sHeaterTuning::load()
else
validatedLoad("lowVolts", lowVolts, 230, u8inBoundsOrZero, 200, 250);
validatedLoad("pumpCal", pumpCal, 0.02, 0.001, 1);
validatedLoad("tempOfs", tempOfs, 0.0, -10.0, +10.0);
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);
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]
);
}
}
void
@ -284,8 +301,25 @@ sHeaterTuning::save()
preferences.putUChar("glowDrive", glowDrive);
preferences.putUChar("lowVolts", lowVolts);
preferences.putFloat("pumpCal", pumpCal);
preferences.putFloat("tempOfs", tempOfs);
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.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]
);
}
}
void

View file

@ -25,12 +25,17 @@
#include "BTC_GPIO.h"
#include "NVCore.h"
#include "../Utility/helpers.h"
#include "Utility/TempSense.h"
#include "../RTC/Timers.h" // for sTimer
void toggle(bool& ref);
void toggle(uint8_t& ref);
struct sProbeTuning {
float offset;
OneWireBus_ROMCode romCode;
};
struct sHeaterTuning : public CESP32_NVStorage {
uint8_t Pmin;
@ -42,7 +47,7 @@ struct sHeaterTuning : public CESP32_NVStorage {
uint8_t glowDrive;
uint8_t lowVolts; // x10
float pumpCal;
float tempOfs;
sProbeTuning tempProbe[3]; // [0],[1],[2] - Primary, Secondary, Tertiary
bool valid() {
bool retval = true;
@ -58,7 +63,9 @@ struct sHeaterTuning : public CESP32_NVStorage {
retval &= INBOUNDS(lowVolts, 100, 125) || (lowVolts == 0);
else
retval &= INBOUNDS(lowVolts, 200, 250 || (lowVolts == 0));
retval &= INBOUNDS(tempOfs, -10, +10);
retval &= INBOUNDS(tempProbe[0].offset, -10, +10);
retval &= INBOUNDS(tempProbe[1].offset, -10, +10);
retval &= INBOUNDS(tempProbe[2].offset, -10, +10);
return retval;
};
void init() {
@ -71,7 +78,12 @@ struct sHeaterTuning : public CESP32_NVStorage {
glowDrive = 5;
pumpCal = 0.02;
lowVolts = 115;
tempOfs = 0;
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));
};
void load();
void save();
@ -85,7 +97,12 @@ struct sHeaterTuning : public CESP32_NVStorage {
glowDrive = rhs.glowDrive;
pumpCal = rhs.pumpCal;
lowVolts = rhs.lowVolts;
tempOfs = rhs.tempOfs;
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);
return *this;
}
float getPmin() const;

View file

@ -23,13 +23,19 @@
#include "TempSense.h"
#include "DebugPort.h"
#include "macros.h"
CTempSense::CTempSense()
{
_TempSensor = NULL;
_owb = NULL;
_nNumSensors = 0;
for(int i=0; i< MAX_DS18B20_DEVICES; i++)
_Sensors[i] = NULL;
for(int i=0; i<3; i++)
_sensorMap[i] = -1;
}
#ifdef SINGLE_DS18B20_SENSOR
void CTempSense::begin(int pin)
{
// initialise DS18B20 sensor interface
@ -48,27 +54,24 @@ void CTempSense::begin(int pin)
attach();
}
}
/*void CTempSense::begin(int pin)
#else
void CTempSense::begin(int pin)
{
// initialise DS18B20 sensor interface
// create one wire bus interface, using RMT peripheral
_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();
readROMcode();
// Create DS18B20 device on the 1-Wire bus
if(found) {
attach();
}
find();
}
*/
#endif
#ifdef SINGLE_DS18B20_SENSOR
bool
CTempSense::readTemperature(float& tempReading)
CTempSense::readSensors(float& tempReading)
{
if(_TempSensor == NULL) {
if(_Sensors[0] == NULL) {
// bool found = find();
bool found = readROMcode();
@ -85,8 +88,8 @@ CTempSense::readTemperature(float& tempReading)
}
}
if(_TempSensor != NULL) {
DS18B20_ERROR error = ds18b20_read_temp(_TempSensor, &tempReading);
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) {
@ -94,63 +97,134 @@ CTempSense::readTemperature(float& tempReading)
}
else {
DebugPort.println("\007DS18B20 sensor removed?");
ds18b20_free(&_TempSensor);
ds18b20_free(&_Sensors[0]);
}
}
return false;
}
/*bool
CTempSense::readTemperature(float& tempReading)
#else
bool
CTempSense::readSensors()
{
if(_TempSensor == NULL) {
bool retval = false;
if(_nNumSensors == 0) {
bool found = find();
if(found) {
DebugPort.println("Found DS18B20 device");
readROMcode();
attach();
DebugPort.println("Found DS18B20 device(s)");
startConvert(); // request a new conversion,
waitConvertDone();
}
}
if(_TempSensor != NULL) {
DS18B20_ERROR error = ds18b20_read_temp(_TempSensor, &tempReading);
// DebugPort.printf(">>>> DS18B20 = %f, error=%d\r\n", fTemperature, error);
if(error == DS18B20_OK) {
return true;
if(_nNumSensors) {
for (int i = 0; i < MAX_DS18B20_DEVICES; ++i) {
_Errors[i] = DS18B20_ERROR_UNKNOWN;
}
else {
DebugPort.println("\007DS18B20 sensor removed?");
ds18b20_free(&_TempSensor);
for (int i = 0; i < _nNumSensors; ++i) {
_Errors[i] = ds18b20_read_temp(_Sensors[i], &_Readings[i]);
}
#ifdef REPORT_READINGS
DebugPort.println("\nTemperature readings (degrees C)");
#endif
for (int i = 0; i < _nNumSensors; ++i) {
if(_Errors[i] == DS18B20_OK) {
#ifdef REPORT_READINGS
DebugPort.printf(" %d: %.1f OK\r\n", i, _Readings[i]);
#endif
retval = true; // at least one sensor read OK
}
else {
#ifdef REPORT_READINGS
DebugPort.printf("\007 %d: DS18B20 sensor removed?\r\n", i);
#endif
}
}
}
return false;
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)
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()
{
// Find all connected devices
DebugPort.println("Finding one wire bus devices...");
memset(_device_rom_codes, 0, sizeof(_device_rom_codes));
_nNumSensors = 0;
OneWireBus_SearchState search_state = {0};
bool found = false;
owb_search_first(_owb, &search_state, &found);
while(found) {
char rom_code_s[17];
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;
_nNumSensors++;
owb_search_next(_owb, &search_state, &found);
}
DebugPort.printf("Found %d 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;
}
for (int i = 0; i < _nNumSensors; ++i)
{
DS18B20_Info * ds18b20_info = ds18b20_malloc(); // heap allocation
_Sensors[i] = ds18b20_info;
if (_nNumSensors == 1)
{
printf("Single device optimisations enabled\n");
ds18b20_init_solo(ds18b20_info, _owb); // only one device on bus
}
else
{
ds18b20_init(ds18b20_info, _owb, _device_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);
}
return found;
}
#endif
#ifdef SINGLE_DS18B20_SENSOR
bool
CTempSense::readROMcode()
{
@ -174,28 +248,104 @@ CTempSense::readROMcode()
bool
CTempSense::attach()
{
if(_TempSensor == NULL) {
_TempSensor = ds18b20_malloc(); // heap allocation
if(_Sensors[0] == NULL) {
_Sensors[0] = ds18b20_malloc(); // heap allocation
DebugPort.printf("Single device optimisations enabled\r\n");
ds18b20_init_solo(_TempSensor, _owb); // only one device on bus
ds18b20_use_crc(_TempSensor, true); // enable CRC check for temperature readings
ds18b20_set_resolution(_TempSensor, DS18B20_RESOLUTION_12_BIT);
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()
{
// kick off the initial temperature conversion
if(_TempSensor)
ds18b20_convert(_TempSensor);
if(_Sensors[0])
ds18b20_convert_all(_owb);
}
void
CTempSense::waitConvertDone()
{
if(_TempSensor)
ds18b20_wait_for_conversion(_TempSensor);
if(_Sensors[0])
ds18b20_wait_for_conversion(_Sensors[0]);
}
int
CTempSense::checkNumSensors() const
{
long start = millis();
bool found = false;
int numSensors = 0;
OneWireBus_SearchState search_state = {0};
owb_search_first(_owb, &search_state, &found);
while(found) {
numSensors++;
owb_search_next(_owb, &search_state, &found);
}
DebugPort.printf("Found %d one-wire device%s\r\n", numSensors, numSensors==1 ? "" : "s");
long tDelta = millis() - start;
DebugPort.printf("checkNumSensors: %ldms\r\n", tDelta);
return numSensors;
}
bool
CTempSense::mapSensor(int idx, OneWireBus_ROMCode romCode)
{
if(idx == -1) {
_sensorMap[0] = _sensorMap[1] = _sensorMap[2] = -1;
return false;
}
if(idx == -2) {
DebugPort.printf("Sensor Map: %d %d %d\r\n",
_sensorMap[0], _sensorMap[1], _sensorMap[2]);
return false;
}
if(!INBOUNDS(idx, 0, 2))
return false;
for(int i = 0; i < _nNumSensors; i++) {
if(memcmp(_Sensors[i]->rom_code.bytes, romCode.bytes, 8) == 0) {
_sensorMap[idx] = i;
DebugPort.printf("Mapped DS18B20 %02X:%02X:%02X:%02X:%02X:%02X as role %d\r\n",
romCode.fields.serial_number[5], romCode.fields.serial_number[4], romCode.fields.serial_number[3],
romCode.fields.serial_number[2], romCode.fields.serial_number[1], romCode.fields.serial_number[0],
idx);
return true;
}
}
return false;
}
bool
CTempSense::getTemperature(float& temperature, int mapIdx)
{
int idx = _sensorMap[mapIdx];
if(idx < 0)
return getTemperatureIdx(temperature, 0); // default to sensor 0 if not mapped
// temperature = _Readings[idx];
// return _Errors[idx] == DS18B20_OK;
return getTemperatureIdx(temperature, idx);
}
bool
CTempSense::getTemperatureIdx(float& temperature, int idx)
{
temperature = _Readings[idx];
return _Errors[idx] == DS18B20_OK;
}
bool
CTempSense::getRomCodeIdx(OneWireBus_ROMCode& romCode, int idx)
{
if(idx >= _nNumSensors)
return false;
romCode = _Sensors[idx]->rom_code;
return true;
}

View file

@ -24,22 +24,40 @@
#include "../../lib/esp32-ds18b20/ds18b20.h"
//#define SINGLE_DS18B20_SENSOR
const int MAX_DS18B20_DEVICES = 3;
class CTempSense {
OneWireBus * _owb;
owb_rmt_driver_info _rmt_driver_info;
DS18B20_Info * _TempSensor = NULL;
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];
bool _discover();
int _sensorMap[3];
public:
CTempSense();
void begin(int pin);
bool find();
#ifdef SINGLE_DS18B20_SENSOR
bool readROMcode();
bool attach();
bool readTemperature(float& tempReading);
#endif
bool readSensors();
void startConvert();
void waitConvertDone();
bool getTemperature(float& tempReading, int mapIdx=0); // indexed as mapped by user
bool getTemperatureIdx(float& tempReading, int selSensor=0); // index is discovery order on one-wire bus
bool getRomCodeIdx(OneWireBus_ROMCode& romCode, int selSensor=0); // index is discovery order on one-wire bus
int checkNumSensors() const;
int getNumSensors() const { return _nNumSensors; };
bool mapSensor(int idx, OneWireBus_ROMCode romCode = { 0 } );
};
#endif

View file

@ -340,8 +340,22 @@ void DecodeCmd(const char* cmd, String& payload)
}
else if(strcmp("TempOffset", cmd) == 0) {
sHeaterTuning ht = NVstore.getHeaterTuning();
ht.tempOfs = payload.toFloat();
if(INBOUNDS(ht.tempOfs, -10.0, +10.0)) {
ht.tempProbe[0].offset = payload.toFloat();
if(INBOUNDS(ht.tempProbe[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)) {
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)) {
NVstore.setHeaterTuning(ht);
}
}