Merge branch 'development' into dingtian_driver

This commit is contained in:
Barbudor 2022-11-07 22:33:35 +01:00
commit b03476ff6f
83 changed files with 2614 additions and 485 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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),

View File

@ -957,7 +957,6 @@ static int m_setfloat(bvm *vm)
* `setbytes(index:int, fill:bytes [, from:int, len:int]) -> nil`
*
*/
#include <stdio.h>
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)

View File

@ -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"))

View File

@ -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
#endif // USE_BERRY_ULP

View File

@ -0,0 +1,4 @@
/********************************************************************
* Tasmota dyn class
*******************************************************************/
#include "solidify/solidified_dyn.h"

View File

@ -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();

View File

@ -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

View File

@ -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()

View File

@ -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 */

View File

@ -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
})
)
);

View File

@ -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):

View File

@ -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)
-#

View File

@ -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

View File

@ -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"

View File

@ -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 };

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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: eFuseflash 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");
}

View File

@ -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;

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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"))) {

View File

@ -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

View File

@ -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

View File

@ -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 <berry.h>
#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
#endif // USE_BERRY

View File

@ -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

View File

@ -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.h>
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)
{

View File

@ -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"));

View File

@ -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);
}

View File

@ -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 <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------
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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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
}
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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; i<NTAG_CNT; i++) {
if (0 == memcmp_P(&Pn532.packetbuffer[3],&NTAG[i].version[0],6)) {
memcpy_P(&result,&NTAG[i].confPage,sizeof(result));
}
}
return result; //Return configuration page address
}
bool PN532_ntag21x_auth(void) {
Pn532.packetbuffer[0] = PN532_COMMAND_INCOMMUNICATETHRU;
Pn532.packetbuffer[1] = NTAG21X_CMD_PWD_AUTH;
memcpy(&Pn532.packetbuffer[2],&Pn532.pwd_auth,4);
if (PN532_writeCommand(Pn532.packetbuffer, 6)) {
return false;
}
if ((PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer)))<3){
return false;
}
if (Pn532.packetbuffer[0]) { //PN532 return any error
return false;
}
return memcmp(&Pn532.packetbuffer[1],&Pn532.pwd_pack,2)==0;
}
bool PN532_ntag2xx_read16 (const uint8_t page, char *out) {
Pn532.packetbuffer[0] = PN532_COMMAND_INCOMMUNICATETHRU;
Pn532.packetbuffer[1] = NTAG2XX_CMD_READ;
Pn532.packetbuffer[2] = page;
if (PN532_writeCommand(Pn532.packetbuffer, 3)) {
return false;
}
if ((PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer)))<17){
return false;
}
if (Pn532.packetbuffer[0]!=0) {
return false;
}
memcpy(out,&Pn532.packetbuffer[1],16);
return true;
}
bool PN532_ntag2xx_write4(uint8_t page, char *in) {
Pn532.packetbuffer[0] = PN532_COMMAND_INCOMMUNICATETHRU;
Pn532.packetbuffer[1] = NTAG2XX_CMD_WRITE;
Pn532.packetbuffer[2] = page; // first page
memcpy(&Pn532.packetbuffer[3],in,4);
if (PN532_writeCommand(Pn532.packetbuffer, 7)) {
return false;
}
if (PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer)) < 1) {
return false;
}
return true;
}
bool PN532_ntag2xx_write16(uint8_t page, char *in) {
for (uint8_t i = 0; i < 4; i++) {
if (!PN532_ntag2xx_write4(page +i, &in[i << 2])) {
return false;
}
}
return true;
}
bool PN532_ntag21x_set_password(uint8_t confPage, bool unsetPasswd) {
char card_datas[16];
if (PN532_ntag2xx_read16(confPage, card_datas)) {
if (unsetPasswd) {
card_datas[3]=0xFF;
return PN532_ntag2xx_write4(confPage, card_datas);
}
card_datas[3]=0; // Set AUTH0 for protect all pages
card_datas[4] |= 0x80; // Set PROT flag for read and write access is protected by the password verification
memcpy(&card_datas[8],&Pn532.pwd_auth_new, 4); // New password
memcpy(&card_datas[12],&Pn532.pwd_pack_new, 2); // New password ack
return PN532_ntag2xx_write16(confPage, card_datas);
}
return false;
}
#endif // USE_PN532_DATA_FUNCTION
void PN532_ScanForTag(void) {
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
uint8_t uid_len = 0;
if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uid_len)) {
ToHex_P((unsigned char*)uid, uid_len, Pn532.uids, sizeof(Pn532.uids));
#ifdef USE_PN532_DATA_FUNCTION
bool erase_success = false;
bool set_success = false;
char card_datas[34];
if (uid_len == 4) { // Lets try to read block 1 of the mifare classic card for more information
bool success = false;
char card_datas[17]={0};
enum {NOPWD, PWD_NONE, PWD_OK, PWD_NOK} str_pwd=NOPWD;
if (Pn532.atqa == 0x44) {
uint8_t confPage=0;
uint8_t nuid[] = { 0, 0, 0, 0, 0, 0, 0 };
uint8_t nuid_len = 0;
if ((confPage=PN532_ntag21x_probe())>0) {
/* 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<XdrvMailbox.data_len;ca++) {
if ((' ' == XdrvMailbox.data[ca]) || ('=' == XdrvMailbox.data[ca])) { XdrvMailbox.data[ca] = ','; }
if (',' == XdrvMailbox.data[ca]) { paramcount++; }
}
UpperCase(XdrvMailbox.data,XdrvMailbox.data);
if (!strcmp(ArgV(argument, 1),"E")) {
ArgV(argument, 1);
strncpy(command,UpperCase(argument,argument),sizeof(command));
if (!strcmp_P(argument,PSTR("ERASE"))) {
memset(Pn532.newdata,0,sizeof(Pn532.newdata));
Pn532.function = 1; // Block 1 of next card/tag will be reset to 0x00...
AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Next scanned tag data block 1 will be erased"));
ResponseTime_P(PSTR(",\"PN532\":{\"COMMAND\":\"E\"}}"));
return serviced;
snprintf_P(log, sizeof(log), PSTR("data block 1 (4-7 for NTAG) will be erased"));
serviced = true;
}
if (!strcmp(ArgV(argument, 1),"S")) {
if (paramcount > 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

View File

@ -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) {

View File

@ -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))

View File

@ -5717,6 +5717,6 @@
:20CA1800A0C902000C010020A8C9020000010020B0C9020004010020B8C902000801002086
:020000040005F5
:207FA800000080011000C0FFFDFF58003AC1B9FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74
:207FC800FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC508FEC5FFFFFFFF00FFFFFF00C5C5FF90
:207FC800FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC508FEC5FFFFFFFF00FFFFFF00C5C5FF97
:187FE800000000FF00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92
:00000001FF