Merge remote-tracking branch 'upstream/development' into development

* upstream/development: (35 commits)
  some fixes
  fix image weblink
  fix compiler error with use_graph
  Add support for another variant of the 6-digit TM1637 display
  Add commands ``DisplayType`` and ``DisplayInvert``
  Update xdrv_05_irremote.ino
  Update xdrv_05_irremote_full.ino
  Update xdrv_05_irremote_full.ino
  Update xdrv_05_irremote.ino
  Update xdrv_20_hue.ino
  Berry fix rules
  Add frequency to CSE7761 driver
  Minor fixes
  Delete .history/tasmota directory
  Delete xdrv_20_hue_20210321092519.ino
  only perform interlock delay once
  No Discovery
  Remove text "Module" from GUI main page
  Refactor DisplayDimmer
  Use Berry as default for Core2 and Odroid-go
  ...
This commit is contained in:
RaphDaMan 2021-03-22 23:17:03 +01:00
commit 3cf5609ad9
68 changed files with 2667 additions and 1331 deletions

View File

@ -18,9 +18,9 @@
| USE_WEBSEND_RESPONSE | - | - | - | - | - | - | - |
| USE_EMULATION_HUE | - | x | x | - | x | - | - |
| USE_EMULATION_WEMO | - | x | x | - | x | - | - |
| USE_DISCOVERY | - | - | x | x | - | - | x |
| USE_DISCOVERY | - | - | - | - | - | - | - |
| WEBSERVER_ADVERTISE | - | - | x | x | - | - | x |
| MQTT_HOST_DISCOVERY | - | - | x | x | - | - | x |
| MQTT_HOST_DISCOVERY | - | - | - | - | - | - | - |
| USE_TIMERS | - | x | x | x | x | x | x |
| USE_TIMERS_WEB | - | x | x | x | x | x | x |
| USE_SUNRISE | - | x | x | x | x | x | x |

View File

@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
## [9.3.1.2]
### Added
- Commands ``MqttKeepAlive 1..100`` to set Mqtt Keep Alive timer (default 30) and ``MqttTimeout 1..100`` to set Mqtt Socket Timeout (default 4) (#5341)
- Commands ``DisplayType`` to select sub-modules where implemented and ``DisplayInvert`` to select inverted display where implemented
- Support for TM1638 seven segment display by Ajith Vasudevan (#11031)
### Changed

View File

@ -82,16 +82,20 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
### Added
- Commands ``MqttKeepAlive 1..100`` to set Mqtt Keep Alive timer (default 30) and ``MqttTimeout 1..100`` to set Mqtt Socket Timeout (default 4) [#5341](https://github.com/arendst/Tasmota/issues/5341)
- Command ``Sensor80 1 <0..7>`` to control MFRC522 RFID antenna gain from 18dB (0) to 48dB (7) [#11073](https://github.com/arendst/Tasmota/issues/11073)
- Commands ``DisplayType`` to select sub-modules where implemented and ``DisplayInvert`` to select inverted display where implemented
- Support for SML VBUS [#11125](https://github.com/arendst/Tasmota/issues/11125)
- Support for NEC and OPTOMA LCD/DLP Projector serial power control by Jan Bubík [#11145](https://github.com/arendst/Tasmota/issues/11145)
- Support for XPT2046 touch screen digitizer on ILI9341 display by nonix [#11159](https://github.com/arendst/Tasmota/issues/11159)
- Support for zigbee lumi.sensor_wleak [#11200](https://github.com/arendst/Tasmota/issues/11200)
- Support for CSE7761 energy monitor as used in ESP32 based Sonoff Dual R3 Pow [#10793](https://github.com/arendst/Tasmota/issues/10793)
- Support for TM1638 seven segment display by Ajith Vasudevan [#11031](https://github.com/arendst/Tasmota/issues/11031)
- Support for MPU6886 on primary or secondary I2C bus
- Allow MCP230xx pinmode from output to input [#11104](https://github.com/arendst/Tasmota/issues/11104)
- Berry improvements [#11163](https://github.com/arendst/Tasmota/issues/11163)
- Extent compile time SetOptions support [#11204](https://github.com/arendst/Tasmota/issues/11204)
- ESP32 Extent BLE [#11212](https://github.com/arendst/Tasmota/issues/11212)
- ESP32 support for WS2812 hardware driver via RMT or I2S
- ESP32 support for secondary I2C controller
### Changed
- TasmotaSerial library from v3.2.0 to v3.3.0

View File

@ -0,0 +1,23 @@
LedControl.h - A library for controling Leds with a MAX7219/MAX7221
Copyright (c) 2007-2015 Eberhard Fahle
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
This permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,25 @@
LedControl
==========
LedControl is an [Arduino](http://arduino.cc) library for MAX7219 and MAX7221 Led display drivers.
The code also works with the [Teensy (3.1)](https://www.pjrc.com/teensy/)
Documentation
-------------
Documentation for the library is on the [Github Project Pages](http://wayoda.github.io/LedControl/)
Download
--------
The lastest binary version of the Library is always available from the
[LedControl Release Page](https://github.com/wayoda/LedControl/releases)
Install
-------
The library can be installed using the [standard Arduino library install procedure](http://arduino.cc/en/Guide/Libraries#.UwxndHX5PtY)

View File

@ -0,0 +1,28 @@
#######################################
# Syntax Coloring Map For LedControl
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
LedControl KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
shutdown KEYWORD2
setScanLimit KEYWORD2
setIntensity KEYWORD2
clearDisplay KEYWORD2
setLed KEYWORD2
setRow KEYWORD2
setColumn KEYWORD2
setDigit KEYWORD2
setChar KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,10 @@
name=LedControl
version=1.0.6
author=Eberhard Fahle <e.fahle@wayoda.org>
maintainer=Eberhard Fahle <e.fahle@wayoda.org>
sentence=A library for the MAX7219 and the MAX7221 Led display drivers.
paragraph=The library supports multiple daisychained drivers and supports Led-Matrix displays as well as 7-Segment displays.
category=Display
url=http://wayoda.github.io/LedControl/
architectures=*

View File

@ -0,0 +1,211 @@
/*
* LedControl.cpp - A library for controling Leds with a MAX7219/MAX7221
* Copyright (c) 2007 Eberhard Fahle
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* This permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "LedControl.h"
//the opcodes for the MAX7221 and MAX7219
#define OP_NOOP 0
#define OP_DIGIT0 1
#define OP_DIGIT1 2
#define OP_DIGIT2 3
#define OP_DIGIT3 4
#define OP_DIGIT4 5
#define OP_DIGIT5 6
#define OP_DIGIT6 7
#define OP_DIGIT7 8
#define OP_DECODEMODE 9
#define OP_INTENSITY 10
#define OP_SCANLIMIT 11
#define OP_SHUTDOWN 12
#define OP_DISPLAYTEST 15
LedControl::LedControl(int dataPin, int clkPin, int csPin, int numDevices) {
SPI_MOSI=dataPin;
SPI_CLK=clkPin;
SPI_CS=csPin;
if(numDevices<=0 || numDevices>8 )
numDevices=8;
maxDevices=numDevices;
pinMode(SPI_MOSI,OUTPUT);
pinMode(SPI_CLK,OUTPUT);
pinMode(SPI_CS,OUTPUT);
digitalWrite(SPI_CS,HIGH);
SPI_MOSI=dataPin;
for(int i=0;i<64;i++)
status[i]=0x00;
for(int i=0;i<maxDevices;i++) {
spiTransfer(i,OP_DISPLAYTEST,0);
//scanlimit is set to max on startup
setScanLimit(i,7);
//decode is done in source
spiTransfer(i,OP_DECODEMODE,0);
clearDisplay(i);
//we go into shutdown-mode on startup
shutdown(i,true);
}
}
int LedControl::getDeviceCount() {
return maxDevices;
}
void LedControl::shutdown(int addr, bool b) {
if(addr<0 || addr>=maxDevices)
return;
if(b)
spiTransfer(addr, OP_SHUTDOWN,0);
else
spiTransfer(addr, OP_SHUTDOWN,1);
}
void LedControl::setScanLimit(int addr, int limit) {
if(addr<0 || addr>=maxDevices)
return;
if(limit>=0 && limit<8)
spiTransfer(addr, OP_SCANLIMIT,limit);
}
void LedControl::setIntensity(int addr, int intensity) {
if(addr<0 || addr>=maxDevices)
return;
if(intensity>=0 && intensity<16)
spiTransfer(addr, OP_INTENSITY,intensity);
}
void LedControl::clearDisplay(int addr) {
int offset;
if(addr<0 || addr>=maxDevices)
return;
offset=addr*8;
for(int i=0;i<8;i++) {
status[offset+i]=0;
spiTransfer(addr, i+1,status[offset+i]);
}
}
void LedControl::setLed(int addr, int row, int column, boolean state) {
int offset;
byte val=0x00;
if(addr<0 || addr>=maxDevices)
return;
if(row<0 || row>7 || column<0 || column>7)
return;
offset=addr*8;
val=B10000000 >> column;
if(state)
status[offset+row]=status[offset+row]|val;
else {
val=~val;
status[offset+row]=status[offset+row]&val;
}
spiTransfer(addr, row+1,status[offset+row]);
}
void LedControl::setRow(int addr, int row, byte value) {
int offset;
if(addr<0 || addr>=maxDevices)
return;
if(row<0 || row>7)
return;
offset=addr*8;
status[offset+row]=value;
spiTransfer(addr, row+1,status[offset+row]);
}
void LedControl::setColumn(int addr, int col, byte value) {
byte val;
if(addr<0 || addr>=maxDevices)
return;
if(col<0 || col>7)
return;
for(int row=0;row<8;row++) {
val=value >> (7-row);
val=val & 0x01;
setLed(addr,row,col,val);
}
}
void LedControl::setDigit(int addr, int digit, byte value, boolean dp) {
int offset;
byte v;
if(addr<0 || addr>=maxDevices)
return;
if(digit<0 || digit>7 || value>15)
return;
offset=addr*8;
v=pgm_read_byte_near(charTable + value);
if(dp)
v|=B10000000;
status[offset+digit]=v;
spiTransfer(addr, digit+1,v);
}
void LedControl::setChar(int addr, int digit, char value, boolean dp) {
int offset;
byte index,v;
if(addr<0 || addr>=maxDevices)
return;
if(digit<0 || digit>7)
return;
offset=addr*8;
index=(byte)value;
if(index >127) {
//no defined beyond index 127, so we use the space char
index=32;
}
v=pgm_read_byte_near(charTable + index);
if(dp)
v|=B10000000;
status[offset+digit]=v;
spiTransfer(addr, digit+1,v);
}
void LedControl::spiTransfer(int addr, volatile byte opcode, volatile byte data) {
//Create an array with the data to shift out
int offset=addr*2;
int maxbytes=maxDevices*2;
for(int i=0;i<maxbytes;i++)
spidata[i]=(byte)0;
//put our device data into the array
spidata[offset+1]=opcode;
spidata[offset]=data;
//enable the line
digitalWrite(SPI_CS,LOW);
//Now shift out the data
for(int i=maxbytes;i>0;i--)
shiftOut(SPI_MOSI,SPI_CLK,MSBFIRST,spidata[i-1]);
//latch the data onto the display
digitalWrite(SPI_CS,HIGH);
}

View File

@ -0,0 +1,190 @@
/*
* LedControl.h - A library for controling Leds with a MAX7219/MAX7221
* Copyright (c) 2007 Eberhard Fahle
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* This permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LedControl_h
#define LedControl_h
#include <pgmspace.h>
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
/*
* Segments to be switched on for characters and digits on
* 7-Segment Displays
*/
const static byte charTable [] PROGMEM = {
B01111110,B00110000,B01101101,B01111001,B00110011,B01011011,B01011111,B01110000,
B01111111,B01111011,B01110111,B00011111,B00001101,B00111101,B01001111,B01000111,
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B10000000,B00000001,B10000000,B00000000,
B01111110,B00110000,B01101101,B01111001,B00110011,B01011011,B01011111,B01110000,
B01111111,B01111011,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B01110111,B00011111,B00001101,B00111101,B01001111,B01000111,B00000000,
B00110111,B00000000,B00000000,B00000000,B00001110,B00000000,B00000000,B00000000,
B01100111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001000,
B00000000,B01110111,B00011111,B00001101,B00111101,B01001111,B01000111,B00000000,
B00110111,B00000000,B00000000,B00000000,B00001110,B00000000,B00010101,B00011101,
B01100111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000
};
class LedControl {
private :
/* The array for shifting the data to the devices */
byte spidata[16];
/* Send out a single command to the device */
void spiTransfer(int addr, byte opcode, byte data);
/* We keep track of the led-status for all 8 devices in this array */
byte status[64];
/* Data is shifted out of this pin*/
int SPI_MOSI;
/* The clock is signaled on this pin */
int SPI_CLK;
/* This one is driven LOW for chip selectzion */
int SPI_CS;
/* The maximum number of devices we use */
int maxDevices;
public:
/*
* Create a new controler
* Params :
* dataPin pin on the Arduino where data gets shifted out
* clockPin pin for the clock
* csPin pin for selecting the device
* numDevices maximum number of devices that can be controled
*/
LedControl(int dataPin, int clkPin, int csPin, int numDevices=1);
/*
* Gets the number of devices attached to this LedControl.
* Returns :
* int the number of devices on this LedControl
*/
int getDeviceCount();
/*
* Set the shutdown (power saving) mode for the device
* Params :
* addr The address of the display to control
* status If true the device goes into power-down mode. Set to false
* for normal operation.
*/
void shutdown(int addr, bool status);
/*
* Set the number of digits (or rows) to be displayed.
* See datasheet for sideeffects of the scanlimit on the brightness
* of the display.
* Params :
* addr address of the display to control
* limit number of digits to be displayed (1..8)
*/
void setScanLimit(int addr, int limit);
/*
* Set the brightness of the display.
* Params:
* addr the address of the display to control
* intensity the brightness of the display. (0..15)
*/
void setIntensity(int addr, int intensity);
/*
* Switch all Leds on the display off.
* Params:
* addr address of the display to control
*/
void clearDisplay(int addr);
/*
* Set the status of a single Led.
* Params :
* addr address of the display
* row the row of the Led (0..7)
* col the column of the Led (0..7)
* state If true the led is switched on,
* if false it is switched off
*/
void setLed(int addr, int row, int col, boolean state);
/*
* Set all 8 Led's in a row to a new state
* Params:
* addr address of the display
* row row which is to be set (0..7)
* value each bit set to 1 will light up the
* corresponding Led.
*/
void setRow(int addr, int row, byte value);
/*
* Set all 8 Led's in a column to a new state
* Params:
* addr address of the display
* col column which is to be set (0..7)
* value each bit set to 1 will light up the
* corresponding Led.
*/
void setColumn(int addr, int col, byte value);
/*
* Display a hexadecimal digit on a 7-Segment Display
* Params:
* addr address of the display
* digit the position of the digit on the display (0..7)
* value the value to be displayed. (0x00..0x0F)
* dp sets the decimal point.
*/
void setDigit(int addr, int digit, byte value, boolean dp);
/*
* Display a character on a 7-Segment display.
* There are only a few characters that make sense here :
* '0','1','2','3','4','5','6','7','8','9','0',
* 'A','b','c','d','E','F','H','L','P',
* '.','-','_',' '
* Params:
* addr address of the display
* digit the position of the character on the display (0..7)
* value the character to be displayed.
* dp sets the decimal point.
*/
void setChar(int addr, int digit, char value, boolean dp);
};
#endif //LedControl.h

View File

@ -4,24 +4,24 @@
void MPU6886::I2C_Read_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer){
myWire.beginTransmission(driver_Addr);
myWire.write(start_Addr);
myWire.endTransmission(false);
myWire->beginTransmission(driver_Addr);
myWire->write(start_Addr);
myWire->endTransmission(false);
uint8_t i = 0;
myWire.requestFrom(driver_Addr,number_Bytes);
myWire->requestFrom(driver_Addr,number_Bytes);
//! Put read results in the Rx buffer
while (myWire.available()) {
read_Buffer[i++] = myWire.read();
while (myWire->available()) {
read_Buffer[i++] = myWire->read();
}
}
void MPU6886::I2C_Write_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer){
myWire.beginTransmission(driver_Addr);
myWire.write(start_Addr);
myWire.write(*write_Buffer);
myWire.endTransmission();
myWire->beginTransmission(driver_Addr);
myWire->write(start_Addr);
myWire->write(*write_Buffer);
myWire->endTransmission();
}

View File

@ -71,9 +71,9 @@ class MPU6886 {
public:
MPU6886(void) {};
#ifdef ESP32
void setBus(uint32_t _bus) { myWire = _bus ? Wire1 : Wire; };
void setBus(uint32_t _bus) { myWire = _bus ? &Wire1 : &Wire; };
#else
void setBus(uint32_t _bus) { myWire = Wire; };
void setBus(uint32_t _bus) { myWire = &Wire; };
#endif
int Init(void);
void getAccelAdc(int16_t* ax, int16_t* ay, int16_t* az);
@ -93,7 +93,7 @@ class MPU6886 {
// void getAhrsData(float *pitch,float *roll,float *yaw);
public:
TwoWire & myWire = Wire; // default to Wire (bus 0)
TwoWire * myWire = &Wire; // default to Wire (bus 0)
float aRes, gRes;
private:

View File

@ -19,7 +19,7 @@ be_define_native_module(energy, NULL);
#else
/* @const_object_info_begin
module tasmota (scope: global, depend: 1) {
getfreeheap, func(l_getFreeHeap)
get_free_heap, func(l_getFreeHeap)
}
@const_object_info_end */
#include "../generate/be_fixed_tasmota.h"

View File

@ -27,6 +27,8 @@ extern int l_getpower(bvm *vm);
extern int l_setlight(bvm *vm);
extern int l_setpower(bvm *vm);
extern int l_i2cenabled(bvm *vm);
// #if !BE_USE_PRECOMPILED_OBJECT
#if 1 // TODO we will do pre-compiled later
// Class definition
@ -39,27 +41,30 @@ void be_load_tasmota_ntvlib(bvm *vm)
{ "_rules", NULL },
{ "_timers", NULL },
{ "_cmd", NULL },
{ "getfreeheap", l_getFreeHeap },
{ "_drivers", NULL },
{ "get_free_heap", l_getFreeHeap },
{ "publish", l_publish },
{ "cmd", l_cmd },
{ "getoption", l_getoption },
{ "get_option", l_getoption },
{ "millis", l_millis },
{ "timereached", l_timereached },
{ "time_reached", l_timereached },
{ "yield", l_yield },
{ "delay", l_delay },
{ "scaleuint", l_scaleuint },
{ "scale_uint", l_scaleuint },
{ "respcmnd", l_respCmnd },
{ "respcmndstr", l_respCmndStr },
{ "respcmnd_done", l_respCmndDone },
{ "respcmnd_error", l_respCmndError },
{ "respcmnd_failed", l_respCmndFailed },
{ "resp_cmnd", l_respCmnd },
{ "resp_cmnd_str", l_respCmndStr },
{ "resp_cmnd_done", l_respCmndDone },
{ "resp_cmnd_error", l_respCmndError },
{ "resp_cmnd_failed", l_respCmndFailed },
{ "resolvecmnd", l_resolveCmnd },
{ "getlight", l_getlight },
{ "getpower", l_getpower },
{ "setlight", l_setlight },
{ "setpower", l_setpower },
{ "get_light", l_getlight },
{ "get_power", l_getpower },
{ "set_light", l_setlight },
{ "set_power", l_setpower },
{ "i2c_enabled", l_i2cenabled },
{ NULL, NULL }
};
@ -69,7 +74,7 @@ void be_load_tasmota_ntvlib(bvm *vm)
#else
/* @const_object_info_begin
module tasmota (scope: global, depend: 1) {
getfreeheap, func(l_getFreeHeap)
get_free_heap, func(l_getFreeHeap)
}
@const_object_info_end */
#include "../generate/be_fixed_tasmota.h"

View File

@ -20,6 +20,7 @@ extern int b_wire_scan(bvm *vm);
extern int b_wire_validwrite(bvm *vm);
extern int b_wire_validread(bvm *vm);
extern int b_wire_detect(bvm *vm);
// #if !BE_USE_PRECOMPILED_OBJECT
#if 1 // TODO we will do pre-compiled later
@ -28,24 +29,25 @@ void be_load_wirelib(bvm *vm)
static const bnfuncinfo members[] = {
{ "_bus", NULL }, // bus number
{ "init", b_wire_init },
{ "_begintransmission", b_wire_begintransmission },
{ "_endtransmission", b_wire_endtransmission },
{ "_requestfrom", b_wire_requestfrom },
{ "_begin_transmission", b_wire_begintransmission },
{ "_end_transmission", b_wire_endtransmission },
{ "_request_from", b_wire_requestfrom },
{ "_available", b_wire_available },
{ "_write", b_wire_write },
{ "_read", b_wire_read },
{ "scan", b_wire_scan },
{ "write", b_wire_validwrite },
{ "read", b_wire_validread },
{ "detect", b_wire_detect },
{ NULL, NULL }
};
be_regclass(vm, "Wire", members);
be_regclass(vm, "Wire_ntv", members);
}
#else
/* @const_object_info_begin
module tasmota (scope: global, depend: 1) {
getfreeheap, func(l_getFreeHeap)
get_free_heap, func(l_getFreeHeap)
}
@const_object_info_end */
#include "../generate/be_fixed_tasmota.h"

View File

@ -162,11 +162,27 @@
* are not required.
* The default is to use the functions in the standard library.
**/
#ifdef USE_BERRY_PSRAM
#ifdef __cplusplus
extern "C" {
#endif
extern void *berry_malloc(uint32_t size);
extern void *berry_realloc(void *ptr, size_t size);
#ifdef __cplusplus
}
#endif
#define BE_EXPLICIT_MALLOC special_malloc
#define BE_EXPLICIT_REALLOC special_realloc
#else
#define BE_EXPLICIT_MALLOC malloc
#define BE_EXPLICIT_REALLOC realloc
#endif // USE_BERRY_PSRAM
#define BE_EXPLICIT_ABORT abort
#define BE_EXPLICIT_EXIT exit
#define BE_EXPLICIT_MALLOC malloc
// #define BE_EXPLICIT_MALLOC malloc
#define BE_EXPLICIT_FREE free
#define BE_EXPLICIT_REALLOC realloc
// #define BE_EXPLICIT_REALLOC realloc
/* Macro: be_assert
* Berry debug assertion. Only enabled when BE_DEBUG is active.

View File

@ -10,11 +10,11 @@ runcolor = nil
def runcolor()
var pwr = energy.read().find('activepower',0)
print(pwr)
var red = tasmota.scaleuint(int(pwr), 0, 2500, 0, 255)
var red = tasmota.scale_uint(int(pwr), 0, 2500, 0, 255)
var green = 255 - red
var channels = [red, green, 0]
tasmota.setlight({"channels":channels, "bri":64, "power":true})
tasmota.settimer(2000, runcolor)
tasmota.set_light({"channels":channels, "bri":64, "power":true})
tasmota.set_timer(2000, runcolor)
end
#- run animation -#

View File

@ -1,211 +0,0 @@
import json import string
tasmota = module("tasmota")
def log(m) print(m) end
def save() end
#######
import string
import json
import gc
import tasmota
#// import alias
import tasmota as t
def charsinstring(s,c)
for i:0..size(s)-1
for j:0..size(c)-1
if s[i] == c[j] return i end
end
end
return -1
end
###
class Tasmota
var _op, _operators, _rules
def init()
self._operators = "=<>!|"
self._op = [
['==', /s1,s2-> str(s1) == str(s2)],
['!==',/s1,s2-> str(s1) != str(s2)],
['=', /f1,f2-> real(f1) == real(f2)],
['!=', /f1,f2-> real(f1) != real(f2)],
['>=', /f1,f2-> real(f1) >= real(f2)],
['<=', /f1,f2-> real(f1) <= real(f2)],
['>', /f1,f2-> real(f1) > real(f2)],
['<', /f1,f2-> real(f1) < real(f2)],
]
self._rules = {}
end
end
###
tasmota._eqstr=/s1,s2-> str(s1) == str(s2)
tasmota._neqstr=/s1,s2-> str(s1) != str(s2)
tasmota._eq=/f1,f2-> real(f1) == real(f2)
tasmota._neq=/f1,f2-> real(f1) != real(f2)
tasmota._gt=/f1,f2-> real(f1) > real(f2)
tasmota._lt=/f1,f2-> real(f1) < real(f2)
tasmota._ge=/f1,f2-> real(f1) >= real(f2)
tasmota._le=/f1,f2-> real(f1) <= real(f2)
tasmota._op=[
['==',tasmota._eqstr],
['!==',tasmota._neqstr],
['=',tasmota._eq],
['!=',tasmota._neq],
['>=',tasmota._ge],
['<=',tasmota._le],
['>',tasmota._gt],
['<',tasmota._lt],
]
tasmota._operators="=<>!|"
# split the item when there is an operator, returns a list of (left,op,right)
# ex: "Dimmer>50" -> ["Dimmer",tasmota_gt,"50"]
tasmota.find_op = def (item)
var pos = charsinstring(item, tasmota._operators)
if pos>=0
var op_split = string.split(item,pos)
#print(op_split)
var op_left = op_split[0]
var op_rest = op_split[1]
# iterate through operators
for op:tasmota._op
if string.find(op_rest,op[0]) == 0
var op_func = op[1]
var op_right = string.split(op_rest,size(op[0]))[1]
return [op_left,op_func,op_right]
end
end
end
return [item, nil, nil]
end
def findkeyi(m,keyi)
var keyu = string.toupper(keyi)
if classof(m) == map
for k:m.keys()
if string.toupper(k)==keyu || keyi=='?'
return k
end
end
end
end
tasmota.try_rule = def (ev, rule, f)
var rl_list = tasmota.find_op(rule)
var e=ev
var rl=string.split(rl_list[0],'#')
for it:rl
found=findkeyi(e,it)
if found == nil
return false
end
e=e[found]
end
# check if condition is true
if rl_list[1]
# did we find a function
if !rl_list[1](e,rl_list[2])
# condition is not met
return false
end
end
f(e,ev)
return true
end
tasmota_rules={}
tasmota.rule = def(pat,f) tasmota_rules[pat] = f end
tasmota.exec_rules = def (ev_json)
var ev = json.load(ev_json)
var ret = false
if ev == nil
log('BRY: ERROR, bad json: '+ev_json, 3)
end
for r:tasmota_rules.keys()
ret = tasmota.try_rule(ev,r,tasmota_rules[r]) || ret
end
return ret
end
tasmota.delay = def(ms)
tend = tasmota.millis(ms)
while !tasmota.timereached(tend)
tasmota.yield()
end
end
def load(f)
try
if f[0] != '/' f = '/' + f end
compile(f,'file')()
except .. as e
log(string.format("BRY: could not load file '%s' - %s",f,e))
end
end
#- Test
#################################################################
def log(m) print(m) end
def my_rule(e,ev) log("e1="+str(e)+" e2="+str(ev)) end
tasmota.rule("ZBRECEIVED#?#LINKQUALITY", my_rule)
tasmota.rule("ZBRECEIVED#0x1234", my_rule)
tasmota.rule("ZBRECEIVED#?#LINKQUALITY<10", my_rule)
tasmota.rule("Dimmer>50", my_rule)
tasmota.rule("Dimmer=01", my_rule)
tasmota.rule("Color==022600", my_rule)
tasmota.exec_rules('{"Color":"022600"}')
tasmota.exec_rules('{"ZbReceived":{"0x1234":{"Device":"0x1234","LinkQuality":50}}}')
tasmota.exec_rules('{"Dimmer":10}')
# tasmota.rule("DIMMER", my_rule)
# tasmota.rule("DIMMER#DATA#DATA", my_rule)
# tasmota.exec_rules('{"Dimmer":{"Data":50}}')
-#
#-
tasmota.find_op("aaa")
tasmota.find_op("aaa>50")
-#
#-
# Example of backlog equivalent
def backlog(cmd_list)
delay_backlog = tasmota.getoption(34) # in milliseconds
delay = 0
for cmd:cmd_list
tasmota.timer(delay, /-> tasmota.cmd(cmd))
delay = delay + delay_backlog
end
end
br def backlog(cmd_list) delay_backlog = tasmota.getoption(34) delay = 0 for cmd:cmd_list tasmota.timer(delay, /-> tasmota.cmd(cmd)) delay = delay + delay_backlog end end
br backlog( [ "Power 0", "Status 4", "Power 1" ] )
-#
#-
tasmota.delay = def(ms) tend = tasmota.millis(ms) log(str(tasmota.millis())) while !tasmota.timereached(tend) end log(str(tasmota.millis())) end
tasmota.delay = def(ms) a=0 tend = tasmota.millis(ms) log(str(tasmota.millis())) while !tasmota.timereached(tend) a=a+1 end log(str(tasmota.millis())) log(str(a)) end
-#

View File

@ -56,6 +56,7 @@ uint8_t hk_services;
extern void Ext_Replace_Cmd_Vars(char *srcbuf, uint32_t srcsize, char *dstbuf, uint32_t dstsize);
extern uint32_t Ext_UpdVar(char *vname, float *fvar, uint32_t mode);
extern void Ext_toLog(char *str);
#define MAX_HAP_DEFS 16
struct HAP_DESC {
@ -64,6 +65,7 @@ struct HAP_DESC {
char var2_name[12];
char var3_name[12];
char var4_name[12];
char var5_name[12];
uint8_t hap_cid;
uint8_t type;
hap_acc_t *accessory;
@ -157,8 +159,8 @@ const struct HAP_CHAR_TABLE {
{HAP_CHAR_UUID_CURRENT_RELATIVE_HUMIDITY,'f',0},
{HAP_CHAR_UUID_CURRENT_AMBIENT_LIGHT_LEVEL,'f',0},
{HAP_CHAR_UUID_BATTERY_LEVEL,'u',0},
{HAP_CHAR_UUID_STATUS_LOW_BATTERY,'b',1},
{HAP_CHAR_UUID_CHARGING_STATE,'b',2},
{HAP_CHAR_UUID_STATUS_LOW_BATTERY,'u',1},
{HAP_CHAR_UUID_CHARGING_STATE,'u',2},
{HAP_CHAR_UUID_ON,'b',0},
{HAP_CHAR_UUID_HUE,'f',1},
{HAP_CHAR_UUID_SATURATION,'f',2},
@ -282,7 +284,7 @@ void hap_update_from_vars(void) {
new_val.u = fvar;
hap_char_update_val(hc, &new_val);
}
hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_STATUS_LOW_BATTERY);
hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_CHARGING_STATE);
if (Ext_UpdVar(hap_devs[cnt].var3_name, &fvar, 0)) {
new_val.u = fvar;
hap_char_update_val(hc, &new_val);
@ -332,6 +334,13 @@ void hap_update_from_vars(void) {
new_val.u = fvar;
hap_char_update_val(hc, &new_val);
}
if (hap_devs[cnt].var5_name[0]) {
hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_COLOR_TEMPERATURE);
if (Ext_UpdVar(hap_devs[cnt].var5_name, &fvar, 0)) {
new_val.u = fvar;
hap_char_update_val(hc, &new_val);
}
}
break;
}
}
@ -454,6 +463,7 @@ uint32_t str2c(char **sp, char *vp, uint32_t len) {
} else {
if (strlen(*sp)) {
strlcpy(vp, *sp, len);
*sp = lp + strlen(*sp);
return 0;
}
}
@ -520,19 +530,16 @@ static void smart_outlet_thread_entry(void *p) {
if (str2c(&lp1, hap_devs[index].var_name, sizeof(hap_devs[index].var_name))) {
goto nextline;
}
if (hap_devs[index].hap_cid == HAP_CID_LIGHTING) {
// get 3 add vars
if (str2c(&lp1, hap_devs[index].var2_name, sizeof(hap_devs[index].var2_name))) {
goto nextline;
}
if (str2c(&lp1, hap_devs[index].var3_name, sizeof(hap_devs[index].var3_name))) {
goto nextline;
}
if (str2c(&lp1, hap_devs[index].var4_name, sizeof(hap_devs[index].var4_name))) {
goto nextline;
}
}
hap_devs[index].var2_name[0] = 0;
hap_devs[index].var3_name[0] = 0;
hap_devs[index].var4_name[0] = 0;
hap_devs[index].var5_name[0] = 0;
str2c(&lp1, hap_devs[index].var2_name, sizeof(hap_devs[index].var2_name));
str2c(&lp1, hap_devs[index].var3_name, sizeof(hap_devs[index].var3_name));
str2c(&lp1, hap_devs[index].var4_name, sizeof(hap_devs[index].var4_name));
str2c(&lp1, hap_devs[index].var5_name, sizeof(hap_devs[index].var5_name));
hap_acc_cfg_t hap_cfg;
hap_cfg.name = hap_devs[index].hap_name;
@ -557,12 +564,20 @@ static void smart_outlet_thread_entry(void *p) {
{ float fvar = 0;
Ext_UpdVar(hap_devs[index].var_name, &fvar, 0);
hap_devs[index].service = hap_serv_lightbulb_create(fvar);
Ext_UpdVar(hap_devs[index].var2_name, &fvar, 0);
ret |= hap_serv_add_char(hap_devs[index].service, hap_char_hue_create(fvar));
Ext_UpdVar(hap_devs[index].var3_name, &fvar, 0);
ret |= hap_serv_add_char(hap_devs[index].service, hap_char_saturation_create(fvar));
if (hap_devs[index].var2_name[0]) {
Ext_UpdVar(hap_devs[index].var2_name, &fvar, 0);
ret |= hap_serv_add_char(hap_devs[index].service, hap_char_hue_create(fvar));
}
if (hap_devs[index].var3_name[0]) {
Ext_UpdVar(hap_devs[index].var3_name, &fvar, 0);
ret |= hap_serv_add_char(hap_devs[index].service, hap_char_saturation_create(fvar));
}
Ext_UpdVar(hap_devs[index].var4_name, &fvar, 0);
ret |= hap_serv_add_char(hap_devs[index].service, hap_char_brightness_create(fvar));
if (hap_devs[index].var5_name[0]) {
Ext_UpdVar(hap_devs[index].var5_name, &fvar, 0);
ret |= hap_serv_add_char(hap_devs[index].service, hap_char_color_temperature_create(fvar));
}
}
break;
case HAP_CID_OUTLET:
@ -681,14 +696,14 @@ nextline:
// vTaskDelete(NULL);
while (1) {
delay(500);
// hap_update_from_vars();
hap_update_from_vars();
}
}
}
#define HK_PASSCODE "111-11-111"
int hap_loop_stop(void);
extern void Ext_toLog(char *str);
void homekit_main(char *desc, uint32_t flag ) {
if (desc) {

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -646,6 +646,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -362,7 +362,7 @@
#define D_TRANSFER_STARTED "Transfert lancé"
#define D_UPLOAD_ERR_1 "Aucun fichier sélectionné"
#define D_UPLOAD_ERR_2 "Espace insuffisant"
#define D_UPLOAD_ERR_3 "Invalid file signature"
#define D_UPLOAD_ERR_3 "Signature de fichier invalide"
#define D_UPLOAD_ERR_4 "La taille du programme à flasher est plus grande que la taille réelle de la mémoire flash"
#define D_UPLOAD_ERR_5 "Erreur de comparaison du buffer de téléchargement"
#define D_UPLOAD_ERR_6 "Téléchargement échoué. Activer WebLog 3"
@ -602,7 +602,7 @@
#define D_SENSOR_WS2812 "WS2812"
#define D_SENSOR_DFR562 "MP3 Player"
#define D_SENSOR_IRSEND "IR TX"
#define D_SENSOR_SWITCH "Inter." // Suffix "1"
#define D_SENSOR_SWITCH "Inter" // Suffix "1"
#define D_SENSOR_BUTTON "Bouton" // Suffix "1"
#define D_SENSOR_RELAY "Relais" // Suffix "1i"
#define D_SENSOR_LED "LED" // Suffix "1i"
@ -624,8 +624,8 @@
#define D_SENSOR_SPI_MOSI "SPI MOSI"
#define D_SENSOR_SPI_CLK "SPI CLK"
#define D_SENSOR_BACKLIGHT "RétroÉcl"
#define D_SENSOR_PMS5003_TX "PMS5003 Tx"
#define D_SENSOR_PMS5003_RX "PMS5003 Rx"
#define D_SENSOR_PMS5003_TX "PMS5003 TX"
#define D_SENSOR_PMS5003_RX "PMS5003 RX"
#define D_SENSOR_SDS0X1_RX "SDS0X1 RX"
#define D_SENSOR_SDS0X1_TX "SDS0X1 TX"
#define D_SENSOR_HPMA_RX "HPMA RX"
@ -634,19 +634,22 @@
#define D_SENSOR_SBR_TX "SerBr TX"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM72_TX "SDM72 TX"
#define D_SENSOR_SDM72_RX "SDM72 RX"
#define D_SENSOR_SDM120_TX "SDMx20 TX"
#define D_SENSOR_SDM120_RX "SDMx20 RX"
#define D_SENSOR_SDM630_TX "SDM630 TX"
#define D_SENSOR_SDM630_RX "SDM630 RX"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
#define D_SENSOR_WE517_TX "WE517 TX"
#define D_SENSOR_WE517_RX "WE517 RX"
#define D_SENSOR_TM1637_CLK "TM1637 CLK"
#define D_SENSOR_TM1637_DIO "TM1637 DIO"
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"
@ -657,8 +660,8 @@
#define D_SENSOR_RFRECV "RF RX"
#define D_SENSOR_TUYA_TX "Tuya TX"
#define D_SENSOR_TUYA_RX "Tuya RX"
#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr"
#define D_SENSOR_MGC3130_RESET "MGC3130 Rst"
#define D_SENSOR_MGC3130_XFER "MGC3130 XFR"
#define D_SENSOR_MGC3130_RESET "MGC3130 RST"
#define D_SENSOR_SSPI_MISO "SSPI MISO"
#define D_SENSOR_SSPI_MOSI "SSPI MOSI"
#define D_SENSOR_SSPI_SCLK "SSPI SCLK"
@ -677,9 +680,9 @@
#define D_SENSOR_HJL_CF "BL0937 CF"
#define D_SENSOR_MCP39F5_TX "MCP39F5 TX"
#define D_SENSOR_MCP39F5_RX "MCP39F5 RX"
#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst"
#define D_SENSOR_CSE7761_TX "CSE7761 Tx"
#define D_SENSOR_CSE7761_RX "CSE7761 Rx"
#define D_SENSOR_MCP39F5_RST "MCP39F5 RST"
#define D_SENSOR_CSE7761_TX "CSE7761 TX"
#define D_SENSOR_CSE7761_RX "CSE7761 RX"
#define D_SENSOR_CSE7766_TX "CSE7766 TX"
#define D_SENSOR_CSE7766_RX "CSE7766 RX"
#define D_SENSOR_PN532_TX "PN532 TX"
@ -687,8 +690,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_P9813_CLK "P9813 CLK"
#define D_SENSOR_P9813_DAT "P9813 DAT"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
@ -696,14 +699,14 @@
#define D_SENSOR_TXD "Série TX"
#define D_SENSOR_RXD "Série RX"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
#define D_SENSOR_HRE_CLOCK "HRE CLK"
#define D_SENSOR_HRE_DATA "HRE DAT"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_OLED_RESET "OLED Reset"
#define D_SENSOR_OLED_RESET "OLED RST"
#define D_SENSOR_ZIGBEE_TXD "ZigBee TX"
#define D_SENSOR_ZIGBEE_RXD "ZigBee RX"
#define D_SENSOR_ZIGBEE_RST "ZigBee Rst"
#define D_SENSOR_ZIGBEE_RST "ZigBee RST"
#define D_SENSOR_SOLAXX1_TX "SolaxX1 TX"
#define D_SENSOR_SOLAXX1_RX "SolaxX1 RX"
#define D_SENSOR_IBEACON_TX "iBeacon TX"
@ -714,36 +717,36 @@
#define D_SENSOR_A4988_STP "A4988 STP"
#define D_SENSOR_A4988_ENA "A4988 ENA"
#define D_SENSOR_A4988_MS1 "A4988 MS1"
#define D_SENSOR_OUTPUT_HI "Output Hi"
#define D_SENSOR_OUTPUT_LO "Output Lo"
#define D_SENSOR_AS608_TX "AS608 Tx"
#define D_SENSOR_AS608_RX "AS608 Rx"
#define D_SENSOR_OUTPUT_HI "Sortie Hi"
#define D_SENSOR_OUTPUT_LO "Sortie Lo"
#define D_SENSOR_AS608_TX "AS608 TX"
#define D_SENSOR_AS608_RX "AS608 RX"
#define D_SENSOR_DDS2382_TX "DDS238-2 TX"
#define D_SENSOR_DDS2382_RX "DDS238-2 RX"
#define D_SENSOR_DDSU666_TX "DDSU666 TX"
#define D_SENSOR_DDSU666_RX "DDSU666 RX"
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2135_CLK "SM2135 CLK"
#define D_SENSOR_SM2135_DAT "SM2135 DAT"
#define D_SENSOR_DEEPSLEEP "Hibernation"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_CLIENT_TX "Esclave TX"
#define D_SENSOR_CLIENT_RX "Esclave RX"
#define D_SENSOR_CLIENT_RESET "Esclave Rst"
#define D_SENSOR_CLIENT_RESET "Esclave RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
#define D_SENSOR_HM10_TX "HM10 TX"
#define D_SENSOR_LE01MR_RX "LE-01MR Rx"
#define D_SENSOR_LE01MR_TX "LE-01MR Tx"
#define D_SENSOR_BL0940_RX "BL0940 Rx"
#define D_SENSOR_LE01MR_RX "LE-01MR RX"
#define D_SENSOR_LE01MR_TX "LE-01MR TX"
#define D_SENSOR_BL0940_RX "BL0940 RX"
#define D_SENSOR_CC1101_GDO0 "CC1101 GDO0"
#define D_SENSOR_CC1101_GDO2 "CC1101 GDO2"
#define D_SENSOR_HRXL_RX "HRXL Rx"
#define D_SENSOR_DYP_RX "DYP Rx"
#define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx"
#define D_SENSOR_HRXL_RX "HRXL RX"
#define D_SENSOR_DYP_RX "DYP RX"
#define D_SENSOR_ELECTRIQ_MOODL "MOODL TX"
#define D_SENSOR_AS3935 "AS3935"
#define D_SENSOR_WINDMETER_SPEED "Anémomètre"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_RX "TInfo RX"
#define D_SENSOR_TELEINFO_ENABLE "TInfo En"
#define D_SENSOR_LMT01_PULSE "LMT01 Impulsion"
#define D_SENSOR_ADC_INPUT "ADC Entrée"
@ -769,14 +772,14 @@
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
#define D_SENSOR_TCP_TXD "TCP TX"
#define D_SENSOR_TCP_RXD "TCP RX"
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx"
#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC TX"
#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC RX"
#define D_SENSOR_PROJECTOR_CTRL_TX "DLP TX"
#define D_SENSOR_PROJECTOR_CTRL_RX "DLP RX"
#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0"
#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset"
#define D_SENSOR_RC522_RST "RC522 Rst"
@ -799,8 +802,8 @@
#define D_SENSOR_SDCARD_CS "CarteSD CS"
#define D_SENSOR_WIEGAND_D0 "Wiegand D0"
#define D_SENSOR_WIEGAND_D1 "Wiegand D1"
#define D_SENSOR_NEOPOOL_TX "NeoPool Tx"
#define D_SENSOR_NEOPOOL_RX "NeoPool Rx"
#define D_SENSOR_NEOPOOL_TX "NeoPool TX"
#define D_SENSOR_NEOPOOL_RX "NeoPool RX"
#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT"
#define D_NEW_ADDRESS "Setting address to"
#define D_OUT_OF_RANGE "Out of Range"
@ -808,6 +811,9 @@
#define D_SENSOR_TFMINIPLUS_TX "TFmini+ TX"
#define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX"
#define D_NEW_ADDRESS "Positionner l'adresse à"
#define D_OUT_OF_RANGE "Hors limites"
#define D_SENSOR_DETECTED "détecté"
// Units
#define D_UNIT_AMPERE "A"
@ -855,8 +861,8 @@
#define D_UNIT_WATTHOUR "Wh"
#define D_UNIT_WATT_METER_QUADRAT "W/m²"
//SDM220, SDM120, SDM72, LE01MR
#define D_EXPORT_POWER "Export Power"
#define D_IMPORT_POWER "Import Power"
#define D_EXPORT_POWER "Puissance fournie"
#define D_IMPORT_POWER "Puissance consommée"
#define D_PHASE_ANGLE "Angle de phase"
#define D_IMPORT_ACTIVE "Énergie act conso"
#define D_EXPORT_ACTIVE "Énergie act fournie"
@ -938,7 +944,7 @@
#define D_SENSOR_BOILER_OT_TX "OpenTherm TX"
// xnrg_15_teleinfo Denky (Teleinfo)
#define D_CONTRACT "Type contrat"
#define D_CONTRACT "Type de contrat"
#define D_POWER_LOAD "Charge actuelle"
#define D_CURRENT_TARIFF "Tarif en cours"
#define D_TARIFF "Tarif"
@ -964,7 +970,7 @@
#define D_FP_FEATUREFAIL "Empreinte trop petite" // 0x07 Failed to generate character file due to the lack of character point or small fingerprint image
#define D_FP_NOMATCH "Le doigt ne correspond pas" // 0x08 Finger doesn't match
#define D_FP_NOTFOUND "Pas de doigt correspondant" // 0x09 Failed to find matching finger
#define D_FP_ENROLLMISMATCH "Echec de la comparaison" // 0x0A Failed to combine the character files
#define D_FP_ENROLLMISMATCH "Échec de la comparaison" // 0x0A Failed to combine the character files
#define D_FP_BADLOCATION "Erreur d'indexation" // 0x0B Addressed PageID is beyond the finger library
#define D_FP_DBRANGEFAIL "Modèle invalide" // 0x0C Error when reading template from library or invalid template
#define D_FP_UPLOADFEATUREFAIL "Erreur de transfert" // 0x0D Error when uploading template
@ -993,43 +999,43 @@
#define D_NEOPOOL_MACH_GENERIC "Generic"
#define D_NEOPOOL_MACH_BAYROL "Bayrol"
#define D_NEOPOOL_MACH_HAY "Hay"
#define D_NEOPOOL_FILTRATION_MANUAL "Manual" // Filtration modes
#define D_NEOPOOL_FILTRATION_MANUAL "Manuel" // Filtration modes
#define D_NEOPOOL_FILTRATION_AUTO "Auto"
#define D_NEOPOOL_FILTRATION_HEATING "Heating"
#define D_NEOPOOL_FILTRATION_SMART "Smart"
#define D_NEOPOOL_FILTRATION_HEATING "Chauffage"
#define D_NEOPOOL_FILTRATION_SMART "Malin"
#define D_NEOPOOL_FILTRATION_INTELLIGENT "Intelligent"
#define D_NEOPOOL_FILTRATION_BACKWASH "Backwash"
#define D_NEOPOOL_FILTRATION_BACKWASH "Rétro-lavage"
#define D_NEOPOOL_FILTRATION_NONE "" // Filtration speed level
#define D_NEOPOOL_FILTRATION_SLOW "slow"
#define D_NEOPOOL_FILTRATION_MEDIUM "medium"
#define D_NEOPOOL_FILTRATION_FAST "fast"
#define D_NEOPOOL_FILTRATION_SLOW "lent"
#define D_NEOPOOL_FILTRATION_MEDIUM "moyen"
#define D_NEOPOOL_FILTRATION_FAST "rapide"
#define D_NEOPOOL_TYPE "Type" // Sensor & relais names
#define D_NEOPOOL_REDOX "Redox"
#define D_NEOPOOL_CHLORINE "Chlorine"
#define D_NEOPOOL_CONDUCTIVITY "Conductivity"
#define D_NEOPOOL_IONIZATION "Ionization"
#define D_NEOPOOL_HYDROLYSIS "Hydrolysis"
#define D_NEOPOOL_RELAY "Relay"
#define D_NEOPOOL_CHLORINE "Chlore"
#define D_NEOPOOL_CONDUCTIVITY "Conductivité"
#define D_NEOPOOL_IONIZATION "Ionisation"
#define D_NEOPOOL_HYDROLYSIS "Hydrolyse"
#define D_NEOPOOL_RELAY "Relais"
#define D_NEOPOOL_RELAY_FILTRATION "Filtration"
#define D_NEOPOOL_RELAY_LIGHT "Light"
#define D_NEOPOOL_RELAY_PH_ACID "Acid pump"
#define D_NEOPOOL_RELAY_PH_BASE "Base pump"
#define D_NEOPOOL_RELAY_RX "Redox level"
#define D_NEOPOOL_RELAY_CL "Chlorine pump"
#define D_NEOPOOL_RELAY_CD "Brine pump"
#define D_NEOPOOL_TIME "Time"
#define D_NEOPOOL_RELAY_LIGHT "Lumière"
#define D_NEOPOOL_RELAY_PH_ACID "Pompe acide"
#define D_NEOPOOL_RELAY_PH_BASE "Pompe base"
#define D_NEOPOOL_RELAY_RX "Pompe RedOx"
#define D_NEOPOOL_RELAY_CL "Pompe Chlore"
#define D_NEOPOOL_RELAY_CD "Pompe Brome"
#define D_NEOPOOL_TIME "Durée"
#define D_NEOPOOL_FILT_MODE "Filtration"
#define D_NEOPOOL_POLARIZATION "Pol" // Sensor status
#define D_NEOPOOL_PR_OFF "PrOff"
#define D_NEOPOOL_SETPOINT_OK "Ok"
#define D_NEOPOOL_COVER "Cover"
#define D_NEOPOOL_SHOCK "Shock"
#define D_NEOPOOL_SETPOINT_OK "OK"
#define D_NEOPOOL_COVER "Couverture"
#define D_NEOPOOL_SHOCK "Choc chlore"
#define D_NEOPOOL_ALARM "! "
#define D_NEOPOOL_LOW "Low"
#define D_NEOPOOL_LOW "Bas"
#define D_NEOPOOL_FLOW1 "FL1"
#define D_NEOPOOL_FLOW2 "FL2"
#define D_NEOPOOL_PH_HIGH "too high" // ph Alarms
#define D_NEOPOOL_PH_LOW "too low"
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded"
#define D_NEOPOOL_PH_HIGH "Trop haut" // ph Alarms
#define D_NEOPOOL_PH_LOW "Trop bas"
#define D_NEOPOOL_PUMP_TIME_EXCEEDED "durée pompage expirée"
#endif // _LANGUAGE_FR_FR_H_

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 - CLK"
#define D_SENSOR_TM1638_DIO "TM1638 - DIO"
#define D_SENSOR_TM1638_STB "TM1638 - STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 - DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 - CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 - CLK"
#define D_SENSOR_HX711_SCK "HX711 - SCK"
#define D_SENSOR_HX711_DAT "HX711 - DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -647,6 +647,9 @@
#define D_SENSOR_TM1638_CLK "TM1638 CLK"
#define D_SENSOR_TM1638_DIO "TM1638 DIO"
#define D_SENSOR_TM1638_STB "TM1638 STB"
#define D_SENSOR_MAX7219_DIN "MAX7219 DIN"
#define D_SENSOR_MAX7219_CS "MAX7219 CS"
#define D_SENSOR_MAX7219_CLK "MAX7219 CLK"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
#define D_SENSOR_FTC532 "FTC532"

View File

@ -463,6 +463,11 @@
// #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code)
// -- Berry Scripting Language - ESP32 only ----------------------------
// #define USE_BERRY // Enable Berry scripting language
#define USE_BERRY_PSRAM // Allocate Berry memory in PSRAM if PSRAM is connected - this might be slightly slower but leaves main memory intact
// -- Optional modules ----------------------------
#define ROTARY_V1 // Add support for Rotary Encoder as used in MI Desk Lamp (+0k8 code)
#define ROTARY_MAX_STEPS 10 // Rotary step boundary

View File

@ -149,7 +149,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t mqtt_state_retain : 1; // bit 7 (v9.3.0.1) - CMND_STATERETAIN
uint32_t mqtt_info_retain : 1; // bit 8 (v9.3.0.1) - CMND_INFORETAIN
uint32_t wiegand_hex_output : 1; // bit 9 (v9.3.1.1) - SetOption123 - (Wiegand) switch tag number output to hex format (1)
uint32_t wiegand_keypad_to_tag : 1; // bit 10 (v9.3.1.1) - SetOption124 - (Wiegand) send key pad stroke as single char (0) or one tag (ending char #) (1)
uint32_t wiegand_keypad_to_tag : 1; // bit 10 (v9.3.1.1) - SetOption124 - (Wiegand) send key pad stroke as single char (0) or one tag (ending char #) (1)
uint32_t zigbee_hide_bridge_topic : 1; // bit 11 (v9.3.1.1) - SetOption125 - (Zigbee) Hide bridge topic from zigbee topic (use with SetOption89) (1)
uint32_t spare12 : 1; // bit 12
uint32_t spare13 : 1; // bit 13
@ -330,12 +330,12 @@ typedef struct {
typedef union {
uint8_t data;
struct {
uint8_t ilimode : 3;
uint8_t Invert : 1;
uint8_t spare2 : 1;
uint8_t spare3 : 1;
uint8_t type : 3;
uint8_t invert : 1;
uint8_t spare4 : 1;
uint8_t spare5 : 1;
uint8_t spare6 : 1;
uint8_t spare7 : 1;
};
} DisplayOptions;

View File

@ -74,6 +74,10 @@ void *special_malloc(uint32_t size) {
return malloc(size);
}
void *special_realloc(void *ptr, size_t size) {
return realloc(ptr, size);
}
#endif
/*********************************************************************************************\
@ -461,6 +465,13 @@ void *special_malloc(uint32_t size) {
return malloc(size);
}
}
void *special_realloc(void *ptr, size_t size) {
if (psramFound()) {
return heap_caps_realloc(ptr, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
} else {
return realloc(ptr, size);
}
}
#endif // ESP32

View File

@ -556,18 +556,22 @@ void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
((POWER_ON == state) || ((POWER_TOGGLE == state) && !(TasmotaGlobal.power & mask)))
) {
interlock_mutex = true; // Clear all but masked relay in interlock group if new set requested
bool perform_interlock_delay = false;
for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) {
if (Settings.interlock[i] & mask) { // Find interlock group
for (uint32_t j = 0; j < TasmotaGlobal.devices_present; j++) {
power_t imask = 1 << j;
if ((Settings.interlock[i] & imask) && (TasmotaGlobal.power & imask) && (mask != imask)) {
ExecuteCommandPower(j +1, POWER_OFF, SRC_IGNORE);
delay(50); // Add some delay to make sure never have more than one relay on
perform_interlock_delay = true;
}
}
break; // An interlocked relay is only present in one group so quit
}
}
if (perform_interlock_delay) {
delay(50); // Add some delay to make sure never have more than one relay on
}
interlock_mutex = false;
}

View File

@ -307,6 +307,7 @@
#define USE_DISPLAY // Add Display Support (+2k code)
#define USE_DISPLAY_TM1637 // [DisplayModel 15] Enable TM1637 module
#define USE_DISPLAY_MAX7219 // [DisplayModel 16] Enable MAX7219 7-segment module
#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram)
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0

View File

@ -55,6 +55,10 @@
#define USE_UFILESYS
#define USE_SDCARD
#define GUI_TRASH_FILE
#define USE_BERRY // Enable Berry scripting language
#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_ADC
#define USE_SPI
#define USE_DISPLAY // Add SPI Display Support (+2k code)
@ -84,6 +88,10 @@
#define USE_UFILESYS
#define USE_SDCARD
#define GUI_TRASH_FILE
#define USE_BERRY // Enable Berry scripting language
#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_I2C
#define USE_BMA423
#define USE_MPU6886

View File

@ -156,6 +156,7 @@ enum UserSelectablePins {
GPIO_CSE7761_TX, GPIO_CSE7761_RX, // CSE7761 Serial interface (Dual R3)
GPIO_VL53L0X_XSHUT1, // VL53L0X_XSHUT (the max number of sensors is VL53L0X_MAX_SENSORS)- Used when connecting multiple VL53L0X
GPIO_TFMINIPLUS_TX, GPIO_TFMINIPLUS_RX, // TFmini Plus ToF sensor
GPIO_MAX7219CLK, GPIO_MAX7219DIN, GPIO_MAX7219CS, // MAX7219 interface
GPIO_SENSOR_END };
enum ProgramSelectablePins {
@ -332,9 +333,13 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_CSE7761_TX "|" D_SENSOR_CSE7761_RX "|"
<<<<<<< HEAD
D_SENSOR_VL53L0X_XSHUT "|"
<<<<<<< HEAD
=======
>>>>>>> TFmini+
D_SENSOR_TFMINIPLUS_TX "|" D_SENSOR_TFMINIPLUS_RX "|"
=======
D_SENSOR_MAX7219_CLK "|" D_SENSOR_MAX7219_DIN "|" D_SENSOR_MAX7219_CS "|"
>>>>>>> upstream/development
;
const char kSensorNamesFixed[] PROGMEM =
@ -798,8 +803,13 @@ const uint16_t kGpioNiceList[] PROGMEM = {
#endif
#ifdef USE_VL53L0X
AGPIO(GPIO_VL53L0X_XSHUT1) + VL53L0X_MAX_SENSORS, // When using multiple VL53L0X.
#endif
#endif
#ifdef USE_DISPLAY_MAX7219
AGPIO(GPIO_MAX7219CLK),
AGPIO(GPIO_MAX7219DIN),
AGPIO(GPIO_MAX7219CS),
#endif // USE_DISPLAY_MAX7219
/*-------------------------------------------------------------------------------------------*\
* ESP32 specifics
\*-------------------------------------------------------------------------------------------*/

View File

@ -214,12 +214,15 @@ const char HTTP_HEAD_STYLE3[] PROGMEM =
"<div style='text-align:center;color:#%06x;'><h3>" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "</h3></div>" // COLOR_TEXT_WARNING
#endif
"<div style='text-align:center;color:#%06x;'><noscript>" D_NOSCRIPT "<br></noscript>" // COLOR_TITLE
/*
#ifdef LANGUAGE_MODULE_NAME
"<h3>" D_MODULE " %s</h3>"
#else
"<h3>%s " D_MODULE "</h3>"
#endif
"<h2>%s</h2>";
*/
"<h3>%s</h3>" // Module name
"<h2>%s</h2>"; // Device name
const char HTTP_MSG_SLIDER_GRADIENT[] PROGMEM =
"<div id='%s' class='r' style='background-image:linear-gradient(to right,%s,%s);'>"

View File

@ -36,15 +36,16 @@
#define D_CMND_POWERCAL "PowerCal"
#define D_CMND_VOLTAGECAL "VoltageCal"
#define D_CMND_CURRENTCAL "CurrentCal"
#define D_CMND_FREQUENCYCAL "FrequencyCal"
#define D_CMND_TARIFF "Tariff"
#define D_CMND_MODULEADDRESS "ModuleAddress"
enum EnergyCommands {
CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL,
CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL, CMND_FREQUENCYCAL,
CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_MODULEADDRESS };
const char kEnergyCommands[] PROGMEM = "|" // No prefix
D_CMND_POWERCAL "|" D_CMND_VOLTAGECAL "|" D_CMND_CURRENTCAL "|"
D_CMND_POWERCAL "|" D_CMND_VOLTAGECAL "|" D_CMND_CURRENTCAL "|" D_CMND_FREQUENCYCAL "|"
D_CMND_POWERSET "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" D_CMND_MODULEADDRESS "|"
#ifdef USE_ENERGY_MARGIN_DETECTION
D_CMND_POWERDELTA "|" D_CMND_POWERLOW "|" D_CMND_POWERHIGH "|" D_CMND_VOLTAGELOW "|" D_CMND_VOLTAGEHIGH "|" D_CMND_CURRENTLOW "|" D_CMND_CURRENTHIGH "|"
@ -57,7 +58,7 @@ const char kEnergyCommands[] PROGMEM = "|" // No prefix
D_CMND_ENERGYRESET "|" D_CMND_TARIFF ;
void (* const EnergyCommand[])(void) PROGMEM = {
&CmndPowerCal, &CmndVoltageCal, &CmndCurrentCal,
&CmndPowerCal, &CmndVoltageCal, &CmndCurrentCal, &CmndFrequencyCal,
&CmndPowerSet, &CmndVoltageSet, &CmndCurrentSet, &CmndFrequencySet, &CmndModuleAddress,
#ifdef USE_ENERGY_MARGIN_DETECTION
&CmndPowerDelta, &CmndPowerLow, &CmndPowerHigh, &CmndVoltageLow, &CmndVoltageHigh, &CmndCurrentLow, &CmndCurrentHigh,
@ -547,14 +548,12 @@ void EnergyEverySecond(void)
* Commands
\*********************************************************************************************/
void EnergyCommandCalResponse(uint32_t nvalue)
{
void EnergyCommandCalResponse(uint32_t nvalue) {
snprintf_P(XdrvMailbox.command, CMDSZ, PSTR("%sCal"), XdrvMailbox.command);
ResponseCmndNumber(nvalue);
}
void CmndEnergyReset(void)
{
void CmndEnergyReset(void) {
uint32_t values[2] = { 0 };
uint32_t params = ParseParameters(2, values);
values[0] *= 100;
@ -641,8 +640,7 @@ void CmndEnergyReset(void)
Settings.flag2.energy_resolution, &return2_kWhtotal);
}
void CmndTariff(void)
{
void CmndTariff(void) {
// Tariff1 22:00,23:00 - Tariff1 start hour for Standard Time and Daylight Savings Time
// Tariff2 6:00,7:00 - Tariff2 start hour for Standard Time and Daylight Savings Time
// Tariffx 1320, 1380 = minutes and also 22:00, 23:00
@ -686,11 +684,9 @@ void CmndTariff(void)
GetStateText(Settings.flag3.energy_weekend)); // CMND_TARIFF
}
void CmndPowerCal(void)
{
void CmndPowerCal(void) {
Energy.command_code = CMND_POWERCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
// if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) {
if (XdrvMailbox.payload > 999) {
Settings.energy_power_calibration = XdrvMailbox.payload;
}
@ -698,11 +694,9 @@ void CmndPowerCal(void)
}
}
void CmndVoltageCal(void)
{
void CmndVoltageCal(void) {
Energy.command_code = CMND_VOLTAGECAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
// if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) {
if (XdrvMailbox.payload > 999) {
Settings.energy_voltage_calibration = XdrvMailbox.payload;
}
@ -710,11 +704,9 @@ void CmndVoltageCal(void)
}
}
void CmndCurrentCal(void)
{
void CmndCurrentCal(void) {
Energy.command_code = CMND_CURRENTCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
// if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) {
if (XdrvMailbox.payload > 999) {
Settings.energy_current_calibration = XdrvMailbox.payload;
}
@ -722,40 +714,45 @@ void CmndCurrentCal(void)
}
}
void CmndPowerSet(void)
{
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);
}
}
void CmndPowerSet(void) {
Energy.command_code = CMND_POWERSET;
if (XnrgCall(FUNC_COMMAND)) { // Watt
EnergyCommandCalResponse(Settings.energy_power_calibration);
}
}
void CmndVoltageSet(void)
{
void CmndVoltageSet(void) {
Energy.command_code = CMND_VOLTAGESET;
if (XnrgCall(FUNC_COMMAND)) { // Volt
EnergyCommandCalResponse(Settings.energy_voltage_calibration);
}
}
void CmndCurrentSet(void)
{
void CmndCurrentSet(void) {
Energy.command_code = CMND_CURRENTSET;
if (XnrgCall(FUNC_COMMAND)) { // milliAmpere
EnergyCommandCalResponse(Settings.energy_current_calibration);
}
}
void CmndFrequencySet(void)
{
void CmndFrequencySet(void) {
Energy.command_code = CMND_FREQUENCYSET;
if (XnrgCall(FUNC_COMMAND)) { // Hz
EnergyCommandCalResponse(Settings.energy_frequency_calibration);
}
}
void CmndModuleAddress(void)
{
void CmndModuleAddress(void) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4) && (1 == Energy.phase_count)) {
Energy.command_code = CMND_MODULEADDRESS;
if (XnrgCall(FUNC_COMMAND)) { // Module address
@ -765,8 +762,7 @@ void CmndModuleAddress(void)
}
#ifdef USE_ENERGY_MARGIN_DETECTION
void CmndPowerDelta(void)
{
void CmndPowerDelta(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 3)) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32000)) {
Settings.energy_power_delta[XdrvMailbox.index -1] = XdrvMailbox.payload;
@ -775,48 +771,42 @@ void CmndPowerDelta(void)
}
}
void CmndPowerLow(void)
{
void CmndPowerLow(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.energy_min_power = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_min_power);
}
void CmndPowerHigh(void)
{
void CmndPowerHigh(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.energy_max_power = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_max_power);
}
void CmndVoltageLow(void)
{
void CmndVoltageLow(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 501)) {
Settings.energy_min_voltage = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_min_voltage);
}
void CmndVoltageHigh(void)
{
void CmndVoltageHigh(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 501)) {
Settings.energy_max_voltage = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_max_voltage);
}
void CmndCurrentLow(void)
{
void CmndCurrentLow(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 16001)) {
Settings.energy_min_current = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_min_current);
}
void CmndCurrentHigh(void)
{
void CmndCurrentHigh(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 16001)) {
Settings.energy_max_current = XdrvMailbox.payload;
}
@ -824,56 +814,49 @@ void CmndCurrentHigh(void)
}
#ifdef USE_ENERGY_POWER_LIMIT
void CmndMaxPower(void)
{
void CmndMaxPower(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.energy_max_power_limit = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_max_power_limit);
}
void CmndMaxPowerHold(void)
{
void CmndMaxPowerHold(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.energy_max_power_limit_hold = (1 == XdrvMailbox.payload) ? MAX_POWER_HOLD : XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_max_power_limit_hold);
}
void CmndMaxPowerWindow(void)
{
void CmndMaxPowerWindow(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.energy_max_power_limit_window = (1 == XdrvMailbox.payload) ? MAX_POWER_WINDOW : XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_max_power_limit_window);
}
void CmndSafePower(void)
{
void CmndSafePower(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.energy_max_power_safe_limit = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_max_power_safe_limit);
}
void CmndSafePowerHold(void)
{
void CmndSafePowerHold(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.energy_max_power_safe_limit_hold = (1 == XdrvMailbox.payload) ? SAFE_POWER_HOLD : XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_max_power_safe_limit_hold);
}
void CmndSafePowerWindow(void)
{
void CmndSafePowerWindow(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 1440)) {
Settings.energy_max_power_safe_limit_window = (1 == XdrvMailbox.payload) ? SAFE_POWER_WINDOW : XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.energy_max_power_safe_limit_window);
}
void CmndMaxEnergy(void)
{
void CmndMaxEnergy(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.energy_max_energy = XdrvMailbox.payload;
Energy.max_energy_state = 3;
@ -881,8 +864,7 @@ void CmndMaxEnergy(void)
ResponseCmndNumber(Settings.energy_max_energy);
}
void CmndMaxEnergyStart(void)
{
void CmndMaxEnergyStart(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 24)) {
Settings.energy_max_energy_start = XdrvMailbox.payload;
}

View File

@ -176,7 +176,10 @@ void IrSendInit(void)
\*********************************************************************************************/
const bool IR_RCV_SAVE_BUFFER = false; // false = do not use buffer, true = use buffer for decoding
const uint32_t IR_TIME_AVOID_DUPLICATE = 500; // Milliseconds
#ifndef IR_TIME_AVOID_DUPLICATE
#define IR_TIME_AVOID_DUPLICATE 50 // Milliseconds
#endif // IR_TIME_AVOID_DUPLICATE
#include <IRrecv.h>

View File

@ -167,7 +167,10 @@ uint64_t reverseBitsInBytes64(uint64_t b) {
\*********************************************************************************************/
const bool IR_FULL_RCV_SAVE_BUFFER = false; // false = do not use buffer, true = use buffer for decoding
const uint32_t IR_TIME_AVOID_DUPLICATE = 50; // Milliseconds
#ifndef IR_TIME_AVOID_DUPLICATE
#define IR_TIME_AVOID_DUPLICATE 50 // Milliseconds
#endif // IR_TIME_AVOID_DUPLICATE
// Below is from IRrecvDumpV2.ino
// As this program is a special purpose capture/decoder, let us use a larger

View File

@ -67,8 +67,8 @@ keywords if then else endif, or, and are better readable for beginners (others m
#define MAX_SARRAY_NUM 32
//uint32_t EncodeLightId(uint8_t relay_id);
//uint32_t DecodeLightId(uint32_t hue_id);
uint32_t EncodeLightId(uint8_t relay_id);
uint32_t DecodeLightId(uint32_t hue_id);
#define SPECIAL_EEPMODE_SIZE 6200
@ -776,7 +776,7 @@ char *script;
script_mem_size += 16;
uint8_t *script_mem;
script_mem = (uint8_t*)calloc(script_mem_size, 1);
script_mem = (uint8_t*)special_malloc(script_mem_size);
if (!script_mem) {
if (imemptr) free(imemptr);
return -4;
@ -2175,7 +2175,7 @@ chknext:
if (ef) {
uint16_t fsiz = ef.size();
if (fsiz<2048) {
char *script = (char*)calloc(fsiz + 16, 1);
char *script = (char*)special_malloc(fsiz + 16);
if (script) {
ef.read((uint8_t*)script,fsiz);
execute_script(script);
@ -3643,15 +3643,22 @@ int32_t UpdVar(char *vname, float *fvar, uint32_t mode) {
if (vtype == NUM_RES || (vtype & STYPE) == 0) {
if (mode) {
// set var
//AddLog(LOG_LEVEL_DEBUG, PSTR("write from homekit: %s - %d"), vname, (uint32_t)res);
index = glob_script_mem.type[ind.index].index;
glob_script_mem.fvars[index] = res;
glob_script_mem.type[ind.index].bits.changed = 1;
#ifdef USE_SCRIPT_GLOBVARS
if (glob_script_mem.type[ind.index].bits.global) {
script_udp_sendvar(vname, &res, 0);
}
#endif //USE_SCRIPT_GLOBVARS
return 0;
} else {
// get var
//index = glob_script_mem.type[ind.index].index;
int32_t ret = glob_script_mem.type[ind.index].bits.hchanged;
glob_script_mem.type[ind.index].bits.hchanged = 0;
//AddLog(LOG_LEVEL_DEBUG, PSTR("read from homekit: %s - %d - %d"), vname, (uint32_t)*fvar, ret);
return ret;
}
} else {
@ -6357,7 +6364,8 @@ void ScriptGetSDCard(void) {
if (!HttpCheckPriviledgedAccess()) { return; }
String stmp = Webserver->uri();
char *cp = strstr_P(stmp.c_str(), PSTR("/sdc/"));
char *cp = strstr_P(stmp.c_str(), PSTR("/ufs/"));
// if (cp) Serial.printf(">>>%s\n",cp);
if (cp) {
#ifdef ESP32
@ -6365,13 +6373,15 @@ void ScriptGetSDCard(void) {
#else
cp += 5;
#endif
if (strstr_P(cp, PSTR("scrdmp.bmp"))) {
SendFile(cp);
return;
} else {
if (ufsp->exists(cp)) {
if (ufsp) {
if (strstr_P(cp, PSTR("scrdmp.bmp"))) {
SendFile(cp);
return;
} else {
if (ufsp->exists(cp)) {
SendFile(cp);
return;
}
}
}
}
@ -6392,7 +6402,6 @@ char buff[512];
#ifdef USE_DISPLAY_DUMP
char *sbmp = strstr_P(fname, PSTR("scrdmp.bmp"));
if (sbmp) {
mime = "image/bmp";
sflg = 1;
}
#endif // USE_DISPLAY_DUMP
@ -6419,7 +6428,7 @@ char buff[512];
#define infoHeaderSize 40
if (buffer) {
uint8_t *bp = buffer;
uint8_t *lbuf = (uint8_t*)calloc(Settings.display_width + 2, 3);
uint8_t *lbuf = (uint8_t*)special_malloc(Settings.display_width + 2);
uint8_t *lbp;
uint8_t fileHeader[fileHeaderSize];
createBitmapFileHeader(Settings.display_height , Settings.display_width , fileHeader);
@ -7679,7 +7688,7 @@ bool Xdrv10(uint8_t function)
// we have a file system
AddLog(LOG_LEVEL_INFO,PSTR("UFILESYSTEM OK!"));
char *script;
script = (char*)calloc(UFSYS_SIZE + 4, 1);
script = (char*)special_malloc(UFSYS_SIZE + 4);
if (!script) break;
glob_script_mem.script_ram = script;
glob_script_mem.script_size = UFSYS_SIZE;
@ -7850,6 +7859,10 @@ bool Xdrv10(uint8_t function)
Webserver->on("/sfd", ScriptFullWebpage);
}
#endif // SCRIPT_FULL_WEBPAGE
#ifdef USE_UFILESYS
Webserver->onNotFound(ScriptGetSDCard);
#endif // USE_UFILESYS
}
break;
#endif // USE_SCRIPT_WEB_DISPLAY
@ -7858,7 +7871,6 @@ bool Xdrv10(uint8_t function)
Webserver->on("/ta",HTTP_POST, HandleScriptTextareaConfiguration);
Webserver->on("/exs", HTTP_POST,[]() { Webserver->sendHeader("Location","/exs");Webserver->send(303);}, script_upload_start);
Webserver->on("/exs", HTTP_GET, ScriptExecuteUploadSuccess);
break;
#endif // USE_WEBSERVER
case FUNC_SAVE_BEFORE_RESTART:
if (bitRead(Settings.rule_enabled, 0)) {

View File

@ -54,22 +54,24 @@ const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log
#define D_CMND_DISP_DIMMER "Dimmer"
#define D_CMND_DISP_MODE "Mode"
#define D_CMND_DISP_MODEL "Model"
#define D_CMND_DISP_TYPE "Type"
#define D_CMND_DISP_REFRESH "Refresh"
#define D_CMND_DISP_ROWS "Rows"
#define D_CMND_DISP_SIZE "Size"
#define D_CMND_DISP_FONT "Font"
#define D_CMND_DISP_ROTATE "Rotate"
#define D_CMND_DISP_TEXT "Text"
#define D_CMND_DISP_INVERT "Invert"
#define D_CMND_DISP_WIDTH "Width"
#define D_CMND_DISP_HEIGHT "Height"
#define D_CMND_DISP_BLINKRATE "Blinkrate"
#define D_CMND_DISP_BATCH "Batch"
#define D_CMND_DISP_TEXT "Text"
#define D_CMND_DISP_CLEAR "Clear"
#define D_CMND_DISP_NUMBER "Number"
#define D_CMND_DISP_FLOAT "Float"
#define D_CMND_DISP_NUMBERNC "NumberNC" // NC - "No Clear"
#define D_CMND_DISP_FLOATNC "FloatNC" // NC - "No Clear"
#define D_CMND_DISP_BRIGHTNESS "Brightness"
#define D_CMND_DISP_NUMBERNC "NumberNC" // NC - "No Clear"
#define D_CMND_DISP_FLOATNC "FloatNC" // NC - "No Clear"
#define D_CMND_DISP_RAW "Raw"
#define D_CMND_DISP_LEVEL "Level"
#define D_CMND_DISP_SEVENSEG_TEXT "SevensegText"
@ -78,9 +80,6 @@ const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log
#define D_CMND_DISP_CLOCK "Clock"
#define D_CMND_DISP_TEXTNC "TextNC" // NC - "No Clear"
#define D_CMND_DISP_SCROLLTEXT "ScrollText"
#define D_CMND_DISP_ILIMODE "ILIMode"
#define D_CMND_DISP_ILIINVERT "Invert"
enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_EVERY_50_MSECOND, FUNC_DISPLAY_EVERY_SECOND,
FUNC_DISPLAY_MODEL, FUNC_DISPLAY_MODE, FUNC_DISPLAY_POWER,
@ -101,31 +100,71 @@ enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_E
enum DisplayInitModes { DISPLAY_INIT_MODE, DISPLAY_INIT_PARTIAL, DISPLAY_INIT_FULL };
const char kDisplayCommands[] PROGMEM = D_PRFX_DISPLAY "|" // Prefix
"|" D_CMND_DISP_MODEL "|" D_CMND_DISP_WIDTH "|" D_CMND_DISP_HEIGHT "|" D_CMND_DISP_MODE "|" D_CMND_DISP_REFRESH "|"
D_CMND_DISP_DIMMER "|" D_CMND_DISP_COLS "|" D_CMND_DISP_ROWS "|" D_CMND_DISP_SIZE "|" D_CMND_DISP_FONT "|"
D_CMND_DISP_ROTATE "|" D_CMND_DISP_TEXT "|" D_CMND_DISP_ADDRESS "|" D_CMND_DISP_BLINKRATE "|"
"|" D_CMND_DISP_MODEL "|" D_CMND_DISP_TYPE "|" D_CMND_DISP_WIDTH "|" D_CMND_DISP_HEIGHT "|" D_CMND_DISP_MODE "|"
D_CMND_DISP_INVERT "|" D_CMND_DISP_REFRESH "|" D_CMND_DISP_DIMMER "|" D_CMND_DISP_COLS "|" D_CMND_DISP_ROWS "|"
D_CMND_DISP_SIZE "|" D_CMND_DISP_FONT "|" D_CMND_DISP_ROTATE "|" D_CMND_DISP_TEXT "|" D_CMND_DISP_ADDRESS "|" D_CMND_DISP_BLINKRATE "|"
#ifdef USE_UFILESYS
D_CMND_DISP_BATCH "|"
#endif
D_CMND_DISP_CLEAR "|" D_CMND_DISP_NUMBER "|" D_CMND_DISP_FLOAT "|" D_CMND_DISP_NUMBERNC "|" D_CMND_DISP_FLOATNC "|"
D_CMND_DISP_RAW "|" D_CMND_DISP_LEVEL "|" D_CMND_DISP_SEVENSEG_TEXT "|" D_CMND_DISP_SEVENSEG_TEXTNC "|"
D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|"
D_CMND_DISP_SCROLLTEXT "|" D_CMND_DISP_ILIMODE "|" D_CMND_DISP_ILIINVERT
D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" D_CMND_DISP_SCROLLTEXT
;
void (* const DisplayCommand[])(void) PROGMEM = {
&CmndDisplay, &CmndDisplayModel, &CmndDisplayWidth, &CmndDisplayHeight, &CmndDisplayMode, &CmndDisplayRefresh,
&CmndDisplayDimmer, &CmndDisplayColumns, &CmndDisplayRows, &CmndDisplaySize, &CmndDisplayFont,
&CmndDisplayRotate, &CmndDisplayText, &CmndDisplayAddress, &CmndDisplayBlinkrate,
&CmndDisplay, &CmndDisplayModel, &CmndDisplayType, &CmndDisplayWidth, &CmndDisplayHeight, &CmndDisplayMode,
&CmndDisplayInvert, &CmndDisplayRefresh, &CmndDisplayDimmer, &CmndDisplayColumns, &CmndDisplayRows,
&CmndDisplaySize, &CmndDisplayFont, &CmndDisplayRotate, &CmndDisplayText, &CmndDisplayAddress, &CmndDisplayBlinkrate,
#ifdef USE_UFILESYS
&CmndDisplayBatch,
#endif
&CmndDisplayClear, &CmndDisplayNumber, &CmndDisplayFloat, &CmndDisplayNumberNC, &CmndDisplayFloatNC,
&CmndDisplayRaw, &CmndDisplayLevel, &CmndDisplaySevensegText, &CmndDisplaySevensegTextNC,
&CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC,
&CmndDisplayScrollText, &CmndDisplayILIMOde , &CmndDisplayILIInvert
&CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, &CmndDisplayScrollText
};
#ifdef USE_GRAPH
typedef union {
uint8_t data;
struct {
uint8_t overlay : 1;
uint8_t draw : 1;
uint8_t nu3 : 1;
uint8_t nu4 : 1;
uint8_t nu5 : 1;
uint8_t nu6 : 1;
uint8_t nu7 : 1;
uint8_t nu8 : 1;
};
} GFLAGS;
struct GRAPH {
uint16_t xp;
uint16_t yp;
uint16_t xs;
uint16_t ys;
float ymin;
float ymax;
float range;
uint32_t x_time; // time per x slice in milliseconds
uint32_t last_ms;
uint32_t last_ms_redrawn;
int16_t decimation; // decimation or graph duration in minutes
uint16_t dcnt;
uint32_t summ;
uint16_t xcnt;
uint8_t *values;
uint8_t xticks;
uint8_t yticks;
uint8_t last_val;
uint8_t color_index;
GFLAGS flags;
};
struct GRAPH *graph[NUM_GRAPHS];
#endif // USE_GRAPH
char *dsp_str;
uint16_t dsp_x;
@ -1637,18 +1676,16 @@ void DisplaySetPower(void)
* Commands
\*********************************************************************************************/
void CmndDisplay(void)
{
Response_P(PSTR("{\"" D_PRFX_DISPLAY "\":{\"" D_CMND_DISP_MODEL "\":%d,\"" D_CMND_DISP_WIDTH "\":%d,\"" D_CMND_DISP_HEIGHT "\":%d,\""
void CmndDisplay(void) {
Response_P(PSTR("{\"" D_PRFX_DISPLAY "\":{\"" D_CMND_DISP_MODEL "\":%d,\"" D_CMND_DISP_TYPE "\":%d,\"" D_CMND_DISP_WIDTH "\":%d,\"" D_CMND_DISP_HEIGHT "\":%d,\""
D_CMND_DISP_MODE "\":%d,\"" D_CMND_DISP_DIMMER "\":%d,\"" D_CMND_DISP_SIZE "\":%d,\"" D_CMND_DISP_FONT "\":%d,\""
D_CMND_DISP_ROTATE "\":%d,\"" D_CMND_DISP_REFRESH "\":%d,\"" D_CMND_DISP_COLS "\":[%d,%d],\"" D_CMND_DISP_ROWS "\":%d}}"),
Settings.display_model, Settings.display_width, Settings.display_height,
Settings.display_mode, ((Settings.display_dimmer * 666) / 100) +1, Settings.display_size, Settings.display_font,
Settings.display_rotate, Settings.display_refresh, Settings.display_cols[0], Settings.display_cols[1], Settings.display_rows);
D_CMND_DISP_ROTATE "\":%d,\"" D_CMND_DISP_INVERT "\":%d,\"" D_CMND_DISP_REFRESH "\":%d,\"" D_CMND_DISP_COLS "\":[%d,%d],\"" D_CMND_DISP_ROWS "\":%d}}"),
Settings.display_model, Settings.display_options.type, Settings.display_width, Settings.display_height,
Settings.display_mode, changeUIntScale(Settings.display_dimmer, 0, 15, 0, 100), Settings.display_size, Settings.display_font,
Settings.display_rotate, Settings.display_options.invert, Settings.display_refresh, Settings.display_cols[0], Settings.display_cols[1], Settings.display_rows);
}
void CmndDisplayModel(void)
{
void CmndDisplayModel(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < DISPLAY_MAX_DRIVERS)) {
uint32_t last_display_model = Settings.display_model;
Settings.display_model = XdrvMailbox.payload;
@ -1661,8 +1698,15 @@ void CmndDisplayModel(void)
ResponseCmndNumber(Settings.display_model);
}
void CmndDisplayWidth(void)
{
void CmndDisplayType(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 7)) {
Settings.display_options.type = XdrvMailbox.payload;
TasmotaGlobal.restart_flag = 2;
}
ResponseCmndNumber(Settings.display_options.type);
}
void CmndDisplayWidth(void) {
if (XdrvMailbox.payload > 0) {
if (XdrvMailbox.payload != Settings.display_width) {
Settings.display_width = XdrvMailbox.payload;
@ -1672,8 +1716,7 @@ void CmndDisplayWidth(void)
ResponseCmndNumber(Settings.display_width);
}
void CmndDisplayHeight(void)
{
void CmndDisplayHeight(void) {
if (XdrvMailbox.payload > 0) {
if (XdrvMailbox.payload != Settings.display_height) {
Settings.display_height = XdrvMailbox.payload;
@ -1683,8 +1726,7 @@ void CmndDisplayHeight(void)
ResponseCmndNumber(Settings.display_height);
}
void CmndDisplayMode(void)
{
void CmndDisplayMode(void) {
#ifdef USE_DISPLAY_MODES1TO5
/* Matrix / 7-segment LCD / Oled TFT
* 1 = Text up and time Time
@ -1716,7 +1758,7 @@ void CmndDisplayMode(void)
void CmndDisplayDimmer(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
Settings.display_dimmer = ((XdrvMailbox.payload +1) * 100) / 666; // Correction for Domoticz (0 - 15)
Settings.display_dimmer = changeUIntScale(XdrvMailbox.payload, 0, 100, 0, 15); // Correction for Domoticz (0 - 15)
if (Settings.display_dimmer && !(disp_power)) {
ExecuteCommandPower(disp_device, POWER_ON, SRC_DISPLAY);
}
@ -1729,146 +1771,11 @@ void CmndDisplayDimmer(void) {
XdspCall(FUNC_DISPLAY_DIM);
}
}
ResponseCmndNumber(((Settings.display_dimmer * 666) / 100) +1);
ResponseCmndNumber(changeUIntScale(Settings.display_dimmer, 0, 15, 0, 100));
}
void CmndDisplayBlinkrate(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
if (!renderer)
XdspCall(FUNC_DISPLAY_BLINKRATE);
}
ResponseCmndNumber(XdrvMailbox.payload);
}
#ifdef USE_UFILESYS
void CmndDisplayBatch(void) {
if (XdrvMailbox.data_len > 0) {
if (!Settings.display_mode) {
Display_Text_From_File(XdrvMailbox.data);
}
ResponseCmndChar(XdrvMailbox.data);
}
}
#endif
void CmndDisplayClear(void)
{
if (!renderer)
XdspCall(FUNC_DISPLAY_CLEAR);
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayNumber(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_NUMBER);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayFloat(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_FLOAT);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayNumberNC(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_NUMBERNC);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayFloatNC(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_FLOATNC);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayRaw(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_RAW);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayLevel(void)
{
bool result = false;
if (!renderer) {
result = XdspCall(FUNC_DISPLAY_LEVEL);
}
if(result) ResponseCmndNumber(XdrvMailbox.payload);
}
void CmndDisplaySevensegText(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_SEVENSEG_TEXT);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayTextNC(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_SEVENSEG_TEXTNC);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplaySevensegTextNC(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_SEVENSEG_TEXTNC);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayScrollDelay(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_SCROLLDELAY);
}
ResponseCmndNumber(XdrvMailbox.payload);
}
void CmndDisplayClock(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_CLOCK);
}
ResponseCmndNumber(XdrvMailbox.payload);
}
void CmndDisplayScrollText(void)
{
bool result = false;
if (!renderer) {
result = XdspCall(FUNC_DISPLAY_SCROLLTEXT);
}
if(result) ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplaySize(void)
{
#ifdef USE_DISPLAY_TM1637
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 6)) {
#else
void CmndDisplaySize(void) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) {
#endif
Settings.display_size = XdrvMailbox.payload;
if (renderer) renderer->setTextSize(Settings.display_size);
//else DisplaySetSize(Settings.display_size);
@ -1876,8 +1783,7 @@ void CmndDisplaySize(void)
ResponseCmndNumber(Settings.display_size);
}
void CmndDisplayFont(void)
{
void CmndDisplayFont(void) {
if ((XdrvMailbox.payload >=0) && (XdrvMailbox.payload <= 4)) {
Settings.display_font = XdrvMailbox.payload;
if (renderer) renderer->setTextFont(Settings.display_font);
@ -1886,27 +1792,7 @@ void CmndDisplayFont(void)
ResponseCmndNumber(Settings.display_font);
}
void CmndDisplayILIMOde(void)
{
if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 7)) {
Settings.display_options.ilimode = XdrvMailbox.payload;
TasmotaGlobal.restart_flag = 2;
}
ResponseCmndNumber(Settings.display_options.ilimode);
}
void CmndDisplayILIInvert(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
Settings.display_options.Invert = XdrvMailbox.payload;
if (renderer) renderer->invertDisplay(Settings.display_options.Invert);
}
ResponseCmndNumber(Settings.display_options.Invert);
}
void CmndDisplayRotate(void)
{
void CmndDisplayRotate(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 4)) {
if ((Settings.display_rotate) != XdrvMailbox.payload) {
/*
@ -1930,8 +1816,77 @@ void CmndDisplayRotate(void)
ResponseCmndNumber(Settings.display_rotate);
}
void CmndDisplayText(void)
{
void CmndDisplayInvert(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
Settings.display_options.invert = XdrvMailbox.payload;
if (renderer) renderer->invertDisplay(Settings.display_options.invert);
}
ResponseCmndNumber(Settings.display_options.invert);
}
void CmndDisplayRefresh(void) {
if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 7)) {
Settings.display_refresh = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.display_refresh);
}
void CmndDisplayColumns(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_COLS)) {
Settings.display_cols[XdrvMailbox.index -1] = XdrvMailbox.payload;
#ifdef USE_DISPLAY_MODES1TO5
if (1 == XdrvMailbox.index) {
DisplayLogBufferInit();
DisplayReAllocScreenBuffer();
}
#endif // USE_DISPLAY_MODES1TO5
}
ResponseCmndIdxNumber(Settings.display_cols[XdrvMailbox.index -1]);
}
}
void CmndDisplayRows(void) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_ROWS)) {
Settings.display_rows = XdrvMailbox.payload;
#ifdef USE_DISPLAY_MODES1TO5
DisplayLogBufferInit();
DisplayReAllocScreenBuffer();
#endif // USE_DISPLAY_MODES1TO5
}
ResponseCmndNumber(Settings.display_rows);
}
void CmndDisplayAddress(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 8)) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) {
Settings.display_address[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
ResponseCmndIdxNumber(Settings.display_address[XdrvMailbox.index -1]);
}
}
void CmndDisplayBlinkrate(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_BLINKRATE);
}
}
ResponseCmndNumber(XdrvMailbox.payload);
}
#ifdef USE_UFILESYS
void CmndDisplayBatch(void) {
if (XdrvMailbox.data_len > 0) {
if (!Settings.display_mode) {
Display_Text_From_File(XdrvMailbox.data);
}
ResponseCmndChar(XdrvMailbox.data);
}
}
#endif
void CmndDisplayText(void) {
if (disp_device && XdrvMailbox.data_len > 0) {
#ifndef USE_DISPLAY_MODES1TO5
DisplayText();
@ -1948,50 +1903,100 @@ void CmndDisplayText(void)
}
}
void CmndDisplayAddress(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 8)) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) {
Settings.display_address[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
ResponseCmndIdxNumber(Settings.display_address[XdrvMailbox.index -1]);
}
/*********************************************************************************************\
* Currently 7-segement specific - should have been handled by (extended) DisplayText command
\*********************************************************************************************/
void CmndDisplayClear(void) {
if (!renderer)
XdspCall(FUNC_DISPLAY_CLEAR);
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayRefresh(void)
{
if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 7)) {
Settings.display_refresh = XdrvMailbox.payload;
void CmndDisplayNumber(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_NUMBER);
}
ResponseCmndNumber(Settings.display_refresh);
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayColumns(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_COLS)) {
Settings.display_cols[XdrvMailbox.index -1] = XdrvMailbox.payload;
#ifdef USE_DISPLAY_MODES1TO5
if (1 == XdrvMailbox.index) {
DisplayLogBufferInit();
DisplayReAllocScreenBuffer();
}
#endif // USE_DISPLAY_MODES1TO5
}
ResponseCmndIdxNumber(Settings.display_cols[XdrvMailbox.index -1]);
void CmndDisplayFloat(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_FLOAT);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayRows(void)
{
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_ROWS)) {
Settings.display_rows = XdrvMailbox.payload;
#ifdef USE_DISPLAY_MODES1TO5
DisplayLogBufferInit();
DisplayReAllocScreenBuffer();
#endif // USE_DISPLAY_MODES1TO5
void CmndDisplayNumberNC(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_NUMBERNC);
}
ResponseCmndNumber(Settings.display_rows);
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayFloatNC(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_FLOATNC);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayRaw(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_RAW);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayLevel(void) {
bool result = false;
if (!renderer) {
result = XdspCall(FUNC_DISPLAY_LEVEL);
}
if(result) ResponseCmndNumber(XdrvMailbox.payload);
}
void CmndDisplaySevensegText(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_SEVENSEG_TEXT);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayTextNC(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_SEVENSEG_TEXTNC);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplaySevensegTextNC(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_SEVENSEG_TEXTNC);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayScrollDelay(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_SCROLLDELAY);
}
ResponseCmndNumber(XdrvMailbox.payload);
}
void CmndDisplayClock(void) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_CLOCK);
}
ResponseCmndNumber(XdrvMailbox.payload);
}
void CmndDisplayScrollText(void) {
bool result = false;
if (!renderer) {
result = XdspCall(FUNC_DISPLAY_SCROLLTEXT);
}
if(result) ResponseCmndChar(XdrvMailbox.data);
}
/*********************************************************************************************\
@ -2177,46 +2182,9 @@ void DrawAClock(uint16_t rad) {
* Graphics
\*********************************************************************************************/
#ifdef USE_GRAPH
typedef union {
uint8_t data;
struct {
uint8_t overlay : 1;
uint8_t draw : 1;
uint8_t nu3 : 1;
uint8_t nu4 : 1;
uint8_t nu5 : 1;
uint8_t nu6 : 1;
uint8_t nu7 : 1;
uint8_t nu8 : 1;
};
} GFLAGS;
struct GRAPH {
uint16_t xp;
uint16_t yp;
uint16_t xs;
uint16_t ys;
float ymin;
float ymax;
float range;
uint32_t x_time; // time per x slice in milliseconds
uint32_t last_ms;
uint32_t last_ms_redrawn;
int16_t decimation; // decimation or graph duration in minutes
uint16_t dcnt;
uint32_t summ;
uint16_t xcnt;
uint8_t *values;
uint8_t xticks;
uint8_t yticks;
uint8_t last_val;
uint8_t color_index;
GFLAGS flags;
};
struct GRAPH *graph[NUM_GRAPHS];
#define TICKLEN 4
void ClrGraph(uint16_t num) {

View File

@ -411,9 +411,10 @@ String GetHueDeviceId(uint16_t id)
{
String deviceid = WiFi.macAddress();
deviceid += F(":00:11-");
deviceid += String(id);
if(id<0x10) deviceid += F("0");
deviceid += String(id,HEX);
deviceid.toLowerCase();
return deviceid; // 5c:cf:7f:13:9f:3d:00:11-1
return deviceid; // 5c:cf:7f:13:9f:3d:00:11-01
}
String GetHueUserId(void)

View File

@ -0,0 +1,62 @@
/*
xdrv_52_0_berry_struct.ino - Berry scripting language, native fucnctions
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
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_BERRY
#include <berry.h>
typedef LList_elt<char[0]> log_elt; // store the string after the header to avoid double allocation if we had used char*
class BerryLog {
public:
// typedef LList_elt<char[0]> log_elt; // store the string after the header to avoid double allocation if we had used char*
inline static size_t size(size_t chars) { return sizeof(log_elt) + chars; }
inline bool isEmpty(void) const { return log.isEmpty(); }
log_elt * addString(const char * s, const char * prefix = nullptr, const char * suffix = nullptr) {
if (suffix == nullptr) { suffix = ""; }
if (prefix == nullptr) { prefix = ""; }
if (s == nullptr) { s = ""; }
size_t s_len = strlen_P(s) + strlen_P(prefix) + strlen_P(suffix);
if (0 == s_len) { return nullptr; } // do nothing
log_elt * elt = (log_elt*) ::operator new(sizeof(log_elt) + s_len + 1); // use low-level new to specify the bytes size
snprintf_P((char*) &elt->val(), s_len+1, PSTR("%s%s%s"), prefix, s, suffix);
log.addToLast(elt);
return elt;
}
void reset(void) {
log.reset();
}
LList<char[0]> log;
};
class BerrySupport {
public:
bvm *vm = nullptr; // berry vm
bool rules_busy = false; // are we already processing rules, avoid infinite loop
bool autoexec_done = false; // do we still need to load 'autoexec.be'
bool repl_active = false; // is REPL running (activates log recording)
// output log is stored as a LinkedList of buffers
// and active only when a REPL command is running
BerryLog log;
};
BerrySupport berry;
#endif // USE_BERRY

View File

@ -23,6 +23,8 @@
#include <berry.h>
#include <Wire.h>
const uint32_t BERRY_MAX_LOGS = 16; // max number of print output recorded when outside of REPL, used to avoid infinite grow of logs
/*********************************************************************************************\
* Native functions mapped to Berry functions
*
@ -30,18 +32,18 @@
*
* import tasmota
*
* tasmota.getfreeheap() -> int
* tasmota.get_free_heap() -> int
* tasmota.publish(topic:string, payload:string[, retain:bool]) -> nil
* tasmota.cmd(command:string) -> string
* tasmota.getoption(index:int) -> int
* tasmota.get_option(index:int) -> int
* tasmota.millis([delay:int]) -> int
* tasmota.timereached(timer:int) -> bool
* tasmota.time_reached(timer:int) -> bool
* tasmota.yield() -> nil
*
* tasmota.getlight([index:int = 0]) -> map
* tasmota.getpower([index:int = 0]) -> bool
* tasmota.setpower(idx:int, power:bool) -> bool or nil
* tasmota.setlight(idx:int, values:map) -> map
* tasmota.get_light([index:int = 0]) -> map
* tasmota.get_power([index:int = 0]) -> bool
* tasmota.set_power(idx:int, power:bool) -> bool or nil
* tasmota.set_light(idx:int, values:map) -> map
*
\*********************************************************************************************/
extern "C" {
@ -97,7 +99,7 @@ extern "C" {
be_raise(vm, kTypeError, nullptr);
}
// Berry: tasmota.getoption(index:int) -> int
// Berry: tasmota.get_option(index:int) -> int
//
int32_t l_getoption(struct bvm *vm);
int32_t l_getoption(struct bvm *vm) {
@ -110,7 +112,7 @@ extern "C" {
be_raise(vm, kTypeError, nullptr);
}
// Berry: tasmota.timereached(timer:int) -> bool
// Berry: tasmota.time_reached(timer:int) -> bool
//
int32_t l_timereached(struct bvm *vm);
int32_t l_timereached(struct bvm *vm) {
@ -145,7 +147,7 @@ extern "C" {
be_return_nil(vm);
}
// Berry: tasmota.scaleuint(int * 5) -> int
// Berry: tasmota.scale_uint(int * 5) -> int
//
int32_t l_scaleuint(struct bvm *vm);
int32_t l_scaleuint(struct bvm *vm) {
@ -315,7 +317,7 @@ extern "C" {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 1 || (top == 2 && be_isint(vm, 2))) {
int32_t light_num = 0;
if (top > 0) {
if (top > 1) {
light_num = be_toint(vm, 2);
}
push_getlight(vm, light_num);
@ -470,6 +472,24 @@ extern "C" {
be_raise(vm, kTypeError, nullptr);
}
#ifdef USE_I2C
// I2C specific
// Berry: `i2c_enabled(index:int) -> bool` is I2C device enabled
int32_t l_i2cenabled(struct bvm *vm);
int32_t l_i2cenabled(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 2 && be_isint(vm, 2)) {
int32_t index = be_toint(vm, 2);
bool enabled = I2cEnabled(index);
be_pushbool(vm, enabled);
be_return(vm); // Return
}
be_raise(vm, kTypeError, nullptr);
}
#else // USE_I2C
int32_t l_i2cenabled(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing")));
#endif // USE_I2C
}
/*********************************************************************************************\
@ -522,6 +542,13 @@ extern "C" {
// called as a replacement to Berry `print()`
void berry_log(const char * berry_buf);
void berry_log(const char * berry_buf) {
if (berry.repl_active) {
if (berry.log.log.length() >= BERRY_MAX_LOGS) {
berry.log.log.remove(berry.log.log.head());
}
}
// AddLog(LOG_LEVEL_INFO, PSTR("[Add to log] %s"), berry_buf);
berry.log.addString(berry_buf, nullptr, "\n");
AddLog(LOG_LEVEL_INFO, PSTR("%s"), berry_buf);
}

View File

@ -48,7 +48,7 @@ int32_t getBus(bvm *vm) {
*
* import wire
*
* wire.getfreeheap() -> int
* wire.get_free_heap() -> int
*
\*********************************************************************************************/
extern "C" {
@ -135,14 +135,18 @@ extern "C" {
int32_t b_wire_write(struct bvm *vm);
int32_t b_wire_write(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
const void * buf;
size_t len;
TwoWire & myWire = getWire(vm);
if (top == 2 && (be_isint(vm, 2) || be_isstring(vm, 2))) {
if (top == 2 && (be_isint(vm, 2) || be_isstring(vm, 2) || be_isinstance(vm, 2))) {
if (be_isint(vm, 2)) {
int32_t value = be_toint(vm, 2);
myWire.write(value);
} else if (be_isstring(vm, 2)) {
const char * s = be_tostring(vm, 1);
myWire.write(s);
} else if ((buf = be_tobytes(vm, 2, &len)) != nullptr) {
myWire.write((uint8_t*) buf, len);
} else {
be_return_nil(vm);
}
@ -211,7 +215,7 @@ extern "C" {
uint8_t addr = be_toint(vm, 2);
uint8_t reg = be_toint(vm, 3);
uint8_t size = be_toint(vm, 4);
bool ok = I2cValidRead(addr, reg, size); // TODO
bool ok = I2cValidRead(addr, reg, size, bus); // TODO
if (ok) {
be_pushint(vm, i2c_buffer);
} else {
@ -221,6 +225,22 @@ extern "C" {
}
be_raise(vm, kTypeError, nullptr);
}
// Berry: `find(address:int) -> bool` true if device responds
int32_t b_wire_detect(struct bvm *vm);
int32_t b_wire_detect(struct bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
TwoWire & myWire = getWire(vm);
if (top == 2 && be_isint(vm, 2)) {
uint8_t addr = be_toint(vm, 2);
// check the presence of the device
myWire.beginTransmission((uint8_t)addr);
bool found = (0 == myWire.endTransmission());
be_pushbool(vm, found);
be_return(vm); // Return
}
be_raise(vm, kTypeError, nullptr);
}
#else // USE_I2C
//
int32_t b_wire_i2cmissing(struct bvm *vm);
@ -239,6 +259,9 @@ extern "C" {
int32_t b_wire_scan(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing")));
int32_t b_wire_validwrite(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing")));
int32_t b_wire_validread(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing")));
int32_t b_wire_readbytes(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing")));
int32_t b_wire_writebytes(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing")));
int32_t b_wire_detect(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing")));
#endif // USE_I2C
}

View File

@ -55,14 +55,11 @@ const char berry_prog[] =
"/f1,f2-> real(f1) < real(f2),"
"] "
"self._operators = \"=<>!|\" "
"self._rules = {} "
"self._timers = [] "
"self._cmd = {} "
"end "
// add `charsinstring(s:string,c:string) -> int``
// add `chars_in_string(s:string,c:string) -> int``
// looks for any char in c, and return the position of the first chat
// or -1 if not found
"def charsinstring(s,c) "
"def chars_in_string(s,c) "
"for i:0..size(s)-1 "
"for j:0..size(c)-1 "
"if s[i] == c[j] return i end "
@ -72,7 +69,7 @@ const char berry_prog[] =
"end "
// find a key in map, case insensitive, return actual key or nil if not found
"def findkeyi(m,keyi) "
"def find_key_i(m,keyi) "
"import string "
"var keyu = string.toupper(keyi) "
"if classof(m) == map "
@ -84,14 +81,11 @@ const char berry_prog[] =
"end "
"end "
// Rules
"def addrule(pat,f) self._rules[pat] = f end "
// # split the item when there is an operator, returns a list of (left,op,right)
// # ex: "Dimmer>50" -> ["Dimmer",tasmota_gt,"50"]
"def find_op(item) "
"import string "
"var pos = self.charsinstring(item, self._operators) "
"var pos = self.chars_in_string(item, self._operators) "
"if pos>=0 "
"var op_split = string.split(item,pos) "
// #print(op_split)
@ -109,6 +103,14 @@ const char berry_prog[] =
"end "
"return [item, nil, nil] "
"end "
// Rules
"def add_rule(pat,f) "
"if !self._rules "
"self._rules={} "
"end "
"self._rules[pat] = f "
"end "
// Rules trigger if match. return true if match, false if not
"def try_rule(ev, rule, f) "
@ -117,7 +119,7 @@ const char berry_prog[] =
"var e=ev "
"var rl=string.split(rl_list[0],'#') "
"for it:rl "
"found=self.findkeyi(e,it) "
"found=self.find_key_i(e,it) "
"if found == nil "
"return false "
"end "
@ -138,55 +140,69 @@ const char berry_prog[] =
// Run rules, i.e. check each individual rule
// Returns true if at least one rule matched, false if none
"def exec_rules(ev_json) "
"import json "
"var ev = json.load(ev_json) "
"var ret = false "
"if ev == nil "
"print('BRY: ERROR, bad json: '+ev_json, 3) "
"else "
"for r: self._rules.keys() "
"ret = self.try_rule(ev,r,self._rules[r]) || ret "
"if self._rules "
"import json "
"var ev = json.load(ev_json) "
"var ret = false "
"if ev == nil "
"print('BRY: ERROR, bad json: '+ev_json, 3) "
"else "
"for r: self._rules.keys() "
"ret = self.try_rule(ev,r,self._rules[r]) || ret "
"end "
"end "
"return ret "
"end "
"return ret "
"return false "
"end "
"def settimer(delay,f) self._timers.push([self.millis(delay),f]) end "
"def set_timer(delay,f) "
"if !self._timers self._timers=[] end "
"self._timers.push([self.millis(delay),f]) "
"end "
// run every 50ms tick
"def run_deferred() "
"var i=0 "
"while i<self._timers.size() "
"if self.timereached(self._timers[i][0]) "
"f=self._timers[i][1] "
"self._timers.remove(i) "
"f() "
"else "
"i=i+1 "
"if self._timers "
"var i=0 "
"while i<self._timers.size() "
"if self.time_reached(self._timers[i][0]) "
"f=self._timers[i][1] "
"self._timers.remove(i) "
"f() "
"else "
"i=i+1 "
"end "
"end "
"end "
"end "
// Delay function, internally calls yield() every 10ms to avoid WDT
"def delay(ms) "
"var tend = self.millis(ms) "
"while !self.timereached(tend) "
"self.yield() "
"end "
"end "
// // Delay function, internally calls yield() every 10ms to avoid WDT
// "def delay(ms) "
// "var tend = self.millis(ms) "
// "while !self.time_reached(tend) "
// "self.yield() "
// "end "
// "end "
// Add command to list
"def addcommand(c,f) "
"def add_cmd(c,f) "
"if !self._cmd "
"self._cmd={} "
"end "
"self._cmd[c]=f "
"end "
"def exec_cmd(cmd, idx, payload) "
"import json "
"var payload_json = json.load(payload) "
"var cmd_found = self.findkeyi(self._cmd, cmd) "
"if cmd_found != nil "
"self.resolvecmnd(cmd_found) " // set the command name in XdrvMailbox.command
"self._cmd[cmd_found](cmd_found, idx, payload, payload_json) "
"return true "
"if self._cmd "
"import json "
"var payload_json = json.load(payload) "
"var cmd_found = self.find_key_i(self._cmd, cmd) "
"if cmd_found != nil "
"self.resolvecmnd(cmd_found) " // set the command name in XdrvMailbox.command
"self._cmd[cmd_found](cmd_found, idx, payload, payload_json) "
"return true "
"end "
"end "
"return false "
"end "
@ -198,18 +214,86 @@ const char berry_prog[] =
"return gc.allocated() "
"end "
//
// Event from Tasmota is:
// 1. event:string -- type of event (cmd, rule, ...)
// 2. cmd:string -- name of the command to process
// 3. index:int -- index number
// 4. payload:string -- payload as text, analyzed as json
//
"def event(type, cmd, idx, payload) "
"if type=='cmd' return self.exec_cmd(cmd, idx, payload) "
"elif type=='rule' return self.exec_rules(payload) "
"elif type=='mqtt_data' return nil " // not yet implemented
"elif type=='gc' return self.gc() "
"elif type=='every_50ms' return self.run_deferred() "
"elif self._drivers "
"for d:self._drivers "
"try "
"if d.dispatch && d.dispatch(type, cmd, idx, payload) nil " // nil for `nop`
"elif type=='every_second' && d.every_second return d.every_second() "
"elif type=='every_100ms' && d.every_100ms return d.every_100ms() "
"end "
"except .. as e,m "
"import string "
"log(string.format('BRY: exception %s - %m',3)) "
"end "
"end "
"end "
"end "
//
// add driver to the queue of event dispatching
//
"def add_driver(d) "
"if self._drivers "
"self._drivers.push(d) "
"else "
"self._drivers = [d]"
"end "
"end "
"end "
// Instantiate tasmota object
"tasmota = Tasmota() "
"wire = Wire(0) "
"wire1 = Wire(1) "
// Not sure how to run call methods from C
"def _exec_rules(e) return tasmota.exec_rules(e) end "
"def _run_deferred() return tasmota.run_deferred() end "
"def _exec_cmd(cmd, idx, payload) return tasmota.exec_cmd(cmd, idx, payload) end "
"def _gc() return tasmota.gc() end "
// Wire class
"class Wire : Wire_ntv "
// read bytes as `bytes()` object
"def read_bytes(addr,reg,size) "
"self._begin_transmission(addr) "
"self._write(reg) "
"self._end_transmission(false) "
"self._request_from(addr,size) "
"var ret=bytes(size) "
"while (self._available()) "
"ret..self._read() "
"end "
"return ret "
"end "
// write bytes from `bytes` object
"def write_bytes(addr,reg,b) "
"self._begin_transmission(addr) "
"self._write(reg) "
"self._write(b) "
"self._end_transmission() "
"end "
"end "
"wire = Wire(0) "
"wire1 = wire "
"wire2 = Wire(1) "
//
// Base class for Tasmota Driver
//
"class Driver "
// functions are needs to be set to trigger an event
"var dispatch " // general dispatcher, returns true if serviced
"var every_second " // called every_second
"var every_100ms " // called every 100ms
// ...
"end "
// simple wrapper to load a file
// prefixes '/' if needed, and simpler to use than `compile()`

View File

@ -24,6 +24,8 @@
#include <berry.h>
#define BERRY_CONSOLE_CMD_DELIMITER "\x01"
const char kBrCommands[] PROGMEM = D_PRFX_BR "|" // prefix
D_CMND_BR_RUN "|" D_CMND_BR_RESET
;
@ -32,14 +34,6 @@ void (* const BerryCommand[])(void) PROGMEM = {
CmndBrRun, CmndBrReset,
};
class BerrySupport {
public:
bvm *vm = nullptr; // berry vm
bool rules_busy = false; // are we already processing rules, avoid infinite loop
bool autoexec_done = false; // do we still need to load 'autoexec.be'
};
BerrySupport berry;
//
// Sanity Check for be_top()
//
@ -53,6 +47,32 @@ void checkBeTop(void) {
}
}
/*********************************************************************************************\
* Memory handler
* Use PSRAM if available
\*********************************************************************************************/
extern "C" {
void *berry_malloc(uint32_t size);
void *berry_realloc(void *ptr, size_t size);
#ifdef USE_BERRY_PSRAM
void *berry_malloc(uint32_t size) {
return special_malloc(size);
}
void *berry_realloc(void *ptr, size_t size) {
return special_realloc(ptr, size);
}
#else
void *berry_malloc(uint32_t size) {
return malloc(size);
}
void *berry_realloc(void *ptr, size_t size) {
return realloc(ptr, size);
}
#endif // USE_BERRY_PSRAM
}
/*********************************************************************************************\
* Handlers for Berry calls and async
*
@ -64,79 +84,13 @@ bool callBerryRule(void) {
berry.rules_busy = true;
char * json_event = TasmotaGlobal.mqtt_data;
bool serviced = false;
checkBeTop();
be_getglobal(berry.vm, "_exec_rules");
if (!be_isnil(berry.vm, -1)) {
// {
// String event_saved = TasmotaGlobal.mqtt_data;
// // json_event = {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}}
// // json_event = {"System":{"Boot":1}}
// // json_event = {"SerialReceived":"on"} - invalid but will be expanded to {"SerialReceived":{"Data":"on"}}
// char *p = strchr(json_event, ':');
// if ((p != NULL) && !(strchr(++p, ':'))) { // Find second colon
// event_saved.replace(F(":"), F(":{\"Data\":"));
// event_saved += F("}");
// // event_saved = {"SerialReceived":{"Data":"on"}}
// }
// be_pushstring(berry.vm, event_saved.c_str());
// }
be_pushstring(berry.vm, TasmotaGlobal.mqtt_data);
int ret = be_pcall(berry.vm, 1);
serviced = be_tobool(berry.vm, 1);
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Event (%s) serviced=%d"), TasmotaGlobal.mqtt_data, serviced);
be_pop(berry.vm, 2); // remove function object
} else {
be_pop(berry.vm, 1); // remove nil object
}
checkBeTop();
serviced = callBerryEventDispatcher(PSTR("rule"), nullptr, 0, TasmotaGlobal.mqtt_data);
berry.rules_busy = false;
return serviced; // TODO event not handled
}
bool callBerryCommand(void) {
bool serviced = false;
checkBeTop();
be_getglobal(berry.vm, "_exec_cmd");
if (!be_isnil(berry.vm, -1)) {
be_pushstring(berry.vm, XdrvMailbox.topic);
be_pushint(berry.vm, XdrvMailbox.index);
be_pushstring(berry.vm, XdrvMailbox.data);
int ret = be_pcall(berry.vm, 3);
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: top=%d", be_top(berry.vm));
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(1)=%s", be_typename(berry.vm, 1));
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(2)=%s", be_typename(berry.vm, 2));
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(3)=%s", be_typename(berry.vm, 3));
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(4)=%s", be_typename(berry.vm, 4));
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(5)=%s", be_typename(berry.vm, 5));
serviced = be_tobool(berry.vm, 1); // return value is in slot 1
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: serviced=%d", serviced);
be_pop(berry.vm, 4); // remove function object
} else {
be_pop(berry.vm, 1); // remove nil object
}
checkBeTop();
return serviced; // TODO event not handled
}
size_t callBerryGC(void) {
size_t ram_used = 0;
checkBeTop();
be_getglobal(berry.vm, "_gc");
if (!be_isnil(berry.vm, -1)) {
int ret = be_pcall(berry.vm, 0);
ram_used = be_toint(berry.vm, 1);
be_pop(berry.vm, 1); // remove function object
} else {
be_pop(berry.vm, 1); // remove nil object
}
checkBeTop();
return ram_used;
return callBerryEventDispatcher(PSTR("gc"), nullptr, 0, nullptr);
}
// void callBerryMqttData(void) {
@ -161,16 +115,79 @@ size_t callBerryGC(void) {
// checkBeTop();
// }
// call a function (if exists) of type void -> void
void callBerryFunctionVoid(const char * fname) {
if (nullptr == berry.vm) { return; }
checkBeTop();
be_getglobal(berry.vm, fname);
/*
// Call a method of a global object, with n args
// Before: stack must containt n args
// After: stack contains return value or nil if something wrong (args removes)
// returns true is successful, false if object or method not found
bool callMethodObjectWithArgs(const char * objname, const char * method, size_t argc) {
if (nullptr == berry.vm) { return false; }
int32_t top = be_top(berry.vm);
// stacks contains n x arg
be_getglobal(berry.vm, objname);
// stacks contains n x arg + object
if (!be_isnil(berry.vm, -1)) {
be_pcall(berry.vm, 0);
be_getmethod(berry.vm, -1, method);
// stacks contains n x arg + object + method
if (!be_isnil(berry.vm, -1)) {
// reshuffle the entire stack since we want: method + object + n x arg
be_pushvalue(berry.vm, -1); // add instance as first arg
// stacks contains n x arg + object + method + method
be_pushvalue(berry.vm, -3); // add instance as first arg
// stacks contains n x arg + object + method + method + object
// now move args 2 slots up to make room for method and object
for (uint32_t i = 1; i <= argc; i++) {
be_moveto(berry.vm, -4 - i, -2 - i);
}
// stacks contains free + free + n x arg + method + object
be_moveto(berry.vm, -2, -4 - argc);
be_moveto(berry.vm, -1, -3 - argc);
// stacks contains method + object + n x arg + method + object
be_pop(berry.vm, 2);
// stacks contains method + object + n x arg
be_pcall(berry.vm, argc + 1);
// stacks contains return_val + object + n x arg
be_pop(berry.vm, argc + 1);
// stacks contains return_val
return true;
}
be_pop(berry.vm, 1); // remove method
// stacks contains n x arg + object
}
be_pop(berry.vm, 1); // remove function or nil object
// stacks contains n x arg + object
be_pop(berry.vm, argc + 1); // clear stack
be_pushnil(berry.vm); // put nil object
return false;
}
*/
// call the event dispatcher from Tasmota object
int32_t callBerryEventDispatcher(const char *type, const char *cmd, int32_t idx, const char *payload) {
int32_t ret = 0;
if (nullptr == berry.vm) { return ret; }
checkBeTop();
be_getglobal(berry.vm, PSTR("tasmota"));
if (!be_isnil(berry.vm, -1)) {
be_getmethod(berry.vm, -1, PSTR("event"));
if (!be_isnil(berry.vm, -1)) {
be_pushvalue(berry.vm, -2); // add instance as first arg
be_pushstring(berry.vm, type != nullptr ? type : "");
be_pushstring(berry.vm, cmd != nullptr ? cmd : "");
be_pushint(berry.vm, idx);
be_pushstring(berry.vm, payload != nullptr ? payload : "{}"); // empty json
be_pcall(berry.vm, 5); // 5 arguments
be_pop(berry.vm, 5);
if (be_isint(berry.vm, -1)) {
ret = be_toint(berry.vm, -1);
}
}
be_pop(berry.vm, 1); // remove method
}
be_pop(berry.vm, 1); // remove instance object
checkBeTop();
return ret;
}
/*********************************************************************************************\
@ -349,6 +366,313 @@ void CmndBrReset(void) {
BrReset();
}
/*********************************************************************************************\
* Berry console
\*********************************************************************************************/
#ifdef USE_WEBSERVER
void BrREPLRun(char * cmd) {
if (berry.vm == nullptr) { return; }
size_t cmd_len = strlen(cmd);
size_t cmd2_len = cmd_len + 12;
char * cmd2 = (char*) malloc(cmd2_len);
do {
int32_t ret_code;
snprintf_P(cmd2, cmd2_len, PSTR("return (%s)"), cmd);
ret_code = be_loadbuffer(berry.vm, PSTR("input"), cmd2, strlen(cmd2));
// AddLog(LOG_LEVEL_INFO, PSTR(">>>> be_loadbuffer cmd2 '%s', ret=%i"), cmd2, ret_code);
if (be_getexcept(berry.vm, ret_code) == BE_SYNTAX_ERROR) {
be_pop(berry.vm, 2); // remove exception values
// if fails, try the direct command
ret_code = be_loadbuffer(berry.vm, PSTR("input"), cmd, cmd_len);
// AddLog(LOG_LEVEL_INFO, PSTR(">>>> be_loadbuffer cmd1 '%s', ret=%i"), cmd, ret_code);
}
if (0 == ret_code) { // code is ready to run
ret_code = be_pcall(berry.vm, 0); // execute code
// AddLog(LOG_LEVEL_INFO, PSTR(">>>> be_pcall ret=%i"), ret_code);
if (0 == ret_code) {
if (!be_isnil(berry.vm, 1)) {
const char * ret_val = be_tostring(berry.vm, 1);
berry.log.addString(ret_val, nullptr, "\n");
// AddLog_P(LOG_LEVEL_INFO, PSTR(">>> %s"), ret_val);
}
be_pop(berry.vm, 1);
}
}
if (BE_EXCEPTION == ret_code) {
be_dumpstack(berry.vm);
char exception_s[120];
ext_snprintf_P(exception_s, sizeof(exception_s), PSTR("%s: %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
berry.log.addString(exception_s, nullptr, "\n");
// AddLog_P(LOG_LEVEL_INFO, PSTR(">>> %s"), exception_s);
be_pop(berry.vm, 2);
}
} while(0);
if (cmd2 != nullptr) {
free(cmd2);
cmd2 = nullptr;
}
checkBeTop();
}
const char HTTP_SCRIPT_BERRY_CONSOLE[] PROGMEM =
"var sn=0,id=0,ft,ltm=%d;" // Scroll position, Get most of weblog initially
// Console command history
"var hc=[],cn=0;" // hc = History commands, cn = Number of history being shown
"function l(p){" // Console log and command service
"var c,cc,o='';"
"clearTimeout(lt);"
"clearTimeout(ft);"
"t=eb('t1');"
"if(p==1){"
"c=eb('c1');" // Console command id
"cc=c.value.trim();"
"if(cc){"
"o='&c1='+encodeURIComponent(cc);"
"hc.length>19&&hc.pop();"
"hc.unshift(cc);"
"cn=0;"
"}"
"c.value='';"
"t.scrollTop=99999;"
"sn=t.scrollTop;"
"}"
"if(t.scrollTop>=sn){" // User scrolled back so no updates
"if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1)
"x=new XMLHttpRequest();"
"x.onreadystatechange=function(){"
"if(x.readyState==4&&x.status==200){"
"var d,t1;"
"d=x.responseText.split(/" BERRY_CONSOLE_CMD_DELIMITER "/);" // Field separator
"var d1=d.shift();"
"if(d1){"
"t1=document.createElement('div');"
"t1.classList.add('br1');"
"t1.innerText=d1;"
"t.appendChild(t1);"
"}"
"d1=d.shift();"
"if(d1){"
"t1=document.createElement('div');"
"t1.classList.add('br2');"
"t1.innerText=d1;"
"t.appendChild(t1);"
"}"
"t.scrollTop=99999;"
"sn=t.scrollTop;"
"clearTimeout(ft);"
"lt=setTimeout(l,ltm);" // webrefresh timer....
"}"
"};"
"x.open('GET','bs?c2='+id+o,true);" // Related to Webserver->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp))
"x.send();"
"ft=setTimeout(l,20000);" // fail timeout, triggered 20s after asking for XHR
"}else{"
"lt=setTimeout(l,ltm);" // webrefresh timer....
"}"
"c1.focus();"
"return false;"
"}"
"wl(l);" // Load initial console text
; // Add console command key eventlistener after name has been synced with id (= wl(jd))
const char HTTP_SCRIPT_BERRY_CONSOLE2[] PROGMEM =
// // Console command history
// "var hc=[],cn=0;" // hc = History commands, cn = Number of history being shown
"var pc=0;" // pc = previous char
"function h(){"
// "if(!(navigator.maxTouchPoints||'ontouchstart'in document.documentElement)){eb('c1').autocomplete='off';}" // No touch so stop browser autocomplete
"eb('c1').addEventListener('keydown',function(e){"
"var b=eb('c1'),c=e.keyCode;" // c1 = Console command id
"if((38==c||40==c)&&0==this.selectionStart&&0==this.selectionEnd){"
"b.autocomplete='off';"
"e.preventDefault();"
"38==c?(++cn>hc.length&&(cn=hc.length),b.value=hc[cn-1]||''):" // ArrowUp
"40==c?(0>--cn&&(cn=0),b.value=hc[cn-1]||''):" // ArrowDown
"0;"
"this.selectionStart=this.selectionEnd=0;"
"}" // ArrowUp or ArrowDown must be a keyboard so stop browser autocomplete
"if(c==13&&pc==13){"
"e.preventDefault();" // prevent 'enter' from being inserted
"l(1);"
"}"
"if(c==9){"
"e.preventDefault();"
"var start=this.selectionStart;"
"var end=this.selectionEnd;"
// set textarea value to: text before caret + tab + text after caret
"this.value=this.value.substring(0, start)+\" \"+this.value.substring(end);"
// put caret at right position again
"this.selectionStart=this.selectionEnd=start + 1;"
"}"
"pc=c;" // record previous key
// "13==c&&(hc.length>19&&hc.pop(),hc.unshift(b.value),cn=0)" // Enter, 19 = Max number -1 of commands in history
"});"
"}"
"wl(h);"; // Add console command key eventlistener after name has been synced with id (= wl(jd))
const char HTTP_BERRY_STYLE_CMND[] PROGMEM =
"<style>"
".br1{" // berry output
"border-left:dotted 2px #860;"
"margin-bottom:4px;"
"margin-top:4px;"
"padding:1px 5px 1px 18px;"
"}"
".br2{" // user input
"padding:0px 5px 0px 5px;"
"color:#faffff;"
"}"
".br0{"
// "-moz-appearance: textfield-multiline;"
// "-webkit-appearance: textarea;"
"font:medium -moz-fixed;"
"font:-webkit-small-control;"
"box-sizing:border-box;"
"width:100%;"
"overflow:auto;"
"resize:vertical;"
"font-family:monospace;"
"overflow:auto;"
"font-size:1em;"
"}"
".bro{"
// "-moz-appearance: textfield-multiline;"
// "-webkit-appearance: textarea;"
"border:1px solid gray;"
"height:250px;"
"padding:2px;"
"background:#222;"
"color:#fb1;"
"white-space:pre;"
"padding:2px 5px 2px 5px;"
"}"
".bri{"
// "-moz-appearance: textfield-multiline;"
// "-webkit-appearance: textarea;"
"border:1px solid gray;"
"height:60px;"
"padding:5px;"
"color:#000000;background:#faffff"
"}"
"</style>"
;
const char HTTP_BERRY_FORM_CMND[] PROGMEM =
"<br>"
"<div contenteditable='false' class='br0 bro' readonly id='t1' cols='340' wrap='off'>"
"<div class='br1'>Welcome to the Berry Scripting console. "
"Check the <a href='https://tasmota.github.io/docs/Berry-Scripting/' target='_blank'>documentation</a>."
"</div>"
"</div>"
// "<textarea readonly id='t1' cols='340' wrap='off'></textarea>"
// "<br><br>"
"<form method='get' id='fo' onsubmit='return l(1);'>"
"<textarea id='c1' class='br0 bri' rows='4' cols='340' wrap='soft' autofocus required></textarea>"
// "<input id='c1' class='bri' type='text' rows='5' placeholder='" D_ENTER_COMMAND "' autofocus><br>"
// "<input type='submit' value=\"Run code (or press 'Enter' twice)\">"
"<button type='submit'>Run code (or press 'Enter' twice)</button>"
"</form>";
const char HTTP_BTN_BERRY_CONSOLE[] PROGMEM =
"<p><form action='bs' method='get'><button>Berry Scripting console</button></form></p>";
void HandleBerryConsoleRefresh(void)
{
String svalue = Webserver->arg(F("c1"));
svalue.trim();
if (svalue.length()) {
berry.log.reset(); // clear all previous logs
berry.repl_active = true; // start recording
// AddLog_P(LOG_LEVEL_INFO, PSTR("BRY: received command %s"), svalue.c_str());
berry.log.addString(svalue.c_str(), nullptr, BERRY_CONSOLE_CMD_DELIMITER);
// Call berry
BrREPLRun((char*)svalue.c_str());
berry.repl_active = false; // don't record further
}
WSContentBegin(200, CT_PLAIN);
if (!berry.log.isEmpty()) {
WSContentFlush();
for (auto & l: berry.log.log) {
_WSContentSend((char*) l);
}
berry.log.reset();
}
WSContentEnd();
}
void HandleBerryConsole(void)
{
if (!HttpCheckPriviledgedAccess()) { return; }
// int i=16;
// // AddLog(LOG_LEVEL_INFO, PSTR("Size = %d %d"), sizeof(LList_elt<char[12]>), sizeof(LList_elt<char[0]>)+12);
// LList_elt<char[0]> * elt = (LList_elt<char[0]>*) ::operator new(sizeof(LList_elt<char[0]>) + 12);
if (Webserver->hasArg(F("c2"))) { // Console refresh requested
HandleBerryConsoleRefresh();
return;
}
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Berry " D_CONSOLE));
WSContentStart_P(PSTR("Berry " D_CONSOLE));
WSContentSend_P(HTTP_SCRIPT_BERRY_CONSOLE, Settings.web_refresh);
WSContentSend_P(HTTP_SCRIPT_BERRY_CONSOLE2);
WSContentSendStyle();
WSContentFlush();
_WSContentSend(HTTP_BERRY_STYLE_CMND);
_WSContentSend(HTTP_BERRY_FORM_CMND);
WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
}
// void HandleBerryConsoleRefresh(void)
// {
// String svalue = Webserver->arg(F("c1"));
// if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) {
// // TODO run command and store result
// // AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), svalue.c_str());
// // ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCONSOLE);
// }
// char stmp[8];
// WebGetArg(PSTR("c2"), stmp, sizeof(stmp));
// uint32_t index = 0; // Initial start, dump all
// if (strlen(stmp)) { index = atoi(stmp); }
// WSContentBegin(200, CT_PLAIN);
// WSContentSend_P(PSTR("%d}1%d}1"), TasmotaGlobal.log_buffer_pointer, Web.reset_web_log_flag);
// if (!Web.reset_web_log_flag) {
// index = 0;
// Web.reset_web_log_flag = true;
// }
// bool cflg = (index);
// char* line;
// size_t len;
// while (GetLog(Settings.weblog_level, &index, &line, &len)) {
// if (len > sizeof(TasmotaGlobal.mqtt_data) -2) { len = sizeof(TasmotaGlobal.mqtt_data); }
// char stemp[len +1];
// strlcpy(stemp, line, len);
// WSContentSend_P(PSTR("%s%s"), (cflg) ? PSTR("\n") : "", stemp);
// cflg = true;
// }
// WSContentSend_P(PSTR("}1"));
// WSContentEnd();
// }
#endif // USE_WEBSERVER
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
@ -363,51 +687,63 @@ bool Xdrv52(uint8_t function)
break;
case FUNC_LOOP:
if (!berry.autoexec_done) {
BrAutoexec();
BrAutoexec(); // run autoexec.be at first tick, so we know all modules are initialized
berry.autoexec_done = true;
}
break;
// Berry wide commands and events
case FUNC_RULES_PROCESS:
result = callBerryRule();
break;
case FUNC_MQTT_DATA:
result = callBerryEventDispatcher(PSTR("mqtt_data"), XdrvMailbox.topic, 0, XdrvMailbox.data);
break;
case FUNC_EVERY_50_MSECOND:
callBerryFunctionVoid(PSTR("_run_deferred"));
break;
case FUNC_EVERY_100_MSECOND:
callBerryFunctionVoid(PSTR("every_100ms"));
break;
case FUNC_EVERY_SECOND:
callBerryFunctionVoid(PSTR("every_second"));
callBerryEventDispatcher(PSTR("every_50ms"), nullptr, 0, nullptr);
break;
case FUNC_COMMAND:
result = DecodeCommand(kBrCommands, BerryCommand);
if (!result) {
result = callBerryCommand();
result = callBerryEventDispatcher(PSTR("cmd"), XdrvMailbox.topic, XdrvMailbox.index, XdrvMailbox.data);
}
break;
// Module specific events
case FUNC_EVERY_100_MSECOND:
callBerryEventDispatcher(PSTR("every_100ms"), nullptr, 0, nullptr);
break;
case FUNC_EVERY_SECOND:
callBerryEventDispatcher(PSTR("every_second"), nullptr, 0, nullptr);
break;
// case FUNC_SET_POWER:
// break;
case FUNC_RULES_PROCESS:
result = callBerryRule();
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_ADD_BUTTON:
WSContentSend_P(HTTP_BTN_BERRY_CONSOLE);
callBerryEventDispatcher(PSTR("web_add_button"), nullptr, 0, nullptr);
break;
case FUNC_WEB_ADD_MAIN_BUTTON:
callBerryEventDispatcher(PSTR("web_add_main_button"), nullptr, 0, nullptr);
break;
case FUNC_WEB_ADD_HANDLER:
callBerryEventDispatcher(PSTR("web_add_handler"), nullptr, 0, nullptr);
WebServer_on(PSTR("/bs"), HandleBerryConsole);
break;
#endif // USE_WEBSERVER
case FUNC_SAVE_BEFORE_RESTART:
break;
case FUNC_MQTT_DATA:
// callBerryMqttData();
callBerryEventDispatcher(PSTR("save_before_restart"), nullptr, 0, nullptr);
break;
case FUNC_WEB_SENSOR:
callBerryEventDispatcher(PSTR("web_sensor"), nullptr, 0, nullptr);
break;
case FUNC_JSON_APPEND:
callBerryEventDispatcher(PSTR("json_aooend"), nullptr, 0, nullptr);
break;
case FUNC_BUTTON_PRESSED:
callBerryEventDispatcher(PSTR("button_pressed"), nullptr, 0, nullptr);
break;

View File

@ -42,7 +42,7 @@ uint8_t ili9342_ctouch_counter = 0;
bool tft_init_done = false;
//Settings.display_options.ilimode = ILIMODE_9341;
//Settings.display_options.type = ILIMODE_9341;
/*********************************************************************************************/
@ -65,8 +65,8 @@ void ILI9341_InitDriver()
// disable screen buffer
buffer = NULL;
if (!Settings.display_options.ilimode || (Settings.display_options.ilimode >= ILIMODE_MAX)) {
Settings.display_options.ilimode = ILIMODE_9341;
if (!Settings.display_options.type || (Settings.display_options.type >= ILIMODE_MAX)) {
Settings.display_options.type = ILIMODE_9341;
}
// default colors
@ -77,11 +77,11 @@ void ILI9341_InitDriver()
if (TasmotaGlobal.soft_spi_enabled) {
// Init renderer, may use hardware spi, however we use SSPI defintion because SD card uses SPI definition (2 spi busses)
if (PinUsed(GPIO_SSPI_MOSI) && PinUsed(GPIO_SSPI_MISO) && PinUsed(GPIO_SSPI_SCLK)) {
ili9341_2 = new ILI9341_2(Pin(GPIO_ILI9341_CS), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_MISO), Pin(GPIO_SSPI_SCLK), Pin(GPIO_OLED_RESET), Pin(GPIO_ILI9341_DC), Pin(GPIO_BACKLIGHT), 2, Settings.display_options.ilimode & 3);
ili9341_2 = new ILI9341_2(Pin(GPIO_ILI9341_CS), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_MISO), Pin(GPIO_SSPI_SCLK), Pin(GPIO_OLED_RESET), Pin(GPIO_ILI9341_DC), Pin(GPIO_BACKLIGHT), 2, Settings.display_options.type & 3);
}
} else if (TasmotaGlobal.spi_enabled) {
if (PinUsed(GPIO_ILI9341_DC)) {
ili9341_2 = new ILI9341_2(Pin(GPIO_ILI9341_CS), Pin(GPIO_SPI_MOSI), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_CLK), Pin(GPIO_OLED_RESET), Pin(GPIO_ILI9341_DC), Pin(GPIO_BACKLIGHT), 1, Settings.display_options.ilimode & 3);
ili9341_2 = new ILI9341_2(Pin(GPIO_ILI9341_CS), Pin(GPIO_SPI_MOSI), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_CLK), Pin(GPIO_OLED_RESET), Pin(GPIO_ILI9341_DC), Pin(GPIO_BACKLIGHT), 1, Settings.display_options.type & 3);
}
}
@ -101,7 +101,7 @@ void ILI9341_InitDriver()
renderer->setTextFont(2);
renderer->setTextSize(1);
renderer->setTextColor(ILI9341_WHITE, ILI9341_BLACK);
renderer->DrawStringAt(50, (Settings.display_height/2)-12, (Settings.display_options.ilimode & 3)==ILIMODE_9341?"ILI9341 TFT!":"ILI9342 TFT!", ILI9341_WHITE, 0);
renderer->DrawStringAt(50, (Settings.display_height/2)-12, (Settings.display_options.type & 3)==ILIMODE_9341?"ILI9341 TFT!":"ILI9342 TFT!", ILI9341_WHITE, 0);
delay(1000);
#endif // SHOW_SPLASH

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@
#ifdef USE_CSE7761
/*********************************************************************************************\
* CSE7761 - Energy (Sonoff Dual R3 Pow)
* {"NAME":"Sonoff Dual R3","GPIO":[0,0,1,0,0,0,3232,3200,0,0,225,0,0,0,0,0,0,0,0,0,1,7296,7328,224,0,0,0,0,160,161,0,0,0,0,0,0],"FLAG":0,"BASE":1}
* {"NAME":"Sonoff Dual R3","GPIO":[32,0,0,0,0,0,0,0,0,576,225,0,0,0,0,0,0,0,0,0,0,7296,7328,224,0,0,0,0,160,161,0,0,0,0,0,0],"FLAG":0,"BASE":1}
*
* Based on datasheet from ChipSea and analysing serial data
* See https://github.com/arendst/Tasmota/discussions/10793
@ -34,29 +34,31 @@
#define CSE7761_UREF 42563 // RmsUc
#define CSE7761_IREF 52241 // RmsIAC
#define CSE7761_PREF 44513 // PowerPAC
#define CSE7761_FREF 3579545 // System clock (3.579545MHz) as used in frequency calculation
#define CSE7761_REG_SYSCON 0x00 // System Control Register
#define CSE7761_REG_EMUCON 0x01 // Metering control register
#define CSE7761_REG_EMUCON2 0x13 // Metering control register 2
#define CSE7761_REG_SYSCON 0x00 // (2) System Control Register (0x0A04)
#define CSE7761_REG_EMUCON 0x01 // (2) Metering control register (0x0000)
#define CSE7761_REG_EMUCON2 0x13 // (2) Metering control register 2 (0x0001)
#define CSE7761_REG_UFREQ 0x23 // Voltage Frequency Register
#define CSE7761_REG_RMSIA 0x24 // The effective value of channel A current
#define CSE7761_REG_RMSIB 0x25 // The effective value of channel B current
#define CSE7761_REG_RMSU 0x26 // Voltage RMS
#define CSE7761_REG_POWERPA 0x2C // Channel A active power, update rate 27.2Hz
#define CSE7761_REG_POWERPB 0x2D // Channel B active power, update rate 27.2Hz
#define CSE7761_REG_SYSSTATUS 0x43 // System status register
#define CSE7761_REG_UFREQ 0x23 // (2) Voltage Frequency (0x0000)
#define CSE7761_REG_RMSIA 0x24 // (3) The effective value of channel A current (0x000000)
#define CSE7761_REG_RMSIB 0x25 // (3) The effective value of channel B current (0x000000)
#define CSE7761_REG_RMSU 0x26 // (3) Voltage RMS (0x000000)
#define CSE7761_REG_POWERFACTOR 0x27 // (3) Power factor register, select by command: channel A Power factor or channel B power factor (0x7FFFFF)
#define CSE7761_REG_POWERPA 0x2C // (4) Channel A active power, update rate 27.2Hz (0x00000000)
#define CSE7761_REG_POWERPB 0x2D // (4) Channel B active power, update rate 27.2Hz (0x00000000)
#define CSE7761_REG_SYSSTATUS 0x43 // (1) System status register
#define CSE7761_REG_COEFFOFFSET 0x6E // Coefficient checksum offset (0xFFFF)
#define CSE7761_REG_COEFFCHKSUM 0x6F // Coefficient checksum
#define CSE7761_REG_RMSIAC 0x70 // Channel A effective current conversion coefficient
#define CSE7761_REG_RMSIBC 0x71 // Channel B effective current conversion coefficient
#define CSE7761_REG_RMSUC 0x72 // Effective voltage conversion coefficient
#define CSE7761_REG_POWERPAC 0x73 // Channel A active power conversion coefficient
#define CSE7761_REG_POWERPBC 0x74 // Channel B active power conversion coefficient
#define CSE7761_REG_POWERSC 0x75 // Apparent power conversion coefficient
#define CSE7761_REG_ENERGYAC 0x76 // Channel A energy conversion coefficient
#define CSE7761_REG_ENERGYBC 0x77 // Channel B energy conversion coefficient
#define CSE7761_REG_COEFFOFFSET 0x6E // (2) Coefficient checksum offset (0xFFFF)
#define CSE7761_REG_COEFFCHKSUM 0x6F // (2) Coefficient checksum
#define CSE7761_REG_RMSIAC 0x70 // (2) Channel A effective current conversion coefficient
#define CSE7761_REG_RMSIBC 0x71 // (2) Channel B effective current conversion coefficient
#define CSE7761_REG_RMSUC 0x72 // (2) Effective voltage conversion coefficient
#define CSE7761_REG_POWERPAC 0x73 // (2) Channel A active power conversion coefficient
#define CSE7761_REG_POWERPBC 0x74 // (2) Channel B active power conversion coefficient
#define CSE7761_REG_POWERSC 0x75 // (2) Apparent power conversion coefficient
#define CSE7761_REG_ENERGYAC 0x76 // (2) Channel A energy conversion coefficient
#define CSE7761_REG_ENERGYBC 0x77 // (2) Channel B energy conversion coefficient
#define CSE7761_SPECIAL_COMMAND 0xEA // Start special command
#define CSE7761_CMD_RESET 0x96 // Reset command, after receiving the command, the chip resets
@ -76,6 +78,7 @@ enum CSE7761 { RmsIAC, RmsIBC, RmsUC, PowerPAC, PowerPBC, PowerSC, EnergyAC, Ene
TasmotaSerial *Cse7761Serial = nullptr;
struct {
uint32_t frequency = 0;
uint32_t voltage_rms = 0;
uint32_t current_rms[2] = { 0 };
uint32_t energy[2] = { 0 };
@ -114,7 +117,7 @@ void Cse7761Write(uint32_t reg, uint32_t data) {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("C61: Tx %*_H"), len, buffer);
}
uint32_t Cse7761Read(uint32_t reg, uint32_t size) {
bool Cse7761ReadOnce(uint32_t log_level, uint32_t reg, uint32_t size, uint32_t* value) {
while (Cse7761Serial->available()) { Cse7761Serial->read(); }
Cse7761Write(reg, 0);
@ -123,8 +126,8 @@ uint32_t Cse7761Read(uint32_t reg, uint32_t size) {
uint32_t rcvd = 0;
uint32_t timeout = millis() + 3;
// while (!TimeReached(timeout) && (rcvd <= size)) {
while (!TimeReached(timeout)) {
while (!TimeReached(timeout) && (rcvd <= size)) {
// while (!TimeReached(timeout)) {
int value = Cse7761Serial->read();
if ((value > -1) && (rcvd < sizeof(buffer) -1)) {
buffer[rcvd++] = value;
@ -133,12 +136,12 @@ uint32_t Cse7761Read(uint32_t reg, uint32_t size) {
if (!rcvd) {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("C61: Rx none"));
return 0;
return false;
}
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("C61: Rx %*_H"), rcvd, buffer);
if (rcvd > 5) {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("C61: Rx overflow"));
return 0;
return false;
}
rcvd--;
@ -150,16 +153,28 @@ uint32_t Cse7761Read(uint32_t reg, uint32_t size) {
}
crc = ~crc;
if (crc != buffer[rcvd]) {
AddLog(LOG_LEVEL_DEBUG, PSTR("C61: Rx %*_H, CRC error %02X"), rcvd +1, buffer, crc);
return 1;
AddLog(log_level, PSTR("C61: Rx %*_H, CRC error %02X"), rcvd +1, buffer, crc);
return false;
}
return result;
*value = result;
return true;
}
uint32_t Cse7761Read(uint32_t reg, uint32_t size) {
bool result = false; // Start loop
uint32_t retry = 3; // Retry up to three times
uint32_t value = 0; // Default no value
while (!result && retry) {
retry--;
result = Cse7761ReadOnce((retry) ? LOG_LEVEL_DEBUG_MORE : LOG_LEVEL_DEBUG, reg, size, &value);
}
return value;
}
uint32_t Cse7761ReadFallback(uint32_t reg, uint32_t prev, uint32_t size) {
uint32_t value = Cse7761Read(reg, size);
if (1 == value) { // CRC Error so use previous value read
if (!value) { // Error so use previous value read
value = prev;
}
return value;
@ -192,16 +207,21 @@ bool Cse7761ChipInit(void) {
// CSE7761Data.coefficient[PowerPBC] = 0xADD7;
}
if (HLW_PREF_PULSE == Settings.energy_power_calibration) {
Settings.energy_frequency_calibration = CSE7761_FREF;
Settings.energy_voltage_calibration = Cse7761Ref(RmsUC);
Settings.energy_current_calibration = Cse7761Ref(RmsIAC);
Settings.energy_power_calibration = Cse7761Ref(PowerPAC);
}
// Just to fix intermediate users
if (Settings.energy_frequency_calibration < CSE7761_FREF / 2) {
Settings.energy_frequency_calibration = CSE7761_FREF;
}
Cse7761Write(CSE7761_SPECIAL_COMMAND, CSE7761_CMD_ENABLE_WRITE);
// delay(8); // Exception on ESP8266
uint32_t timeout = millis() + 8;
while (!TimeReached(timeout)) { }
// uint32_t timeout = millis() + 8;
// while (!TimeReached(timeout)) { }
uint8_t sys_status = Cse7761Read(CSE7761_REG_SYSSTATUS, 1);
#ifdef CSE7761_SIMULATE
@ -310,7 +330,7 @@ bool Cse7761ChipInit(void) {
=1, turn on the power factor output function (Sonoff Dual R3 Pow)
=0, turn off the power factor output function
5 WaveEN Waveform data, instantaneous data output enable signal
=1, turn on the waveform data output function
=1, turn on the waveform data output function (Tasmota add frequency)
=0, turn off the waveform data output function (Sonoff Dual R3 Pow)
4 SAGEN Voltage drop detection enable signal, WaveEN=1 must be configured first
=1, turn on the voltage drop detection function
@ -319,14 +339,15 @@ bool Cse7761ChipInit(void) {
=1, turn on the overvoltage, overcurrent, and overload detection functions
=0, turn off the overvoltage, overcurrent, and overload detection functions (Sonoff Dual R3 Pow)
2 ZxEN Zero-crossing detection, phase angle, voltage frequency measurement enable signal
=1, turn on the zero-crossing detection, phase angle, and voltage frequency measurement functions
=1, turn on the zero-crossing detection, phase angle, and voltage frequency measurement functions (Tasmota add frequency)
=0, disable zero-crossing detection, phase angle, voltage frequency measurement functions (Sonoff Dual R3 Pow)
1 PeakEN Peak detect enable signal
=1, turn on the peak detection function
=0, turn off the peak detection function (Sonoff Dual R3 Pow)
0 NC Default is 1
*/
Cse7761Write(CSE7761_REG_EMUCON2 | 0x80, 0x0FC1);
// Cse7761Write(CSE7761_REG_EMUCON2 | 0x80, 0x0FC1); // Sonoff Dual R3 Pow
Cse7761Write(CSE7761_REG_EMUCON2 | 0x80, 0x0FE5); // Tasmota add Frequency
} else {
AddLog(LOG_LEVEL_DEBUG, PSTR("C61: Write failed"));
return false;
@ -344,6 +365,12 @@ void Cse7761GetData(void) {
#endif
CSE7761Data.voltage_rms = (value >= 0x800000) ? 0 : value;
value = Cse7761ReadFallback(CSE7761_REG_UFREQ, CSE7761Data.frequency, 2);
#ifdef CSE7761_SIMULATE
value = 8948; // 49.99Hz
#endif
CSE7761Data.frequency = (value >= 0x8000) ? 0 : value;
value = Cse7761ReadFallback(CSE7761_REG_RMSIA, CSE7761Data.current_rms[0], 3);
#ifdef CSE7761_SIMULATE
value = 455;
@ -366,8 +393,8 @@ void Cse7761GetData(void) {
#endif
CSE7761Data.active_power[1] = (0 == CSE7761Data.current_rms[1]) ? 0 : (value & 0x80000000) ? (~value) + 1 : value;
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("C61: U%d, I%d/%d, P%d/%d"),
CSE7761Data.voltage_rms,
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("C61: F%d, U%d, I%d/%d, P%d/%d"),
CSE7761Data.frequency, CSE7761Data.voltage_rms,
CSE7761Data.current_rms[0], CSE7761Data.current_rms[1],
CSE7761Data.active_power[0], CSE7761Data.active_power[1]);
@ -375,6 +402,7 @@ void Cse7761GetData(void) {
// Voltage = RmsU * RmsUC * 10 / 0x400000
// Energy.voltage[0] = (float)(((uint64_t)CSE7761Data.voltage_rms * CSE7761Data.coefficient[RmsUC] * 10) >> 22) / 1000; // V
Energy.voltage[0] = ((float)CSE7761Data.voltage_rms / Settings.energy_voltage_calibration); // V
Energy.frequency[0] = (CSE7761Data.frequency) ? ((float)Settings.energy_frequency_calibration / 8 / CSE7761Data.frequency) : 0; // Hz
for (uint32_t channel = 0; channel < 2; channel++) {
Energy.data_valid[channel] = 0;
@ -460,6 +488,7 @@ void Cse7761DrvInit(void) {
CSE7761Data.init = 4; // Init setup steps
Energy.phase_count = 2; // Handle two channels as two phases
Energy.voltage_common = true; // Use common voltage
Energy.frequency_common = true; // Use common frequency
TasmotaGlobal.energy_driver = XNRG_19;
}
}
@ -482,6 +511,10 @@ bool Cse7761Command(void) {
if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(RmsIAC); }
// Service in xdrv_03_energy.ino
}
else if (CMND_FREQUENCYCAL == Energy.command_code) {
if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = CSE7761_FREF; }
// Service in xdrv_03_energy.ino
}
else if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && CSE7761Data.active_power[channel]) {
if ((value > 100) && (value < 200000)) { // Between 1W and 2000W
@ -503,6 +536,13 @@ 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;
}
}
}
else serviced = false; // Unknown command
return serviced;

View File

@ -113,7 +113,6 @@ const char* ConvertNumTxt(uint8_t statu, uint8_t pinmod=0) {
#endif // USE_MCP230xx_OUTPUT
#ifdef USE_MCP230xx_OUTPUT
if ((6 == pinmod) && (statu < 2)) { statu = 1-statu; }
AddLog(LOG_LEVEL_DEBUG, PSTR("MCP: ConvertNumTxt config=%d save_state=%d"),config, Settings.flag.save_state);
if ((config) && (Settings.flag.save_state)) {
return "SAVED";
}
@ -205,7 +204,6 @@ void MCP230xx_ApplySettings(void)
reg_portpins[mcp230xx_port] |= (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].saved_state << idx);
} else {
if (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].keep_output) { // Read the value to use from the MCP230xx
AddLog(LOG_LEVEL_DEBUG, PSTR("MCP: readpins=%d or_val=%d"),reg_readpins, reg_readpins & (1 << idx));
reg_portpins[mcp230xx_port] |= reg_readpins & (1 << idx);
}
else if (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pullup) {

View File

@ -43,6 +43,7 @@
* - added SetOption123 0-Wiegand UID decimal (default) 1-Wiegand UID hexadecimal
* - added SetOption124 0-all keys up to ending char (# or *) send as one tag by MQTT (default) 1-Keypad every key a single tag
* - added a new realtime testing option emulating a Wiegang reader output on same GPIOs where normally reader is attached. Details below
* - fix timing issue when fast glitches are detected on one on the datalines. The interbitgab was too short in that case
\*********************************************************************************************/
#pragma message("**** Wiegand interface enabled ****")
@ -106,10 +107,12 @@ class Wiegand {
bool WiegandConversion (uint64_t , uint16_t );
void setOutputFormat(void); // fix output HEX format
void HandleKeyPad(void); //handle one tag for multi key strokes
static void handleD0Interrupt(void);
static void handleD1Interrupt(void);
static void handleDxInterrupt(int in); // fix #11047
static void ClearRFIDBuffer(int);
uint64_t rfid;
uint32_t tagSize;
@ -142,6 +145,58 @@ volatile bool Wiegand::CodeComplete;
volatile RFID_store Wiegand::rfid_found[WIEGAND_RFID_ARRAY_SIZE];
volatile int Wiegand::currentFoundRFIDcount;
void ICACHE_RAM_ATTR Wiegand::ClearRFIDBuffer(int endIndex = WIEGAND_RFID_ARRAY_SIZE) {
currentFoundRFIDcount=WIEGAND_RFID_ARRAY_SIZE-endIndex; // clear all buffers
for (int i= 0; i < endIndex; i++) {
rfid_found[i].RFID=0;
rfid_found[i].bitCount=0;
}
}
void ICACHE_RAM_ATTR Wiegand::handleD1Interrupt() { // Receive a 1 bit. (D0=high & D1=low)
handleDxInterrupt(1);
}
void ICACHE_RAM_ATTR Wiegand::handleD0Interrupt() { // Receive a 0 bit. (D0=low & D1=high)
handleDxInterrupt(0);
}
void ICACHE_RAM_ATTR Wiegand::handleDxInterrupt(int in) {
unsigned long curTime = micros(); // to be sure I will use micros() instead of millis() overflow is handle by using the minus operator to compare
unsigned long diffTime= curTime - lastFoundTime;
if ( (diffTime > CodeGapTime) && (bitCount > 0)) {
// previous RFID tag (key pad numer)is complete. Will be detected by the code ending gap
// one bit will take the time of impulse_time + impulse_gap_time. it (bitTime) will be recalculated each time an impulse is detected
// the devices will add some inter_code_gap_time to separate codes this will be much longer than the bit_time. (WIEGAND_CODE_GAP_FACTOR)
// unfortunately there's no timing defined for Wiegand. On my test reader the impulse time = 125 µs impulse gap time = 950 µs.
if (currentFoundRFIDcount < WIEGAND_RFID_ARRAY_SIZE) { // when reaching the end of rfid buffer we will overwrite the last one.
currentFoundRFIDcount++;
}
// start a new tag
rfidBuffer = 0;
bitCount = 0;
FirstBitTimeStamp = 0;
}
if (in == 0) { rfidBuffer = rfidBuffer << 1; } // Receive a 0 bit. (D0=low & D1=high): Leftshift the 0 bit is now at the end of rfidBuffer
else if (in == 1) {rfidBuffer = (rfidBuffer << 1) | 1; } // Receive a 1 bit. (D0=high & D1=low): Leftshift + 1 bit
else { return; } // (in==3) called by ScanForTag to get the last tag, because the interrupt handler is no longer called after receiving the last bit
bitCount++;
if (bitCount == 1) { // first bit was detected
FirstBitTimeStamp = (curTime != 0) ? curTime : 1; // accept 1µs differenct to avoid a miss the first timestamp if curTime is 0.
}
else if (bitCount == 2) { // only calculate once per RFID tag, but restrict to values, which are in within a plausible range
bitTime = ((diffTime > (WIEGAND_BIT_TIME_DEFAULT/4)) && (diffTime < (4*WIEGAND_BIT_TIME_DEFAULT))) ? diffTime : WIEGAND_BIT_TIME_DEFAULT;
CodeGapTime = WIEGAND_CODE_GAP_FACTOR * bitTime;
}
//save current rfid in array otherwise we will never see the last found tag
rfid_found[currentFoundRFIDcount].RFID=rfidBuffer;
rfid_found[currentFoundRFIDcount].bitCount= bitCount;
lastFoundTime = curTime; // Last time a bit was detected
}
Wiegand::Wiegand() {
rfid = 0;
lastFoundTime = 0;
@ -154,67 +209,12 @@ Wiegand::Wiegand() {
FirstBitTimeStamp = 0;
CodeGapTime = WIEGAND_CODE_GAP_FACTOR * bitTime;
CodeComplete = false;
currentFoundRFIDcount=0;
for (int i=0; i < WIEGAND_RFID_ARRAY_SIZE; i++ )
{
rfid_found[i].RFID=0;
rfid_found[i].bitCount=0;
}
ClearRFIDBuffer();
outFormat="u"; // standard output format decimal
mqttRFIDKeypadBuffer = 0;
webRFIDKeypadBuffer = 0;
}
void ICACHE_RAM_ATTR Wiegand::handleD1Interrupt() { // Receive a 1 bit. (D0=high & D1=low)
handleDxInterrupt(1);
}
void ICACHE_RAM_ATTR Wiegand::handleD0Interrupt() { // Receive a 0 bit. (D0=low & D1=high)
handleDxInterrupt(0);
}
void ICACHE_RAM_ATTR Wiegand::handleDxInterrupt(int in) {
unsigned long curTime = micros(); // to be sure I will use micros() instead of millis() overflow is handle by using the minus operator to compare
unsigned long diffTime= curTime - lastFoundTime;
if (diffTime > 3000000 ) { //cancel noisy bits in buffer and start a new tag
rfidBuffer = 0;
bitCount = 0;
FirstBitTimeStamp = 0;
}
if ( (diffTime > CodeGapTime) && (bitCount > 0)) {
// previous RFID tag (key pad numer)is complete. Will be detected by the code ending gap
// one bit will take the time of impulse_time + impulse_gap_time. it (bitTime) will be recalculated each time an impulse is detected
// the devices will add some inter_code_gap_time to separate codes this will be much longer than the bit_time. (WIEGAND_CODE_GAP_FACTOR)
// unfortunately there's no timing defined for Wiegang. On my test reader the impulse time = 125 µs impulse gap time = 950 µs.
if (currentFoundRFIDcount < WIEGAND_RFID_ARRAY_SIZE) { // when reaching the end of rfid buffer we will overwrite the last one.
currentFoundRFIDcount++;
}
// start a new tag
rfidBuffer = 0;
bitCount = 0;
FirstBitTimeStamp = 0;
}
if (in ==3) {// called by ScanForTag to get the last tag, because the interrupt handler is no longer called after receiving the last bit
return;
}
if (in == 0) { rfidBuffer = rfidBuffer << 1; } // Receive a 0 bit. (D0=low & D1=high): Leftshift the 0 bit is now at the end of rfidBuffer
else {rfidBuffer = (rfidBuffer << 1) | 1; } // Receive a 1 bit. (D0=high & D1=low): Leftshift + 1 bit
bitCount++;
if (bitCount == 1) { // first bit was detected
FirstBitTimeStamp = (curTime != 0) ? curTime : 1; // accept 1µs differenct to avoid a miss the first timestamp if curTime is 0.
}
else if (bitCount == 2) { // only calculate once per RFID tag
bitTime = diffTime; //calc maximum current length of one bit
CodeGapTime = WIEGAND_CODE_GAP_FACTOR * bitTime;
}
//save current rfid in array otherwise we will never see the last found tag
rfid_found[currentFoundRFIDcount].RFID=rfidBuffer;
rfid_found[currentFoundRFIDcount].bitCount= bitCount;
lastFoundTime = curTime; // Last time a bit was detected
}
void Wiegand::Init() {
isInit = false;
if (PinUsed(GPIO_WIEGAND_D0) && PinUsed(GPIO_WIEGAND_D1)) { // Only start, if the Wiegang pins are selected
@ -400,7 +400,7 @@ void Wiegand::ScanForTag() {
uint64_t oldTag = rfid;
bool validKey = WiegandConversion(rfid_found[i].RFID, rfid_found[i].bitCount);
#if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Previous tag %llu"), oldTag);
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ValidKey: %d Previous tag %llu"), validKey, oldTag);
#endif // DEV_WIEGAND_TEST_MODE>0
if (validKey) { // Only in case of valid key do action. Issue#10585
HandleKeyPad(); //support one tag for multi key input
@ -412,15 +412,14 @@ void Wiegand::ScanForTag() {
MqttPublishTeleSensor();
}
}
rfid_found[i].RFID=0;
rfid_found[i].bitCount=0;
}
}
if (currentFoundRFIDcount > lastFoundRFIDcount) {
// if that happens: we need to move the id found during the loop to top of the array
// and correct the currentFoundRFIDcount
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() %lu tags added while working on buffer"), (currentFoundRFIDcount-lastFoundRFIDcount));
}
currentFoundRFIDcount=0; //reset array
ClearRFIDBuffer(); //reset array
#if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() time elapsed %lu"), (micros() - startTime));
#endif