mirror of
https://github.com/arendst/Tasmota.git
synced 2025-04-27 00:07:17 +00:00
Merge remote-tracking branch 'origin/development' into feature_adafruit_ssd1331
This commit is contained in:
commit
49e8612a14
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -3,7 +3,7 @@
|
||||
**Related issue (if applicable):** fixes #<Tasmota issue number goes here>
|
||||
|
||||
## Checklist:
|
||||
- [ ] The pull request is done against the latest dev branch
|
||||
- [ ] The pull request is done against the latest development branch
|
||||
- [ ] Only relevant files were touched
|
||||
- [ ] Only one feature/fix was added per PR and the code change compiles without warnings
|
||||
- [ ] The code change is tested and works on Tasmota core ESP8266 V.2.7.4.9
|
||||
|
26
.github/workflows/Tasmota_build.yml
vendored
26
.github/workflows/Tasmota_build.yml
vendored
@ -1013,6 +1013,29 @@ jobs:
|
||||
path: ./build_output/firmware
|
||||
|
||||
|
||||
tasmota32-AF:
|
||||
needs: tasmota_pull
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
platformio upgrade --dev
|
||||
platformio update
|
||||
- name: Run PlatformIO
|
||||
run: |
|
||||
platformio run -e tasmota32-AF
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output/firmware
|
||||
|
||||
|
||||
tasmota32-BG:
|
||||
needs: tasmota_pull
|
||||
runs-on: ubuntu-latest
|
||||
@ -1560,6 +1583,7 @@ jobs:
|
||||
mkdir -p ./firmware/tasmota/languages
|
||||
mkdir -p ./firmware/tasmota32/languages
|
||||
mkdir -p ./firmware/tasmota32/ESP32_needed_files/
|
||||
mkdir -p ./firmware/tasmota32/Odroid_go_needed_files/
|
||||
[ ! -f ./mv_firmware/tasmota.* ] || mv ./mv_firmware/tasmota.* ./firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/tasmota-sensors.* ] || mv ./mv_firmware/tasmota-sensors.* ./firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/tasmota-minimal.* ] || mv ./mv_firmware/tasmota-minimal.* ./firmware/tasmota/
|
||||
@ -1575,12 +1599,14 @@ jobs:
|
||||
[ ! -f ./mv_firmware/tasmota32-ir*.* ] || mv ./mv_firmware/tasmota32-ir*.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-display.* ] || mv ./mv_firmware/tasmota32-display.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-web*.* ] || mv ./mv_firmware/tasmota32-web*.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-odroidgo.* ] || mv ./mv_firmware/tasmota32-odroidgo.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-knx.* ] || mv ./mv_firmware/tasmota32-knx.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32* ] || mv ./mv_firmware/tasmota32* ./firmware/tasmota32/languages/
|
||||
[ ! -f ./mv_firmware/* ] || mv ./mv_firmware/* ./firmware/tasmota/languages/
|
||||
rm ./firmware/tasmota32/*.gz
|
||||
rm ./firmware/tasmota32/languages/*.gz
|
||||
[ ! -f ./tools/Esptool/ESP32/*.* ] || mv ./tools/Esptool/ESP32/*.* ./firmware/tasmota32/ESP32_needed_files/
|
||||
[ ! -f ./tools/Esptool/Odroid_go/*.* ] || mv ./tools/Esptool/Odroid_go/*.* ./firmware/tasmota32/Odroid_go_needed_files/
|
||||
[ ! -f ./FIRMWARE.md ] || mv -f ./FIRMWARE.md ./README.md
|
||||
- name: Commit files # transfer the new binaries back into the repository
|
||||
run: |
|
||||
|
26
.github/workflows/Tasmota_build_master.yml
vendored
26
.github/workflows/Tasmota_build_master.yml
vendored
@ -1013,6 +1013,29 @@ jobs:
|
||||
path: ./build_output/firmware
|
||||
|
||||
|
||||
tasmota32-AF:
|
||||
needs: tasmota_pull
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
platformio upgrade --dev
|
||||
platformio update
|
||||
- name: Run PlatformIO
|
||||
run: |
|
||||
platformio run -e tasmota32-AF
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output/firmware
|
||||
|
||||
|
||||
tasmota32-BG:
|
||||
needs: tasmota_pull
|
||||
runs-on: ubuntu-latest
|
||||
@ -1560,6 +1583,7 @@ jobs:
|
||||
mkdir -p ./firmware/tasmota/languages
|
||||
mkdir -p ./firmware/tasmota32/languages
|
||||
mkdir -p ./firmware/tasmota32/ESP32_needed_files/
|
||||
mkdir -p ./firmware/tasmota32/Odroid_go_needed_files/
|
||||
[ ! -f ./mv_firmware/tasmota.* ] || mv ./mv_firmware/tasmota.* ./firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/tasmota-sensors.* ] || mv ./mv_firmware/tasmota-sensors.* ./firmware/tasmota/
|
||||
[ ! -f ./mv_firmware/tasmota-minimal.* ] || mv ./mv_firmware/tasmota-minimal.* ./firmware/tasmota/
|
||||
@ -1575,12 +1599,14 @@ jobs:
|
||||
[ ! -f ./mv_firmware/tasmota32-ir*.* ] || mv ./mv_firmware/tasmota32-ir*.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-display.* ] || mv ./mv_firmware/tasmota32-display.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-web*.* ] || mv ./mv_firmware/tasmota32-web*.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-odroidgo.* ] || mv ./mv_firmware/tasmota32-odroidgo.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32-knx.* ] || mv ./mv_firmware/tasmota32-knx.* ./firmware/tasmota32/
|
||||
[ ! -f ./mv_firmware/tasmota32* ] || mv ./mv_firmware/tasmota32* ./firmware/tasmota32/languages/
|
||||
[ ! -f ./mv_firmware/* ] || mv ./mv_firmware/* ./firmware/tasmota/languages/
|
||||
rm ./firmware/tasmota32/*.gz
|
||||
rm ./firmware/tasmota32/languages/*.gz
|
||||
[ ! -f ./tools/Esptool/ESP32/*.* ] || mv ./tools/Esptool/ESP32/*.* ./firmware/tasmota32/ESP32_needed_files/
|
||||
[ ! -f ./tools/Esptool/Odroid_go/*.* ] || mv ./tools/Esptool/Odroid_go/*.* ./firmware/tasmota32/Odroid_go_needed_files/
|
||||
[ ! -f ./FIRMWARE.md ] || mv -f ./RELEASENOTES.md ./README.md
|
||||
- name: Commit files # transfer the new binaries back into the repository
|
||||
run: |
|
||||
|
@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file.
|
||||
## [9.2.0.2]
|
||||
### Added
|
||||
- Basic support for ESP32 Odroid Go 16MB binary tasmota32-odroidgo.bin (#8630)
|
||||
- Command ``CTRange`` to specify the visible CT range the bulb is capable of
|
||||
- Command ``VirtualCT`` to simulate or fine tune CT bulbs with 3,4,5 channels
|
||||
|
||||
### Breaking Changed
|
||||
- Replaced MFRC522 13.56MHz rfid card reader GPIO selection from ``GPIO_SPI_CS`` by ``GPIO_RC522_CS``
|
||||
|
@ -27,7 +27,7 @@ uint16_t Arduino_ST7789::GetColorFromIndex(uint8_t index) {
|
||||
}
|
||||
|
||||
static const uint8_t PROGMEM
|
||||
cmd_240x240[] = { // Initialization commands for 7789 screens
|
||||
init_cmd[] = { // Initialization commands for 7789 screens
|
||||
10, // 9 commands in list:
|
||||
ST7789_SWRESET, ST_CMD_DELAY, // 1: Software reset, no args, w/delay
|
||||
150, // 150 ms delay
|
||||
@ -38,14 +38,6 @@ static const uint8_t PROGMEM
|
||||
10, // 10 ms delay
|
||||
ST7789_MADCTL , 1, // 4: Memory access ctrl (directions), 1 arg:
|
||||
0x00, // Row addr/col addr, bottom to top refresh
|
||||
ST7789_CASET , 4, // 5: Column addr set, 4 args, no delay:
|
||||
0x00, ST7789_240x240_XSTART, // XSTART = 0
|
||||
(ST7789_TFTWIDTH+ST7789_240x240_XSTART) >> 8,
|
||||
(ST7789_TFTWIDTH+ST7789_240x240_XSTART) & 0xFF, // XEND = 240
|
||||
ST7789_RASET , 4, // 6: Row addr set, 4 args, no delay:
|
||||
0x00, ST7789_240x240_YSTART, // YSTART = 0
|
||||
(ST7789_TFTHEIGHT+ST7789_240x240_YSTART) >> 8,
|
||||
(ST7789_TFTHEIGHT+ST7789_240x240_YSTART) & 0xFF, // YEND = 240
|
||||
ST7789_INVON , ST_CMD_DELAY, // 7: Inversion ON
|
||||
10,
|
||||
ST7789_NORON , ST_CMD_DELAY, // 8: Normal display on, no args, w/delay
|
||||
@ -75,7 +67,7 @@ inline uint16_t swapcolor(uint16_t x) {
|
||||
|
||||
// Constructor when using software SPI. All output pins are configurable.
|
||||
Arduino_ST7789::Arduino_ST7789(int8_t dc, int8_t rst, int8_t sid, int8_t sclk, int8_t cs, int8_t bp)
|
||||
: Renderer(ST7789_TFTWIDTH, ST7789_TFTHEIGHT)
|
||||
: Renderer(_width, _height)
|
||||
{
|
||||
_cs = cs;
|
||||
_dc = dc;
|
||||
@ -91,7 +83,7 @@ Arduino_ST7789::Arduino_ST7789(int8_t dc, int8_t rst, int8_t sid, int8_t sclk, i
|
||||
// Constructor when using hardware SPI. Faster, but must use SPI pins
|
||||
// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
|
||||
Arduino_ST7789::Arduino_ST7789(int8_t dc, int8_t rst, int8_t cs, int8_t bp)
|
||||
: Renderer(ST7789_TFTWIDTH, ST7789_TFTHEIGHT) {
|
||||
: Renderer(_width, _height) {
|
||||
_cs = cs;
|
||||
_dc = dc;
|
||||
_rst = rst;
|
||||
@ -335,29 +327,59 @@ void Arduino_ST7789::setRotation(uint8_t m) {
|
||||
case 0:
|
||||
writedata(ST7789_MADCTL_MX | ST7789_MADCTL_MY | ST7789_MADCTL_RGB);
|
||||
|
||||
_xstart = _colstart;
|
||||
// _ystart = _rowstart;
|
||||
_ystart = 80;
|
||||
_xstart = 0;
|
||||
_ystart = 0;
|
||||
if (_width==240 && _height==240) {
|
||||
_xstart = ST7789_240x240_XSTART_R0;
|
||||
_ystart = ST7789_240x240_YSTART_R0;
|
||||
}
|
||||
if (_width==135 && _height==240) {
|
||||
_xstart = ST7789_135x240_XSTART_R0;
|
||||
_ystart = ST7789_135x240_YSTART_R0;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
writedata(ST7789_MADCTL_MY | ST7789_MADCTL_MV | ST7789_MADCTL_RGB);
|
||||
|
||||
_ystart = _colstart;
|
||||
// _xstart = _rowstart;
|
||||
_xstart = 80;
|
||||
_ystart = 0;
|
||||
_xstart = 0;
|
||||
if (_width==240 && _height==240) {
|
||||
_xstart = ST7789_240x240_XSTART_R1;
|
||||
_ystart = ST7789_240x240_YSTART_R1;
|
||||
}
|
||||
if (_width==240 && _height==135) {
|
||||
_xstart = ST7789_135x240_XSTART_R1;
|
||||
_ystart = ST7789_135x240_YSTART_R1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
writedata(ST7789_MADCTL_RGB);
|
||||
|
||||
_xstart = _colstart;
|
||||
_ystart = _rowstart;
|
||||
_xstart = 0;
|
||||
_ystart = 0;
|
||||
if (_width==240 && _height==240) {
|
||||
_xstart = ST7789_240x240_XSTART_R2;
|
||||
_ystart = ST7789_240x240_YSTART_R2;
|
||||
}
|
||||
if (_width==135 && _height==240) {
|
||||
_xstart = ST7789_135x240_XSTART_R2;
|
||||
_ystart = ST7789_135x240_YSTART_R2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
writedata(ST7789_MADCTL_MX | ST7789_MADCTL_MV | ST7789_MADCTL_RGB);
|
||||
|
||||
_ystart = _colstart;
|
||||
_xstart = _rowstart;
|
||||
_xstart = 0;
|
||||
_ystart = 0;
|
||||
if (_width==240 && _height==240) {
|
||||
_xstart = ST7789_240x240_XSTART_R3;
|
||||
_ystart = ST7789_240x240_YSTART_R3;
|
||||
}
|
||||
if (_width==240 && _height==135) {
|
||||
_xstart = ST7789_135x240_XSTART_R3;
|
||||
_ystart = ST7789_135x240_YSTART_R3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -533,12 +555,10 @@ inline void Arduino_ST7789::DC_LOW(void) {
|
||||
void Arduino_ST7789::init(uint16_t width, uint16_t height) {
|
||||
commonInit(NULL);
|
||||
|
||||
_colstart = ST7789_240x240_XSTART;
|
||||
_rowstart = ST7789_240x240_YSTART;
|
||||
_height = height;
|
||||
_width = width;
|
||||
|
||||
displayInit(cmd_240x240);
|
||||
displayInit(init_cmd);
|
||||
|
||||
setRotation(2);
|
||||
|
||||
|
@ -39,11 +39,23 @@
|
||||
|
||||
//#define SPI_HAS_TRANSACTION // already defined in SPI.h
|
||||
|
||||
#define ST7789_TFTWIDTH 240
|
||||
#define ST7789_TFTHEIGHT 240
|
||||
#define ST7789_240x240_XSTART_R0 0
|
||||
#define ST7789_240x240_YSTART_R0 80
|
||||
#define ST7789_240x240_XSTART_R1 80
|
||||
#define ST7789_240x240_YSTART_R1 0
|
||||
#define ST7789_240x240_XSTART_R2 0
|
||||
#define ST7789_240x240_YSTART_R2 0
|
||||
#define ST7789_240x240_XSTART_R3 0
|
||||
#define ST7789_240x240_YSTART_R3 0
|
||||
|
||||
#define ST7789_240x240_XSTART 0
|
||||
#define ST7789_240x240_YSTART 0
|
||||
#define ST7789_135x240_XSTART_R0 53
|
||||
#define ST7789_135x240_YSTART_R0 40
|
||||
#define ST7789_135x240_XSTART_R1 40
|
||||
#define ST7789_135x240_YSTART_R1 52
|
||||
#define ST7789_135x240_XSTART_R2 52
|
||||
#define ST7789_135x240_YSTART_R2 40
|
||||
#define ST7789_135x240_XSTART_R3 40
|
||||
#define ST7789_135x240_YSTART_R3 53
|
||||
|
||||
#define ST_CMD_DELAY 0x80 // special signifier for command lists
|
||||
|
||||
|
@ -57,8 +57,8 @@ extern "C" {
|
||||
#include "coredecls.h"
|
||||
#define LOG_HEAP_SIZE(a) _Log_heap_size(a)
|
||||
void _Log_heap_size(const char *msg) {
|
||||
register uint32_t *sp asm("a1");
|
||||
int freestack = 4 * (sp - g_pcont->stack);
|
||||
register uint32_t *sp asm("a1");
|
||||
int freestack = 4 * (sp - g_pcont->stack);
|
||||
Serial.printf("%s %d, Fragmentation=%d, Thunkstack=%d, Free stack=%d, FreeContStack=%d\n",
|
||||
msg, ESP.getFreeHeap(), ESP.getHeapFragmentation(), stack_thunk_light_get_max_usage(),
|
||||
freestack, ESP.getFreeContStack());
|
||||
@ -98,60 +98,60 @@ make_stack_thunk_light(br_ssl_engine_sendrec_buf);
|
||||
// unless the Thunk was initialized. Thanks to AES128 GCM, we can keep
|
||||
// symetric processing on the stack
|
||||
void min_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len) {
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_recvapp_ack(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_recvapp_ack(cc, len);
|
||||
}
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_recvapp_ack(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_recvapp_ack(cc, len);
|
||||
}
|
||||
}
|
||||
unsigned char *min_br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len) {
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_recvapp_buf(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_recvapp_buf(cc, len);
|
||||
}
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_recvapp_buf(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_recvapp_buf(cc, len);
|
||||
}
|
||||
}
|
||||
void min_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len) {
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_recvrec_ack(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_recvrec_ack(cc, len);
|
||||
}
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_recvrec_ack(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_recvrec_ack(cc, len);
|
||||
}
|
||||
}
|
||||
unsigned char *min_br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len) {
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_recvrec_buf(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_recvrec_buf(cc, len);
|
||||
}
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_recvrec_buf(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_recvrec_buf(cc, len);
|
||||
}
|
||||
}
|
||||
void min_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len) {
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_sendapp_ack(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_sendapp_ack(cc, len);
|
||||
}
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_sendapp_ack(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_sendapp_ack(cc, len);
|
||||
}
|
||||
}
|
||||
unsigned char *min_br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len) {
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_sendapp_buf(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_sendapp_buf(cc, len);
|
||||
}
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_sendapp_buf(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_sendapp_buf(cc, len);
|
||||
}
|
||||
}
|
||||
void min_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len) {
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_sendrec_ack(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_sendrec_ack(cc, len);
|
||||
}
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_sendrec_ack(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_sendrec_ack(cc, len);
|
||||
}
|
||||
}
|
||||
unsigned char *min_br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len) {
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_sendrec_buf(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_sendrec_buf(cc, len);
|
||||
}
|
||||
if (stack_thunk_light_get_refcnt()) {
|
||||
return thunk_light_br_ssl_engine_sendrec_buf(cc, len);
|
||||
} else {
|
||||
return br_ssl_engine_sendrec_buf(cc, len);
|
||||
}
|
||||
}
|
||||
|
||||
// Use min_ instead of original thunk_
|
||||
@ -176,7 +176,7 @@ namespace BearSSL {
|
||||
|
||||
void WiFiClientSecure_light::_clear() {
|
||||
// TLS handshake may take more than the 5 second default timeout
|
||||
_timeout = 10000; // 10 seconds max, it should never go over 6 seconds
|
||||
_timeout = 10000; // 10 seconds max, it should never go over 6 seconds
|
||||
|
||||
_sc = nullptr;
|
||||
_ctx_present = false;
|
||||
@ -185,17 +185,17 @@ void WiFiClientSecure_light::_clear() {
|
||||
_iobuf_out = nullptr;
|
||||
setBufferSizes(1024, 1024); // reasonable minimum
|
||||
_handshake_done = false;
|
||||
_last_error = 0;
|
||||
_last_error = 0;
|
||||
_recvapp_buf = nullptr;
|
||||
_recvapp_len = 0;
|
||||
_fingerprint_any = true; // by default accept all fingerprints
|
||||
_fingerprint1 = nullptr;
|
||||
_fingerprint2 = nullptr;
|
||||
_chain_P = nullptr;
|
||||
_sk_ec_P = nullptr;
|
||||
_ta_P = nullptr;
|
||||
_fingerprint_any = true; // by default accept all fingerprints
|
||||
_fingerprint1 = nullptr;
|
||||
_fingerprint2 = nullptr;
|
||||
_chain_P = nullptr;
|
||||
_sk_ec_P = nullptr;
|
||||
_ta_P = nullptr;
|
||||
_ta_size = 0;
|
||||
_max_thunkstack_use = 0;
|
||||
_max_thunkstack_use = 0;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
@ -221,24 +221,24 @@ WiFiClientSecure_light::~WiFiClientSecure_light() {
|
||||
void WiFiClientSecure_light::allocateBuffers(void) {
|
||||
// We prefer to allocate all buffers at start, rather than lazy allocation and deallocation
|
||||
// in the long run it avoids heap fragmentation and improves stability
|
||||
LOG_HEAP_SIZE("allocateBuffers before");
|
||||
LOG_HEAP_SIZE("allocateBuffers before");
|
||||
_sc = std::make_shared<br_ssl_client_context>();
|
||||
LOG_HEAP_SIZE("allocateBuffers ClientContext");
|
||||
LOG_HEAP_SIZE("allocateBuffers ClientContext");
|
||||
_iobuf_in = std::shared_ptr<unsigned char>(new unsigned char[_iobuf_in_size], std::default_delete<unsigned char[]>());
|
||||
_iobuf_out = std::shared_ptr<unsigned char>(new unsigned char[_iobuf_out_size], std::default_delete<unsigned char[]>());
|
||||
LOG_HEAP_SIZE("allocateBuffers after");
|
||||
LOG_HEAP_SIZE("allocateBuffers after");
|
||||
}
|
||||
|
||||
void WiFiClientSecure_light::setClientECCert(const br_x509_certificate *cert, const br_ec_private_key *sk,
|
||||
unsigned allowed_usages, unsigned cert_issuer_key_type) {
|
||||
_chain_P = cert;
|
||||
_sk_ec_P = sk;
|
||||
unsigned allowed_usages, unsigned cert_issuer_key_type) {
|
||||
_chain_P = cert;
|
||||
_sk_ec_P = sk;
|
||||
_allowed_usages = allowed_usages;
|
||||
_cert_issuer_key_type = cert_issuer_key_type;
|
||||
}
|
||||
|
||||
void WiFiClientSecure_light::setTrustAnchor(const br_x509_trust_anchor *ta, size_t ta_size) {
|
||||
_ta_P = ta;
|
||||
_ta_P = ta;
|
||||
_ta_size = ta_size;
|
||||
}
|
||||
|
||||
@ -271,9 +271,9 @@ bool WiFiClientSecure_light::flush(unsigned int maxWaitMs) {
|
||||
|
||||
int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
|
||||
DEBUG_BSSL("connect(%s,%d)", ip.toString().c_str(), port);
|
||||
clearLastError();
|
||||
clearLastError();
|
||||
if (!WiFiClient::connect(ip, port)) {
|
||||
setLastError(ERR_TCP_CONNECT);
|
||||
setLastError(ERR_TCP_CONNECT);
|
||||
return 0;
|
||||
}
|
||||
return _connectSSL(nullptr);
|
||||
@ -282,19 +282,19 @@ int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
|
||||
int WiFiClientSecure_light::connect(const char* name, uint16_t port) {
|
||||
DEBUG_BSSL("connect(%s,%d)\n", name, port);
|
||||
IPAddress remote_addr;
|
||||
clearLastError();
|
||||
clearLastError();
|
||||
if (!WiFi.hostByName(name, remote_addr)) {
|
||||
DEBUG_BSSL("connect: Name loopup failure\n");
|
||||
setLastError(ERR_CANT_RESOLVE_IP);
|
||||
setLastError(ERR_CANT_RESOLVE_IP);
|
||||
return 0;
|
||||
}
|
||||
DEBUG_BSSL("connect(%s,%d)\n", remote_addr.toString().c_str(), port);
|
||||
if (!WiFiClient::connect(remote_addr, port)) {
|
||||
DEBUG_BSSL("connect: Unable to connect TCP socket\n");
|
||||
_last_error = ERR_TCP_CONNECT;
|
||||
_last_error = ERR_TCP_CONNECT;
|
||||
return 0;
|
||||
}
|
||||
LOG_HEAP_SIZE("Before calling _connectSSL");
|
||||
LOG_HEAP_SIZE("Before calling _connectSSL");
|
||||
return _connectSSL(name);
|
||||
}
|
||||
|
||||
@ -355,7 +355,7 @@ size_t WiFiClientSecure_light::_write(const uint8_t *buf, size_t size, bool pmem
|
||||
}
|
||||
} while (size);
|
||||
|
||||
LOG_HEAP_SIZE("_write");
|
||||
LOG_HEAP_SIZE("_write");
|
||||
return sent_bytes;
|
||||
}
|
||||
|
||||
@ -399,7 +399,7 @@ int WiFiClientSecure_light::read(uint8_t *buf, size_t size) {
|
||||
int avail = available();
|
||||
bool conn = connected();
|
||||
if (!avail && conn) {
|
||||
return 0; // We're still connected, but nothing to read
|
||||
return 0; // We're still connected, but nothing to read
|
||||
}
|
||||
if (!avail && !conn) {
|
||||
DEBUG_BSSL("read: Not connected, none left available\n");
|
||||
@ -434,7 +434,7 @@ int WiFiClientSecure_light::read() {
|
||||
|
||||
int WiFiClientSecure_light::available() {
|
||||
if (_recvapp_buf) {
|
||||
return _recvapp_len; // Anything from last call?
|
||||
return _recvapp_len; // Anything from last call?
|
||||
}
|
||||
_recvapp_buf = nullptr;
|
||||
_recvapp_len = 0;
|
||||
@ -443,7 +443,7 @@ int WiFiClientSecure_light::available() {
|
||||
}
|
||||
int st = br_ssl_engine_current_state(_eng);
|
||||
if (st == BR_SSL_CLOSED) {
|
||||
return 0; // Nothing leftover, SSL is closed
|
||||
return 0; // Nothing leftover, SSL is closed
|
||||
}
|
||||
if (st & BR_SSL_RECVAPP) {
|
||||
_recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len);
|
||||
@ -620,24 +620,24 @@ static uint8_t htoi (unsigned char c)
|
||||
|
||||
extern "C" {
|
||||
|
||||
// see https://stackoverflow.com/questions/6357031/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-in-c
|
||||
void tohex(unsigned char * in, size_t insz, char * out, size_t outsz) {
|
||||
unsigned char * pin = in;
|
||||
static const char * hex = "0123456789ABCDEF";
|
||||
char * pout = out;
|
||||
for(; pin < in+insz; pout +=3, pin++){
|
||||
pout[0] = hex[(*pin>>4) & 0xF];
|
||||
pout[1] = hex[ *pin & 0xF];
|
||||
pout[2] = ':';
|
||||
if (pout + 3 - out > outsz){
|
||||
/* Better to truncate output string than overflow buffer */
|
||||
/* it would be still better to either return a status */
|
||||
/* or ensure the target buffer is large enough and it never happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
pout[-1] = 0;
|
||||
}
|
||||
// see https://stackoverflow.com/questions/6357031/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-in-c
|
||||
void tohex(unsigned char * in, size_t insz, char * out, size_t outsz) {
|
||||
unsigned char * pin = in;
|
||||
static const char * hex = "0123456789ABCDEF";
|
||||
char * pout = out;
|
||||
for(; pin < in+insz; pout +=3, pin++){
|
||||
pout[0] = hex[(*pin>>4) & 0xF];
|
||||
pout[1] = hex[ *pin & 0xF];
|
||||
pout[2] = ':';
|
||||
if (pout + 3 - out > outsz){
|
||||
/* Better to truncate output string than overflow buffer */
|
||||
/* it would be still better to either return a status */
|
||||
/* or ensure the target buffer is large enough and it never happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
pout[-1] = 0;
|
||||
}
|
||||
|
||||
|
||||
// BearSSL doesn't define a true insecure decoder, so we make one ourselves
|
||||
@ -648,12 +648,12 @@ extern "C" {
|
||||
// Private x509 decoder state
|
||||
struct br_x509_pubkeyfingerprint_context {
|
||||
const br_x509_class *vtable;
|
||||
bool done_cert; // did we parse the first cert already?
|
||||
bool fingerprint_all;
|
||||
uint8_t *pubkey_recv_fingerprint;
|
||||
bool done_cert; // did we parse the first cert already?
|
||||
bool fingerprint_all;
|
||||
uint8_t *pubkey_recv_fingerprint;
|
||||
const uint8_t *fingerprint1;
|
||||
const uint8_t *fingerprint2;
|
||||
unsigned usages; // pubkey usage
|
||||
unsigned usages; // pubkey usage
|
||||
br_x509_decoder_context ctx; // defined in BearSSL
|
||||
};
|
||||
|
||||
@ -662,15 +662,15 @@ extern "C" {
|
||||
br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
|
||||
// Don't process anything but the first certificate in the chain
|
||||
if (!xc->done_cert) {
|
||||
br_x509_decoder_init(&xc->ctx, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
(void)server_name; // ignore server name
|
||||
br_x509_decoder_init(&xc->ctx, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
(void)server_name; // ignore server name
|
||||
}
|
||||
|
||||
// Callback for each certificate present in the chain (but only operates
|
||||
// on the first one by design).
|
||||
static void pubkeyfingerprint_start_cert(const br_x509_class **ctx, uint32_t length) {
|
||||
(void) ctx; // do nothing
|
||||
(void) ctx; // do nothing
|
||||
(void) length;
|
||||
}
|
||||
|
||||
@ -686,7 +686,7 @@ extern "C" {
|
||||
// Callback on individual cert end.
|
||||
static void pubkeyfingerprint_end_cert(const br_x509_class **ctx) {
|
||||
br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
|
||||
xc->done_cert = true; // first cert already processed
|
||||
xc->done_cert = true; // first cert already processed
|
||||
}
|
||||
|
||||
// **** Start patch Castellucci
|
||||
@ -743,18 +743,18 @@ extern "C" {
|
||||
pubkeyfingerprint_pubkey_fingerprint(&sha1_context, xc->ctx.pkey.key.rsa);
|
||||
br_sha1_out(&sha1_context, xc->pubkey_recv_fingerprint); // copy to fingerprint
|
||||
|
||||
if (!xc->fingerprint_all) {
|
||||
if (0 == memcmp_P(xc->pubkey_recv_fingerprint, xc->fingerprint1, 20)) {
|
||||
return 0;
|
||||
}
|
||||
if (0 == memcmp_P(xc->pubkey_recv_fingerprint, xc->fingerprint2, 20)) {
|
||||
return 0;
|
||||
}
|
||||
return 1; // no match, error
|
||||
} else {
|
||||
// Default (no validation at all) or no errors in prior checks = success.
|
||||
return 0;
|
||||
}
|
||||
if (!xc->fingerprint_all) {
|
||||
if (0 == memcmp_P(xc->pubkey_recv_fingerprint, xc->fingerprint1, 20)) {
|
||||
return 0;
|
||||
}
|
||||
if (0 == memcmp_P(xc->pubkey_recv_fingerprint, xc->fingerprint2, 20)) {
|
||||
return 0;
|
||||
}
|
||||
return 1; // no match, error
|
||||
} else {
|
||||
// Default (no validation at all) or no errors in prior checks = success.
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
// set fingerprint status byte to zero
|
||||
// FIXME: find a better way to pass this information
|
||||
@ -796,7 +796,7 @@ extern "C" {
|
||||
xc->pubkey_recv_fingerprint[20] |= 2; // mark for update
|
||||
}
|
||||
if (!xc->pubkey_recv_fingerprint[20]) {
|
||||
return 1; // not marked for update because no match, error
|
||||
return 1; // not marked for update because no match, error
|
||||
}
|
||||
|
||||
// the old fingerprint format matched, recompute new one for update
|
||||
@ -822,9 +822,9 @@ extern "C" {
|
||||
|
||||
// Set up the x509 insecure data structures for BearSSL core to use.
|
||||
void br_x509_pubkeyfingerprint_init(br_x509_pubkeyfingerprint_context *ctx,
|
||||
const uint8_t *fingerprint1, const uint8_t *fingerprint2,
|
||||
uint8_t *recv_fingerprint,
|
||||
bool fingerprint_all) {
|
||||
const uint8_t *fingerprint1, const uint8_t *fingerprint2,
|
||||
uint8_t *recv_fingerprint,
|
||||
bool fingerprint_all) {
|
||||
static const br_x509_class br_x509_pubkeyfingerprint_vtable PROGMEM = {
|
||||
sizeof(br_x509_pubkeyfingerprint_context),
|
||||
pubkeyfingerprint_start_chain,
|
||||
@ -838,26 +838,26 @@ extern "C" {
|
||||
memset(ctx, 0, sizeof * ctx);
|
||||
ctx->vtable = &br_x509_pubkeyfingerprint_vtable;
|
||||
ctx->done_cert = false;
|
||||
ctx->fingerprint1 = fingerprint1;
|
||||
ctx->fingerprint2 = fingerprint2;
|
||||
ctx->pubkey_recv_fingerprint = recv_fingerprint;
|
||||
ctx->fingerprint_all = fingerprint_all;
|
||||
ctx->fingerprint1 = fingerprint1;
|
||||
ctx->fingerprint2 = fingerprint2;
|
||||
ctx->pubkey_recv_fingerprint = recv_fingerprint;
|
||||
ctx->fingerprint_all = fingerprint_all;
|
||||
}
|
||||
|
||||
// We limit to a single cipher to reduce footprint
|
||||
// We limit to a single cipher to reduce footprint
|
||||
// we reference it, don't put in PROGMEM
|
||||
static const uint16_t suites[] = {
|
||||
#ifdef USE_MQTT_TLS_FORCE_EC_CIPHER
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
#else
|
||||
BR_TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||
BR_TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||
#endif
|
||||
};
|
||||
|
||||
// Default initializion for our SSL clients
|
||||
static void br_ssl_client_base_init(br_ssl_client_context *cc) {
|
||||
br_ssl_client_zero(cc);
|
||||
// forbid SSL renegociation, as we free the Private Key after handshake
|
||||
// forbid SSL renegotiation, as we free the Private Key after handshake
|
||||
br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION);
|
||||
|
||||
br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
|
||||
@ -869,14 +869,14 @@ extern "C" {
|
||||
br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
|
||||
br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
|
||||
|
||||
// AES CTR/GCM small version, not contstant time (we don't really care here as there is no TPM anyways)
|
||||
br_ssl_engine_set_gcm(&cc->eng, &br_sslrec_in_gcm_vtable, &br_sslrec_out_gcm_vtable);
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng, &br_aes_small_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng, &br_ghash_ctmul32);
|
||||
// AES CTR/GCM small version, not contstant time (we don't really care here as there is no TPM anyways)
|
||||
br_ssl_engine_set_gcm(&cc->eng, &br_sslrec_in_gcm_vtable, &br_sslrec_out_gcm_vtable);
|
||||
br_ssl_engine_set_aes_ctr(&cc->eng, &br_aes_small_ctr_vtable);
|
||||
br_ssl_engine_set_ghash(&cc->eng, &br_ghash_ctmul32);
|
||||
|
||||
#ifdef USE_MQTT_TLS_FORCE_EC_CIPHER
|
||||
// we support only P256 EC curve for AWS IoT, no EC curve for Letsencrypt unless forced
|
||||
br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15); // TODO
|
||||
// we support only P256 EC curve for AWS IoT, no EC curve for Letsencrypt unless forced
|
||||
br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15); // TODO
|
||||
#endif
|
||||
static const char * alpn_mqtt = "mqtt";
|
||||
br_ssl_engine_set_protocol_names(&cc->eng, &alpn_mqtt, 1);
|
||||
@ -886,110 +886,110 @@ extern "C" {
|
||||
// Called by connect() to do the actual SSL setup and handshake.
|
||||
// Returns if the SSL handshake succeeded.
|
||||
bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
|
||||
// Validation context, either full CA validation or checking only fingerprints
|
||||
// Validation context, either full CA validation or checking only fingerprints
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
br_x509_minimal_context *x509_minimal;
|
||||
br_x509_minimal_context *x509_minimal;
|
||||
#else
|
||||
br_x509_pubkeyfingerprint_context *x509_insecure;
|
||||
#endif
|
||||
|
||||
LOG_HEAP_SIZE("_connectSSL.start");
|
||||
LOG_HEAP_SIZE("_connectSSL.start");
|
||||
|
||||
do { // used to exit on Out of Memory error and keep all cleanup code at the same place
|
||||
// ============================================================
|
||||
// allocate Thunk stack, move to alternate stack and initialize
|
||||
stack_thunk_light_add_ref();
|
||||
LOG_HEAP_SIZE("Thunk allocated");
|
||||
DEBUG_BSSL("_connectSSL: start connection\n");
|
||||
_freeSSL();
|
||||
clearLastError();
|
||||
if (!stack_thunk_light_get_stack_bot()) break;
|
||||
do { // used to exit on Out of Memory error and keep all cleanup code at the same place
|
||||
// ============================================================
|
||||
// allocate Thunk stack, move to alternate stack and initialize
|
||||
stack_thunk_light_add_ref();
|
||||
LOG_HEAP_SIZE("Thunk allocated");
|
||||
DEBUG_BSSL("_connectSSL: start connection\n");
|
||||
_freeSSL();
|
||||
clearLastError();
|
||||
if (!stack_thunk_light_get_stack_bot()) break;
|
||||
|
||||
_ctx_present = true;
|
||||
_eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr
|
||||
_ctx_present = true;
|
||||
_eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr
|
||||
|
||||
br_ssl_client_base_init(_sc.get());
|
||||
br_ssl_client_base_init(_sc.get());
|
||||
|
||||
// ============================================================
|
||||
// Allocatte and initialize Decoder Context
|
||||
LOG_HEAP_SIZE("_connectSSL before DecoderContext allocation");
|
||||
// Only failure possible in the installation is OOM
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
x509_minimal = (br_x509_minimal_context*) malloc(sizeof(br_x509_minimal_context));
|
||||
if (!x509_minimal) break;
|
||||
br_x509_minimal_init(x509_minimal, &br_sha256_vtable, _ta_P, _ta_size);
|
||||
br_x509_minimal_set_rsa(x509_minimal, br_ssl_engine_get_rsavrfy(_eng));
|
||||
br_x509_minimal_set_hash(x509_minimal, br_sha256_ID, &br_sha256_vtable);
|
||||
br_ssl_engine_set_x509(_eng, &x509_minimal->vtable);
|
||||
// ============================================================
|
||||
// Allocatte and initialize Decoder Context
|
||||
LOG_HEAP_SIZE("_connectSSL before DecoderContext allocation");
|
||||
// Only failure possible in the installation is OOM
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
x509_minimal = (br_x509_minimal_context*) malloc(sizeof(br_x509_minimal_context));
|
||||
if (!x509_minimal) break;
|
||||
br_x509_minimal_init(x509_minimal, &br_sha256_vtable, _ta_P, _ta_size);
|
||||
br_x509_minimal_set_rsa(x509_minimal, br_ssl_engine_get_rsavrfy(_eng));
|
||||
br_x509_minimal_set_hash(x509_minimal, br_sha256_ID, &br_sha256_vtable);
|
||||
br_ssl_engine_set_x509(_eng, &x509_minimal->vtable);
|
||||
uint32_t now = UtcTime();
|
||||
uint32_t cfg_time = CfgTime();
|
||||
if (cfg_time > now) { now = cfg_time; }
|
||||
br_x509_minimal_set_time(x509_minimal, now / 86400 + 719528, now % 86400);
|
||||
|
||||
#else
|
||||
x509_insecure = (br_x509_pubkeyfingerprint_context*) malloc(sizeof(br_x509_pubkeyfingerprint_context));
|
||||
//x509_insecure = std::unique_ptr<br_x509_pubkeyfingerprint_context>(new br_x509_pubkeyfingerprint_context);
|
||||
if (!x509_insecure) break;
|
||||
br_x509_pubkeyfingerprint_init(x509_insecure, _fingerprint1, _fingerprint2, _recv_fingerprint, _fingerprint_any);
|
||||
br_ssl_engine_set_x509(_eng, &x509_insecure->vtable);
|
||||
#endif
|
||||
LOG_HEAP_SIZE("_connectSSL after DecoderContext allocation");
|
||||
#else
|
||||
x509_insecure = (br_x509_pubkeyfingerprint_context*) malloc(sizeof(br_x509_pubkeyfingerprint_context));
|
||||
//x509_insecure = std::unique_ptr<br_x509_pubkeyfingerprint_context>(new br_x509_pubkeyfingerprint_context);
|
||||
if (!x509_insecure) break;
|
||||
br_x509_pubkeyfingerprint_init(x509_insecure, _fingerprint1, _fingerprint2, _recv_fingerprint, _fingerprint_any);
|
||||
br_ssl_engine_set_x509(_eng, &x509_insecure->vtable);
|
||||
#endif
|
||||
LOG_HEAP_SIZE("_connectSSL after DecoderContext allocation");
|
||||
|
||||
// ============================================================
|
||||
// Set send/receive buffers
|
||||
br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size);
|
||||
// ============================================================
|
||||
// Set send/receive buffers
|
||||
br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size);
|
||||
|
||||
// ============================================================
|
||||
// allocate Private key if needed, only if USE_MQTT_AWS_IOT
|
||||
LOG_HEAP_SIZE("_connectSSL before PrivKey allocation");
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
// ============================================================
|
||||
// Set the EC Private Key, only USE_MQTT_AWS_IOT
|
||||
// limited to P256 curve
|
||||
br_ssl_client_set_single_ec(_sc.get(), _chain_P, 1,
|
||||
_sk_ec_P, _allowed_usages,
|
||||
_cert_issuer_key_type, &br_ec_p256_m15, br_ecdsa_sign_asn1_get_default());
|
||||
#endif // USE_MQTT_AWS_IOT
|
||||
// ============================================================
|
||||
// allocate Private key if needed, only if USE_MQTT_AWS_IOT
|
||||
LOG_HEAP_SIZE("_connectSSL before PrivKey allocation");
|
||||
#ifdef USE_MQTT_AWS_IOT
|
||||
// ============================================================
|
||||
// Set the EC Private Key, only USE_MQTT_AWS_IOT
|
||||
// limited to P256 curve
|
||||
br_ssl_client_set_single_ec(_sc.get(), _chain_P, 1,
|
||||
_sk_ec_P, _allowed_usages,
|
||||
_cert_issuer_key_type, &br_ec_p256_m15, br_ecdsa_sign_asn1_get_default());
|
||||
#endif // USE_MQTT_AWS_IOT
|
||||
|
||||
// ============================================================
|
||||
// Start TLS connection, ALL
|
||||
if (!br_ssl_client_reset(_sc.get(), hostName, 0)) break;
|
||||
// ============================================================
|
||||
// Start TLS connection, ALL
|
||||
if (!br_ssl_client_reset(_sc.get(), hostName, 0)) break;
|
||||
|
||||
auto ret = _wait_for_handshake();
|
||||
#ifdef DEBUG_ESP_SSL
|
||||
if (!ret) {
|
||||
DEBUG_BSSL("Couldn't connect. Error = %d\n", getLastError());
|
||||
} else {
|
||||
DEBUG_BSSL("Connected! MFLNStatus = %d\n", getMFLNStatus());
|
||||
}
|
||||
#endif
|
||||
LOG_HEAP_SIZE("_connectSSL.end");
|
||||
_max_thunkstack_use = stack_thunk_light_get_max_usage();
|
||||
stack_thunk_light_del_ref();
|
||||
//stack_thunk_light_repaint();
|
||||
LOG_HEAP_SIZE("_connectSSL.end, freeing StackThunk");
|
||||
auto ret = _wait_for_handshake();
|
||||
#ifdef DEBUG_ESP_SSL
|
||||
if (!ret) {
|
||||
DEBUG_BSSL("Couldn't connect. Error = %d\n", getLastError());
|
||||
} else {
|
||||
DEBUG_BSSL("Connected! MFLNStatus = %d\n", getMFLNStatus());
|
||||
}
|
||||
#endif
|
||||
LOG_HEAP_SIZE("_connectSSL.end");
|
||||
_max_thunkstack_use = stack_thunk_light_get_max_usage();
|
||||
stack_thunk_light_del_ref();
|
||||
//stack_thunk_light_repaint();
|
||||
LOG_HEAP_SIZE("_connectSSL.end, freeing StackThunk");
|
||||
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
free(x509_minimal);
|
||||
#else
|
||||
free(x509_insecure);
|
||||
#endif
|
||||
LOG_HEAP_SIZE("_connectSSL after release of Priv Key");
|
||||
return ret;
|
||||
} while (0);
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
free(x509_minimal);
|
||||
#else
|
||||
free(x509_insecure);
|
||||
#endif
|
||||
LOG_HEAP_SIZE("_connectSSL after release of Priv Key");
|
||||
return ret;
|
||||
} while (0);
|
||||
|
||||
// ============================================================
|
||||
// if we arrived here, this means we had an OOM error, cleaning up
|
||||
setLastError(ERR_OOM);
|
||||
DEBUG_BSSL("_connectSSL: Out of memory\n");
|
||||
stack_thunk_light_del_ref();
|
||||
// ============================================================
|
||||
// if we arrived here, this means we had an OOM error, cleaning up
|
||||
setLastError(ERR_OOM);
|
||||
DEBUG_BSSL("_connectSSL: Out of memory\n");
|
||||
stack_thunk_light_del_ref();
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
free(x509_minimal);
|
||||
free(x509_minimal);
|
||||
#else
|
||||
free(x509_insecure);
|
||||
free(x509_insecure);
|
||||
#endif
|
||||
LOG_HEAP_SIZE("_connectSSL clean_on_error");
|
||||
return false;
|
||||
LOG_HEAP_SIZE("_connectSSL clean_on_error");
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -2,38 +2,39 @@
|
||||
// compressed by tools/unishox/compress-html-uncompressed.py
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
const size_t HTTP_SCRIPT_CONSOL_SIZE = 853;
|
||||
const char HTTP_SCRIPT_CONSOL_COMPRESSED[] PROGMEM = "\x33\xBF\xAF\x71\xF0\xE3\x3A\x8B\x44\x3E\x1C\x67\x82\x30\x2F\x83\xAD\xCE\x41\x1D"
|
||||
"\xD1\x87\x78\xF6\x99\xDF\xD0\x67\x56\x1F\x0F\xB3\xEC\xEA\xA3\xC0\x61\x3B\xF9\x56"
|
||||
"\x8D\x78\x2E\x8E\xE8\x54\x77\x8F\x14\x7C\x63\x8E\xE9\xF7\x47\x21\xF6\x77\x8F\x05"
|
||||
"\xA6\x0E\xE8\xC3\xE1\xF0\xE4\x3B\xC7\xB4\x83\x3E\x31\xC7\x74\xFB\x0C\xE4\x3E\xCE"
|
||||
"\xF1\xE0\xB0\xF8\x7D\x9F\xA0\xCE\x43\xE1\xF6\x76\xC9\xF0\x78\x23\x21\x65\xF2\xD2"
|
||||
"\x0F\x06\x8C\xCE\x7D\x47\x74\x33\xA1\x9D\x84\x2D\x9D\xE3\xC0\x21\x45\x3E\x1F\x67"
|
||||
"\xD9\xE2\x8E\x9E\x0F\xF8\x10\x45\x58\x30\xF8\x71\x11\xBD\x2A\x01\xF1\xEE\x3E\x02"
|
||||
"\x35\x13\xC1\xEE\xD3\x07\x74\x11\xA6\x1F\x87\xCF\x71\xDE\x3D\xBA\x60\xEE\x9B\x0F"
|
||||
"\xE1\xF3\x85\x84\x11\xDE\x3D\xA6\xC3\xA5\x8E\xCF\xD1\xDD\x3B\xC7\x83\xDC\x6C\x3E"
|
||||
"\x73\x1F\x44\x6C\x21\xA4\x11\x0A\xAA\x18\x5F\x66\xA1\x6F\xD4\x77\x4E\xF1\xE0\xD8"
|
||||
"\x74\xCE\xFB\xB1\x0C\xBD\x57\x4C\x31\x57\xC3\xCC\xF8\x08\x7C\x28\x1D\xD0\x41\xCA"
|
||||
"\x8E\x9F\x76\x21\x91\x7A\xAE\x99\xF0\xF8\x73\x0F\xD1\xFA\x23\x61\xD3\xD5\x74\x2F"
|
||||
"\xC7\xC3\xE1\xCA\x6C\x81\x07\x87\x03\x69\xD4\x21\xE0\x43\xE1\xB0\xE9\xF7\xE1\x99"
|
||||
"\xDE\x65\x4C\xD9\x47\x4F\x0C\x0B\x68\xEE\x9D\x87\xB8\xE4\x3B\x0E\xF1\xE0\xB4\x43"
|
||||
"\xE0\x87\x4F\x0A\xD3\x14\x77\x4E\xF1\xE3\x4C\x1D\xD0\x44\x92\x7C\x3E\x1C\x67\x78"
|
||||
"\xF6\x95\x02\x2F\x0A\x27\xB8\xDA\x09\x38\x29\xB4\xE8\x13\xE1\xEA\x14\x7E\x02\x2E"
|
||||
"\x06\x76\xCF\x86\xD3\xC1\xEE\x05\xDE\x1E\x4F\x71\xE0\xD8\x74\xC1\x8F\x8E\xE9\xF6"
|
||||
"\x43\xC4\xCA\x8F\xB3\xA8\xFB\x0F\xC7\x68\x33\x94\x7C\x3E\xCE\xD9\x68\x87\x6F\x0E"
|
||||
"\xAA\xF8\xB6\x77\x8F\x06\xC3\xA7\x9F\x08\x77\x4E\xF1\xE0\xF7\x05\x47\xCF\x3A\x04"
|
||||
"\x4E\x4A\x4E\xA3\xE8\x43\xBC\x78\xFB\xA1\x7F\xE4\x62\xC2\xF3\x3C\x1E\xE1\xF0\x8E"
|
||||
"\xE8\x47\x78\xF0\x67\x7F\x42\x83\x3E\x1E\xF1\xEF\x9D\x41\xF0\x23\xF2\xF4\x28\xEE"
|
||||
"\x9D\xE3\xDA\x08\x7C\xA2\x9D\x2C\x41\x09\x99\xBE\xA2\x0B\x7D\x4F\x9F\xCE\xE9\xF6"
|
||||
"\x68\xCC\x84\xC1\xFE\x3E\xCE\xA0\x44\xE2\xDD\x82\x0F\x12\xA3\x81\x13\x97\xB3\xA8"
|
||||
"\x33\xE3\x3A\x1A\x33\x22\x0F\x04\x67\x8D\x30\x77\x4E\x5F\xCF\x87\xC2\x0C\xFF\x1F"
|
||||
"\xE3\x98\xCF\x87\xC2\x0C\xEF\x1E\xD1\xC7\x4B\x17\x58\x1E\x0D\x18\x13\xA6\x7C\x3E"
|
||||
"\xF0\xC1\x83\xEC\xF0\x7B\x8E\x5F\xCF\x87\xC2\x0C\xED\x1D\xD3\xB6\x76\xC3\xE3\xF0"
|
||||
"\x50\x60\x85\xC4\x31\xFA\x3F\x47\x74\x3E\x3E\x02\x24\xB3\xBC\x75\x0E\x04\x2E\x2E"
|
||||
"\x85\x06\x7B\xC1\xF1\xD6\x72\x1E\xF9\xFE\x3F\xC7\xD9\xF6\x77\x8F\x3C\x67\xC3\xE1"
|
||||
"\x06\x76\x8E\xE9\xC6\x7E\x1D\x67\x59\x07\xC0\x83\x88\x1C\x64\x0A\x78\x41\xC9\x67"
|
||||
"\xC3\xE1\x06\x7E\x8F\xD1\xDD\x04\x4C\xC4\xFC\x39\x11\xFA\x3F\x44\x28\x33\xA0\xCC"
|
||||
"\x18\x77\x4E\xF1\xD4\x28\x33\xA0\xBE\x04\x1E\x44\x01\x0B\x1C\x3B\xC7\x50\x7C\x7C"
|
||||
"\x38\xCE\xF1\xEE\x3B\xC7\x83\xDC\x43\xE1\x1D\xD1\x47\x78\xF0";
|
||||
const size_t HTTP_SCRIPT_CONSOL_SIZE = 913;
|
||||
const char HTTP_SCRIPT_CONSOL_COMPRESSED[] PROGMEM = "\x3D\xA1\x3A\x5E\xE3\xE1\xC6\x75\x16\x88\x7C\x38\xCE\xA2\x31\x47\x83\x02\xF8\x3A"
|
||||
"\xDC\xE4\x11\xDD\x18\x77\x8F\x68\x4E\x90\x67\x56\x1F\x0F\xB3\xEC\xF0\x18\x4E\xFE"
|
||||
"\x55\xA3\x5E\x0B\xA3\xBA\x15\x1D\xE0\x49\x9A\x62\x8E\xF1\xE2\x8F\x8C\x71\xDD\x3E"
|
||||
"\xE8\xE4\x3E\xCE\xF1\xE0\xB4\xC1\xDD\x18\x7C\x3E\x1C\x87\x78\xF6\x90\x67\xC6\x38"
|
||||
"\xEE\x9F\x61\x9C\x87\xD9\xDE\x3C\x16\x1F\x0F\xB3\xF4\x19\xC8\x7C\x3E\xCE\xD9\x3E"
|
||||
"\x0F\x04\x64\x2C\xBE\x5A\x41\xE0\xD1\x99\xCF\xA8\xEE\x86\x74\x33\xB0\x85\xB3\xBC"
|
||||
"\x78\x04\x28\xA7\xC3\xEC\xFB\x3C\x51\xD3\xC1\xFF\x02\x08\xAB\x06\x1F\x0E\x22\x37"
|
||||
"\xA0\x1E\x3D\xC7\xC0\x46\xA2\x78\x3D\xDA\x60\xEE\x82\x34\xC3\xF0\xF9\xEE\x3B\xC7"
|
||||
"\xB7\x4C\x1D\xD3\x61\xFC\x3E\x70\xB0\x82\x3B\xC7\xB4\xD8\x74\xB1\xD9\xFA\x3B\xA7"
|
||||
"\x78\xF0\x7B\x8D\x87\xCE\x63\xE8\x8D\x84\x34\x82\x21\x55\x43\x0B\xEC\xD4\x2D\xFA"
|
||||
"\x8E\xE9\xDE\x3C\x1B\x0E\x99\xDF\x76\x21\x97\xAA\xE9\x86\x2A\x2B\xF8\x79\x9F\x01"
|
||||
"\x0F\x85\xF3\xBA\x08\x39\x51\xD3\xEE\xC4\x32\x2F\x55\xD3\x3E\x1F\x0E\x61\xFA\x3F"
|
||||
"\x44\x6C\x3A\x7A\xAE\x85\xF8\xF8\x7C\x39\x4D\x90\x20\xF0\xFE\x6D\x3A\x84\x3C\x08"
|
||||
"\x7C\x36\x1D\x3E\xFC\x33\x3B\xCC\xA9\x9B\x28\xE9\xE1\x81\x6D\x1D\xD3\xB0\xF7\x1C"
|
||||
"\x87\x61\xDE\x3C\x16\x88\x7C\x10\xE9\xE1\x5A\x62\x8E\xE9\xDE\x3C\x69\x83\xBA\x08"
|
||||
"\x92\x4F\x87\xC3\x8C\xEF\x1E\xD2\xA0\x45\xE1\x44\xF7\x1B\x41\x27\x05\x36\x9D\x02"
|
||||
"\x7C\x3D\x42\x8F\xC0\x45\xC0\xCE\xD9\xF0\xDA\x78\x3D\xC0\xB9\xC3\xC8\x26\x71\xF4"
|
||||
"\x15\x1F\x3C\xE8\x11\x39\x1D\x3A\x8F\xA1\x0E\xF1\xE0\xF7\x1E\xE3\xC1\xB0\xE9\x83"
|
||||
"\x1F\x1D\xD3\xEC\x87\x89\x95\x1F\x67\x51\xF6\x1F\x8E\xD0\x67\x28\xF8\x7D\x9D\xB2"
|
||||
"\xD1\x0E\xDE\x1D\x55\xF1\x6C\xEF\x1E\x0D\x87\x4F\x3E\x10\xEE\x9D\xE3\xC1\x80\x4A"
|
||||
"\xC7\x4E\x53\x6D\x9D\xE3\xC1\xEE\x2F\xBA\x17\xFE\x46\x2C\x2F\x33\xC1\xEE\x1F\x08"
|
||||
"\xEE\x84\x77\x8F\x01\x3A\x42\x83\x3E\x1E\xF1\xEF\x9D\x41\xF1\xF0\xE3\x20\x45\xE6"
|
||||
"\xC4\x51\xDD\x3B\xC7\xB4\x10\xF9\x6D\x3A\x58\x82\x13\x33\x7D\x44\x16\xFA\x9F\x3F"
|
||||
"\x9D\xD3\xEC\xD1\x99\x09\x83\xFC\x7D\x9D\x40\x89\xC6\xFB\x04\x1E\x2F\x47\x02\x27"
|
||||
"\x34\x67\x50\x67\xC6\x74\x34\x66\x44\x1E\x08\xCF\x1A\x60\xEE\x9C\xBF\x9F\x0F\x84"
|
||||
"\x19\xFE\x3F\xC7\x31\x9F\x0F\x84\x19\xDE\x3D\xA3\x8E\x96\x2E\xB0\x3C\x1A\x30\x27"
|
||||
"\x4C\xF8\x7D\xE1\x83\x07\xD9\xE0\xF7\x1C\xBF\x9F\x0F\x84\x19\xDA\x3B\xA7\x6C\xED"
|
||||
"\x87\xC7\xE0\xA0\xC1\x0B\x8A\xE3\xF4\x7E\x8E\xE8\x7C\x7C\x04\x49\x67\x78\xEA\x1C"
|
||||
"\x08\x5C\x71\x0A\x0C\xF7\x83\xE3\xAC\xE4\x3D\xF3\xFC\x7F\x8F\xB3\xEC\xEF\x1E\x78"
|
||||
"\xCF\x87\xC2\x0C\xED\x1D\xD3\x8C\xFC\x3A\xCE\xB2\x0F\x81\x07\x10\x38\xC8\x14\xF0"
|
||||
"\x83\x92\xCF\x87\xC2\x0C\xFD\x1F\xA3\xBA\x08\x99\x89\xF8\x72\x23\xF4\x7E\x88\x50"
|
||||
"\x67\x41\x98\x30\xEE\x9D\xE3\xA8\x50\x67\x41\x7C\x08\x3C\x9C\x02\x16\x38\x77\x8E"
|
||||
"\xA0\xF8\xF8\x71\x9D\xE3\xDC\x77\x8F\x07\xB8\x87\xC2\x3B\xA2\x8E\xF1\xE0\xF7\x1B";
|
||||
|
||||
#define HTTP_SCRIPT_CONSOL Decompress(HTTP_SCRIPT_CONSOL_COMPRESSED,HTTP_SCRIPT_CONSOL_SIZE).c_str()
|
@ -2,26 +2,26 @@
|
||||
// compressed by tools/unishox/compress-html-uncompressed.py
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
const size_t HTTP_SCRIPT_ROOT_SIZE = 524;
|
||||
const char HTTP_SCRIPT_ROOT_COMPRESSED[] PROGMEM = "\x30\x2F\x83\xAD\xCE\x41\x59\xDD\x18\x77\x8F\x69\x9D\xFD\x59\xF0\xFB\x3E\xCF\x1A"
|
||||
"\x60\xEE\x85\x67\x4B\xF8\xF0\xB1\xAF\xAB\xC7\x40\x9F\x0F\x50\xA3\xE1\xF0\xE4\x3B"
|
||||
"\xC7\xB4\xAC\xF8\x30\xF0\x18\x4E\xFE\x55\xA3\x5E\x0B\xA3\xBA\x15\x1D\xE3\xC1\xEE"
|
||||
"\xD3\x07\x74\xD8\x7F\x0F\x9C\x2C\x20\x8E\xF1\xED\x36\x1D\x2C\x76\x7E\x8E\xE9\xDE"
|
||||
"\x3C\x1E\xE3\x61\xF3\x98\xFA\x23\x61\x0D\x20\x88\x55\x50\xC2\xFB\x35\x0B\x7E\xA3"
|
||||
"\xBA\x77\x8F\x06\xC3\xA6\x77\xDD\x88\x65\xEA\xBA\x61\x8A\xBE\x1E\x67\xC0\x43\xDA"
|
||||
"\x0E\xE9\xDE\x3D\xBA\x60\xEE\x9B\x0E\x9F\x76\x21\x91\x7A\xAE\x99\xF0\xF8\x73\x0F"
|
||||
"\xD1\xFA\x23\x61\xD3\xD5\x74\x2F\xC7\xC3\xE1\xCA\x6C\x81\x07\x80\x7F\x1F\x0D\x87"
|
||||
"\x4F\xBF\x0C\xCE\xF3\x2A\x2B\x66\xCA\x3A\x7D\x8C\x0A\xC3\x67\x74\xEC\x3D\xB4\x7B"
|
||||
"\x8E\xC1\xE3\xA8\xF6\x1E\x95\x63\x82\x6B\xD4\x64\x13\x3E\x1F\x63\xFA\x25\x0A\x3C"
|
||||
"\xCE\x46\xCF\xA3\xE8\xFB\x3F\x0F\x61\xDE\x20\x46\xC2\xBC\x08\x58\x57\xCF\xC3\xD2"
|
||||
"\x85\x02\x4D\x71\xA0\x83\x5C\xEC\xA1\x47\xE1\xE9\x42\x02\x4E\x4E\x72\x99\x0C\x36"
|
||||
"\x1E\x07\xC5\x6D\x33\xAF\xC3\x2C\x36\x79\xF6\x0F\xFE\xC6\x02\x56\x72\xC1\x0F\x1E"
|
||||
"\x10\xFC\x3D\x0E\xCA\xF8\x24\xD9\x0C\xF7\x1D\x83\xC7\x51\xEC\x3E\x8F\xA3\xEC\xFC"
|
||||
"\x3D\x04\xD3\x30\x43\xCE\xE9\x9B\x28\xEB\xB0\xB4\x7B\x8F\x30\xDF\x53\xF9\xE0\xC6"
|
||||
"\x75\x1D\x63\xEF\x47\x85\x51\xE6\x7B\x0E\xF1\xE1\x8E\x3B\xA7\xD8\x47\x21\xF6\x77"
|
||||
"\x8E\x85\xBD\xCF\xE4\x28\xA8\x86\x90\x47\xCF\x1E\x0F\x71\xEE\x3C\x1B\x0E\x98\x31"
|
||||
"\xF1\xDD\x3E\xC8\x78\x99\x51\xF6\x75\x1F\x67\x43\xB4\x34\xF8\x72\x1F\x67\x6C\xAC"
|
||||
"\xEA\xAF\x8B\x67\x78\xF0\x6C\x3A\x79\xF0\x87\x74\xEF\x1E\x02\xA3\xE7\x9D\x02\x27"
|
||||
"\x23\x96\x75\x1F\x42\x1D\xE3\xC1\xEE";
|
||||
const size_t HTTP_SCRIPT_ROOT_SIZE = 574;
|
||||
const char HTTP_SCRIPT_ROOT_COMPRESSED[] PROGMEM = "\x3D\xA1\x3A\x46\x28\xF0\x60\x5F\x07\x5B\x9C\x82\xB3\xBA\x30\xEF\x1E\xDB\x3E\x0C"
|
||||
"\x3F\xC7\xF8\xFB\x3E\xCF\x01\x84\xEF\xE5\x5A\x35\xE0\xBA\x3B\xA6\x28\xEF\x02\x4C"
|
||||
"\xD0\xA8\xEF\x1E\x34\xC1\xDD\x36\x1F\xC3\xE7\x0B\x08\x23\xBC\x7B\x4D\x87\x4B\x1D"
|
||||
"\x9F\xA3\xBA\x77\x8F\x71\xB0\xF9\xCC\x7D\x11\xB0\x86\x90\x44\x2A\x2B\xA8\x61\x7D"
|
||||
"\x9A\x85\xBF\x51\xDD\x3B\xC7\x83\x61\xD3\x3B\xEE\xC4\x32\xF5\x5D\x30\xC5\x5F\x0F"
|
||||
"\x33\xE0\x21\xEA\xE7\x74\xEF\x1E\xDD\x30\x77\x4D\x87\x4F\xBB\x10\xC8\xBD\x57\x4C"
|
||||
"\xF8\x7C\x39\x87\xE8\xFD\x11\xB0\xE9\xEA\xBA\x17\xE3\xE1\xF0\xE5\x36\x77\x8F\x69"
|
||||
"\x19\xDF\xD7\x8F\x86\xC3\xA7\xDF\x86\x67\x79\x95\x33\x65\x1D\x3E\xC6\x05\x61\xB3"
|
||||
"\xBA\x76\x1E\xDA\x3D\xC7\x60\xF1\xD4\x7B\x0F\x4A\xB1\xC1\x35\xEA\x32\x09\x9F\x0F"
|
||||
"\xB1\xFD\x12\x85\x1E\x67\x23\x67\xD1\xF4\x7D\x9F\x87\xB0\xEF\x10\x23\x61\x5E\x04"
|
||||
"\x2C\x2B\xE7\xE1\xE9\x42\x81\x26\xB8\xD0\x41\xAE\x76\x50\xA3\xF0\xF4\xA1\x01\x27"
|
||||
"\x27\x39\x4C\x86\x1B\x0F\x03\xE2\xB6\x99\xD7\xE1\x96\x1B\x3C\xFB\x07\xFF\x63\x01"
|
||||
"\x2B\x39\x60\x87\x8F\x08\x7E\x1E\x87\x65\x7C\x12\x6C\x86\x7B\x8E\xC1\xE3\xA8\xF6"
|
||||
"\x1F\x47\xD1\xF6\x7E\x1E\x82\x69\x98\x21\xE7\x74\xCD\x94\x75\xD8\x5A\x3D\xC7\x98"
|
||||
"\x6F\xA9\xFC\xF0\x63\x3A\x8E\xB1\xF7\xA3\xC2\xA8\xF3\x3D\x87\x78\xF0\xC7\x1D\xD3"
|
||||
"\xEC\x23\x90\xFB\x3B\xC7\x42\xDE\xE7\xF2\x14\x54\x43\x48\x23\xE7\x81\x7B\x90\x10"
|
||||
"\xA8\xF9\xE7\x40\x89\x3A\xCE\xA3\xE8\x43\xBC\x78\x3D\xC7\xB8\xF0\x6C\x3A\x60\xC7"
|
||||
"\xC7\x74\xFB\x21\xE2\x65\x47\xD9\xD4\x7D\x9D\x0E\xD0\xD3\xE1\xC8\x7D\x9D\xB2\xB3"
|
||||
"\xAA\xBE\x2D\x9D\xE3\xC1\xB0\xE9\xE7\xC2\x1D\xD3\xBC\x78\x30\x09\x78\xD1\xCA\x6D"
|
||||
"\xB3\xBC\x78\x3D\xC7\xB8";
|
||||
|
||||
#define HTTP_SCRIPT_ROOT Decompress(HTTP_SCRIPT_ROOT_COMPRESSED,HTTP_SCRIPT_ROOT_SIZE).c_str()
|
@ -2,32 +2,32 @@
|
||||
// compressed by tools/unishox/compress-html-uncompressed.py
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
const size_t HTTP_SCRIPT_ROOT_SIZE = 744;
|
||||
const char HTTP_SCRIPT_ROOT_COMPRESSED[] PROGMEM = "\x33\xBF\xAF\x98\xF0\xA3\xE1\xC8\x78\x23\x02\xF8\x3A\xDC\xE4\x15\x9D\xD1\x87\x78"
|
||||
"\xF6\x99\xDF\xD5\x9F\x0F\xB3\xEC\xF1\xA6\x0E\xE8\x56\x74\xBF\x8F\x0B\x1A\xFA\xBC"
|
||||
"\x74\x09\xF0\xF5\x0A\x3E\x1F\x0E\x43\xBC\x7B\x4A\xCF\x83\x0F\x01\x84\xEF\xE5\x5A"
|
||||
"\x35\xE0\xBA\x3B\xA1\x51\xDE\x3C\x1E\xED\x30\x77\x4D\x87\xF0\xF9\xC2\xC2\x08\xEF"
|
||||
"\x1E\xD3\x61\xD2\xC7\x67\xE8\xEE\x9D\xE3\xC1\xEE\x36\x1F\x39\x8F\xA2\x36\x10\xD2"
|
||||
"\x08\x85\x55\x0C\x2F\xB3\x50\xB7\xEA\x3B\xA7\x78\xF0\x6C\x3A\x67\x7D\xD8\x86\x5E"
|
||||
"\xAB\xA6\x18\xAB\xE1\xE6\x7C\x04\x3D\xA0\xEE\x9D\xE3\xDB\xA6\x0E\xE9\xB0\xE9\xF7"
|
||||
"\x62\x19\x17\xAA\xE9\x9F\x0F\x87\x30\xFD\x1F\xA2\x36\x1D\x3D\x57\x42\xFC\x7C\x3E"
|
||||
"\x1C\xA6\xC8\x10\x78\x07\xF1\xF0\xD8\x74\xFB\xF0\xCC\xEF\x32\xA6\x6C\xA3\xA7\xD8"
|
||||
"\xC0\xAC\x36\x77\x4E\xC3\xDB\x47\xB8\xEC\x1E\x3A\x8F\x61\xE9\x56\x38\x26\xBD\x46"
|
||||
"\x41\x33\xE1\xF6\x3F\xA2\x50\xA3\xCC\xE4\x6C\xFA\x3E\x8F\xB3\xF0\xF6\x1D\xE2\x04"
|
||||
"\x6C\x2B\xC0\x85\x85\x7C\xFC\x3D\x28\x50\x24\xD7\x1A\x08\x35\xCE\xCA\x14\x7E\x1E"
|
||||
"\x94\x20\x24\xE4\xE7\x29\x90\xC3\x61\xE0\x7C\x56\xD3\x3A\xFC\x32\xC3\x67\x9F\x60"
|
||||
"\xFF\xEC\x60\x25\x67\x2C\x10\xF1\xE1\x0F\xC3\xD0\xEC\xAF\x82\x4D\x90\xCF\x71\xD8"
|
||||
"\x3C\x75\x1E\xC3\xE8\xFA\x3E\xCF\xC3\xD0\x4D\x33\x04\x3C\xEE\x99\xB2\x8E\xBB\x0B"
|
||||
"\x47\xB8\xF3\x0D\xF5\x3F\x9E\x0C\x67\x51\xD6\x3E\xF4\x78\x55\x1E\x67\xB0\xEF\x1E"
|
||||
"\x18\xE3\xBA\x7D\x84\x72\x1F\x67\x78\xE8\x5B\xDC\xFE\x42\x8A\x88\x69\x04\x7C\xF1"
|
||||
"\xE0\xF7\x1E\xE3\xC6\x98\x47\x77\xE6\x3C\x28\xEF\x23\xDA\x6C\x3A\x60\xC7\xC7\x74"
|
||||
"\xFB\x21\xE2\x65\x47\xD9\xD4\x7D\x9D\x0E\xD0\xD3\xE1\xC8\x7D\x9D\xB2\xB3\xAA\xBE"
|
||||
"\x2D\x9D\xE3\xC1\xB0\xE9\xE7\xC2\x1D\xD3\xBC\x78\x0A\x8F\x9E\x74\x08\x9C\x93\xD9"
|
||||
"\xD4\x7D\x08\x77\x8F\x07\xB8\xF7\x02\x27\x2E\x9E\x66\x76\x77\x46\x5F\xCE\xAD\x33"
|
||||
"\xBF\x9D\xE3\xDA\x15\x9D\xD3\xEC\xFD\x78\xCC\xF8\x7D\x9D\xBD\x33\xBF\x9D\xB3\xEC"
|
||||
"\xFD\x9F\x67\x6C\x65\xFC\xEF\x1E\x01\x1B\x0D\xD0\x48\xC3\x41\x0B\x9C\x40\x53\xC5"
|
||||
"\x3E\x63\xC2\x8F\x87\x19\x02\x36\x36\x33\xE7\x74\xC1\xDE\x3D\xBA\x61\x1D\xD3\x07"
|
||||
"\x79\x1E\xD0\x50\xDE\x81\x0B\x2F\x3D\xC9\x85\xE6\x8F\x68\x26\x73\xD0\x08\x79\x81"
|
||||
"\xEE";
|
||||
const size_t HTTP_SCRIPT_ROOT_SIZE = 844;
|
||||
const char HTTP_SCRIPT_ROOT_COMPRESSED[] PROGMEM = "\x09\xD2\xF9\x8F\x0A\x3E\x1C\x87\x51\x18\xA3\xC1\x81\x7C\x1D\x6E\x72\x0A\xCE\xE8"
|
||||
"\xC3\xBC\x7B\x6C\xF8\x30\xFF\x1F\xE3\xEC\xFB\x3C\x06\x13\xBF\x95\x68\xD7\x82\xE8"
|
||||
"\xEE\x98\xA3\xBC\x09\x33\x42\xA3\xBC\x78\xD3\x07\x74\xD8\x7F\x0F\x9C\x2C\x20\x8E"
|
||||
"\xF1\xED\x36\x1D\x2C\x76\x7E\x8E\xE9\xDE\x3C\x1E\xE3\x61\xF3\x98\xFA\x23\x61\x0D"
|
||||
"\x20\x88\x55\x50\xC2\xFB\x35\x0B\x7E\xA3\xBA\x77\x8F\x06\xC3\xA6\x77\xDD\x88\x65"
|
||||
"\xEA\xBA\x61\x8A\xBE\x1E\x67\xC0\x43\xD6\x0E\xE9\xDE\x3D\xBA\x60\xEE\x9B\x0E\x9F"
|
||||
"\x76\x21\x91\x7A\xAE\x99\xF0\xF8\x73\x0F\xD1\xFA\x23\x61\xD3\xD5\x74\x2F\xC7\xC3"
|
||||
"\xE1\xCA\x6C\xEF\x1E\xD2\x33\xBF\xAF\x1F\x0D\x87\x4F\xBF\x0C\xCE\xF3\x2A\x2B\x66"
|
||||
"\xCA\x3A\x7D\x8C\x0A\xC3\x67\x74\xEC\x3D\xB4\x7B\x8E\xC1\xE3\xA8\xF6\x1E\x95\x63"
|
||||
"\x82\x6B\xD4\x64\x13\x3E\x1F\x63\xFA\x25\x0A\x3C\xCE\x46\xCF\xA3\xE8\xFB\x3F\x0F"
|
||||
"\x61\xDE\x20\x46\xC2\xBC\x08\x58\x57\xCF\xC3\xD2\x85\x02\x4D\x71\xA0\x83\x5C\xEC"
|
||||
"\xA1\x47\xE1\xE9\x42\x02\x4E\x4E\x72\x99\x0C\x36\x1E\x07\xC5\x6D\x33\xAF\xC3\x2C"
|
||||
"\x36\x79\xF6\x0F\xFE\xC6\x02\x56\x72\xC1\x0F\x1E\x10\xFC\x3D\x0E\xCA\xF8\x24\xD9"
|
||||
"\x0C\xF7\x1D\x83\xC7\x51\xEC\x3E\x8F\xA3\xEC\xFC\x3D\x04\xD3\x30\x43\xCE\xE9\x9B"
|
||||
"\x28\xEB\xB0\xB4\x7B\x8F\x30\xDF\x53\xF9\xE0\xC6\x75\x1D\x63\xEF\x47\x85\x51\xE6"
|
||||
"\x7B\x0E\xF1\xE1\x8E\x3B\xA7\xD8\x47\x21\xF6\x77\x8E\x85\xBD\xCF\xE4\x28\xA8\x86"
|
||||
"\x90\x47\xCF\x03\x01\xE4\x0B\xE6\x3C\x28\xEF\x1E\xD0\xA8\xF9\xE7\x40\x89\x5E\xCE"
|
||||
"\xA3\xE8\x43\xBC\x78\x3D\xC7\xB8\xF7\x02\x2D\xE3\x61\xD3\x06\x3E\x3B\xA7\xD9\x0F"
|
||||
"\x13\x2A\x2B\x3E\xCE\xA3\xEC\xE8\x76\x86\x9F\x0E\x43\xEC\xED\x95\x9D\x55\xF1\x6C"
|
||||
"\xEF\x1E\x0D\x87\x4F\x3E\x10\xEE\x9D\xE3\xC1\x80\x4B\xC9\x0E\x53\x6D\x9D\xE3\xC1"
|
||||
"\xEE\x3D\xC4\x08\x9C\xD3\x79\x99\xD9\xDD\x19\x7F\x3A\xB4\xCE\xFE\x77\x8F\x68\x56"
|
||||
"\x77\x4F\xB3\xF5\xE3\x33\xE1\xF6\x76\xF4\xCE\xFE\x76\xCF\xB3\xF6\x7D\x9D\xB1\x97"
|
||||
"\xF3\xBC\x78\x04\x6C\x37\x41\x23\x0D\x04\x1E\x7E\x4F\x2A\x01\xA7\x8A\x7C\xC7\x85"
|
||||
"\x1F\x0E\x32\x04\x6C\x6C\x67\xCE\xE9\x83\xBC\x7B\x74\xC1\xDD\x30\x77\x8F\x68\x26"
|
||||
"\x70\xBA\x09\x9C\x3F\x82\x87\x0C\xA0\x85\xA7\x9E\xE6\x17\x98\x2F\x64\x2A\x01\x87"
|
||||
"\xAF\x9E\xE3";
|
||||
|
||||
#define HTTP_SCRIPT_ROOT Decompress(HTTP_SCRIPT_ROOT_COMPRESSED,HTTP_SCRIPT_ROOT_SIZE).c_str()
|
@ -1,49 +1,54 @@
|
||||
const char HTTP_SCRIPT_CONSOL[] PROGMEM =
|
||||
"var sn=0,id=0;" // Scroll position, Get most of weblog initially
|
||||
"function l(p){" // Console log and command service
|
||||
"var c,o='',t;"
|
||||
"clearTimeout(lt);"
|
||||
"t=eb('t1');"
|
||||
"if(p==1){"
|
||||
"c=eb('c1');" // Console command id
|
||||
"o='&c1='+encodeURIComponent(c.value);"
|
||||
"c.value='';"
|
||||
"t.scrollTop=99999;"
|
||||
"sn=t.scrollTop;"
|
||||
"{"
|
||||
"let sn=0,id=0,ft;" // Scroll position, Get most of weblog initially
|
||||
"function l(p){" // Console log and command service
|
||||
"let c,o='';"
|
||||
"clearTimeout(lt);"
|
||||
"clearTimeout(ft);"
|
||||
"t=eb('t1');"
|
||||
"if(p==1){"
|
||||
"c=eb('c1');" // Console command id
|
||||
"o='&c1='+encodeURIComponent(c.value);"
|
||||
"c.value='';"
|
||||
"t.scrollTop=99999;"
|
||||
"sn=t.scrollTop;"
|
||||
"}"
|
||||
"if(t.scrollTop>=sn){" // User scrolled back so no updates
|
||||
"if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1)
|
||||
"x=new XMLHttpRequest();"
|
||||
"x.onreadystatechange=function(){"
|
||||
"if(x.readyState==4&&x.status==200){"
|
||||
"let z,d;"
|
||||
"d=x.responseText.split(/}1/);" // Field separator
|
||||
"id=d.shift();"
|
||||
"if(d.shift()==0){t.value='';}"
|
||||
"z=d.shift();"
|
||||
"if(z.length>0){t.value+=z;}"
|
||||
"t.scrollTop=99999;"
|
||||
"sn=t.scrollTop;"
|
||||
"clearTimeout(ft);"
|
||||
"lt=setTimeout(l,%d);" // webrefresh timer....
|
||||
"}"
|
||||
"};"
|
||||
"x.open('GET','cs?c2='+id+o,true);" // Related to Webserver->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp))
|
||||
"x.send();"
|
||||
"ft=setTimeout(l,20000);" // fail timeout, triggered 20s after asking for XHR
|
||||
"}"
|
||||
"return false;"
|
||||
"}"
|
||||
"if(t.scrollTop>=sn){" // User scrolled back so no updates
|
||||
"if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1)
|
||||
"x=new XMLHttpRequest();"
|
||||
"x.onreadystatechange=function(){"
|
||||
"if(x.readyState==4&&x.status==200){"
|
||||
"var z,d;"
|
||||
"d=x.responseText.split(/}1/);" // Field separator
|
||||
"id=d.shift();"
|
||||
"if(d.shift()==0){t.value='';}"
|
||||
"z=d.shift();"
|
||||
"if(z.length>0){t.value+=z;}"
|
||||
"t.scrollTop=99999;"
|
||||
"sn=t.scrollTop;"
|
||||
"}"
|
||||
"};"
|
||||
"x.open('GET','cs?c2='+id+o,true);" // Related to Webserver->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp))
|
||||
"x.send();"
|
||||
"}"
|
||||
"lt=setTimeout(l,%d);"
|
||||
"return false;"
|
||||
"}"
|
||||
"wl(l);" // Load initial console text
|
||||
"wl(l);" // Load initial console text
|
||||
|
||||
// Console command history
|
||||
"var hc=[],cn=0;" // hc = History commands, cn = Number of history being shown
|
||||
"function h(){"
|
||||
// "if(!(navigator.maxTouchPoints||'ontouchstart'in document.documentElement)){eb('c1').autocomplete='off';}" // No touch so stop browser autocomplete
|
||||
"eb('c1').addEventListener('keydown',function(e){"
|
||||
"var b=eb('c1'),c=e.keyCode;" // c1 = Console command id
|
||||
"if(38==c||40==c){b.autocomplete='off';}" // ArrowUp or ArrowDown must be a keyboard so stop browser autocomplete
|
||||
"38==c?(++cn>hc.length&&(cn=hc.length),b.value=hc[cn-1]||''):" // ArrowUp
|
||||
"40==c?(0>--cn&&(cn=0),b.value=hc[cn-1]||''):" // ArrowDown
|
||||
"13==c&&(hc.length>19&&hc.pop(),hc.unshift(b.value),cn=0)" // Enter, 19 = Max number -1 of commands in history
|
||||
"});"
|
||||
"}"
|
||||
"wl(h);"; // Add console command key eventlistener after name has been synced with id (= wl(jd))
|
||||
// Console command history
|
||||
"let hc=[],cn=0;" // hc = History commands, cn = Number of history being shown
|
||||
"function h(){"
|
||||
// "if(!(navigator.maxTouchPoints||'ontouchstart'in document.documentElement)){eb('c1').autocomplete='off';}" // No touch so stop browser autocomplete
|
||||
"eb('c1').addEventListener('keydown',function(e){"
|
||||
"let b=eb('c1'),c=e.keyCode;" // c1 = Console command id
|
||||
"if(38==c||40==c){b.autocomplete='off';}" // ArrowUp or ArrowDown must be a keyboard so stop browser autocomplete
|
||||
"38==c?(++cn>hc.length&&(cn=hc.length),b.value=hc[cn-1]||''):" // ArrowUp
|
||||
"40==c?(0>--cn&&(cn=0),b.value=hc[cn-1]||''):" // ArrowDown
|
||||
"13==c&&(hc.length>19&&hc.pop(),hc.unshift(b.value),cn=0)" // Enter, 19 = Max number -1 of commands in history
|
||||
"});"
|
||||
"}"
|
||||
"wl(h);" // Add console command key eventlistener after name has been synced with id (= wl(jd))
|
||||
"}";
|
||||
|
@ -1,11 +1,9 @@
|
||||
const char HTTP_SCRIPT_ROOT[] PROGMEM =
|
||||
"{let ft;"
|
||||
"function la(p){"
|
||||
"var a='';"
|
||||
"if(la.arguments.length==1){"
|
||||
"a=p;"
|
||||
"clearTimeout(lt);"
|
||||
"}"
|
||||
"if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1)
|
||||
"a=p||'';"
|
||||
"clearTimeout(ft);clearTimeout(lt);"
|
||||
"if(x!=null){x.abort()}" // Abort if no response within 2 seconds (happens on restart 1)
|
||||
"x=new XMLHttpRequest();"
|
||||
"x.onreadystatechange=function(){"
|
||||
"if(x.readyState==4&&x.status==200){"
|
||||
@ -16,9 +14,11 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM =
|
||||
".replace(/{e}/g,\"</td></tr>\")"
|
||||
".replace(/{c}/g,\"%%'><div style='text-align:center;font-weight:\");"
|
||||
"eb('l1').innerHTML=s;"
|
||||
"clearTimeout(ft);clearTimeout(lt);"
|
||||
"lt=setTimeout(la,%d);" // Settings.web_refresh
|
||||
"}"
|
||||
"};"
|
||||
"x.open('GET','.?m=1'+a,true);" // ?m related to Webserver->hasArg("m")
|
||||
"x.send();"
|
||||
"lt=setTimeout(la,%d);" // Settings.web_refresh
|
||||
"}";
|
||||
"ft=setTimeout(la,20000);" // 20s failure timeout
|
||||
"}}";
|
||||
|
@ -1,11 +1,8 @@
|
||||
const char HTTP_SCRIPT_ROOT[] PROGMEM =
|
||||
"var rfsh=1;"
|
||||
"let rfsh=1,ft;"
|
||||
"function la(p){"
|
||||
"var a='';"
|
||||
"if(la.arguments.length==1){"
|
||||
"a=p;"
|
||||
"clearTimeout(lt);"
|
||||
"}"
|
||||
"a=p||'';"
|
||||
"clearTimeout(ft);clearTimeout(lt);"
|
||||
"if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1)
|
||||
"x=new XMLHttpRequest();"
|
||||
"x.onreadystatechange=function(){"
|
||||
@ -17,12 +14,16 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM =
|
||||
".replace(/{e}/g,\"</td></tr>\")"
|
||||
".replace(/{c}/g,\"%%'><div style='text-align:center;font-weight:\");"
|
||||
"eb('l1').innerHTML=s;"
|
||||
"clearTimeout(ft);clearTimeout(lt);"
|
||||
"if(rfsh){"
|
||||
"lt=setTimeout(la,%d);" // Settings.web_refresh
|
||||
"}"
|
||||
"}"
|
||||
"};"
|
||||
"if (rfsh) {"
|
||||
"if(rfsh){"
|
||||
"x.open('GET','.?m=1'+a,true);" // ?m related to Webserver->hasArg("m")
|
||||
"x.send();"
|
||||
"lt=setTimeout(la,%d);" // Settings.web_refresh
|
||||
"ft=setTimeout(la,20000);" // 20s failure timeout
|
||||
"}"
|
||||
"}"
|
||||
"function seva(par,ivar){"
|
||||
@ -34,11 +35,13 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM =
|
||||
"rfsh=0;"
|
||||
"}"
|
||||
"function pr(f){"
|
||||
"if (f) {"
|
||||
"if(f){"
|
||||
"clearTimeout(lt);clearTimeout(ft);"
|
||||
"lt=setTimeout(la,%d);"
|
||||
"rfsh=1;"
|
||||
"} else {"
|
||||
"clearTimeout(lt);"
|
||||
"}else{"
|
||||
"clearTimeout(lt);clearTimeout(ft);"
|
||||
"rfsh=0;"
|
||||
"}"
|
||||
"}";
|
||||
"}"
|
||||
;
|
||||
|
@ -425,6 +425,8 @@
|
||||
#define D_CMND_DIMMER_RANGE "DimmerRange"
|
||||
#define D_CMND_DIMMER_STEP "DimmerStep"
|
||||
#define D_CMND_HSBCOLOR "HSBColor"
|
||||
#define D_CMND_VIRTUALCT "VirtualCT"
|
||||
#define D_CMND_CTRANGE "CTRange"
|
||||
#define D_CMND_LED "Led"
|
||||
#define D_CMND_LEDTABLE "LedTable"
|
||||
#define D_CMND_FADE "Fade"
|
||||
|
@ -309,6 +309,7 @@
|
||||
#define LIGHT_WHITE_BLEND_MODE false // [SetOption105] White Blend Mode - used to be `RGBWWTable` last value `0`, now deprecated in favor of this option
|
||||
#define LIGHT_VIRTUAL_CT false // [SetOption106] Virtual CT - Creates a virtual White ColorTemp for RGBW lights
|
||||
#define LIGHT_VIRTUAL_CT_CW false // [SetOption107] Virtual CT Channel - signals whether the hardware white is cold CW (true) or warm WW (false)
|
||||
#define LIGHT_VIRTUAL_CT_POINTS 3 // Number of reference points for Virtual CT (min 2, default 3)
|
||||
|
||||
// -- Energy --------------------------------------
|
||||
#define ENERGY_VOLTAGE_ALWAYS false // [SetOption21] Enable show voltage even if powered off
|
||||
@ -494,6 +495,7 @@
|
||||
#define USE_SONOFF_L1 // Add support for Sonoff L1 led control
|
||||
#define USE_ELECTRIQ_MOODL // Add support for ElectriQ iQ-wifiMOODL RGBW LED controller (+0k3 code)
|
||||
#define USE_LIGHT_PALETTE // Add support for color palette (+0k7 code)
|
||||
#define USE_LIGHT_VIRTUAL_CT // Add support for Virtual White Color Temperature (+1.1k code)
|
||||
#define USE_DGR_LIGHT_SEQUENCE // Add support for device group light sequencing (requires USE_DEVICE_GROUPS) (+0k2 code)
|
||||
|
||||
// -- Counter input -------------------------------
|
||||
|
@ -941,6 +941,11 @@ void CmndSetoption(void)
|
||||
else if (4 == ptype) { // SetOption82 .. 113
|
||||
bitWrite(Settings.flag4.data, pindex, XdrvMailbox.payload);
|
||||
switch (pindex) {
|
||||
#ifdef USE_LIGHT
|
||||
case 0: // SetOption 82 - (Alexa) Reduced CT range for Alexa (1)
|
||||
setAlexaCTRange();
|
||||
break;
|
||||
#endif
|
||||
case 3: // SetOption85 - Enable Device Groups
|
||||
case 6: // SetOption88 - PWM Dimmer Buttons control remote devices
|
||||
case 15: // SetOption97 - Set Baud rate for TuyaMCU serial communication (0 = 9600 or 1 = 115200)
|
||||
|
@ -508,6 +508,7 @@
|
||||
|
||||
// -- Optional light modules ----------------------
|
||||
//#undef USE_LIGHT // Enable Dimmer/Light support
|
||||
#undef USE_LIGHT_VIRTUAL_CT // Disable support for Virtual White Color Temperature (SO106)
|
||||
#undef USE_WS2812 // Disable WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
|
||||
#undef USE_MY92X1 // Disable support for MY92X1 RGBCW led controller as used in Sonoff B1, Ailight and Lohas
|
||||
#undef USE_SM16716 // Disable support for SM16716 RGB LED controller (+0k7 code)
|
||||
@ -643,6 +644,7 @@
|
||||
//#undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code)
|
||||
|
||||
// -- Optional light modules ----------------------
|
||||
#undef USE_LIGHT_VIRTUAL_CT // Disable support for Virtual White Color Temperature (SO106)
|
||||
//#undef USE_LIGHT // Also disable all Dimmer/Light support
|
||||
#undef USE_WS2812 // Disable WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
|
||||
#undef USE_MY92X1 // Disable support for MY92X1 RGBCW led controller as used in Sonoff B1, Ailight and Lohas
|
||||
|
@ -132,6 +132,10 @@ const char kLightCommands[] PROGMEM = "|" // No prefix
|
||||
D_CMND_COLOR "|" D_CMND_COLORTEMPERATURE "|" D_CMND_DIMMER "|" D_CMND_DIMMER_RANGE "|" D_CMND_DIMMER_STEP "|" D_CMND_LEDTABLE "|" D_CMND_FADE "|"
|
||||
D_CMND_RGBWWTABLE "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|"
|
||||
D_CMND_WHITE "|" D_CMND_CHANNEL "|" D_CMND_HSBCOLOR
|
||||
"|" D_CMND_CTRANGE
|
||||
#ifdef USE_LIGHT_VIRTUAL_CT
|
||||
"|" D_CMND_VIRTUALCT
|
||||
#endif // USE_LIGHT_VIRTUAL_CT
|
||||
#ifdef USE_LIGHT_PALETTE
|
||||
"|" D_CMND_PALETTE
|
||||
#endif // USE_LIGHT_PALETTE
|
||||
@ -144,6 +148,10 @@ void (* const LightCommand[])(void) PROGMEM = {
|
||||
&CmndColor, &CmndColorTemperature, &CmndDimmer, &CmndDimmerRange, &CmndDimmerStep, &CmndLedTable, &CmndFade,
|
||||
&CmndRgbwwTable, &CmndScheme, &CmndSpeed, &CmndWakeup, &CmndWakeupDuration,
|
||||
&CmndWhite, &CmndChannel, &CmndHsbColor,
|
||||
&CmndCTRange,
|
||||
#ifdef USE_LIGHT_VIRTUAL_CT
|
||||
&CmndVirtualCT,
|
||||
#endif // USE_LIGHT_VIRTUAL_CT
|
||||
#ifdef USE_LIGHT_PALETTE
|
||||
&CmndPalette,
|
||||
#endif // USE_LIGHT_PALETTE
|
||||
@ -181,6 +189,12 @@ const uint16_t CT_MAX = 500; // 2000K
|
||||
// Ranges used for Alexa
|
||||
const uint16_t CT_MIN_ALEXA = 200; // also 5000K
|
||||
const uint16_t CT_MAX_ALEXA = 380; // also 2600K
|
||||
// Virtual CT default values
|
||||
typedef uint8_t vct_pivot_t[LST_MAX];
|
||||
const size_t CT_PIVOTS = LIGHT_VIRTUAL_CT_POINTS;
|
||||
const vct_pivot_t CT_PIVOTS_RGB PROGMEM = { 255, 255, 255, 0, 0 };
|
||||
const vct_pivot_t CT_PIVOTS_CWW PROGMEM = { 0, 0, 0, 255, 0 };
|
||||
const vct_pivot_t CT_PIVOTS_WWW PROGMEM = { 0, 0, 0, 0, 255 };
|
||||
|
||||
// New version of Gamma correction compute
|
||||
// Instead of a table, we do a multi-linear approximation, which is close enough
|
||||
@ -308,6 +322,12 @@ struct LIGHT {
|
||||
|
||||
uint16_t pwm_min = 0; // minimum value for PWM, from DimmerRange, 0..1023
|
||||
uint16_t pwm_max = 1023; // maxumum value for PWM, from DimmerRange, 0..1023
|
||||
|
||||
// Virtual CT
|
||||
uint16_t vct_ct[CT_PIVOTS]; // CT value for each segment
|
||||
#ifdef USE_LIGHT_VIRTUAL_CT
|
||||
vct_pivot_t vct_color[CT_PIVOTS]; // array of 3 colors each with 5 values
|
||||
#endif
|
||||
} Light;
|
||||
|
||||
power_t LightPower(void)
|
||||
@ -378,13 +398,6 @@ class LightStateClass {
|
||||
uint8_t _briCT = 255;
|
||||
|
||||
uint8_t _color_mode = LCM_RGB; // RGB by default
|
||||
// the CT range below represents the rendered range,
|
||||
// This is due to Alexa whose CT range is 199..383
|
||||
// Hence setting Min=200 and Max=380 makes Alexa use the full range
|
||||
// Please note that you can still set CT to 153..500, but any
|
||||
// value below _ct_min_range or above _ct_max_range not change the CT
|
||||
uint16_t _ct_min_range = CT_MIN; // the minimum CT rendered range
|
||||
uint16_t _ct_max_range = CT_MAX; // the maximum CT rendered range
|
||||
|
||||
public:
|
||||
LightStateClass() {
|
||||
@ -535,22 +548,7 @@ class LightStateClass {
|
||||
|
||||
inline uint16_t getCT() const {
|
||||
return _ct; // 153..500, or CT_MIN..CT_MAX
|
||||
}
|
||||
|
||||
// get the CT value within the range into a 10 bits 0..1023 value
|
||||
uint16_t getCT10bits() const {
|
||||
return changeUIntScale(_ct, _ct_min_range, _ct_max_range, 0, 1023);
|
||||
}
|
||||
|
||||
inline void setCTRange(uint16_t ct_min_range, uint16_t ct_max_range) {
|
||||
_ct_min_range = ct_min_range;
|
||||
_ct_max_range = ct_max_range;
|
||||
}
|
||||
|
||||
inline void getCTRange(uint16_t *ct_min_range, uint16_t *ct_max_range) const {
|
||||
if (ct_min_range) { *ct_min_range = _ct_min_range; }
|
||||
if (ct_max_range) { *ct_max_range = _ct_max_range; }
|
||||
}
|
||||
}
|
||||
|
||||
// get current color in XY format
|
||||
void getXY(float *x, float *y) {
|
||||
@ -603,7 +601,7 @@ class LightStateClass {
|
||||
setColorMode(LCM_RGB); // try deactivating CT mode, setColorMode() will check which is legal
|
||||
} else {
|
||||
ct = (ct < CT_MIN ? CT_MIN : (ct > CT_MAX ? CT_MAX : ct));
|
||||
_ww = changeUIntScale(ct, _ct_min_range, _ct_max_range, 0, 255);
|
||||
_ww = changeUIntScale(ct, Light.vct_ct[0], Light.vct_ct[CT_PIVOTS-1], 0, 255);
|
||||
_wc = 255 - _ww;
|
||||
_ct = ct;
|
||||
addCTMode();
|
||||
@ -932,15 +930,6 @@ public:
|
||||
return prev;
|
||||
}
|
||||
|
||||
void setAlexaCTRange(bool alexa_ct_range) {
|
||||
// depending on SetOption82, full or limited CT range
|
||||
if (alexa_ct_range) {
|
||||
_state->setCTRange(CT_MIN_ALEXA, CT_MAX_ALEXA); // 200..380
|
||||
} else {
|
||||
_state->setCTRange(CT_MIN, CT_MAX); // 153..500
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isCTRGBLinked() {
|
||||
return _ct_rgb_linked;
|
||||
}
|
||||
@ -1190,6 +1179,68 @@ uint8_t change10to8(uint16_t v) {
|
||||
return (0 == v) ? 0 : changeUIntScale(v, 4, 1023, 1, 255);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* CT (White Color Temperature)
|
||||
\*********************************************************************************************/
|
||||
//
|
||||
// Ensure that invariants for Virtual CT are good:
|
||||
// - CT_MIN <= ct[0] <= ct[1] <= ct[2] <= CT_MAX
|
||||
|
||||
#ifdef USE_LIGHT_VIRTUAL_CT
|
||||
void checkVirtualCT(void) {
|
||||
if (Light.vct_ct[0] < CT_MIN) { Light.vct_ct[0] = CT_MIN; }
|
||||
if (Light.vct_ct[CT_PIVOTS-1] > CT_MAX) { Light.vct_ct[CT_PIVOTS-1] = CT_MAX; }
|
||||
for (uint32_t i = 0; i < CT_PIVOTS-1; i++) {
|
||||
if (Light.vct_ct[i+1] < Light.vct_ct[i]) { Light.vct_ct[i+1] = Light.vct_ct[i]; }
|
||||
}
|
||||
}
|
||||
#endif // USE_LIGHT_VIRTUAL_CT
|
||||
|
||||
#ifdef USE_LIGHT_VIRTUAL_CT
|
||||
// Init default values for virtual CT, depending on the number of channels
|
||||
void initCTRange(uint32_t channels) {
|
||||
if (channels == 4) {
|
||||
if (Settings.flag4.virtual_ct_cw) { // Hardware White is Cold White
|
||||
memcpy_P(Light.vct_color[0], CT_PIVOTS_CWW, sizeof(Light.vct_color[0])); // Cold white
|
||||
memcpy_P(Light.vct_color[1], CT_PIVOTS_RGB, sizeof(Light.vct_color[1])); // Warm white
|
||||
} else { // Hardware White is Warm White
|
||||
memcpy_P(Light.vct_color[0], CT_PIVOTS_RGB, sizeof(Light.vct_color[0])); // Cold white
|
||||
memcpy_P(Light.vct_color[1], CT_PIVOTS_CWW, sizeof(Light.vct_color[1])); // Warm white
|
||||
}
|
||||
} else if (channels == 5) {
|
||||
memcpy_P(Light.vct_color[0], CT_PIVOTS_CWW, sizeof(Light.vct_color[0])); // Cold white
|
||||
memcpy_P(Light.vct_color[1], CT_PIVOTS_WWW, sizeof(Light.vct_color[1])); // Warm white
|
||||
} else {
|
||||
memcpy_P(Light.vct_color[0], CT_PIVOTS_RGB, sizeof(Light.vct_color[0])); // Cold white
|
||||
memcpy_P(Light.vct_color[1], CT_PIVOTS_RGB, sizeof(Light.vct_color[1])); // Warm white
|
||||
}
|
||||
for (uint32_t i = 1; i < CT_PIVOTS-1; i++) {
|
||||
memcpy_P(Light.vct_color[i+1], Light.vct_color[i], sizeof(Light.vct_color[0])); // Copy slot 1 into slot 2 (slot 2 in unused)
|
||||
}
|
||||
checkVirtualCT();
|
||||
}
|
||||
#endif // USE_LIGHT_VIRTUAL_CT
|
||||
|
||||
void getCTRange(uint16_t * min_ct, uint16_t * max_ct) {
|
||||
if (min_ct != nullptr) { *min_ct = Light.vct_ct[0]; }
|
||||
if (max_ct != nullptr) { *max_ct = Light.vct_ct[CT_PIVOTS-1]; }
|
||||
}
|
||||
|
||||
void setCTRange(uint16_t ct_min, uint16_t ct_max) {
|
||||
Light.vct_ct[0] = ct_min;
|
||||
for (uint32_t i = 1; i < CT_PIVOTS; i++) {
|
||||
Light.vct_ct[i] = ct_max; // all slots above [1] are not used
|
||||
}
|
||||
}
|
||||
|
||||
void setAlexaCTRange(void) { // depending on SetOption82, full or limited CT range
|
||||
if (Settings.flag4.alexa_ct_range) {
|
||||
setCTRange(CT_MIN_ALEXA, CT_MAX_ALEXA);
|
||||
} else {
|
||||
setCTRange(CT_MIN, CT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Gamma correction
|
||||
\*********************************************************************************************/
|
||||
@ -1299,9 +1350,14 @@ bool LightModuleInit(void)
|
||||
} else if ((Settings.param[P_RGB_REMAP] & 128) && (LST_RGBW <= pwm_channels)) { // SetOption37
|
||||
// if RGBW or RGBCW, and SetOption37 >= 128, we manage RGB and W separately, hence adding a device
|
||||
TasmotaGlobal.devices_present++;
|
||||
} else if ((Settings.flag4.virtual_ct) && (LST_RGBW == pwm_channels)) {
|
||||
Light.virtual_ct = true; // enabled
|
||||
TasmotaGlobal.light_type++; // create an additional virtual 5th channel
|
||||
} else {
|
||||
#ifdef USE_LIGHT_VIRTUAL_CT
|
||||
initCTRange(pwm_channels);
|
||||
if ((Settings.flag4.virtual_ct) && (LST_RGB <= pwm_channels)) {
|
||||
Light.virtual_ct = true; // enabled
|
||||
TasmotaGlobal.light_type += 5 - pwm_channels; // pretend it is a 5 channels bulb
|
||||
}
|
||||
#endif // USE_LIGHT_VIRTUAL_CT
|
||||
}
|
||||
|
||||
return (TasmotaGlobal.light_type > LT_BASIC);
|
||||
@ -1367,7 +1423,7 @@ void LightInit(void)
|
||||
|
||||
light_controller.setSubType(Light.subtype);
|
||||
light_controller.loadSettings();
|
||||
light_controller.setAlexaCTRange(Settings.flag4.alexa_ct_range);
|
||||
setAlexaCTRange();
|
||||
light_controller.calcLevels(); // calculate the initial values (#8058)
|
||||
|
||||
if (LST_SINGLE == Light.subtype) {
|
||||
@ -1859,7 +1915,6 @@ void LightAnimate(void)
|
||||
bool power_off = false;
|
||||
|
||||
// make sure we update CT range in case SetOption82 was changed
|
||||
light_controller.setAlexaCTRange(Settings.flag4.alexa_ct_range);
|
||||
Light.strip_timer_counter++;
|
||||
|
||||
// set sleep parameter: either settings,
|
||||
@ -1966,7 +2021,6 @@ void LightAnimate(void)
|
||||
|
||||
uint16_t cur_col_10[LST_MAX]; // 10 bits resolution
|
||||
Light.update = false;
|
||||
bool rgbwwtable_applied = false; // did we already applied RGBWWTable (ex: in white_blend_mode or virtual_ct)
|
||||
|
||||
// first set 8 and 10 bits channels
|
||||
for (uint32_t i = 0; i < LST_MAX; i++) {
|
||||
@ -1975,58 +2029,19 @@ void LightAnimate(void)
|
||||
cur_col_10[i] = change8to10(Light.new_color[i]);
|
||||
}
|
||||
|
||||
bool rgbwwtable_applied_white = false; // did we already applied RGBWWTable to white channels (ex: in white_blend_mode or virtual_ct)
|
||||
if (Light.pwm_multi_channels) {
|
||||
calcGammaMultiChannels(cur_col_10);
|
||||
} else {
|
||||
calcGammaBulbs(cur_col_10);
|
||||
|
||||
// Now see if we need to mix RGB and True White
|
||||
// Valid only for LST_RGBW, LST_RGBCW, rgbwwTable[4] is zero, and white is zero (see doc)
|
||||
if ((LST_RGBW <= Light.subtype) && (Settings.flag4.white_blend_mode) && (0 == cur_col_10[3]+cur_col_10[4])) {
|
||||
uint32_t min_rgb_10 = min3(cur_col_10[0], cur_col_10[1], cur_col_10[2]);
|
||||
for (uint32_t i=0; i<3; i++) {
|
||||
// substract white and adjust according to rgbwwTable
|
||||
uint32_t adjust10 = change8to10(Settings.rgbwwTable[i]);
|
||||
cur_col_10[i] = changeUIntScale(cur_col_10[i] - min_rgb_10, 0, 1023, 0, adjust10);
|
||||
}
|
||||
|
||||
// compute the adjusted white levels for 10 and 8 bits
|
||||
uint32_t adjust_w_10 = changeUIntScale(Settings.rgbwwTable[3], 0, 255, 0, 1023);
|
||||
uint32_t white_10 = changeUIntScale(min_rgb_10, 0, 1023, 0, adjust_w_10); // set white power down corrected with rgbwwTable[3]
|
||||
if (LST_RGBW == Light.subtype) {
|
||||
// we simply set the white channel
|
||||
cur_col_10[3] = white_10;
|
||||
} else { // LST_RGBCW
|
||||
// we distribute white between cold and warm according to CT value
|
||||
uint32_t ct = light_state.getCT10bits();
|
||||
cur_col_10[4] = changeUIntScale(ct, 0, 1023, 0, white_10);
|
||||
cur_col_10[3] = white_10 - cur_col_10[4];
|
||||
}
|
||||
rgbwwtable_applied = true;
|
||||
} else if ((Light.virtual_ct) && (0 == cur_col_10[0]+cur_col_10[1]+cur_col_10[2])) {
|
||||
// virtual_ct is on and we don't have any RGB set
|
||||
uint16_t sw_white = Settings.flag4.virtual_ct_cw ? cur_col_10[4] : cur_col_10[3]; // white power for virtual RGB
|
||||
uint16_t hw_white = Settings.flag4.virtual_ct_cw ? cur_col_10[3] : cur_col_10[4]; // white for hardware LED
|
||||
uint32_t adjust_sw = change8to10(Settings.flag4.virtual_ct_cw ? Settings.rgbwwTable[4] : Settings.rgbwwTable[3]);
|
||||
uint32_t adjust_hw = change8to10(Settings.flag4.virtual_ct_cw ? Settings.rgbwwTable[3] : Settings.rgbwwTable[4]);
|
||||
// set the target channels. Note: Gamma correction was arleady applied
|
||||
cur_col_10[3] = changeUIntScale(hw_white, 0, 1023, 0, adjust_hw);
|
||||
cur_col_10[4] = 0; // we don't actually have a 5the channel
|
||||
sw_white = changeUIntScale(sw_white, 0, 1023, 0, adjust_sw); // pre-adjust virtual channel
|
||||
for (uint32_t i=0; i<3; i++) {
|
||||
uint32_t adjust = change8to10(Settings.rgbwwTable[i]);
|
||||
cur_col_10[i] = changeUIntScale(sw_white, 0, 1023, 0, adjust);
|
||||
}
|
||||
rgbwwtable_applied = true;
|
||||
}
|
||||
// AddLog_P(LOG_LEVEL_INFO, PSTR(">>> calcGammaBulbs In %03X,%03X,%03X,%03X,%03X"), cur_col_10[0], cur_col_10[1], cur_col_10[2], cur_col_10[3], cur_col_10[4]);
|
||||
rgbwwtable_applied_white = calcGammaBulbs(cur_col_10); // true means that one PWM channel is used for CT
|
||||
// AddLog_P(LOG_LEVEL_INFO, PSTR(">>> calcGammaBulbs Out %03X,%03X,%03X,%03X,%03X"), cur_col_10[0], cur_col_10[1], cur_col_10[2], cur_col_10[3], cur_col_10[4]);
|
||||
}
|
||||
|
||||
// Apply RGBWWTable only if not Settings.flag4.white_blend_mode
|
||||
if (!rgbwwtable_applied) {
|
||||
for (uint32_t i = 0; i<Light.subtype; i++) {
|
||||
uint32_t adjust = change8to10(Settings.rgbwwTable[i]);
|
||||
cur_col_10[i] = changeUIntScale(cur_col_10[i], 0, 1023, 0, adjust);
|
||||
}
|
||||
for (uint32_t i = 0; i < (rgbwwtable_applied_white ? 3 : Light.subtype); i++) {
|
||||
uint32_t adjust = change8to10(Settings.rgbwwTable[i]);
|
||||
cur_col_10[i] = changeUIntScale(cur_col_10[i], 0, 1023, 0, adjust);
|
||||
}
|
||||
|
||||
// final adjusments for PMW ranges, post-gamma correction
|
||||
@ -2272,56 +2287,170 @@ void calcGammaMultiChannels(uint16_t cur_col_10[5]) {
|
||||
}
|
||||
}
|
||||
|
||||
void calcGammaBulbs(uint16_t cur_col_10[5]) {
|
||||
// Apply gamma correction for 8 and 10 bits resolutions, if needed
|
||||
|
||||
// First apply combined correction to the overall white power
|
||||
if ((LST_COLDWARM == Light.subtype) || (LST_RGBCW == Light.subtype)) {
|
||||
// channels for white are always the last two channels
|
||||
uint32_t cw1 = Light.subtype - 1; // address for the ColorTone PWM
|
||||
uint32_t cw0 = Light.subtype - 2; // address for the White Brightness PWM
|
||||
uint16_t white_bri10 = cur_col_10[cw0] + cur_col_10[cw1]; // cumulated brightness
|
||||
uint16_t white_bri10_1023 = (white_bri10 > 1023) ? 1023 : white_bri10; // max 1023
|
||||
|
||||
#ifdef ESP8266
|
||||
if ((PHILIPS == TasmotaGlobal.module_type) || (Settings.flag4.pwm_ct_mode)) { // channel 1 is the color tone, mapped to cold channel (0..255)
|
||||
// Xiaomi Philips bulbs follow a different scheme:
|
||||
cur_col_10[cw1] = light_state.getCT10bits();
|
||||
// channel 0=intensity, channel1=temperature
|
||||
if (Settings.light_correction) { // gamma correction
|
||||
cur_col_10[cw0] = ledGamma10_10(white_bri10_1023); // 10 bits gamma correction
|
||||
} else {
|
||||
cur_col_10[cw0] = white_bri10_1023; // no gamma, extend to 10 bits
|
||||
}
|
||||
} else
|
||||
#endif // ESP8266
|
||||
if (Settings.light_correction) {
|
||||
// if sum of both channels is > 255, then channels are probably uncorrelated
|
||||
if (white_bri10 <= 1031) { // take a margin of 8 above 1023 to account for rounding errors
|
||||
// we calculate the gamma corrected sum of CW + WW
|
||||
uint16_t white_bri_gamma10 = ledGamma10_10(white_bri10_1023);
|
||||
// then we split the total energy among the cold and warm leds
|
||||
cur_col_10[cw0] = changeUIntScale(cur_col_10[cw0], 0, white_bri10_1023, 0, white_bri_gamma10);
|
||||
cur_col_10[cw1] = changeUIntScale(cur_col_10[cw1], 0, white_bri10_1023, 0, white_bri_gamma10);
|
||||
} else {
|
||||
cur_col_10[cw0] = ledGamma10_10(cur_col_10[cw0]);
|
||||
cur_col_10[cw1] = ledGamma10_10(cur_col_10[cw1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// Compute the Gamma correction for CW/WW
|
||||
// Can be used for 2-channels (channels 0,1) or 5 channels (channels 3,4)
|
||||
//
|
||||
// It is implicitly called by calcGammaBulb5Channels()
|
||||
//
|
||||
// In:
|
||||
// - 2 channels CW/WW in 10 bits format (0..1023)
|
||||
// Out:
|
||||
// - 2 channels CW/WW in 10 bits format, with Gamma corretion (if enabled), replaced in place
|
||||
// - white_bri10: global brightness of white channel, split over CW/WW (basically the sum of CW+WW, but it's easier to compute on this basis)
|
||||
// - white_free_cw: signals that CW/WW are free mode, and not linked via CT. This is used when channels are manually set on a channel per channel basis. CT is ignored
|
||||
//
|
||||
void calcGammaBulbCW(uint16_t cw10[2], uint16_t *white_bri10_out, bool *white_free_cw_out) {
|
||||
uint16_t white_bri10 = cw10[0] + cw10[1]; // cumulated brightness
|
||||
bool white_free_cw = (white_bri10 > 1031); // take a margin of 8 above 1023 to account for rounding errors
|
||||
white_bri10 = (white_bri10 > 1023) ? 1023 : white_bri10; // max 1023
|
||||
|
||||
if (Settings.light_correction) {
|
||||
// then apply gamma correction to RGB channels
|
||||
if (LST_RGB <= Light.subtype) {
|
||||
for (uint32_t i = 0; i < 3; i++) {
|
||||
cur_col_10[i] = ledGamma10_10(cur_col_10[i]);
|
||||
}
|
||||
}
|
||||
// If RGBW or Single channel, also adjust White channel
|
||||
if ((LST_SINGLE == Light.subtype) || (LST_RGBW == Light.subtype)) {
|
||||
cur_col_10[Light.subtype - 1] = ledGamma10_10(cur_col_10[Light.subtype - 1]);
|
||||
if (white_free_cw) {
|
||||
cw10[0] = ledGamma10_10(cw10[0]);
|
||||
cw10[1] = ledGamma10_10(cw10[1]);
|
||||
} else {
|
||||
uint16_t white_bri10_gamma = ledGamma10_10(white_bri10); // gamma corrected white
|
||||
// now distributed among both channels
|
||||
cw10[0] = changeUIntScale(cw10[0], 0, white_bri10, 0, white_bri10_gamma);
|
||||
cw10[1] = changeUIntScale(cw10[1], 0, white_bri10, 0, white_bri10_gamma);
|
||||
// now use white_bri10_gamma as a reference
|
||||
white_bri10 = white_bri10_gamma;
|
||||
}
|
||||
}
|
||||
if (white_bri10_out != nullptr) { *white_bri10_out = white_bri10; }
|
||||
if (white_free_cw_out != nullptr) { *white_free_cw_out = white_free_cw; }
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the gamma correction for all 5 channels RGBCW
|
||||
// Computation is valid for 1,3,4,5 channels
|
||||
// 2-channels bulbs must be handled separately
|
||||
//
|
||||
// In:
|
||||
// - 5 channels RGBCW in 10 bits format (0..1023)
|
||||
// Out:
|
||||
// - 5 channels RGBCW in 10 bits format, with Gamma corretion (if enabled), replaced in place
|
||||
// - white_bri10: global brightness of white channel, split over CW/WW (basically the sum of CW+WW, but it's easier to compute on this basis)
|
||||
// - white_free_cw: signals that CW/WW are free mode, and not linked via CT. This is used when channels are manually set on a channel per channel basis. CT is ignored
|
||||
//
|
||||
void calcGammaBulb5Channels(uint16_t col10[LST_MAX], uint16_t *white_bri10_out, bool *white_free_cw) {
|
||||
for (uint32_t i = 0; i < 3; i++) {
|
||||
if (Settings.light_correction) {
|
||||
col10[i] = ledGamma10_10(col10[i]);
|
||||
}
|
||||
}
|
||||
calcGammaBulbCW(&col10[3], white_bri10_out, white_free_cw);
|
||||
}
|
||||
|
||||
// sale but converts from 8 bits to 10 bits first
|
||||
void calcGammaBulb5Channels_8(uint8_t in8[LST_MAX], uint16_t col10[LST_MAX]) {
|
||||
for (uint32_t i = 0; i < LST_MAX; i++) {
|
||||
col10[i] = change8to10(in8[i]);
|
||||
}
|
||||
calcGammaBulb5Channels(col10, nullptr, nullptr);
|
||||
}
|
||||
|
||||
bool calcGammaBulbs(uint16_t cur_col_10[5]) {
|
||||
bool rgbwwtable_applied_white = false;
|
||||
bool pwm_ct = false;
|
||||
bool white_free_cw = false; // true if White channels are uncorrelated. Happens when CW+WW>255, i.e. manually setting white channels to exceed to total power of a single channel (may harm the power supply)
|
||||
// Various values needed for accurate White calculation
|
||||
// CT value streteched to 0..1023 (from within CT range, so not necessarily from 153 to 500). 0=Cold, 1023=Warm
|
||||
uint16_t ct = light_state.getCT();
|
||||
uint16_t ct_10 = changeUIntScale(ct, Light.vct_ct[0], Light.vct_ct[CT_PIVOTS-1], 0, 1023);
|
||||
|
||||
uint16_t white_bri10 = 0; // White total brightness normalized to 0..1023
|
||||
// uint32_t cw1 = Light.subtype - 1; // address for the ColorTone PWM
|
||||
uint32_t cw0 = Light.subtype - 2; // address for the White Brightness PWM
|
||||
|
||||
// calc basic gamma correction for all types
|
||||
if ((LST_SINGLE == Light.subtype) || (LST_RGB <= Light.subtype)) {
|
||||
calcGammaBulb5Channels(cur_col_10, &white_bri10, &white_free_cw);
|
||||
} else if (LST_COLDWARM == Light.subtype) {
|
||||
calcGammaBulbCW(cur_col_10, &white_bri10, &white_free_cw);
|
||||
}
|
||||
|
||||
// Now we know ct_10 and white_bri10 (gamma corrected if needed)
|
||||
|
||||
#ifdef ESP8266
|
||||
if ((LST_COLDWARM == Light.subtype) || (LST_RGBCW == Light.subtype)) {
|
||||
if ((PHILIPS == TasmotaGlobal.module_type) || (Settings.flag4.pwm_ct_mode)) { // channel 1 is the color tone, mapped to cold channel (0..255)
|
||||
pwm_ct = true;
|
||||
// Xiaomi Philips bulbs follow a different scheme:
|
||||
// channel 0=intensity, channel1=temperature
|
||||
cur_col_10[cw0] = white_bri10;
|
||||
cur_col_10[cw0+1] = ct_10;
|
||||
return false; // avoid any interference
|
||||
}
|
||||
}
|
||||
#endif // ESP8266
|
||||
|
||||
// Now see if we need to mix RGB and White
|
||||
// Valid only for LST_RGBW, LST_RGBCW, SetOption105 1, and white is zero (see doc)
|
||||
if ((LST_RGBW <= Light.subtype) && (Settings.flag4.white_blend_mode) && (0 == cur_col_10[3]+cur_col_10[4])) {
|
||||
uint32_t min_rgb_10 = min3(cur_col_10[0], cur_col_10[1], cur_col_10[2]);
|
||||
cur_col_10[0] -= min_rgb_10;
|
||||
cur_col_10[1] -= min_rgb_10;
|
||||
cur_col_10[2] -= min_rgb_10;
|
||||
|
||||
// Add to white level
|
||||
uint32_t adjust_w_10 = change8to10(Settings.rgbwwTable[3]); // take the correction factor, bought back to 10 bits
|
||||
white_bri10 += changeUIntScale(min_rgb_10, 0, 1023, 0, adjust_w_10); // set white power down corrected with rgbwwTable[3]
|
||||
white_bri10 = (white_bri10 > 1023) ? 1023 : white_bri10; // max 1023
|
||||
rgbwwtable_applied_white = true;
|
||||
}
|
||||
|
||||
#ifdef USE_LIGHT_VIRTUAL_CT
|
||||
// compute virtual CT, which is suppsed to be compatible with white_blend_mode
|
||||
if (Light.virtual_ct && (!white_free_cw) && (LST_RGBW <= Light.subtype)) { // any light with a white channel
|
||||
vct_pivot_t *pivot = &Light.vct_color[0];
|
||||
uint16_t *from_ct = &Light.vct_ct[0];
|
||||
|
||||
for (uint32_t i = 1; i < CT_PIVOTS-1; i++) {
|
||||
if (ct > Light.vct_ct[i]) { // if above mid-point, take range [1]..[2] instead of [0]..[1]
|
||||
pivot++;
|
||||
from_ct++;
|
||||
}
|
||||
}
|
||||
uint16_t from10[LST_MAX];
|
||||
uint16_t to10[LST_MAX];
|
||||
calcGammaBulb5Channels_8(*pivot, from10);
|
||||
calcGammaBulb5Channels_8(*(pivot+1), to10);
|
||||
|
||||
vct_pivot_t *pivot1 = pivot + 1;
|
||||
// AddLog_P(LOG_LEVEL_INFO, PSTR("+++ from_ct %d, to_ct %d [%03X,%03X,%03X,%03X,%03X] - [%03X,%03X,%03X,%03X,%03X]"),
|
||||
// *from_ct, *(from_ct+1), (*pivot)[0], (*pivot)[1], (*pivot)[2], (*pivot)[3], (*pivot)[4],
|
||||
// (*pivot1)[0], (*pivot1)[1], (*pivot1)[2], (*pivot1)[3], (*pivot1)[4]);
|
||||
// AddLog_P(LOG_LEVEL_INFO, PSTR("+++ from10 [%03X,%03X,%03X,%03X,%03X] - to 10 [%03X,%03X,%03X,%03X,%03X]"),
|
||||
// from10[0],from10[0],from10[0],from10[0],from10[4],
|
||||
// to10[0],to10[0],to10[0],to10[0],to10[4]);
|
||||
|
||||
// set both CW/WW to zero since their previous value don't count anymore
|
||||
cur_col_10[3] = 0;
|
||||
cur_col_10[4] = 0;
|
||||
|
||||
// Add the interpolated point to each component
|
||||
for (uint32_t i = 0; i < LST_MAX; i++) {
|
||||
cur_col_10[i] += changeUIntScale(changeUIntScale(ct, *from_ct, *(from_ct+1), from10[i], to10[i]), 0, 1023, 0, white_bri10);
|
||||
if (cur_col_10[i] > 1023) { cur_col_10[i] = 1023; }
|
||||
}
|
||||
} else
|
||||
#endif // USE_LIGHT_VIRTUAL_CT
|
||||
// compute the actual levels for CW/WW
|
||||
// We know ct_10 and white_bri_10 (which may be Gamma corrected)
|
||||
// cur_col_10[cw0] and cur_col_10[cw1] were unmodified up to now
|
||||
if (LST_RGBW == Light.subtype) {
|
||||
cur_col_10[3] = white_bri10; // simple case, we set the White level to the required brightness
|
||||
} else if ((LST_COLDWARM == Light.subtype) || (LST_RGBCW == Light.subtype)) {
|
||||
// if sum of both channels is > 255, then channels are probably uncorrelated
|
||||
if (!white_free_cw) {
|
||||
// then we split the total energy among the cold and warm leds
|
||||
cur_col_10[cw0+1] = changeUIntScale(ct_10, 0, 1023, 0, white_bri10);
|
||||
cur_col_10[cw0] = white_bri10 - cur_col_10[cw0+1];
|
||||
}
|
||||
}
|
||||
return rgbwwtable_applied_white;
|
||||
}
|
||||
|
||||
#ifdef USE_DEVICE_GROUPS
|
||||
@ -3045,6 +3174,83 @@ void CmndWakeupDuration(void)
|
||||
ResponseCmndNumber(Settings.light_wakeup);
|
||||
}
|
||||
|
||||
void CmndCTRange(void)
|
||||
{
|
||||
// Format is "CTRange ctmin,ctmax"
|
||||
// Ex:
|
||||
// CTRange 153,500
|
||||
// CTRange
|
||||
// CTRange 200,350
|
||||
char *p;
|
||||
strtok_r(XdrvMailbox.data, ",", &p);
|
||||
if (p != nullptr) {
|
||||
int32_t ct_min = strtol(XdrvMailbox.data, nullptr, 0);
|
||||
int32_t ct_max = strtol(p, nullptr, 0);
|
||||
if ( (ct_min >= CT_MIN) && (ct_min <= CT_MAX) &&
|
||||
(ct_max >= CT_MIN) && (ct_max <= CT_MAX) &&
|
||||
(ct_min <= ct_max)
|
||||
) {
|
||||
setCTRange(ct_min, ct_max);
|
||||
} else {
|
||||
return; // error
|
||||
}
|
||||
}
|
||||
Response_P(PSTR("{\"%s\":\"%d,%d\"}"), XdrvMailbox.command, Light.vct_ct[0], Light.vct_ct[CT_PIVOTS-1]);
|
||||
}
|
||||
|
||||
#ifdef USE_LIGHT_VIRTUAL_CT
|
||||
void CmndVirtualCT(void)
|
||||
{
|
||||
if (!Settings.flag4.virtual_ct) {
|
||||
ResponseCmndChar_P(PSTR("You need to enable `SetOption106 1`"));
|
||||
return;
|
||||
}
|
||||
if (XdrvMailbox.data[0] == ('{')) {
|
||||
// parse JSON
|
||||
JsonParser parser(XdrvMailbox.data);
|
||||
JsonParserObject root = parser.getRootObject();
|
||||
if (!root) { return; }
|
||||
|
||||
uint32_t idx = 0;
|
||||
for (auto key : root) {
|
||||
if (idx >= CT_PIVOTS) { ResponseCmndChar_P(PSTR("Too many points")); return; }
|
||||
|
||||
int32_t ct_val = strtol(key.getStr(), nullptr, 0);
|
||||
if ((ct_val < CT_MIN) || (ct_val > CT_MAX)) { ResponseCmndChar_P(PSTR("CT out of range")); return; }
|
||||
char * color = (char*) key.getValue().getStr();
|
||||
// call color parser
|
||||
Light.vct_ct[idx] = ct_val;
|
||||
if (LightColorEntry(color, strlen(color))) {
|
||||
memcpy(&Light.vct_color[idx], Light.entry_color, sizeof(Light.vct_color[idx]));
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
for (uint32_t i = idx-1; i < CT_PIVOTS-1; i++) {
|
||||
Light.vct_ct[i+1] = Light.vct_ct[i];
|
||||
memcpy(&Light.vct_color[i+1], &Light.vct_color[i], sizeof(Light.vct_color[0]));
|
||||
}
|
||||
}
|
||||
checkVirtualCT();
|
||||
|
||||
Response_P(PSTR("{\"%s\":{"), XdrvMailbox.command);
|
||||
uint32_t pivot_len = CT_PIVOTS;
|
||||
vct_pivot_t * pivot = &Light.vct_color[0];
|
||||
if (Light.vct_ct[1] >= Light.vct_ct[2]) { pivot_len = 2; } // only 2 points are valid
|
||||
|
||||
bool end = false;
|
||||
for (uint32_t i = 0; (i < CT_PIVOTS) && !end; i++) {
|
||||
if ((i >= CT_PIVOTS-1) || (Light.vct_ct[i] >= Light.vct_ct[i+1])) {
|
||||
end = true;
|
||||
}
|
||||
ResponseAppend_P(PSTR("\"%d\":\"%02X%02X%02X%02X%02X\"%c"), Light.vct_ct[i],
|
||||
(*pivot)[0], (*pivot)[1], (*pivot)[2], (*pivot)[3], (*pivot)[4],
|
||||
end ? '}' : ',');
|
||||
pivot++;
|
||||
}
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
#endif // USE_LIGHT_VIRTUAL_CT
|
||||
|
||||
#ifdef USE_LIGHT_PALETTE
|
||||
void CmndPalette(void)
|
||||
{
|
||||
|
@ -517,7 +517,7 @@ bool TuyaSetChannels(void)
|
||||
Tuya.Snapshot[0] = changeUIntScale(Light.current_color[0], 0, 255, 0, 100);
|
||||
Tuya.Snapshot[1] = changeUIntScale(Light.current_color[1], 0, 255, 0, 100);
|
||||
} else { // CT Light or RGBWC
|
||||
light_state.getCTRange(&Tuya.CTMin, &Tuya.CTMax); // SetOption82 - Reduce the CT range from 153..500 to 200..380 to accomodate with Alexa range
|
||||
getCTRange(&Tuya.CTMin, &Tuya.CTMax); // SetOption82 - Reduce the CT range from 153..500 to 200..380 to accomodate with Alexa range
|
||||
Tuya.Snapshot[0] = light_state.getDimmer();
|
||||
Tuya.Snapshot[1] = light_state.getCT();
|
||||
}
|
||||
|
@ -64,11 +64,11 @@ void ST7789_InitDriver()
|
||||
|
||||
if (XDSP_12 == Settings.display_model) {
|
||||
|
||||
if (Settings.display_width != ST7789_TFTWIDTH) {
|
||||
Settings.display_width = ST7789_TFTWIDTH;
|
||||
if (!Settings.display_width) {
|
||||
Settings.display_width = 240;
|
||||
}
|
||||
if (Settings.display_height != ST7789_TFTHEIGHT) {
|
||||
Settings.display_height = ST7789_TFTHEIGHT;
|
||||
if (!Settings.display_height) {
|
||||
Settings.display_height = 240;
|
||||
}
|
||||
|
||||
// disable screen buffer
|
||||
@ -130,9 +130,15 @@ void ST7789_InitDriver()
|
||||
|
||||
#ifdef SHOW_SPLASH
|
||||
// Welcome text
|
||||
renderer->setTextFont(2);
|
||||
renderer->setTextColor(ST7789_WHITE,ST7789_BLACK);
|
||||
renderer->DrawStringAt(30, 100, "ST7789 TFT!", ST7789_WHITE,0);
|
||||
int fontSize = 2;
|
||||
renderer->setTextFont(2);
|
||||
if (Settings.display_width<240) {
|
||||
fontSize = 1;
|
||||
}
|
||||
renderer->setTextFont(fontSize);
|
||||
int fontHeight = 12 * fontSize;
|
||||
renderer->DrawStringAt(30, (Settings.display_height-fontHeight)/2, "ST7789 TFT!", ST7789_WHITE,0);
|
||||
delay(1000);
|
||||
#endif
|
||||
|
||||
|
@ -196,6 +196,7 @@ void MCP230xx_ApplySettings(void)
|
||||
I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPIO+mcp230xx_port, reg_portpins);
|
||||
#endif // USE_MCP230xx_OUTPUT
|
||||
}
|
||||
#ifdef USE_MCP230xx_OUTPUT
|
||||
TasmotaGlobal.devices_present -= mcp230xx_oldoutpincount;
|
||||
mcp230xx_oldoutpincount = 0;
|
||||
for (uint32_t idx=0;idx<mcp230xx_pincount;idx++) {
|
||||
@ -206,6 +207,7 @@ void MCP230xx_ApplySettings(void)
|
||||
int_millis[idx]=millis();
|
||||
}
|
||||
TasmotaGlobal.devices_present += mcp230xx_oldoutpincount;
|
||||
#endif // USE_MCP230xx_OUTPUT
|
||||
mcp230xx_int_en = int_en;
|
||||
MCP230xx_CheckForIntCounter(); // update register on whether or not we should be counting interrupts
|
||||
MCP230xx_CheckForIntRetainer(); // update register on whether or not we should be retaining interrupt events for teleperiod
|
||||
|
1
tools/Esptool/Odroid_go/Odroid_flash.bat
Normal file
1
tools/Esptool/Odroid_go/Odroid_flash.bat
Normal file
@ -0,0 +1 @@
|
||||
esptool.py --chip esp32 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dout --flash_freq 40m --flash_size detect 0x1000 bootloader_dout_40m.bin 0x8000 partitions_ffat_12M.bin 0xe000 boot_app0.bin 0x10000 tasmota32-odroid.bin
|
BIN
tools/Esptool/Odroid_go/boot_app0.bin
Normal file
BIN
tools/Esptool/Odroid_go/boot_app0.bin
Normal file
Binary file not shown.
BIN
tools/Esptool/Odroid_go/bootloader_dout_40m.bin
Normal file
BIN
tools/Esptool/Odroid_go/bootloader_dout_40m.bin
Normal file
Binary file not shown.
BIN
tools/Esptool/Odroid_go/partitions_ffat_12M.bin
Normal file
BIN
tools/Esptool/Odroid_go/partitions_ffat_12M.bin
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user