diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b4db35d4..6ed7e1001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,19 +3,43 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [12.2.0.2] +## [12.2.0.3] ### Added +- Support for BP1658CJ RGBCW led bulbs like Orein OS0100411267 by Cossid (#17011) ### Breaking Changed ### Changed -- Prepare for extended calibration and move some persistent data (PowerLow) -- Tasmota ESP32 Framework (Core) from v2.0.5 to v2.0.5.2 ### Fixed ### Removed +## [12.2.0.2] 20221107 +### Added +- Support for Digital Addressable Lighting Interface (DALI) by Andrei Kazmirtsuk (#16938) +- Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2`` +- Support for NTAG2xx tags read and write on PN532 NFC reader (#16939) +- Berry ``bytes().reverse()`` method (#16977) +- ESP32 Support for DMX ArtNet Led matrix animations (#16984) +- Command ``SetOption47 1..255`` to delay power on relay state in seconds reducing power surge. ``SO47 1`` delays until network connected. ``SO47 2`` delays until mqtt connected +- ESP32 DMX ArtNet optimization to avoid any object allocation and avoid garbage collector pauses +- Berry add ``dyn`` class + +### Changed +- Move some persistent data (PowerLow) +- ESP32 Framework (Core) from v2.0.5 to v2.0.5.2 +- ADE7953 monitoring from instant power to accumulated energy (#16941) + +### Fixed +- Deduplicate code and fix %timer n% rule regression from v12.2.0 (#16914) +- Serial initialization for baudrate and config (#16970) +- ModbusBridge buffer overflow (#16979) +- Default serial bridge configuration from 5N1 to 8N1 regression from v10.1.0.3 + +### Removed +- Define ``USE_PN532_DATA_RAW`` from NFC reader (#16939) + ## [12.2.0.1] 20221026 ### Added - DS18x20 support on up to four GPIOs by md5sum-as (#16833) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a56da4e9f..0fc183dd2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -107,22 +107,37 @@ 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.2.0.2 +## Changelog v12.2.0.3 ### Added +- Command ``SetOption47 1..255`` to delay power on relay state in seconds reducing power surge. ``SO47 1`` delays until network connected. ``SO47 2`` delays until mqtt connected +- Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2`` - Command NeoPool ``NPFiltration 2`` toggle [#16859](https://github.com/arendst/Tasmota/issues/16859) - Support for Shelly Pro 1/1PM and 2/2PM [#16773](https://github.com/arendst/Tasmota/issues/16773) - Support for up to four DS18x20 GPIOs by md5sum-as [#16833](https://github.com/arendst/Tasmota/issues/16833) -- Berry add `bytes().setbytes()` [#16892](https://github.com/arendst/Tasmota/issues/16892) +- Support for Digital Addressable Lighting Interface (DALI) by Andrei Kazmirtsuk [#16938](https://github.com/arendst/Tasmota/issues/16938) +- Support for NTAG2xx tags read and write on PN532 NFC reader [#16939](https://github.com/arendst/Tasmota/issues/16939) +- Support for BP1658CJ RGBCW led bulbs like Orein OS0100411267 by Cossid [#17011](https://github.com/arendst/Tasmota/issues/17011) +- Berry ``bytes().setbytes()`` method [#16892](https://github.com/arendst/Tasmota/issues/16892) +- Berry ``bytes().reverse()`` method [#16977](https://github.com/arendst/Tasmota/issues/16977) - Zigbee router firmware for Sonoff ZBBridgePro [#16900](https://github.com/arendst/Tasmota/issues/16900) +- ESP32 Support for DMX ArtNet Led matrix animations [#16984](https://github.com/arendst/Tasmota/issues/16984) ### Breaking Changed ### Changed +- ESP32 Framework (Core) from v2.0.5 to v2.0.5.2 - ESP32 NimBLE library from v1.4.0 to v1.4.1 [#16775](https://github.com/arendst/Tasmota/issues/16775) - DS18x20 ``DS18Alias`` to ``DS18Sens`` [#16833](https://github.com/arendst/Tasmota/issues/16833) - Compiling with reduced boards manifests in favour of Autoconfig [#16848](https://github.com/arendst/Tasmota/issues/16848) +- ADE7953 monitoring from instant power to accumulated energy [#16941](https://github.com/arendst/Tasmota/issues/16941) ### Fixed - BP5758D red channel corruption regression from v12.1.1.6 [#16850](https://github.com/arendst/Tasmota/issues/16850) +- Deduplicate code and fix %timer n% rule regression from v12.2.0 [#16914](https://github.com/arendst/Tasmota/issues/16914) +- Serial initialization for baudrate and config [#16970](https://github.com/arendst/Tasmota/issues/16970) +- ModbusBridge buffer overflow [#16979](https://github.com/arendst/Tasmota/issues/16979) +- Default serial bridge configuration from 5N1 to 8N1 regression from v10.1.0.3 + ### Removed +- Define ``USE_PN532_DATA_RAW`` from NFC reader [#16939](https://github.com/arendst/Tasmota/issues/16939) diff --git a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp b/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp index 99dc6caeb..f750b956f 100644 --- a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp +++ b/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp @@ -95,7 +95,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal void TasmotaSerial::end(bool turnOffDebug) { #ifdef ESP8266 if (m_hardserial) { - Serial.end(); +// Serial.end(); // Keep active for logging } else { if (m_rx_pin > -1) { detachInterrupt(m_rx_pin); diff --git a/lib/default/headers/cam_hal.h b/lib/default/headers/cam_hal.h deleted file mode 100644 index c8e38ed47..000000000 --- a/lib/default/headers/cam_hal.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2010-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "esp_camera.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Uninitialize the lcd_cam module - * - * @param handle Provide handle pointer to release resources - * - * @return - * - ESP_OK Success - * - ESP_FAIL Uninitialize fail - */ -esp_err_t cam_deinit(void); - -/** - * @brief Initialize the lcd_cam module - * - * @param config Configurations - see lcd_cam_config_t struct - * - * @return - * - ESP_OK Success - * - ESP_ERR_INVALID_ARG Parameter error - * - ESP_ERR_NO_MEM No memory to initialize lcd_cam - * - ESP_FAIL Initialize fail - */ -esp_err_t cam_init(const camera_config_t *config); - -esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint16_t sensor_pid); - -void cam_stop(void); - -void cam_start(void); - -camera_fb_t *cam_take(TickType_t timeout); - -void cam_give(camera_fb_t *dma_buffer); - -#ifdef __cplusplus -} -#endif diff --git a/lib/libesp32/berry/default/be_modtab.c b/lib/libesp32/berry/default/be_modtab.c index c02e2ca6d..5b018304e 100644 --- a/lib/libesp32/berry/default/be_modtab.c +++ b/lib/libesp32/berry/default/be_modtab.c @@ -166,7 +166,7 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { #ifdef USE_ALEXA_AVS &be_native_module(crypto), #endif -#if defined(USE_BERRY_ULP) && defined(CONFIG_IDF_TARGET_ESP32) +#if defined(USE_BERRY_ULP) && ((CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)) &be_native_module(ULP), #endif // USE_BERRY_ULP #if defined(USE_MI_ESP32) && !defined(USE_BLE_ESP32) @@ -178,6 +178,7 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { NULL /* do not remove */ }; +be_extern_native_class(dyn); be_extern_native_class(tasmota); be_extern_native_class(Trigger); be_extern_native_class(Driver); @@ -228,6 +229,7 @@ be_extern_native_class(int64); BERRY_LOCAL bclass_array be_class_table = { #ifdef TASMOTA /* first list are direct classes */ + &be_native_class(dyn), &be_native_class(tasmota), &be_native_class(Trigger), &be_native_class(Driver), diff --git a/lib/libesp32/berry/src/be_byteslib.c b/lib/libesp32/berry/src/be_byteslib.c index b2dc9856a..6fcd457db 100644 --- a/lib/libesp32/berry/src/be_byteslib.c +++ b/lib/libesp32/berry/src/be_byteslib.c @@ -957,7 +957,6 @@ static int m_setfloat(bvm *vm) * `setbytes(index:int, fill:bytes [, from:int, len:int]) -> nil` * */ -#include static int m_setbytes(bvm *vm) { int argc = be_top(vm); @@ -968,7 +967,7 @@ static int m_setbytes(bvm *vm) size_t from_len_total; const uint8_t* buf_ptr = (const uint8_t*) be_tobytes(vm, 3, &from_len_total); if (idx < 0) { idx = 0; } - if ((size_t)idx >= attr.len) { idx = attr.len; } + if (idx >= attr.len) { idx = attr.len; } int32_t from_byte = 0; if (argc >= 4 && be_isint(vm, 4)) { @@ -981,9 +980,9 @@ static int m_setbytes(bvm *vm) if (argc >= 5 && be_isint(vm, 5)) { from_len = be_toint(vm, 5); if (from_len < 0) { from_len = 0; } - if (from_len >= from_len_total) { from_len = from_len_total; } + if (from_len >= (int32_t)from_len_total) { from_len = from_len_total; } } - if ((size_t) idx + (size_t)from_len >= attr.len) { from_len = attr.len - idx; } + if (idx + from_len >= attr.len) { from_len = attr.len - idx; } // all parameters ok if (from_len > 0) { @@ -993,6 +992,66 @@ static int m_setbytes(bvm *vm) be_return_nil(vm); } + +/* + * Reverses in-place a sub-buffer composed of groups of n-bytes packets + * + * This is useful for pixel manipulation when displaying RGB pixels + * + * `reverse([index:int, len:int, grouplen:int]) -> self` + * + */ +static int m_reverse(bvm *vm) +{ + int argc = be_top(vm); + buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ + check_ptr(vm, &attr); + + int32_t idx = 0; /* start from index 0 */ + int32_t len = attr.len; /* entire len */ + int32_t grouplen = 1; /* default to 1-byte group */ + + if (argc >= 2 && be_isint(vm, 2)) { + idx = be_toint(vm, 2); + if (idx < 0) { idx = 0; } /* railguards */ + if (idx > attr.len) { idx = attr.len; } + } + if (argc >= 3 && be_isint(vm, 3)) { + len = be_toint(vm, 3); + if (len < 0) { len = attr.len - idx; } /* negative len means */ + } + if (idx + len >= attr.len) { len = attr.len - idx; } + + // truncate len to multiple of grouplen + if (argc >= 4 && be_isint(vm, 4)) { + grouplen = be_toint(vm, 4); + if (grouplen <= 0) { grouplen = 1; } + } + len = len - (len % grouplen); + + // apply reverse + if (len > 0) { + if (grouplen == 1) { + /* fast version if simple byte inversion */ + for (int32_t i = idx, j = idx + len -1; i < j; i++, j--) { + uint8_t temp = attr.bufptr[i]; + attr.bufptr[i] = attr.bufptr[j]; + attr.bufptr[j] = temp; + } + } else { + for (int32_t i = idx, j = idx + len - grouplen; i < j; i += grouplen, j -= grouplen) { + for (int32_t k = 0; k < grouplen; k++) { + uint8_t temp = attr.bufptr[i+k]; + attr.bufptr[i+k] = attr.bufptr[j+k]; + attr.bufptr[j+k] = temp; + } + } + } + } + be_pushvalue(vm, 1); /* push bytes object */ + be_return(vm); +} + static int m_setitem(bvm *vm) { int argc = be_top(vm); @@ -1627,6 +1686,7 @@ void be_load_byteslib(bvm *vm) { "size", m_size }, { "resize", m_resize }, { "clear", m_clear }, + { "reverse", m_reverse }, { "copy", m_copy }, { "+", m_merge }, { "..", m_connect }, @@ -1672,6 +1732,7 @@ class be_class_bytes (scope: global, name: bytes) { size, func(m_size) resize, func(m_resize) clear, func(m_clear) + reverse, func(m_reverse) copy, func(m_copy) +, func(m_merge) .., func(m_connect) diff --git a/lib/libesp32/berry/tests/bytes.be b/lib/libesp32/berry/tests/bytes.be index 44d3f56aa..d2b2c1573 100644 --- a/lib/libesp32/berry/tests/bytes.be +++ b/lib/libesp32/berry/tests/bytes.be @@ -225,3 +225,26 @@ assert(a == bytes('112233445566CCDD99')) a = b.copy() a.setbytes(0, a0) assert(a == bytes('112233445566')) + +# reverse +assert(bytes().reverse() == bytes()) +assert(bytes("AA").reverse() == bytes("AA")) +assert(bytes("1122334455").reverse() == bytes("5544332211")) +assert(bytes("11223344").reverse() == bytes("44332211")) + +assert(bytes("0011223344").reverse(1) == bytes("0044332211")) +assert(bytes("0011223344").reverse(3) == bytes("0011224433")) +assert(bytes("0011223344").reverse(4) == bytes("0011223344")) +assert(bytes("0011223344").reverse(5) == bytes("0011223344")) +assert(bytes("0011223344").reverse(15) == bytes("0011223344")) +assert(bytes("0011223344").reverse(-2) == bytes("4433221100")) + +assert(bytes("0011223344").reverse(1,3) == bytes("0033221144")) +assert(bytes("0011223344").reverse(1,0) == bytes("0011223344")) +assert(bytes("0011223344").reverse(2,2) == bytes("0011332244")) +assert(bytes("0011223344").reverse(0,2) == bytes("1100223344")) +assert(bytes("0011223344").reverse(nil,2) == bytes("1100223344")) +assert(bytes("0011223344").reverse(1, nil) == bytes("0044332211")) + +assert(bytes("0011223344").reverse(nil, nil, 2) == bytes("2233001144")) +assert(bytes("001122334455").reverse(nil, nil, 3) == bytes("334455001122")) diff --git a/lib/libesp32/berry_tasmota/src/be_ULP_lib.c b/lib/libesp32/berry_tasmota/src/be_ULP_lib.c index 7edf43206..a5fe0e417 100644 --- a/lib/libesp32/berry_tasmota/src/be_ULP_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_ULP_lib.c @@ -6,9 +6,9 @@ #include "be_constobj.h" #include "be_mapping.h" -#if defined(USE_BERRY_ULP) && defined(CONFIG_IDF_TARGET_ESP32) +#if defined(USE_BERRY_ULP) && (defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)) -#include "esp32/ulp.h" +// #include "esp32/ulp.h" #include "driver/rtc_io.h" #include "driver/gpio.h" #include "driver/adc.h" @@ -37,8 +37,6 @@ BE_FUNC_CTYPE_DECLARE(be_ULP_sleep, "", "[i]"); // optional int arg extern void be_ULP_load(struct bvm *vm, const uint8_t *buf, size_t size); BE_FUNC_CTYPE_DECLARE(be_ULP_load, "", "@(bytes)~"); // pass: 1/ vm, 2/ bytes point, 3/ bytes size -#include "be_fixed_ULP.h" - /* @const_object_info_begin module ULP (scope: global) { run, ctype_func(be_ULP_run) @@ -51,5 +49,6 @@ module ULP (scope: global) { adc_config, ctype_func(be_ULP_adc_config) } @const_object_info_end */ +#include "be_fixed_ULP.h" -#endif // USE_BERRY_ULP \ No newline at end of file +#endif // USE_BERRY_ULP diff --git a/lib/libesp32/berry_tasmota/src/be_dyn_class.c b/lib/libesp32/berry_tasmota/src/be_dyn_class.c new file mode 100644 index 000000000..b41ac1b29 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/be_dyn_class.c @@ -0,0 +1,4 @@ +/******************************************************************** + * Tasmota dyn class + *******************************************************************/ +#include "solidify/solidified_dyn.h" diff --git a/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp b/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp index 439771fba..4186673c5 100644 --- a/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp +++ b/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp @@ -94,10 +94,30 @@ extern "C" { int32_t be_udp_read(struct bvm *vm) { WiFiUDP *udp = (WiFiUDP*) be_convert_single_elt(vm, 1, NULL, NULL); if (udp->parsePacket()) { - int btr = udp->available(); - uint8_t * buf = (uint8_t*) be_pushbuffer(vm, btr); + int btr = udp->available(); // btr contains the size of bytes_to_read + + int argc = be_top(vm); + if (argc >= 2 && be_isbytes(vm, 2)) { + // we have already a bytes() buffer + be_pushvalue(vm, 2); // push on top + // resize to btr + be_getmember(vm, -1, "resize"); + be_pushvalue(vm, -2); + be_pushint(vm, btr); + be_call(vm, 2); + be_pop(vm, 3); + } else { + be_pushbytes(vm, nullptr, btr); // allocate a buffer of size btr filled with zeros + } + + // get the address of the buffer + be_getmember(vm, -1, "_buffer"); + be_pushvalue(vm, -2); + be_call(vm, 1); + uint8_t * buf = (uint8_t*) be_tocomptr(vm, -2); + be_pop(vm, 2); + int32_t btr2 = udp->read(buf, btr); - be_pushbytes(vm, buf, btr2); // set remotet ip IPAddress remote_ip = udp->remoteIP(); diff --git a/lib/libesp32/berry_tasmota/src/embedded/dyn.be b/lib/libesp32/berry_tasmota/src/embedded/dyn.be new file mode 100644 index 000000000..5266304ba --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/embedded/dyn.be @@ -0,0 +1,27 @@ +################################################################################# +# dyn class +# +# Allows to use a map with members +# see https://github.com/berry-lang/berry/wiki/Chapter-8 +################################################################################# +#@ solidify:dyn +class dyn + var _attr + def init() + self._attr = {} + end + def setmember(name, value) + self._attr[name] = value + end + def member(name) + if self._attr.contains(name) + return self._attr[name] + else + import undefined + return undefined + end + end + def tostring() + return self._attr.tostring() + end +end diff --git a/lib/libesp32/berry_tasmota/src/embedded/leds.be b/lib/libesp32/berry_tasmota/src/embedded/leds.be index 82b154186..23f24ef07 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/leds.be +++ b/lib/libesp32/berry_tasmota/src/embedded/leds.be @@ -117,8 +117,14 @@ class Leds : Leds_ntv def dirty() self.call_native(5) end - def pixels_buffer() - return self.call_native(6) + def pixels_buffer(old_buf) + var buf = self.call_native(6) # address of buffer in memory + if old_buf == nil + return bytes(buf, self.pixel_size() * self.pixel_count()) + else + old_buf._change_buffer(buf) + return old_buf + end end def pixel_size() return self.call_native(7) @@ -275,7 +281,7 @@ class Leds : Leds_ntv # don't trigger on segment, you will need to trigger on full strip instead if bool(force) || (self.offset == 0 && self.w * self.h == self.strip.leds) self.strip.show() - self.pix_buffer = self.strip.pixels_buffer() # update buffer after show() + self.pix_buffer = self.strip.pixels_buffer(self.pix_buffer) # update buffer after show() end end def can_show() diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h new file mode 100644 index 000000000..ccb1c98e5 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h @@ -0,0 +1,157 @@ +/* Solidification of dyn.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(dyn_tostring, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str(_attr), + /* K1 */ be_nested_str(tostring), + }), + &be_const_str_tostring, + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: member +********************************************************************/ +be_local_closure(dyn_member, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(_attr), + /* K1 */ be_nested_str(contains), + /* K2 */ be_nested_str(undefined), + }), + &be_const_str_member, + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x780A0003, // 0004 JMPF R2 #0009 + 0x88080100, // 0005 GETMBR R2 R0 K0 + 0x94080401, // 0006 GETIDX R2 R2 R1 + 0x80040400, // 0007 RET 1 R2 + 0x70020001, // 0008 JMP #000B + 0xA40A0400, // 0009 IMPORT R2 K2 + 0x80040400, // 000A RET 1 R2 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: setmember +********************************************************************/ +be_local_closure(dyn_setmember, /* name */ + be_nested_proto( + 4, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str(_attr), + }), + &be_const_str_setmember, + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x980C0202, // 0001 SETIDX R3 R1 R2 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(dyn_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str(_attr), + }), + &be_const_str_init, + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040013, // 0000 GETGBL R1 G19 + 0x7C040000, // 0001 CALL R1 0 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: dyn +********************************************************************/ +be_local_class(dyn, + 1, + NULL, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key(tostring, 2), be_const_closure(dyn_tostring_closure) }, + { be_const_key(member, 3), be_const_closure(dyn_member_closure) }, + { be_const_key(init, 4), be_const_closure(dyn_init_closure) }, + { be_const_key(setmember, -1), be_const_closure(dyn_setmember_closure) }, + { be_const_key(_attr, -1), be_const_var(0) }, + })), + (bstring*) &be_const_str_dyn +); +/*******************************************************************/ + +void be_load_dyn_class(bvm *vm) { + be_pushntvclass(vm, &be_class_dyn); + be_setglobal(vm, "dyn"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h index 589c59460..8c8692405 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h @@ -1118,7 +1118,7 @@ be_local_closure(Leds_matrix_pixel_count, /* name */ ********************************************************************/ be_local_closure(Leds_matrix_show, /* name */ be_nested_proto( - 4, /* nstack */ + 5, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1139,29 +1139,30 @@ be_local_closure(Leds_matrix_show, /* name */ }), &be_const_str_show, &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ + ( &(const binstruction[23]) { /* code */ 0x60080017, // 0000 GETGBL R2 G23 0x5C0C0200, // 0001 MOVE R3 R1 0x7C080200, // 0002 CALL R2 1 0x740A0009, // 0003 JMPT R2 #000E 0x88080100, // 0004 GETMBR R2 R0 K0 0x1C080501, // 0005 EQ R2 R2 K1 - 0x780A000D, // 0006 JMPF R2 #0015 + 0x780A000E, // 0006 JMPF R2 #0016 0x88080102, // 0007 GETMBR R2 R0 K2 0x880C0103, // 0008 GETMBR R3 R0 K3 0x08080403, // 0009 MUL R2 R2 R3 0x880C0104, // 000A GETMBR R3 R0 K4 0x880C0705, // 000B GETMBR R3 R3 K5 0x1C080403, // 000C EQ R2 R2 R3 - 0x780A0006, // 000D JMPF R2 #0015 + 0x780A0007, // 000D JMPF R2 #0016 0x88080104, // 000E GETMBR R2 R0 K4 0x8C080506, // 000F GETMET R2 R2 K6 0x7C080200, // 0010 CALL R2 1 0x88080104, // 0011 GETMBR R2 R0 K4 0x8C080508, // 0012 GETMET R2 R2 K8 - 0x7C080200, // 0013 CALL R2 1 - 0x90020E02, // 0014 SETMBR R0 K7 R2 - 0x80000000, // 0015 RET 0 + 0x88100107, // 0013 GETMBR R4 R0 K7 + 0x7C080400, // 0014 CALL R2 2 + 0x90020E02, // 0015 SETMBR R0 K7 R2 + 0x80000000, // 0016 RET 0 }) ) ); @@ -1452,24 +1453,44 @@ be_local_closure(Leds_create_matrix, /* name */ ********************************************************************/ be_local_closure(Leds_pixels_buffer, /* name */ be_nested_proto( - 4, /* nstack */ - 1, /* argc */ + 8, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ + ( &(const bvalue[ 4]) { /* constants */ /* K0 */ be_nested_str(call_native), + /* K1 */ be_nested_str(pixel_size), + /* K2 */ be_nested_str(pixel_count), + /* K3 */ be_nested_str(_change_buffer), }), &be_const_str_pixels_buffer, &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x540E0005, // 0001 LDINT R3 6 - 0x7C040400, // 0002 CALL R1 2 - 0x80040200, // 0003 RET 1 R1 + ( &(const binstruction[21]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x54120005, // 0001 LDINT R4 6 + 0x7C080400, // 0002 CALL R2 2 + 0x4C0C0000, // 0003 LDNIL R3 + 0x1C0C0203, // 0004 EQ R3 R1 R3 + 0x780E0009, // 0005 JMPF R3 #0010 + 0x600C0015, // 0006 GETGBL R3 G21 + 0x5C100400, // 0007 MOVE R4 R2 + 0x8C140101, // 0008 GETMET R5 R0 K1 + 0x7C140200, // 0009 CALL R5 1 + 0x8C180102, // 000A GETMET R6 R0 K2 + 0x7C180200, // 000B CALL R6 1 + 0x08140A06, // 000C MUL R5 R5 R6 + 0x7C0C0400, // 000D CALL R3 2 + 0x80040600, // 000E RET 1 R3 + 0x70020003, // 000F JMP #0014 + 0x8C0C0303, // 0010 GETMET R3 R1 K3 + 0x5C140400, // 0011 MOVE R5 R2 + 0x7C0C0400, // 0012 CALL R3 2 + 0x80040200, // 0013 RET 1 R1 + 0x80000000, // 0014 RET 0 }) ) ); diff --git a/pio-tools/post_esp32.py b/pio-tools/post_esp32.py index 3ded90386..370934845 100644 --- a/pio-tools/post_esp32.py +++ b/pio-tools/post_esp32.py @@ -139,6 +139,11 @@ def esp32_create_combined_bin(source, target, env): firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") chip = env.get("BOARD_MCU") tasmota_platform = esp32_create_chip_string(chip) + + if "-DUSE_USB_CDC_CONSOLE" in env.BoardConfig().get("build.extra_flags") and "cdc" not in tasmota_platform: + tasmota_platform += "cdc" + print("WARNING: board definition uses CDC configuration, but environment name does not -> changing tasmota safeboot binary to:", tasmota_platform + "-safeboot.bin") + if not os.path.exists(variants_dir): os.makedirs(variants_dir) if("safeboot" in firmware_name): diff --git a/tasmota/berry/artnet/artnet.be b/tasmota/berry/artnet/artnet.be new file mode 100644 index 000000000..1fcdd5053 --- /dev/null +++ b/tasmota/berry/artnet/artnet.be @@ -0,0 +1,96 @@ +# Art-Net driver + +class ArtNet + var matrix # the led matrix + var port # port number for listening for incoming packets + var udp_server # instance of `udp` class + var universe_start # base universe number + var universe_end # last universe number allowed (excluded) + # static var artnet_sig = bytes().fromstring("Art-Net\x00") # 8 bytes # signature of packet + static var artnet_sig_0 = 0x4172742D # "Art-" + static var artnet_sig_4 = 0x4E657400 # "Net\x00" + + var packet # try reusing the same packer bytes() object for performance + + # local copy of led matrix attributes for faster access + var alternate # field from matrix, alternate lines (reversed). Contains 0 if not alternate, or the number of bytes per pixel + + def init(matrix, universe_start, port, ip_addr) + self.matrix = matrix + self.alternate = matrix.alternate ? matrix.pixel_size() : 0 + # self.v = self.matrix.v + if universe_start == nil universe_start = 0 end + self.universe_start = universe_start + self.universe_end = universe_start + matrix.h + + if port == nil port = 6454 end + self.port = int(port) + if ip_addr == nil ip_addr = "" end + + self.packet = bytes() # instanciate a single bytes() buffer that will be used for all received packets + + self.udp_server = udp() + self.udp_server.begin(ip_addr, self.port) + + # register as fast_loop + tasmota.add_fast_loop(/-> self.fast_loop()) + # set sleep to 5 for a smooth animation + tasmota.global.sleep = 5 + end + + def fast_loop() + var universe_start = self.universe_start + var universe_end = self.universe_end + var artnet_sig_0 = self.artnet_sig_0 + var artnet_sig_4 = self.artnet_sig_4 + var dirty = false + var packet = self.udp_server.read(self.packet) + while (packet != nil) + if size(packet) >= 18 && + packet.get(0, -4) == artnet_sig_0 && packet.get(4, -4) == artnet_sig_4 + var opcode = packet.get(8, 2) # should be 0x5000 + var protocol = packet.get(10, -2) # big endian, should be 14 + var universe = packet.get(14, 2) + + if opcode == 0x5000 && protocol == 14 && universe >= universe_start && universe < universe_end + # tasmota.log("DMX: received Art-Net packet :" + packet.tohex()) + # var seq = packet.get(12, 1) + # var phy = packet.get(13, 1) + var data_len = packet.get(16, -2) + # data starts at offset 18 + if size(packet) >= 18 + data_len # check size + if self.alternate > 0 && (universe - self.universe_start) % 2 + packet.reverse(18, self.alternate, -1) + end + self.matrix.set_bytes(universe, packet, 18, data_len) + dirty = true + end + # import string + # tasmota.log(string.format("DMX: opcode=0x%04X protocol=%i seq=%i phy=%i universe=%i data_len=%i data=%s", + # opcode, protocol, seq, phy, universe, data_len, packet[18..-1].tohex())) + end + end + packet = self.udp_server.read(self.packet) + if packet == nil + tasmota.delay_microseconds(20) # wait 20 us just in case + packet = self.udp_server.read(self.packet) + end + end + + if dirty + self.matrix.dirty() + self.matrix.show() + end + end +end + +return ArtNet + +#- +# Example for M5Stack ATOM Matrix (5x5 matrix without alternate) +import artnet +# var artnet = ArtNet +var strip = Leds(25, gpio.pin(gpio.WS2812, 0)) +var m = strip.create_matrix(5, 5, 0) +var dmx = artnet(m) +-# \ No newline at end of file diff --git a/tasmota/berry/drivers/tm1637.be b/tasmota/berry/drivers/tm1637.be new file mode 100644 index 000000000..9e7b572f0 --- /dev/null +++ b/tasmota/berry/drivers/tm1637.be @@ -0,0 +1,190 @@ +#- +Simplified Tasmota TM1637 driver written in Berry +Might be helpful in the case of using multiple displays +Supports only the 4 digit basic display + +DIO_PIN and CLK_PIN are your esp32 pin numbers +How to use + +> load('tm1637') +> tm = Tm1637(DIO_PIN, CLK_PIN) +> tm.set_on(4) +> tm.print('0123') +> tm.print(456) + +Add custom commands to the native Tasmota console: +> tm_add_custom_commands(DIO_PIN, CLK_PIN) + +And then: +TmBrightness 2 +TmPrint 0123 +TmPrint -5.67 + +Note: adding these commands to autoexec.be should be performed via creating an additional .be file with the content: + tm_add_custom_commands(DIO_PIN, CLK_PIN) + +and then loading it in autoexec.be via load('tm1637') and load('script_name') +The direct addition may not work +-# + +class Tm1637 + static var CMD_CTRL = 0x80 + static var CMD_DISP_ON = 0x08 + static var CMD_DATA = 0x40 + static var CMD_ADDR = 0xC0 + + static var SYMB_DOT = 0x80 + + static var DIGIT_MAP = { + '0': 0x3F, + '1': 0x06, + '2': 0x5B, + '3': 0x4F, + '4': 0x66, + '5': 0x6D, + '6': 0x7D, + '7': 0x07, + '8': 0x7F, + '9': 0x6F, + '-': 0x40, + ' ': 0x00 + } + + var PIN_DIO + var PIN_CLK + + def init(dio, clk) + self.PIN_DIO = dio + self.PIN_CLK = clk + gpio.pin_mode(self.PIN_DIO, gpio.OUTPUT) + gpio.pin_mode(self.PIN_CLK, gpio.OUTPUT) + gpio.digital_write(self.PIN_DIO, 1) + gpio.digital_write(self.PIN_CLK, 1) + end + + def start() + gpio.digital_write(self.PIN_DIO, 1) + gpio.digital_write(self.PIN_CLK, 1) + gpio.digital_write(self.PIN_DIO, 0) + end + + def stop() + gpio.digital_write(self.PIN_CLK, 0) + gpio.digital_write(self.PIN_DIO, 0) + gpio.digital_write(self.PIN_CLK, 1) + gpio.digital_write(self.PIN_DIO, 1) + end + + def ack() + gpio.digital_write(self.PIN_CLK, 0) + gpio.pin_mode(self.PIN_DIO, gpio.INPUT_PULLUP) + var ack_state = gpio.digital_read(self.PIN_DIO) == 0 + gpio.digital_write(self.PIN_CLK, 1) + gpio.digital_write(self.PIN_CLK, 0) + gpio.pin_mode(self.PIN_DIO, gpio.OUTPUT) + return ack_state + end + + def write_bit(bitval) + gpio.digital_write(self.PIN_CLK, 0) + gpio.digital_write(self.PIN_DIO, bitval) + gpio.digital_write(self.PIN_CLK, 1) + end + + def write_byte(byteval) + for pos: 0..7 + self.write_bit((byteval >> pos) & 0x01) + end + end + + def send_command(command) + self.start() + self.write_byte(command) + var ack_state = self.ack() + self.stop() + return ack_state + end + + def send_data(data) + var ack_state = true + self.start() + for i : 0..size(data)-1 + self.write_byte(data[i]) + ack_state = self.ack() && ack_state + end + self.stop() + return ack_state + end + + # 0-8 range, 0 to 'OFF' + def set_on(brightness) + if brightness == nil || brightness > 8 + brightness = 8 + elif brightness < 0 + brightness = 0 + end + var cmd = self.CMD_CTRL + if brightness + cmd |= self.CMD_DISP_ON + brightness -= 1 + end + return self.send_command(cmd | brightness) + end + + def print(num) + import string + + num = str(num) + var max_str_len = 4 + + do + var dot_pos = string.find(num, '.') + if dot_pos >= 0 && dot_pos < 5 + max_str_len = 5 + end + end + if size(num) > max_str_len + num = string.split(num, max_str_len)[0] + end + num = string.format('%4s', num) + var payload = bytes(-5) + payload[0] = self.CMD_ADDR + var int_offset = 1 + for i : 0..size(num)-1 + if num[i] == '.' + payload[i] |= self.SYMB_DOT + int_offset = 0 + else + payload[i + int_offset] = self.DIGIT_MAP[num[i]] + end + end + var ack_state = self.send_command(self.CMD_DATA) && self.send_data(payload) + if !ack_state + log('TM1637 - no ACK, please check connections') + end + return ack_state + end + + def clear() + self.print(' ') + end + + # Won't be called on the system restart + def deinit() + self.set_on(0) + end +end + +def tm_add_custom_commands(dio, clk) + var tm = Tm1637(dio, clk) + tm.clear() + tm.set_on(4) + tasmota.add_cmd('tmprint', def(cmd, idx, payload) + tm.print(payload) ? tasmota.resp_cmnd_done() : tasmota.resp_cmnd_failed() + end) + # 0-8 range, 0 to 'OFF' + tasmota.add_cmd('tmbrightness', def(cmd, idx, payload) + tm.set_on(int(payload)) ? tasmota.resp_cmnd_done() : tasmota.resp_cmnd_failed() + end) + log("Tasmota custom commands registered: TmPrint, TmBrightness") +end diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h index 84c0a78a6..1c46f3df4 100644 --- a/tasmota/include/i18n.h +++ b/tasmota/include/i18n.h @@ -753,6 +753,10 @@ // Commands xdrv_60_shift595.ino - 74x595 family shift register driver #define D_CMND_SHIFT595_DEVICE_COUNT "Shift595DeviceCount" +// Commands xdrv_89_dali.ino +#define D_CMND_DALI_POWER "power" +#define D_CMND_DALI_DIMMER "dim" + // Commands xsns_02_analog.ino #define D_CMND_ADCPARAM "AdcParam" diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index 3dee90dad..99a5f780c 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -362,7 +362,7 @@ enum SO32_49Index { P_HOLD_TIME, // SetOption32 - (Button/Switch) K P_IR_TOLERANCE, // SetOption44 - (IR) Base tolerance percentage for matching incoming IR messages (default 25, max 100) P_BISTABLE_PULSE, // SetOption45 - (Bistable) Pulse time for two coil bistable latching relays (default 40) P_POWER_ON_DELAY, // SetOption46 - (PowerOn) Add delay of 10 x value milliseconds at power on - P_SO47_FREE, // SetOption47 + P_POWER_ON_DELAY2, // SetOption47 - (PowerOn) Add delay of value seconds at power on before activating relays P_SO48_FREE, // SetOption48 P_SO49_FREE // SetOption49 }; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49 @@ -459,10 +459,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, 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_CHAT, SRC_TCL, SRC_BERRY, SRC_FILE, SRC_SSERIAL, SRC_USBCONSOLE, SRC_MAX }; + SRC_THERMOSTAT, SRC_CHAT, SRC_TCL, SRC_BERRY, SRC_FILE, SRC_SSERIAL, SRC_USBCONSOLE, SRC_SO47, SRC_MAX }; 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|Chat|TCL|Berry|File|SSerial|UsbConsole"; + "Thermostat|Chat|TCL|Berry|File|SSerial|UsbConsole|SO47"; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h index b252a2275..661440aea 100644 --- a/tasmota/include/tasmota_configurations_ESP32.h +++ b/tasmota/include/tasmota_configurations_ESP32.h @@ -723,6 +723,7 @@ #define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code) //#define USE_A4988_STEPPER // Add support for A4988/DRV8825 stepper-motor-driver-circuit (+10k5 code) //#define USE_THERMOSTAT // Add support for Thermostat +#define USE_BP1658CJ // Add support for BP1658CJ 5 channel led controller as used in Orein OS0100411267 Bulb #define USE_ETHERNET // Add support for ethernet (+20k code) #define USE_DISPLAY_TM1621_SONOFF // Add support for TM1621 display driver used by Sonoff POWR3xxD and THR3xxD diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index 64da087d2..288670cca 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -198,6 +198,8 @@ enum UserSelectablePins { GPIO_ADE7953_RST, // ADE7953 Reset GPIO_NRG_MBS_TX, GPIO_NRG_MBS_RX, // Generic Energy Modbus device GPIO_ADE7953_CS, // ADE7953 SPI Chip Select + GPIO_DALI_RX, GPIO_DALI_TX, // Dali + GPIO_BP1658CJ_CLK, GPIO_BP1658CJ_DAT,// BP1658CJ GPIO_DINGTIAN_CLK, GPIO_DINGTIAN_SDI, GPIO_DINGTIAN_Q7, GPIO_DINGTIAN_PL, GPIO_DINGTIAN_RCK, // Dingtian relay board - 595's & 165's pins GPIO_SENSOR_END }; @@ -444,6 +446,8 @@ const char kSensorNames[] PROGMEM = D_SENSOR_ADE7953_RST "|" D_SENSOR_NRG_MBS_TX "|" D_SENSOR_NRG_MBS_RX "|" D_SENSOR_ADE7953_CS "|" + D_SENSOR_DALI_RX "|" D_SENSOR_DALI_TX "|" + D_SENSOR_BP1658CJ_CLK "|" D_SENSOR_BP1658CJ_DAT "|" D_GPIO_DINGTIAN_CLK "|" D_GPIO_DINGTIAN_SDI "|" D_GPIO_DINGTIAN_Q7 "|" D_GPIO_DINGTIAN_PL "|" D_GPIO_DINGTIAN_RCK "|" ; @@ -459,6 +463,7 @@ const char kSensorNamesFixed[] PROGMEM = #define MAX_SM2135_DAT 10 #define MAX_SM2335_DAT 16 #define MAX_DSB 4 +#define MAX_BP1658CJ_DAT 16 #define MAX_DINGTIAN_SHIFT 4 const uint16_t kGpioNiceList[] PROGMEM = { @@ -530,6 +535,11 @@ const uint16_t kGpioNiceList[] PROGMEM = { * Protocol specifics \*-------------------------------------------------------------------------------------------*/ +#if defined(USE_DALI) && defined(ESP32) + AGPIO(GPIO_DALI_RX), // DALI RX + AGPIO(GPIO_DALI_TX), // DALI TX +#endif // USE_DALI + #ifdef USE_I2C AGPIO(GPIO_I2C_SCL) + MAX_I2C, // I2C SCL AGPIO(GPIO_I2C_SDA) + MAX_I2C, // I2C SDA @@ -711,6 +721,10 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_SM2335_CLK), // SM2335 CLOCK AGPIO(GPIO_SM2335_DAT) + MAX_SM2335_DAT, // SM2335 DATA #endif // USE_SM2335 +#ifdef USE_BP1658CJ + AGPIO(GPIO_BP1658CJ_CLK), // BP1658CJ CLOCK + AGPIO(GPIO_BP1658CJ_DAT) + MAX_BP1658CJ_DAT, // BP1658CJ DATA +#endif // USE_BP1658CJ #ifdef USE_BP5758D AGPIO(GPIO_BP5758D_CLK), // BP5758D CLOCK AGPIO(GPIO_BP5758D_DAT), // BP5758D DATA diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index 0fa7d6f69..7f952b8f5 100644 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -574,8 +574,7 @@ typedef struct { SOBitfield3 flag3; // 3A0 uint16_t energy_kWhdoy; // 3A4 uint16_t energy_min_power; // 3A6 - - uint8_t free_3A8[4]; // 3A8 - ex_switchmode4-7, Free since 9.2.0.6 + uint32_t pn532_password; // 3A8 - ex_switchmode4-7, Free since 9.2.0.6 #ifdef CONFIG_IDF_TARGET_ESP32S3 // ------------------------------------ @@ -688,15 +687,15 @@ typedef struct { uint16_t mqtt_socket_timeout; // 52E uint8_t mqtt_wifi_timeout; // 530 uint8_t ina219_mode; // 531 - uint16_t ex_pulse_timer[8]; // 532 Free since 11.0.0.3 + + uint16_t ex_pulse_timer[8]; // 532 ex_pulse_timer free since 11.0.0.3 + uint16_t button_debounce; // 542 uint32_t ipv4_address[5]; // 544 uint32_t ipv4_rgx_address; // 558 uint32_t ipv4_rgx_subnetmask; // 55C uint16_t pwm_value_ext[16-5]; // 560 Extension to pwm_value to store up to 16 PWM for ESP32. This array stores values 5..15 - - uint8_t free_576[2]; // 576 - + uint16_t pn532_pack; // 576 int32_t weight_offset; // 578 uint16_t pulse_timer[MAX_PULSETIMERS]; // 57C SysMBitfield1 flag2; // 5BC @@ -842,7 +841,9 @@ typedef struct { uint16_t flowratemeter_calibration[2];// F78 int32_t energy_kWhexport_ph[3]; // F7C uint32_t eth_ipv4_address[5]; // F88 + uint32_t ex_energy_kWhtotal; // F9C + SBitfield1 sbflag1; // FA0 TeleinfoCfg teleinfo; // FA4 uint64_t rf_protocol_mask; // FA8 diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index 6d24b16b5..c2ac91bfd 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 = 0x0C020002; // 12.2.0.2 +const uint32_t VERSION = 0x0C020003; // 12.2.0.3 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index 3f1be7cb8..4138c8863 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM gevind by adres" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Ewekansige Zigbee parameters, kyk asseblief met 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energie Vandag" #define D_ENERGY_YESTERDAY "Energie Gister" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "Diep slaap" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 906634768..d8d775b2b 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Консумация за днес" #define D_ENERGY_YESTERDAY "Консумация за вчера" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/ca_AD.h b/tasmota/language/ca_AD.h index 298302d63..defb50b95 100644 --- a/tasmota/language/ca_AD.h +++ b/tasmota/language/ca_AD.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energy Today" #define D_ENERGY_YESTERDAY "Energy Yesterday" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 9c610b11c..f7d204123 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Spotřeba Dnes" #define D_ENERGY_YESTERDAY "Spotřeba Včera" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 7d17dc86a..581617431 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM gefunden an Adresse" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Zufällige Zigbee Parameter erstellt, Überprüfung mit 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energie heute" #define D_ENERGY_YESTERDAY "Energie gestern" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index d08787942..d6c5184e3 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Ενέργεια σήμερα" #define D_ENERGY_YESTERDAY "Ενέργεια χθες" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 48e822ae2..ff1ba164a 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energy Today" #define D_ENERGY_YESTERDAY "Energy Yesterday" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 741a7a03f..d246517a7 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "Encontrada EEPROM de ZBBridge en" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Configurando parámetros Zigbee de forma aleatoria. Usar 'ZbConfig' para revisarlos." +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energía Hoy" #define D_ENERGY_YESTERDAY "Energía Ayer" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index f5882312e..f00e77194 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "EEPROM ZBBridge trouvée à l'adresse" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomisation des paramètres ZigBee, veuillez vérifier avec 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xsns_03_energy.ino #define D_ENERGY_TODAY "Énergie aujourd'hui" #define D_ENERGY_YESTERDAY "Énergie hier" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 DAT" #define D_SENSOR_SM2335_CLK "SM2335 CLK" #define D_SENSOR_SM2335_DAT "SM2335 DAT" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "Hibernation" diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index fe2966aad..8f36bb8f8 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM fûn op adres" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, kontrolearje asjebleaft mei 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Konsumpsje hjoed" #define D_ENERGY_YESTERDAY "Konsumpsje juster" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 369ce1d51..fe3ef7f3a 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "צריכה יומית" #define D_ENERGY_YESTERDAY "צריכה בעבר" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 03afbab60..652adaf3a 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM található a címen" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Zigbee paramétereknek véletlennek kell lenniük, ellenőrizd a 'ZbConfig'-gal" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Mai energia" #define D_ENERGY_YESTERDAY "Tegnapi energia" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 5a510d64f..e718cbc51 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v9.4.0.1 - Last update 05.10.2022 + * Updated until v9.4.0.1 - Last update 30.10.2022 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "Trovata EEPROM ZBBridge all'indirizzo" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizzazione parametri Zigbee, controlla con \"ZbConfig\"" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali - RX" +#define D_SENSOR_DALI_TX "Dali - TX" +#define D_CONFIGURE_DALI "DALI - Config" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energia - oggi" #define D_ENERGY_YESTERDAY "Energia - ieri" @@ -793,6 +798,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 - DATI" #define D_SENSOR_SM2335_CLK "SM2335 - CLK" #define D_SENSOR_SM2335_DAT "SM2335 - DATI" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ - CLK" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ - DATI" #define D_SENSOR_BP5758D_CLK "BP5758D - CLK" #define D_SENSOR_BP5758D_DAT "BP5758D - DATI" #define D_SENSOR_DEEPSLEEP "Sleep profondo" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 7a2e508f3..f70d84529 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "금일 전력 사용량" #define D_ENERGY_YESTERDAY "어제 전력 사용량" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 3853c69b7..54a973983 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM aanwezig op adres" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Willekeurige Zigbee parameters gemaakt, controleer met 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Verbruik vandaag" #define D_ENERGY_YESTERDAY "Verbruik gisteren" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 9eb7e64bf..0c37c4a12 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "Znaleziono ZBBridge EEPROM na adresie" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Losowanie parametrów Zigbee, proszę sprawdzić 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energia dzisiaj" #define D_ENERGY_YESTERDAY "Energia wczoraj" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "Głęboko uśpiony" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 8ea175cca..5d56e0150 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "EEPROM ZBBridge encontrada no endereço" // "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizando parametros Zigbee, por favor congira em 'ZbConfig'" // "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Consumo energético de hoje" #define D_ENERGY_YESTERDAY "Consumo energético de ontem" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index c9bc5153b..20851d0fe 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM encontrada no edereço" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomização de parâmetros Zigbee, por-favor verifique a 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Consumo energético de hoje" #define D_ENERGY_YESTERDAY "Consumo energético de ontem" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 0d8cca5bc..0adc3cf66 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energia de Azi" #define D_ENERGY_YESTERDAY "Energia de Ieri" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 2354947c0..7b5c92433 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Конфигурация DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Энергия Сегодня" #define D_ENERGY_YESTERDAY "Энергия Вчера" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 1afb86018..b2a2e6727 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Spotreba dnes" #define D_ENERGY_YESTERDAY "Spotreba včera" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 3b80797ad..abec120b1 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energi idag" #define D_ENERGY_YESTERDAY "Energi igår" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 7f5ffac7e..1000df44e 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energy Today" #define D_ENERGY_YESTERDAY "Energy Yesterday" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 510a975fb..9561005bb 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Енергія Сьогодні" #define D_ENERGY_YESTERDAY "Енергія Вчора" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index 8e0837bd0..6bf27fff4 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Năng lượng tiêu thụ hôm nay" #define D_ENERGY_YESTERDAY "Năng lượng tiêu thụ hôm qua" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 26b7aa758..a09337d9a 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "找到 ZBBridge EEPROM, 地址:" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "正在随机化 Zigbee 参数, 请通过 'ZbConfig' 检查" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "今日用电量" #define D_ENERGY_YESTERDAY "昨日用电量" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 2ecde2dce..393b60a5e 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -511,6 +511,11 @@ #define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" #define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +// xdrv_89_dali.ino +#define D_SENSOR_DALI_RX "Dali RX" +#define D_SENSOR_DALI_TX "Dali TX" +#define D_CONFIGURE_DALI "Config DALI" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "今日用電量" #define D_ENERGY_YESTERDAY "昨日用電量" @@ -795,6 +800,8 @@ #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_SM2335_CLK "SM2335 Clk" #define D_SENSOR_SM2335_DAT "SM2335 Dat" +#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" +#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" #define D_SENSOR_BP5758D_CLK "BP5758D Clk" #define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 51ea0d677..aacbc1b64 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -562,6 +562,7 @@ #define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code) #define USE_SM2135 // Add support for SM2135 RGBCW led control as used in Action LSC (+0k6 code) #define USE_SM2335 // Add support for SM2335 RGBCW led control as used in SwitchBot Color Bulb (+0k7 code) +#define USE_BP1658CJ // Add support for BP1658CJ RGBCW led control as used in Orein OS0100411267 Bulb #define USE_BP5758D // Add support for BP5758D RGBCW led control as used in some Tuya lightbulbs (+0k8 code) #define USE_SONOFF_L1 // Add support for Sonoff L1 led control #define USE_ELECTRIQ_MOODL // Add support for ElectriQ iQ-wifiMOODL RGBW LED controller (+0k3 code) @@ -776,9 +777,8 @@ #define MP3_VOLUME 30 // Set the startup volume on init, the range can be 0..100(max) // #define USE_DY_SV17F // Use of DY-SV17F MP3 Player commands: play, stop, track and volume //#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger (+1k6 code) -//#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) -// #define USE_PN532_DATA_FUNCTION // Add sensor40 command support for erase, setting data block content (+1k7 code, 388 bytes mem) -// #define USE_PN532_DATA_RAW // Allow DATA block to be used by non-alpha-numberic data (+ 80 bytes code, 48 bytes ram) +//#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k7 code, 156 bytes mem) +// #define USE_PN532_DATA_FUNCTION // Add sensor40 command support for erase, setting data block content (+3k code, 32 bytes mem) //#define USE_RDM6300 // Add support for RDM6300 125kHz RFID Reader (+0k8) //#define USE_IBEACON // Add support for bluetooth LE passive scan of ibeacon devices (uses HM17 module) //#define USE_GPS // Add support for GPS and NTP Server for becoming Stratus 1 Time Source (+3k1 code, +132 bytes RAM) @@ -1034,6 +1034,11 @@ #define USE_ESP32_SENSORS // Add support for ESP32 temperature and optional hall effect sensor +// #define USE_DALI // Add support for DALI + #define DALI_IN_INVERT 0 // DALI RX inverted ? + #define DALI_OUT_INVERT 0 // DALI TX inverted ? + #define DALI_TIMER 0 // ESP32 hardware timer number 0-3 !!! timer 3 used in xdrv_10_scripter.ino !!! + //#define USE_SONOFF_SPM // Add support for ESP32 based Sonoff Smart Stackable Power Meter (+11k code) //#define USE_DISPLAY_TM1621_SONOFF // Add support for TM1621 dsiplay driver used by Sonoff POWR3xxD and THR3xxD @@ -1070,6 +1075,7 @@ #define USE_BERRY_PSRAM // Allocate Berry memory in PSRAM if PSRAM is connected - this might be slightly slower but leaves main memory intact #define USE_BERRY_IRAM // Allocate some data structures in IRAM (which is ususally unused) when possible and if no PSRAM is available // #define USE_BERRY_DEBUG // Compile Berry bytecode with line number information, makes exceptions easier to debug. Adds +8% of memory consumption for compiled code + // #define UBE_BERRY_DEBUG_GC // Print low-level GC metrics // #define USE_BERRY_INT64 // Add 64 bits integer support (+1.7KB Flash) #define USE_WEBCLIENT // Enable `webclient` to make HTTP/HTTPS requests. Can be disabled for security reasons. // #define USE_WEBCLIENT_HTTPS // Enable HTTPS outgoing requests based on BearSSL (much ligher then mbedTLS, 42KB vs 150KB) in insecure mode (no verification of server's certificate) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 707f95771..f8cebb836 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -253,6 +253,7 @@ struct TasmotaGlobal_t { power_t blink_power; // Blink power state power_t blink_powersave; // Blink start power save state power_t blink_mask; // Blink relay active mask + power_t power_on_delay_state; int serial_in_byte_counter; // Index in receive buffer @@ -333,6 +334,7 @@ struct TasmotaGlobal_t { uint8_t last_source; // Last command source uint8_t shutters_present; // Number of actual define shutters uint8_t discovery_counter; // Delayed discovery counter + uint8_t power_on_delay; // Delay relay power on to reduce power surge (SetOption47) #ifdef USE_PWM_DIMMER uint8_t restore_powered_off_led_counter; // Seconds before powered-off LED (LEDLink) is restored uint8_t pwm_dimmer_led_bri; // Adjusted brightness LED level @@ -516,7 +518,7 @@ void setup(void) { Settings->baudrate = APP_BAUDRATE / 300; Settings->serial_config = TS_SERIAL_8N1; } - SetSerialBaudrate(Settings->baudrate * 300); // Reset serial interface if current baudrate is different from requested baudrate + SetSerialInitBegin(); // Reset serial interface if current baudrate and/or config is different from requested settings if (1 == RtcReboot.fast_reboot_count) { // Allow setting override only when all is well UpdateQuickPowerCycle(true); diff --git a/tasmota/tasmota_support/settings.ino b/tasmota/tasmota_support/settings.ino index bf1f9ba63..c31a603bf 100644 --- a/tasmota/tasmota_support/settings.ino +++ b/tasmota/tasmota_support/settings.ino @@ -45,7 +45,7 @@ void RtcSettingsSave(void) { if (RTC_MEM_VALID != RtcSettings.valid) { memset(&RtcSettings, 0, sizeof(RtcSettings)); RtcSettings.valid = RTC_MEM_VALID; -// RtcSettings.ex_energy_kWhtoday = Settings->energy_power_calibration2; +// RtcSettings.ex_energy_kWhtoday = Settings->energy_power_calibration2; // = ex_energy_kWhtoday // RtcSettings.ex_energy_kWhtotal = Settings->ex_energy_kWhtotal; for (uint32_t i = 0; i < 3; i++) { RtcSettings.energy_kWhtoday_ph[i] = Settings->energy_kWhtoday_ph[i]; @@ -914,6 +914,7 @@ void SettingsDefaultSet2(void) { // Serial Settings->serial_config = TS_SERIAL_8N1; Settings->baudrate = APP_BAUDRATE / 300; + Settings->sserial_config = TS_SERIAL_8N1; Settings->sbaudrate = SOFT_BAUDRATE / 300; Settings->serial_delimiter = 0xff; Settings->seriallog_level = SERIAL_LOG_LEVEL; @@ -1535,8 +1536,8 @@ void SettingsDelta(void) { memset(&Settings->energy_kWhtoday_ph, 0, 36); memset(&RtcSettings.energy_kWhtoday_ph, 0, 24); Settings->energy_kWhtotal_ph[0] = Settings->ex_energy_kWhtotal; - Settings->energy_kWhtoday_ph[0] = Settings->energy_power_calibration2; - Settings->energy_kWhyesterday_ph[0] = Settings->energy_voltage_calibration2; + Settings->energy_kWhtoday_ph[0] = Settings->energy_power_calibration2; // = ex_energy_kWhtoday + Settings->energy_kWhyesterday_ph[0] = Settings->energy_voltage_calibration2; // = ex_energy_kWhyesterday RtcSettings.energy_kWhtoday_ph[0] = RtcSettings.ex_energy_kWhtoday; RtcSettings.energy_kWhtotal_ph[0] = RtcSettings.ex_energy_kWhtotal; } diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 3dbebd6e0..2e1e77dd0 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -106,6 +106,11 @@ uint32_t ResetReason(void) { return ESP_ResetInfoReason(); } +bool ResetReasonPowerOn(void) { + uint32_t reset_reason = ESP_ResetInfoReason(); + return ((reset_reason == REASON_DEFAULT_RST) || (reset_reason == REASON_EXT_SYS_RST)); +} + String GetResetReason(void) { if (OsWatchBlockedLoop()) { char buff[32]; @@ -1977,6 +1982,13 @@ void SetSerialBegin(void) { #endif // ESP32 } +void SetSerialInitBegin(void) { + TasmotaGlobal.baudrate = Settings->baudrate * 300; + if ((GetSerialBaudrate() != TasmotaGlobal.baudrate) || (TS_SERIAL_8N1 != Settings->serial_config)) { + SetSerialBegin(); + } +} + void SetSerialConfig(uint32_t serial_config) { if (serial_config > TS_SERIAL_8O2) { serial_config = TS_SERIAL_8N1; diff --git a/tasmota/tasmota_support/support_esp.ino b/tasmota/tasmota_support/support_esp.ino index b4fb28cf6..a0ce1d228 100644 --- a/tasmota/tasmota_support/support_esp.ino +++ b/tasmota/tasmota_support/support_esp.ino @@ -99,13 +99,49 @@ void *special_calloc(size_t num, size_t size) { } String GetDeviceHardware(void) { + /* + ESP8266 SoCs + - 32-bit MCU & 2.4 GHz Wi-Fi + - High-performance 160 MHz single-core CPU + - +19.5 dBm output power ensures a good physical range + - Sleep current is less than 20 μA, making it suitable for battery-powered and wearable-electronics applications + - Peripherals include UART, GPIO, I2C, I2S, SDIO, PWM, ADC and SPI + */ // esptool.py get_efuses - uint32_t efuse1 = *(uint32_t*)(0x3FF00050); - uint32_t efuse2 = *(uint32_t*)(0x3FF00054); -// uint32_t efuse3 = *(uint32_t*)(0x3FF00058); -// uint32_t efuse4 = *(uint32_t*)(0x3FF0005C); + uint32_t efuse0 = *(uint32_t*)(0x3FF00050); +// uint32_t efuse1 = *(uint32_t*)(0x3FF00054); + uint32_t efuse2 = *(uint32_t*)(0x3FF00058); + uint32_t efuse3 = *(uint32_t*)(0x3FF0005C); - if (((efuse1 & (1 << 4)) || (efuse2 & (1 << 16))) && (ESP.getFlashChipRealSize() < 1048577)) { // ESP8285 can only have 1M flash + bool r0_4 = efuse0 & (1 << 4); // ESP8285 + bool r2_16 = efuse2 & (1 << 16); // ESP8285 + if (r0_4 || r2_16) { // ESP8285 + // 1M 2M 2M 4M + // r0_4 1 1 0 0 + bool r3_25 = efuse3 & (1 << 25); // ESP8285 flash matrix 0 0 1 1 + bool r3_26 = efuse3 & (1 << 26); // ESP8285 flash matrix 0 1 0 1 + bool r3_27 = efuse3 & (1 << 27); // ESP8285 flash matrix 0 0 0 0 + uint32_t pkg_version = 0; + if (!r3_27) { + if (r0_4 && !r3_25) { + pkg_version = (r3_26) ? 2 : 1; + } + else if (!r0_4 && r3_25) { + pkg_version = (r3_26) ? 4 : 2; + } + } + bool max_temp = efuse0 & (1 << 5); // Max flash temperature (0 = 85C, 1 = 105C) + switch (pkg_version) { + case 1: + if (max_temp) { return F("ESP8285H08"); } // 1M flash + else { return F("ESP8285N08"); } + case 2: + if (max_temp) { return F("ESP8285H16"); } // 2M flash + else { return F("ESP8285N16"); } + case 4: + if (max_temp) { return F("ESP8285H32"); } // 4M flash + else { return F("ESP8285N32"); } + } return F("ESP8285"); } return F("ESP8266EX"); @@ -768,6 +804,17 @@ typedef struct { bool single_core = (1 == chip_info.cores); if (chip_model < 2) { // ESP32 + /* + ESP32 Series + - 32-bit MCU & 2.4 GHz Wi-Fi & Bluetooth/Bluetooth LE + - Two or one CPU core(s) with adjustable clock frequency, ranging from 80 MHz to 240 MHz + - +19.5 dBm output power ensures a good physical range + - Classic Bluetooth for legacy connections, also supporting L2CAP, SDP, GAP, SMP, AVDTP, AVCTP, A2DP (SNK) and AVRCP (CT) + - Support for Bluetooth Low Energy (Bluetooth LE) profiles including L2CAP, GAP, GATT, SMP, and GATT-based profiles like BluFi, SPP-like, etc + - Bluetooth Low Energy (Bluetooth LE) connects to smart phones, broadcasting low-energy beacons for easy detection + - Sleep current is less than 5 μA, making it suitable for battery-powered and wearable-electronics applications + - Peripherals include capacitive touch sensors, Hall sensor, SD card interface, Ethernet, high-speed SPI, UART, I2S and I2C + */ #ifdef CONFIG_IDF_TARGET_ESP32 /* esptool: def get_pkg_version(self): @@ -807,6 +854,15 @@ typedef struct { return F("ESP32"); } else if (2 == chip_model) { // ESP32-S2 + /* + ESP32-S2 Series + - 32-bit MCU & 2.4 GHz Wi-Fi + - High-performance 240 MHz single-core CPU + - Ultra-low-power performance: fine-grained clock gating, dynamic voltage and frequency scaling + - Security features: eFuse、flash encryption, secure boot, signature verification, integrated AES, SHA and RSA algorithms + - Peripherals include 43 GPIOs, 1 full-speed USB OTG interface, SPI, I2S, UART, I2C, LED PWM, LCD interface, camera interface, ADC, DAC, touch sensor, temperature sensor + - Availability of common cloud connectivity agents and common product features shortens the time to market + */ #ifdef CONFIG_IDF_TARGET_ESP32S2 /* esptool: def get_flash_version(self): @@ -840,13 +896,19 @@ typedef struct { #endif // CONFIG_IDF_TARGET_ESP32S2 return F("ESP32-S2"); } - else if (9 == chip_model) { // ESP32-S3 -#ifdef CONFIG_IDF_TARGET_ESP32S3 - // no variants for now -#endif // CONFIG_IDF_TARGET_ESP32S3 - return F("ESP32-S3"); // Max 240MHz, Dual core, QFN 7*7, ESP32-S3-WROOM-1, ESP32-S3-DevKitC-1 + else if (4 == chip_model) { // ESP32-S3(beta2) + return F("ESP32-S3"); } - else if (5 == chip_model) { // ESP32-C3 + else if (5 == chip_model) { // ESP32-C3 = ESP8685 + /* + ESP32-C3 Series + - 32-bit RISC-V MCU & 2.4 GHz Wi-Fi & Bluetooth 5 (LE) + - 32-bit RISC-V single-core processor with a four-stage pipeline that operates at up to 160 MHz + - State-of-the-art power and RF performance + - 400 KB of SRAM and 384 KB of ROM on the chip, and SPI, Dual SPI, Quad SPI, and QPI interfaces that allow connection to flash + - Reliable security features ensured by RSA-3072-based secure boot, AES-128-XTS-based flash encryption, the innovative digital signature and the HMAC peripheral, hardware acceleration support for cryptographic algorithms + - Rich set of peripheral interfaces and GPIOs, ideal for various scenarios and complex applications + */ #ifdef CONFIG_IDF_TARGET_ESP32C3 /* esptool: def get_pkg_version(self): @@ -894,7 +956,22 @@ typedef struct { #endif // CONFIG_IDF_TARGET_ESP32C6 return F("ESP32-C6"); } - else if (10 == chip_model) { // ESP32-H2 + else if (9 == chip_model) { // ESP32-S3 + /* + ESP32-S3 Series + - 32-bit MCU & 2.4 GHz Wi-Fi & Bluetooth 5 (LE) + - Xtensa® 32-bit LX7 dual-core processor that operates at up to 240 MHz + - 512 KB of SRAM and 384 KB of ROM on the chip, and SPI, Dual SPI, Quad SPI, Octal SPI, QPI, and OPI interfaces that allow connection to flash and external RAM + - Additional support for vector instructions in the MCU, which provides acceleration for neural network computing and signal processing workloads + - Peripherals include 45 programmable GPIOs, SPI, I2S, I2C, PWM, RMT, ADC and UART, SD/MMC host and TWAITM + - Reliable security features ensured by RSA-based secure boot, AES-XTS-based flash encryption, the innovative digital signature and the HMAC peripheral, “World Controller” + */ +#ifdef CONFIG_IDF_TARGET_ESP32S3 + // no variants for now +#endif // CONFIG_IDF_TARGET_ESP32S3 + return F("ESP32-S3"); // Max 240MHz, Dual core, QFN 7*7, ESP32-S3-WROOM-1, ESP32-S3-DevKitC-1 + } + else if (10 == chip_model) { // ESP32-H2(beta1) #ifdef CONFIG_IDF_TARGET_ESP32H2 /* esptool: def get_pkg_version(self): @@ -916,6 +993,33 @@ typedef struct { #endif // CONFIG_IDF_TARGET_ESP32H2 return F("ESP32-H2"); } + else if (12 == chip_model) { // ESP32-C2 = ESP8684 + /* + ESP32-C2 Series + - 32-bit RISC-V MCU & 2.4 GHz Wi-Fi & Bluetooth 5 (LE) + - 32-bit RISC-V single-core processor that operates at up to 120 MHz + - State-of-the-art power and RF performance + - 576 KB ROM, 272 KB SRAM (16 KB for cache) on the chip + - 14 programmable GPIOs: SPI, UART, I2C, LED PWM controller, General DMA controller (GDMA), SAR ADC, Temperature sensor + */ + + return F("ESP32-C2"); + } + else if (13 == chip_model) { // ESP32-C6 + /* + ESP32-C6 Series + - 32-bit RISC-V MCU & 2.4 GHz Wi-Fi 6 & Bluetooth 5 (LE) & IEEE 802.15.4 + - 32-bit RISC-V single-core processor that operates at up to 160 MHz + - State-of-the-art power and RF performance + - 320 KB ROM, 512 KB SRAM, 16 KB Low-power SRAM on the chip, and works with external flash + - 30 (QFN40) or 22 (QFN32) programmable GPIOs, with support for SPI, UART, I2C, I2S, RMT, TWAI and PWM + */ + + return F("ESP32-C6"); + } + else if (14 == chip_model) { // ESP32-H2(beta2) + return F("ESP32-H2"); + } return F("ESP32"); } diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index 78d972340..9c728ef75 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -840,10 +840,15 @@ void ResponseAppendFeatures(void) #if defined(USE_ENERGY_SENSOR) && defined(USE_MODBUS_ENERGY) feature9 |= 0x00000010; // xnrg_29_modbus.ino #endif -// feature9 |= 0x00000020; -// feature9 |= 0x00000040; -// feature9 |= 0x00000080; - +#if defined(USE_SPI) && defined(USE_SHELLY_PRO) + feature9 |= 0x00000020; // xdrv_88_esp32_shelly_pro.ino +#endif +#ifdef USE_DALI + feature9 |= 0x00000040; // xdrv_89_esp32_dali.ino +#endif +#if defined(USE_LIGHT) && defined(USE_BP1658CJ) + feature9 |= 0x00000080; // xlgt_10_bp1658cj.ino +#endif // feature9 |= 0x00000100; // feature9 |= 0x00000200; // feature9 |= 0x00000400; diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index b51856b4b..00fdd00f9 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -240,6 +240,11 @@ void SetLatchingRelay(power_t lpower, uint32_t state) { } void SetDevicePower(power_t rpower, uint32_t source) { + if (TasmotaGlobal.power_on_delay) { + TasmotaGlobal.power_on_delay_state = rpower; + return; + } + ShowSource(source); TasmotaGlobal.last_source = source; @@ -384,7 +389,7 @@ void SetPowerOnState(void) SetDevicePower(1, SRC_RESTART); } else { power_t devices_mask = POWER_MASK >> (POWER_SIZE - TasmotaGlobal.devices_present); - if ((ResetReason() == REASON_DEFAULT_RST) || (ResetReason() == REASON_EXT_SYS_RST)) { + if (ResetReasonPowerOn()) { switch (Settings->poweronstate) { case POWER_ALL_OFF: case POWER_ALL_OFF_PULSETIME_ON: @@ -422,7 +427,8 @@ void SetPowerOnState(void) uint32_t port = 0; for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { #ifdef ESP8266 - if (!Settings->flag3.no_power_feedback) { // SetOption63 - Don't scan relay power state at restart - #5594 and #5663 + if (!Settings->flag3.no_power_feedback && // SetOption63 - Don't scan relay power state at restart - #5594 and #5663 + !TasmotaGlobal.power_on_delay) { // SetOption47 - Delay switching relays to reduce power surge at power on if ((port < MAX_RELAYS) && PinUsed(GPIO_REL1, port)) { if (bitRead(TasmotaGlobal.rel_bistable, port)) { port++; // Skip both bistable relays as always 0 @@ -1056,6 +1062,29 @@ void PerformEverySecond(void) #endif } + if (TasmotaGlobal.power_on_delay) { + if (1 == Settings->param[P_POWER_ON_DELAY2]) { // SetOption47 1 + // Allow relay power on once network is available + if (!TasmotaGlobal.global_state.network_down) { + TasmotaGlobal.power_on_delay = 0; + } + } + else if (2 == Settings->param[P_POWER_ON_DELAY2]) { // SetOption47 2 + // Allow relay power on once mqtt is available + if (!TasmotaGlobal.global_state.mqtt_down) { + TasmotaGlobal.power_on_delay = 0; + } + } + else { // SetOption47 3..255 + // Allow relay power on after x seconds + TasmotaGlobal.power_on_delay--; + } + if (!TasmotaGlobal.power_on_delay && TasmotaGlobal.power_on_delay_state) { + // Set relays according to last SetDevicePower() request + SetDevicePower(TasmotaGlobal.power_on_delay_state, SRC_SO47); + } + } + if (TasmotaGlobal.mqtt_cmnd_blocked_reset) { TasmotaGlobal.mqtt_cmnd_blocked_reset--; if (!TasmotaGlobal.mqtt_cmnd_blocked_reset) { @@ -2046,6 +2075,19 @@ void GpioInit(void) // AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t*)TasmotaGlobal.gpio_pin, nitems(TasmotaGlobal.gpio_pin), sizeof(TasmotaGlobal.gpio_pin[0])); + if (ResetReasonPowerOn()) { + TasmotaGlobal.power_on_delay = Settings->param[P_POWER_ON_DELAY2]; // SetOption47 - Delay switching relays to reduce power surge at power on + if (TasmotaGlobal.power_on_delay) { + // This is the earliest possibility to disable relays connected to esp8266/esp32 gpios at power up to reduce power surge + for (uint32_t i = 0; i < MAX_RELAYS; i++) { + if (PinUsed(GPIO_REL1, i)) { + DigitalWrite(GPIO_REL1, i, bitRead(TasmotaGlobal.rel_inverted, i) ? 1 : 0); // Off + } + } + AddLog(LOG_LEVEL_DEBUG, PSTR("INI: SO47 %d Power off relays"), Settings->param[P_POWER_ON_DELAY2]); + } + } + analogWriteRange(Settings->pwm_range); // Default is 1023 (Arduino.h) analogWriteFreq(Settings->pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c) @@ -2169,7 +2211,11 @@ void GpioInit(void) } } - delay(Settings->param[P_POWER_ON_DELAY] * 10); // SetOption46 - Allow Wemos D1 power to stabilize before starting I2C polling for devices powered locally + if (Settings->param[P_POWER_ON_DELAY]) { // SetOption46 - Allow Wemos D1 power to stabilize before starting I2C polling for devices powered locally + uint32_t init_delay = Settings->param[P_POWER_ON_DELAY] * 10; + AddLog(LOG_LEVEL_DEBUG, PSTR("INI: SO46 Wait %d msec"), init_delay); + delay(init_delay); + } #ifdef USE_I2C TasmotaGlobal.i2c_enabled = (PinUsed(GPIO_I2C_SCL) && PinUsed(GPIO_I2C_SDA)); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index f6e90ca2b..cef329705 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -41,6 +41,9 @@ #define D_CMND_TARIFF "Tariff" #define D_CMND_MODULEADDRESS "ModuleAddress" +enum EnergyCalibration { + ENERGY_POWER_CALIBRATION, ENERGY_VOLTAGE_CALIBRATION, ENERGY_CURRENT_CALIBRATION, ENERGY_FREQUENCY_CALIBRATION }; + enum EnergyCommands { CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL, CMND_FREQUENCYCAL, CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_MODULEADDRESS, CMND_ENERGYCONFIG }; @@ -412,8 +415,8 @@ bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool & return (change != save_flag); } -void EnergyMarginCheck(void) -{ +void EnergyMarginCheck(void) { + if (!Energy.phase_count || (TasmotaGlobal.uptime < 8)) { return; } if (Energy.power_steady_counter) { Energy.power_steady_counter--; return; @@ -637,11 +640,6 @@ void EnergyEverySecond(void) * Commands \*********************************************************************************************/ -void EnergyCommandCalResponse(uint32_t nvalue) { - snprintf_P(XdrvMailbox.command, CMDSZ, PSTR("%sCal"), XdrvMailbox.command); - ResponseCmndNumber(nvalue); -} - void ResponseCmndEnergyTotalYesterdayToday(void) { char value_chr[TOPSZ]; // Used by EnergyFormatIndex char value2_chr[TOPSZ]; @@ -835,71 +833,117 @@ void CmndTariff(void) { GetStateText(Settings->flag3.energy_weekend)); // CMND_TARIFF } +uint32_t EnergyGetCalibration(uint32_t chan, uint32_t cal_type) { + uint32_t channel = ((1 == chan) && (2 == Energy.phase_count)) ? 1 : 0; + if (channel) { + switch (cal_type) { + case ENERGY_POWER_CALIBRATION: return Settings->energy_power_calibration2; + case ENERGY_VOLTAGE_CALIBRATION: return Settings->energy_voltage_calibration2; + case ENERGY_CURRENT_CALIBRATION: return Settings->energy_current_calibration2; + } + } else { + switch (cal_type) { + case ENERGY_POWER_CALIBRATION: return Settings->energy_power_calibration; + case ENERGY_VOLTAGE_CALIBRATION: return Settings->energy_voltage_calibration; + case ENERGY_CURRENT_CALIBRATION: return Settings->energy_current_calibration; + } + } + return Settings->energy_frequency_calibration; +} + +void EnergyCommandCalSetResponse(uint32_t cal_type) { + if (XdrvMailbox.payload > 99) { + uint32_t channel = ((2 == XdrvMailbox.index) && (2 == Energy.phase_count)) ? 1 : 0; + if (channel) { + switch (cal_type) { + case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration2 = XdrvMailbox.payload; break; + case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration2 = XdrvMailbox.payload; break; + case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration2 = XdrvMailbox.payload; break; + case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = XdrvMailbox.payload; break; + } + } else { + switch (cal_type) { + case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration = XdrvMailbox.payload; break; + case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration = XdrvMailbox.payload; break; + case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration = XdrvMailbox.payload; break; + case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = XdrvMailbox.payload; break; + } + } + } + if (ENERGY_FREQUENCY_CALIBRATION == cal_type) { + ResponseAppend_P(PSTR("%d}"), Settings->energy_frequency_calibration); + } else { + if (2 == Energy.phase_count) { + ResponseAppend_P(PSTR("[%d,%d]}"), EnergyGetCalibration(0, cal_type), EnergyGetCalibration(1, cal_type)); + } else { + ResponseAppend_P(PSTR("%d}"), EnergyGetCalibration(0, cal_type)); + } + } +} + +void EnergyCommandCalResponse(uint32_t cal_type) { + Response_P(PSTR("{\"%s\":"), XdrvMailbox.command); + EnergyCommandCalSetResponse(cal_type); +} + +void EnergyCommandSetCalResponse(uint32_t cal_type) { + Response_P(PSTR("{\"%sCal\":"), XdrvMailbox.command); + EnergyCommandCalSetResponse(cal_type); +} + void CmndPowerCal(void) { Energy.command_code = CMND_POWERCAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds - if (XdrvMailbox.payload > 999) { - Settings->energy_power_calibration = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings->energy_power_calibration); + EnergyCommandCalResponse(ENERGY_POWER_CALIBRATION); } } void CmndVoltageCal(void) { Energy.command_code = CMND_VOLTAGECAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds - if (XdrvMailbox.payload > 999) { - Settings->energy_voltage_calibration = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings->energy_voltage_calibration); + EnergyCommandCalResponse(ENERGY_VOLTAGE_CALIBRATION); } } void CmndCurrentCal(void) { Energy.command_code = CMND_CURRENTCAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds - if (XdrvMailbox.payload > 999) { - Settings->energy_current_calibration = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings->energy_current_calibration); + EnergyCommandCalResponse(ENERGY_CURRENT_CALIBRATION); } } void CmndFrequencyCal(void) { Energy.command_code = CMND_FREQUENCYCAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds - if (XdrvMailbox.payload > 999) { - Settings->energy_frequency_calibration = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings->energy_frequency_calibration); + EnergyCommandCalResponse(ENERGY_FREQUENCY_CALIBRATION); } } void CmndPowerSet(void) { Energy.command_code = CMND_POWERSET; if (XnrgCall(FUNC_COMMAND)) { // Watt - EnergyCommandCalResponse(Settings->energy_power_calibration); + EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION); } } void CmndVoltageSet(void) { Energy.command_code = CMND_VOLTAGESET; if (XnrgCall(FUNC_COMMAND)) { // Volt - EnergyCommandCalResponse(Settings->energy_voltage_calibration); + EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION); } } void CmndCurrentSet(void) { Energy.command_code = CMND_CURRENTSET; if (XnrgCall(FUNC_COMMAND)) { // milliAmpere - EnergyCommandCalResponse(Settings->energy_current_calibration); + EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION); } } void CmndFrequencySet(void) { Energy.command_code = CMND_FREQUENCYSET; if (XnrgCall(FUNC_COMMAND)) { // Hz - EnergyCommandCalResponse(Settings->energy_frequency_calibration); + EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION); } } @@ -1050,9 +1094,6 @@ void EnergyDrvInit(void) { Energy.voltage_available = true; // Enable if voltage is measured Energy.current_available = true; // Enable if current is measured Energy.power_on = true; -#ifdef USE_ENERGY_MARGIN_DETECTION - Energy.power_steady_counter = 8; // Allow for power on stabilization -#endif // USE_ENERGY_MARGIN_DETECTION TasmotaGlobal.energy_driver = ENERGY_NONE; XnrgCall(FUNC_PRE_INIT); // Find first energy driver diff --git a/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino b/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino index 27acc5ae7..538da6b09 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino @@ -1763,6 +1763,7 @@ void LightReapplyColor(void) { void LightAnimate(void) { bool power_off = false; + static int32_t sleep_previous = -1; // previous value of sleep before changing it to PWM_MAX_SLEEP, -1 means unchanged // make sure we update CT range in case SetOption82 was changed Light.strip_timer_counter++; @@ -1770,13 +1771,17 @@ void LightAnimate(void) // set sleep parameter: either settings, // or set a maximum of PWM_MAX_SLEEP if light is on or Fade is running if (Light.power || Light.fade_running) { - if (Settings->sleep > PWM_MAX_SLEEP) { + if (TasmotaGlobal.sleep > PWM_MAX_SLEEP) { + sleep_previous = TasmotaGlobal.sleep; // save previous value of sleep TasmotaGlobal.sleep = PWM_MAX_SLEEP; // set a maximum value (in milliseconds) to sleep to ensure that animations are smooth } else { - TasmotaGlobal.sleep = Settings->sleep; // or keep the current sleep if it's low enough + sleep_previous = -1; // if low enough, don't change it } } else { - TasmotaGlobal.sleep = Settings->sleep; + if (sleep_previous > 0) { + TasmotaGlobal.sleep = sleep_previous; + sleep_previous = -1; // rearm + } } if (!Light.power) { // All channels powered off diff --git a/tasmota/tasmota_xdrv_driver/xdrv_09_timers.ino b/tasmota/tasmota_xdrv_driver/xdrv_09_timers.ino index 438ade4d5..8c1fd530e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_09_timers.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_09_timers.ino @@ -253,10 +253,10 @@ uint16_t TimerGetTimeOfDay(uint8_t index) int16_t xtime = xtimer.time; #ifdef USE_SUNRISE if (xtimer.mode) { - if (xtime >= 12*60) xtime = 12*60 - xtime; - xtime += (int16_t)SunMinutes(xtimer.mode-1); - if (xtime < 0) xtime += 24*60; - if (xtime >= 24*60) xtime -= 24*60; + ApplyTimerOffsets(&xtimer); + xtime = xtimer.time; + if (xtime==2047 && xtimer.mode==1) xtime *= -1; // Sun always has already rises + if (xtime==2046 && xtimer.mode==2) xtime *= -1; // Sun always has already set } #endif return xtime; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino index 6686b8770..49342df27 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino @@ -1458,19 +1458,7 @@ bool findNextVariableValue(char * &pVarname, float &value) } else if (sVarName.startsWith(F("TIMER"))) { uint32_t index = sVarName.substring(5).toInt(); if (index > 0 && index <= MAX_TIMERS) { - value = Settings->timer[index -1].time; -#if defined(USE_SUNRISE) - // Correct %timerN% values for sunrise/sunset timers - if ((1 == Settings->timer[index -1].mode) || (2 == Settings->timer[index -1].mode)) { - // in this context, time variable itself is merely an offset, with <720 being negative - value += -720 + SunMinutes(Settings->timer[index -1].mode -1); - if (2 == Settings->timer[index -1].mode) { - // To aid rule comparative statements, sunset past midnight (high lattitudes) is expressed past 24h00 - // So sunset at 00h45 is at 24h45 - if (value < 360) { value += 1440; } - } - } -#endif // USE_SUNRISE + value = TimerGetTimeOfDay(index -1); } #if defined(USE_SUNRISE) } else if (sVarName.equals(F("SUNRISE"))) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_29_deepsleep.ino b/tasmota/tasmota_xdrv_driver/xdrv_29_deepsleep.ino index 81f7b3a3e..27377eeea 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_29_deepsleep.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_29_deepsleep.ino @@ -118,11 +118,14 @@ void DeepSleepPrepare(void) RtcSettings.deepsleep_slip = tmin(tmax(RtcSettings.deepsleep_slip, 9000), 11000); } +// AddLog(LOG_LEVEL_DEBUG, PSTR("DSL: Time %ld, next %ld, slip %ld"), timeslip, RtcSettings.nextwakeup, RtcSettings.deepsleep_slip ); // It may happen that wakeup in just <5 seconds in future // In this case also add deepsleep to nextwakeup if (RtcSettings.nextwakeup <= (LocalTime() + DEEPSLEEP_MIN_TIME)) { - // ensure nextwakeup is at least in the future + // ensure nextwakeup is at least in the future, and add 5% RtcSettings.nextwakeup += (((LocalTime() + DEEPSLEEP_MIN_TIME - RtcSettings.nextwakeup) / Settings->deepsleep) + 1) * Settings->deepsleep; + RtcSettings.nextwakeup += Settings->deepsleep * 0.05; +// AddLog(LOG_LEVEL_DEBUG, PSTR("DSL: Time too short: time %ld, next %ld, slip %ld"), timeslip, RtcSettings.nextwakeup, RtcSettings.deepsleep_slip); } String dt = GetDT(RtcSettings.nextwakeup); // 2017-03-07T11:08:02 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino index 54c6c2c15..3d6b8f86b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino @@ -151,19 +151,11 @@ extern "C" { break; case 6: // # 06 : Pixels void -> bytes() (mapped to the buffer) { - size_t pixels_bytes; - if (s_ws2812_grb) pixels_bytes = s_ws2812_grb->PixelsSize(); - if (s_sk6812_grbw) pixels_bytes = s_sk6812_grbw->PixelsSize(); - uint8_t * pixels; if (s_ws2812_grb) pixels = s_ws2812_grb->Pixels(); if (s_sk6812_grbw) pixels = s_sk6812_grbw->Pixels(); - be_getbuiltin(vm, "bytes"); be_pushcomptr(vm, pixels); - be_pushint(vm, pixels_bytes); - be_call(vm, 2); - be_pop(vm, 2); } break; case 7: // # 07 : PixelSize void -> int diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_ulp.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_ulp.ino index 4dbc24b3c..9d154a8da 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_ulp.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_ulp.ino @@ -1,5 +1,5 @@ /* - xdrv_52_3_berry_ulp.ino - Berry scripting language, ULP support for ESP32 + xdrv_52_3_berry_ulp.ino - Berry scripting language, ULP support for ESP32, ESP32S2, ESP32S3 Copyright (C) 2021 Stephan Hadinger & Christian Baars, Berry language by Guan Wenliang https://github.com/Skiars/berry @@ -21,9 +21,21 @@ #ifdef USE_BERRY_ULP #include -#if defined(USE_BERRY_ULP) && defined(CONFIG_IDF_TARGET_ESP32) +#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) +#if defined(CONFIG_IDF_TARGET_ESP32) #include "esp32/ulp.h" +#endif // esp32 +#if defined(CONFIG_IDF_TARGET_ESP32S2) +#include "esp32s2/ulp.h" +#include "esp32s2/ulp_riscv.h" +#include "esp32s2/ulp_riscv_adc.h" +#endif // s2 +#if defined(CONFIG_IDF_TARGET_ESP32S3) +#include "esp32s3/ulp.h" +#include "esp32s3/ulp_riscv.h" +#include "esp32s3/ulp_riscv_adc.h" +#endif //s3 #include "driver/rtc_io.h" #include "driver/gpio.h" #include "driver/adc.h" @@ -36,7 +48,11 @@ extern "C" { // // `ULP.run() -> nil` void be_ULP_run(int32_t entry) { +#if defined(CONFIG_IDF_TARGET_ESP32) ulp_run(entry); // entry point should be at the beginning of program +#else // S2 or S3 + ulp_riscv_run(); +#endif } // `ULP.wake_period(period_index:int, period_us:int) -> nil` @@ -52,7 +68,11 @@ extern "C" { // `ULP.get_mem(position:int) -> int` int32_t be_ULP_get_mem(int32_t pos) { - return RTC_SLOW_MEM[pos] & 0xFFFF; // only low 16 bits are used +#if defined(CONFIG_IDF_TARGET_ESP32) + return RTC_SLOW_MEM[pos] & 0xFFFF; // only low 16 bits are used +#else + return RTC_SLOW_MEM[pos]; // full 32bit for RISCV ULP +#endif } // `ULP.gpio_init(pin:int, mode:int) -> rtc_pin:int` @@ -70,25 +90,40 @@ extern "C" { // `ULP.adc_config(channel:int, attenuation:int, width:int) -> nil` // // enums: channel 0-7, attenuation 0-3, width 0-3 - void be_ULP_adc_config(struct bvm *vm, adc1_channel_t channel, adc_atten_t attenuation, adc_bits_width_t width) { - esp_err_t err = adc1_config_channel_atten(channel, attenuation); - err += adc1_config_width(width); + void be_ULP_adc_config(struct bvm *vm, int32_t channel, int32_t attenuation, int32_t width) { +#if defined(CONFIG_IDF_TARGET_ESP32) + esp_err_t err = adc1_config_channel_atten((adc1_channel_t)channel, (adc_atten_t)attenuation); + err += adc1_config_width((adc_bits_width_t)width); if (err != ESP_OK) { be_raisef(vm, "ulp_adc_config_error", "ULP: invalid code err=%i", err); } else { adc1_ulp_enable(); } +#else // S2 or S3 + ulp_riscv_adc_cfg_t cfg = { + .channel = (adc_channel_t)channel, + .atten = (adc_atten_t)attenuation, + .width = (adc_bits_width_t)width + }; + esp_err_t err = ulp_riscv_adc_init(&cfg); + if (err != ESP_OK) { + be_raisef(vm, "ulp_adc_config_error", "ULP: invalid code err=%i", err); + } +#endif } /** * @brief Load a Berry byte buffer containing a ULP program as raw byte data * * @param vm as `ULP.load(code:bytes) -> nil` - * @return void + * @return void for ESP32 or binary type as int32_t on RISCV capable SOC's */ void be_ULP_load(struct bvm *vm, const uint8_t *buf, size_t size) { - // AddLog(LOG_LEVEL_INFO, "ULP: load addr=%p size=%i %*_H", buf, size/4, size, buf); - esp_err_t err = ulp_load_binary(0, buf, size / 4); +#if defined(CONFIG_IDF_TARGET_ESP32) + esp_err_t err = ulp_load_binary(0, buf, size / 4); // FSM type only, specific header, size in long words +#else // S2 or S3 + esp_err_t err = ulp_riscv_load_binary(buf, size); // there are no header bytes, just load and hope for a valid binary - size in bytes +#endif // defined(CONFIG_IDF_TARGET_ESP32) if (err != ESP_OK) { be_raisef(vm, "ulp_load_error", "ULP: invalid code err=%i", err); } @@ -109,10 +144,9 @@ extern "C" { esp_deep_sleep_start(); } - } //extern "C" -#endif //CONFIG_IDF_TARGET_ESP32 +#endif //CONFIG_IDF_TARGET_ESP32 .. S2 .. S3 #endif // USE_BERRY_ULP -#endif // USE_BERRY \ No newline at end of file +#endif // USE_BERRY diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino index 36ac8b4e0..d28e0e41e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino @@ -231,6 +231,7 @@ void BerryObservability(bvm *vm, int event...) { slots_used_before_gc, slots_allocated_before_gc, slots_used_after_gc, slots_allocated_after_gc); +#ifdef UBE_BERRY_DEBUG_GC // Add more in-deptch metrics AddLog(LOG_LEVEL_DEBUG_MORE, D_LOG_BERRY "GC timing (us) 1:%i 2:%i 3:%i 4:%i 5:%i total:%i", vm->micros_gc1 - vm->micros_gc0, @@ -254,6 +255,7 @@ void BerryObservability(bvm *vm, int event...) { vm->gc_mark_module, vm->gc_mark_comobj ); +#endif // make new threshold tighter when we reach high memory usage if (!UsePSRAM() && vm->gc.threshold > 20*1024) { vm->gc.threshold = vm->gc.usage + 10*1024; // increase by only 10 KB diff --git a/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino index 479ea560b..31b1c7a19 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino @@ -35,10 +35,10 @@ * * -- Write multiple coils -- * ModbusSend {"deviceaddress": 1, "functioncode": 15, "startaddress": 1, "type":"bit", "count":4, "values":[1,0,1,1]} - * - * Info for modbusBridgeTCPServer: + * + * Info for modbusBridgeTCPServer: * https://ipc2u.com/articles/knowledge-base/detailed-description-of-the-modbus-tcp-protocol-with-command-examples/ - * + * * Info for modbus serial communications: * https://ozeki.hu/p_5879-mobdbus-function-code-4-read-input-registers.html * https://www.modbustools.com/modbus.html @@ -102,7 +102,7 @@ ModbusBridgeTCP modbusBridgeTCP; #endif #include -TasmotaModbus *tasmotaModbus = nullptr; +TasmotaModbus *modbusBridgeModbus = nullptr; enum class ModbusBridgeError { @@ -172,22 +172,18 @@ ModbusBridge modbusBridge; /********************************************************************************************/ // -// Helper functions for data conversion between little and big endian +// Helper functions // -uint16_t swap_endian16(uint16_t num) +uint16_t ModbusBridgeSwapEndian16(uint16_t num) { return (num>>8) | (num<<8); } -uint32_t swap_endian32(uint32_t num) +void ModbusBridgeAllocError(const char* s) { - return ((num>>24)&0xff) | // move byte 3 to byte 0 - ((num<<8)&0xff0000) | // move byte 1 to byte 2 - ((num>>8)&0xff00) | // move byte 2 to byte 1 - ((num<<24)&0xff000000); // byte 0 to byte 3 + AddLog(LOG_LEVEL_ERROR, PSTR("MBS: could not allocate %s buffer"), s); } - /********************************************************************************************/ // // Applies serial configuration to modbus serial port @@ -199,7 +195,7 @@ bool ModbusBridgeBegin(void) if (Settings->modbus_sconfig > TS_SERIAL_8O2) Settings->modbus_sconfig = TS_SERIAL_8N1; - int result = tasmotaModbus->Begin(Settings->modbus_sbaudrate * 300, ConvertSerialConfig(Settings->modbus_sconfig)); // Reinitialize modbus port with new baud rate + int result = modbusBridgeModbus->Begin(Settings->modbus_sbaudrate * 300, ConvertSerialConfig(Settings->modbus_sconfig)); // Reinitialize modbus port with new baud rate if (result) { if (2 == result) @@ -211,7 +207,7 @@ bool ModbusBridgeBegin(void) return result; } -void SetModbusBridgeConfig(uint32_t serial_config) +void ModbusBridgeSetConfig(uint32_t serial_config) { if (serial_config > TS_SERIAL_8O2) { @@ -224,7 +220,7 @@ void SetModbusBridgeConfig(uint32_t serial_config) } } -void SetModbusBridgeBaudrate(uint32_t baudrate) +void ModbusBridgeSetBaudrate(uint32_t baudrate) { if ((baudrate >= 300) && (baudrate <= 115200)) { @@ -242,14 +238,19 @@ void SetModbusBridgeBaudrate(uint32_t baudrate) // void ModbusBridgeHandle(void) { - bool data_ready = tasmotaModbus->ReceiveReady(); + bool data_ready = modbusBridgeModbus->ReceiveReady(); if (data_ready) { uint8_t *buffer; if (modbusBridge.byteCount == 0) modbusBridge.byteCount = modbusBridge.dataCount * 2; buffer = (uint8_t *)malloc(9 + modbusBridge.byteCount); // Addres(1), Function(1), Length(1), Data(1..n), CRC(2) + if (nullptr == buffer) + { + ModbusBridgeAllocError(PSTR("read")); + return; + } memset(buffer, 0, 9 + modbusBridge.byteCount); - uint32_t error = tasmotaModbus->ReceiveBuffer(buffer, 0, modbusBridge.byteCount); + uint32_t error = modbusBridgeModbus->ReceiveBuffer(buffer, 0, modbusBridge.byteCount); #ifdef USE_MODBUS_BRIDGE_TCP for (uint32_t i = 0; i < nitems(modbusBridgeTCP.client_tcp); i++) @@ -257,7 +258,7 @@ void ModbusBridgeHandle(void) WiFiClient &client = modbusBridgeTCP.client_tcp[i]; if (client) { - uint8_t header[8]; + uint8_t header[9]; uint8_t nrOfBytes = 8; header[0] = modbusBridgeTCP.tcp_transaction_id >> 8; header[1] = modbusBridgeTCP.tcp_transaction_id; @@ -274,7 +275,7 @@ void ModbusBridgeHandle(void) nrOfBytes += 1; client.write(header, 9); } - else if (buffer[1] <= 2) + else if (buffer[1] <= 2) { header[4] = modbusBridge.byteCount >> 8; header[5] = modbusBridge.byteCount + 3; @@ -284,7 +285,7 @@ void ModbusBridgeHandle(void) client.write(buffer + 3, modbusBridge.byteCount); // Don't send CRC nrOfBytes += modbusBridge.byteCount; } - else if (buffer[1] <= 4) + else if (buffer[1] <= 4) { header[4] = modbusBridge.byteCount >> 8; header[5] = modbusBridge.byteCount + 3; @@ -358,10 +359,10 @@ void ModbusBridgeHandle(void) if (modbusBridge.type == ModbusBridgeType::mb_raw) { Response_P(PSTR("{\"" D_JSON_MODBUS_RECEIVED "\":{\"RAW\":[")); - for (uint8_t i = 0; i < tasmotaModbus->ReceiveCount(); i++) + for (uint8_t i = 0; i < modbusBridgeModbus->ReceiveCount(); i++) { ResponseAppend_P(PSTR("%d"), buffer[i]); - if (i < tasmotaModbus->ReceiveCount() - 1) + if (i < modbusBridgeModbus->ReceiveCount() - 1) ResponseAppend_P(PSTR(",")); } ResponseAppend_P(PSTR("]}")); @@ -371,10 +372,10 @@ void ModbusBridgeHandle(void) else if (modbusBridge.type == ModbusBridgeType::mb_hex) { Response_P(PSTR("{\"" D_JSON_MODBUS_RECEIVED "\":{\"HEX\":[")); - for (uint8_t i = 0; i < tasmotaModbus->ReceiveCount(); i++) + for (uint8_t i = 0; i < modbusBridgeModbus->ReceiveCount(); i++) { ResponseAppend_P(PSTR("0x%02X"), buffer[i]); - if (i < tasmotaModbus->ReceiveCount() - 1) + if (i < modbusBridgeModbus->ReceiveCount() - 1) ResponseAppend_P(PSTR(",")); } ResponseAppend_P(PSTR("]}")); @@ -396,7 +397,7 @@ void ModbusBridgeHandle(void) ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_START_ADDRESS "\":%d,"), (buffer[2] << 8) + buffer[3]); dataOffset = 4; } - ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), tasmotaModbus->ReceiveCount()); + ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), modbusBridgeModbus->ReceiveCount()); ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_COUNT "\":%d,"), modbusBridge.count); ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_VALUES "\":[")); @@ -530,7 +531,7 @@ void ModbusBridgeHandle(void) ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_DEVICE_ADDRESS "\":%d,"), buffer[0]); ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_FUNCTION_CODE "\":%d,"), buffer[1]); ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_START_ADDRESS "\":%d,"), (buffer[2] << 8) + buffer[3]); - ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), tasmotaModbus->ReceiveCount()); + ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), modbusBridgeModbus->ReceiveCount()); ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_COUNT "\":%d"), (buffer[4] << 8) + buffer[5]); ResponseAppend_P(PSTR("}")); ResponseJsonEnd(); @@ -557,14 +558,14 @@ void ModbusBridgeInit(void) { if (PinUsed(GPIO_MBR_RX) && PinUsed(GPIO_MBR_TX)) { - tasmotaModbus = new TasmotaModbus(Pin(GPIO_MBR_RX), Pin(GPIO_MBR_TX)); + modbusBridgeModbus = new TasmotaModbus(Pin(GPIO_MBR_RX), Pin(GPIO_MBR_TX)); ModbusBridgeBegin(); #ifdef USE_MODBUS_BRIDGE_TCP // If TCP bridge is enabled allocate a TCP receive buffer modbusBridgeTCP.tcp_buf = (uint8_t *)malloc(MODBUS_BRIDGE_TCP_BUF_SIZE); - if (!modbusBridgeTCP.tcp_buf) + if (nullptr == modbusBridgeTCP.tcp_buf) { - AddLog(LOG_LEVEL_ERROR, PSTR("MBS: MBRTCP could not allocate buffer")); + ModbusBridgeAllocError(PSTR("TCP")); return; } #endif @@ -582,7 +583,7 @@ void ModbusTCPHandle(void) bool busy; // did we transfer some data? int32_t buf_len; - if (!tasmotaModbus) + if (!modbusBridgeModbus) return; // check for a new client connection @@ -656,8 +657,8 @@ void ModbusTCPHandle(void) if (mbfunctioncode <= 2) { count = (uint16_t)((((uint16_t)modbusBridgeTCP.tcp_buf[10]) << 8) | ((uint16_t)modbusBridgeTCP.tcp_buf[11])); - modbusBridge.byteCount = ((count - 1) >> 3) + 1; - modbusBridge.dataCount = ((count - 1) >> 4) + 1; + modbusBridge.byteCount = ((count - 1) >> 3) + 1; + modbusBridge.dataCount = ((count - 1) >> 4) + 1; } else if (mbfunctioncode <= 4) { @@ -667,17 +668,22 @@ void ModbusTCPHandle(void) } else { - // For functioncode 15 & 16 ignore bytecount, tasmotaModbus does calculate this + // For functioncode 15 & 16 ignore bytecount, modbusBridgeModbus does calculate this uint8_t dataStartByte = mbfunctioncode <= 6 ? 10 : 13; uint16_t byteCount = (buf_len - dataStartByte); modbusBridge.byteCount = 2; modbusBridge.dataCount = 1; writeData = (uint16_t *)malloc((byteCount / 2)+1); - + if (nullptr == writeData) + { + ModbusBridgeAllocError(PSTR("write")); + return; + } + if ((mbfunctioncode == 15) || (mbfunctioncode == 16)) count = (uint16_t)((((uint16_t)modbusBridgeTCP.tcp_buf[10]) << 8) | ((uint16_t)modbusBridgeTCP.tcp_buf[11])); else count = 1; - + for (uint16_t dataPointer = 0; dataPointer < byteCount; dataPointer++) { if (dataPointer % 2 == 0) @@ -685,7 +691,7 @@ void ModbusTCPHandle(void) writeData[dataPointer / 2] = (uint16_t)(((uint16_t)modbusBridgeTCP.tcp_buf[dataStartByte + dataPointer]) << 8); } else - { + { writeData[dataPointer / 2] |= ((uint16_t)modbusBridgeTCP.tcp_buf[dataStartByte + dataPointer]); } } @@ -694,7 +700,7 @@ void ModbusTCPHandle(void) AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: MBRTCP to Modbus TransactionId:%d, deviceAddress:%d, functionCode:%d, startAddress:%d, count:%d, recvCount:%d, recvBytes:%d"), modbusBridgeTCP.tcp_transaction_id, mbdeviceaddress, mbfunctioncode, mbstartaddress, count, modbusBridge.dataCount, modbusBridge.byteCount); - tasmotaModbus->Send(mbdeviceaddress, mbfunctioncode, mbstartaddress, count, writeData); + modbusBridgeModbus->Send(mbdeviceaddress, mbfunctioncode, mbstartaddress, count, writeData); free(writeData); } @@ -860,6 +866,11 @@ void CmndModbusBridgeSend(void) else { writeData = (uint16_t *)malloc(modbusBridge.dataCount); + if (nullptr == writeData) + { + ModbusBridgeAllocError(PSTR("write")); + return; + } for (uint8_t jsonDataArrayPointer = 0; jsonDataArrayPointer < writeDataSize; jsonDataArrayPointer++) { @@ -889,7 +900,7 @@ void CmndModbusBridgeSend(void) writeData[jsonDataArrayPointer / 2] = (int8_t)jsonDataArray[jsonDataArrayPointer / 2].getInt(0) << 8; if (modbusBridge.dataCount != writeDataSize / 2) errorcode = ModbusBridgeError::wrongcount; break; - + case ModbusBridgeType::mb_hex: case ModbusBridgeType::mb_raw: case ModbusBridgeType::mb_uint8: @@ -899,31 +910,31 @@ void CmndModbusBridgeSend(void) writeData[jsonDataArrayPointer / 2] = (uint8_t)jsonDataArray[jsonDataArrayPointer].getUInt(0) << 8; if (modbusBridge.dataCount != writeDataSize / 2) errorcode = ModbusBridgeError::wrongcount; break; - + case ModbusBridgeType::mb_int16: - writeData[jsonDataArrayPointer] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getInt(0)) + writeData[jsonDataArrayPointer] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getInt(0)) : (int16_t)jsonDataArray[jsonDataArrayPointer].getInt(0); break; - + case ModbusBridgeType::mb_uint16: - writeData[jsonDataArrayPointer] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getUInt(0)) + writeData[jsonDataArrayPointer] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getUInt(0)) : (int16_t)jsonDataArray[jsonDataArrayPointer].getUInt(0); break; - + case ModbusBridgeType::mb_int32: - writeData[(jsonDataArrayPointer * 2)] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getInt(0)) + writeData[(jsonDataArrayPointer * 2)] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getInt(0)) : (int16_t)(jsonDataArray[jsonDataArrayPointer].getInt(0) >> 16); - writeData[(jsonDataArrayPointer * 2) + 1] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getInt(0) >> 16) + writeData[(jsonDataArrayPointer * 2) + 1] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getInt(0) >> 16) : (uint16_t)(jsonDataArray[jsonDataArrayPointer].getInt(0)); break; - + case ModbusBridgeType::mb_uint32: - writeData[(jsonDataArrayPointer * 2)] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getUInt(0)) + writeData[(jsonDataArrayPointer * 2)] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getUInt(0)) : (uint16_t)(jsonDataArray[jsonDataArrayPointer].getUInt(0) >> 16); - writeData[(jsonDataArrayPointer * 2) + 1] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getUInt(0) >> 16) + writeData[(jsonDataArrayPointer * 2) + 1] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getUInt(0) >> 16) : (uint16_t)(jsonDataArray[jsonDataArrayPointer].getUInt(0)); break; - + case ModbusBridgeType::mb_float: // TODO default: @@ -952,20 +963,20 @@ void CmndModbusBridgeSend(void) if ((modbusBridge.functionCode == ModbusBridgeFunctionCode::mb_writeSingleCoil) || (modbusBridge.functionCode == ModbusBridgeFunctionCode::mb_writeSingleRegister)) modbusBridge.dataCount = 1; - uint8_t error = tasmotaModbus->Send(modbusBridge.deviceAddress, (uint8_t)modbusBridge.functionCode, modbusBridge.startAddress, modbusBridge.dataCount, writeData); + uint8_t error = modbusBridgeModbus->Send(modbusBridge.deviceAddress, (uint8_t)modbusBridge.functionCode, modbusBridge.startAddress, modbusBridge.dataCount, writeData); free(writeData); - + if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("MBS: MBR Driver send error %u"), error); return; - } + } ResponseCmndDone(); } void CmndModbusBridgeSetBaudrate(void) { - SetModbusBridgeBaudrate(XdrvMailbox.payload); + ModbusBridgeSetBaudrate(XdrvMailbox.payload); ResponseCmndNumber(Settings->modbus_sbaudrate * 300); } @@ -981,7 +992,7 @@ void CmndModbusBridgeSetConfig(void) { // Use 0..23 as serial config option if ((XdrvMailbox.payload >= TS_SERIAL_5N1) && (XdrvMailbox.payload <= TS_SERIAL_8O2)) { - SetModbusBridgeConfig(XdrvMailbox.payload); + ModbusBridgeSetConfig(XdrvMailbox.payload); } } else if ((XdrvMailbox.payload >= 5) && (XdrvMailbox.payload <= 8)) @@ -989,7 +1000,7 @@ void CmndModbusBridgeSetConfig(void) int8_t serial_config = ParseSerialConfig(XdrvMailbox.data); if (serial_config >= 0) { - SetModbusBridgeConfig(serial_config); + ModbusBridgeSetConfig(serial_config); } } } @@ -1004,7 +1015,7 @@ void CmndModbusBridgeSetConfig(void) void CmndModbusTCPStart(void) { - if (!tasmotaModbus) + if (!modbusBridgeModbus) { return; } @@ -1057,7 +1068,7 @@ void CmndModbusTCPConnect(void) { int32_t tcp_port = XdrvMailbox.payload; - if (!tasmotaModbus) + if (!modbusBridgeModbus) { return; } @@ -1116,7 +1127,7 @@ bool Xdrv63(uint8_t function) { ModbusBridgeInit(); } - else if (tasmotaModbus) + else if (modbusBridgeModbus) { switch (function) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino b/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino index ba4dbab50..11e57f2c4 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino @@ -191,8 +191,9 @@ bool WcPinUsed(void) { } if (!PinUsed(GPIO_WEBCAM_XCLK) || !PinUsed(GPIO_WEBCAM_PCLK) || !PinUsed(GPIO_WEBCAM_VSYNC) || !PinUsed(GPIO_WEBCAM_HREF) || - !PinUsed(GPIO_WEBCAM_SIOD) || !PinUsed(GPIO_WEBCAM_SIOC)) { - pin_used = false; + ((!PinUsed(GPIO_WEBCAM_SIOD) || !PinUsed(GPIO_WEBCAM_SIOC)) && !TasmotaGlobal.i2c_enabled_2) // preferred option is to reuse and share I2Cbus 2 + ) { + pin_used = false; } return pin_used; } @@ -341,8 +342,14 @@ uint32_t WcSetup(int32_t fsiz) { config.pin_pclk = Pin(GPIO_WEBCAM_PCLK); // PCLK_GPIO_NUM; config.pin_vsync = Pin(GPIO_WEBCAM_VSYNC); // VSYNC_GPIO_NUM; config.pin_href = Pin(GPIO_WEBCAM_HREF); // HREF_GPIO_NUM; - config.pin_sscb_sda = Pin(GPIO_WEBCAM_SIOD); // SIOD_GPIO_NUM; - config.pin_sscb_scl = Pin(GPIO_WEBCAM_SIOC); // SIOC_GPIO_NUM; + config.pin_sccb_sda = Pin(GPIO_WEBCAM_SIOD); // SIOD_GPIO_NUM; - unset to use shared I2C bus 2 + config.pin_sccb_scl = Pin(GPIO_WEBCAM_SIOC); // SIOC_GPIO_NUM; + if(TasmotaGlobal.i2c_enabled_2){ // configure SIOD and SIOC as SDA,2 and SCL,2 + config.sccb_i2c_port = 1; // reuse initialized bus 2, can be shared now + if(config.pin_sccb_sda < 0){ // GPIO_WEBCAM_SIOD must not be set to really make it happen + AddLog(LOG_LEVEL_INFO, PSTR("CAM: use I2C bus 2")); + } + } config.pin_pwdn = Pin(GPIO_WEBCAM_PWDN); // PWDN_GPIO_NUM; config.pin_reset = Pin(GPIO_WEBCAM_RESET); // RESET_GPIO_NUM; AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Template pin config")); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino index 60f0f0a88..a822b04c9 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino @@ -49,13 +49,15 @@ void ShellyProUpdate(void) { // bit 3 = wifi led green // bit 4 = wifi led red // bit 5 - 7 = nc - uint32_t val = SPro.power | SPro.ledlink; + // OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3 + // - this inhibits output of signals (also relay state) during power on for a few seconds + uint8_t val = SPro.power | SPro.ledlink; SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); SPI.transfer(val); // Write 74HC595 shift register SPI.endTransaction(); - delayMicroseconds(2); // Wait for SPI clock to stop +// delayMicroseconds(2); // Wait for SPI clock to stop digitalWrite(SPro.pin_shift595_rclk, 1); // Latch data - delayMicroseconds(2); // Shelly 10mS + delayMicroseconds(1); // Shelly 10mS digitalWrite(SPro.pin_shift595_rclk, 0); } @@ -64,9 +66,9 @@ void ShellyProPreInit(void) { PinUsed(GPIO_SPI_CS) && TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 - if (PinUsed(GPIO_SWT1)) { + if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) { TasmotaGlobal.devices_present++; // Shelly Pro 1 - if (PinUsed(GPIO_SWT1, 1)) { + if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) { TasmotaGlobal.devices_present++; // Shelly Pro 2 } @@ -76,21 +78,18 @@ void ShellyProPreInit(void) { // Does nothing if SPI is already initiated (by ADE7953) so no harm done SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); - SPro.power = TasmotaGlobal.power &3; // Restore power - SPro.ledlink = 0x18; // Blue led on - ShellyProUpdate(); - + SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() SPro.detected = true; } } } void ShellyProInit(void) { - int pin_lan_reset = 5; // GPIO5 = LAN8720 nRST -// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on + int pin_lan_reset = 5; // GPIO5 = LAN8720 nRST +// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on digitalWrite(pin_lan_reset, 0); pinMode(pin_lan_reset, OUTPUT); - delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS + delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS digitalWrite(pin_lan_reset, 1); AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), @@ -123,9 +122,14 @@ void ShellyProLedLink(void) { - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. */ SPro.last_update = TasmotaGlobal.uptime; - uint32_t ledlink = 0x1C; // All leds off - if (XdrvMailbox.index) { ledlink &= 0xFB; } // Blue blinks if wifi/mqtt lost - if (!TasmotaGlobal.global_state.wifi_down) { ledlink &= 0xF7; } // Green On + uint32_t ledlink = 0x1C; // All leds off + if (XdrvMailbox.index) { + ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost + } + else if (!TasmotaGlobal.global_state.wifi_down) { + ledlink &= 0xF7; // Green On + } + ShellyProUpdateLedLink(ledlink); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_89_esp32_dali.ino b/tasmota/tasmota_xdrv_driver/xdrv_89_esp32_dali.ino new file mode 100644 index 000000000..0a247a2bd --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_89_esp32_dali.ino @@ -0,0 +1,583 @@ +/* + xdrv_89_esp32_dali.ino - DALI support for Tasmota + + Copyright (C) 2022 Andrei Kazmirtsuk aka eeak + + 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 . + + -------------------------------------------------------------------------------------------- + Version yyyymmdd Action Description + -------------------------------------------------------------------------------------------- + 0.0.0.1 20221027 publish - initial version +*/ + +#ifdef ESP32 +#ifdef USE_DALI + +/*********************************************************************************************\ + * DALI support for Tasmota +\*********************************************************************************************/ + +#define XDRV_89 89 + +#ifndef DALI_TIMER + #define DALI_TIMER 0 // Default timer +#endif + +#define BROADCAST_DP 0b11111110 // 0xFE +#define DALI_TOPIC "DALI" + +enum +{ + DALI_NO_ACTION, + DALI_SENDING_DATA, + DALI_RECEIVING_DATA, + DALI_ERROR +}; + +// http and json defines +#define D_NAME_DALI "DALI" + +const char S_JSON_DALI_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_DALI "\":{\"%s\":%d}}"; +const char kDALI_Commands[] PROGMEM = D_CMND_DALI_POWER "|" D_CMND_DALI_DIMMER; + +enum DALI_Commands { // commands for Console + CMND_DALI_PWR, + CMND_DALI_DIM, +}; + +struct DALI { + uint16_t send_dali_data; // data to send to DALI bus + uint16_t received_dali_data; // data received from DALI bus + uint8_t flag; // DALI status flag + uint8_t bit_count; // nr of rec/send bits + uint16_t tick_count; // nr of ticks of the timer + bool former_val; // bit value in previous tick of timer + hw_timer_t *timer; // hardware timer +} *Dali = nullptr; + + + +/*********************************************************************************************\ + * DALI low level +\*********************************************************************************************/ + +/** +* @brief This function handles hardware timer Handler. +* @param None +* @retval None +*/ +void IRAM_ATTR DALI_Tick_Handler(void) +{ + if (getDaliFlag() == DALI_RECEIVING_DATA) + { + receive_tick(); + } + else if (getDaliFlag() == DALI_SENDING_DATA) + { + send_tick(); + } +} + +/** +* @brief This function enable data transfer start interrupt. +* @param None +* @retval None +*/ +void enableDaliRxInterrupt() { + Dali->flag = DALI_NO_ACTION; + timerAlarmDisable(Dali->timer); + attachInterrupt(Pin(GPIO_DALI_RX), receiveDaliData, FALLING); +} + +/** +* @brief This function disable data transfer start interrupt. +* @param None +* @retval None +*/ +void disableRxInterrupt() { + timerAlarmEnable(Dali->timer); + detachInterrupt(Pin(GPIO_DALI_RX)); +} + +/** +* @brief receiving flag status +* @param None +* @retval uint8_t flag +*/ +uint8_t getDaliFlag(void) +{ + return Dali->flag; +} + +/** +* @brief DALI data received callback +* @param None +* @retval uint8_t flag +*/ +void DataReceivedCallback() { + AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: Received: %d %d"), Dali->received_dali_data>>9, Dali->received_dali_data&0xff); +} + +/*************** R E C E I V E * P R O C E D U R E S *******/ + +/** +* @brief receive data from DALI bus +* @param None +* @retval None +*/ +void receiveDaliData() +{ + // null variables + Dali->received_dali_data = 0; + Dali->bit_count = 0; + Dali->tick_count = 0; + Dali->former_val = true; + + Dali->flag = DALI_RECEIVING_DATA; + + disableRxInterrupt(); +} + +/** +* @brief Get state of DALIIN pin +* @param None +* @retval bool status +*/ +bool get_DALIIN(void) +{ + bool dali_read = digitalRead(Pin(GPIO_DALI_RX)); + return (false == DALI_IN_INVERT) ? dali_read : !dali_read; +} + +/** +* @brief receiving data from DALI bus +* @param None +* @retval None +* +* |--------|----|---------------------------|----| +* 0 24 32 160 176 +* wait start data stop +*/ +void receive_tick(void) +{ + // four ticks per bit + bool actual_val = get_DALIIN(); + Dali->tick_count++; + + // edge detected + if(actual_val != Dali->former_val) + { + switch(Dali->bit_count) + { + case 0: + if (Dali->tick_count > 2) + { + Dali->tick_count = 0; + Dali->bit_count = 1; // start bit + } + break; + case 17: // 1st stop bit + if(Dali->tick_count > 6) { // stop bit error, no edge should exist + Dali->flag = DALI_ERROR; + } + break; + default: // other bits + if(Dali->tick_count > 6) + { + Dali->received_dali_data |= (actual_val << (16-Dali->bit_count)); + Dali->bit_count++; + Dali->tick_count = 0; + } + break; + } + }else // voltage level stable + { + switch(Dali->bit_count) + { + case 0: + if(Dali->tick_count==8) { // too long start bit + Dali->flag = DALI_ERROR; + } + break; + case 17: + // First stop bit + if (Dali->tick_count==8) + { + if (actual_val==0) // wrong level of stop bit + { + Dali->flag = DALI_ERROR; + } + else + { + Dali->bit_count++; + Dali->tick_count = 0; + } + } + break; + case 18: + // Second stop bit + if (Dali->tick_count==8) + { + enableDaliRxInterrupt(); + DataReceivedCallback(); + + } + break; + default: // normal bits + if(Dali->tick_count==10) + { // too long delay before edge + Dali->flag = DALI_ERROR; + } + break; + } + } + Dali->former_val = actual_val; + if(getDaliFlag() == DALI_ERROR) + { + enableDaliRxInterrupt(); + } +} + + +/*************** S E N D * P R O C E D U R E S *************/ + +/** +* @brief Set value to the DALIOUT pin +* @param bool +* @retval None +*/ +void set_DALIOUT(bool pin_value) +{ + digitalWrite(Pin(GPIO_DALI_TX), pin_value == DALI_OUT_INVERT ? LOW : HIGH); +} + +/** +* @brief gets state of the DALIOUT pin +* @param None +* @retval bool state of the DALIOUT pin +*/ +bool get_DALIOUT(void) +{ + bool dali_read = digitalRead(Pin(GPIO_DALI_TX)); + return (false == DALI_OUT_INVERT) ? dali_read : !dali_read; +} + +/** +* @brief Send data to DALI bus +* @param byteToSend +* @retval None +*/ +void sendDaliData(uint8_t firstByte, uint8_t secondByte) +{ + Dali->send_dali_data = firstByte << 8; + Dali->send_dali_data += secondByte & 0xff; + Dali->bit_count = 0; + Dali->tick_count = 0; + + Dali->flag = DALI_SENDING_DATA; + + disableRxInterrupt(); +} + +/** +* @brief DALI protocol physical layer for slave device +* @param None +* @retval None +* +* |--------|----|---------------------------|----| +* 0 24 32 160 176 +* wait start data stop +*/ +void send_tick(void) +{ + // access to the routine just every 4 ticks = every half bit + if ((Dali->tick_count & 0x03) == 0) + { + if (Dali->tick_count < 160) + { + // settling time between forward and backward frame + if (Dali->tick_count < 24) + { + Dali->tick_count++; + return; + } + + // start of the start bit + if (Dali->tick_count == 24) + { + // GPIOB->ODR ^= GPIO_ODR_7; + set_DALIOUT(false); + Dali->tick_count++; + return; + } + + // edge of the start bit + // 28 ticks = 28/9600 = 2,92ms = delay between forward and backward message frame + if (Dali->tick_count == 28) + { + set_DALIOUT(true); + Dali->tick_count++; + return; + } + + // bit value (edge) selection + bool bit_value = (bool)((Dali->send_dali_data >> (15 - Dali->bit_count)) & 0x01); + + // Every half bit -> Manchester coding + if (!((Dali->tick_count - 24) & 0x0007)) + { // div by 8 + if (get_DALIOUT() == bit_value) // former value of bit = new value of bit + set_DALIOUT((bool)(1 - bit_value)); + } + + // Generate edge for actual bit + if (!((Dali->tick_count - 28) & 0x0007)) + { + set_DALIOUT(bit_value); + Dali->bit_count++; + } + } + else + { // end of data byte, start of stop bits + if (Dali->tick_count == 160) + { + set_DALIOUT(true); // start of stop bit + } + + // end of stop bits, no settling time + if (Dali->tick_count == 176) + { + enableDaliRxInterrupt(); + } + } + } + Dali->tick_count++; + + return; +} + +/***********************************************************/ + +void DaliPreInit() { + if (!PinUsed(GPIO_DALI_TX) || !PinUsed(GPIO_DALI_RX)) { return; } + AddLog(LOG_LEVEL_INFO, PSTR("DLI: Init - RX-pin: %d, TX-pin: %d"), Pin(GPIO_DALI_RX), Pin(GPIO_DALI_TX)); + // pinMode(LED, OUTPUT); + pinMode(Pin(GPIO_DALI_TX), OUTPUT); + digitalWrite(Pin(GPIO_DALI_TX), HIGH); + pinMode(Pin(GPIO_DALI_RX), INPUT); + + Dali = (DALI*)calloc(1,sizeof(DALI)); + if (!Dali) { + AddLog(LOG_LEVEL_INFO, PSTR("DLI: Memory allocation error")); + return; + } + Dali->timer = timerBegin(DALI_TIMER, 13, true); + timerAttachInterrupt(Dali->timer, &DALI_Tick_Handler, true); + timerAlarmWrite(Dali->timer, 641, true); + + attachInterrupt(Pin(GPIO_DALI_RX), receiveDaliData, FALLING); + enableDaliRxInterrupt(); +} + +void DaliPwr(uint8_t val){ + sendDaliData(BROADCAST_DP, val); +} + +bool DaliCmd(void) +{ + char command[CMDSZ]; + uint8_t name_len = strlen(D_NAME_DALI); + if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_NAME_DALI), name_len)) + { + uint32_t command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + name_len, kDALI_Commands); + switch (command_code) + { + case CMND_DALI_PWR: + if (XdrvMailbox.data_len) + { + if (254 >= XdrvMailbox.payload) + { + DaliPwr(XdrvMailbox.payload); + } + } + Response_P(S_JSON_DALI_COMMAND_NVALUE, command, XdrvMailbox.payload); + break; + default: + return false; + } + return true; + } + else + { + return false; + } +} + + +bool DaliMqtt() +{ + char stopic[TOPSZ]; + strncpy(stopic, XdrvMailbox.topic, TOPSZ); + XdrvMailbox.topic[TOPSZ - 1] = 0; + + char *items[10]; + char *p = stopic; + int cnt = 0; + do + { + items[cnt] = strtok(p, "/"); + cnt++; + p = nullptr; + } while (items[cnt - 1]); + cnt--; // repreents the number of items + + if (cnt < 3) + { // not for us? + AddLog(LOG_LEVEL_INFO,PSTR("cnt: %d < 3"), cnt); + return false; + } + + int DALIindex = 0; + int ADRindex = 0; + int CMDindex = 0; + uint8_t DALIaddr = BROADCAST_DP; + if (strcasecmp_P(items[cnt - 3], PSTR(DALI_TOPIC)) != 0) + { + if (strcasecmp_P(items[cnt - 2], PSTR(DALI_TOPIC)) != 0) + { + if (strcasecmp_P(items[cnt - 1], PSTR(DALI_TOPIC)) != 0) + { + return false; // not for us + } + else + { + if (true == DaliJsonParse()) { return true; } + } + } + else + { + DALIindex = cnt - 2; + CMDindex = cnt - 1; + } + } + else + { + DALIindex = cnt - 3; + CMDindex = cnt - 2; + ADRindex = cnt - 1; + DALIaddr = ((int)CharToFloat(items[ADRindex])) << 1; + + } + + uint8_t level; + uint8_t value = (uint8_t)CharToFloat(XdrvMailbox.data); + if (strcasecmp_P(items[CMDindex], PSTR("percent")) == 0) { + float percent = (float)(254 * value * 0.01); + level = (uint8_t)percent; + } + else if (strcasecmp_P(items[CMDindex], PSTR("level")) == 0) { + level = value; + } + else { + AddLog(LOG_LEVEL_INFO,PSTR("command not recognized: %s"), items[CMDindex]); + return false; // not for us + } + + AddLog(LOG_LEVEL_INFO,PSTR("Dali value %d on address %d"), value, DALIaddr); + sendDaliData(DALIaddr, level); + + return true; +} + +bool DaliJsonParse() +{ + bool served = false; + JsonParser parser((char *)XdrvMailbox.data); + JsonParserObject root = parser.getRootObject(); + if (root) + { + int DALIindex = 0; + int ADRindex = 0; + int8_t DALIdim = -1; + uint8_t DALIaddr = BROADCAST_DP; + + JsonParserToken val = root[PSTR("cmd")]; + if (val) + { + uint8_t cmd = val.getUInt(); + val = root[PSTR("addr")]; + if (val) + { + uint8_t addr = val.getUInt(); + AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: cmd = %d, addr = %d"), cmd, addr); + sendDaliData(addr, cmd); + return true; + } + else + { + return false; + } + } + val = root[PSTR("addr")]; + if (val) + { + uint8_t addr = val.getUInt(); + if ((addr >= 0) && (addr < 64)) + DALIaddr = addr << 1; + } + val = root[PSTR("dim")]; + if (val) + { + uint8_t dim = val.getUInt(); + if (dim < 255) + DALIdim = dim; + } + + sendDaliData(DALIaddr, DALIdim); + served = true; + } + + return served; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv89(uint8_t function) +{ + bool result = false; + + if (FUNC_INIT == function) + { + DaliPreInit(); + } + else if (Dali) + { + switch (function) + { + case FUNC_MQTT_DATA: + result = DaliMqtt(); + break; + case FUNC_COMMAND: + result = DaliCmd(); + break; + } + } + return result; +} + +#endif // USE_DALI +#endif // ESP32 \ No newline at end of file diff --git a/tasmota/tasmota_xlgt_light/xlgt_10_bp1658cj.ino b/tasmota/tasmota_xlgt_light/xlgt_10_bp1658cj.ino new file mode 100644 index 000000000..c241e796d --- /dev/null +++ b/tasmota/tasmota_xlgt_light/xlgt_10_bp1658cj.ino @@ -0,0 +1,179 @@ +/* + xlgt_10_bp1658cj.ino - bp1658cj five channel led support for Tasmota + + Copyright (C) 2022 Theo Arends and Cossid + + 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 . +*/ + +#ifdef USE_LIGHT +#ifdef USE_BP1658CJ +/*********************************************************************************************\ + * BP1658CJ RGBCW Led bulbs like the Orein OS0100411267 Bulb + * + * Orein OS0100411267 Bulb + * + * + * FIXME + * {"NAME":"Orein OS0100411267 Bulb","GPIO":[0,0,0,0,9129,9088,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} +\*********************************************************************************************/ + +#define XLGT_10 10 + +// 10 = identification | 00 = Standby | 0000 = start at OUT1/5 +#define BP1658CJ_ADDR_STANDBY 0x80 // 10000000 0x80 +// 10 = identification | 01 = 3 channels (RGB) | 0000 = start at OUT1/5 +//#define BP1658CJ_ADDR_START_3CH 0x90 // 10010000 0xC8 +// 10 = identification | 10 = 2 channels (CW) | 0000 = start at OUT1/5 +//#define BP1658CJ_ADDR_START_2CH 0xA0 // 10100000 0xA0 +// 10 = identification | 11 = 5 channels (RGB+CW) | 0000 = start at OUT1/5 +#define BP1658CJ_ADDR_START_5CH 0xB0 // 10110000 0xB0 + +// Current values +// 0x0 // 0000 RGB 0mA | CW 0mA +// 0x1 // 0001 RGB 10mA | CW 5mA +// 0x2 // 0010 RGB 20mA | CW 10mA +// 0x3 // 0011 RGB 30mA | CW 15mA +// 0x4 // 0100 RGB 40mA | CW 20mA +// 0x5 // 0101 RGB 50mA | CW 25mA +// 0x6 // 0110 RGB 60mA | CW 30mA +// 0x7 // 0111 RGB 70mA | CW 35mA +// 0x8 // 1000 RGB 80mA | CW 40mA +// 0x9 // 1001 RGB 900mA | CW 45mA +// 0xA // 1010 RGB 100mA | CW 50mA +// 0xB // 1011 RGB 110mA | CW 55mA +// 0xC // 1100 RGB 120mA | CW 60mA +// 0xD // 1101 RGB 130mA | CW 65mA +// 0xE // 1110 RGB 140mA | CW 70mA +// 0xF // 1111 RGB 150mA | CW 75mA + +struct BP1658CJ { + uint8_t clk = 0; + uint8_t data = 0; + uint8_t current; +} Bp1658cj; + +/*********************************************************************************************\ + * BP1658CJ code - inspired by Bp5758d/SM2335 +\*********************************************************************************************/ +const uint8_t BP1658CJ_DELAY = 2; + +void BP1658CJInit(void) { + pinMode(Bp1658cj.data, OUTPUT); + pinMode(Bp1658cj.clk, OUTPUT); + BP1658CJStop(); +} + +void BP1658CJWrite(uint8_t value) { + for (int bit_idx = 7; bit_idx >= 0; bit_idx--) { + bool bit = bitRead(value, bit_idx); + digitalWrite(Bp1658cj.data, bit); + delayMicroseconds(BP1658CJ_DELAY); + digitalWrite(Bp1658cj.clk, HIGH); + delayMicroseconds(BP1658CJ_DELAY); + digitalWrite(Bp1658cj.clk, LOW); + delayMicroseconds(BP1658CJ_DELAY); + } + // Wait for ACK + pinMode(Bp1658cj.data, INPUT); + digitalWrite(Bp1658cj.clk, HIGH); + delayMicroseconds(BP1658CJ_DELAY); + digitalWrite(Bp1658cj.clk, LOW); + delayMicroseconds(BP1658CJ_DELAY); + pinMode(Bp1658cj.data, OUTPUT); +} + +void BP1658CJStart(uint8_t addr) { + digitalWrite(Bp1658cj.data, LOW); + delayMicroseconds(BP1658CJ_DELAY); + digitalWrite(Bp1658cj.clk, LOW); + delayMicroseconds(BP1658CJ_DELAY); + BP1658CJWrite(addr); +} + +void BP1658CJStop(void) { + digitalWrite(Bp1658cj.clk, HIGH); + delayMicroseconds(BP1658CJ_DELAY); + digitalWrite(Bp1658cj.data, HIGH); + delayMicroseconds(BP1658CJ_DELAY); +} + +/********************************************************************************************/ + +bool BP1658CJSetChannels(void) { + uint16_t *cur_col_10 = (uint16_t*)XdrvMailbox.command; + + // If we receive 0 for all channels, we'll assume that the lightbulb is off, and activate BP1658CJ's standby mode. + if (cur_col_10[0] == 0 && cur_col_10[1] == 0 && cur_col_10[2] == 0 && cur_col_10[3] == 0 && cur_col_10[4] == 0) { + BP1658CJStart(BP1658CJ_ADDR_STANDBY); + // Clear all remaining data. This clears out Current, Red, Green, Blue, Cold White, Warm White. + for (int i = 0; i < 11; i++) { + BP1658CJWrite(0); + } + BP1658CJStop(); + return true; + } + + // Write the header activating all 5 channels + BP1658CJStart(BP1658CJ_ADDR_START_5CH); + // Set the current defined in ModuleSelected. + BP1658CJWrite(Bp1658cj.current); + // Set RGB and CW grayscale. + for (int i = 0; i < 5; i++) { + BP1658CJWrite((uint8_t)(cur_col_10[i] & 0x1F)); + BP1658CJWrite((uint8_t)(cur_col_10[i] >> 5)); + } + BP1658CJStop(); + return true; +} + +void BP1658CJModuleSelected(void) +{ + if (PinUsed(GPIO_BP1658CJ_CLK) && PinUsed(GPIO_BP1658CJ_DAT, GPIO_ANY)) { + Bp1658cj.clk = Pin(GPIO_BP1658CJ_CLK); + Bp1658cj.data = Pin(GPIO_BP1658CJ_DAT, GPIO_ANY); + // See #define MAX_BP1658CJ_DAT 16 in tasmota_template.h + int currentDat = GetPin(Bp1658cj.data) - AGPIO(GPIO_BP1658CJ_DAT); // 0 .. 15 + // Split RGB and CW current. + Bp1658cj.current = (currentDat << 4) | currentDat; + + BP1658CJInit(); + + TasmotaGlobal.light_type = LT_RGBWC; + TasmotaGlobal.light_driver = XLGT_10; + AddLog(LOG_LEVEL_DEBUG, PSTR("LGT: BP1658CJ Found")); + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xlgt10(uint8_t function) +{ + bool result = false; + + switch (function) { + case FUNC_SET_CHANNELS: + result = BP1658CJSetChannels(); + break; + case FUNC_MODULE_INIT: + BP1658CJModuleSelected(); + break; + } + return result; +} + +#endif // USE_BP1658CJ +#endif // USE_LIGHT diff --git a/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino b/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino index 883dfdbb2..d28347af5 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino @@ -290,17 +290,17 @@ bool HlwCommand(void) { } else if (CMND_POWERSET == Energy.command_code) { if (XdrvMailbox.data_len && Hlw.cf_power_pulse_length ) { - Settings->energy_power_calibration = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf_power_pulse_length ) / Hlw.power_ratio; + XdrvMailbox.payload = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf_power_pulse_length ) / Hlw.power_ratio; } } else if (CMND_VOLTAGESET == Energy.command_code) { if (XdrvMailbox.data_len && Hlw.cf1_voltage_pulse_length ) { - Settings->energy_voltage_calibration = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf1_voltage_pulse_length ) / Hlw.voltage_ratio; + XdrvMailbox.payload = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf1_voltage_pulse_length ) / Hlw.voltage_ratio; } } else if (CMND_CURRENTSET == Energy.command_code) { if (XdrvMailbox.data_len && Hlw.cf1_current_pulse_length) { - Settings->energy_current_calibration = ((uint32_t)(CharToFloat(XdrvMailbox.data)) * Hlw.cf1_current_pulse_length) / Hlw.current_ratio; + XdrvMailbox.payload = ((uint32_t)(CharToFloat(XdrvMailbox.data)) * Hlw.cf1_current_pulse_length) / Hlw.current_ratio; } } else serviced = false; // Unknown command diff --git a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino index 296bd6520..6717304cf 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino @@ -63,7 +63,8 @@ void CseReceived(void) { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // F2 5A 02 F7 60 00 03 61 00 40 10 05 72 40 51 A6 58 63 10 1B E1 7F 4D 4E - F2 = Power cycle exceeds range - takes too long - No load // 55 5A 02 F7 60 00 03 5A 00 40 10 04 8B 9F 51 A6 58 18 72 75 61 AC A1 30 - 55 = Ok, 61 = Power not valid (load below 5W) - // 55 5A 02 F7 60 00 03 AB 00 40 10 02 60 5D 51 A6 58 03 E9 EF 71 0B 7A 36 - 55 = Ok, 71 = Ok + // 55 5A 02 F7 60 00 03 AB 00 40 10 02 60 5D 51 A6 58 03 E9 EF 71 0B 7A 36 - 55 = Ok, 71 = Ok, F1 = CF overflow, no problem + // 55 5A 02 F1 E8 00 07 9D 00 3F 3E 00 35 F8 50 DB 38 00 B2 A2 F1 D6 97 3E - CF overflow // 55 5A 02 DB 40 00 03 25 00 3D 18 03 8E CD 4F 0A 60 2A 56 85 61 01 02 1A - OK voltage // 55 5A 02 DB 40 07 17 1D 00 3D 18 03 8E CD 4F 0A 60 2B EF EA 61 01 02 2C - Wrong voltage @@ -256,17 +257,17 @@ bool CseCommand(void) { if (CMND_POWERSET == Energy.command_code) { if (XdrvMailbox.data_len && Cse.power_cycle) { - Settings->energy_power_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.power_cycle) / CSE_PREF; + XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.power_cycle) / CSE_PREF; } } else if (CMND_VOLTAGESET == Energy.command_code) { if (XdrvMailbox.data_len && Cse.voltage_cycle) { - Settings->energy_voltage_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.voltage_cycle) / CSE_UREF; + XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.voltage_cycle) / CSE_UREF; } } else if (CMND_CURRENTSET == Energy.command_code) { if (XdrvMailbox.data_len && Cse.current_cycle) { - Settings->energy_current_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.current_cycle) / 1000; + XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.current_cycle) / 1000; } } else serviced = false; // Unknown command diff --git a/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino b/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino index 7601731a4..807176c64 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino @@ -602,7 +602,7 @@ bool McpCommand(void) if (XdrvMailbox.data_len && mcp_active_power) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 100); if ((value > 100) && (value < 200000)) { // Between 1W and 2000W - Settings->energy_power_calibration = value; + XdrvMailbox.payload = value; mcp_calibrate |= MCP_CALIBRATE_POWER; McpGetCalibration(); } @@ -612,7 +612,7 @@ bool McpCommand(void) if (XdrvMailbox.data_len && mcp_voltage_rms) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); if ((value > 1000) && (value < 2600)) { // Between 100V and 260V - Settings->energy_voltage_calibration = value; + XdrvMailbox.payload = value; mcp_calibrate |= MCP_CALIBRATE_VOLTAGE; McpGetCalibration(); } @@ -622,7 +622,7 @@ bool McpCommand(void) if (XdrvMailbox.data_len && mcp_current_rms) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); if ((value > 100) && (value < 80000)) { // Between 10mA and 8A - Settings->energy_current_calibration = value; + XdrvMailbox.payload = value; mcp_calibrate |= MCP_CALIBRATE_CURRENT; McpGetCalibration(); } @@ -632,7 +632,7 @@ bool McpCommand(void) if (XdrvMailbox.data_len && mcp_line_frequency) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 1000); if ((value > 45000) && (value < 65000)) { // Between 45Hz and 65Hz - Settings->energy_frequency_calibration = value; + XdrvMailbox.payload = value; mcp_calibrate |= MCP_CALIBRATE_FREQUENCY; McpGetFrequency(); } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 49686aca8..0cef9b6ab 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -69,6 +69,8 @@ /*********************************************************************************************/ +#define ADE7953_ACCU_ENERGY // Use accumulating energy instead of instant power + //#define ADE7953_DUMP_REGS #define ADE7953_PREF 1540 // 4194304 / (1540 / 1000) = 2723574 (= WGAIN, VAGAIN and VARGAIN) @@ -201,10 +203,22 @@ const uint16_t Ade7953CalibRegs[2][ADE7953_CALIBREGS] { const uint8_t ADE7953_REGISTERS = 6; const uint16_t Ade7953Registers[2][ADE7953_REGISTERS] { +#ifdef ADE7953_ACCU_ENERGY + { ADE7953_IRMSA, ADE7953_AENERGYA, ADE7953_APENERGYA, ADE7953_RENERGYA, ADE7953_VRMS, ADE7943_Period }, + { ADE7953_IRMSB, ADE7953_AENERGYB, ADE7953_APENERGYB, ADE7953_RENERGYB, ADE7953_VRMS, ADE7943_Period } +#else // No ADE7953_ACCU_ENERGY { ADE7953_IRMSA, ADE7953_AWATT, ADE7953_AVA, ADE7953_AVAR, ADE7953_VRMS, ADE7943_Period }, { ADE7953_IRMSB, ADE7953_BWATT, ADE7953_BVA, ADE7953_BVAR, ADE7953_VRMS, ADE7943_Period } +#endif // ADE7953_ACCU_ENERGY }; +#ifdef ADE7953_ACCU_ENERGY +const float ADE7953_LSB_PER_WATTSECOND = 2.5; +const float ADE7953_POWER_CORRECTION = 23.41494; // See https://github.com/arendst/Tasmota/pull/16941 +#else // No ADE7953_ACCU_ENERGY +const float ADE7953_LSB_PER_WATTSECOND = 44; +#endif // ADE7953_ACCU_ENERGY + struct Ade7953 { uint32_t voltage_rms[2] = { 0, 0 }; uint32_t current_rms[2] = { 0, 0 }; @@ -272,7 +286,7 @@ void Ade7953Write(uint16_t reg, uint32_t val) { } int32_t Ade7953Read(uint16_t reg) { - uint32_t response = 0; + uint32_t response = 0; int size = Ade7953RegSize(reg); if (size) { @@ -304,7 +318,7 @@ int32_t Ade7953Read(uint16_t reg) { } #endif // USE_ESP32_SPI } - return response; + return response; } #ifdef ADE7953_DUMP_REGS @@ -439,6 +453,9 @@ void Ade7953GetData(void) { acc_mode, reg[0][4], reg[1][4], reg[0][5], reg[1][5], reg[0][0], reg[1][0], reg[0][1], reg[1][1], reg[0][2], reg[1][2], reg[0][3], reg[1][3]); + // If the device is initializing, we read the energy registers to reset them, but don't report the values as the first read may be inaccurate + if (Ade7953.init_step) { return; } + uint32_t apparent_power[2] = { 0, 0 }; uint32_t reactive_power[2] = { 0, 0 }; @@ -463,12 +480,19 @@ void Ade7953GetData(void) { for (uint32_t channel = 0; channel < 2; channel++) { Energy.data_valid[channel] = 0; + float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 10; +#ifdef ADE7953_ACCU_ENERGY + power_calibration /= ADE7953_POWER_CORRECTION; +#endif // ADE7953_ACCU_ENERGY + float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION); + float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) * 10; + Energy.frequency[channel] = 223750.0f / ((float)reg[channel][5] + 1); - divider = (Ade7953.calib_data[channel][ADE7953_CAL_VGAIN] != ADE7953_GAIN_DEFAULT) ? 10000 : Settings->energy_voltage_calibration; + divider = (Ade7953.calib_data[channel][ADE7953_CAL_VGAIN] != ADE7953_GAIN_DEFAULT) ? 10000 : voltage_calibration; Energy.voltage[channel] = (float)Ade7953.voltage_rms[channel] / divider; - divider = (Ade7953.calib_data[channel][ADE7953_CAL_WGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 44 : (Settings->energy_power_calibration / 10); + divider = (Ade7953.calib_data[channel][ADE7953_CAL_WGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; Energy.active_power[channel] = (float)Ade7953.active_power[channel] / divider; - divider = (Ade7953.calib_data[channel][ADE7953_CAL_VARGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 44 : (Settings->energy_power_calibration / 10); + divider = (Ade7953.calib_data[channel][ADE7953_CAL_VARGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; Energy.reactive_power[channel] = (float)reactive_power[channel] / divider; if (ADE7953_SHELLY_EM == Ade7953.model) { if (bitRead(acc_mode, 10 +channel)) { // APSIGN @@ -478,12 +502,12 @@ void Ade7953GetData(void) { Energy.reactive_power[channel] *= -1; } } - divider = (Ade7953.calib_data[channel][ADE7953_CAL_VAGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 44 : (Settings->energy_power_calibration / 10); + divider = (Ade7953.calib_data[channel][ADE7953_CAL_VAGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; Energy.apparent_power[channel] = (float)apparent_power[channel] / divider; if (0 == Energy.active_power[channel]) { Energy.current[channel] = 0; } else { - divider = (Ade7953.calib_data[channel][ADE7953_CAL_IGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 100000 : (Settings->energy_current_calibration * 10); + divider = (Ade7953.calib_data[channel][ADE7953_CAL_IGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 100000 : current_calibration; Energy.current[channel] = (float)Ade7953.current_rms[channel] / divider; Energy.kWhtoday_delta[channel] += Energy.active_power[channel] * 1000 / 36; } @@ -493,14 +517,13 @@ void Ade7953GetData(void) { } void Ade7953EnergyEverySecond(void) { - if (Ade7953.init_step) { - if (1 == Ade7953.init_step) { - Ade7953Init(); - } + if (Ade7953.init_step) { + if (2 == Ade7953.init_step) { Ade7953Init(); } + if (1 == Ade7953.init_step) { Ade7953GetData(); } // Read registers but do not display yet Ade7953.init_step--; - } else { - Ade7953GetData(); - } + } else { + Ade7953GetData(); + } } /*********************************************************************************************/ @@ -657,11 +680,14 @@ void Ade7953DrvInit(void) { Settings->energy_power_calibration = ADE7953_PREF; Settings->energy_voltage_calibration = ADE7953_UREF; Settings->energy_current_calibration = ADE7953_IREF; + Settings->energy_power_calibration2 = ADE7953_PREF; + Settings->energy_voltage_calibration2 = ADE7953_UREF; + Settings->energy_current_calibration2 = ADE7953_IREF; } Ade7953Defaults(); - Ade7953.init_step = 2; + Ade7953.init_step = 3; // Energy.phase_count = 1; // Energy.voltage_common = false; @@ -705,21 +731,27 @@ bool Ade7953Command(void) { else if (CMND_POWERSET == Energy.command_code) { if (XdrvMailbox.data_len && Ade7953.active_power[channel]) { if ((value > 100) && (value < 200000)) { // Between 1W and 2000W - Settings->energy_power_calibration = (Ade7953.active_power[channel] * 1000) / value; // 0.00 W +#ifdef ADE7953_ACCU_ENERGY + float power_calibration = (float)(Ade7953.active_power[channel] * 1000) / value; // 0.00 W + power_calibration *= ADE7953_POWER_CORRECTION; + XdrvMailbox.payload = (uint32_t)power_calibration; // 0.00 W +#else // No ADE7953_ACCU_ENERGY + XdrvMailbox.payload = (Ade7953.active_power[channel] * 1000) / value; // 0.00 W +#endif // ADE7953_ACCU_ENERGY } } } else if (CMND_VOLTAGESET == Energy.command_code) { if (XdrvMailbox.data_len && Ade7953.voltage_rms[channel]) { if ((value > 10000) && (value < 26000)) { // Between 100V and 260V - Settings->energy_voltage_calibration = (Ade7953.voltage_rms[channel] * 100) / value; // 0.00 V + XdrvMailbox.payload = (Ade7953.voltage_rms[channel] * 100) / value; // 0.00 V } } } else if (CMND_CURRENTSET == Energy.command_code) { if (XdrvMailbox.data_len && Ade7953.current_rms[channel]) { if ((value > 2000) && (value < 1000000)) { // Between 20mA and 10A - Settings->energy_current_calibration = ((Ade7953.current_rms[channel] * 100) / value) * 100; // 0.00 mA + XdrvMailbox.payload = ((Ade7953.current_rms[channel] * 100) / value) * 100; // 0.00 mA } } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino index f73a276b8..740029725 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino @@ -193,9 +193,11 @@ void Bl09XXUpdateEnergy() { AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %2_f, T %2_f"), &Energy.voltage[0], &Bl09XX.temperature); #endif for (uint32_t chan = 0; chan < Energy.phase_count; chan++) { - if (Bl09XX.power[chan] > Settings->energy_power_calibration) { // We need at least 1W - Energy.active_power[chan] = (float)Bl09XX.power[chan] / Settings->energy_power_calibration; - Energy.current[chan] = (float)Bl09XX.current[chan] / Settings->energy_current_calibration; + uint32_t power_calibration = EnergyGetCalibration(chan, ENERGY_POWER_CALIBRATION); + uint32_t current_calibration = EnergyGetCalibration(chan, ENERGY_CURRENT_CALIBRATION); + if (Bl09XX.power[chan] > power_calibration) { // We need at least 1W + Energy.active_power[chan] = (float)Bl09XX.power[chan] / power_calibration; + Energy.current[chan] = (float)Bl09XX.current[chan] / current_calibration; } else { Energy.active_power[chan] = 0; Energy.current[chan] = 0; @@ -289,6 +291,9 @@ void Bl09XXInit(void) { Settings->energy_voltage_calibration = bl09xx_uref[Bl09XX.model]; Settings->energy_current_calibration = bl09xx_iref[Bl09XX.model]; Settings->energy_power_calibration = bl09xx_pref[Bl09XX.model]; + Settings->energy_voltage_calibration2 = bl09xx_uref[Bl09XX.model]; + Settings->energy_current_calibration2 = bl09xx_iref[Bl09XX.model]; + Settings->energy_power_calibration2 = bl09xx_pref[Bl09XX.model]; } if ((BL0940_MODEL == Bl09XX.model) && (Settings->energy_current_calibration < (BL0940_IREF / 20))) { Settings->energy_current_calibration *= 100; @@ -357,17 +362,17 @@ bool Bl09XXCommand(void) { if (CMND_POWERSET == Energy.command_code) { if (XdrvMailbox.data_len && Bl09XX.power[channel]) { - Settings->energy_power_calibration = (Bl09XX.power[channel] * 100) / value; + XdrvMailbox.payload = (Bl09XX.power[channel] * 100) / value; } } else if (CMND_VOLTAGESET == Energy.command_code) { if (XdrvMailbox.data_len && Bl09XX.voltage) { - Settings->energy_voltage_calibration = (Bl09XX.voltage * 100) / value; + XdrvMailbox.payload = (Bl09XX.voltage * 100) / value; } } else if (CMND_CURRENTSET == Energy.command_code) { if (XdrvMailbox.data_len && Bl09XX.current[channel]) { - Settings->energy_current_calibration = (Bl09XX.current[channel] * 100) / value; + XdrvMailbox.payload = (Bl09XX.current[channel] * 100) / value; } } else serviced = false; // Unknown command diff --git a/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino b/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino index 04afe6af4..a17361047 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino @@ -152,7 +152,7 @@ PROGMEM "|" ; -#define TELEINFO_SERIAL_BUFFER_STANDARD 512 // Receive buffer size for Standard mode +#define TELEINFO_SERIAL_BUFFER_STANDARD 1536 // Receive buffer size for Standard mode #define TELEINFO_SERIAL_BUFFER_HISTORIQUE 512 // Receive buffer size for Legacy mode #define TELEINFO_PROCESS_BUFFER 32 // Local processing buffer @@ -163,6 +163,7 @@ uint8_t tic_rx_pin = NOT_A_PIN; char serialNumber[13] = ""; // Serial number is 12 char long bool tinfo_found = false; int serial_buffer_size; +uint32_t total_wh; int contrat; int tarif; int isousc; @@ -183,7 +184,12 @@ char * getValueFromLabelIndex(int labelIndex, char * value) // Get the label name GetTextIndexed(labelName, sizeof(labelName), labelIndex, kLabel); // Get value of label name - return tinfo.valueGet(labelName, value) ; + tinfo.valueGet(labelName, value) ; + // Standard mode has values with space before/after + if (tinfo_mode==TINFO_MODE_STANDARD) { + Trim(value); + } + return value; } /* ====================================================================== @@ -329,12 +335,11 @@ void DataCallback(struct _ValueList * me, uint8_t flags) char value[32]; uint32_t hc = 0; uint32_t hp = 0; - uint32_t total = 0; // Base, un seul index if (ilabel == LABEL_BASE) { - total = atol(me->value); - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Base:%ld"), total); + total_wh = atol(me->value); + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Base:%ld"), total_wh); // Heures creuses/pleines calculer total } else { // Heures creuses get heures pleines @@ -352,15 +357,17 @@ void DataCallback(struct _ValueList * me, uint8_t flags) } } if (hc>0 && hp>0) { - total = hc + hp; + total_wh = hc + hp; } - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: HC:%ld HP:%ld Total:%ld"), hc, hp, total); + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: HC:%ld HP:%ld Total:%ld"), hc, hp, total_wh); } - AddLog (LOG_LEVEL_INFO, PSTR ("TIC: Total counter updated to %ld Wh"), total); - if (total>0) { - Energy.import_active[0] = (float)total/1000.0f; - EnergyUpdateTotal(); + AddLog (LOG_LEVEL_INFO, PSTR ("TIC: Total counter updated to %ld Wh"), total_wh); + if (total_wh>0) { + Energy.total[0] = (float) total_wh / 1000.0f; + Energy.import_active[0] = Energy.total[0]; + //Energy.import_active[0] = (float)total/1000.0f; + //EnergyUpdateTotal(); AddLog (LOG_LEVEL_DEBUG_MORE, PSTR ("TIC: import_active[0]=%.3fKWh"), Energy.import_active[0] ); } } @@ -368,10 +375,10 @@ void DataCallback(struct _ValueList * me, uint8_t flags) // Wh total index (all contract) else if ( ilabel == LABEL_EAST) { - uint32_t total = atol(me->value); - Energy.import_active[0] = (float)total/1000.0f; - EnergyUpdateTotal(); - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Total:%ldWh"), total); + total_wh = atol(me->value); + Energy.total[0] = (float) total_wh / 1000.0f; + Energy.import_active[0] = Energy.total[0]; + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Total:%ldWh"), total_wh); } // Wh indexes (standard) @@ -538,7 +545,7 @@ void NewFrameCallback(struct _ValueList * me) Energy.data_valid[0] = 0; // Deprecated see setOption108 - // send teleinfo raw data only if setup like that + // send teleinfo MQTT raw data only if setup like that if (Settings->teleinfo.raw_send) { // Do we need to skip this frame if (raw_skip == 0 ) { @@ -578,6 +585,7 @@ void TInfoDrvInit(void) { Energy.voltage_available = false; Energy.phase_count = 1; // init hardware energy counters + total_wh = 0; Settings->flag3.hardware_energy_total = true; } } @@ -673,6 +681,25 @@ void TInfoInit(void) } } +// +/* ====================================================================== +Function: TInfoSaveBeforeRestart +Purpose : Save data before ESP restart +Input : - +Output : - +Comments: - +====================================================================== */ +void TInfoSaveBeforeRestart() +{ + // if teleinfo enabled, set it low + if (PinUsed (GPIO_TELEINFO_ENABLE)) { + digitalWrite( Pin(GPIO_TELEINFO_ENABLE), LOW); + } + + // update energy total (in kwh) + EnergyUpdateTotal(); + +} /* ====================================================================== Function: TInfoCmd @@ -842,6 +869,7 @@ Comments: - void TInfoProcess(void) { static char buff[TELEINFO_PROCESS_BUFFER]; + static uint32_t tick_update = 0; #ifdef MEASURE_PERF static unsigned long max_time = 0; unsigned long duration = millis(); @@ -872,6 +900,14 @@ void TInfoProcess(void) if (duration > max_time) { max_time = duration; AddLog(LOG_LEVEL_INFO,PSTR("TIC: max_time=%lu"), max_time); } if (tmp_size > max_size) { max_size = tmp_size; AddLog(LOG_LEVEL_INFO,PSTR("TIC: max_size=%d"), max_size); } #endif + + // if needed, update energy total every hour + if (tick_update++ > 3600 * 4) { + EnergyUpdateTotal(); + AddLog (LOG_LEVEL_INFO, PSTR ("TIC: Total counter updated to %lu Wh"), total_wh); + tick_update = 0; + } + } /* ====================================================================== @@ -886,7 +922,8 @@ const char HTTP_ENERGY_ID_TELEINFO[] PROGMEM = "{s}ID{m}%s{e}" ; const char HTTP_ENERGY_INDEX_TELEINFO[] PROGMEM = "{s}%s{m}%s " D_UNIT_WATTHOUR "{e}" ; const char HTTP_ENERGY_PAPP_TELEINFO[] PROGMEM = "{s}" D_POWERUSAGE "{m}%d " D_UNIT_WATT "{e}" ; //const char HTTP_ENERGY_IINST_TELEINFO[] PROGMEM = "{s}" D_CURRENT "%s{m}%d " D_UNIT_AMPERE "{e}" ; -const char HTTP_ENERGY_TARIF_TELEINFO[] PROGMEM = "{s}" D_CURRENT_TARIFF "{m}%s%s{e}" ; +const char HTTP_ENERGY_TARIF_TELEINFO_STD[] PROGMEM = "{s}" D_CURRENT_TARIFF "{m}%s{e}" ; +const char HTTP_ENERGY_TARIF_TELEINFO_HISTO[] PROGMEM = "{s}" D_CURRENT_TARIFF "{m}Heures %s{e}" ; const char HTTP_ENERGY_CONTRAT_TELEINFO[] PROGMEM = "{s}" D_CONTRACT "{m}%s %d" D_UNIT_AMPERE "{e}" ; const char HTTP_ENERGY_LOAD_TELEINFO[] PROGMEM = "{s}" D_POWER_LOAD "{m}%d" D_UNIT_PERCENT "{e}" ; const char HTTP_ENERGY_IMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_CURRENT "{m}%d" D_UNIT_AMPERE "{e}" ; @@ -977,9 +1014,9 @@ void TInfoShow(bool json) if (tarif) { GetTextIndexed(name, sizeof(name), tarif-1, kTarifName); if (tinfo_mode==TINFO_MODE_STANDARD ) { - WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO, "", name); + WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO_STD, name); } else { - WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO, "Heures ", name); + WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO_HISTO, name); } } if (contrat && isousc) { @@ -1006,7 +1043,7 @@ void TInfoShow(bool json) WSContentSend_P(HTTP_ENERGY_PMAX_TELEINFO, atoi(value)); } if (getValueFromLabelIndex(LABEL_LTARF, value) ) { - WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO, value); + WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO_STD, value); } if (getValueFromLabelIndex(LABEL_NGTF, value) ) { if (isousc) { @@ -1035,6 +1072,9 @@ bool Xnrg15(uint8_t function) case FUNC_INIT: TInfoInit(); break; + case FUNC_SAVE_BEFORE_RESTART: + if (tinfo_found) { TInfoSaveBeforeRestart(); } + break; case FUNC_PRE_INIT: TInfoDrvInit(); break; diff --git a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino index ec6647a76..5a282bc50 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino @@ -226,6 +226,8 @@ bool Cse7761ChipInit(void) { Settings->energy_voltage_calibration = Cse7761Ref(RmsUC); Settings->energy_current_calibration = Cse7761Ref(RmsIAC); Settings->energy_power_calibration = Cse7761Ref(PowerPAC); + Settings->energy_current_calibration2 = Settings->energy_current_calibration; + Settings->energy_power_calibration2 = Settings->energy_power_calibration; } // Just to fix intermediate users if (Settings->energy_frequency_calibration < CSE7761_FREF / 2) { @@ -466,15 +468,17 @@ void Cse7761GetData(void) { for (uint32_t channel = 0; channel < 2; channel++) { Energy.data_valid[channel] = 0; + uint32_t power_calibration = EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION); // Active power = PowerPA * PowerPAC * 1000 / 0x80000000 // Energy.active_power[channel] = (float)(((uint64_t)CSE7761Data.active_power[channel] * CSE7761Data.coefficient[PowerPAC + channel] * 1000) >> 31) / 1000; // W - Energy.active_power[channel] = (float)CSE7761Data.active_power[channel] / Settings->energy_power_calibration; // W + Energy.active_power[channel] = (float)CSE7761Data.active_power[channel] / power_calibration; // W if (0 == Energy.active_power[channel]) { Energy.current[channel] = 0; } else { + uint32_t current_calibration = EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION); // Current = RmsIA * RmsIAC / 0x800000 // Energy.current[channel] = (float)(((uint64_t)CSE7761Data.current_rms[channel] * CSE7761Data.coefficient[RmsIAC + channel]) >> 23) / 1000; // A - Energy.current[channel] = (float)CSE7761Data.current_rms[channel] / Settings->energy_current_calibration; // A + Energy.current[channel] = (float)CSE7761Data.current_rms[channel] / current_calibration; // A CSE7761Data.energy[channel] += Energy.active_power[channel]; CSE7761Data.energy_update[channel]++; } @@ -616,7 +620,7 @@ bool Cse7761Command(void) { else if (CMND_POWERSET == Energy.command_code) { if (XdrvMailbox.data_len && CSE7761Data.active_power[channel]) { if ((value > 100) && (value < 200000)) { // Between 1W and 2000W - Settings->energy_power_calibration = ((CSE7761Data.active_power[channel]) / value) * 100; + XdrvMailbox.payload = ((CSE7761Data.active_power[channel]) / value) * 100; } } } @@ -627,7 +631,7 @@ bool Cse7761Command(void) { else if (CMND_VOLTAGESET == Energy.command_code) { if (XdrvMailbox.data_len && CSE7761Data.voltage_rms) { if ((value > 10000) && (value < 26000)) { // Between 100V and 260V - Settings->energy_voltage_calibration = (CSE7761Data.voltage_rms * 100) / value; + XdrvMailbox.payload = (CSE7761Data.voltage_rms * 100) / value; } } } @@ -638,7 +642,7 @@ bool Cse7761Command(void) { else if (CMND_CURRENTSET == Energy.command_code) { if (XdrvMailbox.data_len && CSE7761Data.current_rms[channel]) { if ((value > 1000) && (value < 1000000)) { // Between 10mA and 10A - Settings->energy_current_calibration = ((CSE7761Data.current_rms[channel] * 100) / value) * 1000; + XdrvMailbox.payload = ((CSE7761Data.current_rms[channel] * 100) / value) * 1000; } } } @@ -650,7 +654,7 @@ bool Cse7761Command(void) { else if (CMND_FREQUENCYSET == Energy.command_code) { if (XdrvMailbox.data_len && CSE7761Data.frequency) { if ((value > 4500) && (value < 6500)) { // Between 45.00Hz and 65.00Hz - Settings->energy_frequency_calibration = (CSE7761Data.frequency * 8 * value) / 100; + XdrvMailbox.payload = (CSE7761Data.frequency * 8 * value) / 100; } } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino b/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino index f9714b052..c87fd2a30 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino @@ -22,24 +22,24 @@ /*********************************************************************************************\ * Chinese BL6523 based Watt hour meter * - * This meter provides accurate Voltage, Frequency, Ampere, Wattage, Power Factor, KWh + * This meter provides accurate Voltage, Frequency, Ampere, Wattage, Power Factor, KWh * To use Tasmota the user needs to add an ESP8266 or ESP32 * Three lines need to be connected via 1KOhh resistors to ESP from the main board(RX,TX GND) - * + * * Connection Eg (ESP8266) - Non - Isolated: * BL6523 RX ->1KOhm-> ESP IO4(D2) (Should be Input Capable) * BL6523 TX ->1KOhm-> ESP IO5(D1) (Should be Input Capable) * BL6523 GND -> ESP GND - * + * * Connection Eg (ESP32) - Non - Isolated: * BL6523 RX ->1KOhm-> ESP IO4 (Should be Input Capable) * BL6523 TX ->1KOhm-> ESP IO5 (Should be Input Capable) * BL6523 GND -> ESP GND - * + * * To build add the below to user_config_override.h * #define USE_ENERGY_SENSOR // Enable Energy sensor framework * #define USE_BL6523 // Add support for Chinese BL6523 based Watt hour meter (+1k code)¸ - * + * * After Installation use the below template sample: * {"NAME":"BL6523 Smart Meter","GPIO":[0,0,0,0,7488,7520,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} \*********************************************************************************************/ @@ -106,7 +106,7 @@ bool Bl6523ReadData(void) Bl6523RxSerial->flush(); // Make room for another burst AddLogBuffer(LOG_LEVEL_DEBUG_MORE, rx_buffer, BL6523_RX_DATASET_SIZE); - + i=0; while (Bl6523TxSerial->available() < BL6523_TX_DATASET_SIZE) { @@ -116,15 +116,15 @@ bool Bl6523ReadData(void) break; } } - + uint8_t tx_buffer[BL6523_TX_DATASET_SIZE]; Bl6523TxSerial->readBytes(tx_buffer, BL6523_TX_DATASET_SIZE); Bl6523TxSerial->flush(); // Make room for another burst - + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, tx_buffer, BL6523_TX_DATASET_SIZE); - + /* Checksum: (Addr+Data_L+Data_M+Data_H) & 0xFF, then byte invert */ uint8_t crc = rx_buffer[1]; //Addr for (uint32_t i = 0; i < (BL6523_TX_DATASET_SIZE - 1); i++) @@ -136,15 +136,15 @@ bool Bl6523ReadData(void) if (crc != tx_buffer[BL6523_TX_DATASET_SIZE - 1]) { AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL6:" D_CHECKSUM_FAILURE)); - Bl6523TxSerial->flush(); - Bl6523RxSerial->flush(); + Bl6523TxSerial->flush(); + Bl6523RxSerial->flush(); return false; } /* WRITE DATA (format: command(write->0xCA) address data_low data_mid data_high checksum ) WRITE Sample(RX): RX: CA 3E 55 00 00 6C (WRPROT - allow) -RX: CA 14 00 00 10 DB (MODE) +RX: CA 14 00 00 10 DB (MODE) RX: CA 15 04 00 00 E6 (GAIN - IB 16x gain ) RX: CA 19 08 00 00 DE (WA_CFDIV ) RX: CA 3E AA 00 00 17 (WRPROT - disable) @@ -154,8 +154,8 @@ RX: CA 3E AA 00 00 17 (WRPROT - disable) READ Sample(RX-TX) Data: RX: 35 05 TX: E4 00 00 16 (IA rms ) RX: 35 07 TX: D5 A3 2E 52 (V rms ) -RX: 35 09 TX: F0 FB 02 09 (FREQ) -RX: 35 0A TX: 00 00 00 F5 (WATT) +RX: 35 09 TX: F0 FB 02 09 (FREQ) +RX: 35 0A TX: 00 00 00 F5 (WATT) RX: 35 08 TX: 00 00 00 F7 (PF) RX: 35 0C TX: 00 00 00 F3 (WATT_HR) */ @@ -169,7 +169,7 @@ switch(rx_buffer[1]) { break; case BL6523_REG_FREQ : Energy.frequency[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_frequency_calibration; // 50.0 Hz - break; + break; case BL6523_REG_WATTS : Energy.active_power[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_power_calibration; // -196.3 W break; @@ -181,7 +181,7 @@ switch(rx_buffer[1]) { powf_buf = ((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]); powf_word = (powf_buf >> 23) ? ~(powf_buf & 0x7fffff) : powf_buf & 0x7fffff; //Extract the 23 bits and invert if sign bit(24) is set for (int i = 0; i < 23; i++){ // Accumulate powf from 23 bits - powf += ((powf_word >> (22-i)) * pow(2,(0-(i+1)))); + powf += ((powf_word >> (22-i)) * pow(2,(0-(i+1)))); powf_word = powf_word & (0x7fffff >> (1+i)); } powf = (powf_buf >> 23) ? (0.0f - (powf)) : powf; // Negate if sign bit(24) is set @@ -190,8 +190,8 @@ switch(rx_buffer[1]) { case BL6523_REG_WATTHR : Energy.import_active[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / ( Settings->energy_power_calibration - BL6523_PWHRREF_D ); // 6.216 kWh => used in EnergyUpdateTotal() break; - default : - break; + default : + break; } Energy.data_valid[SINGLE_PHASE] = 0; EnergyUpdateTotal(); @@ -201,7 +201,7 @@ switch(rx_buffer[1]) { Bl6523.discovery_triggered = true; } return true; - + } /*********************************************************************************************/ @@ -216,7 +216,7 @@ void Bl6523Update(void) { if (Bl6523.valid) { Bl6523.valid--; - } + } } } @@ -224,7 +224,7 @@ void Bl6523Update(void) void Bl6523Init(void) { - + Bl6523.type = 0; Bl6523RxSerial = new TasmotaSerial(Pin(GPIO_BL6523_RX), -1, 1); Bl6523TxSerial = new TasmotaSerial(Pin(GPIO_BL6523_TX), -1, 1); @@ -247,7 +247,7 @@ void Bl6523Init(void) AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:Init Failure!" )); TasmotaGlobal.energy_driver = ENERGY_NONE; } - + } bool Bl6523Command(void) { @@ -262,28 +262,28 @@ bool Bl6523Command(void) { else if (CMND_POWERSET == Energy.command_code) { if (XdrvMailbox.data_len) { if ((abs_value > 100) && (abs_value < 200000)) { // Between 1.00 and 2000.00 W - Settings->energy_power_calibration = abs_value; + XdrvMailbox.payload = abs_value; } } } else if (CMND_VOLTAGESET == Energy.command_code) { if (XdrvMailbox.data_len) { if ((abs_value > 10000) && (abs_value < 26000)) { // Between 100.00 and 260.00 V - Settings->energy_voltage_calibration = abs_value; + XdrvMailbox.payload = abs_value; } } } else if (CMND_CURRENTSET == Energy.command_code) { if (XdrvMailbox.data_len) { if ((abs_value > 1000) && (abs_value < 1000000)) { // Between 10.00 mA and 10.00000 A - Settings->energy_current_calibration = abs_value; + XdrvMailbox.payload = abs_value; } } } else if (CMND_FREQUENCYSET == Energy.command_code) { if (XdrvMailbox.data_len) { if ((abs_value > 4500) && (abs_value < 6500)) { // Between 45.00 and 65.00 Hz - Settings->energy_frequency_calibration = abs_value; + XdrvMailbox.payload = abs_value; } } } @@ -323,7 +323,7 @@ void Bl6523DrvInit(void) AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:PreInit Failure!" )); TasmotaGlobal.energy_driver = ENERGY_NONE; } - + } /*********************************************************************************************\ @@ -333,7 +333,7 @@ void Bl6523DrvInit(void) bool Xnrg22(uint8_t function) { bool result = false; - + switch (function) { case FUNC_EVERY_250_MSECOND: @@ -341,7 +341,7 @@ bool Xnrg22(uint8_t function) break; case FUNC_COMMAND: result = Bl6523Command(); - break; + break; case FUNC_INIT: Bl6523Init(); break; @@ -349,7 +349,7 @@ bool Xnrg22(uint8_t function) Bl6523DrvInit(); break; } - + return result; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino index 065c909af..021003e3a 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino @@ -55,14 +55,20 @@ struct { void NrgDummyEverySecond(void) { if (Energy.power_on) { // Powered on for (uint32_t channel = 0; channel < Energy.phase_count; channel++) { - Energy.voltage[channel] = ((float)Settings->energy_voltage_calibration / 100); // V - Energy.frequency[channel] = ((float)Settings->energy_frequency_calibration / 100); // Hz - if (bitRead(TasmotaGlobal.power, channel)) { // Emulate power read only if device is powered on - Energy.active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : ((float)Settings->energy_power_calibration / 100); // W + + float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 100; + float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION) / 100; + float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) / 100000; + float frequency_calibration = (float)EnergyGetCalibration(channel, ENERGY_FREQUENCY_CALIBRATION) / 100; + + Energy.voltage[channel] = power_calibration; // V + Energy.frequency[channel] = frequency_calibration; // Hz + if (bitRead(TasmotaGlobal.power, channel)) { // Emulate power read only if device is powered on + Energy.active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : voltage_calibration; // W if (0 == Energy.active_power[channel]) { Energy.current[channel] = 0; } else { - Energy.current[channel] = (NrgDummy.current[channel]) ? ((float)NrgDummy.current[channel] / 1000) : ((float)Settings->energy_current_calibration / 100000); // A + Energy.current[channel] = (NrgDummy.current[channel]) ? ((float)NrgDummy.current[channel] / 1000) : current_calibration; // A Energy.kWhtoday_delta[channel] += Energy.active_power[channel] * 1000 / 36; } Energy.data_valid[channel] = 0; @@ -84,28 +90,28 @@ bool NrgDummyCommand(void) { else if (CMND_POWERSET == Energy.command_code) { if (XdrvMailbox.data_len) { if ((abs_value >= 100) && (abs_value <= 16000000)) { // Between 1.00 and 160000.00 W - Settings->energy_power_calibration = abs_value; + XdrvMailbox.payload = abs_value; } } } else if (CMND_VOLTAGESET == Energy.command_code) { if (XdrvMailbox.data_len) { if ((abs_value >= 10000) && (abs_value <= 40000)) { // Between 100.00 and 400.00 V - Settings->energy_voltage_calibration = abs_value; + XdrvMailbox.payload = abs_value; } } } else if (CMND_CURRENTSET == Energy.command_code) { if (XdrvMailbox.data_len) { if ((abs_value >= 1000) && (abs_value <= 40000000)) { // Between 10.00 mA and 400.00000 A - Settings->energy_current_calibration = abs_value; + XdrvMailbox.payload = abs_value; } } } else if (CMND_FREQUENCYSET == Energy.command_code) { if (XdrvMailbox.data_len) { if ((abs_value >= 4500) && (abs_value <= 6500)) { // Between 45.00 and 65.00 Hz - Settings->energy_frequency_calibration = abs_value; + XdrvMailbox.payload = abs_value; } } } @@ -134,6 +140,9 @@ void NrgDummyDrvInit(void) { Settings->energy_voltage_calibration = NRG_DUMMY_UREF; Settings->energy_current_calibration = NRG_DUMMY_IREF; Settings->energy_power_calibration = NRG_DUMMY_PREF; + Settings->energy_voltage_calibration2 = NRG_DUMMY_UREF; + Settings->energy_current_calibration2 = NRG_DUMMY_IREF; + Settings->energy_power_calibration2 = NRG_DUMMY_PREF; } Energy.phase_count = (TasmotaGlobal.devices_present < ENERGY_MAX_PHASES) ? TasmotaGlobal.devices_present : ENERGY_MAX_PHASES; diff --git a/tasmota/tasmota_xsns_sensor/xsns_40_pn532.ino b/tasmota/tasmota_xsns_sensor/xsns_40_pn532.ino index 03eba20c7..4c39f4342 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_40_pn532.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_40_pn532.ino @@ -1,7 +1,7 @@ /* xsns_40_pn532.ino - Support for PN532 (HSU) NFC Tag Reader on Tasmota - Copyright (C) 2021 Andre Thomas and Theo Arends + Copyright (C) 2021 Andre Thomas, Theo Arends and md5sum-as (https://github.com/md5sum-as) 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 @@ -47,24 +47,48 @@ TasmotaSerial *PN532_Serial; #define PN532_COMMAND_SAMCONFIGURATION 0x14 #define PN532_COMMAND_RFCONFIGURATION 0x32 #define PN532_COMMAND_INDATAEXCHANGE 0x40 +#define PN532_COMMAND_INCOMMUNICATETHRU 0x42 #define PN532_COMMAND_INLISTPASSIVETARGET 0x4A - +#define PN532_COMMAND_INRELEASE 0x52 +#define PN532_COMMAND_INSELECT 0x54 #define PN532_MIFARE_ISO14443A 0x00 #define MIFARE_CMD_READ 0x30 #define MIFARE_CMD_AUTH_A 0x60 #define MIFARE_CMD_AUTH_B 0x61 #define MIFARE_CMD_WRITE 0xA0 +#define NTAG21X_CMD_GET_VERSION 0x60 +#define NTAG2XX_CMD_READ 0x30 +#define NTAG21X_CMD_FAST_READ 0x3A +#define NTAG21X_CMD_PWD_AUTH 0x1B +#define NTAG2XX_CMD_WRITE 0xA2 + +const struct { + uint8_t version[6]; + uint8_t confPage; +} NTAG[] PROGMEM ={ + {.version={0x04, 0x02, 0x01, 0x00, 0x0f, 0x03},.confPage=0x29}, /* NTAG213 */ + {.version={0x04, 0x02, 0x01, 0x00, 0x11, 0x03},.confPage=0x83}, /* NTAG215 */ + {.version={0x04, 0x02, 0x01, 0x00, 0x13, 0x03},.confPage=0xe3}, /* NTAG216 */ + {.version={0x04, 0x05, 0x02, 0x02, 0x13, 0x03},.confPage=0xe3}, /* NT3H2111 */ + {.version={0x04, 0x05, 0x02, 0x02, 0x15, 0x03},.confPage=0xe3}, /* NT3H2211 */ +}; +#define NTAG_CNT (sizeof(NTAG)/7) // num records in NTAG array + struct PN532 { char uids[21]; // Number of bytes in the UID. 4, 7 or 10 uint8_t packetbuffer[64]; // Global buffer used to store packet uint8_t command = 0; // Carry command code between functions uint8_t scantimer = 0; // Prevent multiple successful reads within 2 second window bool present = false; // Maintain detection flag + uint16_t atqa; #ifdef USE_PN532_DATA_FUNCTION uint8_t newdata[16]; uint8_t function = 0; - uint8_t newdata_len = 0; + uint32_t pwd_auth; + uint16_t pwd_pack; + uint32_t pwd_auth_new; + uint16_t pwd_pack_new; #endif // USE_PN532_DATA_FUNCTION } Pn532; @@ -82,6 +106,10 @@ void PN532_Init(void) { PN532_SAMConfig(); AddLog(LOG_LEVEL_INFO,"NFC: PN532 NFC Reader detected v%u.%u",(ver>>16) & 0xFF, (ver>>8) & 0xFF); Pn532.present = true; +#ifdef USE_PN532_DATA_FUNCTION + Pn532.pwd_auth=Settings->pn532_password; + Pn532.pwd_pack=Settings->pn532_pack; +#endif } } } @@ -273,9 +301,9 @@ bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidL return 0; } - uint16_t sens_res = Pn532.packetbuffer[2]; - sens_res <<= 8; - sens_res |= Pn532.packetbuffer[3]; + Pn532.atqa = Pn532.packetbuffer[2]; + Pn532.atqa <<= 8; + Pn532.atqa |= Pn532.packetbuffer[3]; /* Card appears to be Mifare Classic */ *uidLength = Pn532.packetbuffer[5]; @@ -310,9 +338,27 @@ bool PN532_SAMConfig(void) { return (0 < PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer))); } +/* void PN532_inSelect(void) { + Pn532.packetbuffer[0] = PN532_COMMAND_INSELECT; + Pn532.packetbuffer[1] = 1; + if (PN532_writeCommand(Pn532.packetbuffer, 2)) { + return ; + } + int16_t res = PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer)); +} */ + #ifdef USE_PN532_DATA_FUNCTION -uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) { +void PN532_inRelease(void) { + Pn532.packetbuffer[0] = PN532_COMMAND_INRELEASE; + Pn532.packetbuffer[1] = 1; + if (PN532_writeCommand(Pn532.packetbuffer, 2)) { + return; + } + PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer)); +} + +uint8_t PN532_mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) { uint8_t i; uint8_t _key[6]; uint8_t _uid[7]; @@ -349,7 +395,7 @@ uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t return 1; } -uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) { +uint8_t PN532_mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) { /* Prepare the command */ Pn532.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; Pn532.packetbuffer[1] = 1; /* Card number */ @@ -376,7 +422,7 @@ uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) { return 1; } -uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) { +uint8_t PN532_mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) { /* Prepare the first command */ Pn532.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; Pn532.packetbuffer[1] = 1; /* Card number */ @@ -393,73 +439,181 @@ uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) { return (0 < PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer))); } +uint8_t PN532_ntag21x_probe (void) { + uint8_t result=0; + + Pn532.packetbuffer[0] = PN532_COMMAND_INCOMMUNICATETHRU; + Pn532.packetbuffer[1] = NTAG21X_CMD_GET_VERSION; + + if (PN532_writeCommand(Pn532.packetbuffer, 2)) { + return result; + } + + if (PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer))<9){ + return result; + } + + if (Pn532.packetbuffer[3] != 4) { // not NTAG type + return result; + } + + for (uint8_t i=0; i0) { + /* NTAG EV1 found*/ + str_pwd=PWD_NONE; + if (!PN532_ntag2xx_read16(4, card_datas)) { + if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, nuid, &nuid_len)) { + if (memcmp(uid, nuid, sizeof(uid))==0) { + if (PN532_ntag21x_auth()) { + str_pwd=PWD_OK; + if (Pn532.function == 3) { /* new password */ + success = PN532_ntag21x_set_password(confPage, false); + } + if (Pn532.function == 4) { /* clear password */ + success = PN532_ntag21x_set_password(confPage, true); + } + } else { + str_pwd=PWD_NOK; + } + if (!PN532_ntag2xx_read16(4, card_datas)) card_datas[0]=0; + } + } + } else { + if (Pn532.function == 3) { /* new password */ + success = PN532_ntag21x_set_password(confPage, false); + } + } + } else { + if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, nuid, &nuid_len)) { + if (memcmp(uid, nuid, sizeof(uid))==0) { + if (!PN532_ntag2xx_read16(4, card_datas)) card_datas[0]=0; + } + } + } + if ((Pn532.function == 1) || (Pn532.function == 2)) { + success = PN532_ntag2xx_write16(4, (char *)Pn532.newdata); + if (!PN532_ntag2xx_read16(4, card_datas)) card_datas[0]=0; + } + } + else if (uid_len == 4) { // Lets try to read blocks 1 & 2 of the mifare classic card for more information uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - if (mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) { - uint8_t card_data[16]; - if (mifareclassic_ReadDataBlock(1, card_data)) { -#ifdef USE_PN532_DATA_RAW - memcpy(&card_datas,&card_data,sizeof(card_data)); -#else - for (uint32_t i = 0;i < sizeof(card_data);i++) { - if ((isalpha(card_data[i])) || ((isdigit(card_data[i])))) { - card_datas[i] = char(card_data[i]); - } else { - card_datas[i] = '\0'; - } - } -#endif // USE_PN532_DATA_RAW + if (PN532_mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) { + if ((Pn532.function == 1) || (Pn532.function == 2)) { + success=PN532_mifareclassic_WriteDataBlock(1, Pn532.newdata); } - if (Pn532.function == 1) { // erase block 1 of card - for (uint32_t i = 0;i<16;i++) { - card_data[i] = 0x00; - } - if (mifareclassic_WriteDataBlock(1, card_data)) { - erase_success = true; - AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Erase success")); - memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string - } - } - if (Pn532.function == 2) { -#ifdef USE_PN532_DATA_RAW - memcpy(&card_data,&Pn532.newdata,sizeof(card_data)); - if (mifareclassic_WriteDataBlock(1, card_data)) { - set_success = true; - AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data write successful")); - memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string - } -#else - bool IsAlphaNumeric = true; - for (uint32_t i = 0;i < Pn532.newdata_len;i++) { - if ((!isalpha(Pn532.newdata[i])) && (!isdigit(Pn532.newdata[i]))) { - IsAlphaNumeric = false; + if (PN532_mifareclassic_ReadDataBlock(1, (uint8_t *)card_datas)) { + for (uint32_t i = 0; i < 16; i++) { + if (!isprint(card_datas[i])) { + // do not output non-printable characters to the console + card_datas[i] = 0; } } - if (IsAlphaNumeric) { - memcpy(&card_data,&Pn532.newdata,Pn532.newdata_len); - card_data[Pn532.newdata_len] = '\0'; // Enforce null termination - if (mifareclassic_WriteDataBlock(1, card_data)) { - set_success = true; - AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data write successful")); - memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string - } - } else { - AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data must be alphanumeric")); - } -#endif // USE_PN532_DATA_RAW + } else { + card_datas[0] = 0; } } else { sprintf_P(card_datas, PSTR("AUTHFAIL")); @@ -467,19 +621,50 @@ void PN532_ScanForTag(void) { } switch (Pn532.function) { case 0x01: - if (!erase_success) { - AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Erase fail - exiting erase mode")); + if (success) { + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Erase success")); + } else { + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Erase fail - exiting erase mode")); } break; case 0x02: - if (!set_success) { - AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Write failed - exiting set mode")); + if (success) { + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Data write successful")); + } else{ + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Write failed - exiting set mode")); } + break; + case 0x03: + if (success) { + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Set password successful")); + } else{ + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Set password failed - exiting set mode")); + } + break; + case 0x04: + if (success) { + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Unset password successful")); + } else{ + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Unset password failed - exiting set mode")); + } + break; default: break; } Pn532.function = 0; - ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\",\"" D_JSON_DATA "\":\"%s\"}}"), Pn532.uids, card_datas); + card_datas[16] = 0; + ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\",\"" D_JSON_DATA "\":\"%s\""), Pn532.uids, card_datas); + if (str_pwd == PWD_NONE) { + ResponseAppend_P(PSTR(",\"Auth\":\"None\"")); + } else + if (str_pwd == PWD_OK) { + ResponseAppend_P(PSTR(",\"Auth\":\"Ok\"")); + } else + if (str_pwd == PWD_NOK) { + ResponseAppend_P(PSTR(",\"Auth\":\"NOk\"")); + } + ResponseAppend_P(PSTR("}}")); + PN532_inRelease(); #else ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\"}}"), Pn532.uids); #endif // USE_PN532_DATA_FUNCTION @@ -492,44 +677,73 @@ void PN532_ScanForTag(void) { #ifdef USE_PN532_DATA_FUNCTION bool PN532_Command(void) { - bool serviced = true; - uint8_t paramcount = 0; - if (XdrvMailbox.data_len > 0) { - paramcount=1; - } else { - serviced = false; + bool serviced = false; + char command[10]; + char log[70]; + if (ArgC() < 1) { return serviced; } + char argument[XdrvMailbox.data_len]; - for (uint32_t ca=0;ca 1) { - if (XdrvMailbox.data[XdrvMailbox.data_len-1] == ',') { - serviced = false; - return serviced; - } + if (!strcmp_P(argument,PSTR("WRITE"))) { + if (ArgC() > 1) { ArgV(argument, 2); - Pn532.newdata_len = strlen(argument); - if (Pn532.newdata_len > 15) { Pn532.newdata_len = 15; } - memcpy(&Pn532.newdata,&argument,Pn532.newdata_len); - Pn532.newdata[Pn532.newdata_len] = 0x00; // Null terminate the string + memset(Pn532.newdata,0,sizeof(Pn532.newdata)); + strncpy((char *)Pn532.newdata,argument,sizeof(Pn532.newdata)); + if (strlen(argument)>16) argument[16]=0; Pn532.function = 2; - AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Next scanned tag data block 1 will be set to '%s'"), Pn532.newdata); - ResponseTime_P(PSTR(",\"PN532\":{\"COMMAND\":\"S\"}}")); - return serviced; + snprintf_P(log, sizeof(log), PSTR("data block 1 (4-7 for NTAG) will be set to '%s'"), argument); + serviced = true; } } - return false; + if (!strcmp_P(argument,PSTR("AUTH"))) { + if (ArgC() > 1) { + Pn532.pwd_auth=strtoul(ArgV(argument,2),nullptr,0); + } + if (ArgC() > 2) { + Pn532.pwd_pack=strtoul(ArgV(argument,3),nullptr,0); + } + Settings->pn532_password=Pn532.pwd_auth; + Settings->pn532_pack=Pn532.pwd_pack; + + serviced = true; + } + if (!strcmp_P(argument,PSTR("SET_PWD"))) { + snprintf_P(log, sizeof(log), PSTR("will be protected")); + Pn532.pwd_auth_new=Pn532.pwd_auth; + Pn532.pwd_pack_new=Pn532.pwd_pack; + if (ArgC() > 1) { + Pn532.pwd_auth_new=strtoul(ArgV(argument,2),nullptr,0); + } + if (ArgC() > 2) { + Pn532.pwd_pack_new=strtoul(ArgV(argument,3),nullptr,0); + } + Pn532.function = 3; + serviced = true; + } + if (!strcmp_P(argument,PSTR("UNSET_PWD"))) { + snprintf_P(log, sizeof(log), PSTR("will be unprotected")); + Pn532.function = 4; + serviced = true; + } + if (!strcmp_P(argument,PSTR("CANCEL"))) { + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Job canceled")); + Pn532.function = 0; + serviced = true; + } else { + AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Next scanned tag %s"), log); + } + if (serviced) ResponseTime_P(PSTR(",\"PN532\":{\"COMMAND\":\"%s\"}}"),command); + return serviced; } #endif // USE_PN532_DATA_FUNCTION diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino index 62e06f3ac..451044a8e 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -1683,7 +1683,7 @@ void sml_shift_in(uint32_t meters,uint32_t shard) { meter_spos[meters] = 0; } // modbus - if (meter_spos[meters] >= 8) { + if (meter_spos[meters] >= 3) { uint32_t mlen = smltbuf[meters][2] + 5; if (mlen > SML_BSIZ) mlen = SML_BSIZ; if (meter_spos[meters] >= mlen) { diff --git a/tools/decode-status.py b/tools/decode-status.py index d076f11a2..1ae8641e2 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -97,8 +97,8 @@ a_setoption = [[ "(Rotary) Rotary step boundary (default 10)", "(IR) Base tolerance percentage for matching incoming IR messages (default 25, max 100)", "(Bistable) Pulse time in milliseconds for two coil bistable latching relays (default 40)", - "(not used) Tuya MCU power Id", - "(not used) Energy Tariff1 start hour", + "(PowerOn) Add delay of 10 x value milliseconds at power on", + "(PowerOn) Add delay of value seconds at power on before activating relays", "(not used) Energy Tariff2 start hour", "", ],[ @@ -287,7 +287,7 @@ a_features = [[ "USE_BP5758D","USE_HYT","USE_SM2335","USE_DISPLAY_TM1621_SONOFF" ],[ "USE_SGP40","USE_LUXV30B","USE_CANSNIFFER","USE_QMC5883L", - "USE_MODBUS_ENERGY","","","", + "USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ", "","","","", "","","","", "","","","", @@ -321,7 +321,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v12.1.1.4 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v12.2.0.3 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj)) diff --git a/tools/fw_SonoffZigbeeBridgePro_router_only_cc2652/SonoffZBPro_router_20220125.hex b/tools/fw_SonoffZigbeeBridgePro_router_only_cc2652/SonoffZBPro_router_20220125.hex index 1d220c012..19bb38b64 100644 --- a/tools/fw_SonoffZigbeeBridgePro_router_only_cc2652/SonoffZBPro_router_20220125.hex +++ b/tools/fw_SonoffZigbeeBridgePro_router_only_cc2652/SonoffZBPro_router_20220125.hex @@ -5717,6 +5717,6 @@ :20CA1800A0C902000C010020A8C9020000010020B0C9020004010020B8C902000801002086 :020000040005F5 :207FA800000080011000C0FFFDFF58003AC1B9FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 -:207FC800FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC508FEC5FFFFFFFF00FFFFFF00C5C5FF90 +:207FC800FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC508FEC5FFFFFFFF00FFFFFF00C5C5FF97 :187FE800000000FF00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 :00000001FF