diff --git a/src/Afterburner.cpp b/src/Afterburner.cpp index ce03650..afe0580 100644 --- a/src/Afterburner.cpp +++ b/src/Afterburner.cpp @@ -121,6 +121,7 @@ #include "Utility/GetLine.h" #include "Utility/DemandManager.h" #include "Protocol/BlueWireTask.h" +#include "Protocol/433MHz.h" #if USE_TWDT == 1 #include "esp_task_wdt.h" #endif @@ -132,9 +133,9 @@ // #define RX_DATA_TIMOUT 50 const int FirmwareRevision = 32; -const int FirmwareSubRevision = 0; -const int FirmwareMinorRevision = 0; -const char* FirmwareDate = "21 May 2020"; +const int FirmwareSubRevision = 1; +const int FirmwareMinorRevision = ; +const char* FirmwareDate = "19 Jun 2020"; /* * Macro to check the outputs of TWDT functions and trigger an abort if an @@ -170,6 +171,7 @@ bool HandleMQTTsetup(char rxVal); void showMainmenu(); bool checkTemperatureSensors(); void checkBlueWireEvents(); +void checkUHF(); // DS18B20 temperature sensor support // Uses the RMT timeslot driver to operate as a one-wire bus @@ -217,6 +219,7 @@ bool bReportBlueWireData = REPORT_RAW_DATA; bool bReportJSONData = REPORT_JSON_TRANSMIT; bool bReportRecyleEvents = REPORT_BLUEWIRE_RECYCLES; bool bReportOEMresync = REPORT_OEM_RESYNC; +bool pair433MHz = false; CProtocol BlueWireRxData; CProtocol BlueWireTxData; @@ -602,6 +605,7 @@ void setup() { &handleBlueWireTask); + UHFremote.begin(Rx433MHz_pin, RMT_CHANNEL_4); delay(1000); // just to hold the splash screeen for while @@ -632,6 +636,8 @@ void loop() checkBlueWireEvents(); + checkUHF(); + vTaskDelay(1); } // loop @@ -1006,6 +1012,9 @@ void checkDebugCommands() else if(rxVal == ('h' & 0x1f)) { // CTRL-H hourmeter reset pHourMeter->resetHard(); } + else if(rxVal == ('p' & 0x1f)) { // CTRL-P fuel usage reset + FuelGauge.reset(); + } else if(rxVal == ('r' & 0x1f)) { // CTRL-R reboot ESP.restart(); // reset the esp } @@ -1470,3 +1479,52 @@ const CProtocolPackage& getHeaterInfo() return BlueWireData; } +// int UHFsubcode(int val) +// { +// val &= 0x03; +// val = 0x0001 << val; +// return val; +// } + +void checkUHF() +{ + if(!pair433MHz) { + UHFremote.manage(); + // unsigned long test = 0xF5F0AC10; + // if(UHFremote.available()) { + // unsigned long code; + // UHFremote.read(code); + // DebugPort.printf("UHF remote code = %08lX\r\n", code); + + // unsigned long ID = (test >> 8) & 0xfffff0; + // if(((code ^ ID) & 0xfffff0) == 0) { + // int subCode = code & 0xf; + // if(test & 0x800) { + // if((UHFsubcode(test >> 6) ^ subCode) == 0xf) { + // DebugPort.println("UHF start request!"); + // HeaterManager.reqOnOff(true); + // } + // } + // if(test & 0x400) { + // if((UHFsubcode(test >> 4) ^ subCode) == 0xf) { + // DebugPort.println("UHF stop request!"); + // HeaterManager.reqOnOff(false); + // } + // } + // if(test & 0x200) { + // if((UHFsubcode(test >> 2) ^ subCode) == 0xf) { + // DebugPort.println("UHF inc temp request!"); + // CDemandManager::deltaDemand(+1); + // } + // } + // if(test & 0x100) { + // if((UHFsubcode(test >> 0) ^ subCode) == 0xf) { + // DebugPort.println("UHF dec temp request!"); + // CDemandManager::deltaDemand(+1); + // } + // } + // } + // } + } +} + diff --git a/src/Bluetooth/BluetoothHC05.cpp b/src/Bluetooth/BluetoothHC05.cpp index ec6de19..38b6d10 100644 --- a/src/Bluetooth/BluetoothHC05.cpp +++ b/src/Bluetooth/BluetoothHC05.cpp @@ -113,6 +113,12 @@ CBluetoothHC05::begin() DebugPort.println("HC-05 found"); + Reset(true); // reset, staying in command mode + + _openSerial(38400); // open serial port at a std. baud rate + + delay(100); + DebugPort.print(" Setting Name to \"Afterburner\"... "); if(!ATCommand("AT+NAME=\"Afterburner\"\r\n")) { DebugPort.println("FAILED"); @@ -122,7 +128,8 @@ CBluetoothHC05::begin() } DebugPort.print(" Setting baud rate to 9600N81..."); - if(!ATCommand("AT+UART=9600,1,0\r\n")) { + //if(!ATCommand("AT+UART=9600,1,0\r\n")) { + if(!ATCommand("AT+UART=38400,1,0\r\n")) { DebugPort.println("FAILED"); } else { @@ -164,10 +171,11 @@ CBluetoothHC05::begin() }*/ _flush(); delay(100); - _openSerial(9600); + // _openSerial(9600); // leave HC-05 command mode, return to data mode - digitalWrite(_keyPin, LOW); + Reset(false); // reset, shift into data mode6 + // digitalWrite(_keyPin, LOW); } @@ -236,6 +244,16 @@ CBluetoothHC05::ATCommand(const char* cmd) return false; } +bool +CBluetoothHC05::Reset(bool keystate) +{ + HC05_SerialPort.print("AT+RESET\r\n"); + digitalWrite(_keyPin, keystate ? HIGH : LOW); + delay(1000); + _flush(); + return true; +} + // protected function, to perform Hayes commands with HC-05 bool CBluetoothHC05::ATResponse(const char* cmd, const char* respHdr, char* response, int& len) diff --git a/src/Bluetooth/BluetoothHC05.h b/src/Bluetooth/BluetoothHC05.h index 580f525..c9fbaf0 100644 --- a/src/Bluetooth/BluetoothHC05.h +++ b/src/Bluetooth/BluetoothHC05.h @@ -39,6 +39,7 @@ static HardwareSerial& HC05_SerialPort(Serial2); class CBluetoothHC05 : public CBluetoothAbstract { bool ATCommand(const char* str); bool ATResponse(const char* str, const char* respHdr, char* response, int& len); + bool Reset(bool keystate); int _sensePin, _keyPin; CModerator foldbackModerator; char _MAC[32]; diff --git a/src/OLED/433MHzScreen.cpp b/src/OLED/433MHzScreen.cpp new file mode 100644 index 0000000..aef18c0 --- /dev/null +++ b/src/OLED/433MHzScreen.cpp @@ -0,0 +1,332 @@ +/* + * This file is part of the "bluetoothheater" distribution + * (https://gitlab.com/mrjones.id.au/bluetoothheater) + * + * Copyright (C) 2020 Ray Jones + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +/////////////////////////////////////////////////////////////////////////// +// +// C433MHzScreen +// +// This screen allows the pairing of 433MHz remotes +// +/////////////////////////////////////////////////////////////////////////// + +#include "433MHzScreen.h" +#include "KeyPad.h" +#include "fonts/Arial.h" +#include "../RTC/Clock.h" +#include "../Utility/macros.h" +#include "../Utility/NVStorage.h" +#include "../Protocol/433MHz.h" +#include "fonts/Icons.h" + +extern bool pair433MHz; +static const int column[] = { 64, 84, 104, 120 }; +static const int line[] = { 42, 31, 20 }; + +C433MHzScreen::C433MHzScreen(C128x64_OLED& display, CScreenManager& mgr) : CUIEditScreen(display, mgr) +{ + _initUI(); +} + +bool +C433MHzScreen::onSelect() +{ + CScreen::onSelect(); + _initUI(); + pair433MHz = true; + UHFremote.getCodes(_rawCodes); + return true; +} + +void +C433MHzScreen::onExit() +{ + pair433MHz = false; +} + + +void +C433MHzScreen::_initUI() +{ + CUIEditScreen::_initUI(); + _repeatCount = 0; +} + + +bool +C433MHzScreen::show() +{ + _display.clearDisplay(); + + if(!CUIEditScreen::show()) { + + _showTitle("433MHz Remote"); + + _drawBitmap(61, 13, medStopIconInfo); + _drawBitmap(81, 12, medStartIconInfo); + _drawBitmap(100, 14, dnIconInfo); + _drawBitmap(116, 13, upIconInfo); + + _printMenuText(5, line[2], "Remote 1", _rowSel == 3 && _colSel == 0); + _printMenuText(5, line[1], "Remote 2", _rowSel == 2 && _colSel == 0); + _printMenuText(5, line[0], "Remote 3", _rowSel == 1 && _colSel == 0); + + if(_rowSel == 0) { + _printMenuText(_display.xCentre(), 53, " \021 Exit \020 ", true, eCentreJustify); + } + else { + switch(_colSel) { + case 0: + _printMenuText(_display.xCentre(), 54, " \020 to start teaching ", false, eCentreJustify); + break; + case 1: + _printMenuText(_display.xCentre(), 54, " Teach \"Off\"", false, eCentreJustify); + break; + case 2: + _printMenuText(_display.xCentre(), 54, " Teach \"On\" ", false, eCentreJustify); + break; + case 3: + _printMenuText(_display.xCentre(), 54, " Teach \"Decrease\" ", false, eCentreJustify); + break; + case 4: + _printMenuText(_display.xCentre(), 54, " Teach \"Increase\" ", false, eCentreJustify); + break; + } + } + } + + return true; +} + +bool +C433MHzScreen::animate() +{ + + if(_saveBusy()) { + return false; + } + + if(UHFremote.available()) { + UHFremote.read(_code); + DebugPort.printf("UHF remote code = %08lX\r\n", _code); + if(_colSel) { + if(_code) { + _rawCodes[_rowSel-1][_colSel-1] = _code; + } + else { + _colSel++; + WRAPLIMITS(_colSel, 0, 4); + } + } + } + for(int row = 0; row < 3; row++) { + for(int col = 0; col < 4; col++) { + int xPos = column[col]; + int yPos = line[row]; + bool rowColMatch = (row == (_rowSel-1)) && (col == (_colSel-1)); + if(_rawCodes[row][col]) { + if(rowColMatch) + _printMenuText(xPos, yPos, "*", true, eCentreJustify); + else + _printInverted(xPos, yPos, "*", _rawCodes[row][col] == _code, eCentreJustify); + } + else { + _printMenuText(xPos, yPos, " ", rowColMatch, eCentreJustify); + } + } + } + return true; +} + +bool +C433MHzScreen::keyHandler(uint8_t event) +{ + + if(CUIEditScreen::keyHandler(event)) { // manage password collection and NV save confirm + return true; + } + + if(event & keyPressed) { + _repeatCount = 0; + // press CENTRE + if(event & key_Centre) { + } + // press LEFT + if(event & key_Left) { + if(_rowSel == 0) { + _ScreenManager.prevMenu(); + } + else { + _colSel--; + WRAPLOWERLIMIT(_colSel, 0, 4); + } + } + // press RIGHT + if(event & key_Right) { + if(_rowSel == 0) { + _ScreenManager.nextMenu(); + } + else { + _colSel++; + WRAPUPPERLIMIT(_colSel, 4, 0); + } + } + // press UP + if(event & key_Up) { + _rowSel++; + _colSel = 0; + UPPERLIMIT(_rowSel, 4); + } + // press DOWN + if(event & key_Down) { + _rowSel--; + _colSel = 0; + LOWERLIMIT(_rowSel, 0); + } + } + + if(event & keyRepeat) { + _repeatCount++; + UPPERLIMIT(_repeatCount, 5); + if(_repeatCount == 2) { + if(_rowSel && _colSel) { + _rawCodes[_rowSel-1][_colSel-1] = 0; // scrub code for button + _colSel++; + WRAPLIMITS(_colSel, 0, 4); + } + } + } + + if(event & keyReleased) { + // press CENTRE + if(event & key_Centre) { + if(_rowSel == 0) { + _ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu + } + else if(_repeatCount == 0) { + _confirmSave(); // enter save confirm mode + _rowSel = 0; + } + } + } + + _ScreenManager.reqUpdate(); + return true; +} + +// Data word in NV ram is stored as follows +// +// | 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +// | | | | | +// | | | | Enabled | Key Codes | +// | Unique ID (20 bits) | U D R S| KCU | KCD | KCR | KCS | +// +// Key enabled bits +// U = Up - key code in b7-b6 +// D = Down - key code in b5-b5 +// R = Run - key code in b3-b2 +// S = Stop - key code in b1-b0 +// +// key code bits +// 00 => 0x01 +// 01 => 0x02 +// 10 => 0x04 +// 11 => 0x08 +// +/*void +C433MHzScreen::_decode(int idx) +{ + unsigned long code = _savedCodes[idx]; + for(int i=0; i<4; i++) { + int mask = 0x100 << i; + if(code & mask) { + int uniqueID = (code >> 8) & 0xFFFFF0; + int shift = (code >> (i*2)) & 0x3; + int keyCode = 1 << shift; + _rawCodes[idx][i] = uniqueID | keyCode; + } + else + _rawCodes[idx][i] = 0; + } +}*/ + +/*int +C433MHzScreen::_encode(int idx) +{ + unsigned long uniqueCode = _rawCodes[idx][0] & 0xFFFFF0; + + // confirm all recorded keys share the same unique code + for(int i=1; i<4; i++) { + if(_rawCodes[idx][i] && (uniqueCode != (_rawCodes[idx][i] & 0xFFFFF0))) { + return -1; + } + } + + // start building the encoded value for NV storage + unsigned long encoded = uniqueCode << 8; + for(int i=0; i<4; i++) { + if(_rawCodes[idx][i]) { + int keyCode = _rawCodes[idx][i] & 0xf; + switch(keyCode) { + case 1: + encoded |= (0 << i*2); + break; + case 2: + encoded |= (1 << i*2); + break; + case 4: + encoded |= (2 << i*2); + break; + case 8: + encoded |= (3 << i*2); + break; + default: + return -2; + break; + } + encoded |= (0x100 << i); + } + } + _savedCodes[idx] = encoded; + return 0; +}*/ + +void +C433MHzScreen::_saveNV() +{ + UHFremote.saveNV(_rawCodes); + // sUserSettings userSettings = NVstore.getUserSettings(); + // for(int i=0; i<3; i++) { + // int err = _encode(i); + // if(err != 0) { + // DebugPort.printf("Error encoding UHF code (%d)\r\n", err); + // return; + // } + // userSettings.UHFcode[i] = _savedCodes[i]; + // } + + // DebugPort.println("UHF Remote encodes"); + // for(int i = 0; i<3; i++) { + // DebugPort.printf("0x%08lX 0x%08lX 0x%08lX 0x%08lX => 0x%08lX\r\n", _rawCodes[i][0], _rawCodes[i][1], _rawCodes[i][2], _rawCodes[i][3], _savedCodes[i]); + // } + // NVstore.setUserSettings(userSettings); + // NVstore.save(); +} diff --git a/src/OLED/433MHzScreen.h b/src/OLED/433MHzScreen.h new file mode 100644 index 0000000..8c5bd41 --- /dev/null +++ b/src/OLED/433MHzScreen.h @@ -0,0 +1,54 @@ +/* + * This file is part of the "bluetoothheater" distribution + * (https://gitlab.com/mrjones.id.au/bluetoothheater) + * + * Copyright (C) 2020 Ray Jones + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __433MHZSCREEN_H__ +#define __433MHZSCREEN_H__ + +#include +#include "UIEditScreen.h" +#include "../RTC/BTCDateTime.h" + +class C128x64_OLED; +class CScreenManager; +class CProtocol; + +class C433MHzScreen : public CUIEditScreen { + void _initUI(); + // void _decode(int idx); + // int _encode(int idx); + void _saveNV(); + unsigned long _code; + // unsigned long _savedCodes[3]; + unsigned long _rawCodes[3][4]; + unsigned long _ID; + uint8_t _defined; + uint8_t _keyCode; + uint8_t _repeatCount; +public: + C433MHzScreen(C128x64_OLED& display, CScreenManager& mgr); + bool onSelect(); + void onExit(); + bool show(); + bool animate(); + bool keyHandler(uint8_t event); +}; + +#endif diff --git a/src/OLED/BME280Screen.cpp b/src/OLED/BME280Screen.cpp index 348303b..a4687b3 100644 --- a/src/OLED/BME280Screen.cpp +++ b/src/OLED/BME280Screen.cpp @@ -66,7 +66,7 @@ CBME280Screen::show() _printMenuText(64, 16, "Sensor not found", false, eCentreJustify); } - _printMenuText(_display.xCentre(), 52, " \021 Exit \020 ", true, eCentreJustify); + _printMenuText(_display.xCentre(), 53, " \021 Exit \020 ", true, eCentreJustify); } return true; diff --git a/src/OLED/ScreenManager.cpp b/src/OLED/ScreenManager.cpp index 9f08485..4d70428 100644 --- a/src/OLED/ScreenManager.cpp +++ b/src/OLED/ScreenManager.cpp @@ -52,6 +52,7 @@ #include "FrostScreen.h" #include "HumidityScreen.h" #include "WebPageUpdateScreen.h" +#include "433MHzScreen.h" #include "LVCScreen.h" #include #include "../cfg/pins.h" @@ -432,6 +433,7 @@ CScreenManager::_loadScreens() menuloop.push_back(new CWiFiSTAScreen(*_pDisplay, *this)); menuloop.push_back(new CMQTTScreen(*_pDisplay, *this)); menuloop.push_back(new CBTScreen(*_pDisplay, *this)); + menuloop.push_back(new C433MHzScreen(*_pDisplay, *this)); if(getTempSensor().getBME280().getCount()) { menuloop.push_back(new CTempSensorScreen(*_pDisplay, *this)); menuloop.push_back(new CBME280Screen(*_pDisplay, *this)); diff --git a/src/OLED/fonts/Icons.cpp b/src/OLED/fonts/Icons.cpp index 25629b6..3abc017 100644 --- a/src/OLED/fonts/Icons.cpp +++ b/src/OLED/fonts/Icons.cpp @@ -636,6 +636,18 @@ const uint8_t PROGMEM startIcon[] = }; const BITMAP_INFO StartIconInfo(5, 9, startIcon); +const uint8_t PROGMEM medStartIcon[] = +{ + 0x80, // # + 0xC0, // ## + 0xE0, // ### + 0xF0, // #### + 0xE0, // ### + 0xC0, // ## + 0x80, // # +}; +const BITMAP_INFO medStartIconInfo(4, 7, medStartIcon); + const uint8_t PROGMEM miniStartIcon[] = { 0x80, // # @@ -659,6 +671,33 @@ const uint8_t PROGMEM stopIcon[] = 0x00, // }; const BITMAP_INFO StopIconInfo(6, 8, stopIcon); +const uint8_t PROGMEM medStopIcon[] = +{ + 0xF8, // ##### + 0xF8, // ##### + 0xF8, // ##### + 0xF8, // ##### + 0xF8, // ##### +}; +const BITMAP_INFO medStopIconInfo(5, 5, medStopIcon); + +// 'wifiInIcon, 5x5px +const uint8_t dnIcon [] PROGMEM = { + 0xfe, // ####### + 0x7c, // ##### + 0x38, // ### + 0x10, // # +}; +const BITMAP_INFO dnIconInfo(7, 4, dnIcon); + +// 'wifiOutIcon, 5x5px +const uint8_t upIcon [] PROGMEM = { + 0x10, // # + 0x38, // ### + 0x7c, // ##### + 0xfe, // ####### +}; +const BITMAP_INFO upIconInfo(7, 4, upIcon); const uint8_t PROGMEM miniStopIcon[] = { diff --git a/src/OLED/fonts/Icons.h b/src/OLED/fonts/Icons.h index ed7ec7d..76488d8 100644 --- a/src/OLED/fonts/Icons.h +++ b/src/OLED/fonts/Icons.h @@ -97,12 +97,17 @@ extern const BITMAP_INFO BulbOffIconInfo; // Bitmap for start extern const BITMAP_INFO StartIconInfo; +extern const BITMAP_INFO medStartIconInfo; extern const BITMAP_INFO miniStartIconInfo; // Bitmap sizes for stop extern const BITMAP_INFO StopIconInfo; +extern const BITMAP_INFO medStopIconInfo; extern const BITMAP_INFO miniStopIconInfo; +extern const BITMAP_INFO dnIconInfo; +extern const BITMAP_INFO upIconInfo; + // Bitmap for displayTimeout extern const BITMAP_INFO DisplayTimeoutIconInfo; diff --git a/src/Protocol/433MHz.cpp b/src/Protocol/433MHz.cpp new file mode 100644 index 0000000..52a8901 --- /dev/null +++ b/src/Protocol/433MHz.cpp @@ -0,0 +1,382 @@ +/* + * This file is part of the "bluetoothheater" distribution + * (https://gitlab.com/mrjones.id.au/bluetoothheater) + * + * Copyright (C) 2020 Ray Jones + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include +#include "433MHz.h" +#include "../cfg/pins.h" +#include "../Utility/macros.h" +#include "../Utility/NVStorage.h" +#include "../Utility/helpers.h" + +#define DEBUG_433MHz + +C433MHzRemote UHFremote; + +static void IRAM_ATTR rmt_driver_isr_default(void *arg); + + +C433MHzRemote::C433MHzRemote() +{ + _rxQueue = NULL; + _taskHandle = NULL; + _runState = 0; + _prevCode = 0; + _timeout = 0; + _debug = false; +} + +C433MHzRemote::~C433MHzRemote() +{ + end(); +} + +void +C433MHzRemote::_staticTask(void* arg) +{ + C433MHzRemote* pThis = (C433MHzRemote*)arg; + + pThis->_task(); + + vTaskDelete(NULL); +} + + +void +C433MHzRemote::_task() +{ + rmt_rx_start(_rxCfg.channel, true); + _runState = 1; + while(_runState == 1) { + _doComms(); + delay(1); + } + rmt_rx_stop(_rxCfg.channel); + _runState = 0; +} + + +void +C433MHzRemote::_doComms() +{ + // wait for ring buffer response, or time out + size_t rx_size; + rmt_item32_t* rxItems = (rmt_item32_t *)xRingbufferReceive(_ringbuffer, &rx_size, 45); + + if (rxItems) { + _decodeRxItems(rxItems, rx_size / 4); + vRingbufferReturnItem(_ringbuffer, (void *)rxItems); + } + + if(_timeout) { + long tDelta = xTaskGetTickCount() - _timeout; + if(tDelta >= 0) { + _timeout = 0; + _prevCode = 0; + if(_rxQueue) + xQueueSend(_rxQueue, &_prevCode, 0); // inject no button press + } + } +} + +bool +C433MHzRemote::_decodeRxItems(const rmt_item32_t* rxItems, int size) +{ +// #ifdef DEBUG_433MHz +// Serial.printf("433MHz RxItems = %d\r\n", size); +// for(int i=0; i 0.6ms + // if(rxItems[i].duration0 > 600) + if(rxItems[i].duration0 > meanBitTime/2) + newCode |= 0x0001; + } + else { + // Serial.printf("433MHz remote @ transition %d: bitTime=%d lvl0=%d lvl1=%d?\r\n", i, bitTime, rxItems[i].level0, rxItems[i].level1); + newCode = 0; + return false; + } + } + // Serial.printf("433MHz val = 0x%08lX (%d)\r\n", newCode, size); + if(_prevCode != newCode) { + _prevCode = newCode; + if(_rxQueue) + xQueueSend(_rxQueue, &newCode, 0); // queue new button press +// #ifdef DEBUG_433MHz + if(_debug) { + Serial.printf("433MHz RxItems = %d (%d)\r\n", size, meanBitTime); + for(int i=0; i 6ms no transitions => end of Rx + + ESP_ERROR_CHECK(rmt_config(&_rxCfg)); + ESP_ERROR_CHECK(rmt_driver_install(_rxCfg.channel, 512, 0)); + // ringbuffer for rx + ESP_ERROR_CHECK(rmt_get_ringbuf_handle(_rxCfg.channel, &_ringbuffer)); + + _rxQueue = xQueueCreate(4, sizeof(unsigned long)); + + xTaskCreate(_staticTask, + "UHFremoteTask", + 4000, + this, + TASK_PRIORITY_HEATERCOMMS, + &_taskHandle); + +} + +void +C433MHzRemote::end() +{ + DebugPort.printf("Stopping UHF remote task %d\r\n", _runState); + if(_runState == 1) { // check task is running + _runState = 2; // ask task to stop + DebugPort.println("Stopping UHF remote task wait"); + while(_runState != 0) { + vTaskDelay(1); + } + _taskHandle = NULL; + } + + ESP_ERROR_CHECK(rmt_driver_uninstall(_rxCfg.channel)); + _ringbuffer = NULL; +} + +bool +C433MHzRemote::available() +{ + unsigned long test; + return xQueuePeek(_rxQueue, &test, 0) != 0; +} + +bool +C433MHzRemote::read(unsigned long& val) +{ + return xQueueReceive(_rxQueue, &val, 0) != 0; +} + +// Data word in NV ram is stored as follows +// +// | 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +// | | | | | +// | | | | Enabled | Key Codes | +// | Unique ID (20 bits) | U D R S| KCU | KCD | KCR | KCS | +// +// Key enabled bits +// U = Up - key code in b7-b6 +// D = Down - key code in b5-b5 +// R = Run - key code in b3-b2 +// S = Stop - key code in b1-b0 +// +// key code bits +// 00 => 0x01 +// 01 => 0x02 +// 10 => 0x04 +// 11 => 0x08 +// +void +C433MHzRemote::_readNV() +{ + for(int rmt=0; rmt<3; rmt++) { + unsigned long code = NVstore.getUserSettings().UHFcode[rmt]; + for(int i=0; i<4; i++) { + int mask = 0x100 << i; + if(code & mask) { + int uniqueID = (code >> 8) & 0xFFFFF0; + int shift = (code >> (i*2)) & 0x3; + int keyCode = 1 << shift; + _rawCodes[rmt][i] = uniqueID | keyCode; + } + else + _rawCodes[rmt][i] = 0; + } + DebugPort.printf("0x%08lX => 0x%08lX 0x%08lX 0x%08lX 0x%08lX\r\n", code, _rawCodes[rmt][0], _rawCodes[rmt][1], _rawCodes[rmt][2], _rawCodes[rmt][3]); + } +} + +int +C433MHzRemote::saveNV(unsigned long codes[3][4]) +{ + sUserSettings userSettings = NVstore.getUserSettings(); + + for(int rmt=0; rmt<3; rmt++) { + unsigned long uniqueCode = codes[rmt][0] & 0xFFFFF0; + + // confirm all recorded keys share the same unique code + for(int i=1; i<4; i++) { + if(codes[rmt][i] && (uniqueCode != (codes[rmt][i] & 0xFFFFF0))) { + return -1; + } + } + + // start building the encoded value for NV storage + unsigned long encoded = uniqueCode << 8; + for(int i=0; i<4; i++) { + if(codes[rmt][i]) { + int keyCode = codes[rmt][i] & 0xf; + switch(keyCode) { + case 1: + encoded |= (0 << i*2); + break; + case 2: + encoded |= (1 << i*2); + break; + case 4: + encoded |= (2 << i*2); + break; + case 8: + encoded |= (3 << i*2); + break; + default: + return -2; + break; + } + encoded |= (0x100 << i); + } + } + userSettings.UHFcode[rmt] = encoded; + + DebugPort.printf("0x%08lX 0x%08lX 0x%08lX 0x%08lX => 0x%08lX\r\n", codes[rmt][0], codes[rmt][1], codes[rmt][2], codes[rmt][3], encoded); + } + + NVstore.setUserSettings(userSettings); + NVstore.save(); + + for(int rmt=0; rmt<3; rmt++) { + for(int i=0; i<4; i++) { + _rawCodes[rmt][i] = codes[rmt][i]; + } + } + + return 0; +} + +void +C433MHzRemote::getCodes(unsigned long codes[3][4]) +{ + for(int rmt=0; rmt<3; rmt++) { + for(int i=0; i<4; i++) { + codes[rmt][i] = _rawCodes[rmt][i]; + } + } +} + +void +C433MHzRemote::manage() +{ + if(available()) { + unsigned long code; + read(code); + DebugPort.printf("UHF remote code = %08lX\r\n", code); + + if(code) { // only react to an actual code, not release + const int IDmatch = (code << 8) & 0xfffff000; + int rmt; + // find a mtaching unique ID + for(rmt=0; rmt<3; rmt++) { + if( IDmatch == (NVstore.getUserSettings().UHFcode[rmt] & 0xfffff000) ) { + break; + } + } + if(rmt == 3) + return; // match not found - abort + + const int subCode = code & 0xf; + if(subCode == (_rawCodes[rmt][0] & 0xf) ) { + DebugPort.println("UHF stop request!"); + requestOff(); + } + if(subCode == (_rawCodes[rmt][1] & 0xf) ) { + DebugPort.println("UHF start request!"); + requestOn(); + } + if(subCode == (_rawCodes[rmt][2] & 0xf) ) { + DebugPort.println("UHF dec temp request!"); + CDemandManager::deltaDemand(-1); + } + if(subCode == (_rawCodes[rmt][3] & 0xf) ) { + DebugPort.println("UHF inc temp request!"); + CDemandManager::deltaDemand(+1); + } + } + } +} + +void +C433MHzRemote::enableISR(bool state) +{ + rmt_set_rx_intr_en(_rxCfg.channel, state); + rmt_set_err_intr_en(_rxCfg.channel, state); +} + +extern C433MHzRemote UHFremote; + diff --git a/src/Protocol/433MHz.h b/src/Protocol/433MHz.h new file mode 100644 index 0000000..8132094 --- /dev/null +++ b/src/Protocol/433MHz.h @@ -0,0 +1,68 @@ +/* + * This file is part of the "bluetoothheater" distribution + * (https://gitlab.com/mrjones.id.au/bluetoothheater) + * + * Copyright (C) 2020 Ray Jones + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef __433MHzREMOTE_H__ +#define __433MHzREMOTE_H__ + +#include +#include "../Utility/UtilClasses.h" +#include "driver/rmt.h" + +class C433MHzRemote { +protected: + static void _staticTask(void* arg); + rmt_config_t _rxCfg; + RingbufHandle_t _ringbuffer; + QueueHandle_t _rxQueue; + TaskHandle_t _taskHandle; + int _runState; + unsigned long _prevCode; + unsigned long _timeout; + unsigned long _rawCodes[3][4]; + bool _debug; + + void _task(); + + void _doComms(); + bool _decodeRxItems(const rmt_item32_t* rxItems, int size); + // NV storage + void _readNV(); + +public: + C433MHzRemote(); + ~C433MHzRemote(); + void begin(gpio_num_t pin, rmt_channel_t channel); + void end(); + + bool available(); + bool read(unsigned long& val); + void manage(); + + void getCodes(unsigned long codes[3][4]); + + // NV storage + int saveNV(unsigned long codes[3][4]); + void enableISR(bool state); +}; + +extern C433MHzRemote UHFremote; + + +#endif \ No newline at end of file diff --git a/src/Protocol/BlueWireTask.cpp b/src/Protocol/BlueWireTask.cpp index 34f40f2..499c88d 100644 --- a/src/Protocol/BlueWireTask.cpp +++ b/src/Protocol/BlueWireTask.cpp @@ -382,7 +382,9 @@ void BlueWireTask(void*) { #if DBG_FREERTOS == 1 digitalWrite(GPIOout1_pin, LOW); #endif - vTaskDelay(1); + if (!BlueWireSerial.available()) { + vTaskDelay(1); + } #if DBG_FREERTOS == 1 digitalWrite(GPIOout1_pin, HIGH); #endif diff --git a/src/Protocol/Protocol.cpp b/src/Protocol/Protocol.cpp index d406d17..8bd6444 100644 --- a/src/Protocol/Protocol.cpp +++ b/src/Protocol/Protocol.cpp @@ -233,11 +233,19 @@ CProtocol::getVoltage_Supply() const } void -CProtocol::setAltitude(float altitude) +CProtocol::setAltitude(float altitude, bool valid) { int16_t alt = (int16_t)altitude; Controller.Altitude_MSB = (alt >> 8) & 0xff; Controller.Altitude_LSB = (alt >> 0) & 0xff; + if(valid) { + Controller.Unknown1_MSB = 0xeb; + Controller.Unknown1_LSB = 0x47; + } + else { + Controller.Unknown1_MSB = 0x01; // always 0x01 + Controller.Unknown1_LSB = 0x2c; // always 0x2c 16bit: "300 secs = max run without burn detected" ?? + } } int diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 0176122..51f822d 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -162,7 +162,7 @@ public: int16_t getTemperature_HeatExchg() const; // temperature of heat exchanger void setTemperature_HeatExchg(uint16_t degC); // temperature of heat exchanger // altitude - void setAltitude(float altitude); + void setAltitude(float altitude, bool valid); int getAltitude() const; void DebugReport(const char* hdr, const char* ftr); diff --git a/src/Protocol/TxManage.cpp b/src/Protocol/TxManage.cpp index e237450..158b8b1 100644 --- a/src/Protocol/TxManage.cpp +++ b/src/Protocol/TxManage.cpp @@ -173,10 +173,16 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster) float altitude; if(getTempSensor().getAltitude(altitude)) { // if a BME280 is fitted - m_TxFrame.setAltitude(altitude); + // use calculated height + // set 0xeb 0x47 in "unknown bytes" + // - 0xeb happens with all pressure quipped units + // - 0x47 with all other than coffee pod which sends 0x00? + m_TxFrame.setAltitude(altitude, true); } else { - m_TxFrame.setAltitude(3500); // default height - yes it is weird, but that's what the simple controllers send! + // default height - yes it is weird, but that's what the simple controllers send! + // set 0x01 0x2c in "unknown bytes" - all no pressure equipped OEM controlelrs do that + m_TxFrame.setAltitude(3500, false); } m_TxFrame.setPump_Prime(_prime); diff --git a/src/RTC/TimerManager.cpp b/src/RTC/TimerManager.cpp index 263d685..1ace27f 100644 --- a/src/RTC/TimerManager.cpp +++ b/src/RTC/TimerManager.cpp @@ -227,6 +227,10 @@ CTimerManager::manageTime(int _hour, int _minute, int _dow) int minute = currentTime.minute(); int dow = currentTime.dayOfTheWeek(); + if(!INBOUNDS(dow, 0, 6)) DebugPort.printf("CTimerManager::manageTime out of bounds dow : %d\r\n", dow); + if(!INBOUNDS(minute, 0, 59)) DebugPort.printf("CTimerManager::manageTime out of bounds minute : %d\r\n", minute); + if(!INBOUNDS(hour, 0, 23)) DebugPort.printf("CTimerManager::manageTime out of bounds hour : %d\r\n", hour); + int retval = 0; int dayMinute = (hour * 60) + minute; int newID = _weekMap[dow][dayMinute]; diff --git a/src/Utility/BTC_GPIO.h b/src/Utility/BTC_GPIO.h index 8550922..06d0cb4 100644 --- a/src/Utility/BTC_GPIO.h +++ b/src/Utility/BTC_GPIO.h @@ -210,6 +210,17 @@ struct sGPIOparams { CGPIOout2::Modes out2Mode; CGPIOalg::Modes algMode; int8_t thresh[2]; + + sGPIOparams& operator=(const sGPIOparams& rhs) { + in1Mode = rhs.in1Mode; + in2Mode = rhs.in2Mode; + out1Mode = rhs.out1Mode; + out2Mode = rhs.out2Mode; + algMode = rhs.algMode; + thresh[0] = rhs.thresh[0]; + thresh[1] = rhs.thresh[1]; + return *this; + } }; struct sGPIO { diff --git a/src/Utility/DemandManager.cpp b/src/Utility/DemandManager.cpp index 9f55936..26e918f 100644 --- a/src/Utility/DemandManager.cpp +++ b/src/Utility/DemandManager.cpp @@ -94,7 +94,7 @@ CDemandManager::setPumpHz(uint8_t newDemand) RTC_Store.setDesiredPump(newDemand); } -// set a transient setpoint for use by prgrammed timer starts +// set a transient setpoint for use by programmed timer starts // setpoints only change if timer temperature is actually defined void CDemandManager::setFromTimer(uint8_t timerDemand) @@ -154,7 +154,7 @@ CDemandManager::checkStart() } -// generic method adjust the active heter demand. +// generic method adjust the active heater demand. // thi may be Pump Hz or desired temeperature, dependent upon if thermostat mode is active bool CDemandManager::setDemand(uint8_t newDemand) diff --git a/src/Utility/NVStorage.cpp b/src/Utility/NVStorage.cpp index 460c56e..9242b0c 100644 --- a/src/Utility/NVStorage.cpp +++ b/src/Utility/NVStorage.cpp @@ -24,6 +24,7 @@ #include "DebugPort.h" #include #include +#include "../Protocol/433MHz.h" bool sNVStore::valid() @@ -57,8 +58,28 @@ sNVStore::init() CHeaterStorage::CHeaterStorage() { _calValues.init(); + _semaphore = xSemaphoreCreateBinary(); + giveSemaphore(); } +CHeaterStorage::~CHeaterStorage() +{ + vSemaphoreDelete(_semaphore); +} + +void +CHeaterStorage::takeSemaphore() +{ + xSemaphoreTake(_semaphore, portMAX_DELAY); +} + +void +CHeaterStorage::giveSemaphore() +{ + xSemaphoreGive(_semaphore); +} + + float sHeaterTuning::getPmin() const { @@ -211,7 +232,7 @@ CHeaterStorage::setHourMeter(const sHourMeter& newVals) // //#ifdef ESP32 -CESP32HeaterStorage::CESP32HeaterStorage() +CESP32HeaterStorage::CESP32HeaterStorage() : CHeaterStorage() { init(); } @@ -245,6 +266,9 @@ void CESP32HeaterStorage::doSave() { if(_bShouldSave) { + takeSemaphore(); + UHFremote.enableISR(false); + // portENTER_CRITICAL(); _bShouldSave = false; DebugPort.println("Saving to NV storage"); _calValues.heaterTuning.save(); @@ -255,6 +279,9 @@ CESP32HeaterStorage::doSave() _calValues.MQTT.save(); _calValues.Credentials.save(); _calValues.hourMeter.save(); + // portEXIT_CRITICAL(); + UHFremote.enableISR(true); + giveSemaphore(); } } @@ -514,6 +541,9 @@ sUserSettings::load() validatedLoad("Clock12hr", clock12hr, 0, u8inBounds, 0, 1); validatedLoad("holdPassword", holdPassword, 0, u8inBounds, 0, 1); validatedLoad("humidityStart", humidityStart, 0, u8inBounds, 0, 100); + validatedLoad("UHFcode0", UHFcode[0], 0, 0, 0xffffffff); + validatedLoad("UHFcode1", UHFcode[1], 0, 0, 0xffffffff); + validatedLoad("UHFcode2", UHFcode[2], 0, 0, 0xffffffff); preferences.end(); } @@ -554,6 +584,9 @@ sUserSettings::save() preferences.putUChar("Clock12hr", clock12hr); preferences.putUChar("holdPassword", holdPassword); preferences.putUChar("humidityStart", humidityStart); + preferences.putULong("UHFcode0", UHFcode[0]); + preferences.putULong("UHFcode1", UHFcode[1]); + preferences.putULong("UHFcode2", UHFcode[2]); preferences.end(); } diff --git a/src/Utility/NVStorage.h b/src/Utility/NVStorage.h index d061924..cabeb5e 100644 --- a/src/Utility/NVStorage.h +++ b/src/Utility/NVStorage.h @@ -326,6 +326,7 @@ struct sUserSettings : public CESP32_NVStorage { uint8_t clock12hr; uint8_t holdPassword; uint8_t humidityStart; + uint32_t UHFcode[3]; bool valid() { bool retval = true; @@ -347,7 +348,7 @@ struct sUserSettings : public CESP32_NVStorage { retval &= HomeMenu.valid(); retval &= JSON.valid(); return retval; - } + }; void init() { dimTime = 60000; menuTimeout = 60000; @@ -375,6 +376,9 @@ struct sUserSettings : public CESP32_NVStorage { clock12hr = 0; holdPassword = 0; humidityStart = 0; + UHFcode[0] = 0; + UHFcode[1] = 0; + UHFcode[2] = 0; }; void load(); void save(); @@ -390,13 +394,7 @@ struct sUserSettings : public CESP32_NVStorage { useThermostat = rhs.useThermostat; wifiMode = rhs.wifiMode; enableOTA = rhs.enableOTA; - GPIO.in1Mode = rhs.GPIO.in1Mode; - GPIO.in2Mode = rhs.GPIO.in2Mode; - GPIO.out1Mode = rhs.GPIO.out1Mode; - GPIO.out2Mode = rhs.GPIO.out2Mode; - GPIO.algMode = rhs.GPIO.algMode; - GPIO.thresh[0] = rhs.GPIO.thresh[0]; - GPIO.thresh[1] = rhs.GPIO.thresh[1]; + GPIO = rhs.GPIO; FrameRate = rhs.FrameRate; cyclic = rhs.cyclic; HomeMenu = rhs.HomeMenu; @@ -405,6 +403,9 @@ struct sUserSettings : public CESP32_NVStorage { clock12hr = rhs.clock12hr; holdPassword = rhs.holdPassword; humidityStart = rhs.humidityStart; + UHFcode[0] = rhs.UHFcode[0]; + UHFcode[1] = rhs.UHFcode[1]; + UHFcode[2] = rhs.UHFcode[2]; return *this; } }; @@ -433,11 +434,12 @@ struct sNVStore { class CHeaterStorage /*: public CESP32_NVStorage*/ { + SemaphoreHandle_t _semaphore; protected: sNVStore _calValues; public: CHeaterStorage(); - virtual ~CHeaterStorage() {}; + virtual ~CHeaterStorage(); // TODO: These are only here to allow building without fully // fleshing out NV storage for Due, Mega etc @@ -465,6 +467,8 @@ public: void setUserSettings(const sUserSettings& info); void setHeaterTuning(const sHeaterTuning& info); bool setHourMeter(const sHourMeter& info); + void takeSemaphore(); + void giveSemaphore(); }; diff --git a/src/Utility/TempSense.cpp b/src/Utility/TempSense.cpp index 3aa2453..b716194 100644 --- a/src/Utility/TempSense.cpp +++ b/src/Utility/TempSense.cpp @@ -423,14 +423,14 @@ CBME280Sensor::getTemperature(float& tempReading, bool filtered) return false; } - long tDelta = millis() - _lastSampleTime; +/* long tDelta = millis() - _lastSampleTime; if(tDelta >= 0) { _bme.takeForcedMeasurement(); float temperature = _bme.readTemperature(); update(temperature); _lastSampleTime = millis() + 1000; DebugPort.println("Forced BME sensor reading"); - } + }*/ CSensor::getTemperature(tempReading, filtered); // tempReading += NVstore.getHeaterTuning().BME280probe.offset;; @@ -461,11 +461,19 @@ CBME280Sensor::getHumidity(float& reading, bool fresh) int CBME280Sensor::getAllReadings(bme280_readings& readings) { + _bme.takeForcedMeasurement(); int retval = _bme.readAll(readings); _fAltitude = readings.altitude; _fHumidity = readings.humidity; update(readings.temperature); +/* _bme.takeForcedMeasurement(); + readings.temperature = _bme.readTemperature(); + update(readings.temperature); + _fAltitude = readings.altitude = _bme.readAltitude(1013.25); + _fHumidity =readings.humidity = _bme.readHumidity(); + int retval = 0x07; // temperature read OK*/ + _lastSampleTime = millis() + 1000; return retval; diff --git a/src/cfg/pins.h b/src/cfg/pins.h index f8e456f..48d5d8a 100644 --- a/src/cfg/pins.h +++ b/src/cfg/pins.h @@ -24,37 +24,37 @@ #include "BTCConfig.h" -const uint8_t UART_Tx = 1; -const uint8_t LED_Pin = 2; -const uint8_t UART_Rx = 3; -const uint8_t HC05_KeyPin = 4; -const uint8_t TxEnbPin = 5; -const uint8_t Tx433MHz_pin = 12; // HSPI std pins -const uint8_t Rx433MHz_pin = 13; // " -const uint8_t GPIOout2_pin = 14; // " +const gpio_num_t UART_Tx = GPIO_NUM_1; +const gpio_num_t LED_Pin = GPIO_NUM_2; +const gpio_num_t UART_Rx = GPIO_NUM_3; +const gpio_num_t HC05_KeyPin = GPIO_NUM_4; +const gpio_num_t TxEnbPin = GPIO_NUM_5; +const gpio_num_t Tx433MHz_pin = GPIO_NUM_12; // HSPI std pins +const gpio_num_t Rx433MHz_pin = GPIO_NUM_13; // " +const gpio_num_t GPIOout2_pin = GPIO_NUM_14; // " #if USE_JTAG == 1 -const uint8_t DS18B20_Pin = 33; +const gpio_num_t DS18B20_Pin = GPIO_NUM_33; #else -const uint8_t DS18B20_Pin = 15; +const gpio_num_t DS18B20_Pin = GPIO_NUM_15; #endif -const uint8_t Rx1Pin = 16; -const uint8_t Tx1Pin = 17; -const uint8_t Tx2Pin = 18; -const uint8_t Rx2Pin = 19; -const uint8_t OLED_SDA_pin = 21; // I2C std pins -const uint8_t OLED_SCL_pin = 22; // " -const uint8_t HC05_SensePin = 23; -const uint8_t GPIOin2_pin = 25; -const uint8_t GPIOin1_pinV21V10 = 26; +const gpio_num_t Rx1Pin = GPIO_NUM_16; +const gpio_num_t Tx1Pin = GPIO_NUM_17; +const gpio_num_t Tx2Pin = GPIO_NUM_18; +const gpio_num_t Rx2Pin = GPIO_NUM_19; +const gpio_num_t OLED_SDA_pin = GPIO_NUM_21; // I2C std pins +const gpio_num_t OLED_SCL_pin = GPIO_NUM_22; // " +const gpio_num_t HC05_SensePin = GPIO_NUM_23; +const gpio_num_t GPIOin2_pin = GPIO_NUM_25; +const gpio_num_t GPIOin1_pinV21V10 = GPIO_NUM_26; const adc2_channel_t GPIOalg_pinINVALID = ADC2_CHANNEL_9; // GPIO 26 - Cannot use ADC2 with WiFi enabled!!! -const uint8_t GPIOout1_pin = 27; +const uint8_t GPIOout1_pin = GPIO_NUM_27; -const uint8_t keyUp_pin = 32; -const uint8_t GPIOin1_pinV20 = 33; +const gpio_num_t keyUp_pin = GPIO_NUM_32; +const gpio_num_t GPIOin1_pinV20 = GPIO_NUM_33; const adc1_channel_t GPIOalg_pin = ADC1_CHANNEL_5; // GPIO 33 - OK with Wifi, ADC1 channel -const uint8_t keyDown_pin = 34; // input only, no chip pullup -const uint8_t keyCentre_pin = 35; // input only, no chip pullup -const uint8_t keyRight_pin = 36; // input only, no chip pullup -const uint8_t keyLeft_pin = 39; // input only, no chip pullup +const gpio_num_t keyDown_pin = GPIO_NUM_34; // input only, no chip pullup +const gpio_num_t keyCentre_pin = GPIO_NUM_35; // input only, no chip pullup +const gpio_num_t keyRight_pin = GPIO_NUM_36; // input only, no chip pullup +const gpio_num_t keyLeft_pin = GPIO_NUM_39; // input only, no chip pullup