Merge branch 'development' into HP303B

# Conflicts:
#	tasmota/support_features.ino Resolved
#	tools/decode-status.py Resolved
This commit is contained in:
Robert Jaakke 2020-06-11 21:56:27 +02:00
commit 9835c55203
22 changed files with 1786 additions and 1212 deletions

View File

@ -52,7 +52,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
## Changelog ## Changelog
### Version 8.3.1.2 ### Version 8.3.1.3
- Change IRremoteESP8266 library updated to v2.7.7 - Change IRremoteESP8266 library updated to v2.7.7
- Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519) - Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519)
@ -76,3 +76,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
- Add support for up to two BH1750 sensors controlled by commands ``BH1750Resolution`` and ``BH1750MTime`` (#8139) - Add support for up to two BH1750 sensors controlled by commands ``BH1750Resolution`` and ``BH1750MTime`` (#8139)
- Add support for up to eight MCP9808 temperature sensors by device111 (#8594) - Add support for up to eight MCP9808 temperature sensors by device111 (#8594)
- Add support for BL0940 energy monitor as used in Blitzwolf BW-SHP10 (#8175) - Add support for BL0940 energy monitor as used in Blitzwolf BW-SHP10 (#8175)
- Add initial support for Telegram bot (#8619)

View File

@ -1,5 +1,9 @@
## Unreleased (development) ## Unreleased (development)
### 8.3.1.3 20200611
- Add initial support for Telegram bot (#8619)
### 8.3.1.2 20200522 ### 8.3.1.2 20200522
- Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]`` - Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]``

View File

@ -40,7 +40,7 @@ uint32_t *stack_thunk_light_save = NULL; /* Saved A1 while in BearSSL */
uint32_t stack_thunk_light_refcnt = 0; uint32_t stack_thunk_light_refcnt = 0;
//#define _stackSize (5600/4) //#define _stackSize (5600/4)
#if defined(USE_MQTT_AWS_IOT) || defined(USE_MQTT_TLS_FORCE_EC_CIPHER) #ifdef USE_MQTT_TLS_FORCE_EC_CIPHER
#define _stackSize (5300/4) // using a light version of bearssl we can save 300 bytes #define _stackSize (5300/4) // using a light version of bearssl we can save 300 bytes
#else #else
#define _stackSize (3600/4) // using a light version of bearssl we can save 2k #define _stackSize (3600/4) // using a light version of bearssl we can save 2k

View File

@ -52,7 +52,7 @@ extern uint32_t stack_thunk_light_refcnt;
// Thunking macro // Thunking macro
#define make_stack_thunk_light(fcnToThunk) \ #define make_stack_thunk_light(fcnToThunk) \
__asm("\n\ __asm__("\n\
.text\n\ .text\n\
.literal_position\n\ .literal_position\n\
.literal .LC_STACK_VALUE"#fcnToThunk", 0xdeadbeef\n\ .literal .LC_STACK_VALUE"#fcnToThunk", 0xdeadbeef\n\

1827
tasmota/WiFiClientSecureLightBearSSL.cpp Normal file → Executable file

File diff suppressed because it is too large Load Diff

442
tasmota/WiFiClientSecureLightBearSSL.h Normal file → Executable file
View File

@ -1,221 +1,221 @@
/* /*
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
- Mostly compatible with Arduino WiFi shield library and standard - Mostly compatible with Arduino WiFi shield library and standard
WiFiClient/ServerSecure (except for certificate handling). WiFiClient/ServerSecure (except for certificate handling).
Copyright (c) 2018 Earle F. Philhower, III Copyright (c) 2018 Earle F. Philhower, III
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <core_version.h> #include <core_version.h>
#ifndef wificlientlightbearssl_h #ifndef wificlientlightbearssl_h
#define wificlientlightbearssl_h #define wificlientlightbearssl_h
#if defined(USE_MQTT_TLS) || defined (USE_SENDMAIL) #ifdef USE_TLS
#include <vector> #include <vector>
#include "WiFiClient.h" #include "WiFiClient.h"
#include <t_bearssl.h> #include <t_bearssl.h>
namespace BearSSL { namespace BearSSL {
class WiFiClientSecure_light : public WiFiClient { class WiFiClientSecure_light : public WiFiClient {
public: public:
WiFiClientSecure_light(int recv, int xmit); WiFiClientSecure_light(int recv, int xmit);
~WiFiClientSecure_light() override; ~WiFiClientSecure_light() override;
void allocateBuffers(void); void allocateBuffers(void);
int connect(IPAddress ip, uint16_t port) override; int connect(IPAddress ip, uint16_t port) override;
int connect(const char* name, uint16_t port) override; int connect(const char* name, uint16_t port) override;
uint8_t connected() override; uint8_t connected() override;
size_t write(const uint8_t *buf, size_t size) override; size_t write(const uint8_t *buf, size_t size) override;
size_t write_P(PGM_P buf, size_t size) override; size_t write_P(PGM_P buf, size_t size) override;
size_t write(const char *buf) { size_t write(const char *buf) {
return write((const uint8_t*)buf, strlen(buf)); return write((const uint8_t*)buf, strlen(buf));
} }
size_t write_P(const char *buf) { size_t write_P(const char *buf) {
return write_P((PGM_P)buf, strlen_P(buf)); return write_P((PGM_P)buf, strlen_P(buf));
} }
size_t write(Stream& stream); // Note this is not virtual size_t write(Stream& stream); // Note this is not virtual
int read(uint8_t *buf, size_t size) override; int read(uint8_t *buf, size_t size) override;
int available() override; int available() override;
int read() override; int read() override;
int peek() override; int peek() override;
size_t peekBytes(uint8_t *buffer, size_t length) override; size_t peekBytes(uint8_t *buffer, size_t length) override;
bool flush(unsigned int maxWaitMs); bool flush(unsigned int maxWaitMs);
bool stop(unsigned int maxWaitMs); bool stop(unsigned int maxWaitMs);
void flush() override { (void)flush(0); } void flush() override { (void)flush(0); }
void stop() override { (void)stop(0); } void stop() override { (void)stop(0); }
// Only check SHA1 fingerprint of public key // Only check SHA1 fingerprint of public key
void setPubKeyFingerprint(const uint8_t *f1, const uint8_t *f2, void setPubKeyFingerprint(const uint8_t *f1, const uint8_t *f2,
bool f_any = false) { bool f_any = false) {
_fingerprint1 = f1; _fingerprint1 = f1;
_fingerprint2 = f2; _fingerprint2 = f2;
_fingerprint_any = f_any; _fingerprint_any = f_any;
} }
const uint8_t * getRecvPubKeyFingerprint(void) { const uint8_t * getRecvPubKeyFingerprint(void) {
return _recv_fingerprint; return _recv_fingerprint;
} }
void setClientECCert(const br_x509_certificate *cert, const br_ec_private_key *sk, void setClientECCert(const br_x509_certificate *cert, const br_ec_private_key *sk,
unsigned allowed_usages, unsigned cert_issuer_key_type); unsigned allowed_usages, unsigned cert_issuer_key_type);
void setTrustAnchor(const br_x509_trust_anchor *ta); void setTrustAnchor(const br_x509_trust_anchor *ta);
// Sets the requested buffer size for transmit and receive // Sets the requested buffer size for transmit and receive
void setBufferSizes(int recv, int xmit); void setBufferSizes(int recv, int xmit);
// Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection) // Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection)
int getMFLNStatus() { int getMFLNStatus() {
return connected() && br_ssl_engine_get_mfln_negotiated(_eng); return connected() && br_ssl_engine_get_mfln_negotiated(_eng);
} }
int32_t getLastError(void) { int32_t getLastError(void) {
if (_last_error) { if (_last_error) {
return _last_error; return _last_error;
} else { } else {
return br_ssl_engine_last_error(_eng); return br_ssl_engine_last_error(_eng);
} }
} }
inline void setLastError(int32_t err) { inline void setLastError(int32_t err) {
_last_error = err; _last_error = err;
} }
inline void clearLastError(void) { inline void clearLastError(void) {
_last_error = 0; _last_error = 0;
} }
inline size_t getMaxThunkStackUse(void) { inline size_t getMaxThunkStackUse(void) {
return _max_thunkstack_use; return _max_thunkstack_use;
} }
private: private:
void _clear(); void _clear();
bool _ctx_present; bool _ctx_present;
std::shared_ptr<br_ssl_client_context> _sc; std::shared_ptr<br_ssl_client_context> _sc;
inline bool ctx_present() { inline bool ctx_present() {
return _ctx_present; return _ctx_present;
} }
br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts
std::shared_ptr<unsigned char> _iobuf_in; std::shared_ptr<unsigned char> _iobuf_in;
std::shared_ptr<unsigned char> _iobuf_out; std::shared_ptr<unsigned char> _iobuf_out;
time_t _now; time_t _now;
int _iobuf_in_size; int _iobuf_in_size;
int _iobuf_out_size; int _iobuf_out_size;
bool _handshake_done; bool _handshake_done;
uint64_t _last_error; uint64_t _last_error;
bool _fingerprint_any; // accept all fingerprints bool _fingerprint_any; // accept all fingerprints
const uint8_t *_fingerprint1; // fingerprint1 to be checked against const uint8_t *_fingerprint1; // fingerprint1 to be checked against
const uint8_t *_fingerprint2; // fingerprint2 to be checked against const uint8_t *_fingerprint2; // fingerprint2 to be checked against
uint8_t _recv_fingerprint[20]; // fingerprint received uint8_t _recv_fingerprint[20]; // fingerprint received
unsigned char *_recvapp_buf; unsigned char *_recvapp_buf;
size_t _recvapp_len; size_t _recvapp_len;
bool _clientConnected(); // Is the underlying socket alive? bool _clientConnected(); // Is the underlying socket alive?
bool _connectSSL(const char *hostName); // Do initial SSL handshake bool _connectSSL(const char *hostName); // Do initial SSL handshake
void _freeSSL(); void _freeSSL();
int _run_until(unsigned target, bool blocking = true); int _run_until(unsigned target, bool blocking = true);
size_t _write(const uint8_t *buf, size_t size, bool pmem); size_t _write(const uint8_t *buf, size_t size, bool pmem);
bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting
// Optional client certificate // Optional client certificate
const br_x509_certificate *_chain_P; // PROGMEM certificate const br_x509_certificate *_chain_P; // PROGMEM certificate
const br_ec_private_key *_sk_ec_P; // PROGMEM private key const br_ec_private_key *_sk_ec_P; // PROGMEM private key
const br_x509_trust_anchor *_ta_P; // PROGMEM server CA const br_x509_trust_anchor *_ta_P; // PROGMEM server CA
unsigned _allowed_usages; unsigned _allowed_usages;
unsigned _cert_issuer_key_type; unsigned _cert_issuer_key_type;
// record the maximum use of ThunkStack for monitoring // record the maximum use of ThunkStack for monitoring
size_t _max_thunkstack_use; size_t _max_thunkstack_use;
}; };
#define ERR_OOM -1000 #define ERR_OOM -1000
#define ERR_CANT_RESOLVE_IP -1001 #define ERR_CANT_RESOLVE_IP -1001
#define ERR_TCP_CONNECT -1002 #define ERR_TCP_CONNECT -1002
#define ERR_MISSING_EC_KEY -1003 // #define ERR_MISSING_EC_KEY -1003 // deprecated, AWS IoT is not called if the private key is not present
#define ERR_MISSING_CA -1004 #define ERR_MISSING_CA -1004
// For reference, BearSSL error codes: // For reference, BearSSL error codes:
// #define BR_ERR_OK 0 // #define BR_ERR_OK 0
// #define BR_ERR_BAD_PARAM 1 // #define BR_ERR_BAD_PARAM 1
// #define BR_ERR_BAD_STATE 2 // #define BR_ERR_BAD_STATE 2
// #define BR_ERR_UNSUPPORTED_VERSION 3 // #define BR_ERR_UNSUPPORTED_VERSION 3
// #define BR_ERR_BAD_VERSION 4 // #define BR_ERR_BAD_VERSION 4
// #define BR_ERR_BAD_LENGTH 5 // #define BR_ERR_BAD_LENGTH 5
// #define BR_ERR_TOO_LARGE 6 // #define BR_ERR_TOO_LARGE 6
// #define BR_ERR_BAD_MAC 7 // #define BR_ERR_BAD_MAC 7
// #define BR_ERR_NO_RANDOM 8 // #define BR_ERR_NO_RANDOM 8
// #define BR_ERR_UNKNOWN_TYPE 9 // #define BR_ERR_UNKNOWN_TYPE 9
// #define BR_ERR_UNEXPECTED 10 // #define BR_ERR_UNEXPECTED 10
// #define BR_ERR_BAD_CCS 12 // #define BR_ERR_BAD_CCS 12
// #define BR_ERR_BAD_ALERT 13 // #define BR_ERR_BAD_ALERT 13
// #define BR_ERR_BAD_HANDSHAKE 14 // #define BR_ERR_BAD_HANDSHAKE 14
// #define BR_ERR_OVERSIZED_ID 15 // #define BR_ERR_OVERSIZED_ID 15
// #define BR_ERR_BAD_CIPHER_SUITE 16 // #define BR_ERR_BAD_CIPHER_SUITE 16
// #define BR_ERR_BAD_COMPRESSION 17 // #define BR_ERR_BAD_COMPRESSION 17
// #define BR_ERR_BAD_FRAGLEN 18 // #define BR_ERR_BAD_FRAGLEN 18
// #define BR_ERR_BAD_SECRENEG 19 // #define BR_ERR_BAD_SECRENEG 19
// #define BR_ERR_EXTRA_EXTENSION 20 // #define BR_ERR_EXTRA_EXTENSION 20
// #define BR_ERR_BAD_SNI 21 // #define BR_ERR_BAD_SNI 21
// #define BR_ERR_BAD_HELLO_DONE 22 // #define BR_ERR_BAD_HELLO_DONE 22
// #define BR_ERR_LIMIT_EXCEEDED 23 // #define BR_ERR_LIMIT_EXCEEDED 23
// #define BR_ERR_BAD_FINISHED 24 // #define BR_ERR_BAD_FINISHED 24
// #define BR_ERR_RESUME_MISMATCH 25 // #define BR_ERR_RESUME_MISMATCH 25
// #define BR_ERR_INVALID_ALGORITHM 26 // #define BR_ERR_INVALID_ALGORITHM 26
// #define BR_ERR_BAD_SIGNATURE 27 // #define BR_ERR_BAD_SIGNATURE 27
// #define BR_ERR_WRONG_KEY_USAGE 28 // #define BR_ERR_WRONG_KEY_USAGE 28
// #define BR_ERR_NO_CLIENT_AUTH 29 // #define BR_ERR_NO_CLIENT_AUTH 29
// #define BR_ERR_IO 31 // #define BR_ERR_IO 31
// #define BR_ERR_RECV_FATAL_ALERT 256 // #define BR_ERR_RECV_FATAL_ALERT 256
// #define BR_ERR_SEND_FATAL_ALERT 512 // #define BR_ERR_SEND_FATAL_ALERT 512
// #define BR_ERR_X509_OK 32 // #define BR_ERR_X509_OK 32
// #define BR_ERR_X509_INVALID_VALUE 33 // #define BR_ERR_X509_INVALID_VALUE 33
// #define BR_ERR_X509_TRUNCATED 34 // #define BR_ERR_X509_TRUNCATED 34
// #define BR_ERR_X509_EMPTY_CHAIN 35 // #define BR_ERR_X509_EMPTY_CHAIN 35
// #define BR_ERR_X509_INNER_TRUNC 36 // #define BR_ERR_X509_INNER_TRUNC 36
// #define BR_ERR_X509_BAD_TAG_CLASS 37 // #define BR_ERR_X509_BAD_TAG_CLASS 37
// #define BR_ERR_X509_BAD_TAG_VALUE 38 // #define BR_ERR_X509_BAD_TAG_VALUE 38
// #define BR_ERR_X509_INDEFINITE_LENGTH 39 // #define BR_ERR_X509_INDEFINITE_LENGTH 39
// #define BR_ERR_X509_EXTRA_ELEMENT 40 // #define BR_ERR_X509_EXTRA_ELEMENT 40
// #define BR_ERR_X509_UNEXPECTED 41 // #define BR_ERR_X509_UNEXPECTED 41
// #define BR_ERR_X509_NOT_CONSTRUCTED 42 // #define BR_ERR_X509_NOT_CONSTRUCTED 42
// #define BR_ERR_X509_NOT_PRIMITIVE 43 // #define BR_ERR_X509_NOT_PRIMITIVE 43
// #define BR_ERR_X509_PARTIAL_BYTE 44 // #define BR_ERR_X509_PARTIAL_BYTE 44
// #define BR_ERR_X509_BAD_BOOLEAN 45 // #define BR_ERR_X509_BAD_BOOLEAN 45
// #define BR_ERR_X509_OVERFLOW 46 // #define BR_ERR_X509_OVERFLOW 46
// #define BR_ERR_X509_BAD_DN 47 // #define BR_ERR_X509_BAD_DN 47
// #define BR_ERR_X509_BAD_TIME 48 // #define BR_ERR_X509_BAD_TIME 48
// #define BR_ERR_X509_UNSUPPORTED 49 // #define BR_ERR_X509_UNSUPPORTED 49
// #define BR_ERR_X509_LIMIT_EXCEEDED 50 // #define BR_ERR_X509_LIMIT_EXCEEDED 50
// #define BR_ERR_X509_WRONG_KEY_TYPE 51 // #define BR_ERR_X509_WRONG_KEY_TYPE 51
// #define BR_ERR_X509_BAD_SIGNATURE 52 // #define BR_ERR_X509_BAD_SIGNATURE 52
// #define BR_ERR_X509_TIME_UNKNOWN 53 // #define BR_ERR_X509_TIME_UNKNOWN 53
// #define BR_ERR_X509_EXPIRED 54 // #define BR_ERR_X509_EXPIRED 54
// #define BR_ERR_X509_DN_MISMATCH 55 // #define BR_ERR_X509_DN_MISMATCH 55
// #define BR_ERR_X509_BAD_SERVER_NAME 56 // #define BR_ERR_X509_BAD_SERVER_NAME 56
// #define BR_ERR_X509_CRITICAL_EXTENSION 57 // #define BR_ERR_X509_CRITICAL_EXTENSION 57
// #define BR_ERR_X509_NOT_CA 58 // #define BR_ERR_X509_NOT_CA 58
// #define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59 // #define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59
// #define BR_ERR_X509_WEAK_PUBLIC_KEY 60 // #define BR_ERR_X509_WEAK_PUBLIC_KEY 60
// #define BR_ERR_X509_NOT_TRUSTED 62 // #define BR_ERR_X509_NOT_TRUSTED 62
}; };
#endif // USE_MQTT_TLS #endif // USE_TLS
#endif // wificlientlightbearssl_h #endif // wificlientlightbearssl_h

View File

@ -367,6 +367,11 @@
// Full documentation here: https://github.com/arendst/Tasmota/wiki/AWS-IoT // Full documentation here: https://github.com/arendst/Tasmota/wiki/AWS-IoT
// #define USE_4K_RSA // Support 4096 bits certificates, instead of 2048 // #define USE_4K_RSA // Support 4096 bits certificates, instead of 2048
// -- Telegram Protocol ---------------------------
//#define USE_TELEGRAM // Support for Telegram protocol (+49k code, +7.0k mem and +4.8k additional during connection handshake)
#define USE_TELEGRAM_FINGERPRINT "\xB2\x72\x47\xA6\x69\x8C\x3C\x69\xF9\x58\x6C\xF3\x60\x02\xFB\x83\xFA\x8B\x1F\x23" // Telegram api.telegram.org TLS public key fingerpring
// #define USE_MQTT_TLS_CA_CERT // Use certificate instead of fingerprint
// -- KNX IP Protocol ----------------------------- // -- KNX IP Protocol -----------------------------
//#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem) //#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem)
#define USE_KNX_WEB_MENU // Enable KNX WEB MENU (+8.3k code, +144 mem) #define USE_KNX_WEB_MENU // Enable KNX WEB MENU (+8.3k code, +144 mem)
@ -753,4 +758,16 @@
#error "Select either USE_RULES or USE_SCRIPT. They can't both be used at the same time" #error "Select either USE_RULES or USE_SCRIPT. They can't both be used at the same time"
#endif #endif
/*********************************************************************************************\
* Post-process compile options for TLS
\*********************************************************************************************/
#if defined(USE_MQTT_TLS) || defined(USE_SENDMAIL) || defined(USE_TELEGRAM)
#define USE_TLS // flag indicates we need to include TLS code
#if defined(USE_MQTT_AWS_IOT) || defined(USE_TELEGRAM)
#define USE_MQTT_TLS_FORCE_EC_CIPHER // AWS IoT and TELEGRAM require EC Cipher
#endif
#endif
#endif // _MY_USER_CONFIG_H_ #endif // _MY_USER_CONFIG_H_

View File

@ -391,8 +391,7 @@ void UpdateQuickPowerCycle(bool update)
* Config Settings.text char array support * Config Settings.text char array support
\*********************************************************************************************/ \*********************************************************************************************/
uint32_t GetSettingsTextLen(void) uint32_t GetSettingsTextLen(void) {
{
char* position = Settings.text_pool; char* position = Settings.text_pool;
for (uint32_t size = 0; size < SET_MAX; size++) { for (uint32_t size = 0; size < SET_MAX; size++) {
while (*position++ != '\0') { } while (*position++ != '\0') { }
@ -400,8 +399,20 @@ uint32_t GetSettingsTextLen(void)
return position - Settings.text_pool; return position - Settings.text_pool;
} }
bool SettingsUpdateText(uint32_t index, const char* replace_me) bool settings_text_mutex = false;
{ uint32_t settings_text_busy_count = 0;
bool SettingsUpdateFinished(void) {
uint32_t wait_loop = 10;
while (settings_text_mutex && wait_loop) { // Wait for any update to finish
yield();
delayMicroseconds(1);
wait_loop--;
}
return (wait_loop > 0); // true if finished
}
bool SettingsUpdateText(uint32_t index, const char* replace_me) {
if (index >= SET_MAX) { if (index >= SET_MAX) {
return false; // Setting not supported - internal error return false; // Setting not supported - internal error
} }
@ -438,16 +449,24 @@ bool SettingsUpdateText(uint32_t index, const char* replace_me)
return false; // Replace text too long return false; // Replace text too long
} }
if (diff != 0) { if (settings_text_mutex && !SettingsUpdateFinished()) {
// Shift Settings.text up or down settings_text_busy_count++;
memmove_P(Settings.text_pool + start_pos + replace_len, Settings.text_pool + end_pos, char_len - end_pos); } else {
} settings_text_mutex = true;
// Replace text
memmove_P(Settings.text_pool + start_pos, replace, replace_len);
// Fill for future use
memset(Settings.text_pool + char_len + diff, 0x00, settings_text_size - char_len - diff);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG "CR %d/%d"), GetSettingsTextLen(), settings_text_size); if (diff != 0) {
// Shift Settings.text up or down
memmove_P(Settings.text_pool + start_pos + replace_len, Settings.text_pool + end_pos, char_len - end_pos);
}
// Replace text
memmove_P(Settings.text_pool + start_pos, replace, replace_len);
// Fill for future use
memset(Settings.text_pool + char_len + diff, 0x00, settings_text_size - char_len - diff);
settings_text_mutex = false;
}
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG "CR %d/%d, Busy %d"), GetSettingsTextLen(), settings_text_size, settings_text_busy_count);
return true; return true;
} }
@ -459,6 +478,7 @@ char* SettingsText(uint32_t index)
if (index >= SET_MAX) { if (index >= SET_MAX) {
position += settings_text_size -1; // Setting not supported - internal error - return empty string position += settings_text_size -1; // Setting not supported - internal error - return empty string
} else { } else {
SettingsUpdateFinished();
for (;index > 0; index--) { for (;index > 0; index--) {
while (*position++ != '\0') { } while (*position++ != '\0') { }
} }

View File

@ -997,7 +997,7 @@ char* ResponseGetTime(uint32_t format, char* time_str)
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":%u"), UtcTime()); snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":%u"), UtcTime());
break; break;
case 3: case 3:
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s.%03d\""), GetDateAndTime(DT_LOCAL).c_str(), RtcMillis()); snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL_MILLIS).c_str());
break; break;
default: default:
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());

View File

@ -575,11 +575,13 @@ void GetFeatures(void)
#ifdef USE_BL0940 #ifdef USE_BL0940
feature6 |= 0x00004000; // xnrg_14_bl0940.ino feature6 |= 0x00004000; // xnrg_14_bl0940.ino
#endif #endif
#ifdef USE_TELEGRAM
feature6 |= 0x00008000; // xdrv_40_telegram.ino
#endif
#ifdef USE_HP303B #ifdef USE_HP303B
feature6 |= 0x00008000; // xsns_73_hp303b.ino feature6 |= 0x00010000; // xsns_73_hp303b.ino
#endif #endif
// feature6 |= 0x00010000;
// feature6 |= 0x00020000; // feature6 |= 0x00020000;
// feature6 |= 0x00040000; // feature6 |= 0x00040000;
// feature6 |= 0x00080000; // feature6 |= 0x00080000;

View File

@ -206,6 +206,14 @@ String GetDateAndTime(uint8_t time_type)
break; break;
} }
String dt = GetDT(time); // 2017-03-07T11:08:02 String dt = GetDT(time); // 2017-03-07T11:08:02
if (DT_LOCAL_MILLIS == time_type) {
char ms[10];
snprintf_P(ms, sizeof(ms), PSTR(".%03d"), RtcMillis());
dt += ms;
time_type = DT_LOCAL;
}
if (Settings.flag3.time_append_timezone && (DT_LOCAL == time_type)) { // SetOption52 - Append timezone to JSON time if (Settings.flag3.time_append_timezone && (DT_LOCAL == time_type)) { // SetOption52 - Append timezone to JSON time
dt += GetTimeZone(); // 2017-03-07T11:08:02-07:00 dt += GetTimeZone(); // 2017-03-07T11:08:02-07:00
} }

View File

@ -214,7 +214,7 @@ enum WeekInMonthOptions {Last, First, Second, Third, Fourth};
enum DayOfTheWeekOptions {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat}; enum DayOfTheWeekOptions {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat};
enum MonthNamesOptions {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; enum MonthNamesOptions {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
enum HemisphereOptions {North, South}; enum HemisphereOptions {North, South};
enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_LOCALNOTZ, DT_DST, DT_STD, DT_RESTART, DT_ENERGY, DT_BOOTCOUNT }; enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_LOCALNOTZ, DT_DST, DT_STD, DT_RESTART, DT_ENERGY, DT_BOOTCOUNT, DT_LOCAL_MILLIS };
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE}; enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
@ -293,7 +293,7 @@ enum SettingsTextIndex { SET_OTAURL,
SET_TEMPLATE_NAME, SET_TEMPLATE_NAME,
SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4, SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4,
SET_DEVICENAME, SET_DEVICENAME,
SET_TELEGRAMTOKEN, SET_TELEGRAM_TOKEN, SET_TELEGRAM_CHATID,
SET_MAX }; SET_MAX };
enum DevGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYPE_UPDATE_COMMAND }; enum DevGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYPE_UPDATE_COMMAND };
@ -321,9 +321,10 @@ enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER, enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER, SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER,
SRC_THERMOSTAT, SRC_MAX }; SRC_THERMOSTAT, SRC_CHAT, SRC_MAX };
const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|" const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|"
"Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|Thermostat"; "Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|"
"Thermostat|Chat";
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };
@ -344,10 +345,10 @@ const SerConfu8 kTasmotaSerialConfig[] PROGMEM = {
SERIAL_5O2, SERIAL_6O2, SERIAL_7O2, SERIAL_8O2 SERIAL_5O2, SERIAL_6O2, SERIAL_7O2, SERIAL_8O2
}; };
enum TuyaSupportedFunctions { TUYA_MCU_FUNC_NONE, TUYA_MCU_FUNC_SWT1 = 1, TUYA_MCU_FUNC_SWT2, TUYA_MCU_FUNC_SWT3, TUYA_MCU_FUNC_SWT4, enum TuyaSupportedFunctions { TUYA_MCU_FUNC_NONE, TUYA_MCU_FUNC_SWT1 = 1, TUYA_MCU_FUNC_SWT2, TUYA_MCU_FUNC_SWT3, TUYA_MCU_FUNC_SWT4,
TUYA_MCU_FUNC_REL1 = 11, TUYA_MCU_FUNC_REL2, TUYA_MCU_FUNC_REL3, TUYA_MCU_FUNC_REL4, TUYA_MCU_FUNC_REL5, TUYA_MCU_FUNC_REL1 = 11, TUYA_MCU_FUNC_REL2, TUYA_MCU_FUNC_REL3, TUYA_MCU_FUNC_REL4, TUYA_MCU_FUNC_REL5,
TUYA_MCU_FUNC_REL6, TUYA_MCU_FUNC_REL7, TUYA_MCU_FUNC_REL8, TUYA_MCU_FUNC_DIMMER = 21, TUYA_MCU_FUNC_POWER = 31, TUYA_MCU_FUNC_REL6, TUYA_MCU_FUNC_REL7, TUYA_MCU_FUNC_REL8, TUYA_MCU_FUNC_DIMMER = 21, TUYA_MCU_FUNC_POWER = 31,
TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE, TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE,
TUYA_MCU_FUNC_REL1_INV = 41, TUYA_MCU_FUNC_REL2_INV, TUYA_MCU_FUNC_REL3_INV, TUYA_MCU_FUNC_REL4_INV, TUYA_MCU_FUNC_REL5_INV, TUYA_MCU_FUNC_REL1_INV = 41, TUYA_MCU_FUNC_REL2_INV, TUYA_MCU_FUNC_REL3_INV, TUYA_MCU_FUNC_REL4_INV, TUYA_MCU_FUNC_REL5_INV,
TUYA_MCU_FUNC_REL6_INV, TUYA_MCU_FUNC_REL7_INV, TUYA_MCU_FUNC_REL8_INV, TUYA_MCU_FUNC_LOWPOWER_MODE = 51, TUYA_MCU_FUNC_LAST = 255 TUYA_MCU_FUNC_REL6_INV, TUYA_MCU_FUNC_REL7_INV, TUYA_MCU_FUNC_REL8_INV, TUYA_MCU_FUNC_LOWPOWER_MODE = 51, TUYA_MCU_FUNC_LAST = 255
}; };

View File

@ -36,9 +36,9 @@
#include "tasmota_version.h" // Tasmota version information #include "tasmota_version.h" // Tasmota version information
#include "tasmota.h" // Enumeration used in my_user_config.h #include "tasmota.h" // Enumeration used in my_user_config.h
#include "my_user_config.h" // Fixed user configurable options #include "my_user_config.h" // Fixed user configurable options
#ifdef USE_MQTT_TLS #ifdef USE_TLS
#include <t_bearssl.h> // We need to include before "tasmota_globals.h" to take precedence over the BearSSL version in Arduino #include <t_bearssl.h> // We need to include before "tasmota_globals.h" to take precedence over the BearSSL version in Arduino
#endif // USE_MQTT_TLS #endif // USE_TLS
#include "tasmota_globals.h" // Function prototypes and global configuration #include "tasmota_globals.h" // Function prototypes and global configuration
#include "i18n.h" // Language support configured by my_user_config.h #include "i18n.h" // Language support configured by my_user_config.h
#include "tasmota_template.h" // Hardware configuration #include "tasmota_template.h" // Hardware configuration

View File

@ -21,9 +21,8 @@
// Please use fingerprint validation instead // Please use fingerprint validation instead
// However, the CA are available below for future use if it appears to be useful // However, the CA are available below for future use if it appears to be useful
#ifdef USE_MQTT_TLS_CA_CERT #if defined(USE_TLS) && defined(USE_MQTT_TLS_CA_CERT)
#ifndef USE_MQTT_AWS_IOT
/*********************************************************************************************\ /*********************************************************************************************\
* LetsEncrypt IdenTrust DST Root CA X3 certificate, RSA 2048 bits SHA 256, valid until 20210417 * LetsEncrypt IdenTrust DST Root CA X3 certificate, RSA 2048 bits SHA 256, valid until 20210417
* *
@ -35,7 +34,7 @@
* remove "static" and add "PROGMEM" * remove "static" and add "PROGMEM"
\*********************************************************************************************/ \*********************************************************************************************/
static const unsigned char PROGMEM TA0_DN[] = { static const unsigned char PROGMEM LetsEncrypt_DN[] = {
0x30, 0x4A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x30, 0x4A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x0D, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72, 0x13, 0x0D, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72,
@ -45,7 +44,7 @@ static const unsigned char PROGMEM TA0_DN[] = {
0x79, 0x20, 0x58, 0x33 0x79, 0x20, 0x58, 0x33
}; };
static const unsigned char PROGMEM TA0_RSA_N[] = { static const unsigned char PROGMEM LetsEncrypt_RSA_N[] = {
0x9C, 0xD3, 0x0C, 0xF0, 0x5A, 0xE5, 0x2E, 0x47, 0xB7, 0x72, 0x5D, 0x37, 0x9C, 0xD3, 0x0C, 0xF0, 0x5A, 0xE5, 0x2E, 0x47, 0xB7, 0x72, 0x5D, 0x37,
0x83, 0xB3, 0x68, 0x63, 0x30, 0xEA, 0xD7, 0x35, 0x26, 0x19, 0x25, 0xE1, 0x83, 0xB3, 0x68, 0x63, 0x30, 0xEA, 0xD7, 0x35, 0x26, 0x19, 0x25, 0xE1,
0xBD, 0xBE, 0x35, 0xF1, 0x70, 0x92, 0x2F, 0xB7, 0xB8, 0x4B, 0x41, 0x05, 0xBD, 0xBE, 0x35, 0xF1, 0x70, 0x92, 0x2F, 0xB7, 0xB8, 0x4B, 0x41, 0x05,
@ -70,27 +69,22 @@ static const unsigned char PROGMEM TA0_RSA_N[] = {
0xD8, 0x7D, 0xC3, 0x93 0xD8, 0x7D, 0xC3, 0x93
}; };
static const unsigned char TA0_RSA_E[] = { static const unsigned char LetsEncrypt_RSA_E[] = {
0x01, 0x00, 0x01 0x01, 0x00, 0x01
}; };
static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = { static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = {
{ (unsigned char *)TA0_DN, sizeof TA0_DN }, { (unsigned char *)LetsEncrypt_DN, sizeof LetsEncrypt_DN },
BR_X509_TA_CA, BR_X509_TA_CA,
{ {
BR_KEYTYPE_RSA, BR_KEYTYPE_RSA,
{ .rsa = { { .rsa = {
(unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N, (unsigned char *)LetsEncrypt_RSA_N, sizeof LetsEncrypt_RSA_N,
(unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E, (unsigned char *)LetsEncrypt_RSA_E, sizeof LetsEncrypt_RSA_E,
} } } }
} }
}; };
#define TAs_NUM 1
#endif // not USE_MQTT_AWS_IOT
#ifdef USE_MQTT_AWS_IOT
/*********************************************************************************************\ /*********************************************************************************************\
* Amazon Root CA, RSA 2048 bits SHA 256, valid until 20380117 * Amazon Root CA, RSA 2048 bits SHA 256, valid until 20380117
* *
@ -103,7 +97,7 @@ static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = {
\*********************************************************************************************/ \*********************************************************************************************/
const unsigned char PROGMEM TA0_DN[] = { const unsigned char PROGMEM AmazonRootCA1_DN[] = {
0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17, 0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17,
@ -111,7 +105,7 @@ const unsigned char PROGMEM TA0_DN[] = {
0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31 0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31
}; };
const unsigned char PROGMEM TA0_RSA_N[] = { const unsigned char PROGMEM AmazonRootCA1_RSA_N[] = {
0xB2, 0x78, 0x80, 0x71, 0xCA, 0x78, 0xD5, 0xE3, 0x71, 0xAF, 0x47, 0x80, 0xB2, 0x78, 0x80, 0x71, 0xCA, 0x78, 0xD5, 0xE3, 0x71, 0xAF, 0x47, 0x80,
0x50, 0x74, 0x7D, 0x6E, 0xD8, 0xD7, 0x88, 0x76, 0xF4, 0x99, 0x68, 0xF7, 0x50, 0x74, 0x7D, 0x6E, 0xD8, 0xD7, 0x88, 0x76, 0xF4, 0x99, 0x68, 0xF7,
0x58, 0x21, 0x60, 0xF9, 0x74, 0x84, 0x01, 0x2F, 0xAC, 0x02, 0x2D, 0x86, 0x58, 0x21, 0x60, 0xF9, 0x74, 0x84, 0x01, 0x2F, 0xAC, 0x02, 0x2D, 0x86,
@ -136,24 +130,79 @@ const unsigned char PROGMEM TA0_RSA_N[] = {
0x9A, 0xC8, 0xAA, 0x0D 0x9A, 0xC8, 0xAA, 0x0D
}; };
static const unsigned char PROGMEM TA0_RSA_E[] = { static const unsigned char PROGMEM AmazonRootCA1_RSA_E[] = {
0x01, 0x00, 0x01 0x01, 0x00, 0x01
}; };
const br_x509_trust_anchor PROGMEM AmazonRootCA1_TA = { const br_x509_trust_anchor PROGMEM AmazonRootCA1_TA = {
{ (unsigned char *)TA0_DN, sizeof TA0_DN }, { (unsigned char *)AmazonRootCA1_DN, sizeof AmazonRootCA1_DN },
BR_X509_TA_CA, BR_X509_TA_CA,
{ {
BR_KEYTYPE_RSA, BR_KEYTYPE_RSA,
{ .rsa = { { .rsa = {
(unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N, (unsigned char *)AmazonRootCA1_RSA_N, sizeof AmazonRootCA1_RSA_N,
(unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E, (unsigned char *)AmazonRootCA1_RSA_E, sizeof AmazonRootCA1_RSA_E,
} } } }
} }
}; };
#define TAs_NUM 1 // we add a separate CA for telegram
/*********************************************************************************************\
* GoDaddy Daddy Secure Certificate Authority - G2, RSA 2048 bits SHA 256, valid until 20220523
*
* to convert do: "brssl ta GoDaddyCA.pem"
* then copy and paste below, chain the generic names to the same as below
* remove "static" and add "PROGMEM"
\*********************************************************************************************/
#endif // USE_MQTT_AWS_IOT const unsigned char GoDaddyCAG2_DN[] PROGMEM = {
0x30, 0x3E, 0x31, 0x21, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13,
0x18, 0x44, 0x6F, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x43, 0x6F, 0x6E, 0x74,
0x72, 0x6F, 0x6C, 0x20, 0x56, 0x61, 0x6C, 0x69, 0x64, 0x61, 0x74, 0x65,
0x64, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10,
0x61, 0x70, 0x69, 0x2E, 0x74, 0x65, 0x6C, 0x65, 0x67, 0x72, 0x61, 0x6D,
0x2E, 0x6F, 0x72, 0x67
};
#endif // USE_MQTT_TLS_CA_CERT const unsigned char GoDaddyCAG2_RSA_N[] PROGMEM = {
0xB4, 0xA3, 0x16, 0x9E, 0x5C, 0x57, 0xC9, 0x89, 0x65, 0xED, 0xEA, 0x78,
0x0B, 0xAE, 0x8A, 0x58, 0x2F, 0xAE, 0x5A, 0xC8, 0x6E, 0x49, 0x8D, 0xFC,
0x57, 0xA5, 0x98, 0x88, 0x78, 0x2E, 0x0B, 0x3C, 0x40, 0x3C, 0x21, 0x2E,
0x9A, 0x94, 0x98, 0x33, 0xA7, 0xE3, 0x42, 0xA7, 0x85, 0xFA, 0xD0, 0x73,
0x84, 0x01, 0x1C, 0x72, 0x39, 0x37, 0x23, 0xB5, 0x56, 0x1D, 0x43, 0xA5,
0x71, 0x14, 0x08, 0x24, 0xA5, 0x39, 0xCC, 0xDE, 0x58, 0x53, 0x94, 0x8E,
0x2A, 0x42, 0xA7, 0x4E, 0x2D, 0x07, 0x32, 0x9E, 0xBA, 0x8B, 0xD3, 0x2A,
0xA9, 0x9E, 0xC0, 0xE3, 0xCE, 0x9A, 0x10, 0x96, 0x45, 0x58, 0x7A, 0xC7,
0x1E, 0x45, 0x14, 0x23, 0x92, 0xBB, 0x54, 0x82, 0x88, 0x94, 0x49, 0xB6,
0xBE, 0x81, 0x21, 0x00, 0x29, 0x6D, 0xC9, 0xCE, 0x8B, 0x39, 0x3A, 0xDC,
0x35, 0x15, 0xD9, 0xEB, 0x47, 0x9C, 0xEF, 0xBA, 0x09, 0x0E, 0x16, 0xE4,
0xD9, 0xEB, 0x72, 0x30, 0xFA, 0x49, 0xAB, 0x98, 0x31, 0x7C, 0xB3, 0xAC,
0x2B, 0x29, 0x91, 0x87, 0x08, 0x41, 0x72, 0x5E, 0x35, 0xC7, 0x87, 0x04,
0x22, 0xF5, 0x48, 0x76, 0x30, 0x6D, 0x88, 0xDF, 0xF2, 0xA5, 0x29, 0x13,
0x70, 0xB3, 0x87, 0x02, 0xD5, 0x6B, 0x58, 0xB1, 0xE8, 0x73, 0xC7, 0xE4,
0xEF, 0x79, 0x86, 0xA4, 0x07, 0x5F, 0x67, 0xB4, 0x79, 0x8D, 0xA4, 0x25,
0x01, 0x82, 0x8C, 0xE0, 0x30, 0x17, 0xCB, 0x4B, 0x5C, 0xFB, 0xEB, 0x4C,
0x12, 0x51, 0xB9, 0xC9, 0x04, 0x1F, 0x7E, 0xD2, 0xF8, 0xBA, 0xF5, 0x35,
0x8D, 0x8A, 0x1C, 0x37, 0x82, 0xF0, 0x15, 0x73, 0x00, 0x6E, 0x3D, 0x1C,
0x76, 0x8B, 0x01, 0x74, 0x81, 0x3D, 0xE4, 0x2C, 0xA7, 0xCC, 0x2F, 0x66,
0xDC, 0x44, 0xA8, 0x27, 0x3F, 0xEA, 0xD0, 0xA7, 0xA8, 0xF1, 0xCB, 0xEA,
0xDA, 0x07, 0x38, 0xBD
};
const unsigned char GoDaddyCAG2_RSA_E[] PROGMEM = {
0x01, 0x00, 0x01
};
const br_x509_trust_anchor GoDaddyCAG2_TA PROGMEM = {
{ (unsigned char *)GoDaddyCAG2_DN, sizeof GoDaddyCAG2_DN },
0,
{
BR_KEYTYPE_RSA,
{ .rsa = {
(unsigned char *)GoDaddyCAG2_RSA_N, sizeof GoDaddyCAG2_RSA_N,
(unsigned char *)GoDaddyCAG2_RSA_E, sizeof GoDaddyCAG2_RSA_E,
} }
}
};
#endif // defined(USE_TLS) && defined(USE_MQTT_TLS_CA_CERT)

View File

@ -88,7 +88,7 @@ extern "C" void resetPins();
const uint16_t WEB_LOG_SIZE = 4000; // Max number of characters in weblog const uint16_t WEB_LOG_SIZE = 4000; // Max number of characters in weblog
#endif #endif
#if defined(USE_MQTT_TLS) && defined(ARDUINO_ESP8266_RELEASE_2_3_0) #if defined(USE_TLS) && defined(ARDUINO_ESP8266_RELEASE_2_3_0)
#error "TLS is no more supported on Core 2.3.0, use 2.4.2 or higher." #error "TLS is no more supported on Core 2.3.0, use 2.4.2 or higher."
#endif #endif

View File

@ -20,7 +20,7 @@
#ifndef _TASMOTA_VERSION_H_ #ifndef _TASMOTA_VERSION_H_
#define _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_
const uint32_t VERSION = 0x08030102; const uint32_t VERSION = 0x08030103;
// Lowest compatible version // Lowest compatible version
const uint32_t VERSION_COMPATIBLE = 0x07010006; const uint32_t VERSION_COMPATIBLE = 0x07010006;

View File

@ -1555,10 +1555,10 @@ void LightState(uint8_t append)
if (!Light.pwm_multi_channels) { if (!Light.pwm_multi_channels) {
if (unlinked) { if (unlinked) {
// RGB and W are unlinked, we display the second Power/Dimmer // RGB and W are unlinked, we display the second Power/Dimmer
ResponseAppend_P(PSTR("\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d" ResponseAppend_P(PSTR("\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "1\":%d"
",\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d"), ",\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "2\":%d"),
Light.device, GetStateText(Light.power & 1), Light.device, light_state.getDimmer(1), Light.device, GetStateText(Light.power & 1), light_state.getDimmer(1),
Light.device + 1, GetStateText(Light.power & 2 ? 1 : 0), Light.device + 1, light_state.getDimmer(2)); Light.device + 1, GetStateText(Light.power & 2 ? 1 : 0), light_state.getDimmer(2));
} else { } else {
GetPowerDevice(scommand, Light.device, sizeof(scommand), Settings.flag.device_index_enable); // SetOption26 - Switch between POWER or POWER1 GetPowerDevice(scommand, Light.device, sizeof(scommand), Settings.flag.device_index_enable); // SetOption26 - Switch between POWER or POWER1
ResponseAppend_P(PSTR("\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d"), scommand, GetStateText(Light.power & 1), ResponseAppend_P(PSTR("\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d"), scommand, GetStateText(Light.power & 1),

View File

@ -3979,8 +3979,7 @@ void ListDir(char *path, uint8_t depth) {
char path[48]; char path[48];
void Script_FileUploadConfiguration(void) void Script_FileUploadConfiguration(void) {
{
uint8_t depth=0; uint8_t depth=0;
strcpy(path,"/"); strcpy(path,"/");
@ -3995,17 +3994,6 @@ void Script_FileUploadConfiguration(void)
} }
} }
void ScriptFileUploadSuccess(void) {
WSContentStart_P(S_INFORMATION);
WSContentSendStyle();
WSContentSend_P(PSTR("<div style='text-align:center;'><b>" D_UPLOAD " <font color='#"));
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "</font></b><br/>"), WebColor(COL_TEXT_SUCCESS));
WSContentSend_P(PSTR("</div><br/>"));
WSContentSend_P(PSTR("<p><form action='%s' method='get'><button>%s</button></form></p>"),"/upl",D_UPL_DONE);
//WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
}
WSContentStart_P(S_SCRIPT_FILE_UPLOAD); WSContentStart_P(S_SCRIPT_FILE_UPLOAD);
WSContentSendStyle(); WSContentSendStyle();
WSContentSend_P(HTTP_FORM_FILE_UPLOAD,D_SDCARD_DIR); WSContentSend_P(HTTP_FORM_FILE_UPLOAD,D_SDCARD_DIR);
@ -4023,13 +4011,22 @@ void Script_FileUploadConfiguration(void)
Web.upload_error = 0; Web.upload_error = 0;
} }
void ScriptFileUploadSuccess(void) {
WSContentStart_P(S_INFORMATION);
WSContentSendStyle();
WSContentSend_P(PSTR("<div style='text-align:center;'><b>" D_UPLOAD " <font color='#"));
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "</font></b><br/>"), WebColor(COL_TEXT_SUCCESS));
WSContentSend_P(PSTR("</div><br/>"));
WSContentSend_P(PSTR("<p><form action='%s' method='get'><button>%s</button></form></p>"),"/upl",D_UPL_DONE);
//WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
}
File upload_file; File upload_file;
void script_upload(void) { void script_upload(void) {
//AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: file upload")); //AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: file upload"));
HTTPUpload& upload = Webserver->upload(); HTTPUpload& upload = Webserver->upload();
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
char npath[48]; char npath[48];

View File

@ -1331,7 +1331,7 @@ void ThermostatGetLocalSensor(uint8_t ctr_output) {
DynamicJsonBuffer jsonBuffer; DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((const char*)mqtt_data); JsonObject& root = jsonBuffer.parseObject((const char*)mqtt_data);
if (root.success()) { if (root.success()) {
const char* value_c = root["THERMOSTAT_SENSOR_NAME"]["Temperature"]; const char* value_c = root[THERMOSTAT_SENSOR_NAME]["Temperature"];
if (value_c != NULL && strlen(value_c) > 0 && (isdigit(value_c[0]) || (value_c[0] == '-' && isdigit(value_c[1])) ) ) { if (value_c != NULL && strlen(value_c) > 0 && (isdigit(value_c[0]) || (value_c[0] == '-' && isdigit(value_c[1])) ) ) {
int16_t value = (int16_t)(CharToFloat(value_c) * 10); int16_t value = (int16_t)(CharToFloat(value_c) * 10);
if ( (value >= -1000) if ( (value >= -1000)

View File

@ -0,0 +1,470 @@
/*
xdrv_40_telegram.ino - telegram for Tasmota
Copyright (C) 2020 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_TELEGRAM
/*********************************************************************************************\
* Telegram bot
*
* Supported commands:
* TmToken <token> - Add your BotFather created bot token (default none)
* TmChatId <chat_id> - Add your BotFather created bot chat id (default none)
* TmPoll <seconds> - Telegram receive poll time (default 10 seconds)
* TmState 0 - Disable telegram sending (default)
* TmState 1 - Enable telegram sending
* TmState 2 - Disable telegram listener (default)
* TmState 3 - Enable telegram listener
* TmState 4 - Disable telegram response echo (default)
* TmState 5 - Enable telegram response echo
* TmSend <data> - If telegram sending is enabled AND a chat id is present then send data
*
* Tested with defines
* #define USE_TELEGRAM // Support for Telegram protocol
* #define USE_TELEGRAM_FINGERPRINT "\xB2\x72\x47\xA6\x69\x8C\x3C\x69\xF9\x58\x6C\xF3\x60\x02\xFB\x83\xFA\x8B\x1F\x23" // Telegram api.telegram.org TLS public key fingerpring
\*********************************************************************************************/
#define XDRV_40 40
#define TELEGRAM_SEND_RETRY 4 // Retries
#define TELEGRAM_LOOP_WAIT 10 // Seconds
#ifdef USE_MQTT_TLS_CA_CERT
static const uint32_t tls_rx_size = 2048; // since Telegram CA is bigger than 1024 bytes, we need to increase rx buffer
static const uint32_t tls_tx_size = 1024;
#else
static const uint32_t tls_rx_size = 1024;
static const uint32_t tls_tx_size = 1024;
#endif
#include "WiFiClientSecureLightBearSSL.h"
BearSSL::WiFiClientSecure_light *telegramClient = nullptr;
static const uint8_t Telegram_Fingerprint[] PROGMEM = USE_TELEGRAM_FINGERPRINT;
struct {
String message[3][6]; // amount of messages read per time (update_id, name_id, name, lastname, chat_id, text)
uint8_t state = 0;
uint8_t index = 0;
uint8_t retry = 0;
uint8_t poll = TELEGRAM_LOOP_WAIT;
uint8_t wait = 0;
bool send_enable = false;
bool recv_enable = false;
bool echo_enable = false;
bool recv_busy = false;
} Telegram;
bool TelegramInit(void) {
bool init_done = false;
if (strlen(SettingsText(SET_TELEGRAM_TOKEN))) {
if (!telegramClient) {
telegramClient = new BearSSL::WiFiClientSecure_light(tls_rx_size, tls_tx_size);
#ifdef USE_MQTT_TLS_CA_CERT
telegramClient->setTrustAnchor(&GoDaddyCAG2_TA);
#else
telegramClient->setPubKeyFingerprint(Telegram_Fingerprint, Telegram_Fingerprint, false); // check server fingerprint
#endif
Telegram.message[0][0]="0"; // Number of received messages
Telegram.message[1][0]="";
Telegram.message[0][1]="0"; // Code of last read Message
AddLog_P2(LOG_LEVEL_INFO, PSTR("TGM: Started"));
}
init_done = true;
}
return init_done;
}
String TelegramConnectToTelegram(String command) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Cmnd %s"), command.c_str());
if (!TelegramInit()) { return ""; }
String response = "";
uint32_t tls_connect_time = millis();
if (telegramClient->connect("api.telegram.org", 443)) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Connected in %d ms, max ThunkStack used %d"), millis() - tls_connect_time, telegramClient->getMaxThunkStackUse());
telegramClient->println("GET /"+command);
String a = "";
char c;
int ch_count=0;
uint32_t now = millis();
bool avail = false;
while (millis() -now < 1500) {
while (telegramClient->available()) {
char c = telegramClient->read();
if (ch_count < 700) {
response = response + c;
ch_count++;
}
avail = true;
}
if (avail) {
break;
}
}
telegramClient->stop();
}
return response;
}
void TelegramGetUpdates(String offset) {
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: getUpdates"));
if (!TelegramInit()) { return; }
String _token = SettingsText(SET_TELEGRAM_TOKEN);
String command = "bot" + _token + "/getUpdates?offset=" + offset;
String response = TelegramConnectToTelegram(command); //recieve reply from telegram.org
// {"ok":true,"result":[]}
// or
// {"ok":true,"result":[
// {"update_id":973125394,
// "message":{"message_id":25,
// "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"},
// "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"},
// "date":1591877503,
// "text":"M1"
// }
// },
// {"update_id":973125395,
// "message":{"message_id":26,
// "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"},
// "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"},
// "date":1591877508,
// "text":"M2"
// }
// }
// ]}
// or
// {"ok":true,"result":[
// {"update_id":973125396,
// "message":{"message_id":29,
// "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"},
// "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"},
// "date":1591879753,
// "text":"/power toggle",
// "entities":[{"offset":0,"length":6,"type":"bot_command"}]
// }
// }
// ]}
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str());
// parsing of reply from Telegram into separate received messages
int i = 0; //messages received counter
if (response != "") {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Sent Update request messages up to %s"), offset.c_str());
String a = "";
int ch_count = 0;
String c;
for (uint32_t n = 1; n < response.length() +1; n++) { //Search for each message start
ch_count++;
c = response.substring(n -1, n);
a = a + c;
if (ch_count > 8) {
if (a.substring(ch_count -9) == "update_id") {
if (i > 1) { break; }
Telegram.message[i][0] = a.substring(0, ch_count -11);
a = a.substring(ch_count-11);
i++;
ch_count = 11;
}
}
}
if (1 == i) {
Telegram.message[i][0] = a.substring(0, ch_count); //Assign of parsed message into message matrix if only 1 message)
}
if (i > 1) { i = i -1; }
}
//check result of parsing process
if (response == "") {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Failed to update"));
return;
}
if (0 == i) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: No new messages"));
Telegram.message[0][0] = "0";
} else {
Telegram.message[0][0] = String(i); //returns how many messages are in the array
for (int b = 1; b < i+1; b++) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Msg %d %s"), b, Telegram.message[b][0].c_str());
}
TelegramAnalizeMessage();
}
}
void TelegramAnalizeMessage(void) {
for (uint32_t i = 1; i < Telegram.message[0][0].toInt() +1; i++) {
Telegram.message[i][5] = "";
DynamicJsonBuffer jsonBuffer;
JsonObject &root = jsonBuffer.parseObject(Telegram.message[i][0]);
if (root.success()) {
Telegram.message[i][0] = root["update_id"].as<String>();
Telegram.message[i][1] = root["message"]["from"]["id"].as<String>();
Telegram.message[i][2] = root["message"]["from"]["first_name"].as<String>();
Telegram.message[i][3] = root["message"]["from"]["last_name"].as<String>();
Telegram.message[i][4] = root["message"]["chat"]["id"].as<String>();
Telegram.message[i][5] = root["message"]["text"].as<String>();
}
int id = Telegram.message[Telegram.message[0][0].toInt()][0].toInt() +1;
Telegram.message[0][1] = id; // Write id of last read message
for (int j = 0; j < 6; j++) {
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Parsed%d \"%s\""), j, Telegram.message[i][j].c_str());
}
}
}
bool TelegramSendMessage(String chat_id, String text) {
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: sendMessage"));
if (!TelegramInit()) { return false; }
bool sent = false;
if (text != "") {
String _token = SettingsText(SET_TELEGRAM_TOKEN);
String command = "bot" + _token + "/sendMessage?chat_id=" + chat_id + "&text=" + text;
String response = TelegramConnectToTelegram(command);
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str());
if (response.startsWith("{\"ok\":true")) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Message sent"));
sent = true;
}
}
return sent;
}
/*
void TelegramSendGetMe(void) {
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: getMe"));
if (!TelegramInit()) { return; }
String _token = SettingsText(SET_TELEGRAM_TOKEN);
String command = "bot" + _token + "/getMe";
String response = TelegramConnectToTelegram(command);
// {"ok":true,"result":{"id":1179906608,"is_bot":true,"first_name":"Tasmota","username":"tasmota_bot","can_join_groups":true,"can_read_all_group_messages":false,"supports_inline_queries":false}}
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str());
}
*/
String TelegramExecuteCommand(const char *svalue) {
String response = "";
uint32_t curridx = web_log_index;
ExecuteCommand(svalue, SRC_CHAT);
if (web_log_index != curridx) {
uint32_t counter = curridx;
response = F("{");
bool cflg = false;
do {
char* tmp;
size_t len;
GetLog(counter, &tmp, &len);
if (len) {
// [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char* JSON = (char*)memchr(tmp, '{', len);
if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
size_t JSONlen = len - (JSON - tmp);
if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); }
char stemp[JSONlen];
strlcpy(stemp, JSON +1, JSONlen -2);
if (cflg) { response += F(","); }
response += stemp;
cflg = true;
}
}
counter++;
counter &= 0xFF;
if (!counter) counter++; // Skip 0 as it is not allowed
} while (counter != web_log_index);
response += F("}");
} else {
response = F("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}");
}
return response;
}
void TelegramLoop(void) {
if (!global_state.wifi_down && (Telegram.recv_enable || Telegram.echo_enable)) {
switch (Telegram.state) {
case 0:
TelegramInit();
Telegram.state++;
break;
case 1:
TelegramGetUpdates(Telegram.message[0][1]); // launch API GetUpdates up to xxx message
Telegram.index = 1;
Telegram.retry = TELEGRAM_SEND_RETRY;
Telegram.state++;
break;
case 2:
if (Telegram.echo_enable) {
if (Telegram.retry && (Telegram.index < Telegram.message[0][0].toInt() + 1)) {
if (TelegramSendMessage(Telegram.message[Telegram.index][4], Telegram.message[Telegram.index][5])) {
Telegram.index++;
Telegram.retry = TELEGRAM_SEND_RETRY;
} else {
Telegram.retry--;
}
} else {
Telegram.message[0][0] = ""; // All messages have been replied - reset new messages
Telegram.wait = Telegram.poll;
Telegram.state++;
}
} else {
if (Telegram.message[0][0].toInt() && (Telegram.message[Telegram.index][5].length() > 0)) {
String logging = TelegramExecuteCommand(Telegram.message[Telegram.index][5].c_str());
if (logging.length() > 0) {
TelegramSendMessage(Telegram.message[Telegram.index][4], logging);
}
}
Telegram.message[0][0] = ""; // All messages have been replied - reset new messages
Telegram.wait = Telegram.poll;
Telegram.state++;
}
break;
case 3:
if (Telegram.wait) {
Telegram.wait--;
} else {
Telegram.state = 1;
}
}
}
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
#define D_CMND_TMSTATE "State"
#define D_CMND_TMPOLL "Poll"
#define D_CMND_TMSEND "Send"
#define D_CMND_TMTOKEN "Token"
#define D_CMND_TMCHATID "ChatId"
const char kTelegramCommands[] PROGMEM = "Tm|" // Prefix
D_CMND_TMSTATE "|" D_CMND_TMPOLL "|" D_CMND_TMTOKEN "|" D_CMND_TMCHATID "|" D_CMND_TMSEND;
void (* const TelegramCommand[])(void) PROGMEM = {
&CmndTmState, &CmndTmPoll, &CmndTmToken, &CmndTmChatId, &CmndTmSend };
void CmndTmState(void) {
if (XdrvMailbox.data_len > 0) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6)) {
switch (XdrvMailbox.payload) {
case 0: // Off
case 1: // On
Telegram.send_enable = XdrvMailbox.payload &1;
break;
case 2: // Off
case 3: // On
Telegram.recv_enable = XdrvMailbox.payload &1;
break;
case 4: // Off
case 5: // On
Telegram.echo_enable = XdrvMailbox.payload &1;
break;
}
}
}
snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"Send\":\"%s\",\"Receive\":\"%s\",\"Echo\":\"%s\"}}"),
XdrvMailbox.command, GetStateText(Telegram.send_enable), GetStateText(Telegram.recv_enable), GetStateText(Telegram.echo_enable));
}
void CmndTmPoll(void) {
if ((XdrvMailbox.payload >= 4) && (XdrvMailbox.payload <= 300)) {
Telegram.poll = XdrvMailbox.payload;
if (Telegram.poll < Telegram.wait) {
Telegram.wait = Telegram.poll;
}
}
ResponseCmndNumber(Telegram.poll);
}
void CmndTmToken(void) {
if (XdrvMailbox.data_len > 0) {
SettingsUpdateText(SET_TELEGRAM_TOKEN, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data);
}
ResponseCmndChar(SettingsText(SET_TELEGRAM_TOKEN));
}
void CmndTmChatId(void) {
if (XdrvMailbox.data_len > 0) {
SettingsUpdateText(SET_TELEGRAM_CHATID, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data);
}
ResponseCmndChar(SettingsText(SET_TELEGRAM_CHATID));
}
void CmndTmSend(void) {
if (!Telegram.send_enable || !strlen(SettingsText(SET_TELEGRAM_CHATID))) {
ResponseCmndChar(D_JSON_FAILED);
return;
}
if (XdrvMailbox.data_len > 0) {
String message = XdrvMailbox.data;
String chat_id = SettingsText(SET_TELEGRAM_CHATID);
if (!TelegramSendMessage(chat_id, message)) {
ResponseCmndChar(D_JSON_FAILED);
return;
}
}
ResponseCmndDone();
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv40(uint8_t function)
{
bool result = false;
switch (function) {
case FUNC_EVERY_SECOND:
TelegramLoop();
break;
case FUNC_COMMAND:
result = DecodeCommand(kTelegramCommands, TelegramCommand);
break;
}
return result;
}
#endif // USE_TELEGRAM

View File

@ -20,6 +20,8 @@
Version Date Action Description Version Date Action Description
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
1.0.0.2 20200611 changed - bugfix: decouple restart of the work loop from FUNC_JSON_APPEND callback
---
1.0.0.1 20190917 changed - rework of the inner loop to enable delays in the middle of I2C-reads 1.0.0.1 20190917 changed - rework of the inner loop to enable delays in the middle of I2C-reads
changed - double send address change only for fw>0x25 changed - double send address change only for fw>0x25
changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS
@ -300,7 +302,7 @@ void ChirpServiceAllSensors(uint8_t job){
void ChirpEvery100MSecond(void) void ChirpEvery100MSecond(void)
{ {
// DEBUG_SENSOR_LOG(PSTR("CHIRP: every second")); // DEBUG_SENSOR_LOG(PSTR("CHIRP: every 100 mseconds, counter: %u, next job: %u"),chirp_timeout_count,chirp_next_job);
if(chirp_timeout_count == 0) { //countdown complete, now do something if(chirp_timeout_count == 0) { //countdown complete, now do something
switch(chirp_next_job) { switch(chirp_next_job) {
case 0: //this should only be called after driver initialization case 0: //this should only be called after driver initialization
@ -377,10 +379,11 @@ void ChirpEvery100MSecond(void)
break; break;
case 13: case 13:
DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE")); DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE"));
chirp_next_job++;
break; break;
case 14: case 14:
if (Settings.tele_period > 16){ if (Settings.tele_period > 16){
chirp_timeout_count = (Settings.tele_period - 17) * 10; // sync it with the TELEPERIOD, we need about up to 17 seconds to measure chirp_timeout_count = (Settings.tele_period - 16) * 10; // sync it with the TELEPERIOD, we need about up to 16 seconds to measure
DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout 1/10 sec: %u, tele: %u"), chirp_timeout_count, Settings.tele_period); DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout 1/10 sec: %u, tele: %u"), chirp_timeout_count, Settings.tele_period);
} }
else{ else{
@ -533,7 +536,6 @@ bool Xsns48(uint8_t function)
break; break;
case FUNC_JSON_APPEND: case FUNC_JSON_APPEND:
ChirpShow(1); ChirpShow(1);
chirp_next_job = 14; // TELE done, now compute time for next measure cycle
break; break;
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR: case FUNC_WEB_SENSOR:

View File

@ -205,8 +205,8 @@ a_features = [[
"USE_KEELOQ","USE_HRXL","USE_SONOFF_D1","USE_HDC1080", "USE_KEELOQ","USE_HRXL","USE_SONOFF_D1","USE_HDC1080",
"USE_IAQ","USE_DISPLAY_SEVENSEG","USE_AS3935","USE_PING", "USE_IAQ","USE_DISPLAY_SEVENSEG","USE_AS3935","USE_PING",
"USE_WINDMETER","USE_OPENTHERM","USE_THERMOSTAT","USE_VEML6075", "USE_WINDMETER","USE_OPENTHERM","USE_THERMOSTAT","USE_VEML6075",
"USE_VEML7700","USE_MCP9808","USE_BL0940","USE_HP303B", "USE_VEML7700","USE_MCP9808","USE_BL0940","USE_TELEGRAM",
"","","","", "USE_HP303B","","","",
"","","","", "","","","",
"","","","", "","","","",
"","","","USE_WEBCAM" "","","","USE_WEBCAM"
@ -243,7 +243,7 @@ else:
obj = json.load(fp) obj = json.load(fp)
def StartDecode(): def StartDecode():
print ("\n*** decode-status.py v20200607 by Theo Arends and Jacek Ziolkowski ***") print ("\n*** decode-status.py v20200611 by Theo Arends and Jacek Ziolkowski ***")
# print("Decoding\n{}".format(obj)) # print("Decoding\n{}".format(obj))