diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile index 29d75d19d..f16b02389 100644 --- a/.gitpod.Dockerfile +++ b/.gitpod.Dockerfile @@ -1,5 +1,3 @@ FROM gitpod/workspace-full USER gitpod - -RUN pip3 install -U platformio diff --git a/.gitpod.yml b/.gitpod.yml index 50d9a86d9..170b688e0 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,6 +1,5 @@ tasks: - - before: platformio upgrade - - command: platformio run -e tasmota + - command: pip3 install -U platformio && platformio run -e tasmota image: file: .gitpod.Dockerfile diff --git a/CHANGELOG.md b/CHANGELOG.md index 84e39168f..3cea49b84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. ## [Released] +## [12.0.2] 20220620 +- Release Paul + +## [12.0.1.2] +### Added +- Command ``DnsTimeout 100..20000`` to change default DNS timeout from 1000 msec blocking if no DNS server found + +### Fixed +- MQTT rc -4 connections regression from v12.0.0 (#15809) + +## [12.0.1] 20220617 +- Release Paul + +### Fixed +- Resolving NTP and/or MQTT server names regression from v12.0.0 (#15816) ## [12.0.0] 20220615 - Release Paul diff --git a/RELEASENOTES.md b/RELEASENOTES.md index aa09ba62f..8cd5eb1a0 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -72,7 +72,7 @@ Latest released binaries can be downloaded from - http://ota.tasmota.com/tasmota/release Historical binaries can be downloaded from -- http://ota.tasmota.com/tasmota/release-12.0.0 +- http://ota.tasmota.com/tasmota/release-12.0.2 The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz`` @@ -97,7 +97,7 @@ Latest released binaries can be downloaded from - http://ota.tasmota.com/tasmota32/release Historical binaries can be downloaded from -- http://ota.tasmota.com/tasmota32/release-12.0.0 +- http://ota.tasmota.com/tasmota32/release-12.0.2 The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota32/release/tasmota32.bin`` @@ -107,44 +107,9 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.0.0 Paul +## Changelog v12.0.2 Paul ### Added -- Command ``SetOption139 0/1`` to switch between pressure unit "mmHg" (0) or "inHg" (1) when ``SO24 1`` [#15350](https://github.com/arendst/Tasmota/issues/15350) -- Command ``SetOption140 0/1`` to switch between MQTT Clean Session (0) or Persistent Session (1) [#15530](https://github.com/arendst/Tasmota/issues/15530) -- Command ``SetOption141 1`` to disable display of module name in GUI header -- Command ``SetOption142 1`` to wait 1 second for wifi connection solving some FRITZ!Box modem issues [#14985](https://github.com/arendst/Tasmota/issues/14985) -- Command ``EnergyExportActive`` to (p)reset energy export active for supported devices. Currently ADE7880 only [#13515](https://github.com/arendst/Tasmota/issues/13515) -- Command ``IfxRp ""|`` adds optional InfluxDb Retention Policy [#15513](https://github.com/arendst/Tasmota/issues/15513) -- Command ``SspmDisplay 2`` to display Sonoff SPM energy data in GUI for user tab-selected relay modules [#13447](https://github.com/arendst/Tasmota/issues/13447) -- Command ``SSerialSend9 0/1`` to enable Serial Bridge console Tee for debugging purposes -- Support for Sonoff MS01 soil moisture sensor [#15335](https://github.com/arendst/Tasmota/issues/15335) -- Support for daisy chaining MAX7219 displays [#15345](https://github.com/arendst/Tasmota/issues/15345) -- Support for Sensirion SHT4X using define USE_SHT3X [#15349](https://github.com/arendst/Tasmota/issues/15349) -- Support for Sonoff SPM v1.2.0 -- Support for Sonoff Zigbee Bridge Pro by Stephan Hadinger [#15701](https://github.com/arendst/Tasmota/issues/15701) -- Support for Sonoff NSPanel Smart Scene Wall Switch -- Support for flowrate meters like YF-DN50 and similary [#15474](https://github.com/arendst/Tasmota/issues/15474) -- Support for 5-channel light dimmer driver BP5758D used in Tuya bulbs [#15713](https://github.com/arendst/Tasmota/issues/15713) -- Support for HYTxxx temperature and humidity sensor [#15715](https://github.com/arendst/Tasmota/issues/15715) -- Sonoff SPM delayed SetPowerOnState [#13447](https://github.com/arendst/Tasmota/issues/13447) -- ESP32 Command ``Restart 3`` to switch between SafeBoot and Production - -### Breaking Changed - -### Changed -- Restructured tasmota source directories taking benefit from PlatformIO Core v6.0.2 -- Prepare to remove dedicated Home Assistant discovery in favour of Tasmota Discovery and hatasmota -- ESP32 Tasmota SafeBoot with changed partition scheme allowing larger binaries -- ESP32 increase Serial Bridge input buffer from 130 to 520 characters +- Command ``DnsTimeout 100..20000`` to change default DNS timeout from 1000 msec blocking if no DNS server found ### Fixed -- Improv initial or erase device installation failing to provide Configure WiFi option -- SCD40 start low power command [#15361](https://github.com/arendst/Tasmota/issues/15361) -- BL09xx negative power presentation [#15374](https://github.com/arendst/Tasmota/issues/15374) -- Possible pin output toggle after power on [#15630](https://github.com/arendst/Tasmota/issues/15630) -- Reduce blocking by adding WifiPollDns before resolving NTP and/or MQTT server names [#14394](https://github.com/arendst/Tasmota/issues/14394) -- SHT1X driver hangs and wrong values on ESP32 [#15790](https://github.com/arendst/Tasmota/issues/15790) -- ESP32 Arduino Core WiFi timeout is changed from msec to seconds - -### Removed -- Arduino IDE support +- MQTT rc -4 on TLS connections regression from v12.0.0 [#15809](https://github.com/arendst/Tasmota/issues/15809) diff --git a/lib/default/DnsClient/library.properties b/lib/default/DnsClient/library.properties new file mode 100644 index 000000000..7ac2d2393 --- /dev/null +++ b/lib/default/DnsClient/library.properties @@ -0,0 +1,7 @@ +name=DnsClient +version=1.0 +author=MCQN Ltd, Theo Arends +maintainer=Theo +sentence=Dns client allowing timeout selection. +paragraph=This class uses WifiUdp. +architectures=esp8266,esp32 diff --git a/lib/default/DnsClient/src/DnsClient.cpp b/lib/default/DnsClient/src/DnsClient.cpp new file mode 100644 index 000000000..19bc4444d --- /dev/null +++ b/lib/default/DnsClient/src/DnsClient.cpp @@ -0,0 +1,334 @@ +/* + DnsClient.cpp - DNS client for Arduino + + SPDX-FileCopyrightText: 2009-2010 MCQN Ltd. and Theo Arends + + SPDX-License-Identifier: GPL-3.0-only +*/ + +// Arduino DNS client for WizNet5100-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#include "DnsClient.h" + +// Various flags and header field values for a DNS message +#define UDP_HEADER_SIZE 8 +#define DNS_HEADER_SIZE 12 +#define TTL_SIZE 4 +#define QUERY_FLAG (0) +#define RESPONSE_FLAG (1<<15) +#define QUERY_RESPONSE_MASK (1<<15) +#define OPCODE_STANDARD_QUERY (0) +#define OPCODE_INVERSE_QUERY (1<<11) +#define OPCODE_STATUS_REQUEST (2<<11) +#define OPCODE_MASK (15<<11) +#define AUTHORITATIVE_FLAG (1<<10) +#define TRUNCATION_FLAG (1<<9) +#define RECURSION_DESIRED_FLAG (1<<8) +#define RECURSION_AVAILABLE_FLAG (1<<7) +#define RESP_NO_ERROR (0) +#define RESP_FORMAT_ERROR (1) +#define RESP_SERVER_FAILURE (2) +#define RESP_NAME_ERROR (3) +#define RESP_NOT_IMPLEMENTED (4) +#define RESP_REFUSED (5) +#define RESP_MASK (15) +#define TYPE_A (0x0001) +#define CLASS_IN (0x0001) +#define LABEL_COMPRESSION_MASK (0xC0) +// Port number that DNS servers listen on +#define DNS_PORT 53 + +// Possible return codes from ProcessResponse +#define SUCCESS 1 +#define TIMED_OUT -1 +#define INVALID_SERVER -2 +#define TRUNCATED -3 +#define INVALID_RESPONSE -4 + +#ifndef htons +#define htons(x) ( ((x)<< 8 & 0xFF00) | ((x)>> 8 & 0x00FF) ) +#endif + +void DNSClient::begin(const IPAddress& aDNSServer) { + iDNSServer = aDNSServer; + iRequestId = 0; +} + +void DNSClient::setTimeout(uint32_t aTimeout) { + iTimeout = aTimeout; +} + +int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) { + // See if it's a numeric IP address + if (aResult.fromString(aHostname)) { + // It is, our work here is done + return SUCCESS; + } + + // Check we've got a valid DNS server to use + if ((0xFFFFFFFF == (uint32_t)iDNSServer) || (0 == (uint32_t)iDNSServer)) { + return INVALID_SERVER; + } + + int ret = 0; + // Find a socket to use + if (iUdp.begin(1024+(millis() & 0xF)) == 1) { + // Try up to three times + int retries = 0; +// while ((retries < 3) && (ret <= 0)) { + // Send DNS request + ret = iUdp.beginPacket(iDNSServer, DNS_PORT); + if (ret != 0) { + // Now output the request data + ret = BuildRequest(aHostname); + if (ret != 0) { + // And finally send the request + ret = iUdp.endPacket(); + if (ret != 0) { + // Now wait for a response + int wait_retries = 0; + ret = TIMED_OUT; + while ((wait_retries < 3) && (ret == TIMED_OUT)) { + ret = ProcessResponse(iTimeout, aResult); + wait_retries++; + } + } + } + } + retries++; +// } + // We're done with the socket now + iUdp.stop(); + } + return ret; +} + +int DNSClient::BuildRequest(const char* aName) { + // Build header + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ID | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | QDCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ANCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | NSCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ARCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // As we only support one request at a time at present, we can simplify + // some of this header + iRequestId = millis(); // generate a random ID + uint16_t twoByteBuffer; + + // FIXME We should also check that there's enough space available to write to, rather + // FIXME than assume there's enough space (as the code does at present) + iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId)); + + twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(1); // One question record + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = 0; // Zero answer records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // and zero additional records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + // Build question + const char* start =aName; + const char* end =start; + uint8_t len; + // Run through the name being requested + while (*end) { + // Find out how long this section of the name is + end = start; + while (*end && (*end != '.') ) { + end++; + } + + if (end-start > 0) { + // Write out the size of this section + len = end-start; + iUdp.write(&len, sizeof(len)); + // And then write out the section + iUdp.write((uint8_t*)start, end-start); + } + start = end+1; + } + + // We've got to the end of the question name, so terminate it with a zero-length section + len = 0; + iUdp.write(&len, sizeof(len)); + // Finally the type and class of question + twoByteBuffer = htons(TYPE_A); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(CLASS_IN); // Internet class of question + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // Success! Everything buffered okay + return SUCCESS; +} + +int DNSClient::ProcessResponse(uint32_t aTimeout, IPAddress& aAddress) { + uint32_t startTime = millis(); + + // Wait for a response packet + while(iUdp.parsePacket() <= 0) { + if ((millis() - startTime) > aTimeout) { + return TIMED_OUT; + } + delay(20); + } + + // We've had a reply! + // Read the UDP header + uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header + // Check that it's a response from the right server and the right port + if ( (iDNSServer != iUdp.remoteIP()) || (iUdp.remotePort() != DNS_PORT) ) { + // It's not from who we expected + return INVALID_SERVER; + } + + // Read through the rest of the response + if (iUdp.available() < DNS_HEADER_SIZE) { + return TRUNCATED; + } + iUdp.read(header, DNS_HEADER_SIZE); + + uint16_t staging; // Staging used to avoid type-punning warnings + memcpy(&staging, &header[2], sizeof(uint16_t)); + uint16_t header_flags = htons(staging); + memcpy(&staging, &header[0], sizeof(uint16_t)); + // Check that it's a response to this request + if ( (iRequestId != staging) || ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) ) { + // Mark the entire packet as read + iUdp.flush(); + return INVALID_RESPONSE; + } + // Check for any errors in the response (or in our request) + // although we don't do anything to get round these + if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) { + // Mark the entire packet as read + iUdp.flush(); + return -5; // INVALID_RESPONSE; + } + + // And make sure we've got (at least) one answer + memcpy(&staging, &header[6], sizeof(uint16_t)); + uint16_t answerCount = htons(staging); + if (answerCount == 0 ) { + // Mark the entire packet as read + iUdp.flush(); + return -6; // INVALID_RESPONSE; + } + + // Skip over any questions + memcpy(&staging, &header[4], sizeof(uint16_t)); + for (uint32_t i = 0; i < htons(staging); i++) { + // Skip over the name + uint8_t len; + do { + iUdp.read(&len, sizeof(len)); + if (len > 0) { + // Don't need to actually read the data out for the string, just + // advance ptr to beyond it + while(len--) { + iUdp.read(); // we don't care about the returned byte + } + } + } while (len != 0); + + // Now jump over the type and class + for (uint32_t i = 0; i < 4; i++) { + iUdp.read(); // we don't care about the returned byte + } + } + + // Now we're up to the bit we're interested in, the answer + // There might be more than one answer (although we'll just use the first + // type A answer) and some authority and additional resource records but + // we're going to ignore all of them. + + for (uint32_t i = 0; i < answerCount; i++) { + // Skip the name + uint8_t len; + do { + iUdp.read(&len, sizeof(len)); + if ((len & LABEL_COMPRESSION_MASK) == 0) { + // It's just a normal label + if (len > 0) { + // And it's got a length + // Don't need to actually read the data out for the string, + // just advance ptr to beyond it + while(len--) { + iUdp.read(); // we don't care about the returned byte + } + } + } else { + // This is a pointer to a somewhere else in the message for the + // rest of the name. We don't care about the name, and RFC1035 + // says that a name is either a sequence of labels ended with a + // 0 length octet or a pointer or a sequence of labels ending in + // a pointer. Either way, when we get here we're at the end of + // the name + // Skip over the pointer + iUdp.read(); // we don't care about the returned byte + // And set len so that we drop out of the name loop + len = 0; + } + } while (len != 0); + + // Check the type and class + uint16_t answerType; + uint16_t answerClass; + iUdp.read((uint8_t*)&answerType, sizeof(answerType)); + iUdp.read((uint8_t*)&answerClass, sizeof(answerClass)); + + // Ignore the Time-To-Live as we don't do any caching + for (uint32_t i = 0; i < TTL_SIZE; i++) { + iUdp.read(); // We don't care about the returned byte + } + + // And read out the length of this answer + // Don't need header_flags anymore, so we can reuse it here + iUdp.read((uint8_t*)&header_flags, sizeof(header_flags)); + + if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) { + if (htons(header_flags) != 4) { + // It's a weird size + // Mark the entire packet as read + iUdp.flush(); + return -9; // INVALID_RESPONSE; + } + iUdp.read(aAddress.raw_address(), 4); +// uint32_t address; +// iUdp.read((uint8_t*)&address, sizeof(address)); +// aAddress = (IPAddress)address; + + // Check we've got a valid address + if ((0xFFFFFFFF != (uint32_t)aAddress) && (0 != (uint32_t)aAddress)) { + return SUCCESS; + } + } else { + // This isn't an answer type we're after, move onto the next one + for (uint32_t i = 0; i < htons(header_flags); i++) { + iUdp.read(); // we don't care about the returned byte + } + } + } + + // Mark the entire packet as read + iUdp.flush(); + + // If we get here then we haven't found an answer + return -10; // INVALID_RESPONSE; +} diff --git a/lib/default/DnsClient/src/DnsClient.h b/lib/default/DnsClient/src/DnsClient.h new file mode 100644 index 000000000..42f29b190 --- /dev/null +++ b/lib/default/DnsClient/src/DnsClient.h @@ -0,0 +1,42 @@ +/* + DnsClient.h - DNS client for Arduino + + SPDX-FileCopyrightText: 2009-2010 MCQN Ltd. and Theo Arends + + SPDX-License-Identifier: GPL-3.0-only +*/ + +// Arduino DNS client for WizNet5100-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#ifndef DNSClient_h +#define DNSClient_h + +#include +#include +#include + +class DNSClient { +public: + void begin(const IPAddress& aDNSServer); + void setTimeout(uint32_t aTimeout = 1000); + + /* Resolve the given hostname to an IP address. + @param aHostname Name to be resolved + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, else error code + */ + int getHostByName(const char* aHostname, IPAddress& aResult); + +protected: + int BuildRequest(const char* aName); + int ProcessResponse(uint32_t aTimeout, IPAddress& aAddress); + + IPAddress iDNSServer; + uint16_t iRequestId; + uint16_t iTimeout = 1000; + WiFiUDP iUdp; +}; + +#endif diff --git a/lib/libesp32/berry/src/be_object.c b/lib/libesp32/berry/src/be_object.c index 606d2bb0f..aa2f71799 100644 --- a/lib/libesp32/berry/src/be_object.c +++ b/lib/libesp32/berry/src/be_object.c @@ -71,3 +71,14 @@ void be_commonobj_delete(bvm *vm, bgcobject *obj) be_free(vm, co, sizeof(bcommomobj)); } } + +/* generic destroy method for comobj, just call be_os_free() on the pointer */ +int be_commonobj_destroy_generic(bvm* vm) +{ + int argc = be_top(vm); + if (argc > 0) { + void * obj = be_tocomptr(vm, 1); + if (obj != NULL) { be_os_free(obj); } + } + be_return_nil(vm); +} diff --git a/lib/libesp32/berry/src/be_object.h b/lib/libesp32/berry/src/be_object.h index 13d4be006..dbde8317f 100644 --- a/lib/libesp32/berry/src/be_object.h +++ b/lib/libesp32/berry/src/be_object.h @@ -259,5 +259,6 @@ typedef const char* (*breader)(void*, size_t*); const char* be_vtype2str(bvalue *v); bvalue* be_indexof(bvm *vm, int idx); void be_commonobj_delete(bvm *vm, bgcobject *obj); +int be_commonobj_destroy_generic(bvm* vm); #endif diff --git a/lib/libesp32/berry_int64/src/be_int64_class.c b/lib/libesp32/berry_int64/src/be_int64_class.c index 9d8bd5958..5cbfa54d2 100644 --- a/lib/libesp32/berry_int64/src/be_int64_class.c +++ b/lib/libesp32/berry_int64/src/be_int64_class.c @@ -35,12 +35,14 @@ static void int64_toa(int64_t num, uint8_t* str) { void* int64_init(bvm *vm, int32_t val) { int64_t *i64 = (int64_t*)be_malloc(vm, sizeof(int64_t)); *i64 = (int64_t) val; + // serial_debug("int64_init p=%p\n", i64); return i64; } BE_FUNC_CTYPE_DECLARE(int64_init, "+_p", "@[i]") void int64_deinit(bvm *vm, int64_t *i64) { - // TODO + // serial_debug("int64_deinit p=%p\n", i64); + be_free(vm, i64, sizeof(int64_t)); } BE_FUNC_CTYPE_DECLARE(int64_deinit, "", "@.") @@ -168,7 +170,6 @@ void* int64_tobytes(int64_t *i64, size_t *len) { BE_FUNC_CTYPE_DECLARE(int64_tobytes, "&", ".") void int64_frombytes(int64_t *i64, uint8_t* ptr, size_t len, int32_t idx) { - serial_debug("int64_frombytes p=%p len=%i idx=%i\n", ptr, len, idx); if (idx < 0) { idx = len + idx; } // support negative index, counting from the end if (idx < 0) { idx = 0; } // sanity check if (idx > len) { idx = len; } diff --git a/lib/libesp32/berry_tasmota/src/be_md5_lib.c b/lib/libesp32/berry_tasmota/src/be_md5_lib.c index a4bcb23f4..3b73940ce 100644 --- a/lib/libesp32/berry_tasmota/src/be_md5_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_md5_lib.c @@ -10,18 +10,6 @@ #include "be_exec.h" #include "esp_rom_md5.h" -int free_ctx(bvm* vm) { - int argc = be_top(vm); - if (argc > 0) { - be_getmember(vm, 1, ".p"); - md5_context_t * ctx = (md5_context_t *) be_tocomptr(vm, -1); - if (ctx != NULL) { - be_os_free(ctx); - } - } - be_return_nil(vm); -} - // `Md5.init() -> ` int32_t m_md5_init(struct bvm *vm); int32_t m_md5_init(struct bvm *vm) { @@ -32,7 +20,7 @@ int32_t m_md5_init(struct bvm *vm) { } esp_rom_md5_init(ctx); - be_newcomobj(vm, ctx, &free_ctx); + be_newcomobj(vm, ctx, &be_commonobj_destroy_generic); be_setmember(vm, 1, ".p"); be_return_nil(vm); } diff --git a/lib/libesp32/berry_tasmota/src/be_re_lib.c b/lib/libesp32/berry_tasmota/src/be_re_lib.c index bc28c0e67..971814a2d 100644 --- a/lib/libesp32/berry_tasmota/src/be_re_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_re_lib.c @@ -7,6 +7,7 @@ *******************************************************************/ #include "be_constobj.h" #include "be_mem.h" +#include "be_object.h" #include "re1.5.h" /******************************************************************** @@ -33,15 +34,6 @@ re.split = def (regex_str, str) end # native extern const bclass be_class_re_pattern; -int be_free_comobj(bvm* vm) { - int argc = be_top(vm); - if (argc > 0) { - void * obj = be_tocomptr(vm, 1); - if (obj != NULL) { be_os_free(obj); } - } - be_return_nil(vm); -} - // Native functions be_const_func() // Berry: `re.compile(pattern:string) -> instance(be_pattern)` int be_re_compile(bvm *vm) { @@ -60,7 +52,7 @@ int be_re_compile(bvm *vm) { } be_pushntvclass(vm, &be_class_re_pattern); be_call(vm, 0); - be_newcomobj(vm, code, &be_free_comobj); + be_newcomobj(vm, code, &be_commonobj_destroy_generic); be_setmember(vm, -2, "_p"); be_pop(vm, 1); be_return(vm); diff --git a/tasmota/berry/modules/Partition_Wizard.tapp b/tasmota/berry/modules/Partition_Wizard.tapp index f98760d4f..0b78e8f9d 100644 Binary files a/tasmota/berry/modules/Partition_Wizard.tapp and b/tasmota/berry/modules/Partition_Wizard.tapp differ diff --git a/tasmota/berry/modules/Partition_Wizard/autoexec.be b/tasmota/berry/modules/Partition_Wizard/autoexec.be index 968e1a502..da230371a 100644 --- a/tasmota/berry/modules/Partition_Wizard/autoexec.be +++ b/tasmota/berry/modules/Partition_Wizard/autoexec.be @@ -1,2 +1,2 @@ -# rm Partition_wizard.tapp; zip -j -0 Partition_wizard.tapp Partition_Wizard/* +# rm Partition_Wizard.tapp; zip -j -0 Partition_Wizard.tapp Partition_Wizard/* import partition_wizard diff --git a/tasmota/berry/modules/Partition_Wizard/partition_wizard.bec b/tasmota/berry/modules/Partition_Wizard/partition_wizard.bec index 843fe128c..33aa383a1 100644 Binary files a/tasmota/berry/modules/Partition_Wizard/partition_wizard.bec and b/tasmota/berry/modules/Partition_Wizard/partition_wizard.bec differ diff --git a/tasmota/berry/modules/partition_wizard.be b/tasmota/berry/modules/partition_wizard.be index 445a7a345..e5845fc32 100644 --- a/tasmota/berry/modules/partition_wizard.be +++ b/tasmota/berry/modules/partition_wizard.be @@ -480,7 +480,7 @@ class Partition_wizard_UI webserver.content_send("
 Migrate to safeboot partition layout 

") webserver.content_send("

The `safeboot` layout allows for increased size
of firmware or file-system.

") - webserver.content_send("

Please see Safeboot layout documentation

") + webserver.content_send("

Please see Safeboot layout documentation

") webserver.content_send("

 

") webserver.content_send(string.format("

Step 1: %s

", self.display_step_state(self.test_step_1(p), "boot on `app1`"))) @@ -558,7 +558,7 @@ class Partition_wizard_UI # display if layout is factory if self.has_factory_layout(p) - webserver.content_send("

This device uses the safeboot layout

") + webserver.content_send("

This device uses the Safeboot layout

") end webserver.content_send("

") diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h index 473bd8b4a..87706b3b7 100644 --- a/tasmota/include/i18n.h +++ b/tasmota/include/i18n.h @@ -317,6 +317,7 @@ #define D_WCFG_5_WAIT "Wait" #define D_WCFG_6_SERIAL "Serial" #define D_WCFG_7_WIFIMANAGER_RESET_ONLY "ManagerRst" +#define D_CMND_DNSTIMEOUT "DnsTimeout" #define D_CMND_DEVICENAME "DeviceName" #define D_CMND_FRIENDLYNAME "FriendlyName" #define D_CMND_FN "FN" diff --git a/tasmota/include/tasmota_globals.h b/tasmota/include/tasmota_globals.h index fce339e63..abdb5deb2 100644 --- a/tasmota/include/tasmota_globals.h +++ b/tasmota/include/tasmota_globals.h @@ -268,6 +268,10 @@ String EthernetMacAddress(void); #define TASM_FILE_AUTOEXEC "/autoexec.bat" // Commands executed after restart #define TASM_FILE_CONFIG "/config.sys" // Settings executed after restart +#ifndef DNS_TIMEOUT +#define DNS_TIMEOUT 1000 // Milliseconds +#endif + #ifndef MQTT_MAX_PACKET_SIZE #define MQTT_MAX_PACKET_SIZE 1200 // Bytes //#define MQTT_MAX_PACKET_SIZE 2048 // Bytes diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index a501d90d0..2aaa9aaf6 100644 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -675,8 +675,9 @@ typedef struct { uint8_t knx_CB_registered; // 4A8 Number of Group Address to write uint8_t switchmode[MAX_SWITCHES_SET]; // 4A9 - uint8_t free_4c5[5]; // 4C5 + uint8_t free_4c5[3]; // 4C5 + uint16_t dns_timeout; // 4C8 uint8_t ds3502_state[MAX_DS3502]; // 4CA uint16_t influxdb_port; // 4CE power_t interlock[MAX_INTERLOCKS_SET]; // 4D0 MAX_INTERLOCKS = MAX_RELAYS / 2 diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index 6800a56d2..36f5b9805 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C000000; // 12.0.0.0 +const uint32_t VERSION = 0x0C000200; // 12.0.2.0 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index b8c9901a8..1ce6bf230 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -79,6 +79,7 @@ #define WIFI_CONFIG_TOOL WIFI_RETRY // [WifiConfig] Default tool if Wi-Fi fails to connect (default option: 4 - WIFI_RETRY) // (WIFI_RESTART, WIFI_MANAGER, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL, WIFI_MANAGER_RESET_ONLY) // The configuration can be changed after first setup using WifiConfig 0, 2, 4, 5, 6 and 7. +#define DNS_TIMEOUT 1000 // [DnsTimeout] Number of ms before DNS timeout #define WIFI_ARP_INTERVAL 60 // [SetOption41] Send gratuitous ARP interval #define WIFI_SCAN_AT_RESTART false // [SetOption56] Scan Wi-Fi network at restart for configured AP's #define WIFI_SCAN_REGULARLY true // [SetOption57] Scan Wi-Fi network every 44 minutes for configured AP's diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 9bc4e7833..00d3a21d1 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -35,6 +35,7 @@ // Libraries #include // Ota #include // Ota +#include // Any getHostByName #ifdef ESP32 #ifdef USE_TLS #include "HTTPUpdateLight.h" // Ota over HTTPS for ESP32 @@ -125,8 +126,7 @@ typedef struct { int32_t energy_kWhtoday_ph[3]; // 2D8 int32_t energy_kWhtotal_ph[3]; // 2E4 int32_t energy_kWhexport_ph[3]; // 2F0 - - uint8_t free_2fc[4]; // 2FC + uint32_t utc_time; // 2FC } TRtcSettings; TRtcSettings RtcSettings; #ifdef ESP32 @@ -159,6 +159,7 @@ struct XDRVMAILBOX { char *command; } XdrvMailbox; +DNSClient DnsClient; WiFiUDP PortUdp; // UDP Syslog and Alexa #ifdef ESP32 @@ -589,6 +590,7 @@ void setup(void) { TasmotaGlobal.init_state = INIT_GPIOS; SetPowerOnState(); + DnsClient.setTimeout(Settings->dns_timeout); WifiConnect(); AddLog(LOG_LEVEL_INFO, PSTR(D_PROJECT " %s - %s " D_VERSION " %s%s-" ARDUINO_CORE_RELEASE "(%s)"), diff --git a/tasmota/tasmota_support/settings.ino b/tasmota/tasmota_support/settings.ino index 1d03c5c0e..35b9f9dbe 100644 --- a/tasmota/tasmota_support/settings.ino +++ b/tasmota/tasmota_support/settings.ino @@ -37,6 +37,9 @@ uint32_t GetRtcSettingsCrc(void) { void RtcSettingsSave(void) { RtcSettings.baudrate = Settings->baudrate * 300; + if (UtcTime() > START_VALID_TIME) { // 2016-01-01 + RtcSettings.utc_time = UtcTime(); + } if (GetRtcSettingsCrc() != rtc_settings_crc) { if (RTC_MEM_VALID != RtcSettings.valid) { @@ -923,6 +926,7 @@ void SettingsDefaultSet2(void) { flag3.use_wifi_scan |= WIFI_SCAN_AT_RESTART; flag3.use_wifi_rescan |= WIFI_SCAN_REGULARLY; Settings->wifi_output_power = 170; + Settings->dns_timeout = DNS_TIMEOUT; Settings->param[P_ARP_GRATUITOUS] = WIFI_ARP_INTERVAL; ParseIPv4(&Settings->ipv4_address[0], PSTR(WIFI_IP_ADDRESS)); ParseIPv4(&Settings->ipv4_address[1], PSTR(WIFI_GATEWAY)); @@ -1537,6 +1541,9 @@ void SettingsDelta(void) { Settings->weight_offset = Settings->energy_frequency_calibration * Settings->weight_calibration; #endif } + if (Settings->version < 0x0C000102) { // 12.0.1.2 + Settings->dns_timeout = DNS_TIMEOUT; + } Settings->version = VERSION; SettingsSave(1); diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 343bc6a7f..0cb2d6af2 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -2452,11 +2452,10 @@ void SyslogAsync(bool refresh) { uint32_t current_hash = GetHash(SettingsText(SET_SYSLOG_HOST), strlen(SettingsText(SET_SYSLOG_HOST))); if (syslog_host_hash != current_hash) { IPAddress temp_syslog_host_addr; - int ok = WiFi.hostByName(SettingsText(SET_SYSLOG_HOST), temp_syslog_host_addr); // If sleep enabled this might result in exception so try to do it once using hash - if (!ok || (0xFFFFFFFF == (uint32_t)temp_syslog_host_addr)) { // 255.255.255.255 is assumed a DNS problem + if (!WifiHostByName(SettingsText(SET_SYSLOG_HOST), temp_syslog_host_addr)) { // If sleep enabled this might result in exception so try to do it once using hash TasmotaGlobal.syslog_level = 0; TasmotaGlobal.syslog_timer = SYSLOG_TIMER; - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION "Loghost DNS resolve failed (%s). " D_RETRY_IN " %d " D_UNIT_SECOND), SettingsText(SET_SYSLOG_HOST), SYSLOG_TIMER); + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RETRY_IN " %d " D_UNIT_SECOND), SYSLOG_TIMER); return; } syslog_host_hash = current_hash; diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index 8bf0ef967..584e35236 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -30,7 +30,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_TEMPLATE "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SYSLOG "|" D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_SERIALBUFFER "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALCONFIG "|" D_CMND_SERIALDELIMITER "|" - D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|" D_CMND_WIFI "|" + D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|" D_CMND_WIFI "|" D_CMND_DNSTIMEOUT "|" D_CMND_DEVICENAME "|" D_CMND_FN "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TELEPERIOD "|" D_CMND_RESET "|" D_CMND_TIME "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_LEDMASK "|" D_CMND_LEDPWM_ON "|" D_CMND_LEDPWM_OFF "|" D_CMND_LEDPWM_MODE "|" D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM"|" D_CMND_SWITCHTEXT "|" @@ -65,7 +65,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = { &CmndModule, &CmndModules, &CmndGpio, &CmndGpios, &CmndTemplate, &CmndPwm, &CmndPwmfrequency, &CmndPwmrange, &CmndButtonDebounce, &CmndSwitchDebounce, &CmndSyslog, &CmndLoghost, &CmndLogport, &CmndSerialBuffer, &CmndSerialSend, &CmndBaudrate, &CmndSerialConfig, &CmndSerialDelimiter, - &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig, &CmndWifi, + &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig, &CmndWifi, &CmndDnsTimeout, &CmndDevicename, &CmndFriendlyname, &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd, &CmndTimeDst, &CmndAltitude, &CmndLedPower, &CmndLedState, &CmndLedMask, &CmndLedPwmOn, &CmndLedPwmOff, &CmndLedPwmMode, &CmndWifiPower, &CmndTempOffset, &CmndHumOffset, &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, &CmndSwitchText, @@ -2277,6 +2277,15 @@ void CmndWifi(void) Response_P(PSTR("{\"" D_JSON_WIFI "\":\"%s\",\"" D_JSON_WIFI_MODE "\":\"11%c\"}"), GetStateText(Settings->flag4.network_wifi), pgm_read_byte(&kWifiPhyMode[WiFi.getPhyMode() & 0x3]) ); } +void CmndDnsTimeout(void) { + // Set timeout between 100 and 20000 mSec + if ((XdrvMailbox.payload >= 100) && (XdrvMailbox.payload <= 20000)) { + Settings->dns_timeout = XdrvMailbox.payload; + DnsClient.setTimeout(Settings->dns_timeout); + } + ResponseCmndNumber(Settings->dns_timeout); +} + #ifdef USE_I2C void CmndI2cScan(void) { diff --git a/tasmota/tasmota_support/support_rtc.ino b/tasmota/tasmota_support/support_rtc.ino index aac70eac4..85efa6a84 100644 --- a/tasmota/tasmota_support/support_rtc.ino +++ b/tasmota/tasmota_support/support_rtc.ino @@ -489,10 +489,15 @@ void RtcInit(void) { if (Settings->cfg_timestamp > START_VALID_TIME) { // Fix file timestamp while utctime is not synced - uint32_t local_time = Settings->cfg_timestamp +1; - RtcGetDaylightSavingTimes(local_time); - local_time += RtcTimeZoneOffset(local_time); + uint32_t utc_time = Settings->cfg_timestamp; + if (RtcSettings.utc_time > utc_time) { + utc_time = RtcSettings.utc_time; + } + utc_time++; + RtcGetDaylightSavingTimes(utc_time); + uint32_t local_time = utc_time + RtcTimeZoneOffset(utc_time); RtcSetTimeOfDay(local_time); +// AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: Timestamp %s"), GetDT(local_time).c_str()); } } diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index c71826c38..7215e4682 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -729,44 +729,20 @@ void wifiKeepAlive(void) { } #endif // ESP8266 -bool WifiPollDns(void) { - // WiFi.hostByName takes over ten seconds if no DNS server found - // This function checks to find the DNS server within 1 second - // This is an alternative for ping using less resources and some DNS server do not respond to pings (ICMP) - // See https://github.com/letscontrolit/ESPEasy/issues/1494#issuecomment-397872538 - WiFiClient DnsClient; - -#ifdef ESP8266 - DnsClient.setTimeout(1000); -#else - DnsClient.setTimeout(1); -#endif - uint32_t i = 3; // Check DNS1 only (to keep blocking to a minimum of 1 second) -// for (i = 3; i < 5; i++) { // Check DNS1 and DNS2 - uint32_t dns_address = (!TasmotaGlobal.global_state.eth_down) ? Settings->eth_ipv4_address[i] : Settings->ipv4_address[i]; - if (DnsClient.connect((IPAddress)dns_address, 53)) { - DnsClient.stop(); - return true; - } -// } - AddLog(LOG_LEVEL_DEBUG, PSTR("DNS: Disconnected")); - return false; +bool WifiHostByName(const char* aHostname, IPAddress& aResult) { + // Use this instead of WiFi.hostByName or connect(host_name,.. to block less if DNS server is not found + uint32_t dns_address = (!TasmotaGlobal.global_state.eth_down) ? Settings->eth_ipv4_address[3] : Settings->ipv4_address[3]; + DnsClient.begin((IPAddress)dns_address); + if (DnsClient.getHostByName(aHostname, aResult) != 1) { + AddLog(LOG_LEVEL_DEBUG, PSTR("DNS: Unable to resolve '%s'"), aHostname); + return false; + } + return true; } -int WifiHostByName(const char* aHostname, IPAddress& aResult) { - // Use this instead of WiFi.hostByName or connect(host_name,.. to block less if DNS server is not found - aResult = (uint32_t)(0); - if (aResult.fromString(aHostname)) { - // Host name is already an IP address so use it! - return 1; - } - else if (WifiPollDns() && WiFi.hostByName(aHostname, aResult)) { - // Host name resolved - if (0xFFFFFFFF != (uint32_t)aResult) { - return 1; - } - } - return 0; +bool WifiDnsPresent(const char* aHostname) { + IPAddress aResult; + return WifiHostByName(aHostname, aResult); } void WifiPollNtp() { @@ -826,7 +802,7 @@ uint32_t WifiGetNtp(void) { } if (!WifiHostByName(ntp_server, time_server_ip)) { ntp_server_id++; - AddLog(LOG_LEVEL_DEBUG, PSTR("NTP: Unable to resolve '%s'"), ntp_server); +// AddLog(LOG_LEVEL_DEBUG, PSTR("NTP: Unable to resolve '%s'"), ntp_server); return 0; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino index 94abb0547..6867454ca 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino @@ -992,8 +992,6 @@ void MqttConnected(void) { } void MqttReconnect(void) { - char stopic[TOPSZ]; - Mqtt.allowed = Settings->flag.mqtt_enabled && (TasmotaGlobal.restart_flag == 0); // SetOption3 - Enable MQTT, and don't connect if restart in process if (Mqtt.allowed) { #if defined(USE_MQTT_AZURE_DPS_SCOPEID) && defined(USE_MQTT_AZURE_DPS_PRESHAREDKEY) @@ -1040,6 +1038,23 @@ void MqttReconnect(void) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT D_ATTEMPTING_CONNECTION)); + if (MqttClient.connected()) { MqttClient.disconnect(); } + + MqttSetClientTimeout(); + + MqttClient.setCallback(MqttDataHandler); + + // Keep using hostname to solve rc -4 issues + if (!WifiDnsPresent(SettingsText(SET_MQTT_HOST))) { + MqttDisconnected(-5); // MQTT_DNS_DISCONNECTED + return; + } + MqttClient.setServer(SettingsText(SET_MQTT_HOST), Settings->mqtt_port); + + if (2 == Mqtt.initial_connection_state) { // Executed once just after power on and wifi is connected + Mqtt.initial_connection_state = 1; + } + char *mqtt_user = nullptr; char *mqtt_pwd = nullptr; if (strlen(SettingsText(SET_MQTT_USER))) { @@ -1049,49 +1064,37 @@ void MqttReconnect(void) { mqtt_pwd = SettingsText(SET_MQTT_PWD); } - GetTopic_P(stopic, TELE, TasmotaGlobal.mqtt_topic, S_LWT); - Response_P(S_LWT_OFFLINE); - - if (MqttClient.connected()) { MqttClient.disconnect(); } - - MqttSetClientTimeout(); - #ifdef USE_MQTT_TLS + uint32_t mqtt_connect_time = millis(); if (Mqtt.mqtt_tls) { tlsClient->stop(); } else { -// EspClient = WiFiClient(); // Wifi Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497) MqttClient.setClient(EspClient); } -#else -// EspClient = WiFiClient(); // Wifi Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497) - MqttClient.setClient(EspClient); -#endif - - if (2 == Mqtt.initial_connection_state) { // Executed once just after power on and wifi is connected - Mqtt.initial_connection_state = 1; - } - - MqttClient.setCallback(MqttDataHandler); -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) +#ifdef USE_MQTT_AWS_IOT // re-assign private keys in case it was updated in between if (Mqtt.mqtt_tls) { if ((nullptr != AWS_IoT_Private_Key) && (nullptr != AWS_IoT_Client_Certificate)) { + // if private key is there, we remove user/pwd + mqtt_user = nullptr; + mqtt_pwd = nullptr; tlsClient->setClientECCert(AWS_IoT_Client_Certificate, AWS_IoT_Private_Key, 0xFFFF /* all usages, don't care */, 0); } } -#endif - IPAddress mqtt_host_ip; - if (!WifiHostByName(SettingsText(SET_MQTT_HOST), mqtt_host_ip)) { - MqttDisconnected(-5); // MQTT_DNS_DISCONNECTED - return; +#endif // USE_MQTT_AWS_IOT +#ifdef USE_MQTT_AZURE_IOT + String azureMqtt_password = SettingsText(SET_MQTT_PWD); + if (azureMqtt_password.indexOf("SharedAccessSignature") == -1) { + // assuming a PreSharedKey was provided, calculating a SAS Token into azureMqtt_password + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "Authenticating with an Azure IoT Hub Token")); + azureMqtt_password = AzurePSKtoToken(SettingsText(SET_MQTT_HOST), SettingsText(SET_MQTT_CLIENT), SettingsText(SET_MQTT_PWD)); } - MqttClient.setServer(mqtt_host_ip, Settings->mqtt_port); - - uint32_t mqtt_connect_time = millis(); -#if defined(USE_MQTT_TLS) + String azureMqtt_userString = String(SettingsText(SET_MQTT_HOST)) + "/" + String(SettingsText(SET_MQTT_CLIENT)); + "/?api-version=2018-06-30"; + mqtt_user = (char*)azureMqtt_userString.c_str(); + mqtt_pwd = (char*)azureMqtt_password.c_str(); +#endif // USE_MQTT_AZURE_IOT bool allow_all_fingerprints = false; bool learn_fingerprint1 = false; bool learn_fingerprint2 = false; @@ -1105,31 +1108,21 @@ void MqttReconnect(void) { allow_all_fingerprints |= learn_fingerprint2; tlsClient->setPubKeyFingerprint(Settings->mqtt_fingerprint[0], Settings->mqtt_fingerprint[1], allow_all_fingerprints); } -#endif - bool lwt_retain = Settings->flag4.mqtt_no_retain ? false : true; // no retained last will if "no_retain" -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) - if (Mqtt.mqtt_tls) { - if ((nullptr != AWS_IoT_Private_Key) && (nullptr != AWS_IoT_Client_Certificate)) { - // if private key is there, we remove user/pwd - mqtt_user = nullptr; - mqtt_pwd = nullptr; - } - } -#endif +#else // No USE_MQTT_TLS + MqttClient.setClient(EspClient); +#endif // USE_MQTT_TLS -#ifdef USE_MQTT_AZURE_IOT - String azureMqtt_password = SettingsText(SET_MQTT_PWD); - if (azureMqtt_password.indexOf("SharedAccessSignature") == -1) { - // assuming a PreSharedKey was provided, calculating a SAS Token into azureMqtt_password - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "Authenticating with an Azure IoT Hub Token")); - azureMqtt_password = AzurePSKtoToken(SettingsText(SET_MQTT_HOST), SettingsText(SET_MQTT_CLIENT), SettingsText(SET_MQTT_PWD)); - } - - String azureMqtt_userString = String(SettingsText(SET_MQTT_HOST)) + "/" + String(SettingsText(SET_MQTT_CLIENT)); + "/?api-version=2018-06-30"; - if (MqttClient.connect(TasmotaGlobal.mqtt_client, azureMqtt_userString.c_str(), azureMqtt_password.c_str(), stopic, 1, lwt_retain, ResponseData(), Settings->flag5.mqtt_persistent ? 0:1)) { -#else - if (MqttClient.connect(TasmotaGlobal.mqtt_client, mqtt_user, mqtt_pwd, stopic, 1, lwt_retain, ResponseData(), Settings->flag5.mqtt_persistent ? 0:1)) { -#endif // USE_MQTT_AZURE_IOT + char stopic[TOPSZ]; + GetTopic_P(stopic, TELE, TasmotaGlobal.mqtt_topic, S_LWT); + Response_P(S_LWT_OFFLINE); + if (MqttClient.connect(TasmotaGlobal.mqtt_client, + mqtt_user, + mqtt_pwd, + stopic, // Will topic + 1, // Will QoS + Settings->flag4.mqtt_no_retain ? false : true, // No retained last will if "no_retain", + ResponseData(), // Will message + Settings->flag5.mqtt_persistent ? 0 : 1)) { // Clean Session #ifdef USE_MQTT_TLS if (Mqtt.mqtt_tls) { #ifdef ESP8266 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino b/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino index 5a0ab9097..4390bd1d9 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino @@ -244,7 +244,7 @@ extern "C" { // -2: unable to resolve address int32_t t_ping_start(const char *hostname, uint32_t count) { IPAddress ipfull; - if (!WiFi.hostByName(hostname, ipfull)) { + if (!WifiHostByName(hostname, ipfull)) { ipfull = 0xFFFFFFFF; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_40_telegram.ino b/tasmota/tasmota_xdrv_driver/xdrv_40_telegram.ino index a988fff8f..56d0d882d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_40_telegram.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_40_telegram.ino @@ -105,8 +105,11 @@ String TelegramConnectToTelegram(const String &command) { if (!TelegramInit()) { return ""; } - String host = F("api.telegram.org"); String response = ""; + String host = F("api.telegram.org"); + if (!WifiDnsPresent(host.c_str())) { + return response; + } uint32_t tls_connect_time = millis(); if (telegramClient->connect(host.c_str(), 443)) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index e80f585ce..f89ed23c6 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -23,6 +23,7 @@ #include #include "be_mem.h" +#include "be_object.h" /*********************************************************************************************\ * AES class @@ -30,15 +31,6 @@ \*********************************************************************************************/ extern "C" { - int free_br_obj(bvm* vm) { - int argc = be_top(vm); - if (argc > 0) { - void * obj = be_tocomptr(vm, 1); - if (obj != NULL) { be_os_free(obj); } - } - be_return_nil(vm); - } - // `AES_GCM.init(secret_key:bytes(32), iv:bytes(12)) -> instance` int32_t m_aes_gcm_init(struct bvm *vm); int32_t m_aes_gcm_init(struct bvm *vm) { @@ -64,14 +56,14 @@ extern "C" { br_aes_small_ctr_keys * ctr_ctx = (br_aes_small_ctr_keys *) be_os_malloc(sizeof(br_aes_small_ctr_keys)); if (!ctr_ctx) { be_throw(vm, BE_MALLOC_FAIL); } br_aes_small_ctr_init(ctr_ctx, bytes, length); - be_newcomobj(vm, ctr_ctx, &free_br_obj); + be_newcomobj(vm, ctr_ctx, &be_commonobj_destroy_generic); be_setmember(vm, 1, ".p1"); // Initialize an AES GCM structure based on this CTR engine br_gcm_context * gcm_ctx = (br_gcm_context *) be_os_malloc(sizeof(br_gcm_context)); if (!gcm_ctx) { be_throw(vm, BE_MALLOC_FAIL); } br_gcm_init(gcm_ctx, &ctr_ctx->vtable, &br_ghash_ctmul32); - be_newcomobj(vm, gcm_ctx, &free_br_obj); + be_newcomobj(vm, gcm_ctx, &be_commonobj_destroy_generic); be_setmember(vm, 1, ".p2"); // Reset GCM context with provided IV