mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-30 14:16:32 +00:00
Merge branch 'development' into development
This commit is contained in:
commit
c55ad6bd39
0
lib/Adafruit_SGP30-1.0.0.13/.github/ISSUE_TEMPLATE.md → lib/Adafruit_SGP30-1.0.3/.github/ISSUE_TEMPLATE.md
vendored
Normal file → Executable file
0
lib/Adafruit_SGP30-1.0.0.13/.github/ISSUE_TEMPLATE.md → lib/Adafruit_SGP30-1.0.3/.github/ISSUE_TEMPLATE.md
vendored
Normal file → Executable file
0
lib/Adafruit_SGP30-1.0.0.13/.github/PULL_REQUEST_TEMPLATE.md → lib/Adafruit_SGP30-1.0.3/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file → Executable file
0
lib/Adafruit_SGP30-1.0.0.13/.github/PULL_REQUEST_TEMPLATE.md → lib/Adafruit_SGP30-1.0.3/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file → Executable file
0
lib/Adafruit_SGP30-1.0.0.13/.gitignore → lib/Adafruit_SGP30-1.0.3/.gitignore
vendored
Normal file → Executable file
0
lib/Adafruit_SGP30-1.0.0.13/.gitignore → lib/Adafruit_SGP30-1.0.3/.gitignore
vendored
Normal file → Executable file
0
lib/Adafruit_SGP30-1.0.0.13/.travis.yml → lib/Adafruit_SGP30-1.0.3/.travis.yml
Normal file → Executable file
0
lib/Adafruit_SGP30-1.0.0.13/.travis.yml → lib/Adafruit_SGP30-1.0.3/.travis.yml
Normal file → Executable file
58
lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.cpp → lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.cpp
Normal file → Executable file
58
lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.cpp → lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.cpp
Normal file → Executable file
@ -37,7 +37,7 @@
|
||||
//#define I2C_DEBUG
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
/*!
|
||||
@brief Instantiates a new SGP30 class
|
||||
*/
|
||||
/**************************************************************************/
|
||||
@ -45,7 +45,7 @@ Adafruit_SGP30::Adafruit_SGP30() {
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
/*!
|
||||
@brief Setups the hardware and detects a valid SGP30. Initializes I2C
|
||||
then reads the serialnumber and checks that we are talking to an SGP30
|
||||
@param theWire Optional pointer to I2C interface, otherwise use Wire
|
||||
@ -60,31 +60,32 @@ boolean Adafruit_SGP30::begin(TwoWire *theWire) {
|
||||
_i2c = theWire;
|
||||
}
|
||||
|
||||
_i2c->begin();
|
||||
// assume i2c initialized already to avoid resetting clock stretching
|
||||
// _i2c->begin();
|
||||
|
||||
|
||||
|
||||
uint8_t command[2];
|
||||
command[0] = 0x36;
|
||||
command[1] = 0x82;
|
||||
if (! readWordFromCommand(command, 2, 10, serialnumber, 3))
|
||||
if (! readWordFromCommand(command, 2, 10, serialnumber, 3))
|
||||
return false;
|
||||
|
||||
uint16_t featureset;
|
||||
command[0] = 0x20;
|
||||
command[1] = 0x2F;
|
||||
if (! readWordFromCommand(command, 2, 10, &featureset, 1))
|
||||
if (! readWordFromCommand(command, 2, 10, &featureset, 1))
|
||||
return false;
|
||||
//Serial.print("Featureset 0x"); Serial.println(featureset, HEX);
|
||||
if (featureset != SGP30_FEATURESET)
|
||||
if (featureset != SGP30_FEATURESET)
|
||||
return false;
|
||||
if (! IAQinit())
|
||||
if (! IAQinit())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
/*!
|
||||
@brief Commands the sensor to begin the IAQ algorithm. Must be called after startup.
|
||||
@returns True if command completed successfully, false if something went wrong!
|
||||
*/
|
||||
@ -97,7 +98,7 @@ boolean Adafruit_SGP30::IAQinit(void) {
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
/*!
|
||||
@brief Commands the sensor to take a single eCO2/VOC measurement. Places results in {@link TVOC} and {@link eCO2}
|
||||
@returns True if command completed successfully, false if something went wrong!
|
||||
*/
|
||||
@ -113,9 +114,9 @@ boolean Adafruit_SGP30::IAQmeasure(void) {
|
||||
eCO2 = reply[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
/*!
|
||||
@brief Request baseline calibration values for both CO2 and TVOC IAQ calculations. Places results in parameter memory locaitons.
|
||||
@param eco2_base A pointer to a uint16_t which we will save the calibration value to
|
||||
@param tvoc_base A pointer to a uint16_t which we will save the calibration value to
|
||||
@ -135,7 +136,7 @@ boolean Adafruit_SGP30::getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base)
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
/*!
|
||||
@brief Assign baseline calibration values for both CO2 and TVOC IAQ calculations.
|
||||
@param eco2_base A uint16_t which we will save the calibration value from
|
||||
@param tvoc_base A uint16_t which we will save the calibration value from
|
||||
@ -157,7 +158,30 @@ boolean Adafruit_SGP30::setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base) {
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
/*!
|
||||
@brief Set the absolute humidity value [mg/m^3] for compensation to increase precision of TVOC and eCO2.
|
||||
@param absolute_humidity A uint32_t [mg/m^3] which we will be used for compensation. If the absolute humidity is set to zero, humidity compensation will be disabled.
|
||||
@returns True if command completed successfully, false if something went wrong!
|
||||
*/
|
||||
/**************************************************************************/
|
||||
boolean Adafruit_SGP30::setHumidity(uint32_t absolute_humidity) {
|
||||
if (absolute_humidity > 256000) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t ah_scaled = (uint16_t)(((uint64_t)absolute_humidity * 256 * 16777) >> 24);
|
||||
uint8_t command[5];
|
||||
command[0] = 0x20;
|
||||
command[1] = 0x61;
|
||||
command[2] = ah_scaled >> 8;
|
||||
command[3] = ah_scaled & 0xFF;
|
||||
command[4] = generateCRC(command+2, 2);
|
||||
|
||||
return readWordFromCommand(command, 5, 10);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief I2C low level interfacing
|
||||
*/
|
||||
/**************************************************************************/
|
||||
@ -186,16 +210,16 @@ boolean Adafruit_SGP30::readWordFromCommand(uint8_t command[], uint8_t commandLe
|
||||
|
||||
delay(delayms);
|
||||
|
||||
if (readlen == 0)
|
||||
if (readlen == 0)
|
||||
return true;
|
||||
|
||||
uint8_t replylen = readlen * (SGP30_WORD_LEN +1);
|
||||
if (_i2c->requestFrom(_i2caddr, replylen) != replylen)
|
||||
if (_i2c->requestFrom(_i2caddr, replylen) != replylen)
|
||||
return false;
|
||||
uint8_t replybuffer[replylen];
|
||||
#ifdef I2C_DEBUG
|
||||
Serial.print("\t\t<- ");
|
||||
#endif
|
||||
#endif
|
||||
for (uint8_t i=0; i<replylen; i++) {
|
||||
replybuffer[i] = _i2c->read();
|
||||
#ifdef I2C_DEBUG
|
1
lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.h → lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.h
Normal file → Executable file
1
lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.h → lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.h
Normal file → Executable file
@ -42,6 +42,7 @@ class Adafruit_SGP30 {
|
||||
|
||||
boolean getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base);
|
||||
boolean setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base);
|
||||
boolean setHumidity(uint32_t absolute_humidity);
|
||||
|
||||
/**
|
||||
* The last measurement of the IAQ-calculated Total Volatile Organic Compounds in ppb. This value is set when you call {@link IAQmeasure()}
|
0
lib/Adafruit_SGP30-1.0.0.13/README.md → lib/Adafruit_SGP30-1.0.3/README.md
Normal file → Executable file
0
lib/Adafruit_SGP30-1.0.0.13/README.md → lib/Adafruit_SGP30-1.0.3/README.md
Normal file → Executable file
16
lib/Adafruit_SGP30-1.0.0.13/examples/sgp30test/sgp30test.ino → lib/Adafruit_SGP30-1.0.3/examples/sgp30test/sgp30test.ino
Normal file → Executable file
16
lib/Adafruit_SGP30-1.0.0.13/examples/sgp30test/sgp30test.ino → lib/Adafruit_SGP30-1.0.3/examples/sgp30test/sgp30test.ino
Normal file → Executable file
@ -3,6 +3,17 @@
|
||||
|
||||
Adafruit_SGP30 sgp;
|
||||
|
||||
/* return absolute humidity [mg/m^3] with approximation formula
|
||||
* @param temperature [°C]
|
||||
* @param humidity [%RH]
|
||||
*/
|
||||
uint32_t getAbsoluteHumidity(float temperature, float humidity) {
|
||||
// approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
|
||||
const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
|
||||
const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
|
||||
return absoluteHumidityScaled;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
Serial.println("SGP30 test");
|
||||
@ -22,6 +33,11 @@ void setup() {
|
||||
|
||||
int counter = 0;
|
||||
void loop() {
|
||||
// If you have a temperature / humidity sensor, you can set the absolute humidity to enable the humditiy compensation for the air quality signals
|
||||
//float temperature = 22.1; // [°C]
|
||||
//float humidity = 45.2; // [%RH]
|
||||
//sgp.setHumidity(getAbsoluteHumidity(temperature, humidity));
|
||||
|
||||
if (! sgp.IAQmeasure()) {
|
||||
Serial.println("Measurement failed");
|
||||
return;
|
2
lib/Adafruit_SGP30-1.0.0.13/library.properties → lib/Adafruit_SGP30-1.0.3/library.properties
Normal file → Executable file
2
lib/Adafruit_SGP30-1.0.0.13/library.properties → lib/Adafruit_SGP30-1.0.3/library.properties
Normal file → Executable file
@ -1,5 +1,5 @@
|
||||
name=Adafruit SGP30 Sensor
|
||||
version=1.0.2
|
||||
version=1.0.3
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=This is an Arduino library for the Adafruit SGP30 Gas / Air Quality Sensor
|
0
lib/Adafruit_SGP30-1.0.0.13/license.txt → lib/Adafruit_SGP30-1.0.3/license.txt
Normal file → Executable file
0
lib/Adafruit_SGP30-1.0.0.13/license.txt → lib/Adafruit_SGP30-1.0.3/license.txt
Normal file → Executable file
10
platformio.ini
Normal file → Executable file
10
platformio.ini
Normal file → Executable file
@ -65,9 +65,9 @@ build_flags = ${esp82xx_defaults.build_flags}
|
||||
-DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
|
||||
-DVTABLES_IN_FLASH
|
||||
|
||||
[core_2_5_1]
|
||||
; *** Esp8266 core for Arduino version 2.5.1
|
||||
platform = espressif8266@~2.1.1
|
||||
[core_2_5_2]
|
||||
; *** Esp8266 core for Arduino version 2.5.2
|
||||
platform = espressif8266@~2.2.0
|
||||
build_flags = ${esp82xx_defaults.build_flags}
|
||||
-Wl,-Teagle.flash.1m.ld
|
||||
; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473
|
||||
@ -133,8 +133,8 @@ build_flags = ${esp82xx_defaults.build_flags}
|
||||
;build_flags = ${core_2_3_0.build_flags}
|
||||
;platform = ${core_2_4_2.platform}
|
||||
;build_flags = ${core_2_4_2.build_flags}
|
||||
platform = ${core_2_5_1.platform}
|
||||
build_flags = ${core_2_5_1.build_flags}
|
||||
platform = ${core_2_5_2.platform}
|
||||
build_flags = ${core_2_5_2.build_flags}
|
||||
;platform = ${core_stage.platform}
|
||||
;build_flags = ${core_stage.build_flags}
|
||||
|
||||
|
621
scripter.md
Normal file
621
scripter.md
Normal file
@ -0,0 +1,621 @@
|
||||
**Script Language for Tasmota**
|
||||
|
||||
As an alternative to rules. (about 14,2k flash size, variable ram size)
|
||||
|
||||
In submenu Configuration =\> edit script
|
||||
1535 bytes max script size (uses rules buffer)
|
||||
|
||||
to enable:
|
||||
\#define USE_SCRIPT
|
||||
\#undef USE_RULES
|
||||
|
||||
|
||||
Up to 50 variables (45 numeric and 5 strings, maybe changed by #define)
|
||||
Freely definable variable names (all names are intentionally case sensitive)
|
||||
Nested if,then,else up to a level of 8
|
||||
Math operators **+,-,\*,/,%,&,|,^**
|
||||
all operators may be used in the op= form e.g. **+=**
|
||||
Left right evaluation with optional brackets
|
||||
all numbers are float
|
||||
e.g. temp=hum\*(100/37.5)+temp-(timer\*hum%10)
|
||||
no spaces allowed between math operations
|
||||
Comparison operators **==,!=,\>,\>=,<,<=**
|
||||
**and** , **or** support
|
||||
|
||||
strings support **+** and **+=** operators
|
||||
string comparison **==,!=**
|
||||
max string size = 19 chars (default, can be increased or decreased by optional >D parameter)
|
||||
|
||||
**Comments** start with **;**
|
||||
|
||||
**Sections** defined:
|
||||
|
||||
>**\>D ssize**
|
||||
ssize = optional max stringsize (default=19)
|
||||
define and init variables here, must be the first section, no other code allowed
|
||||
**p:**vname specifies permanent vars (the number of permanent vars is limited by tasmota rules space (50 bytes)
|
||||
numeric var=4 bytes, string var=lenght of string+1)
|
||||
**t:**vname specifies countdown timers, if >0 they are decremented in seconds until zero is reached. see example below
|
||||
**i:**vname specifies auto increment counters if >=0 (in seconds)
|
||||
**m:**vname specifies a median filter variable with 5 entries (for elimination of outliers)
|
||||
**M:**vname specifies a moving average filter variable with 8 entries (for smoothing data)
|
||||
(max 5 filters in total m+M)
|
||||
|
||||
>all variable names length taken together may not exceed 256 characters, so keep variable names as short as possible.
|
||||
memory is dynamically allocated as a result of the D section.
|
||||
copying a string to a number or reverse is supported
|
||||
|
||||
>**\>B**
|
||||
executed on BOOT time
|
||||
|
||||
>**\>T**
|
||||
executed on teleperiod time (**SENSOR** and **STATE**), get tele vars only in this section
|
||||
|
||||
>**\>S**
|
||||
executed every second
|
||||
|
||||
>**\>E**
|
||||
executed e.g. on power change and mqtt **RESULT**
|
||||
|
||||
>**\>R**
|
||||
executed on restart, p vars are saved automatically after this call
|
||||
|
||||
|
||||
special variables (read only):
|
||||
|
||||
>**upsecs** = seconds since start
|
||||
**uptime** = minutes since start
|
||||
**time** = minutes since midnight
|
||||
**sunrise** = sunrise minutes since midnight
|
||||
**sunset** = sunset minutes since midnight
|
||||
**tper** = teleperiod (may be set also)
|
||||
**tstamp** = timestamp (local date and time)
|
||||
**topic** = mqtt topic
|
||||
**gtopic** = mqtt group topic
|
||||
**prefixn** = prefix n = 1-3
|
||||
**pwr[x]** = tasmota power state (x = 1-N)
|
||||
**sw[x]** = tasmota switch state (x = 1-N)
|
||||
>**pin[x]** = gpio pin level (x = 0-16)
|
||||
**pn[x]** = pin number for sensor code x, 99 if none
|
||||
**pd[x]** = defined sensor for gpio pin nr x none=999
|
||||
**gtmp** = global temperature
|
||||
**ghum** = global humidity
|
||||
**gprs** = global pressure
|
||||
**pow(x y)** = calculates the power of x^y
|
||||
**med(n x)** = calculates a 5 value median filter of x (2 filters possible n=0,1)
|
||||
**int(x)** = gets the integer part of x (like floor)
|
||||
**hn(x)** = converts x (0..255) zu a hex nibble string
|
||||
**mqtts** = state of mqtt disconnected=0, connected>0
|
||||
**wifis** = state of wifi disconnected=0, connected>0
|
||||
|
||||
>**hours** = hours
|
||||
**mins** = mins
|
||||
**secs** = seconds
|
||||
**day** = day of month
|
||||
**wday** = day of week
|
||||
**month** = month
|
||||
**year** = year
|
||||
|
||||
these variables are cleared after reading true
|
||||
>**chg[var]** = true if a variables value was changed (numeric vars only)
|
||||
**upd[var]** = true if a variable was updated
|
||||
**boot** = true on BOOT
|
||||
**tinit** = true on time init
|
||||
**tset** = true on time set
|
||||
**mqttc** = true on mqtt connect
|
||||
**mqttd** = true on mqtt disconnect
|
||||
**wific** = true on wifi connect
|
||||
**wifid** = true on wifi disconnect
|
||||
|
||||
system vars (for debugging)
|
||||
>**stack** = stack size
|
||||
**heap** = heap size
|
||||
**ram** = used ram size
|
||||
**slen** = script length
|
||||
**micros** = running microseconds
|
||||
**millis** = running milliseconds
|
||||
**loglvl** = loglevel of script cmds, may be set also
|
||||
|
||||
remarks:
|
||||
if you define a variable with the same name as a special
|
||||
variable that special variable is discarded
|
||||
|
||||
|
||||
**Tasmota** cmds start with **=\>**
|
||||
within cmds you can replace text with variables with **%varname%**
|
||||
a single percent sign must be given as **%%**
|
||||
|
||||
**special** cmds:
|
||||
|
||||
>**=\> print** prints to info log for debugging
|
||||
|
||||
to save code space nearly no error messages are provided. However it is taken care of that at least it should not crash on syntax errors.
|
||||
if a variable does not exist a **???** is given on commands
|
||||
if a **SENSOR** or **STATUS** or **RESULT** message or a var does not exist the destination variable is NOT updated.
|
||||
|
||||
2 possibilities for conditionals:
|
||||
>**if** a==b
|
||||
**and** x==y
|
||||
**or** k==i
|
||||
**then** => do this
|
||||
**else** => do that
|
||||
**endif**
|
||||
|
||||
OR
|
||||
|
||||
>**if** a==b
|
||||
**and** x==y
|
||||
**or** k==i **{**
|
||||
=> do this
|
||||
**} else {**
|
||||
=> do that
|
||||
**}**
|
||||
|
||||
you may NOT mix both methods
|
||||
|
||||
also possible e.g.
|
||||
|
||||
>if var1-var2==var3*var4
|
||||
then
|
||||
|
||||
remarks:
|
||||
the last closing bracket must be on a single line
|
||||
the condition may not be enclosed in brackets
|
||||
|
||||
>**break** exits a section or terminates a for next loop
|
||||
**dprecx** sets decimal precision to x (0-9)
|
||||
**svars** save permanent vars
|
||||
**delay(x)** pauses x milliseconds (should be as short as possible)
|
||||
**spin(x m)** set gpio pin x (0-16) to value m (0,1) only the last bit is used, so even values set the pin to zero and uneven values set the pin to 1
|
||||
**spinm(x m)** set pin mode gpio pin x (0-16) to mode m (input=0,output=1)
|
||||
|
||||
>**#name** names a subroutine, subroutines are called with **=#name**
|
||||
**#name(param)** names a subroutines with a parameter is called with **=#name(param)**
|
||||
subroutines end with the next '#' or '>' line or break, may be nested
|
||||
params can be numbers or strings and on mismatch are converted
|
||||
|
||||
>**for var from to inc**
|
||||
**next**
|
||||
specifies a for next loop, (loop count must not be less then 1)
|
||||
|
||||
>**switch x**
|
||||
**case a**
|
||||
**case b**
|
||||
**ends**
|
||||
specifies a switch case selector
|
||||
|
||||
**konsole script cmds**
|
||||
>**script 1 or 0** switch script on or off
|
||||
**script >cmdline** executes the script cmdline
|
||||
can be used e.g. to set variables e.g. **script >mintmp=15**
|
||||
more then one line may be executed seperated by a semicolon e.g. **script >mintmp=15;maxtemp=40**
|
||||
script itself cant be set because the size would not fit the mqtt buffers
|
||||
|
||||
***example script***
|
||||
meant to show some of the possibilities
|
||||
(actually this code ist too large)
|
||||
|
||||
**\>D**
|
||||
; define all vars here
|
||||
p:mintmp=10 (p:means permanent)
|
||||
p:maxtmp=30
|
||||
t:timer1=30 (t:means countdown timer)
|
||||
t:mt=0
|
||||
i:count=0 (i:means auto counter)
|
||||
hello="hello world"
|
||||
string="xxx"
|
||||
url="[192.168.178.86]"
|
||||
hum=0
|
||||
temp=0
|
||||
timer=0
|
||||
dimmer=0
|
||||
sw=0
|
||||
rssi=0
|
||||
param=0
|
||||
|
||||
col=""
|
||||
ocol=""
|
||||
chan1=0
|
||||
chan2=0
|
||||
chan3=0
|
||||
|
||||
ahum=0
|
||||
atemp=0
|
||||
tcnt=0
|
||||
hour=0
|
||||
state=1
|
||||
m:med5=0
|
||||
M:movav=0
|
||||
|
||||
**\>B**
|
||||
|
||||
string=hello+"how are you?"
|
||||
=\>print BOOT executed
|
||||
=\>print %hello%
|
||||
=\>mp3track 1
|
||||
|
||||
; list gpio pin definitions
|
||||
for cnt 0 16 1
|
||||
tmp=pd[cnt]
|
||||
=>print %cnt% = %tmp%
|
||||
next
|
||||
|
||||
; get gpio pin for relais 1
|
||||
tmp=pn[21]
|
||||
=>print relais 1 is on pin %tmp%
|
||||
|
||||
; pulse relais over raw gpio
|
||||
spin(tmp 1)
|
||||
delay(100)
|
||||
spin(tmp 0)
|
||||
|
||||
; raw pin level
|
||||
=>print level of gpio1 %pin[1]%
|
||||
|
||||
; pulse over tasmota cmd
|
||||
=>power 1
|
||||
delay(100)
|
||||
=>power 0
|
||||
|
||||
**\>T**
|
||||
|
||||
hum=BME280#Humidity
|
||||
temp=BME280#Temperature
|
||||
rssi=Wifi#RSSI
|
||||
string=SleepMode
|
||||
|
||||
; add to median filter
|
||||
median=temp
|
||||
; add to moving average filter
|
||||
movav=hum
|
||||
|
||||
; show filtered results
|
||||
=>print %median% %movav%
|
||||
|
||||
if chg[rssi]>0
|
||||
then =>print rssi changed to %rssi%
|
||||
endif
|
||||
|
||||
if temp\>30
|
||||
and hum\>70
|
||||
then =\>print damn hot!
|
||||
endif
|
||||
|
||||
**\>S**
|
||||
|
||||
; every second but not completely reliable time here
|
||||
; use upsecs and uptime or best t: for reliable timers
|
||||
|
||||
; call subrountines with parameters
|
||||
=#sub1("hallo")
|
||||
=#sub2(999)
|
||||
|
||||
; stop timer after expired
|
||||
if timer1==0
|
||||
then timer1=-1
|
||||
=>print timer1 expired
|
||||
endif
|
||||
|
||||
; auto counter with restart
|
||||
if count>=10
|
||||
then =>print 10 seconds over
|
||||
count=0
|
||||
endif
|
||||
|
||||
if upsecs%5==0
|
||||
then =\>print %upsecs% (every 5 seconds)
|
||||
endif
|
||||
|
||||
; not recommended for reliable timers
|
||||
timer+=1
|
||||
if timer\>=5
|
||||
then =\>print 5 seconds over (may be)
|
||||
timer=0
|
||||
endif
|
||||
|
||||
dimmer+=1
|
||||
if dimmer\>100
|
||||
then dimmer=0
|
||||
endif
|
||||
|
||||
=\>dimmer %dimmer%
|
||||
=\>WebSend %url% dimmer %dimmer%
|
||||
|
||||
; show on display
|
||||
dprec0
|
||||
=\>displaytext [c1l1f1s2p20] dimmer=%dimmer%
|
||||
|
||||
=\>print %upsecs% %uptime% %time% %sunrise% %sunset% %tstamp%
|
||||
|
||||
if time\>sunset
|
||||
and time< sunrise
|
||||
then
|
||||
; night time
|
||||
if pwr[1]==0
|
||||
then =\>power1 1
|
||||
endif
|
||||
else
|
||||
; day time
|
||||
if pwr[1]\>0
|
||||
then =\>power1 0
|
||||
endif
|
||||
endif
|
||||
|
||||
; clr display on boot
|
||||
if boot\>0
|
||||
then =\>displaytext [z]
|
||||
endif
|
||||
|
||||
; frost warning
|
||||
if temp<0
|
||||
and mt<=0
|
||||
then =#sendmail("frost alert")
|
||||
; alarm only every 5 minutes
|
||||
mt=300
|
||||
=>mp3track 2
|
||||
endif
|
||||
|
||||
; var has been updated
|
||||
if upd[hello]>0
|
||||
then =>print %hello%
|
||||
endif
|
||||
|
||||
; send to Thingspeak every 60 seconds
|
||||
; average data in between
|
||||
if upsecs%60==0
|
||||
then
|
||||
ahum/=tcnt
|
||||
atemp/=tcnt
|
||||
=>Websend [184.106.153.149:80]/update?key=PYUZMVWCICBW492&field1=%atemp%&field2=%ahum%
|
||||
tcnt=0
|
||||
atemp=0
|
||||
ahum=0
|
||||
else
|
||||
ahum+=hum
|
||||
atemp+=temp
|
||||
tcnt+=1
|
||||
endif
|
||||
|
||||
hour=int(time/60)
|
||||
if chg[hour]>0
|
||||
then
|
||||
; exactly every hour
|
||||
=>print full hour reached
|
||||
endif
|
||||
|
||||
if time>5 {
|
||||
=>print more then 5 minutes after midnight
|
||||
} else {
|
||||
=>print less then 5 minutes after midnight
|
||||
}
|
||||
|
||||
|
||||
; publish abs hum every teleperiod time
|
||||
if mqtts>0
|
||||
and upsecs%tper==0
|
||||
then
|
||||
; calc abs humidity
|
||||
tmp=pow(2.718281828 (17.67\*temp)/(temp+243.5))
|
||||
tmp=(6.112\*tmp\*hum\*18.01534)/((273.15+temp)\*8.31447215)
|
||||
; publish median filtered value
|
||||
=>Publish tele/%topic%/SENSOR {"Script":{"abshum":%med(0 tmp)%}}
|
||||
endif
|
||||
|
||||
;switch case state machine
|
||||
switch state
|
||||
case 1
|
||||
=>print state=%state% , start
|
||||
state+=1
|
||||
case 2
|
||||
=>print state=%state%
|
||||
state+=1
|
||||
case 3
|
||||
=>print state=%state% , reset
|
||||
state=1
|
||||
ends
|
||||
|
||||
|
||||
; subroutines
|
||||
\#sub1(string)
|
||||
=>print sub1: %string%
|
||||
\#sub2(param)
|
||||
=>print sub2: %param%
|
||||
|
||||
\#sendmail(string)
|
||||
=>sendmail [smtp.gmail.com:465:user:passwd:<sender@gmail.de>:<rec@gmail.de>:alarm] %string%
|
||||
|
||||
**\>E**
|
||||
=\>print event executed!
|
||||
|
||||
|
||||
; check if switch changed state
|
||||
sw=sw[1]
|
||||
if chg[sw]>0
|
||||
then =\>power1 %sw%
|
||||
endif
|
||||
|
||||
hello="event occured"
|
||||
|
||||
; check for Color change (Color is a string)
|
||||
col=Color
|
||||
; color change needs 2 string vars
|
||||
if col!=ocol
|
||||
then ocol=col
|
||||
=>print color changed %col%
|
||||
endif
|
||||
|
||||
; or check change of color channels
|
||||
chan1=Channel[1]
|
||||
chan2=Channel[2]
|
||||
chan3=Channel[3]
|
||||
|
||||
if chg[chan1]>0
|
||||
or chg[chan2]>0
|
||||
or chg[chan3]>0
|
||||
then => color has changed
|
||||
endif
|
||||
|
||||
; compose color string for red
|
||||
col=hn(255)+hn(0)+hn(0)
|
||||
=>color %col%
|
||||
|
||||
**\>R**
|
||||
=\>print restarting now
|
||||
|
||||
**a real example**
|
||||
epaper 29 with sgp30 and bme280
|
||||
some vars are set from iobroker
|
||||
DisplayText substituted to save script space
|
||||
\>D
|
||||
hum=0
|
||||
temp=0
|
||||
press=0
|
||||
ahum=0
|
||||
tvoc=0
|
||||
eco2=0
|
||||
zwz=0
|
||||
wr1=0
|
||||
wr2=0
|
||||
wr3=0
|
||||
otmp=0
|
||||
pwl=0
|
||||
tmp=0
|
||||
DT="DisplayText"
|
||||
; preset units in case they are not available
|
||||
punit="hPa"
|
||||
tunit="C"
|
||||
|
||||
\>B
|
||||
;reset auto draw
|
||||
=>%DT% [zD0]
|
||||
;clr display and draw a frame
|
||||
=>%DT% [x0y20h296x0y40h296]
|
||||
|
||||
\>T
|
||||
; get tele vars
|
||||
temp=BME280#Temperature
|
||||
hum=BME280#Humidity
|
||||
press=BME280#Pressure
|
||||
tvoc=SGP30#TVOC
|
||||
eco2=SGP30#eCO2
|
||||
ahum=SGP30#aHumidity
|
||||
tunit=TempUnit
|
||||
punit=PressureUnit
|
||||
|
||||
\>S
|
||||
// update display every teleperiod time
|
||||
if upsecs%tper==0
|
||||
then
|
||||
dprec2
|
||||
=>%DT% [f1p7x0y5]%temp% %tunit%
|
||||
=>%DT% [p5x70y5]%hum% %%[x250y5t]
|
||||
=>%DT% [p11x140y5]%press% %punit%
|
||||
=>%DT% [p10x30y25]TVOC: %tvoc% ppb
|
||||
=>%DT% [p10x160y25]eCO2: %eco2% ppm
|
||||
=>%DT% [p10c26l5]ahum: %ahum% g^m3
|
||||
|
||||
dprec0
|
||||
=>%DT% [p25c1l5]WR 1 (Dach) : %wr1% W
|
||||
=>%DT% [p25c1l6]WR 2 (Garage): %-wr3% W
|
||||
=>%DT% [p25c1l7]WR 3 (Garten): %-wr2% W
|
||||
=>%DT% [p25c1l8]Aussentemperatur: %otmp% C
|
||||
=>%DT% [x170y95r120:30f2p6x185y100] %pwl% %%
|
||||
; now update screen
|
||||
=>%DT% [d]
|
||||
endif
|
||||
|
||||
|
||||
\>E
|
||||
|
||||
\>R
|
||||
|
||||
**another real example**
|
||||
ILI 9488 color LCD Display shows various energy graphs
|
||||
display switches on and off with proximity sensor
|
||||
BMP280 and vl5310x
|
||||
some vars are set from iobroker
|
||||
|
||||
**>D**
|
||||
temp=0
|
||||
press=0
|
||||
zwz=0
|
||||
wr1=0
|
||||
wr2=0
|
||||
wr3=0
|
||||
otmp=0
|
||||
pwl=0
|
||||
tmp=0
|
||||
dist=0
|
||||
DT="DisplayText"
|
||||
punit="hPa"
|
||||
tunit="C"
|
||||
hour=0
|
||||
|
||||
**>B**
|
||||
=>%DT% [z]
|
||||
|
||||
// define 2 graphs, 2. has 3 tracks
|
||||
=>%DT% [zCi1G2656:5:20:400:80:1440:-5000:5000:3Ci7f3x410y20]+5000 W[x410y95]-5000 W [Ci7f1x70y3] Zweirichtungsz~80hler - 24 Stunden
|
||||
=>%DT% [Ci1G2657:5:120:400:80:1440:0:5000:3Ci7f3x410y120]+5000 W[x410y195]0 W [Ci7f1x70y103] Wechselrichter 1-3 - 24 Stunden
|
||||
=>%DT% [Ci1G2658:5:120:400:80:1440:0:5000:16][Ci1G2659:5:120:400:80:1440:0:5000:5]
|
||||
=>%DT% [f1s1b0:260:260:100:50:2:11:4:2:Rel 1:b1:370:260:100:50:2:11:4:2:Dsp off:]
|
||||
=>mp3volume 100
|
||||
=>mp3track 4
|
||||
|
||||
**>T**
|
||||
; get some tele vars
|
||||
temp=BMP280#Temperature
|
||||
press=BMP280#Pressure
|
||||
tunit=TempUnit
|
||||
punit=PressureUnit
|
||||
dist=VL53L0X#Distance
|
||||
|
||||
; check proximity sensor to switch display on/off
|
||||
; to prevent burn in
|
||||
if dist>300
|
||||
then
|
||||
if pwr[2]>0
|
||||
then
|
||||
=>power2 0
|
||||
endif
|
||||
else
|
||||
if pwr[2]==0
|
||||
then
|
||||
=>power2 1
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
**>S**
|
||||
; update graph every teleperiod
|
||||
if upsecs%tper==0
|
||||
then
|
||||
dprec2
|
||||
=>%DT% [f1Ci3x40y260w30Ci1]
|
||||
=>%DT% [Ci7x120y220t]
|
||||
=>%DT% [Ci7x180y220T]
|
||||
=>%DT% [Ci7p8x120y240]%temp% %tunit%
|
||||
=>%DT% [Ci7x120y260]%press% %punit%
|
||||
=>%DT% [Ci7x120y280]%dist% mm
|
||||
dprec0
|
||||
=>%DT% [g0:%zwz%g1:%wr1%g2:%-wr2%g3:%-wr3%]
|
||||
if zwz>0
|
||||
then
|
||||
=>%DT% [p-8x410y55Ci2Bi0]%zwz% W
|
||||
else
|
||||
=>%DT% [p-8x410y55Ci3Bi0]%zwz% W
|
||||
endif
|
||||
=>%DT% [p-8x410y140Ci3Bi0]%wr1% W
|
||||
=>%DT% [p-8x410y155Ci16Bi0]%-wr2% W
|
||||
=>%DT% [p-8x410y170Ci5Bi0]%-wr3% W
|
||||
endif
|
||||
|
||||
; chime every full hour
|
||||
hour=int(time/60)
|
||||
if chg[hour]>0
|
||||
then =>mp3track 4
|
||||
endif
|
||||
|
||||
**>E**
|
||||
|
||||
**>R**
|
@ -513,6 +513,7 @@
|
||||
#define D_SENSOR_BUTTON "Бутон" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Реле" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Брояч" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -578,6 +579,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Tlačítko" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relé" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1",
|
||||
#define D_SENSOR_COUNTER "Počítadlo" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Button" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Button" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Button" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Botón" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relé" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Contador" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IR Rx"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Bouton" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relais" // Suffix "1i"
|
||||
#define D_SENSOR_LED "LED" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Compteur" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "RécptIR"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "לחצן" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "ממסר" // Suffix "1i"
|
||||
#define D_SENSOR_LED "לד" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "מונה" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Gomb" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relé" // Suffix "1i"
|
||||
#define D_SENSOR_LED "LED" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Számláló" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IR vevő"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Button" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Button" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Button" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relais" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Teller" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Przyci" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Przek" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Liczni" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Botão" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relé" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Contador" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Botão" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relé" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Contador" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Кнопка" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Реле" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Счетчик" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Tlačidlo" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relé" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1",
|
||||
#define D_SENSOR_COUNTER "Počítadlo" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Knapp" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relä" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Räknare" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Button" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Кнопка" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Реле" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Лічильник" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Button" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -512,6 +512,7 @@
|
||||
#define D_SENSOR_BUTTON "Button" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relay" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_LED_LINK "LedLink" // Suffix "i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Counter" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
@ -577,6 +578,7 @@
|
||||
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
|
||||
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
|
||||
#define D_SENSOR_ARIRFRCV "ALux IrRcv"
|
||||
#define D_SENSOR_ARIRFSEL "ALux IrSel"
|
||||
#define D_SENSOR_TXD "Serial Tx"
|
||||
#define D_SENSOR_RXD "Serial Rx"
|
||||
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
|
||||
|
@ -275,7 +275,8 @@
|
||||
#define USE_WEBSERVER // Enable web server and Wifi Manager (+66k code, +8k mem)
|
||||
#define WEB_PORT 80 // Web server Port for User and Admin mode
|
||||
#define WEB_USERNAME "admin" // Web server Admin mode user name
|
||||
#define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+22k code, +2k mem)
|
||||
#define USE_EMULATION_HUE // Enable Hue Bridge emulation for Alexa (+14k code, +2k mem common)
|
||||
#define USE_EMULATION_WEMO // Enable Belkin WeMo emulation for Alexa (+6k code, +2k mem common)
|
||||
|
||||
// -- mDNS ----------------------------------------
|
||||
#define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem)
|
||||
@ -288,8 +289,11 @@
|
||||
#define USE_SUNRISE // Add support for Sunrise and sunset tools (+16k)
|
||||
#define SUNRISE_DAWN_ANGLE DAWN_NORMAL // Select desired Dawn Angle from (DAWN_NORMAL, DAWN_CIVIL, DAWN_NAUTIC, DAWN_ASTRONOMIC)
|
||||
|
||||
// -- Rules ---------------------------------------
|
||||
#define USE_RULES // Add support for rules (+4k4 code)
|
||||
// -- Rules or Script ----------------------------
|
||||
// Select none or only one of the below defines
|
||||
#define USE_RULES // Add support for rules (+8k code)
|
||||
//#define USE_SCRIPT // Add support for script (+15k code)
|
||||
|
||||
// #define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem)
|
||||
// #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code)
|
||||
|
||||
@ -342,6 +346,7 @@
|
||||
// #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem)
|
||||
// #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code)
|
||||
// #define USE_SCD30 // Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code)
|
||||
#define USE_SPS30 // Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+1.7 code)
|
||||
#define USE_ADE7953 // Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5)
|
||||
|
||||
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
|
||||
|
@ -211,8 +211,9 @@ struct SYSCFG {
|
||||
uint8_t weblog_level; // 1AC
|
||||
uint8_t mqtt_fingerprint[2][20]; // 1AD
|
||||
|
||||
uint8_t free_1D5[20]; // 1D5 Free since 5.12.0e
|
||||
uint8_t free_1D5[19]; // 1D5 Free since 5.12.0e
|
||||
|
||||
uint8_t sps30_inuse_hours; // 1E8
|
||||
char mqtt_host[33]; // 1E9 - Keep together with below as being copied as one chunck with reset 6
|
||||
uint16_t mqtt_port; // 20A - Keep together
|
||||
char mqtt_client[33]; // 20C - Keep together
|
||||
@ -345,7 +346,7 @@ struct SYSCFG {
|
||||
uint16_t weight_max; // 7BE Total max weight in kilogram
|
||||
unsigned long weight_reference; // 7C0 Reference weight in gram
|
||||
unsigned long weight_calibration; // 7C4
|
||||
unsigned long energy_frequency_calibration; // 7C8
|
||||
unsigned long energy_frequency_calibration; // 7C8 also used by HX711 to save last weight
|
||||
uint16_t web_refresh; // 7CC
|
||||
char mems[MAX_RULE_MEMS][10]; // 7CE
|
||||
char rules[MAX_RULE_SETS][MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m, 3 x 512 bytes in v5.14.0b
|
||||
|
@ -444,6 +444,7 @@ void SettingsSaveAll(void)
|
||||
Settings.power = 0;
|
||||
}
|
||||
XsnsCall(FUNC_SAVE_BEFORE_RESTART);
|
||||
XdrvCall(FUNC_SAVE_BEFORE_RESTART);
|
||||
#ifdef USE_EEPROM
|
||||
EepromCommit();
|
||||
#endif
|
||||
|
@ -143,7 +143,10 @@ uint8_t backlog_pointer = 0; // Command backlog pointer
|
||||
uint8_t sleep; // Current copy of Settings.sleep
|
||||
uint8_t blinkspeed = 1; // LED blink rate
|
||||
uint8_t pin[GPIO_MAX]; // Possible pin configurations
|
||||
uint8_t leds_present = 0; // Max number of LED supported
|
||||
uint8_t led_inverted = 0; // LED inverted flag (1 = (0 = On, 1 = Off))
|
||||
uint8_t led_power = 0; // LED power state
|
||||
uint8_t ledlnk_inverted = 0; // Link LED inverted flag (1 = (0 = On, 1 = Off))
|
||||
uint8_t pwm_inverted = 0; // PWM inverted flag (1 = inverted)
|
||||
uint8_t counter_no_pullup = 0; // Counter input pullup flag (1 = No pullup)
|
||||
uint8_t energy_flg = 0; // Energy monitor configured
|
||||
@ -370,19 +373,56 @@ void SetDevicePower(power_t rpower, int source)
|
||||
}
|
||||
}
|
||||
|
||||
void SetLedPowerIdx(uint8_t led, uint8_t state)
|
||||
{
|
||||
if ((99 == pin[GPIO_LEDLNK]) && (0 == led)) { // Legacy - LED1 is link led only if LED2 is present
|
||||
if (pin[GPIO_LED2] < 99) { led = 1; }
|
||||
}
|
||||
if (pin[GPIO_LED1 + led] < 99) {
|
||||
uint8_t mask = 1 << led;
|
||||
if (state) {
|
||||
state = 1;
|
||||
led_power |= mask;
|
||||
} else {
|
||||
led_power &= (0xFF ^ mask);
|
||||
}
|
||||
digitalWrite(pin[GPIO_LED1 + led], bitRead(led_inverted, led) ? !state : state);
|
||||
}
|
||||
}
|
||||
|
||||
void SetLedPower(uint8_t state)
|
||||
{
|
||||
if (state) { state = 1; }
|
||||
if (99 == pin[GPIO_LEDLNK]) { // Legacy - Only use LED1 and/or LED2
|
||||
SetLedPowerIdx(0, state);
|
||||
} else {
|
||||
power_t mask = 1;
|
||||
for (uint8_t i = 0; i < leds_present; i++) { // Map leds to power
|
||||
bool tstate = (power & mask);
|
||||
SetLedPowerIdx(i, tstate);
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t led_pin = 0;
|
||||
if (pin[GPIO_LED2] < 99) { led_pin = 1; }
|
||||
digitalWrite(pin[GPIO_LED1 + led_pin], (bitRead(led_inverted, led_pin)) ? !state : state);
|
||||
void SetLedPowerAll(uint8_t state)
|
||||
{
|
||||
for (uint8_t i = 0; i < leds_present; i++) {
|
||||
SetLedPowerIdx(i, state);
|
||||
}
|
||||
}
|
||||
|
||||
void SetLedLink(uint8_t state)
|
||||
{
|
||||
if (state) { state = 1; }
|
||||
digitalWrite(pin[GPIO_LED1], (bitRead(led_inverted, 0)) ? !state : state);
|
||||
uint8_t led_pin = pin[GPIO_LEDLNK];
|
||||
uint8_t led_inv = ledlnk_inverted;
|
||||
if (99 == led_pin) { // Legacy - LED1 is status
|
||||
led_pin = pin[GPIO_LED1];
|
||||
led_inv = bitRead(led_inverted, 0);
|
||||
}
|
||||
if (led_pin < 99) {
|
||||
if (state) { state = 1; }
|
||||
digitalWrite(led_pin, (led_inv) ? !state : state);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t GetFanspeed(void)
|
||||
@ -1422,7 +1462,8 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
|
||||
}
|
||||
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.altitude);
|
||||
}
|
||||
else if (CMND_LEDPOWER == command_code) {
|
||||
else if ((CMND_LEDPOWER == command_code) && (index > 0) && (index <= MAX_LEDS)) {
|
||||
/*
|
||||
if ((payload >= 0) && (payload <= 2)) {
|
||||
Settings.ledstate &= 8;
|
||||
switch (payload) {
|
||||
@ -1435,15 +1476,83 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
|
||||
break;
|
||||
}
|
||||
blinks = 0;
|
||||
SetLedPower(Settings.ledstate &8);
|
||||
SetLedPowerIdx(index -1, Settings.ledstate &8);
|
||||
}
|
||||
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(bitRead(Settings.ledstate, 3)));
|
||||
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, GetStateText(bitRead(Settings.ledstate, 3)));
|
||||
*/
|
||||
/*
|
||||
if (99 == pin[GPIO_LEDLNK]) {
|
||||
if ((payload >= 0) && (payload <= 2)) {
|
||||
Settings.ledstate &= 8;
|
||||
switch (payload) {
|
||||
case 0: // Off
|
||||
case 1: // On
|
||||
Settings.ledstate = payload << 3;
|
||||
break;
|
||||
case 2: // Toggle
|
||||
Settings.ledstate ^= 8;
|
||||
break;
|
||||
}
|
||||
blinks = 0;
|
||||
SetLedPower(Settings.ledstate &8);
|
||||
}
|
||||
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(bitRead(Settings.ledstate, 3)));
|
||||
} else {
|
||||
if ((payload >= 0) && (payload <= 2)) {
|
||||
Settings.ledstate &= 8; // Disable power control
|
||||
uint8_t mask = 1 << (index -1); // Led to control
|
||||
switch (payload) {
|
||||
case 0: // Off
|
||||
led_power &= (0xFF ^ mask);
|
||||
case 1: // On
|
||||
led_power |= mask;
|
||||
break;
|
||||
case 2: // Toggle
|
||||
led_power ^= mask;
|
||||
break;
|
||||
}
|
||||
blinks = 0;
|
||||
SetLedPowerIdx(index -1, (led_power & mask));
|
||||
}
|
||||
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, GetStateText(bitRead(led_power, index -1)));
|
||||
}
|
||||
*/
|
||||
if (99 == pin[GPIO_LEDLNK]) { index = 1; }
|
||||
if ((payload >= 0) && (payload <= 2)) {
|
||||
Settings.ledstate &= 8; // Disable power control
|
||||
uint8_t mask = 1 << (index -1); // Led to control
|
||||
switch (payload) {
|
||||
case 0: // Off
|
||||
led_power &= (0xFF ^ mask);
|
||||
Settings.ledstate = 0;
|
||||
break;
|
||||
case 1: // On
|
||||
led_power |= mask;
|
||||
Settings.ledstate = 8;
|
||||
break;
|
||||
case 2: // Toggle
|
||||
led_power ^= mask;
|
||||
Settings.ledstate ^= 8;
|
||||
break;
|
||||
}
|
||||
blinks = 0;
|
||||
if (99 == pin[GPIO_LEDLNK]) {
|
||||
SetLedPower(Settings.ledstate &8);
|
||||
} else {
|
||||
SetLedPowerIdx(index -1, (led_power & mask));
|
||||
}
|
||||
}
|
||||
uint8_t state = bitRead(led_power, index -1);
|
||||
if (99 == pin[GPIO_LEDLNK]) {
|
||||
state = bitRead(Settings.ledstate, 3);
|
||||
}
|
||||
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, GetStateText(state));
|
||||
}
|
||||
else if (CMND_LEDSTATE == command_code) {
|
||||
if ((payload >= 0) && (payload < MAX_LED_OPTION)) {
|
||||
Settings.ledstate = payload;
|
||||
if (!Settings.ledstate) {
|
||||
SetLedPower(0);
|
||||
SetLedPowerAll(0);
|
||||
SetLedLink(0);
|
||||
}
|
||||
}
|
||||
@ -1469,7 +1578,12 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
|
||||
Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_UNKNOWN "\"}"));
|
||||
type = (char*)topicBuf;
|
||||
}
|
||||
if (mqtt_data[0] != '\0') { MqttPublishPrefixTopic_P(RESULT_OR_STAT, type); }
|
||||
if (mqtt_data[0] != '\0') {
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
|
||||
#ifdef USE_SCRIPT
|
||||
XdrvRulesProcess();
|
||||
#endif
|
||||
}
|
||||
fallback_topic_flag = false;
|
||||
}
|
||||
|
||||
@ -1838,6 +1952,9 @@ void MqttPublishTeleState(void)
|
||||
mqtt_data[0] = '\0';
|
||||
MqttShowState();
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN);
|
||||
#ifdef USE_SCRIPT
|
||||
RulesTeleperiod(); // Allow rule based HA messages
|
||||
#endif // USE_SCRIPT
|
||||
}
|
||||
|
||||
bool MqttShowSensor(void)
|
||||
@ -1922,7 +2039,7 @@ void PerformEverySecond(void)
|
||||
mqtt_data[0] = '\0';
|
||||
if (MqttShowSensor()) {
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
|
||||
#ifdef USE_RULES
|
||||
#if defined(USE_RULES) || defined(USE_SCRIPT)
|
||||
RulesTeleperiod(); // Allow rule based HA messages
|
||||
#endif // USE_RULES
|
||||
}
|
||||
@ -2025,8 +2142,6 @@ void Every250mSeconds(void)
|
||||
}
|
||||
}
|
||||
if ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) {
|
||||
// if ( (!Settings.flag.global_state && global_state.data) || ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) ) {
|
||||
// SetLedPower(blinkstate); // Set led on or off
|
||||
SetLedLink(blinkstate); // Set led on or off
|
||||
}
|
||||
if (!blinkstate) {
|
||||
@ -2176,7 +2291,9 @@ void Every250mSeconds(void)
|
||||
SettingsDefault();
|
||||
restart_flag = 2;
|
||||
}
|
||||
SettingsSaveAll();
|
||||
if (2 == restart_flag) {
|
||||
SettingsSaveAll();
|
||||
}
|
||||
restart_flag--;
|
||||
if (restart_flag <= 0) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING));
|
||||
@ -2449,6 +2566,10 @@ void GpioInit(void)
|
||||
bitSet(led_inverted, mpin - GPIO_LED1_INV);
|
||||
mpin -= (GPIO_LED1_INV - GPIO_LED1);
|
||||
}
|
||||
else if (mpin == GPIO_LEDLNK_INV) {
|
||||
ledlnk_inverted = 1;
|
||||
mpin -= (GPIO_LEDLNK_INV - GPIO_LEDLNK);
|
||||
}
|
||||
else if ((mpin >= GPIO_PWM1_INV) && (mpin < (GPIO_PWM1_INV + MAX_PWMS))) {
|
||||
bitSet(pwm_inverted, mpin - GPIO_PWM1_INV);
|
||||
mpin -= (GPIO_PWM1_INV - GPIO_PWM1);
|
||||
@ -2560,10 +2681,24 @@ void GpioInit(void)
|
||||
|
||||
for (uint8_t i = 0; i < MAX_LEDS; i++) {
|
||||
if (pin[GPIO_LED1 +i] < 99) {
|
||||
pinMode(pin[GPIO_LED1 +i], OUTPUT);
|
||||
digitalWrite(pin[GPIO_LED1 +i], bitRead(led_inverted, i));
|
||||
#ifdef USE_ARILUX_RF
|
||||
if ((3 == i) && (leds_present < 2) && (99 == pin[GPIO_ARIRFSEL])) {
|
||||
pin[GPIO_ARIRFSEL] = pin[GPIO_LED4]; // Legacy support where LED4 was Arilux RF enable
|
||||
pin[GPIO_LED4] = 99;
|
||||
} else {
|
||||
#endif
|
||||
pinMode(pin[GPIO_LED1 +i], OUTPUT);
|
||||
leds_present++;
|
||||
digitalWrite(pin[GPIO_LED1 +i], bitRead(led_inverted, i));
|
||||
#ifdef USE_ARILUX_RF
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (pin[GPIO_LEDLNK] < 99) {
|
||||
pinMode(pin[GPIO_LEDLNK], OUTPUT);
|
||||
digitalWrite(pin[GPIO_LEDLNK], ledlnk_inverted);
|
||||
}
|
||||
|
||||
ButtonInit();
|
||||
SwitchInit();
|
||||
@ -2645,6 +2780,13 @@ void setup(void)
|
||||
sleep = Settings.sleep;
|
||||
#ifndef USE_EMULATION
|
||||
Settings.flag2.emulation = 0;
|
||||
#else
|
||||
#ifndef USE_EMULATION_WEMO
|
||||
if (EMUL_WEMO == Settings.flag2.emulation) { Settings.flag2.emulation = 0; }
|
||||
#endif
|
||||
#ifndef USE_EMULATION_HUE
|
||||
if (EMUL_HUE == Settings.flag2.emulation) { Settings.flag2.emulation = 0; }
|
||||
#endif
|
||||
#endif // USE_EMULATION
|
||||
|
||||
if (Settings.param[P_BOOT_LOOP_OFFSET]) {
|
||||
|
@ -46,6 +46,13 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
||||
* Default global defines
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_EMULATION_HUE
|
||||
#define USE_EMULATION
|
||||
#endif
|
||||
#ifdef USE_EMULATION_WEMO
|
||||
#define USE_EMULATION
|
||||
#endif
|
||||
|
||||
#ifndef MODULE
|
||||
#define MODULE SONOFF_BASIC // [Module] Select default model
|
||||
#endif
|
||||
|
@ -171,7 +171,7 @@ enum UserSelectablePins {
|
||||
GPIO_DCKI, // my92x1 CLK input
|
||||
GPIO_CSE7766_TX, // CSE7766 Serial interface (S31 and Pow R2)
|
||||
GPIO_CSE7766_RX, // CSE7766 Serial interface (S31 and Pow R2)
|
||||
GPIO_ARIRFRCV, // AliLux RF Receive input
|
||||
GPIO_ARIRFRCV, // AriLux RF Receive input
|
||||
GPIO_TXD, // Serial interface
|
||||
GPIO_RXD, // Serial interface
|
||||
GPIO_ROT1A, // Rotary switch1 A Pin
|
||||
@ -181,6 +181,9 @@ enum UserSelectablePins {
|
||||
GPIO_HRE_CLOCK, // Clock/Power line for HR-E Water Meter
|
||||
GPIO_HRE_DATA, // Data line for HR-E Water Meter
|
||||
GPIO_ADE7953_IRQ, // ADE7953 IRQ
|
||||
GPIO_LEDLNK, // Link led
|
||||
GPIO_LEDLNK_INV, // Inverted link led
|
||||
GPIO_ARIRFSEL, // Arilux RF Receive input selected
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
// Programmer selectable GPIO functionality
|
||||
@ -246,6 +249,8 @@ const char kSensorNames[] PROGMEM =
|
||||
D_SENSOR_ROTARY "1a|" D_SENSOR_ROTARY "1b|" D_SENSOR_ROTARY "2a|" D_SENSOR_ROTARY "2b|"
|
||||
D_SENSOR_HRE_CLOCK "|" D_SENSOR_HRE_DATA "|"
|
||||
D_SENSOR_ADE7953_IRQ "|"
|
||||
D_SENSOR_LED_LINK "|" D_SENSOR_LED_LINK "i|"
|
||||
D_SENSOR_ARIRFSEL "|"
|
||||
;
|
||||
|
||||
// User selectable ADC0 functionality
|
||||
@ -448,6 +453,8 @@ const uint8_t kGpioNiceList[] PROGMEM = {
|
||||
GPIO_LED3_INV,
|
||||
GPIO_LED4,
|
||||
GPIO_LED4_INV,
|
||||
GPIO_LEDLNK, // Link led
|
||||
GPIO_LEDLNK_INV, // Inverted link led
|
||||
GPIO_PWM1, // RGB Red or C Cold White
|
||||
GPIO_PWM1_INV,
|
||||
GPIO_PWM2, // RGB Green or CW Warm White
|
||||
@ -616,7 +623,8 @@ const uint8_t kGpioNiceList[] PROGMEM = {
|
||||
GPIO_ROT2B, // Rotary switch2 B Pin
|
||||
#endif
|
||||
#ifdef USE_ARILUX_RF
|
||||
GPIO_ARIRFRCV, // AliLux RF Receive input
|
||||
GPIO_ARIRFRCV, // AriLux RF Receive input
|
||||
GPIO_ARIRFSEL, // Arilux RF Receive input selected
|
||||
#endif
|
||||
#ifdef USE_HRE
|
||||
GPIO_HRE_CLOCK,
|
||||
@ -1109,9 +1117,9 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
0, 0
|
||||
},
|
||||
{ "Huafan SS", // Hua Fan Smart Socket (ESP8266) - like Sonoff Pow
|
||||
GPIO_LED1_INV, // GPIO00 Blue Led (0 = On, 1 = Off) - Link status
|
||||
GPIO_LEDLNK_INV, // GPIO00 Blue Led (0 = On, 1 = Off) - Link status
|
||||
0, 0,
|
||||
GPIO_LED2_INV, // GPIO03 Red Led (0 = On, 1 = Off) - Power status
|
||||
GPIO_LED1_INV, // GPIO03 Red Led (0 = On, 1 = Off) - Power status
|
||||
GPIO_KEY1, // GPIO04 Button
|
||||
GPIO_REL1_INV, // GPIO05 Relay (0 = On, 1 = Off)
|
||||
// GPIO06 (SD_CLK Flash)
|
||||
@ -1304,7 +1312,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
GPIO_PWM3, // GPIO12 RGB LED Blue
|
||||
GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White as used on Arilux LC10)
|
||||
GPIO_PWM1, // GPIO14 RGB LED Red
|
||||
GPIO_LED4_INV, // GPIO15 RF receiver control (Arilux LC10)
|
||||
GPIO_ARIRFSEL, // GPIO15 RF receiver control (Arilux LC10)
|
||||
0, 0
|
||||
},
|
||||
{ "Luani HVIO", // ESP8266_HVIO
|
||||
@ -1350,7 +1358,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
// (PwmFrequency 1111Hz)
|
||||
GPIO_KEY1, // GPIO00 Optional Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
GPIO_LED4_INV, // GPIO02 RF receiver control
|
||||
GPIO_ARIRFSEL, // GPIO02 RF receiver control
|
||||
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||
GPIO_ARIRFRCV, // GPIO04 IR or RF receiver (optional)
|
||||
GPIO_PWM1, // GPIO05 RGB LED Red
|
||||
@ -1370,7 +1378,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
// (PwmFrequency 540Hz)
|
||||
GPIO_KEY1, // GPIO00 Optional Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
GPIO_LED4_INV, // GPIO02 RF receiver control
|
||||
GPIO_ARIRFSEL, // GPIO02 RF receiver control
|
||||
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||
GPIO_PWM2, // GPIO04 RGB LED Green
|
||||
GPIO_PWM1, // GPIO05 RGB LED Red
|
||||
@ -1498,9 +1506,9 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
// https://www.amazon.de/Steckdose-Homecube-intelligente-Verbrauchsanzeige-funktioniert/dp/B076Q2LKHG/ref=sr_1_fkmr0_1
|
||||
// https://www.amazon.de/Intelligente-Stromverbrauch-Fernsteurung-Schaltbare-Energieklasse/dp/B076WZQS4S/ref=sr_1_1
|
||||
// https://www.aliexpress.com/store/product/BlitzWolf-BW-SHP6-EU-Plug-Metering-Version-WIFI-Smart-Socket-220V-240V-10A-Work-with-Amazon/1965360_32945504669.html
|
||||
GPIO_LED2_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status
|
||||
GPIO_LED1_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status
|
||||
GPIO_LEDLNK_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status
|
||||
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||
0,
|
||||
GPIO_HJL_CF, // GPIO05 BL0937 or HJL-01 CF power
|
||||
@ -1624,7 +1632,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
0,
|
||||
GPIO_KEY1, // GPIO01 Serial TXD and Button
|
||||
0,
|
||||
GPIO_LED2_INV, // GPIO03 Serial RXD and Red Led (0 = On, 1 = Off) - Power status
|
||||
GPIO_LED1_INV, // GPIO03 Serial RXD and Red Led (0 = On, 1 = Off) - Power status
|
||||
GPIO_HJL_CF, // GPIO04 BL0937 or HJL-01 CF power
|
||||
GPIO_NRG_CF1, // GPIO05 BL0937 or HJL-01 CF1 current / voltage
|
||||
// GPIO06 (SD_CLK Flash)
|
||||
@ -1634,7 +1642,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285)
|
||||
// GPIO11 (SD_CMD Flash)
|
||||
GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage)
|
||||
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link status
|
||||
GPIO_LEDLNK_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link status
|
||||
GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On)
|
||||
0, 0, 0
|
||||
},
|
||||
@ -1678,7 +1686,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
},
|
||||
{ "Gosund SP1 v23", // https://www.amazon.de/gp/product/B0777BWS1P
|
||||
0,
|
||||
GPIO_LED1_INV, // GPIO01 Serial RXD and LED1 (blue) inv - Link status
|
||||
GPIO_LEDLNK_INV, // GPIO01 Serial RXD and LED1 (blue) inv - Link status
|
||||
0,
|
||||
GPIO_KEY1, // GPIO03 Serial TXD and Button
|
||||
GPIO_HJL_CF, // GPIO04 BL0937 or HJL-01 CF power
|
||||
@ -1690,7 +1698,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285)
|
||||
// GPIO11 (SD_CMD Flash)
|
||||
GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage)
|
||||
GPIO_LED2_INV, // GPIO13 LED2 (red) inv - Power status
|
||||
GPIO_LED1_INV, // GPIO13 LED2 (red) inv - Power status
|
||||
GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On)
|
||||
0, 0, 0
|
||||
},
|
||||
@ -1728,8 +1736,8 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285)
|
||||
// GPIO11 (SD_CMD Flash)
|
||||
GPIO_NRG_SEL_INV, // GPIO12 HLW8012 CF Sel output (0 = Voltage)
|
||||
GPIO_LED2_INV, // GPIO13 Red Led (0 = On, 1 = Off) - Power status
|
||||
GPIO_LED1_INV, // GPIO14 Blue Led (0 = On, 1 = Off) - Link status
|
||||
GPIO_LED1_INV, // GPIO13 Red Led (0 = On, 1 = Off) - Power status
|
||||
GPIO_LEDLNK_INV, // GPIO14 Blue Led (0 = On, 1 = Off) - Link status
|
||||
GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On)
|
||||
0, 0
|
||||
},
|
||||
@ -1757,9 +1765,9 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
{ "Teckin US", // Teckin SP20 US with Energy Monitoring
|
||||
// https://www.amazon.com/Outlet-Compatible-Monitoring-Function-Required/dp/B079Q5W22B
|
||||
// https://www.amazon.com/Outlet-ZOOZEE-Monitoring-Function-Compatible/dp/B07J2LR5KN
|
||||
GPIO_LED2_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status
|
||||
GPIO_LED1_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status
|
||||
0,
|
||||
GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status
|
||||
GPIO_LEDLNK_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status
|
||||
0,
|
||||
GPIO_REL1, // GPIO04 Relay (0 = Off, 1 = On)
|
||||
GPIO_HJL_CF, // GPIO05 BL0937 or HJL-01 CF power
|
||||
@ -1809,8 +1817,8 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285)
|
||||
0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285)
|
||||
// GPIO11 (SD_CMD Flash)
|
||||
GPIO_LED1_INV, // GPIO12 Green LED - Link status
|
||||
GPIO_LED2, // GPIO13 Red LED - Power status
|
||||
GPIO_LEDLNK_INV, // GPIO12 Green LED - Link status
|
||||
GPIO_LED1, // GPIO13 Red LED - Power status
|
||||
0, 0, 0, 0
|
||||
},
|
||||
{ "YTF IR Bridge", // https://www.aliexpress.com/item/Tuya-universal-Smart-IR-Hub-remote-control-Voice-Control-AC-TV-Work-With-Alexa-Google-Home/32951202513.html
|
||||
@ -1854,7 +1862,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
},
|
||||
{ "KA10", // SMANERGY KA10 (ESP8285 - BL0937 Energy Monitoring) - https://www.amazon.es/dp/B07MBTCH2Y
|
||||
0, // GPIO00
|
||||
GPIO_LED1_INV, // GPIO01 Blue LED - Link status
|
||||
GPIO_LEDLNK_INV, // GPIO01 Blue LED - Link status
|
||||
0, // GPIO02
|
||||
GPIO_KEY1, // GPIO03 Button
|
||||
GPIO_HJL_CF, // GPIO04 BL0937 CF power
|
||||
@ -1866,7 +1874,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285)
|
||||
// GPIO11 (SD_CMD Flash)
|
||||
GPIO_NRG_SEL_INV, // GPIO12 BL0937 Sel output (1 = Voltage)
|
||||
GPIO_LED2, // GPIO13 Red LED - Power status
|
||||
GPIO_LED1, // GPIO13 Red LED - Power status
|
||||
GPIO_REL1, // GPIO14 Relay 1
|
||||
0, 0, 0
|
||||
},
|
||||
@ -1923,7 +1931,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
},
|
||||
{ "WAGA CHCZ02MB", // WAGA life CHCZ02MB (HJL-01 Energy Monitoring)
|
||||
// https://www.ebay.com/itm/332595697006
|
||||
GPIO_LED2_INV, // GPIO00 Red LED
|
||||
GPIO_LED1_INV, // GPIO00 Red LED
|
||||
0, // GPIO01 Serial RXD
|
||||
0, // GPIO02
|
||||
GPIO_NRG_SEL_INV, // GPIO03 HJL-01 Sel output (1 = Voltage)
|
||||
@ -1938,7 +1946,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
GPIO_REL1, // GPIO12 Relay
|
||||
GPIO_KEY1, // GPIO13 Button
|
||||
GPIO_NRG_CF1, // GPIO14 HJL-01 CF1 voltage / current
|
||||
GPIO_LED1_INV, // GPIO15 Blue LED - Link status
|
||||
GPIO_LEDLNK_INV, // GPIO15 Blue LED - Link status
|
||||
0, 0
|
||||
},
|
||||
{ "SYF05", // Sunyesmart SYF05 (a.k.a. Fcmila) = TYWE3S + SM16726
|
||||
@ -2070,7 +2078,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
GPIO_PWM3, // GPIO12 RGB LED Blue
|
||||
GPIO_PWM4, // GPIO13 RGBW LED White
|
||||
GPIO_PWM1, // GPIO14 RGB LED Red
|
||||
GPIO_LED4_INV, // GPIO15 RF receiver control
|
||||
GPIO_ARIRFSEL, // GPIO15 RF receiver control
|
||||
0, 0
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,6 @@
|
||||
#ifndef _SONOFF_VERSION_H_
|
||||
#define _SONOFF_VERSION_H_
|
||||
|
||||
const uint32_t VERSION = 0x0605000B;
|
||||
const uint32_t VERSION = 0x0605000C;
|
||||
|
||||
#endif // _SONOFF_VERSION_H_
|
||||
|
@ -674,6 +674,42 @@ double FastPrecisePow(double a, double b)
|
||||
return r * u.d;
|
||||
}
|
||||
|
||||
float FastPrecisePowf(const float x, const float y)
|
||||
{
|
||||
// return (float)(pow((double)x, (double)y));
|
||||
return (float)FastPrecisePow(x, y);
|
||||
}
|
||||
|
||||
double TaylorLog(double x)
|
||||
{
|
||||
// https://stackoverflow.com/questions/46879166/finding-the-natural-logarithm-of-a-number-using-taylor-series-in-c
|
||||
|
||||
if (x <= 0.0) { return NAN; }
|
||||
double z = (x + 1) / (x - 1); // We start from power -1, to make sure we get the right power in each iteration;
|
||||
double step = ((x - 1) * (x - 1)) / ((x + 1) * (x + 1)); // Store step to not have to calculate it each time
|
||||
double totalValue = 0;
|
||||
double powe = 1;
|
||||
double y;
|
||||
for (int count = 0; count < 10; count++) { // Experimental number of 10 iterations
|
||||
z *= step;
|
||||
y = (1 / powe) * z;
|
||||
totalValue = totalValue + y;
|
||||
powe = powe + 2;
|
||||
}
|
||||
totalValue *= 2;
|
||||
/*
|
||||
char logxs[33];
|
||||
dtostrfd(x, 8, logxs);
|
||||
double log1 = log(x);
|
||||
char log1s[33];
|
||||
dtostrfd(log1, 8, log1s);
|
||||
char log2s[33];
|
||||
dtostrfd(totalValue, 8, log2s);
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("input %s, log %s, taylor %s"), logxs, log1s, log2s);
|
||||
*/
|
||||
return totalValue;
|
||||
}
|
||||
|
||||
uint32_t SqrtInt(uint32_t num)
|
||||
{
|
||||
if (num <= 1) {
|
||||
|
@ -49,8 +49,8 @@ void GetFeatures(void)
|
||||
#ifdef WEBSERVER_ADVERTISE
|
||||
feature_drv1 |= 0x00000100; // xdrv_02_webserver.ino
|
||||
#endif
|
||||
#ifdef USE_EMULATION
|
||||
feature_drv1 |= 0x00000200; // xplg_wemohue.ino
|
||||
#ifdef USE_EMULATION_HUE
|
||||
feature_drv1 |= 0x00000200; // xdrv_20_hue.ino
|
||||
#endif
|
||||
#if (MQTT_LIBRARY_TYPE == MQTT_PUBSUBCLIENT)
|
||||
feature_drv1 |= 0x00000400; // xdrv_01_mqtt.ino
|
||||
@ -180,9 +180,13 @@ void GetFeatures(void)
|
||||
#ifdef USE_SM16716
|
||||
feature_drv2 |= 0x00040000; // xdrv_04_light.ino
|
||||
#endif
|
||||
#ifdef USE_SCRIPT
|
||||
feature_drv2 |= 0x00080000; // xdrv_10_scripter.ino
|
||||
#endif
|
||||
#ifdef USE_EMULATION_WEMO
|
||||
feature_drv2 |= 0x00100000; // xdrv_21_wemo.ino
|
||||
#endif
|
||||
|
||||
// feature_drv2 |= 0x00080000;
|
||||
// feature_drv2 |= 0x00100000;
|
||||
// feature_drv2 |= 0x00200000;
|
||||
// feature_drv2 |= 0x00400000;
|
||||
|
||||
|
136
sonoff/support_udp.ino
Normal file
136
sonoff/support_udp.ino
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
support_udp.ino - Udp support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Heiko Krupp and Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_EMULATION
|
||||
|
||||
#define UDP_BUFFER_SIZE 200 // Max UDP buffer size needed for M-SEARCH message
|
||||
#define UDP_MSEARCH_SEND_DELAY 1500 // Delay in ms before M-Search response is send
|
||||
|
||||
#include <Ticker.h>
|
||||
Ticker TickerMSearch;
|
||||
|
||||
IPAddress udp_remote_ip; // M-Search remote IP address
|
||||
uint16_t udp_remote_port; // M-Search remote port
|
||||
|
||||
bool udp_connected = false;
|
||||
bool udp_response_mutex = false; // M-Search response mutex to control re-entry
|
||||
|
||||
/*********************************************************************************************\
|
||||
* UPNP/SSDP search targets
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char URN_BELKIN_DEVICE[] PROGMEM = "urn:belkin:device:**";
|
||||
const char UPNP_ROOTDEVICE[] PROGMEM = "upnp:rootdevice";
|
||||
const char SSDPSEARCH_ALL[] PROGMEM = "ssdpsearch:all";
|
||||
const char SSDP_ALL[] PROGMEM = "ssdp:all";
|
||||
|
||||
/*********************************************************************************************\
|
||||
* UDP support routines
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool UdpDisconnect(void)
|
||||
{
|
||||
if (udp_connected) {
|
||||
PortUdp.flush();
|
||||
WiFiUDP::stopAll();
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_MULTICAST_DISABLED));
|
||||
udp_connected = false;
|
||||
}
|
||||
return udp_connected;
|
||||
}
|
||||
|
||||
bool UdpConnect(void)
|
||||
{
|
||||
if (!udp_connected) {
|
||||
// Simple Service Discovery Protocol (SSDP)
|
||||
if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), 1900)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED));
|
||||
udp_response_mutex = false;
|
||||
udp_connected = true;
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_JOIN_FAILED));
|
||||
udp_connected = false;
|
||||
}
|
||||
}
|
||||
return udp_connected;
|
||||
}
|
||||
|
||||
void PollUdp(void)
|
||||
{
|
||||
if (udp_connected) {
|
||||
if (PortUdp.parsePacket()) {
|
||||
char packet_buffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP/SSDP packet
|
||||
|
||||
int len = PortUdp.read(packet_buffer, UDP_BUFFER_SIZE -1);
|
||||
packet_buffer[len] = 0;
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len);
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer);
|
||||
|
||||
// Simple Service Discovery Protocol (SSDP)
|
||||
if (devices_present && !udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) {
|
||||
udp_response_mutex = true;
|
||||
|
||||
udp_remote_ip = PortUdp.remoteIP();
|
||||
udp_remote_port = PortUdp.remotePort();
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: M-SEARCH Packet from %s:%d\n%s"),
|
||||
// udp_remote_ip.toString().c_str(), udp_remote_port, packet_buffer);
|
||||
|
||||
uint32_t response_delay = UDP_MSEARCH_SEND_DELAY + ((millis() &0x7) * 100); // 1500 - 2200 msec
|
||||
|
||||
LowerCase(packet_buffer, packet_buffer);
|
||||
RemoveSpace(packet_buffer);
|
||||
|
||||
#ifdef USE_EMULATION_WEMO
|
||||
if (EMUL_WEMO == Settings.flag2.emulation) {
|
||||
if (strstr_P(packet_buffer, URN_BELKIN_DEVICE) != nullptr) { // type1 echo dot 2g, echo 1g's
|
||||
TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 1);
|
||||
return;
|
||||
}
|
||||
else if ((strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || // type2 Echo 2g (echo & echo plus)
|
||||
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
|
||||
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
|
||||
TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // USE_EMULATION_WEMO
|
||||
|
||||
#ifdef USE_EMULATION_HUE
|
||||
if (EMUL_HUE == Settings.flag2.emulation) {
|
||||
if ((strstr_P(packet_buffer, PSTR(":device:basic:1")) != nullptr) ||
|
||||
(strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) ||
|
||||
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
|
||||
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
|
||||
TickerMSearch.attach_ms(response_delay, HueRespondToMSearch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // USE_EMULATION_HUE
|
||||
|
||||
udp_response_mutex = false;
|
||||
}
|
||||
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USE_EMULATION
|
@ -131,7 +131,7 @@ void WifiConfig(uint8_t type)
|
||||
{
|
||||
if (!wifi_config_type) {
|
||||
if ((WIFI_RETRY == type) || (WIFI_WAIT == type)) { return; }
|
||||
#if defined(USE_WEBSERVER) && defined(USE_EMULATION)
|
||||
#ifdef USE_EMULATION
|
||||
UdpDisconnect();
|
||||
#endif // USE_EMULATION
|
||||
WiFi.disconnect(); // Solve possible Wifi hangs
|
||||
@ -159,7 +159,7 @@ void WifiConfig(uint8_t type)
|
||||
#ifdef USE_SMARTCONFIG
|
||||
else if (WIFI_SMARTCONFIG == wifi_config_type) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_1_SMARTCONFIG " " D_ACTIVE_FOR_3_MINUTES));
|
||||
WiFi.mode(WIFI_STA); // Disable AP mode
|
||||
WiFi.mode(WIFI_STA); // Disable AP mode
|
||||
WiFi.beginSmartConfig();
|
||||
}
|
||||
#endif // USE_SMARTCONFIG
|
||||
@ -211,7 +211,7 @@ void WifiBegin(uint8_t flag, uint8_t channel)
|
||||
{
|
||||
const char kWifiPhyMode[] = " BGN";
|
||||
|
||||
#if defined(USE_WEBSERVER) && defined(USE_EMULATION)
|
||||
#ifdef USE_EMULATION
|
||||
UdpDisconnect();
|
||||
#endif // USE_EMULATION
|
||||
|
||||
@ -565,7 +565,7 @@ void WifiCheck(uint8_t param)
|
||||
|
||||
} else {
|
||||
WifiSetState(0);
|
||||
#if defined(USE_WEBSERVER) && defined(USE_EMULATION)
|
||||
#ifdef USE_EMULATION
|
||||
UdpDisconnect();
|
||||
#endif // USE_EMULATION
|
||||
mdns_begun = 0;
|
||||
|
@ -493,9 +493,6 @@ void StartWebserver(int type, IPAddress ipweb)
|
||||
WebServer->on("/rs", HandleRestoreConfiguration);
|
||||
WebServer->on("/rt", HandleResetConfiguration);
|
||||
WebServer->on("/in", HandleInformation);
|
||||
#ifdef USE_EMULATION
|
||||
HueWemoAddHandlers();
|
||||
#endif // USE_EMULATION
|
||||
XdrvCall(FUNC_WEB_ADD_HANDLER);
|
||||
XsnsCall(FUNC_WEB_ADD_HANDLER);
|
||||
#endif // Not FIRMWARE_MINIMAL
|
||||
@ -1532,11 +1529,19 @@ void HandleOtherConfiguration(void)
|
||||
#ifdef USE_EMULATION
|
||||
WSContentSend_P(PSTR("<p></p><fieldset><legend><b> " D_EMULATION " </b></legend><p>")); // Keep close to Friendlynames so do not use <br/>
|
||||
for (uint8_t i = 0; i < EMUL_MAX; i++) {
|
||||
WSContentSend_P(PSTR("<input id='r%d' name='b2' type='radio' value='%d'%s><b>%s</b> %s<br/>"), // Different id only used for labels
|
||||
i, i,
|
||||
(i == Settings.flag2.emulation) ? " checked" : "",
|
||||
GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions),
|
||||
(i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? D_SINGLE_DEVICE : D_MULTI_DEVICE);
|
||||
#ifndef USE_EMULATION_WEMO
|
||||
if (i == EMUL_WEMO) { i++; }
|
||||
#endif
|
||||
#ifndef USE_EMULATION_HUE
|
||||
if (i == EMUL_HUE) { i++; }
|
||||
#endif
|
||||
if (i < EMUL_MAX) {
|
||||
WSContentSend_P(PSTR("<input id='r%d' name='b2' type='radio' value='%d'%s><b>%s</b> %s<br/>"), // Different id only used for labels
|
||||
i, i,
|
||||
(i == Settings.flag2.emulation) ? " checked" : "",
|
||||
GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions),
|
||||
(i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? D_SINGLE_DEVICE : D_MULTI_DEVICE);
|
||||
}
|
||||
}
|
||||
WSContentSend_P(PSTR("</p></fieldset>"));
|
||||
#endif // USE_EMULATION
|
||||
@ -2189,11 +2194,13 @@ void HandleNotFound(void)
|
||||
if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the error page.
|
||||
|
||||
#ifdef USE_EMULATION
|
||||
#ifdef USE_EMULATION_HUE
|
||||
String path = WebServer->uri();
|
||||
if ((EMUL_HUE == Settings.flag2.emulation) && (path.startsWith("/api"))) {
|
||||
HandleHueApi(&path);
|
||||
} else
|
||||
#endif // USE_EMULATION
|
||||
#endif // USE_EMULATION_HUE
|
||||
#endif // USE_EMULATION
|
||||
{
|
||||
WSContentBegin(404, CT_PLAIN);
|
||||
WSContentSend_P(PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"), WebServer->uri().c_str(), (WebServer->method() == HTTP_GET) ? "GET" : "POST", WebServer->args());
|
||||
@ -2430,7 +2437,16 @@ bool WebCommand(void)
|
||||
}
|
||||
#ifdef USE_EMULATION
|
||||
else if (CMND_EMULATION == command_code) {
|
||||
#if defined(USE_EMULATION_WEMO) && defined(USE_EMULATION_HUE)
|
||||
if ((XdrvMailbox.payload >= EMUL_NONE) && (XdrvMailbox.payload < EMUL_MAX)) {
|
||||
#else
|
||||
#ifndef USE_EMULATION_WEMO
|
||||
if ((EMUL_NONE == XdrvMailbox.payload) || (EMUL_HUE == XdrvMailbox.payload)) {
|
||||
#endif
|
||||
#ifndef USE_EMULATION_HUE
|
||||
if ((EMUL_NONE == XdrvMailbox.payload) || (EMUL_WEMO == XdrvMailbox.payload)) {
|
||||
#endif
|
||||
#endif
|
||||
Settings.flag2.emulation = XdrvMailbox.payload;
|
||||
restart_flag = 2;
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ void MqttReconnect(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(USE_WEBSERVER) && defined(USE_EMULATION)
|
||||
#ifdef USE_EMULATION
|
||||
UdpDisconnect();
|
||||
#endif // USE_EMULATION
|
||||
|
||||
|
@ -716,6 +716,8 @@ void LightStateClass::HsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t *
|
||||
if (r_b) *r_b = b;
|
||||
}
|
||||
|
||||
#define POW FastPrecisePowf
|
||||
|
||||
void LightStateClass::RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x, float *r_y) {
|
||||
float x = 0.31271f; // default medium white
|
||||
float y = 0.32902f;
|
||||
@ -726,9 +728,9 @@ void LightStateClass::RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x,
|
||||
float b = (float)i_b / 255.0f;
|
||||
// https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d
|
||||
// Gamma correction
|
||||
r = (r > 0.04045f) ? powf((r + 0.055f) / (1.0f + 0.055f), 2.4f) : (r / 12.92f);
|
||||
g = (g > 0.04045f) ? powf((g + 0.055f) / (1.0f + 0.055f), 2.4f) : (g / 12.92f);
|
||||
b = (b > 0.04045f) ? powf((b + 0.055f) / (1.0f + 0.055f), 2.4f) : (b / 12.92f);
|
||||
r = (r > 0.04045f) ? POW((r + 0.055f) / (1.0f + 0.055f), 2.4f) : (r / 12.92f);
|
||||
g = (g > 0.04045f) ? POW((g + 0.055f) / (1.0f + 0.055f), 2.4f) : (g / 12.92f);
|
||||
b = (b > 0.04045f) ? POW((b + 0.055f) / (1.0f + 0.055f), 2.4f) : (b / 12.92f);
|
||||
|
||||
// conversion to X, Y, Z
|
||||
// Y is also the Luminance
|
||||
@ -762,9 +764,9 @@ void LightStateClass::XyToRgb(float x, float y, uint8_t *rr, uint8_t *rg, uint8_
|
||||
r = r / max; // normalize to max == 1.0
|
||||
g = g / max;
|
||||
b = b / max;
|
||||
r = (r <= 0.0031308f) ? 12.92f * r : 1.055f * powf(r, (1.0f / 2.4f)) - 0.055f;
|
||||
g = (g <= 0.0031308f) ? 12.92f * g : 1.055f * powf(g, (1.0f / 2.4f)) - 0.055f;
|
||||
b = (b <= 0.0031308f) ? 12.92f * b : 1.055f * powf(b, (1.0f / 2.4f)) - 0.055f;
|
||||
r = (r <= 0.0031308f) ? 12.92f * r : 1.055f * POW(r, (1.0f / 2.4f)) - 0.055f;
|
||||
g = (g <= 0.0031308f) ? 12.92f * g : 1.055f * POW(g, (1.0f / 2.4f)) - 0.055f;
|
||||
b = (b <= 0.0031308f) ? 12.92f * b : 1.055f * POW(b, (1.0f / 2.4f)) - 0.055f;
|
||||
//
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, "XyToRgb XZ (%s %s) rgb (%s %s %s)",
|
||||
// String(X,5).c_str(), String(Z,5).c_str(),
|
||||
@ -1105,23 +1107,24 @@ void AriluxRfHandler(void)
|
||||
|
||||
void AriluxRfInit(void)
|
||||
{
|
||||
if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_LED4] < 99)) {
|
||||
if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_ARIRFSEL] < 99)) {
|
||||
if (Settings.last_module != Settings.module) {
|
||||
Settings.rf_code[1][6] = 0;
|
||||
Settings.rf_code[1][7] = 0;
|
||||
Settings.last_module = Settings.module;
|
||||
}
|
||||
arilux_rf_received_value = 0;
|
||||
digitalWrite(pin[GPIO_LED4], !bitRead(led_inverted, 3)); // Turn on RF
|
||||
|
||||
digitalWrite(pin[GPIO_ARIRFSEL], 0); // Turn on RF
|
||||
attachInterrupt(pin[GPIO_ARIRFRCV], AriluxRfInterrupt, CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
void AriluxRfDisable(void)
|
||||
{
|
||||
if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_LED4] < 99)) {
|
||||
if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_ARIRFSEL] < 99)) {
|
||||
detachInterrupt(pin[GPIO_ARIRFRCV]);
|
||||
digitalWrite(pin[GPIO_LED4], bitRead(led_inverted, 3)); // Turn off RF
|
||||
digitalWrite(pin[GPIO_ARIRFSEL], 1); // Turn off RF
|
||||
}
|
||||
}
|
||||
#endif // USE_ARILUX_RF
|
||||
@ -1351,8 +1354,9 @@ void LightInit(void)
|
||||
}
|
||||
}
|
||||
if (pin[GPIO_ARIRFRCV] < 99) {
|
||||
if (pin[GPIO_LED4] < 99) {
|
||||
digitalWrite(pin[GPIO_LED4], bitRead(led_inverted, 3)); // Turn off RF
|
||||
if (pin[GPIO_ARIRFSEL] < 99) {
|
||||
pinMode(pin[GPIO_ARIRFSEL], OUTPUT);
|
||||
digitalWrite(pin[GPIO_ARIRFSEL], 1); // Turn off RF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ void TimerEverySecond(void)
|
||||
if (time == set_time) {
|
||||
if (xtimer.days & days) {
|
||||
Settings.timer[i].arm = xtimer.repeat;
|
||||
#ifdef USE_RULES
|
||||
#if defined(USE_RULES) || defined(USE_SCRIPT)
|
||||
if (3 == xtimer.power) { // Blink becomes Rule disregarding device and allowing use of Backlog commands
|
||||
Response_P(PSTR("{\"Clock\":{\"Timer\":%d}}"), i +1);
|
||||
XdrvRulesProcess();
|
||||
@ -359,7 +359,8 @@ bool TimerCommand(void)
|
||||
Settings.timer[index -1].data = Settings.timer[XdrvMailbox.payload -1].data; // Copy timer
|
||||
}
|
||||
} else {
|
||||
#ifndef USE_RULES
|
||||
//#ifndef USE_RULES
|
||||
#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0
|
||||
if (devices_present) {
|
||||
#endif
|
||||
StaticJsonBuffer<256> jsonBuffer;
|
||||
@ -437,7 +438,8 @@ bool TimerCommand(void)
|
||||
|
||||
index++;
|
||||
}
|
||||
#ifndef USE_RULES
|
||||
//#ifndef USE_RULES
|
||||
#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0
|
||||
} else {
|
||||
Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_TIMER_NO_DEVICE "\"}"), index); // No outputs defined so nothing to control
|
||||
error = 1;
|
||||
@ -630,7 +632,7 @@ const char HTTP_TIMER_SCRIPT5[] PROGMEM =
|
||||
"if(%d>0){" // Create Output and Action drop down boxes
|
||||
"eb('oa').innerHTML=\"<b>" D_TIMER_OUTPUT "</b> <span><select style='width:60px;' id='d1' name='d1'></select></span> <b>" D_TIMER_ACTION "</b> <select style='width:99px;' id='p1' name='p1'></select>\";"
|
||||
"o=qs('#p1');ce('" D_OFF "',o);ce('" D_ON "',o);ce('" D_TOGGLE "',o);" // Create offset direction select options
|
||||
#ifdef USE_RULES
|
||||
#if defined(USE_RULES) || defined(USE_SCRIPT)
|
||||
"ce('" D_RULE "',o);"
|
||||
#else
|
||||
"ce('" D_BLINK "',o);"
|
||||
@ -768,7 +770,7 @@ bool Xdrv09(uint8_t function)
|
||||
#ifdef USE_WEBSERVER
|
||||
#ifdef USE_TIMERS_WEB
|
||||
case FUNC_WEB_ADD_BUTTON:
|
||||
#ifdef USE_RULES
|
||||
#if defined(USE_RULES) || defined(USE_SCRIPT)
|
||||
WSContentSend_P(HTTP_BTN_MENU_TIMER);
|
||||
#else
|
||||
if (devices_present) { WSContentSend_P(HTTP_BTN_MENU_TIMER); }
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#ifdef USE_RULES
|
||||
#ifndef USE_SCRIPT
|
||||
/*********************************************************************************************\
|
||||
* Rules based heavily on ESP Easy implementation
|
||||
*
|
||||
@ -586,6 +587,16 @@ void RulesEverySecond(void)
|
||||
}
|
||||
}
|
||||
|
||||
void RulesSaveBeforeRestart(void)
|
||||
{
|
||||
if (Settings.rule_enabled) { // Any rule enabled
|
||||
char json_event[32];
|
||||
|
||||
strncpy_P(json_event, PSTR("{\"System\":{\"Save\":1}}"), sizeof(json_event));
|
||||
RulesProcessEvent(json_event);
|
||||
}
|
||||
}
|
||||
|
||||
void RulesSetPower(void)
|
||||
{
|
||||
rules_new_power = XdrvMailbox.index;
|
||||
@ -1278,6 +1289,9 @@ bool Xdrv10(uint8_t function)
|
||||
case FUNC_RULES_PROCESS:
|
||||
result = RulesProcess();
|
||||
break;
|
||||
case FUNC_SAVE_BEFORE_RESTART:
|
||||
RulesSaveBeforeRestart();
|
||||
break;
|
||||
#ifdef SUPPORT_MQTT_EVENT
|
||||
case FUNC_MQTT_DATA:
|
||||
result = RulesMqttData();
|
||||
@ -1287,4 +1301,5 @@ bool Xdrv10(uint8_t function)
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // Do not USE_SCRIPT
|
||||
#endif // USE_RULES
|
2238
sonoff/xdrv_10_scripter.ino
Normal file
2238
sonoff/xdrv_10_scripter.ino
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
xplg_wemohue.ino - wemo and hue support for Sonoff-Tasmota
|
||||
xdrv_20_hue.ino - Philips Hue support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Heiko Krupp and Theo Arends
|
||||
|
||||
@ -17,93 +17,10 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(USE_WEBSERVER) && defined(USE_EMULATION)
|
||||
/*********************************************************************************************\
|
||||
* Belkin WeMo and Philips Hue bridge emulation
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define UDP_BUFFER_SIZE 200 // Max UDP buffer size needed for M-SEARCH message
|
||||
#define UDP_MSEARCH_SEND_DELAY 1500 // Delay in ms before M-Search response is send
|
||||
|
||||
#include <Ticker.h>
|
||||
Ticker TickerMSearch;
|
||||
|
||||
IPAddress udp_remote_ip; // M-Search remote IP address
|
||||
uint16_t udp_remote_port; // M-Search remote port
|
||||
|
||||
bool udp_connected = false;
|
||||
bool udp_response_mutex = false; // M-Search response mutex to control re-entry
|
||||
|
||||
/*********************************************************************************************\
|
||||
* UPNP search targets
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char URN_BELKIN_DEVICE[] PROGMEM = "urn:belkin:device:**";
|
||||
const char UPNP_ROOTDEVICE[] PROGMEM = "upnp:rootdevice";
|
||||
const char SSDPSEARCH_ALL[] PROGMEM = "ssdpsearch:all";
|
||||
const char SSDP_ALL[] PROGMEM = "ssdp:all";
|
||||
|
||||
/*********************************************************************************************\
|
||||
* WeMo UPNP support routines
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char WEMO_MSEARCH[] PROGMEM =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=86400\r\n"
|
||||
"DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://%s:80/setup.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n"
|
||||
"SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
|
||||
"ST: %s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
|
||||
"USN: uuid:%s::%s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"\r\n";
|
||||
|
||||
String WemoSerialnumber(void)
|
||||
{
|
||||
char serial[16];
|
||||
|
||||
snprintf_P(serial, sizeof(serial), PSTR("201612K%08X"), ESP.getChipId());
|
||||
return String(serial);
|
||||
}
|
||||
|
||||
String WemoUuid(void)
|
||||
{
|
||||
char uuid[27];
|
||||
|
||||
snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), WemoSerialnumber().c_str());
|
||||
return String(uuid);
|
||||
}
|
||||
|
||||
void WemoRespondToMSearch(int echo_type)
|
||||
{
|
||||
char message[TOPSZ];
|
||||
|
||||
TickerMSearch.detach();
|
||||
if (PortUdp.beginPacket(udp_remote_ip, udp_remote_port)) {
|
||||
char type[24];
|
||||
if (1 == echo_type) { // type1 echo 1g & dot 2g
|
||||
strcpy_P(type, URN_BELKIN_DEVICE);
|
||||
} else { // type2 echo 2g (echo, plus, show)
|
||||
strcpy_P(type, UPNP_ROOTDEVICE);
|
||||
}
|
||||
char response[400];
|
||||
snprintf_P(response, sizeof(response), WEMO_MSEARCH, WiFi.localIP().toString().c_str(), type, WemoUuid().c_str(), type);
|
||||
PortUdp.write(response);
|
||||
PortUdp.endPacket();
|
||||
snprintf_P(message, sizeof(message), PSTR(D_RESPONSE_SENT));
|
||||
} else {
|
||||
snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE));
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"),
|
||||
echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port);
|
||||
|
||||
udp_response_mutex = false;
|
||||
}
|
||||
|
||||
#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE)
|
||||
/*********************************************************************************************\
|
||||
* Philips Hue bridge emulation
|
||||
*
|
||||
* Hue Bridge UPNP support routines
|
||||
* Need to send 3 response packets with varying ST and USN
|
||||
*
|
||||
@ -111,6 +28,8 @@ void WemoRespondToMSearch(int echo_type)
|
||||
* Philips Lighting is 00:17:88:00:00:00
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_20 20
|
||||
|
||||
const char HUE_RESPONSE[] PROGMEM =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
@ -187,256 +106,6 @@ void HueRespondToMSearch(void)
|
||||
udp_response_mutex = false;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Belkin WeMo and Philips Hue bridge UDP multicast support
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool UdpDisconnect(void)
|
||||
{
|
||||
if (udp_connected) {
|
||||
PortUdp.flush();
|
||||
WiFiUDP::stopAll();
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_MULTICAST_DISABLED));
|
||||
udp_connected = false;
|
||||
}
|
||||
return udp_connected;
|
||||
}
|
||||
|
||||
bool UdpConnect(void)
|
||||
{
|
||||
if (!udp_connected) {
|
||||
// Simple Service Discovery Protocol (SSDP)
|
||||
if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), 1900)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED));
|
||||
udp_response_mutex = false;
|
||||
udp_connected = true;
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_JOIN_FAILED));
|
||||
udp_connected = false;
|
||||
}
|
||||
}
|
||||
return udp_connected;
|
||||
}
|
||||
|
||||
void PollUdp(void)
|
||||
{
|
||||
if (udp_connected) {
|
||||
if (PortUdp.parsePacket()) {
|
||||
char packet_buffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP/SSDP packet
|
||||
|
||||
int len = PortUdp.read(packet_buffer, UDP_BUFFER_SIZE -1);
|
||||
packet_buffer[len] = 0;
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len);
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer);
|
||||
|
||||
if (devices_present && !udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) {
|
||||
udp_response_mutex = true;
|
||||
|
||||
udp_remote_ip = PortUdp.remoteIP();
|
||||
udp_remote_port = PortUdp.remotePort();
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: M-SEARCH Packet from %s:%d\n%s"),
|
||||
// udp_remote_ip.toString().c_str(), udp_remote_port, packet_buffer);
|
||||
|
||||
uint32_t response_delay = UDP_MSEARCH_SEND_DELAY + ((millis() &0x7) * 100); // 1500 - 2200 msec
|
||||
|
||||
LowerCase(packet_buffer, packet_buffer);
|
||||
RemoveSpace(packet_buffer);
|
||||
if (EMUL_WEMO == Settings.flag2.emulation) {
|
||||
if (strstr_P(packet_buffer, URN_BELKIN_DEVICE) != nullptr) { // type1 echo dot 2g, echo 1g's
|
||||
TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 1);
|
||||
return;
|
||||
}
|
||||
else if ((strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || // type2 Echo 2g (echo & echo plus)
|
||||
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
|
||||
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
|
||||
TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 2);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((strstr_P(packet_buffer, PSTR(":device:basic:1")) != nullptr) ||
|
||||
(strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) ||
|
||||
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
|
||||
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
|
||||
TickerMSearch.attach_ms(response_delay, HueRespondToMSearch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
udp_response_mutex = false;
|
||||
}
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Wemo web server additions
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char WEMO_EVENTSERVICE_XML[] PROGMEM =
|
||||
"<scpd xmlns=\"urn:Belkin:service-1-0\">"
|
||||
"<actionList>"
|
||||
"<action>"
|
||||
"<name>SetBinaryState</name>"
|
||||
"<argumentList>"
|
||||
"<argument>"
|
||||
"<retval/>"
|
||||
"<name>BinaryState</name>"
|
||||
"<relatedStateVariable>BinaryState</relatedStateVariable>"
|
||||
"<direction>in</direction>"
|
||||
"</argument>"
|
||||
"</argumentList>"
|
||||
"</action>"
|
||||
"<action>"
|
||||
"<name>GetBinaryState</name>"
|
||||
"<argumentList>"
|
||||
"<argument>"
|
||||
"<retval/>"
|
||||
"<name>BinaryState</name>"
|
||||
"<relatedStateVariable>BinaryState</relatedStateVariable>"
|
||||
"<direction>out</direction>"
|
||||
"</argument>"
|
||||
"</argumentList>"
|
||||
"</action>"
|
||||
"</actionList>"
|
||||
"<serviceStateTable>"
|
||||
"<stateVariable sendEvents=\"yes\">"
|
||||
"<name>BinaryState</name>"
|
||||
"<dataType>bool</dataType>"
|
||||
"<defaultValue>0</defaultValue>"
|
||||
"</stateVariable>"
|
||||
"<stateVariable sendEvents=\"yes\">"
|
||||
"<name>level</name>"
|
||||
"<dataType>string</dataType>"
|
||||
"<defaultValue>0</defaultValue>"
|
||||
"</stateVariable>"
|
||||
"</serviceStateTable>"
|
||||
"</scpd>\r\n\r\n";
|
||||
|
||||
const char WEMO_METASERVICE_XML[] PROGMEM =
|
||||
"<scpd xmlns=\"urn:Belkin:service-1-0\">"
|
||||
"<specVersion>"
|
||||
"<major>1</major>"
|
||||
"<minor>0</minor>"
|
||||
"</specVersion>"
|
||||
"<actionList>"
|
||||
"<action>"
|
||||
"<name>GetMetaInfo</name>"
|
||||
"<argumentList>"
|
||||
"<retval />"
|
||||
"<name>GetMetaInfo</name>"
|
||||
"<relatedStateVariable>MetaInfo</relatedStateVariable>"
|
||||
"<direction>in</direction>"
|
||||
"</argumentList>"
|
||||
"</action>"
|
||||
"</actionList>"
|
||||
"<serviceStateTable>"
|
||||
"<stateVariable sendEvents=\"yes\">"
|
||||
"<name>MetaInfo</name>"
|
||||
"<dataType>string</dataType>"
|
||||
"<defaultValue>0</defaultValue>"
|
||||
"</stateVariable>"
|
||||
"</serviceStateTable>"
|
||||
"</scpd>\r\n\r\n";
|
||||
|
||||
const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM =
|
||||
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<s:Body>"
|
||||
"<u:%cetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">"
|
||||
"<BinaryState>%d</BinaryState>"
|
||||
"</u:%cetBinaryStateResponse>"
|
||||
"</s:Body>"
|
||||
"</s:Envelope>\r\n";
|
||||
|
||||
const char WEMO_SETUP_XML[] PROGMEM =
|
||||
"<?xml version=\"1.0\"?>"
|
||||
"<root xmlns=\"urn:Belkin:device-1-0\">"
|
||||
"<device>"
|
||||
"<deviceType>urn:Belkin:device:controllee:1</deviceType>"
|
||||
"<friendlyName>{x1</friendlyName>"
|
||||
"<manufacturer>Belkin International Inc.</manufacturer>"
|
||||
"<modelName>Socket</modelName>"
|
||||
"<modelNumber>3.1415</modelNumber>"
|
||||
"<UDN>uuid:{x2</UDN>"
|
||||
"<serialNumber>{x3</serialNumber>"
|
||||
"<binaryState>0</binaryState>"
|
||||
"<serviceList>"
|
||||
"<service>"
|
||||
"<serviceType>urn:Belkin:service:basicevent:1</serviceType>"
|
||||
"<serviceId>urn:Belkin:serviceId:basicevent1</serviceId>"
|
||||
"<controlURL>/upnp/control/basicevent1</controlURL>"
|
||||
"<eventSubURL>/upnp/event/basicevent1</eventSubURL>"
|
||||
"<SCPDURL>/eventservice.xml</SCPDURL>"
|
||||
"</service>"
|
||||
"<service>"
|
||||
"<serviceType>urn:Belkin:service:metainfo:1</serviceType>"
|
||||
"<serviceId>urn:Belkin:serviceId:metainfo1</serviceId>"
|
||||
"<controlURL>/upnp/control/metainfo1</controlURL>"
|
||||
"<eventSubURL>/upnp/event/metainfo1</eventSubURL>"
|
||||
"<SCPDURL>/metainfoservice.xml</SCPDURL>"
|
||||
"</service>"
|
||||
"</serviceList>"
|
||||
"</device>"
|
||||
"</root>\r\n";
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void HandleUpnpEvent(void)
|
||||
{
|
||||
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_BASIC_EVENT));
|
||||
|
||||
char event[500];
|
||||
strlcpy(event, WebServer->arg(0).c_str(), sizeof(event));
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), event);
|
||||
|
||||
//differentiate get and set state
|
||||
char state = 'G';
|
||||
if (strstr_P(event, PSTR("SetBinaryState")) != nullptr) {
|
||||
state = 'S';
|
||||
uint8_t power = POWER_TOGGLE;
|
||||
if (strstr_P(event, PSTR("State>1</Binary")) != nullptr) {
|
||||
power = POWER_ON;
|
||||
}
|
||||
else if (strstr_P(event, PSTR("State>0</Binary")) != nullptr) {
|
||||
power = POWER_OFF;
|
||||
}
|
||||
if (power != POWER_TOGGLE) {
|
||||
uint8_t device = (light_type) ? devices_present : 1; // Select either a configured light or relay1
|
||||
ExecuteCommandPower(device, power, SRC_WEMO);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf_P(event, sizeof(event), WEMO_RESPONSE_STATE_SOAP, state, bitRead(power, devices_present -1), state);
|
||||
WSSend(200, CT_XML, event);
|
||||
}
|
||||
|
||||
void HandleUpnpService(void)
|
||||
{
|
||||
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_EVENT_SERVICE));
|
||||
|
||||
WSSend(200, CT_PLAIN, FPSTR(WEMO_EVENTSERVICE_XML));
|
||||
}
|
||||
|
||||
void HandleUpnpMetaService(void)
|
||||
{
|
||||
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_META_SERVICE));
|
||||
|
||||
WSSend(200, CT_PLAIN, FPSTR(WEMO_METASERVICE_XML));
|
||||
}
|
||||
|
||||
void HandleUpnpSetupWemo(void)
|
||||
{
|
||||
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_SETUP));
|
||||
|
||||
String setup_xml = FPSTR(WEMO_SETUP_XML);
|
||||
setup_xml.replace("{x1", Settings.friendlyname[0]);
|
||||
setup_xml.replace("{x2", WemoUuid());
|
||||
setup_xml.replace("{x3", WemoSerialnumber());
|
||||
WSSend(200, CT_XML, setup_xml);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Hue web server additions
|
||||
\*********************************************************************************************/
|
||||
@ -970,19 +639,22 @@ void HandleHueApi(String *path)
|
||||
else HueGlobalConfig(path);
|
||||
}
|
||||
|
||||
void HueWemoAddHandlers(void)
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xdrv20(uint8_t function)
|
||||
{
|
||||
if (devices_present) {
|
||||
if (EMUL_WEMO == Settings.flag2.emulation) {
|
||||
WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
|
||||
WebServer->on("/eventservice.xml", HandleUpnpService);
|
||||
WebServer->on("/metainfoservice.xml", HandleUpnpMetaService);
|
||||
WebServer->on("/setup.xml", HandleUpnpSetupWemo);
|
||||
}
|
||||
if (EMUL_HUE == Settings.flag2.emulation) {
|
||||
WebServer->on("/description.xml", HandleUpnpSetupHue);
|
||||
bool result = false;
|
||||
|
||||
if (devices_present && (EMUL_HUE == Settings.flag2.emulation)) {
|
||||
switch (function) {
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
WebServer->on("/description.xml", HandleUpnpSetupHue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_WEBSERVER && USE_EMULATION
|
||||
#endif // USE_WEBSERVER && USE_EMULATION && USE_EMULATION_HUE
|
271
sonoff/xdrv_21_wemo.ino
Normal file
271
sonoff/xdrv_21_wemo.ino
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
xdrv_21_wemo.ino - wemo support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Heiko Krupp and Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined (USE_EMULATION_WEMO)
|
||||
/*********************************************************************************************\
|
||||
* Belkin WeMo emulation
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_21 21
|
||||
|
||||
const char WEMO_MSEARCH[] PROGMEM =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=86400\r\n"
|
||||
"DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://%s:80/setup.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n"
|
||||
"SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
|
||||
"ST: %s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
|
||||
"USN: uuid:%s::%s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"\r\n";
|
||||
|
||||
String WemoSerialnumber(void)
|
||||
{
|
||||
char serial[16];
|
||||
|
||||
snprintf_P(serial, sizeof(serial), PSTR("201612K%08X"), ESP.getChipId());
|
||||
return String(serial);
|
||||
}
|
||||
|
||||
String WemoUuid(void)
|
||||
{
|
||||
char uuid[27];
|
||||
|
||||
snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), WemoSerialnumber().c_str());
|
||||
return String(uuid);
|
||||
}
|
||||
|
||||
void WemoRespondToMSearch(int echo_type)
|
||||
{
|
||||
char message[TOPSZ];
|
||||
|
||||
TickerMSearch.detach();
|
||||
if (PortUdp.beginPacket(udp_remote_ip, udp_remote_port)) {
|
||||
char type[24];
|
||||
if (1 == echo_type) { // type1 echo 1g & dot 2g
|
||||
strcpy_P(type, URN_BELKIN_DEVICE);
|
||||
} else { // type2 echo 2g (echo, plus, show)
|
||||
strcpy_P(type, UPNP_ROOTDEVICE);
|
||||
}
|
||||
char response[400];
|
||||
snprintf_P(response, sizeof(response), WEMO_MSEARCH, WiFi.localIP().toString().c_str(), type, WemoUuid().c_str(), type);
|
||||
PortUdp.write(response);
|
||||
PortUdp.endPacket();
|
||||
snprintf_P(message, sizeof(message), PSTR(D_RESPONSE_SENT));
|
||||
} else {
|
||||
snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE));
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"),
|
||||
echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port);
|
||||
|
||||
udp_response_mutex = false;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Wemo web server additions
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char WEMO_EVENTSERVICE_XML[] PROGMEM =
|
||||
"<scpd xmlns=\"urn:Belkin:service-1-0\">"
|
||||
"<actionList>"
|
||||
"<action>"
|
||||
"<name>SetBinaryState</name>"
|
||||
"<argumentList>"
|
||||
"<argument>"
|
||||
"<retval/>"
|
||||
"<name>BinaryState</name>"
|
||||
"<relatedStateVariable>BinaryState</relatedStateVariable>"
|
||||
"<direction>in</direction>"
|
||||
"</argument>"
|
||||
"</argumentList>"
|
||||
"</action>"
|
||||
"<action>"
|
||||
"<name>GetBinaryState</name>"
|
||||
"<argumentList>"
|
||||
"<argument>"
|
||||
"<retval/>"
|
||||
"<name>BinaryState</name>"
|
||||
"<relatedStateVariable>BinaryState</relatedStateVariable>"
|
||||
"<direction>out</direction>"
|
||||
"</argument>"
|
||||
"</argumentList>"
|
||||
"</action>"
|
||||
"</actionList>"
|
||||
"<serviceStateTable>"
|
||||
"<stateVariable sendEvents=\"yes\">"
|
||||
"<name>BinaryState</name>"
|
||||
"<dataType>bool</dataType>"
|
||||
"<defaultValue>0</defaultValue>"
|
||||
"</stateVariable>"
|
||||
"<stateVariable sendEvents=\"yes\">"
|
||||
"<name>level</name>"
|
||||
"<dataType>string</dataType>"
|
||||
"<defaultValue>0</defaultValue>"
|
||||
"</stateVariable>"
|
||||
"</serviceStateTable>"
|
||||
"</scpd>\r\n\r\n";
|
||||
|
||||
const char WEMO_METASERVICE_XML[] PROGMEM =
|
||||
"<scpd xmlns=\"urn:Belkin:service-1-0\">"
|
||||
"<specVersion>"
|
||||
"<major>1</major>"
|
||||
"<minor>0</minor>"
|
||||
"</specVersion>"
|
||||
"<actionList>"
|
||||
"<action>"
|
||||
"<name>GetMetaInfo</name>"
|
||||
"<argumentList>"
|
||||
"<retval />"
|
||||
"<name>GetMetaInfo</name>"
|
||||
"<relatedStateVariable>MetaInfo</relatedStateVariable>"
|
||||
"<direction>in</direction>"
|
||||
"</argumentList>"
|
||||
"</action>"
|
||||
"</actionList>"
|
||||
"<serviceStateTable>"
|
||||
"<stateVariable sendEvents=\"yes\">"
|
||||
"<name>MetaInfo</name>"
|
||||
"<dataType>string</dataType>"
|
||||
"<defaultValue>0</defaultValue>"
|
||||
"</stateVariable>"
|
||||
"</serviceStateTable>"
|
||||
"</scpd>\r\n\r\n";
|
||||
|
||||
const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM =
|
||||
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<s:Body>"
|
||||
"<u:%cetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">"
|
||||
"<BinaryState>%d</BinaryState>"
|
||||
"</u:%cetBinaryStateResponse>"
|
||||
"</s:Body>"
|
||||
"</s:Envelope>\r\n";
|
||||
|
||||
const char WEMO_SETUP_XML[] PROGMEM =
|
||||
"<?xml version=\"1.0\"?>"
|
||||
"<root xmlns=\"urn:Belkin:device-1-0\">"
|
||||
"<device>"
|
||||
"<deviceType>urn:Belkin:device:controllee:1</deviceType>"
|
||||
"<friendlyName>{x1</friendlyName>"
|
||||
"<manufacturer>Belkin International Inc.</manufacturer>"
|
||||
"<modelName>Socket</modelName>"
|
||||
"<modelNumber>3.1415</modelNumber>"
|
||||
"<UDN>uuid:{x2</UDN>"
|
||||
"<serialNumber>{x3</serialNumber>"
|
||||
"<binaryState>0</binaryState>"
|
||||
"<serviceList>"
|
||||
"<service>"
|
||||
"<serviceType>urn:Belkin:service:basicevent:1</serviceType>"
|
||||
"<serviceId>urn:Belkin:serviceId:basicevent1</serviceId>"
|
||||
"<controlURL>/upnp/control/basicevent1</controlURL>"
|
||||
"<eventSubURL>/upnp/event/basicevent1</eventSubURL>"
|
||||
"<SCPDURL>/eventservice.xml</SCPDURL>"
|
||||
"</service>"
|
||||
"<service>"
|
||||
"<serviceType>urn:Belkin:service:metainfo:1</serviceType>"
|
||||
"<serviceId>urn:Belkin:serviceId:metainfo1</serviceId>"
|
||||
"<controlURL>/upnp/control/metainfo1</controlURL>"
|
||||
"<eventSubURL>/upnp/event/metainfo1</eventSubURL>"
|
||||
"<SCPDURL>/metainfoservice.xml</SCPDURL>"
|
||||
"</service>"
|
||||
"</serviceList>"
|
||||
"</device>"
|
||||
"</root>\r\n";
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void HandleUpnpEvent(void)
|
||||
{
|
||||
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_BASIC_EVENT));
|
||||
|
||||
char event[500];
|
||||
strlcpy(event, WebServer->arg(0).c_str(), sizeof(event));
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), event);
|
||||
|
||||
//differentiate get and set state
|
||||
char state = 'G';
|
||||
if (strstr_P(event, PSTR("SetBinaryState")) != nullptr) {
|
||||
state = 'S';
|
||||
uint8_t power = POWER_TOGGLE;
|
||||
if (strstr_P(event, PSTR("State>1</Binary")) != nullptr) {
|
||||
power = POWER_ON;
|
||||
}
|
||||
else if (strstr_P(event, PSTR("State>0</Binary")) != nullptr) {
|
||||
power = POWER_OFF;
|
||||
}
|
||||
if (power != POWER_TOGGLE) {
|
||||
uint8_t device = (light_type) ? devices_present : 1; // Select either a configured light or relay1
|
||||
ExecuteCommandPower(device, power, SRC_WEMO);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf_P(event, sizeof(event), WEMO_RESPONSE_STATE_SOAP, state, bitRead(power, devices_present -1), state);
|
||||
WSSend(200, CT_XML, event);
|
||||
}
|
||||
|
||||
void HandleUpnpService(void)
|
||||
{
|
||||
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_EVENT_SERVICE));
|
||||
|
||||
WSSend(200, CT_PLAIN, FPSTR(WEMO_EVENTSERVICE_XML));
|
||||
}
|
||||
|
||||
void HandleUpnpMetaService(void)
|
||||
{
|
||||
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_META_SERVICE));
|
||||
|
||||
WSSend(200, CT_PLAIN, FPSTR(WEMO_METASERVICE_XML));
|
||||
}
|
||||
|
||||
void HandleUpnpSetupWemo(void)
|
||||
{
|
||||
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_SETUP));
|
||||
|
||||
String setup_xml = FPSTR(WEMO_SETUP_XML);
|
||||
setup_xml.replace("{x1", Settings.friendlyname[0]);
|
||||
setup_xml.replace("{x2", WemoUuid());
|
||||
setup_xml.replace("{x3", WemoSerialnumber());
|
||||
WSSend(200, CT_XML, setup_xml);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xdrv21(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (devices_present && (EMUL_WEMO == Settings.flag2.emulation)) {
|
||||
switch (function) {
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
|
||||
WebServer->on("/eventservice.xml", HandleUpnpService);
|
||||
WebServer->on("/metainfoservice.xml", HandleUpnpMetaService);
|
||||
WebServer->on("/setup.xml", HandleUpnpSetupWemo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_WEBSERVER && USE_EMULATION && USE_EMULATION_WEMO
|
@ -233,26 +233,27 @@ void HlwSnsInit(void)
|
||||
void HlwDrvInit(void)
|
||||
{
|
||||
if (!energy_flg) {
|
||||
hlw_model_type = 0; // HLW8012
|
||||
hlw_model_type = 0; // HLW8012
|
||||
if (pin[GPIO_HJL_CF] < 99) {
|
||||
pin[GPIO_HLW_CF] = pin[GPIO_HJL_CF];
|
||||
pin[GPIO_HJL_CF] = 99;
|
||||
hlw_model_type = 1; // HJL-01/BL0937
|
||||
hlw_model_type = 1; // HJL-01/BL0937
|
||||
}
|
||||
|
||||
if (pin[GPIO_HLW_CF] < 99) { // HLW8012 or HJL-01 based device
|
||||
if (pin[GPIO_HLW_CF] < 99) { // HLW8012 or HJL-01 based device Power monitor
|
||||
|
||||
hlw_ui_flag = 1; // Voltage on high
|
||||
hlw_ui_flag = 1; // Voltage on high
|
||||
if (pin[GPIO_NRG_SEL_INV] < 99) {
|
||||
pin[GPIO_NRG_SEL] = pin[GPIO_NRG_SEL_INV];
|
||||
pin[GPIO_NRG_SEL_INV] = 99;
|
||||
hlw_ui_flag = 0; // Voltage on low
|
||||
hlw_ui_flag = 0; // Voltage on low
|
||||
}
|
||||
|
||||
if (99 == pin[GPIO_NRG_SEL]) {
|
||||
energy_current_available = false;
|
||||
}
|
||||
if (99 == pin[GPIO_NRG_CF1]) {
|
||||
if (pin[GPIO_NRG_CF1] < 99) { // Voltage and/or Current monitor
|
||||
if (99 == pin[GPIO_NRG_SEL]) { // Voltage and/or Current selector
|
||||
energy_current_available = false; // Assume Voltage
|
||||
}
|
||||
} else {
|
||||
energy_current_available = false;
|
||||
energy_voltage_available = false;
|
||||
}
|
||||
|
@ -189,6 +189,7 @@ void CseEverySecond(void)
|
||||
}
|
||||
else {
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Load overflow"));
|
||||
cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED;
|
||||
}
|
||||
EnergyUpdateToday();
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ void AdcEverySecond(void)
|
||||
int adc = AdcRead(2);
|
||||
// Steinhart-Hart equation for thermistor as temperature sensor
|
||||
double Rt = (adc * ANALOG_NTC_BRIDGE_RESISTANCE) / (1024.0 * ANALOG_V33 - (double)adc);
|
||||
double T = ANALOG_NTC_B_COEFFICIENT / (ANALOG_NTC_B_COEFFICIENT / ANALOG_T0 + log(Rt / ANALOG_NTC_RESISTANCE));
|
||||
double T = ANALOG_NTC_B_COEFFICIENT / (ANALOG_NTC_B_COEFFICIENT / ANALOG_T0 + TaylorLog(Rt / ANALOG_NTC_RESISTANCE));
|
||||
adc_temp = ConvertTemp(TO_CELSIUS(T));
|
||||
}
|
||||
}
|
||||
|
@ -149,9 +149,9 @@ void SenseairShow(bool json)
|
||||
GetTextIndexed(senseair_types, sizeof(senseair_types), senseair_type -1, kSenseairTypes);
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR("%s,\"%s\":{\"" D_JSON_CO2 "\":%d"), senseair_types, senseair_co2);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_CO2 "\":%d"), senseair_types, senseair_co2);
|
||||
if (senseair_type != 2) {
|
||||
ResponseAppend_P(PSTR("%s,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s"), temperature, humidity);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s"), temperature, humidity);
|
||||
}
|
||||
ResponseJsonEnd();
|
||||
#ifdef USE_DOMOTICZ
|
||||
|
@ -34,55 +34,122 @@ Adafruit_SGP30 sgp;
|
||||
|
||||
uint8_t sgp30_type = 0;
|
||||
uint8_t sgp30_ready = 0;
|
||||
uint8_t sgp30_counter = 0;
|
||||
float sgp30_abshum;
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void sgp30_Init(void) {
|
||||
if (sgp.begin()) {
|
||||
sgp30_type = 1;
|
||||
// snprintf_P(log_data, sizeof(log_data), PSTR("SGP: Serialnumber 0x%04X-0x%04X-0x%04X"), sgp.serialnumber[0], sgp.serialnumber[1], sgp.serialnumber[2]);
|
||||
// AddLog(LOG_LEVEL_DEBUG);
|
||||
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "SGP30", 0x58);
|
||||
AddLog(LOG_LEVEL_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
//#define POW_FUNC pow
|
||||
#define POW_FUNC FastPrecisePow
|
||||
|
||||
float sgp30_AbsoluteHumidity(float temperature, float humidity,char tempUnit) {
|
||||
//taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
|
||||
//precision is about 0.1°C in range -30 to 35°C
|
||||
//August-Roche-Magnus 6.1094 exp(17.625 x T)/(T + 243.04)
|
||||
//Buck (1981) 6.1121 exp(17.502 x T)/(T + 240.97)
|
||||
//reference https://www.eas.ualberta.ca/jdwilson/EAS372_13/Vomel_CIRES_satvpformulae.html
|
||||
float temp = NAN;
|
||||
const float mw = 18.01534; // molar mass of water g/mol
|
||||
const float r = 8.31447215; // Universal gas constant J/mol/K
|
||||
|
||||
if (isnan(temperature) || isnan(humidity) ) {
|
||||
return NAN;
|
||||
}
|
||||
|
||||
if (tempUnit != 'C') {
|
||||
temperature = (temperature - 32.0) * (5.0 / 9.0); /*conversion to [°C]*/
|
||||
}
|
||||
|
||||
temp = POW_FUNC(2.718281828, (17.67 * temperature) / (temperature + 243.5));
|
||||
|
||||
|
||||
|
||||
//return (6.112 * temp * humidity * 2.1674) / (273.15 + temperature); //simplified version
|
||||
return (6.112 * temp * humidity * mw) / ((273.15 + temperature) * r); //long version
|
||||
}
|
||||
|
||||
#define SAVE_PERIOD 30
|
||||
|
||||
void Sgp30Update(void) // Perform every second to ensure proper operation of the baseline compensation algorithm
|
||||
{
|
||||
sgp30_ready = 0;
|
||||
if (!sgp30_type) {
|
||||
if (sgp.begin()) {
|
||||
sgp30_type = 1;
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SGP: Serialnumber 0x%04X-0x%04X-0x%04X"), sgp.serialnumber[0], sgp.serialnumber[1], sgp.serialnumber[2]);
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "SGP30", 0x58);
|
||||
if (!sgp.IAQmeasure() || !sgp30_type) {
|
||||
// retry to init every 100 seconds
|
||||
if (21 == (uptime %100)) {
|
||||
sgp30_Init();
|
||||
}
|
||||
} else {
|
||||
if (!sgp.IAQmeasure()) return; // Measurement failed
|
||||
sgp30_counter++;
|
||||
if (30 == sgp30_counter) {
|
||||
sgp30_counter = 0;
|
||||
return; // Measurement failed
|
||||
}
|
||||
if (global_update) {
|
||||
// abs hum in mg/m3
|
||||
sgp30_abshum=sgp30_AbsoluteHumidity(global_temperature,global_humidity,TempUnit());
|
||||
sgp.setHumidity(sgp30_abshum*1000);
|
||||
}
|
||||
sgp30_ready = 1;
|
||||
|
||||
uint16_t TVOC_base;
|
||||
uint16_t eCO2_base;
|
||||
// these should normally be stored permanently and used for fast restart
|
||||
if (!(uptime%SAVE_PERIOD)) {
|
||||
// store settings every N seconds
|
||||
uint16_t TVOC_base;
|
||||
uint16_t eCO2_base;
|
||||
|
||||
if (!sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) return; // Failed to get baseline readings
|
||||
// snprintf_P(log_data, sizeof(log_data), PSTR("SGP: Baseline values eCO2 0x%04X, TVOC 0x%04X"), eCO2_base, TVOC_base);
|
||||
// AddLog(LOG_LEVEL_DEBUG);
|
||||
|
||||
if (!sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) return; // Failed to get baseline readings
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SGP: Baseline values eCO2 0x%04X, TVOC 0x%04X"), eCO2_base, TVOC_base);
|
||||
}
|
||||
sgp30_ready = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
const char HTTP_SNS_SGP30[] PROGMEM =
|
||||
"{s}SGP30 " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}" // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
||||
"{s}SGP30 " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}";
|
||||
const char HTTP_SNS_AHUM[] PROGMEM = "{s}SGP30 " "Abs Humidity" "{m}%s g/m3{e}";
|
||||
#endif
|
||||
|
||||
#define D_JSON_AHUM "aHumidity"
|
||||
|
||||
void Sgp30Show(bool json)
|
||||
{
|
||||
if (sgp30_ready) {
|
||||
char abs_hum[33];
|
||||
|
||||
if (global_update) {
|
||||
// has humidity + temperature
|
||||
dtostrfd(sgp30_abshum,4,abs_hum);
|
||||
}
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d}"), sgp.eCO2, sgp.TVOC);
|
||||
ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d"), sgp.eCO2, sgp.TVOC);
|
||||
if (global_update) {
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"),abs_hum);
|
||||
}
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
#ifdef USE_DOMOTICZ
|
||||
if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, sgp.eCO2);
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_SGP30, sgp.eCO2, sgp.TVOC);
|
||||
if (global_update) {
|
||||
WSContentSend_PD(HTTP_SNS_AHUM, abs_hum);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
@ -93,6 +160,9 @@ bool Xsns21(uint8_t function)
|
||||
|
||||
if (i2c_flg) {
|
||||
switch (function) {
|
||||
case FUNC_INIT:
|
||||
sgp30_Init();
|
||||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
Sgp30Update();
|
||||
break;
|
||||
@ -110,4 +180,4 @@ bool Xsns21(uint8_t function)
|
||||
}
|
||||
|
||||
#endif // USE_SGP30
|
||||
#endif // USE_I2C
|
||||
#endif // USE_I2C
|
||||
|
@ -374,21 +374,11 @@ void calculateColorTemperature(void)
|
||||
n = (xc - 0.3320F) / (0.1858F - yc);
|
||||
|
||||
/* Calculate the final CCT */
|
||||
color_data.cct = (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F;
|
||||
color_data.cct = (449.0F * FastPrecisePowf(n, 3)) + (3525.0F * FastPrecisePowf(n, 2)) + (6823.3F * n) + 5520.33F;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Taken from the Adafruit-Library
|
||||
* @brief Implements missing powf function
|
||||
*/
|
||||
|
||||
float powf(const float x, const float y)
|
||||
{
|
||||
return (float)(pow((double)x, (double)y));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Getters and setters for register values
|
||||
******************************************************************************/
|
||||
|
@ -62,6 +62,7 @@ enum HxCalibrationSteps { HX_CAL_END, HX_CAL_LIMBO, HX_CAL_FINISH, HX_CAL_FAIL,
|
||||
const char kHxCalibrationStates[] PROGMEM = D_HX_CAL_FAIL "|" D_HX_CAL_DONE "|" D_HX_CAL_REFERENCE "|" D_HX_CAL_REMOVE;
|
||||
|
||||
long hx_weight = 0;
|
||||
long hx_last_weight = 0;
|
||||
long hx_sum_weight = 0;
|
||||
long hx_offset = 0;
|
||||
long hx_scale = 1;
|
||||
@ -116,11 +117,18 @@ long HxRead()
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void HxReset(void)
|
||||
void HxResetPart(void)
|
||||
{
|
||||
hx_tare_flg = true;
|
||||
hx_sum_weight = 0;
|
||||
hx_sample_count = 0;
|
||||
hx_last_weight = 0;
|
||||
}
|
||||
|
||||
void HxReset(void)
|
||||
{
|
||||
HxResetPart();
|
||||
Settings.energy_frequency_calibration = 0;
|
||||
}
|
||||
|
||||
void HxCalibrationStateTextJson(uint8_t msg_id)
|
||||
@ -147,6 +155,7 @@ void HxCalibrationStateTextJson(uint8_t msg_id)
|
||||
* Sensor34 5 <weight in gram> - Set max weight
|
||||
* Sensor34 6 - Show item weigth in decigram
|
||||
* Sensor34 6 <weight in decigram> - Set item weight
|
||||
* Sensor34 7 - Save current weight to be used as start weight on restart
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool HxCommand(void)
|
||||
@ -199,6 +208,10 @@ bool HxCommand(void)
|
||||
}
|
||||
show_parms = true;
|
||||
break;
|
||||
case 7: // WeightSave
|
||||
Settings.energy_frequency_calibration = hx_weight;
|
||||
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, D_JSON_DONE);
|
||||
break;
|
||||
default:
|
||||
serviced = false;
|
||||
}
|
||||
@ -238,8 +251,7 @@ void HxInit(void)
|
||||
if (!Settings.weight_reference) { Settings.weight_reference = HX_REFERENCE; }
|
||||
hx_scale = Settings.weight_calibration;
|
||||
HxRead();
|
||||
HxReset();
|
||||
|
||||
HxResetPart();
|
||||
hx_type = 1;
|
||||
}
|
||||
}
|
||||
@ -254,7 +266,16 @@ void HxEvery100mSecond(void)
|
||||
long average = hx_sum_weight / hx_sample_count; // grams
|
||||
long value = average - hx_offset; // grams
|
||||
hx_weight = value / hx_scale; // grams
|
||||
if (hx_weight < 0) { hx_weight = 0; }
|
||||
if (hx_weight < 0) {
|
||||
if (Settings.energy_frequency_calibration) {
|
||||
long difference = Settings.energy_frequency_calibration + hx_weight;
|
||||
hx_last_weight = difference;
|
||||
if (difference < 0) { HxReset(); } // Cancel last weight as there seems to be no more weight on the scale
|
||||
}
|
||||
hx_weight = 0;
|
||||
} else {
|
||||
hx_last_weight = Settings.energy_frequency_calibration;
|
||||
}
|
||||
|
||||
if (hx_tare_flg) {
|
||||
hx_tare_flg = false;
|
||||
@ -313,6 +334,8 @@ void HxEvery100mSecond(void)
|
||||
if (!hx_calibrate_timer) {
|
||||
hx_calibrate_step = HX_CAL_END; // End of calibration
|
||||
}
|
||||
} else {
|
||||
hx_weight += hx_last_weight; // grams
|
||||
}
|
||||
|
||||
hx_sum_weight = 0;
|
||||
@ -320,6 +343,12 @@ void HxEvery100mSecond(void)
|
||||
}
|
||||
}
|
||||
|
||||
void HxSaveBeforeRestart()
|
||||
{
|
||||
Settings.energy_frequency_calibration = hx_weight;
|
||||
hx_sample_count = HX_SAMPLES +1; // Stop updating hx_weight
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
const char HTTP_HX711_WEIGHT[] PROGMEM =
|
||||
"{s}HX711 " D_WEIGHT "{m}%s " D_UNIT_KILOGRAM "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
||||
@ -484,6 +513,9 @@ bool Xsns34(uint8_t function)
|
||||
case FUNC_JSON_APPEND:
|
||||
HxShow(1);
|
||||
break;
|
||||
case FUNC_SAVE_BEFORE_RESTART:
|
||||
HxSaveBeforeRestart();
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_SENSOR:
|
||||
HxShow(0);
|
||||
|
299
sonoff/xsns_44_sps30.ino
Normal file
299
sonoff/xsns_44_sps30.ino
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
xsns_44_sps30.ino - Sensirion SPS30
|
||||
|
||||
Copyright (C) 2019 Gerhard Mutz and Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_I2C
|
||||
#ifdef USE_SPS30
|
||||
|
||||
#define XSNS_44 44
|
||||
|
||||
#define SPS30_ADDR 0x69
|
||||
|
||||
#include <Wire.h>
|
||||
#include <twi.h>
|
||||
|
||||
uint8_t sps30_ready = 0;
|
||||
struct SPS30 {
|
||||
float PM1_0;
|
||||
float PM2_5;
|
||||
float PM4_0;
|
||||
float PM10;
|
||||
float NCPM0_5;
|
||||
float NCPM1_0;
|
||||
float NCPM2_5;
|
||||
float NCPM4_0;
|
||||
float NCPM10;
|
||||
float TYPSIZ;
|
||||
} sps30_result;
|
||||
|
||||
#define SPS_CMD_START_MEASUREMENT 0x0010
|
||||
#define SPS_CMD_START_MEASUREMENT_ARG 0x0300
|
||||
#define SPS_CMD_STOP_MEASUREMENT 0x0104
|
||||
#define SPS_CMD_READ_MEASUREMENT 0x0300
|
||||
#define SPS_CMD_GET_DATA_READY 0x0202
|
||||
#define SPS_CMD_AUTOCLEAN_INTERVAL 0x8004
|
||||
#define SPS_CMD_CLEAN 0x5607
|
||||
#define SPS_CMD_GET_ACODE 0xd025
|
||||
#define SPS_CMD_GET_SERIAL 0xd033
|
||||
#define SPS_CMD_RESET 0xd304
|
||||
#define SPS_WRITE_DELAY_US 20000
|
||||
#define SPS_MAX_SERIAL_LEN 32
|
||||
|
||||
uint8_t sps30_calc_CRC(uint8_t *data) {
|
||||
uint8_t crc = 0xFF;
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
crc ^= data[i];
|
||||
for(uint8_t bit = 8; bit > 0; --bit) {
|
||||
if(crc & 0x80) {
|
||||
crc = (crc << 1) ^ 0x31u;
|
||||
} else {
|
||||
crc = (crc << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop);
|
||||
|
||||
void sps30_get_data(uint16_t cmd, uint8_t *data, uint8_t dlen) {
|
||||
unsigned char cmdb[2];
|
||||
uint8_t tmp[3];
|
||||
uint8_t index=0;
|
||||
memset(data,0,dlen);
|
||||
uint8_t twi_buff[64];
|
||||
|
||||
Wire.beginTransmission(SPS30_ADDR);
|
||||
cmdb[0]=cmd>>8;
|
||||
cmdb[1]=cmd;
|
||||
Wire.write(cmdb,2);
|
||||
Wire.endTransmission();
|
||||
|
||||
// need 60 bytes max
|
||||
dlen/=2;
|
||||
dlen*=3;
|
||||
|
||||
twi_readFrom(SPS30_ADDR,twi_buff,dlen,1);
|
||||
|
||||
uint8_t bind=0;
|
||||
while (bind<dlen) {
|
||||
tmp[0] = twi_buff[bind++];
|
||||
tmp[1] = twi_buff[bind++];
|
||||
tmp[2] = twi_buff[bind++];
|
||||
if (sps30_calc_CRC(tmp)!=tmp[2]) {
|
||||
// chksum error
|
||||
index+=2;
|
||||
} else {
|
||||
data[index++]=tmp[0];
|
||||
data[index++]=tmp[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sps30_cmd(uint16_t cmd) {
|
||||
unsigned char cmdb[6];
|
||||
Wire.beginTransmission(SPS30_ADDR);
|
||||
cmdb[0]=cmd>>8;
|
||||
cmdb[1]=cmd;
|
||||
|
||||
if (cmd==SPS_CMD_START_MEASUREMENT) {
|
||||
cmdb[2]=SPS_CMD_START_MEASUREMENT_ARG>>8;
|
||||
cmdb[3]=SPS_CMD_START_MEASUREMENT_ARG&0xff;
|
||||
cmdb[4]=sps30_calc_CRC(&cmdb[2]);
|
||||
Wire.write(cmdb,5);
|
||||
} else {
|
||||
Wire.write(cmdb,2);
|
||||
}
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
void SPS30_Detect() {
|
||||
|
||||
if (!I2cDevice(SPS30_ADDR)) {
|
||||
return;
|
||||
}
|
||||
uint8_t dcode[32];
|
||||
sps30_get_data(SPS_CMD_GET_SERIAL,dcode,sizeof(dcode));
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("sps30 found with serial: %s"),dcode);
|
||||
sps30_cmd(SPS_CMD_START_MEASUREMENT);
|
||||
sps30_ready = 1;
|
||||
}
|
||||
|
||||
#define D_UNIT_PM "ug/m3"
|
||||
#define D_UNIT_NCPM "#/m3"
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
const char HTTP_SNS_SPS30_a[] PROGMEM ="{s}SPS30 " "%s" "{m}%s " D_UNIT_PM "{e}";
|
||||
const char HTTP_SNS_SPS30_b[] PROGMEM ="{s}SPS30 " "%s" "{m}%s " D_UNIT_NCPM "{e}";
|
||||
const char HTTP_SNS_SPS30_c[] PROGMEM ="{s}SPS30 " "TYPSIZ" "{m}%s " "um" "{e}";
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
#define PMDP 2
|
||||
|
||||
#define SPS30_HOURS Settings.sps30_inuse_hours
|
||||
//#define SPS30_HOURS sps30_inuse_hours
|
||||
//uint8_t sps30_inuse_hours;
|
||||
|
||||
void SPS30_Every_Second() {
|
||||
|
||||
if (!sps30_ready) return;
|
||||
|
||||
if (uptime%10==0) {
|
||||
uint8_t vars[sizeof(float)*10];
|
||||
sps30_get_data(SPS_CMD_READ_MEASUREMENT,vars,sizeof(vars));
|
||||
float *fp=&sps30_result.PM1_0;
|
||||
|
||||
typedef union {
|
||||
uint8_t array[4];
|
||||
float value;
|
||||
} ByteToFloat;
|
||||
|
||||
ByteToFloat conv;
|
||||
|
||||
for (uint8_t count=0; count<10; count++) {
|
||||
for (uint8_t i = 0; i < 4; i++){
|
||||
conv.array[3-i] = vars[count*sizeof(float)+i];
|
||||
}
|
||||
*fp++=conv.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (uptime%3600==0 && uptime>60) {
|
||||
// should auto clean once per week runtime
|
||||
// so count hours, should be in Settings
|
||||
SPS30_HOURS++;
|
||||
if (SPS30_HOURS>(7*24)) {
|
||||
sps30_cmd(SPS_CMD_CLEAN);
|
||||
SPS30_HOURS=0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SPS30_Show(bool json) {
|
||||
char str[64];
|
||||
if (!sps30_ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (json) {
|
||||
dtostrfd(sps30_result.PM1_0,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"SPS30\":{\"" "PM1_0" "\":%s"), str);
|
||||
dtostrfd(sps30_result.PM2_5,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"" "PM2_5" "\":%s"), str);
|
||||
dtostrfd(sps30_result.PM4_0,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"" "PM4_0" "\":%s"), str);
|
||||
dtostrfd(sps30_result.PM10,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"" "PM10" "\":%s"), str);
|
||||
dtostrfd(sps30_result.NCPM0_5,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"" "NCPM0_5" "\":%s"), str);
|
||||
dtostrfd(sps30_result.NCPM1_0,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"" "NCPM1_0" "\":%s"), str);
|
||||
dtostrfd(sps30_result.NCPM2_5,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"" "NCPM2_5" "\":%s"), str);
|
||||
dtostrfd(sps30_result.NCPM4_0,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"" "NCPM4_0" "\":%s"), str);
|
||||
dtostrfd(sps30_result.NCPM10,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"" "NCPM10" "\":%s"), str);
|
||||
dtostrfd(sps30_result.TYPSIZ,PMDP,str);
|
||||
ResponseAppend_P(PSTR(",\"" "TYPSIZ" "\":%s}"), str);
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
dtostrfd(sps30_result.PM1_0,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 1.0",str);
|
||||
dtostrfd(sps30_result.PM2_5,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 2.5",str);
|
||||
dtostrfd(sps30_result.PM4_0,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 4.0",str);
|
||||
dtostrfd(sps30_result.PM10,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 10",str);
|
||||
dtostrfd(sps30_result.NCPM0_5,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 0.5",str);
|
||||
dtostrfd(sps30_result.NCPM1_0,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 1.0",str);
|
||||
dtostrfd(sps30_result.NCPM2_5,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 2.5",str);
|
||||
dtostrfd(sps30_result.NCPM4_0,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 4.0",str);
|
||||
dtostrfd(sps30_result.NCPM10,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 10",str);
|
||||
dtostrfd(sps30_result.TYPSIZ,PMDP,str);
|
||||
WSContentSend_PD(HTTP_SNS_SPS30_c,str);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool XSNS_44_cmd(void) {
|
||||
boolean serviced = true;
|
||||
const char S_JSON_SPS30[] = "{\"" D_CMND_SENSOR "%d\":%s}";
|
||||
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
char *cp=XdrvMailbox.data;
|
||||
if (*cp=='c') {
|
||||
// clean cmd
|
||||
sps30_cmd(SPS_CMD_CLEAN);
|
||||
cp++;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SPS30, XSNS_44,"clean_fan");
|
||||
} else {
|
||||
serviced=false;
|
||||
}
|
||||
}
|
||||
return serviced;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
|
||||
bool Xsns44(byte function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (i2c_flg) {
|
||||
switch (function) {
|
||||
case FUNC_INIT:
|
||||
SPS30_Detect();
|
||||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
SPS30_Every_Second();
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
SPS30_Show(1);
|
||||
break;
|
||||
case FUNC_COMMAND_SENSOR:
|
||||
if (XSNS_44 == XdrvMailbox.index) {
|
||||
result = XSNS_44_cmd();
|
||||
}
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_SENSOR:
|
||||
SPS30_Show(0);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_SPS30
|
||||
#endif // USE_I2C
|
@ -908,11 +908,9 @@ Setting_6_5_0_10['flag3'][0].update ({
|
||||
'use_underscore': ('<L', (0x3A0,1,14), (None, None, ('SetOption', '"SetOption64 {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
# ======================================================================
|
||||
Setting_6_5_0_11 = copy.deepcopy(Setting_6_5_0_10)
|
||||
Setting_6_5_0_11['flag3'][0].update ({
|
||||
'tuya_show_dimmer': ('<L', (0x3A0,1,15), (None, None, ('SetOption', '"SetOption65 {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Settings = [
|
||||
(0x605000B, 0xe00, Setting_6_5_0_11),
|
||||
|
@ -106,7 +106,9 @@ a_setoption = [[
|
||||
"Enable normal sleep instead of dynamic sleep",
|
||||
"Force local operation when button/switch topic is set",
|
||||
"Do not use retain flag on HOLD messages",
|
||||
"","","",
|
||||
"Do not scan relay power state at restart",
|
||||
"Use _ instead of - as sensor index separator",
|
||||
"",
|
||||
"","","","",
|
||||
"","","","",
|
||||
"","","","",
|
||||
@ -116,7 +118,7 @@ a_setoption = [[
|
||||
a_features = [[
|
||||
"","","USE_I2C","USE_SPI",
|
||||
"USE_DISCOVERY","USE_ARDUINO_OTA","USE_MQTT_TLS","USE_WEBSERVER",
|
||||
"WEBSERVER_ADVERTISE","USE_EMULATION","MQTT_PUBSUBCLIENT","MQTT_TASMOTAMQTT",
|
||||
"WEBSERVER_ADVERTISE","USE_EMULATION_HUE","MQTT_PUBSUBCLIENT","MQTT_TASMOTAMQTT",
|
||||
"MQTT_ESPMQTTARDUINO","MQTT_HOST_DISCOVERY","USE_ARILUX_RF","USE_WS2812",
|
||||
"USE_WS2812_DMA","USE_IR_REMOTE","USE_IR_HVAC","USE_IR_RECEIVE",
|
||||
"USE_DOMOTICZ","USE_DISPLAY","USE_HOME_ASSISTANT","USE_SERIAL_BRIDGE",
|
||||
@ -127,8 +129,8 @@ a_features = [[
|
||||
"FIRMWARE_KNX_NO_EMULATION","USE_DISPLAY_MODES1TO5","USE_DISPLAY_GRAPH","USE_DISPLAY_LCD",
|
||||
"USE_DISPLAY_SSD1306","USE_DISPLAY_MATRIX","USE_DISPLAY_ILI9341","USE_DISPLAY_EPAPER",
|
||||
"USE_DISPLAY_SH1106","USE_MP3_PLAYER","USE_PCA9685","USE_TUYA_DIMMER",
|
||||
"USE_RC_SWITCH","USE_ARMTRONIX_DIMMERS","","",
|
||||
"","","","NO_EXTRA_4K_HEAP",
|
||||
"USE_RC_SWITCH","USE_ARMTRONIX_DIMMERS","USE_SM16716","USE_SCRIPT",
|
||||
"USE_EMULATION_WEMO","","","NO_EXTRA_4K_HEAP",
|
||||
"VTABLES_IN_IRAM","VTABLES_IN_DRAM","VTABLES_IN_FLASH","PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH",
|
||||
"PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY","PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH","DEBUG_THEO","USE_DEBUG_DRIVER"
|
||||
],[
|
||||
|
Loading…
x
Reference in New Issue
Block a user