Split websocket handling into a task

Read all added to BME-280 (MariusZ)
New security menu in debug/telnet
This commit is contained in:
Ray Jones 2020-04-26 16:15:08 +10:00
parent 5cdc5c95a5
commit 9ff2d9410b
14 changed files with 695 additions and 111 deletions

View File

@ -423,6 +423,129 @@ bool Adafruit_BME280::isReadingCalibration(void) {
return (rStatus & (1 << 0)) != 0;
}
/*!
* Pressure and humidity readings require precise temperature for correctness.
* For this reason both readPressure() and readHumidity() call readTemperature() internally,
* which results in 2 SPI/I2C transactions for those readings.
*
* If user code calls a sequence of individual read*() methods to get all sensed values
* it may make sense to replace it with a call to this method
* and get all readings in 3 SPI/I2C transactions, instead of 5.
*
* @brief Returns all environmental values sensed
* @returns 0 on failure, otherwise a bitwise OR of BME280_{T,P,H}_OK flags
* @param readings reference to bme280_readings structure to be filled with data
*/
int Adafruit_BME280::readAll(bme280_readings& readings)
{
int retval = 0;
readings.temperature = readTemperature(); // will set t_fine attribute, for immediate reuse
if (readings.temperature == NAN) // temperature is required for other measurements, abort
{
readings.humidity = NAN;
readings.pressure = NAN;
readings.altitude = NAN;
return retval;
}
retval |= BME280_T_OK; // temperature read OK
// t_fine attribute has just been updated by readTemperature(), proceed
// below code copied almost verbatim from readPressure()
int64_t var1, var2, p;
int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA);
// less readable code, but reading humidity register could be moved here to minimise
// time before obtaining t_fine and applying it to humidity calculations
// int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA);
if (adc_P == 0x800000) // value in case pressure measurement was disabled
{
readings.pressure = NAN;
}
else
{
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)
{
readings.pressure = (float) 0.0; // avoid exception caused by division by zero
}
else
{
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);
readings.pressure = (float) p / 256;
retval |= BME280_P_OK; // pressure read OK
// calculate altitude ref to std sea level pressure
readings.altitude = readAltitude(1013.25);
}
}
// proceed with reading humidity
// again, code copied almost verbatim from readHumidity()
// t_fine attribute is assumed to be valid
int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA);
if (adc_H == 0x8000)
{ // value in case humidity measurement was disabled
readings.humidity = NAN;
}
else
{
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);
readings.humidity = h / 1024.0;
retval |= BME280_H_OK; // humidity reading OK
}
return retval;
}
/*!
* @brief Returns the temperature from the sensor
* @returns the temperature read from the device

View File

@ -127,13 +127,27 @@ class Adafruit_BME280_Unified : public Adafruit_Sensor
*/
/***********************************************************/
/*!
@brief environment readings combined
*/
/***********************************************************/
typedef struct {
float temperature; // temperature sensed [C]
float humidity; // humidity sensed [%Rh]
float pressure; // pressure sensed [Pa]
float altitude; // [m], referenced to std. sea level pressure
} bme280_readings;
/**************************************************************************/
/*!
@brief Class that stores state and functions for interacting with BME280 IC
*/
/**************************************************************************/
class Adafruit_BME280 {
public:
/*=========================================================*/
/**************************************************************************/
/*!
@brief sampling rates
@ -188,6 +202,19 @@ public:
STANDBY_MS_1000 = 0b101
};
/*******************************************************/
/*!
@brief read status for readAll()
*/
/*******************************************************/
enum read_success {
BME280_T_OK = 0x01,
BME280_P_OK = 0x02,
BME280_H_OK = 0x04
};
// constructors
Adafruit_BME280();
Adafruit_BME280(int8_t cspin, SPIClass *theSPI = &SPI);
@ -214,6 +241,8 @@ public:
float readAltitude(float seaLevel);
float seaLevelForAltitude(float altitude, float pressure);
int readAll(bme280_readings& readings);
uint32_t sensorID(void);
protected:

View File

@ -85,10 +85,10 @@ const int _number_of_closed_slots = CONFIG_LWIP_MAX_ACTIVE_TCP;
static uint32_t _closed_slots[_number_of_closed_slots];
static uint32_t _closed_index = []() {
_slots_lock = xSemaphoreCreateBinary();
xSemaphoreGive(_slots_lock);
for (int i = 0; i < _number_of_closed_slots; ++ i) {
_closed_slots[i] = 1;
_closed_slots[i] = 1; // slot available
}
xSemaphoreGive(_slots_lock);
return 1;
}();
@ -849,21 +849,25 @@ void AsyncClient::_allocate_closed_slot(){
}
}
if (_closed_slot != -1) {
_closed_slots[_closed_slot] = 0;
_closed_slots[_closed_slot] = 0; // slot in use!
}
xSemaphoreGive(_slots_lock);
}
void AsyncClient::_free_closed_slot(){
xSemaphoreTake(_slots_lock, portMAX_DELAY);
if(_closed_slot >= 16 || _closed_slot < -1) {
Serial.printf("CLOSED SLOTS BOUNDS!! free_closed_slot (%d)\r\n", _closed_slot);
xSemaphoreGive(_slots_lock);
return;
}
if (_closed_slot != -1) {
_closed_slots[_closed_slot] = _closed_index;
_closed_slots[_closed_slot] = _closed_index; // slot released by index
_closed_slot = -1;
++ _closed_index;
if(_closed_index == 0) _closed_index = 1;
}
xSemaphoreGive(_slots_lock);
}
/*
@ -888,12 +892,12 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){
void AsyncClient::_error(int8_t err) {
if(_pcb){
tcp_arg(_pcb, NULL);
if(_pcb->state == LISTEN) {
// if(_pcb->state == LISTEN) {
tcp_sent(_pcb, NULL);
tcp_recv(_pcb, NULL);
tcp_err(_pcb, NULL);
tcp_poll(_pcb, NULL, 0);
}
// }
_pcb = NULL;
}
if(_error_cb) {
@ -911,12 +915,12 @@ int8_t AsyncClient::_lwip_fin(tcp_pcb* pcb, int8_t err) {
return ERR_OK;
}
tcp_arg(_pcb, NULL);
if(_pcb->state == LISTEN) {
// if(_pcb->state == LISTEN) {
tcp_sent(_pcb, NULL);
tcp_recv(_pcb, NULL);
tcp_err(_pcb, NULL);
tcp_poll(_pcb, NULL, 0);
}
// }
if(tcp_close(_pcb) != ERR_OK) {
tcp_abort(_pcb);
}

View File

@ -152,6 +152,8 @@ void heaterOff();
void updateFilteredData(CProtocol& HeaterInfo);
bool HandleMQTTsetup(char rxVal);
void showMainmenu();
bool checkTemperatureSensors();
void checkBlueWireEvents();
// DS18B20 temperature sensor support
// Uses the RMT timeslot driver to operate as a one-wire bus
@ -181,6 +183,7 @@ CGPIOalg GPIOalg;
#endif
CMQTTsetup MQTTmenu;
CSecuritySetup SecurityMenu;
@ -261,14 +264,52 @@ CBluetoothAbstract& getBluetoothClient()
return Bluetooth;
}
// collect and report any debug messages from the blue wire task
char taskMsg[BLUEWIRE_MSGQUEUESIZE];
void checkBlueWireDebugMsgs()
void checkBlueWireEvents()
{
// collect and report any debug messages from the blue wire task
if(BlueWireMsgBuf && xQueueReceive(BlueWireMsgBuf, taskMsg, 0))
DebugPort.print(taskMsg);
// check for complted data exchange from the blue wire task
if(BlueWireSemaphore && xSemaphoreTake(BlueWireSemaphore, 0)) {
updateJSONclients(bReportJSONData);
updateMQTT();
NVstore.doSave(); // now is a good time to store to the NV storage, well away from any blue wire activity
}
// collect transmitted heater data from blue wire task
if(BlueWireTxQueue && xQueueReceive(BlueWireTxQueue, BlueWireTxData.Data, 0)) {
}
// collect and process received heater data from blue wire task
if(BlueWireRxQueue && xQueueReceive(BlueWireRxQueue, BlueWireRxData.Data, 0)) {
BlueWireData.set(BlueWireRxData, BlueWireTxData);
SmartError.monitor(BlueWireRxData);
updateFilteredData(BlueWireRxData);
FuelGauge.Integrate(BlueWireRxData.getPump_Actual());
if(INBOUNDS(BlueWireRxData.getRunState(), 1, 5)) { // check for Low Voltage Cutout
SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue());
SmartError.checkfuelUsage();
}
// trap being in state 0 with a heater error - cancel user on memory to avoid unexpected cyclic restarts
if(RTC_Store.getCyclicEngaged() && (BlueWireRxData.getRunState() == 0) && (BlueWireRxData.getErrState() > 1)) {
const char* msg = "Forcing cyclic cancel due to error induced shutdown\r\n";
xQueueSend(BlueWireMsgBuf, msg, 0);
// DebugPort.println("Forcing cyclic cancel due to error induced shutdown");
RTC_Store.setCyclicEngaged(false);
}
pHourMeter->monitor(BlueWireRxData);
}
}
// callback function for Keypad events.
// must be an absolute function, cannot be a class member due the "this" element!
void parentKeyHandler(uint8_t event)
@ -308,6 +349,19 @@ void WatchdogTask(void * param)
}
}
void webSocketTask(void*)
{
for(;;) {
#if USE_WEBSERVER == 1
#ifndef OLD_WEBSOCKETHANDLER
bHaveWebClient = doWebServer();
#endif
#endif //USE_WEBSERVER
checkWebSocketSend();
vTaskDelay(1);
}
}
//**************************************************************************************************
//** **
@ -340,6 +394,8 @@ extern "C" unsigned long __wrap_millis() {
void setup() {
vTaskPrioritySet(NULL, TASK_PRIORITY_ARDUINO); // elevate normal ardion loop etc higher than the usual '1'
// ensure cyclic mode is disabled after power on
bool bESP32PowerUpInit = false;
if(rtc_get_reset_reason(0) == 1/* || bForceInit*/) {
@ -522,13 +578,24 @@ void setup() {
TempSensor.getDS18B20().mapSensor(2, NVstore.getHeaterTuning().DS18B20probe[2].romCode);
// create task to run blue wire interface
TaskHandle_t bwTask;
TaskHandle_t Task;
xTaskCreate(BlueWireTask,
"BlueWireTask",
2000,
NULL,
3,
&bwTask);
TASK_PRIORITY_BLUEWIRE,
&Task);
// create task to run the websockets
xTaskCreate(webSocketTask,
"WebSocketTask",
6000,
NULL,
TASK_PRIORITY_ARDUINO,
&Task);
delay(1000); // just to hold the splash screeen for while
}
@ -541,23 +608,28 @@ void setup() {
void loop()
{
float fTemperature;
unsigned long timenow = millis();
// DebugPort.handle(); // keep telnet spy alive
// report any debug messages from the blue wire task
checkBlueWireDebugMsgs();
feedWatchdog(); // feed watchdog
doStreaming(); // do wifi, BT tx etc
Clock.update();
if(checkTemperatureSensors())
ScreenManager.reqUpdate();
checkDisplayUpdate();
long tDelta = timenow - lastTemperatureTime;
checkBlueWireEvents();
vTaskDelay(1);
} // loop
bool checkTemperatureSensors()
{
long tDelta = millis() - lastTemperatureTime;
if(tDelta > MIN_TEMPERATURE_INTERVAL) { // maintain a minimum holdoff period
lastTemperatureTime = millis(); // reset time to observe temeprature
@ -567,6 +639,8 @@ void loop()
}
TempSensor.readSensors();
float fTemperature;
if(TempSensor.getTemperature(0, fTemperature)) { // get Primary sensor temperature
if(DS18B20holdoff) {
DS18B20holdoff--;
@ -588,48 +662,10 @@ void loop()
TempSensor.startConvert(); // request a new conversion, will be ready by the time we loop back around
ScreenManager.reqUpdate();
return true;
}
if(BlueWireSemaphore && xSemaphoreTake(BlueWireSemaphore, 0)) {
updateJSONclients(bReportJSONData);
updateMQTT();
NVstore.doSave(); // now is a good time to store to the NV storage, well away from any blue wire activity
}
// collect transmitted heater data from blue wire task
if(BlueWireTxQueue && xQueueReceive(BlueWireTxQueue, BlueWireTxData.Data, 0)) {
}
// collect and process received heater data from blue wire task
if(BlueWireRxQueue && xQueueReceive(BlueWireRxQueue, BlueWireRxData.Data, 0)) {
BlueWireData.set(BlueWireRxData, BlueWireTxData);
SmartError.monitor(BlueWireRxData);
updateFilteredData(BlueWireRxData);
FuelGauge.Integrate(BlueWireRxData.getPump_Actual());
if(INBOUNDS(BlueWireRxData.getRunState(), 1, 5)) { // check for Low Voltage Cutout
SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue());
SmartError.checkfuelUsage();
}
// trap being in state 0 with a heater error - cancel user on memory to avoid unexpected cyclic restarts
if(RTC_Store.getCyclicEngaged() && (BlueWireRxData.getRunState() == 0) && (BlueWireRxData.getErrState() > 1)) {
const char* msg = "Forcing cyclic cancel due to error induced shutdown\r\n";
xQueueSend(BlueWireMsgBuf, msg, 0);
// DebugPort.println("Forcing cyclic cancel due to error induced shutdown");
RTC_Store.setCyclicEngaged(false);
}
pHourMeter->monitor(BlueWireRxData);
}
} // loop
return false;
}
void manageCyclicMode()
{
@ -827,6 +863,12 @@ void checkDebugCommands()
}
return;
}
if(SecurityMenu.Handle(rxVal)) {
if(rxVal == 0) {
showMainmenu();
}
return;
}
if(nGetConf) {
DebugPort.print(rxVal);
@ -1130,6 +1172,9 @@ void checkDebugCommands()
else if(rxVal == 'm') {
MQTTmenu.setActive();
}
else if(rxVal == 's') {
SecurityMenu.setActive();
}
else if(rxVal == ('o' & 0x1f)) {
bReportOEMresync = !bReportOEMresync;
DebugPort.printf("Toggled OEM resync event reporting %s\r\n", bReportOEMresync ? "ON" : "OFF");
@ -1413,7 +1458,9 @@ void doStreaming()
doOTA();
#endif // USE_OTA
#if USE_WEBSERVER == 1
#ifdef OLD_WEBSOCKETHANDLER
bHaveWebClient = doWebServer();
#endif
#endif //USE_WEBSERVER
#if USE_MQTT == 1
// most MQTT is managed via callbacks, but need some sundry housekeeping
@ -1586,26 +1633,6 @@ void setPassword(const char* name, int type)
}
}
void setWebUsername(const char* name)
{
sCredentials creds = NVstore.getCredentials();
strncpy(creds.webUsername, name, 31);
creds.webUsername[31] = 0;
NVstore.setCredentials(creds);
NVstore.save();
NVstore.doSave(); // ensure NV storage
}
void setWebPassword(const char* name)
{
sCredentials creds = NVstore.getCredentials();
strncpy(creds.webPassword, name, 31);
creds.webPassword[31] = 0;
NVstore.setCredentials(creds);
NVstore.save();
NVstore.doSave(); // ensure NV storage
}
void showMainmenu()
{
@ -1614,13 +1641,8 @@ void showMainmenu()
DebugPort.println("");
DebugPort.printf(" <B> - toggle raw blue wire data reporting, currently %s\r\n", bReportBlueWireData ? "ON" : "OFF");
DebugPort.printf(" <J> - toggle output JSON reporting, currently %s\r\n", bReportJSONData ? "ON" : "OFF");
DebugPort.printf(" <N> - change AP SSID, currently \"%s\"\r\n", NVstore.getCredentials().APSSID);
DebugPort.println(" <P> - change AP password");
DebugPort.println(" <M> - configure MQTT");
DebugPort.println(" <U> - change Web page username");
DebugPort.println(" <W> - change Web page password");
DebugPort.println(" <Y> - change Web /update username");
DebugPort.println(" <Z> - change Web /update password");
DebugPort.println(" <S> - configure Security");
DebugPort.println(" <+> - request heater turns ON");
DebugPort.println(" <-> - request heater turns OFF");
DebugPort.println(" <CTRL-R> - restart the ESP");

View File

@ -61,6 +61,26 @@ CBME280Screen::show()
_printMenuText(80, 26, msg, false);
sprintf(msg, "%.0fm", altitude);
_printMenuText(80, 36, msg, false);
// int rv = getTempSensor().getBME280().getAllReadings(readings);
// if(rv & Adafruit_BME280::BME280_T_OK)
// sprintf(msg, "%.1f`C", readings.temperature);
// else
// strcpy(msg, "n/a");
// _printMenuText(80, 16, msg, false);
//
// if(rv & Adafruit_BME280::BME280_H_OK)
// sprintf(msg, "%.1f%%", readings.humidity);
// else
// strcpy(msg, "n/a");
// _printMenuText(80, 26, msg, false);
//
// if(rv & Adafruit_BME280::BME280_P_OK)
// sprintf(msg, "%.0fm", readings.altitude);
// else
// strcpy(msg, "n/a");
// _printMenuText(80, 36, msg, false);
}
else {
_printMenuText(64, 16, "Sensor not found", false, eCentreJustify);

View File

@ -84,7 +84,7 @@ CClock::update()
_currentTime = _rtc.now(); // moderate I2C accesses
Wire.setClock(origClock);
_nextRTCfetch = millis() + 500;
// _checkTimers();
// check timers upon minute rollovers
if(_currentTime.minute() != _prevMinute) {
CTimerManager::manageTime(_currentTime.hour(), _currentTime.minute(), _currentTime.dayOfTheWeek());

View File

@ -66,21 +66,30 @@ CGetLine::handle(char rxVal)
if(rxVal < ' ') {
if(_idx == 0) {
if(_pTarget)
strcpy(_buffer, _pTarget);
strcpy(_buffer, _pTarget); // copy buffer if control upon first key, may well be a enter
}
if(rxVal == ('x' & 0x1f)) { // CTRL-X - erase string, return done
memset(_buffer, 0, sizeof(_buffer));
// CTRL-H (backspace)
if(rxVal == ('h' & 0x1f)) {
if(_idx)
_idx--;
}
// CTRL-X
if(rxVal == ('x' & 0x1f)) {
memset(_buffer, 0, sizeof(_buffer)); // erase string, return done
_zeroTarget();
return true;
}
if(rxVal == '\r') // ignore CR
return false;
if(rxVal == '\n') { // accept buffered string upon LF, return done
_copyTarget();
// CR (ala CTRL-M)
if(rxVal == '\r')
return false; // do nothing upon CR
// LF (ala CTRL-J)
if(rxVal == '\n') {
_copyTarget(); // accept buffered string upon LF, return done
return true;
}
if(rxVal == 0x1b) { // abort, no change upon ESC, return done
return true;
// ESC
if(rxVal == 0x1b) {
return true; // abort, no change upon ESC, return done
}
}
else {
@ -89,10 +98,16 @@ CGetLine::handle(char rxVal)
DebugPort.print('*');
else
DebugPort.print(rxVal);
_buffer[_idx++] = rxVal;
if(_idx == _maxlen) {
_copyTarget();
return true;
if(rxVal == 0x7f) { // backspace
if(_idx)
_idx--;
}
else {
_buffer[_idx++] = rxVal;
if(_idx == _maxlen) {
_copyTarget();
return true;
}
}
}
return false;
@ -109,6 +124,11 @@ CGetLine::_doNum(char rxVal)
_Numeric = val;
return true;
}
// CTRL-H (backspace)
if(rxVal == ('h' & 0x1f)) {
if(_idx)
_idx--;
}
if(rxVal == 0x1b) {
return true;
}
@ -125,6 +145,11 @@ CGetLine::_doNum(char rxVal)
}
}
else {
if(rxVal == 0x7f) { // backspace
if(_idx)
_idx--;
return false;
}
return true;
}
return false;

View File

@ -183,3 +183,275 @@ CMQTTsetup::HandleMQTTsetup(char rxVal)
return true;
}
CSecuritySetup::CSecuritySetup()
{
_active = false;
_password.Idx = 0;
_password.State = 0;
}
void
CSecuritySetup::setActive()
{
_active = true;
_showMenu(true);
}
void insertDummy(int len);
void
CSecuritySetup::_showMenu(bool init)
{
_mode = 0;
_password.Idx = 0;
_password.State = 0;
DebugPort.enable(true);
if(init)
_credsSetup = NVstore.getCredentials();
int len;
DebugPort.print("\014");
DebugPort.println("Security configuration");
DebugPort.println("");
DebugPort.println(" Access Point credentials");
DebugPort.printf(" <1> - set SSID, currently \"%s\"\r\n", _credsSetup.APSSID);
DebugPort.print(" <2> - set password");
len = strlen(_credsSetup.APpassword);
if(len == 0)
DebugPort.print(", currently UNRESTRICTED\r\n");
else {
insertDummy(len);
}
DebugPort.println("");
DebugPort.println(" Web page credentials");
DebugPort.printf(" <3> - set username, currently \"%s\"\r\n", _credsSetup.webUsername);
DebugPort.print(" <4> - set password");
len = strlen(_credsSetup.webPassword);
if(len == 0)
DebugPort.printf(", currently UNRESTRICTED\r\n");
else {
insertDummy(len);
}
DebugPort.println("");
DebugPort.println(" /update web page credentials");
DebugPort.printf(" <5> - set username, currently \"%s\"\r\n", _credsSetup.webUpdateUsername);
DebugPort.printf(" <6> - set password");
len = strlen(_credsSetup.webUpdatePassword);
if(len == 0)
DebugPort.printf(", UNRESTRICTED!\r\n");
else {
insertDummy(len);
}
DebugPort.println("");
DebugPort.printf(" <ENTER> - save and exit\r\n");
DebugPort.printf(" <ESC> - abort\r\n");
DebugPort.enable(false); // suppress sundry debug whilst Security menu is active
}
void insertDummy(int len) {
char dummy[32];
memset(dummy, 0, 32);
if(len > 31)
len = 31;
for(int i = 0; i < len; i++)
dummy[i] = '*';
DebugPort.printf(" (%s)\r\n", dummy);
}
bool
CSecuritySetup::Handle(char& rxVal)
{
if(_active) {
DebugPort.enable(true);
_active = _handle(rxVal);
if(_active)
DebugPort.enable(false);
else
rxVal = 0;
return true;
}
return false;
}
bool
CSecuritySetup::_handle(char rxVal)
{
bool bJumptoMenuRoot = false;
if(_getPassword()) {
if(_handlePassword(rxVal)) {
if(!_getPassword())
_showMenu();
}
return true;
}
switch(_mode) {
case 0: // initial menu entry selection
if(rxVal == 0x1b) {
_credsSetup = NVstore.getCredentials();
return false;
}
if(rxVal == '\n') {
NVstore.setCredentials(_credsSetup);
NVstore.save();
return false;
}
if(rxVal >= '1' && rxVal <= '6') {
_mode = rxVal - '0';
DebugPort.print("\014");
switch(_mode) {
case 1:
DebugPort.printf("Enter new AP SSID (%s)", _credsSetup.APSSID);
_lineInput.reset(_credsSetup.APSSID, 31);
break;
case 2:
DebugPort.print("Enter current AP password");
_initPassword(0);
break;
case 3:
DebugPort.printf("Enter new Web page access username (currently '%s', CTRL-X to erase)", _credsSetup.webUsername);
_lineInput.reset(_credsSetup.webUsername, 31);
break;
case 4:
DebugPort.print("Enter current web page access password");
_initPassword(1);
break;
case 5:
DebugPort.printf("Enter new /update web page access username (currently '%s', CTRL-X to erase)", _credsSetup.webUpdateUsername);
_lineInput.reset(_credsSetup.webUpdateUsername, 31);
break;
case 6:
DebugPort.print("Enter current /update web page access password");
_initPassword(2);
break;
}
DebugPort.print("... ");
}
else {
_showMenu();
}
return true;
case 1: // enter AP SSID
case 2: // enter AP password
case 3: // enter web page username
case 4: // enter web page password
case 5: // enter /update username
case 6: // enter /update password
if(_lineInput.handle(rxVal)) {
bJumptoMenuRoot = true;
}
break;
}
if(bJumptoMenuRoot) {
_showMenu();
}
return true;
}
void
CSecuritySetup::_initPassword(int idx)
{
_lineInput.reset();
_lineInput.maskEntry();
_password.Idx = idx;
_password.State = 1;
}
bool
CSecuritySetup::_getPassword()
{
return _password.State != 0;
}
bool
CSecuritySetup::_handlePassword(char rxVal)
{
switch(_password.State) {
case 1:
if(_lineInput.handle(rxVal)) {
_password.str1 = _lineInput.getString();
_password.str2 = _getCurrentPassword();
if(_password.str1 != _password.str2) {
DebugPort.println("\r\nPassword does not match existing - ABORTING");
_password.State = 0;
}
else {
_password.State = 2;
DebugPort.print("\r\nPlease enter new password - ");
DebugPort.enable(false); // block other debug msgs whilst we get the password
}
_lineInput.reset();
_lineInput.maskEntry();
}
return true;
case 2:
if(_lineInput.handle(rxVal)) {
_password.str1 = _lineInput.getString();
if(_lineInput.getLen() < 8) {
// ABORT - too short
DebugPort.println("\r\nNew password must be at least 8 characters - ABORTING");
_password.State = 0;
}
else if(_lineInput.getLen() > 31) {
// ABORT - too long!
DebugPort.println("\r\nNew password is longer than 31 characters - ABORTING");
_password.State = 0;
}
else {
_password.State = 3;
DebugPort.print("\r\nPlease confirm new password - ");
DebugPort.enable(false); // block other debug msgs whilst we get the password
}
_lineInput.reset();
_lineInput.maskEntry();
}
return true;
case 3:
if(_lineInput.handle(rxVal)) {
_password.str2 = _lineInput.getString();
_lineInput.reset();
if(_password.str1 != _password.str2) {
DebugPort.println("\r\nNew passwords do not match - ABORTING");
_password.State = 0;
}
else {
_password.State = 4;
DebugPort.print("\r\nSet new password (y/n) - ");
}
}
return true;
case 4:
if(rxVal == 'y' || rxVal == 'Y') {
_setPassword(_password.str2.c_str());
}
_password.State = 0;
return true;
}
return false;
}
const char*
CSecuritySetup::_getCurrentPassword() {
switch(_password.Idx) {
case 0: return _credsSetup.APpassword;
case 1: return _credsSetup.webPassword;
case 2: return _credsSetup.webUpdatePassword;
}
return "";
}
void
CSecuritySetup::_setPassword(const char* newPW)
{
switch(_password.Idx) {
case 0: strcpy(_credsSetup.APpassword, newPW); break;
case 1: strcpy(_credsSetup.webPassword, newPW); break;
case 2: strcpy(_credsSetup.webUpdatePassword, newPW); break;
}
}

View File

@ -35,3 +35,26 @@ public:
bool Handle(char& rxVal);
void setActive();
};
class CSecuritySetup {
CGetLine _lineInput;
int _mode;
bool _active;
struct {
int Idx;
int State;
String str1, str2;
} _password;
sCredentials _credsSetup;
bool _handle(char rxVal);
void _showMenu(bool init = false);
void _initPassword(int idx);
bool _getPassword();
bool _handlePassword(char rxVal);
const char* _getCurrentPassword();
void _setPassword(const char* newPW);
public:
CSecuritySetup();
bool Handle(char& rxVal);
void setActive();
};

View File

@ -429,6 +429,7 @@ CBME280Sensor::getTemperature(float& tempReading, bool filtered)
float temperature = _bme.readTemperature();
update(temperature);
_lastSampleTime = millis() + 1000;
DebugPort.println("Forced BME sensor reading");
}
CSensor::getTemperature(tempReading, filtered);
@ -457,6 +458,19 @@ CBME280Sensor::getHumidity(float& reading, bool fresh)
return true;
}
int
CBME280Sensor::getAllReadings(bme280_readings& readings)
{
int retval = _bme.readAll(readings);
_fAltitude = readings.altitude;
_fHumidity = readings.humidity;
update(readings.temperature);
_lastSampleTime = millis() + 1000;
return retval;
}
const char*
CBME280Sensor::getID()
{
@ -495,9 +509,8 @@ CTempSense::startConvert()
bool
CTempSense::readSensors()
{
float fDummy;
getAltitude(fDummy, true);
getHumidity(fDummy, true);
bme280_readings readings;
getBME280().getAllReadings(readings);
return DS18B20.readSensors();
}

View File

@ -98,6 +98,7 @@ public:
bool getTemperature(float& tempReading, bool filtered) ;
bool getAltitude(float& reading, bool fresh=false);
bool getHumidity(float& reading, bool fresh=false);
int getAllReadings(bme280_readings& readings);
const char* getID();
int getCount() const { return _count; };
};

View File

@ -42,6 +42,7 @@
#include "BrowserUpload.h"
#include <Update.h>
#include "WebContentDL.h"
#include <FreeRTOS.h>
extern WiFiManager wm;
extern const char* stdHeader;
@ -50,6 +51,8 @@ extern const char* updateIndex;
extern const char* formatDoneContent;
extern const char* rebootIndex;
QueueHandle_t webSocketQueue = NULL;
extern void checkSplashScreenUpdate();
sBrowserUpload BrowserUpload;
@ -85,6 +88,7 @@ void onUploadProgression();
void onRename();
void build404Response(String& content, String file);
void build500Response(String& content, String file);
bool checkWebSocketSend();
const char* getWebContent(bool start) {
@ -99,6 +103,8 @@ const char* getWebContent(bool start) {
void initWebServer(void) {
webSocketQueue = xQueueCreate(10, sizeof(char*));
if (MDNS.begin("Afterburner")) {
DebugPort.println("MDNS responder started");
}
@ -175,13 +181,18 @@ String getContentType(String filename) { // convert the file extension to the MI
}
bool handleFileRead(String path) { // send the right file to the client (if it exists)
DebugPort.println("handleFileRead: " + path);
if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file
if(path.indexOf("index.html") >= 0) {
if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file in that folder
if(path.indexOf("index.html") >= 0) { // if referencing
sCredentials creds = NVstore.getCredentials();
if (!server.authenticate(creds.webUsername, creds.webPassword)) {
server.requestAuthentication();
return true; // not entirely correct, but avoids 404 response
if(strlen(creds.webPassword)) { // optionally present an authentication prompt for /index.html
if (!server.authenticate(creds.webUsername, creds.webPassword)) {
server.requestAuthentication();
return true; // not entirely correct, but avoids 404 response
}
}
}
@ -495,13 +506,18 @@ void rootRedirect()
server.send(303);
}
bool sendWebSocketString(const char* Str)
{
#ifdef WEBTIMES
CProfile profile;
#endif
if(webSocket.connectedClients()) {
char* pMsg = new char[strlen(Str)+1];
strcpy(pMsg, Str);
if(webSocketQueue) xQueueSend(webSocketQueue, &pMsg, 0);
/* if(webSocket.connectedClients()) {
#ifdef WEBTIMES
unsigned long tCon = profile.elapsed(true);
@ -516,6 +532,38 @@ bool sendWebSocketString(const char* Str)
#endif
feedWatchdog();
return retval;
}*/
return false;
}
bool checkWebSocketSend()
{
bool retval = false;
#ifdef WEBTIMES
CProfile profile;
#endif
char* pMsg = NULL;
if(webSocketQueue && xQueueReceive(webSocketQueue, &pMsg, 0)) {
if(webSocket.connectedClients()) {
#ifdef WEBTIMES
unsigned long tCon = profile.elapsed(true);
#endif
bTxWebData = true; // OLED tx data animation flag
if(pMsg)
retval = webSocket.broadcastTXT(pMsg);
#ifdef WEBTIMES
unsigned long tWeb = profile.elapsed(true);
DebugPort.printf("Websend times : %ld,%ld\r\n", tCon, tWeb);
#endif
// feedWatchdog();
delete pMsg;
}
return retval;
}
return false;
}

View File

@ -36,6 +36,7 @@ void listSPIFFS(const char * dirname, uint8_t levels, String& HTMLreport, int wi
const char* getWebContent(bool start);
void getWebContent(const char* filename);
bool checkWebSocketSend();
#endif

View File

@ -117,3 +117,6 @@
//
#define USE_SW_WATCHDOG 1
#define TASK_PRIORITY_ARDUINO 3
#define TASK_PRIORITY_BLUEWIRE 5