mirror of https://github.com/arendst/Tasmota.git
Merge branch 'development' of https://github.com/arendst/Sonoff-Tasmota into chirp
This commit is contained in:
commit
e6eaa42bfe
|
@ -1,52 +1,66 @@
|
||||||
---
|
---
|
||||||
name: Bug report
|
name: Bug report
|
||||||
about: Create a report to help us improve
|
about: Create a report to help us improve
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<GUIDE>
|
> **GUIDE**
|
||||||
|
>
|
||||||
<This BUG issue template is meant to REPORT Tasmota software BUGS ONLY>
|
> This BUG issue template is meant to REPORT Tasmota software BUGS ONLY>
|
||||||
|
>
|
||||||
<Please DO NOT OPEN AN ISSUE:>
|
> Please DO NOT OPEN AN ISSUE:
|
||||||
<If your Tasmota version is not the latest, please update before posting. Your issue might be already solved. Latest precompiled bins of Tasmota can be downloaded from http://thehackbox.org/tasmota/>
|
> - If your Tasmota version is not the latest from the development branch, please update your device before submitting your issue. Your problem might already be solved. The latest precompiled binaries of Tasmota can be downloaded from http://thehackbox.org/tasmota/
|
||||||
<If your issue is a flashing issue, please address that to the Tasmota Support Chat>
|
> - If your issue is a flashing issue, please address it to the [Tasmota Support Chat](https://discord.gg/Ks2Kzd4)
|
||||||
<If your issue is compilation problem, please address that to the Tasmota Support Chat>
|
> - If your issue is compilation problem, please address it to the [Tasmota Support Chat](https://discord.gg/Ks2Kzd4)
|
||||||
<If your issue has been addresed before (duplicated issue), please ask in the original issue>
|
> - If your issue has been addressed before (i.e., duplicated issue), please ask in the original issue
|
||||||
<If your issue is wifi problem or mqtt problem, please try first the steps provided in troubleshooting of the wiki>
|
> - If your issue is a Wi-Fi problem or MQTT problem, please try the steps provided in the [FAQ](https://github.com/arendst/Sonoff-Tasmota/wiki/FAQ) and troubleshooting wiki articles
|
||||||
|
>
|
||||||
Please take a few minutes to complete the requested information below. Our ability to provide assistance is greatly hampered without it. The details requested potentially affect which options to pursue. The small amount of time you spend completing the template will also help the volunteers providing the assistance to you to reduce the time required to help you.
|
> Please take a few minutes to complete the requested information below. Our ability to provide assistance is greatly hampered without it. The details requested potentially affect which options to pursue. The small amount of time you spend completing the template will also help the volunteers providing the assistance to you to reduce the time required to help you.
|
||||||
|
|
||||||
### BUG DESCRIPTION
|
### BUG DESCRIPTION
|
||||||
_A clear and concise description of what the bug is._
|
_A clear and concise description of what the bug is._
|
||||||
|
|
||||||
|
|
||||||
### REQUESTED INFORMATION
|
### REQUESTED INFORMATION
|
||||||
_Make sure these boxes are checked before submitting your issue. Thank you_
|
_Make sure your have performed every step and checked the applicable boxes before submitting your issue. Thank you!_
|
||||||
|
|
||||||
**FAILURE TO COMPLETE THE REQUESTED INFORMATION WILL RESULT IN YOUR ISSUE BEING CLOSED**
|
**FAILURE TO COMPLETE THE REQUESTED INFORMATION WILL RESULT IN YOUR ISSUE BEING CLOSED**
|
||||||
|
|
||||||
- [ ] Read the [Contributing Guide and Policy](https://github.com/arendst/Sonoff-Tasmota/blob/development/CONTRIBUTING.md) and [the Code of Conduct](https://github.com/arendst/Sonoff-Tasmota/blob/development/CODE_OF_CONDUCT.md)
|
- [ ] Read the [Contributing Guide and Policy](https://github.com/arendst/Sonoff-Tasmota/blob/development/CONTRIBUTING.md) and [the Code of Conduct](https://github.com/arendst/Sonoff-Tasmota/blob/development/CODE_OF_CONDUCT.md)
|
||||||
- [ ] Searched the problem in issues (https://github.com/arendst/Sonoff-Tasmota/issues)
|
- [ ] Searched the problem in [issues](https://github.com/arendst/Sonoff-Tasmota/issues)
|
||||||
- [ ] Searched the problem in the wiki (https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting)
|
- [ ] Searched the problem in the [wiki](https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting)
|
||||||
- [ ] Searched the problem in the forum (https://groups.google.com/d/forum/sonoffusers)
|
- [ ] Searched the problem in the [forum](https://groups.google.com/d/forum/sonoffusers)
|
||||||
- [ ] Searched the problem in the chat (https://discord.gg/Ks2Kzd4)
|
- [ ] Searched the problem in the [chat](https://discord.gg/Ks2Kzd4)
|
||||||
- [ ] Device used (i.e. Sonoff Basic) : _____
|
- [ ] Device used (e.g., Sonoff Basic): _____
|
||||||
- [ ] Tasmota binary firmware version number used : ____ / (pre-compiled or self-compiled ?)
|
- [ ] Tasmota binary firmware version number used: _____
|
||||||
- [ ] Development IDE - Compiler / Upload tools used : ____ / ____
|
- [ ] Pre-compiled
|
||||||
- [ ] Provide the output of command ``status 0`` :
|
- [ ] Self-compiled
|
||||||
```
|
- [ ] IDE / Compiler used: _____
|
||||||
STATUS 0 OUTPUT HERE:
|
- [ ] Flashing tools used: _____
|
||||||
|
- [ ] Provide the output of command: ``Backlog Template; Module; GPIO``:
|
||||||
|
```
|
||||||
|
Configuration output here:
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
- [ ] Provide the output of console when you experience your issue if apply :
|
- [ ] If using rules, provide the output of this command: ``Backlog Rule1; Rule2; Rule3``:
|
||||||
_(Please use_ ``weblog 4`` _for more debug information)_
|
```
|
||||||
```
|
Rules output here:
|
||||||
CONSOLE OUTPUT HERE:
|
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
- [ ] Provide the output of this command: ``Status 0``:
|
||||||
|
```
|
||||||
|
STATUS 0 output here:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] Provide the output of the Console log output when you experience your issue; if applicable:
|
||||||
|
_(Please use_ ``weblog 4`` _for more debug information)_
|
||||||
|
```
|
||||||
|
Console output here:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### TO REPRODUCE
|
### TO REPRODUCE
|
||||||
_Steps to reproduce the behavior:_
|
_Steps to reproduce the behavior:_
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
---
|
---
|
||||||
name: Troubleshooting
|
name: Troubleshooting
|
||||||
about: Users Troubleshooting Help
|
about: Users Troubleshooting Help
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<GUIDE>
|
> **GUIDE**
|
||||||
|
>
|
||||||
<This troubleshooting issue template is meant to help Tasmota users with difficult problems. It is aimed to be opened if using the wiki and the support chat could not solve the issue. The Github Issue tracker is NOT a general discussion forum>
|
> This troubleshooting issue template is meant to help Tasmota users with difficult problems. It is aimed to be opened if using the wiki and the support chat could not solve the issue. The Github Issue tracker is NOT a general discussion forum!
|
||||||
|
>
|
||||||
<Please DO NOT OPEN AN ISSUE:>
|
> Please DO NOT OPEN AN ISSUE:
|
||||||
<If you have general questions or you need help on Tasmota usage, go to the Tasmota support chat>
|
> - If you have general questions or you need help on Tasmota usage, go to the [Tasmota Support Chat](https://discord.gg/Ks2Kzd4)
|
||||||
<If your Tasmota version is not the latest, please update before posting. Your issue might be already solved. Latest precompiled bins of Tasmota can be downloaded from http://thehackbox.org/tasmota/>
|
> - If your Tasmota version is not the latest from the development branch, please update your device before submitting your issue. Your problem might already be solved. The latest precompiled binaries of Tasmota can be downloaded from http://thehackbox.org/tasmota/
|
||||||
<If your issue is a new device, please use the Tasmota Template Feature. See wiki for that>
|
> - If your issue is about a new device, please use the Tasmota [Template](../wiki/Templates) feature.
|
||||||
<If your issue is a flashing issue, please address that to the Tasmota Support Chat>
|
> - If your issue is a flashing issue, please address it to the [Tasmota Support Chat](https://discord.gg/Ks2Kzd4)
|
||||||
<If your issue is compilation problem, please address that to the Tasmota Support Chat>
|
> - If your issue is compilation problem, please address it to the [Tasmota Support Chat](https://discord.gg/Ks2Kzd4)
|
||||||
<If your issue has been addresed before (duplicated issue), please ask in the original issue>
|
> - If your issue has been addressed before (i.e., duplicated issue), please ask in the original issue
|
||||||
<If your issue is wifi problem or mqtt problem, please try first the steps provided in troubleshooting of the wiki>
|
> - If your issue is a Wi-Fi problem or MQTT problem, please try the steps provided in the [FAQ](https://github.com/arendst/Sonoff-Tasmota/wiki/FAQ) and troubleshooting wiki articles
|
||||||
|
>
|
||||||
Please take a few minutes to complete the requested information below. Our ability to provide assistance is greatly hampered without it. The details requested potentially affect which options to pursue. The small amount of time you spend completing the template will also help the volunteers providing the assistance to you to reduce the time required to help you.
|
> Please take a few minutes to complete the requested information below. Our ability to provide assistance is greatly hampered without it. The details requested potentially affect which options to pursue. The small amount of time you spend completing the template will also help the volunteers providing the assistance to you to reduce the time required to help you.
|
||||||
|
|
||||||
### ISSUE DESCRIPTION - TROUBLESHOOTING
|
### ISSUE DESCRIPTION - TROUBLESHOOTING
|
||||||
_A clear description of what the issue is and be as extensive as possible_
|
_A clear description of what the issue is and be as extensive as possible_
|
||||||
|
@ -33,20 +32,36 @@ _Make sure these boxes are checked before submitting your issue. Thank you_
|
||||||
- [ ] Searched the problem in the wiki (https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting)
|
- [ ] Searched the problem in the wiki (https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting)
|
||||||
- [ ] Searched the problem in the forum (https://groups.google.com/d/forum/sonoffusers)
|
- [ ] Searched the problem in the forum (https://groups.google.com/d/forum/sonoffusers)
|
||||||
- [ ] Searched the problem in the chat (https://discord.gg/Ks2Kzd4)
|
- [ ] Searched the problem in the chat (https://discord.gg/Ks2Kzd4)
|
||||||
- [ ] Device used (i.e. Sonoff Basic) : _____
|
- [ ] Device used (e.g., Sonoff Basic): _____
|
||||||
- [ ] Tasmota binary firmware version number used : ____ / (pre-compiled or self-compiled ?)
|
- [ ] Tasmota binary firmware version number used: _____
|
||||||
- [ ] Development IDE - Compiler / Upload tools used : ____ / ____
|
- [ ] Pre-compiled
|
||||||
- [ ] Provide the output of command ``status 0`` :
|
- [ ] Self-compiled
|
||||||
```
|
- [ ] IDE / Compiler used: _____
|
||||||
STATUS 0 OUTPUT HERE:
|
- [ ] Flashing tools used: _____
|
||||||
|
- [ ] Provide the output of this command: ``Backlog Template; Module; GPIO``:
|
||||||
|
```
|
||||||
|
Configuration output here:
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
- [ ] Provide the output of console when you experience your issue if apply :
|
- [ ] If using rules, provide the output of this command: ``Backlog Rule1; Rule2; Rule3``:
|
||||||
_(Please use_ ``weblog 4`` _for more debug information)_
|
```
|
||||||
```
|
Rules output here:
|
||||||
CONSOLE OUTPUT HERE:
|
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
- [ ] Provide the output of this command: ``Status 0``:
|
||||||
|
```
|
||||||
|
STATUS 0 output here:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] Provide the output of the Console log output when you experience your issue; if applicable:
|
||||||
|
_(Please use_ ``weblog 4`` _for more debug information)_
|
||||||
|
```
|
||||||
|
Console output here:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
**(Please, remember to close the issue when the problem has been addressed)**
|
**(Please, remember to close the issue when the problem has been addressed)**
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
---
|
---
|
||||||
name: Feature request
|
name: Feature request
|
||||||
about: Suggest an idea for this project
|
about: Suggest an idea for this project
|
||||||
|
|
||||||
---
|
---
|
||||||
Please take a few minutes to complete the requested information below. Our ability to provide assistance is greatly hampered without it. The details requested potentially affect which options to pursue. The small amount of time you spend completing the template will also help the volunteers providing the assistance to you to reduce the time required to help you.
|
|
||||||
|
> Please take a few minutes to complete the requested information below. Our ability to provide assistance is greatly hampered without it. The details requested potentially affect which options to pursue. The small amount of time you spend completing the template will also help the volunteers providing the assistance to you to reduce the time required to help you.
|
||||||
|
|
||||||
**Have you looked for this feature in other issues and in the wiki?**
|
**Have you looked for this feature in other issues and in the wiki?**
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,6 @@
|
||||||
- [ ] The pull request is done against the latest dev branch
|
- [ ] The pull request is done against the latest dev branch
|
||||||
- [ ] Only relevant files were touched
|
- [ ] Only relevant files were touched
|
||||||
- [ ] Only one feature/fix was added per PR.
|
- [ ] Only one feature/fix was added per PR.
|
||||||
- [ ] The code change is tested and works on core 2.3.0, 2.4.2 and 2.5.2
|
- [ ] The code change is tested and works on core 2.3.0, 2.4.2, 2.5.2, and pre-2.6
|
||||||
- [ ] The code change pass travis tests. **Your PR cannot be merged unless tests pass**
|
- [ ] The code change pass travis tests. **Your PR cannot be merged unless tests pass**
|
||||||
- [ ] I accept the [CLA](https://github.com/arendst/Sonoff-Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla).
|
- [ ] I accept the [CLA](https://github.com/arendst/Sonoff-Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla).
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
.piolibdeps
|
.piolibdeps
|
||||||
.clang_complete
|
.clang_complete
|
||||||
.gcc-flags.json
|
.gcc-flags.json
|
||||||
|
.cache
|
||||||
sonoff/user_config_override.h
|
sonoff/user_config_override.h
|
||||||
build
|
build
|
||||||
firmware.map
|
firmware.map
|
||||||
|
|
183
RELEASENOTES.md
183
RELEASENOTES.md
|
@ -1,4 +1,4 @@
|
||||||
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
|
<img src="https://github.com/arendst/Sonoff-Tasmota/blob/master/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
|
||||||
|
|
||||||
# RELEASE NOTES
|
# RELEASE NOTES
|
||||||
|
|
||||||
|
@ -10,8 +10,13 @@ See [wiki migration path](https://github.com/arendst/Sonoff-Tasmota/wiki/Upgrade
|
||||||
3. Migrate to **Sonoff-Tasmota 5.14**
|
3. Migrate to **Sonoff-Tasmota 5.14**
|
||||||
4. Migrate to **Sonoff-Tasmota 6.x**
|
4. Migrate to **Sonoff-Tasmota 6.x**
|
||||||
|
|
||||||
## Core version 2.3.0 vs 2.4.2
|
## Support of TLS
|
||||||
This release is based on ESP8266/Arduino library core 2.3.0 (again) as some people encountered wifi related issues on core 2.4.2. For others core 2.4.2 is working just fine. Both version are available from http://thehackbox.org/tasmota/release/
|
TLS support for core 2.3.0 is removed.
|
||||||
|
|
||||||
|
TLS is supported on core 2.4.2 and up. To save resources when TLS is enabled mDNS needs to be disabled. In addition to TLS using fingerprints now also user supplied CA certs and AWS IoT is supported. See full documentation on https://github.com/arendst/Sonoff-Tasmota/wiki/AWS-IoT
|
||||||
|
|
||||||
|
## Core version 2.3.0 vs 2.4.2 vs 2.5.2
|
||||||
|
This release is based on ESP8266/Arduino library core 2.3.0 as some people encountered wifi related issues on core 2.4.2 and 2.5.2. For others core 2.4.2 or 2.5.2 is working just fine. All version are available from http://thehackbox.org/tasmota/release/
|
||||||
|
|
||||||
## Change in default initial configuration tool
|
## Change in default initial configuration tool
|
||||||
Firmware binary **sonoff-classic.bin** supports **WifiManager, Wps and SmartConfig** for initial configuration. The default tool is **Wps**.
|
Firmware binary **sonoff-classic.bin** supports **WifiManager, Wps and SmartConfig** for initial configuration. The default tool is **Wps**.
|
||||||
|
@ -92,6 +97,7 @@ Module | Description
|
||||||
67 SP10 | Tuya SP10 Wifi Smart Switch with Energy Monitoring
|
67 SP10 | Tuya SP10 Wifi Smart Switch with Energy Monitoring
|
||||||
68 WAGA CHCZ02MB | WAGA life CHCZ02MB Wifi Smart Switch with Energy Monitoring
|
68 WAGA CHCZ02MB | WAGA life CHCZ02MB Wifi Smart Switch with Energy Monitoring
|
||||||
69 SYF05 | Sunyesmart SYF05 RGBWW Wifi Led Bulb
|
69 SYF05 | Sunyesmart SYF05 RGBWW Wifi Led Bulb
|
||||||
|
70 Sonoff L1 | Sonoff L1 light strip
|
||||||
|
|
||||||
## Provided Binary Downloads
|
## Provided Binary Downloads
|
||||||
The following binary downloads have been compiled with ESP8266/Arduino library core version **2.3.0**.
|
The following binary downloads have been compiled with ESP8266/Arduino library core version **2.3.0**.
|
||||||
|
@ -107,6 +113,8 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
|
||||||
|
|
||||||
Core version **2.4.2** binaries can be found at http://thehackbox.org/tasmota/release/020402/
|
Core version **2.4.2** binaries can be found at http://thehackbox.org/tasmota/release/020402/
|
||||||
|
|
||||||
|
Core version **2.5.2** binaries can be found at http://thehackbox.org/tasmota/release/020502/
|
||||||
|
|
||||||
## Available Features and Sensors
|
## Available Features and Sensors
|
||||||
|
|
||||||
| Feature or Sensor | minimal | basic | classic | sonoff | knx | sensors | display | Remarks
|
| Feature or Sensor | minimal | basic | classic | sonoff | knx | sensors | display | Remarks
|
||||||
|
@ -118,9 +126,12 @@ Core version **2.4.2** binaries can be found at http://thehackbox.org/tasmota/re
|
||||||
| USE_DOMOTICZ | - | - | x | x | x | x | - |
|
| USE_DOMOTICZ | - | - | x | x | x | x | - |
|
||||||
| USE_HOME_ASSISTANT | - | - | - | x | x | x | - |
|
| USE_HOME_ASSISTANT | - | - | - | x | x | x | - |
|
||||||
| USE_MQTT_TLS | - | - | - | - | - | - | - |
|
| USE_MQTT_TLS | - | - | - | - | - | - | - |
|
||||||
|
| USE_MQTT_TLS_CA_CERT | - | - | - | - | - | - | - |
|
||||||
|
| USE_MQTT_AWS_IOT | - | - | - | - | - | - | - |
|
||||||
| USE_KNX | - | - | - | - | x | - | - |
|
| USE_KNX | - | - | - | - | x | - | - |
|
||||||
| USE_WEBSERVER | x | x | x | x | x | x | x | WifiManager
|
| USE_WEBSERVER | x | x | x | x | x | x | x | WifiManager
|
||||||
| USE_EMULATION | - | x | x | x | - | x | - |
|
| USE_EMULATION_HUE | - | x | x | x | - | x | - |
|
||||||
|
| USE_EMULATION_WEMO | - | x | x | x | - | x | - |
|
||||||
| USE_DISCOVERY | - | - | x | x | x | x | x |
|
| USE_DISCOVERY | - | - | x | x | x | x | x |
|
||||||
| WEBSERVER_ADVERTISE | - | - | x | x | x | x | x |
|
| WEBSERVER_ADVERTISE | - | - | x | x | x | x | x |
|
||||||
| MQTT_HOST_DISCOVERY | - | - | x | x | x | x | x |
|
| MQTT_HOST_DISCOVERY | - | - | x | x | x | x | x |
|
||||||
|
@ -128,12 +139,15 @@ Core version **2.4.2** binaries can be found at http://thehackbox.org/tasmota/re
|
||||||
| USE_TIMERS_WEB | - | x | - | x | x | x | x |
|
| USE_TIMERS_WEB | - | x | - | x | x | x | x |
|
||||||
| USE_SUNRISE | - | x | - | x | x | x | x |
|
| USE_SUNRISE | - | x | - | x | x | x | x |
|
||||||
| USE_RULES | - | x | - | x | x | x | x |
|
| USE_RULES | - | x | - | x | x | x | x |
|
||||||
|
| USE_SCRIPT | - | - | - | - | - | - | - |
|
||||||
| USE_EXPRESSION | - | - | - | - | - | - | - |
|
| USE_EXPRESSION | - | - | - | - | - | - | - |
|
||||||
| | | | | | | | |
|
| | | | | | | | |
|
||||||
| USE_ADC_VCC | x | x | x | x | x | - | x |
|
| USE_ADC_VCC | x | x | x | - | - | - | - |
|
||||||
|
| USE_COUNTER | - | - | - | x | x | x | x |
|
||||||
| USE_DS18B20 | - | - | - | - | - | - | - | Single sensor
|
| USE_DS18B20 | - | - | - | - | - | - | - | Single sensor
|
||||||
| USE_DS18x20 | - | - | x | x | x | x | x | Multiple sensors
|
| USE_DS18x20 | - | - | x | x | x | x | x | Multiple sensors
|
||||||
| USE_DS18x20_LEGACY | - | - | - | - | - | - | - | Multiple sensors
|
| USE_DS18x20_LEGACY | - | - | - | - | - | - | - | Multiple sensors
|
||||||
|
| USE_DHT | - | - | x | x | x | x | x |
|
||||||
| | | | | | | | |
|
| | | | | | | | |
|
||||||
| Feature or Sensor | minimal | basic | classic | sonoff | knx | sensors | display | Remarks
|
| Feature or Sensor | minimal | basic | classic | sonoff | knx | sensors | display | Remarks
|
||||||
| USE_I2C | - | - | - | x | x | x | x |
|
| USE_I2C | - | - | - | x | x | x | x |
|
||||||
|
@ -162,6 +176,10 @@ Core version **2.4.2** binaries can be found at http://thehackbox.org/tasmota/re
|
||||||
| USE_MGC3130 | - | - | - | - | - | - | - |
|
| USE_MGC3130 | - | - | - | - | - | - | - |
|
||||||
| USE_MAX44009 | - | - | - | - | - | - | - |
|
| USE_MAX44009 | - | - | - | - | - | - | - |
|
||||||
| USE_SCD30 | - | - | - | - | - | x | - |
|
| USE_SCD30 | - | - | - | - | - | x | - |
|
||||||
|
| USE_SPS30 | - | - | - | - | - | - | - |
|
||||||
|
| USE_ADE7953 | - | - | - | x | x | x | x |
|
||||||
|
| USE_VL53L0X | - | - | - | - | - | - | - |
|
||||||
|
| USE_MLX90614 | - | - | - | - | - | - | - |
|
||||||
| | | | | | | | |
|
| | | | | | | | |
|
||||||
| Feature or Sensor | minimal | basic | classic | sonoff | knx | sensors | display | Remarks
|
| Feature or Sensor | minimal | basic | classic | sonoff | knx | sensors | display | Remarks
|
||||||
| USE_SPI | - | - | - | - | - | - | x |
|
| USE_SPI | - | - | - | - | - | - | x |
|
||||||
|
@ -206,81 +224,80 @@ Core version **2.4.2** binaries can be found at http://thehackbox.org/tasmota/re
|
||||||
| USE_DISPLAY_EPAPER_29 | - | - | - | - | - | - | x | Disabled for core 2.3.0
|
| USE_DISPLAY_EPAPER_29 | - | - | - | - | - | - | x | Disabled for core 2.3.0
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
Version 6.5.0 20190319
|
Version 6.6.0 20190707
|
||||||
* Remove commands SetOption14 and SetOption63 as it has been superseded by command Interlock
|
* Remove support of TLS on core 2.3.0 and extent support on core 2.4.2 and up
|
||||||
* Remove command SetOption35 0-255 for mDNS start-up delay (#4793)
|
* Remove MQTT uptime message every hour
|
||||||
* Remove support for MQTT_LIBRARY_TYPE, MQTT_ARDUINOMQTT and MQTT_TASMOTAMQTT (#5474)
|
* Refactor some defines to const
|
||||||
* Change webserver content handling from single String to small Chunks increasing RAM
|
* Refactor webserver HTML input, button, textarea, and select name based on id
|
||||||
* Change code use of boolean to bool and byte to uint8_t
|
* Refactor webserver sensor data collection
|
||||||
* Change code uint8_t flags to bool flags
|
* Refactor TLS based on BearSSL, warning breaking change for fingerprints validation
|
||||||
* Change sonoff_template.h layout regarding optional module flags like ADC0
|
* Refactor management of lights, using classes and integers instead of floats
|
||||||
* Change sonoff_template.h module lay-out by removing non-configurable GPIOs
|
* Refactor UDP initial message handling from string to char using static memory and add debug info (#5505)
|
||||||
* Change button driver making it modular
|
* Refactor ``IRsend`` and receive for 64-bit support (#5523)
|
||||||
* Change switch driver making it modular and introduce input filter (#4665, #4724)
|
* Refactor MQTT which might solve issue (#5755)
|
||||||
* Change switch input detection by optimizing switch debounce (#4724)
|
* Refactor ``IRSend`` by using heap when more than 199 values need to be send. May need increase of define MQTT_MAX_PACKET_SIZE too (#5950)
|
||||||
* Change web authentication (#4865)
|
* Refactor double to float in rules, and replaced trigonometric functions from stdlib with smaller versions (#6005)
|
||||||
* Change image name BE_MINIMAL to FIRMWARE_MINIMAL and USE_xyz to FIRMWARE_xyz (#5106)
|
* Change pubsubclient MQTT_KEEPALIVE from 10 to 30 seconds for AWS IoT support
|
||||||
* Change GUI weblog from XML to plain text solving possible empty screens (#5154)
|
* Change gamma correction as default behavior, ie "Ledtable 1"
|
||||||
* Fix most compiler warnings
|
* Change PWM resolution from 8 to 10 bits for low brightness lights
|
||||||
* Fix Display exception 28 when JSON value is NULL received
|
* Change ``IRSend`` Panasonic protocol to 64-bit (#5523)
|
||||||
* Fix epaper driver (#4785)
|
* Change ADC0 to enabled by default in my_user_config.h (#5671)
|
||||||
* Fix HAss Sensor Discovery Software Watchdog restart (#4831, #4988)
|
* Change define USE_EMULATION by USE_EMULATION_HUE and USE_EMULATION_WEMO (#5826)
|
||||||
* Fix allowable MAX_RULE_VARS to 16 (#4933)
|
* Change default ``PowerDelta`` from 80% to 0% on new installations (#5858, #5028, #4813, #4130, #4145, #3795, #3778, #3660, #3648)
|
||||||
* Fix mDNS addService (#4938, #4951)
|
* Fix display Bug in KNX webmenu for Physical Address
|
||||||
* Fix HAss discovery of MHZ19(B) sensors (#4992)
|
* Fix the Unescape() function and the ``SendSerial3`` behaviour
|
||||||
* Fix some exceptions and watchdogs due to lack of stack space (#5215)
|
* Fix webserver multiple Javascript window.onload functionality
|
||||||
* Fix GUI wifi password acception starting with asteriks (*) (#5231, #5242)
|
* Fix TasmotaSerial at 9600 bps solving DFPlayer comms (#5528)
|
||||||
* Fix command WebSend intermittent results (#5273, #5304)
|
* Fix Configure Timer Web GUI (#5568)
|
||||||
* Fix additional characters in fallbacktopic, hostname and mqttclient on core 2.5.0 (#5359, #5417)
|
* Fix Shelly 2.5 I2C address priority issue when VEML6070 code is present by disabling VEML6070 for Shelly 2.5 (#5592)
|
||||||
* Fix Energy TotalStartTime when commands EnergyReset0 and/or EnergyReset3 used (#5373)
|
* Fix use of ``SerialDelimiter`` value 128 (#5634)
|
||||||
* Fix DS18S20 temperature calculation (#5375)
|
* Fix Sonoff Pow R2 / S31 invalid energy increments (#5789)
|
||||||
* Fix float calculations in range from 0 to -1 (#5386)
|
* Fix core 2.5.x ISR not in IRAM exception (#5837)
|
||||||
* Fix exception on GUI Configure Logging and Configure Other (#5424)
|
* Fix Philips Hue emulation Alexa issue by using part of MAC address for LightId (#5849)
|
||||||
* Add commands PowerCal, VoltageCal and CurrentCal for HLW8012, HJL01 and BL0937 based energy sensors
|
* Fix missing white channel for WS2812 (#5869)
|
||||||
* Add command SerialDelimiter 128 to filter reception of only characters between ASCII 32 and 127 (#5131)
|
* Fix PZem startup issue (#5875)
|
||||||
* Add command SSerialSend5 \<hexdata\> to SerialBridge
|
* Fix exception 9 when syslog is enabled and NTP is just synced (#5917)
|
||||||
* Add command Interlock 0 / 1 / 1,2 3,4 .. to control interlock ON/OFF and add up to 8 relays in 1 to 4 interlock groups (#4910, #5014)
|
* Fix Toggle functionality to button double press when one button and two devices are detected (#5935)
|
||||||
* Add command Template 255 to copy module configuration over to current active template and store as user template named Merged (#5371)
|
* Fix command ``Channel`` for dual dimmers (#5940)
|
||||||
* Add command WifiConfig 7 to allow reset of device in AP mode without admin password (#5297)
|
* Fix not restoring white value on power off/power on (#5993)
|
||||||
* Add command SetOption36 to control boot loop default restoration (#4645, #5063)
|
* Add command ``AdcParam`` to control ADC0 Temperature and Light formula parameters
|
||||||
* Add command SetOption37 for RGBCW color mapping (#5326)
|
* Add command ``LedMask`` to assign which relay has access to power LED (#5602, #5612)
|
||||||
* Add command SetOption55 0/1 and define MDNS_ENABLE to disable/enable mDNS (#4793, #4923)
|
* Add extended LED power control using command ``LedPowerX`` where X is 1 to 4. Enabled when "LedLink(i)" is configured too (#5709)
|
||||||
* Add command SetOption62 0/1 to disable retain on Button or Switch hold messages (#5299)
|
* Add command ``Sensor20 1..255`` to change Nova Fitness SDS01 working period in minutes (#5452)
|
||||||
* Add support for Smanergy KA10 Smart Wall Socket with Energy monitoring
|
* Add command ``SetOption38 6..255`` to set IRReceive protocol detection sensitivity mimizing UNKNOWN protocols (#5853)
|
||||||
* Add support for commands in sensor drivers
|
* Add command ``SetOption39 1..255`` to control CSE7766 (Pow R2) or HLW8032 (Blitzwolf SHP5) handling of power loads below 6W. Default setting is 128 (#5756)
|
||||||
* Add support for MAX31855 K-Type thermocouple sensor using softSPI (#4764)
|
* Add command ``SetOption40 0..250`` to disable button functionality if activated for over 0.1 second. Needs SetOption1 1 and SetOption13 0 (#5449)
|
||||||
* Add support for Near Field Communication (NFC) controller PN532 using Serial (#4791, #5162)
|
* Add command ``SetOption63 0/1`` to disable relay state feedback scan at restart (#5594, #5663)
|
||||||
* Add support for OBI Power Socket 2 (#4829)
|
* Add command ``SetOption64 0/1`` to switch between "-" or "_" as sensor index separator impacting DS18X20, DHT, BMP and SHT3X sensor names (#5689)
|
||||||
* Add support for YTF IR Bridge (#4855)
|
* Add command ``SetOption65 0/1`` and more Tuya Serial based device support (#5815)
|
||||||
* Add support for Mi LED Desk Lamp with rotary switch (#4887)
|
* Add command ``WebColor`` to change GUI colors on the fly
|
||||||
* Add support for Digoo DG-SP202 Smart Socket with Energy monitoring (#4891)
|
* Add support for AWS IoT with TLS 1.2 on core 2.4.2 and up. Full doc here: https://github.com/arendst/Sonoff-Tasmota/wiki/AWS-IoT
|
||||||
* Add support for MAX44009 Ambient Light sensor (#4907)
|
* Add support for Badger HR-E Water Meter (#5539)
|
||||||
* Add support for inverted buttons and inverted buttons without pullup (#4914)
|
* Add support for Shelly 2.5 Energy and overtemp Monitoring (#5592)
|
||||||
* Add support for Luminea ZX2820 Smart Socket with Energy monitoring (#4921)
|
* Add support for color and colortone for Philips Hue emulation via Alexa (#5600 #4809)
|
||||||
* Add support for multiple ADS1115 I2C devices (#5083)
|
* Add support for Scripts as replacement for Rules. Default disabled but can be enabled in my_user_config.h (#5689)
|
||||||
* Add support for online template change using command Template or GUI Configure Other (#5177)
|
* Add support for up to four LEDs related to four power outputs. Enabled when "LedLink(i)" is configured too (#5709)
|
||||||
* Add support for Korean language translations (#5344)
|
* Add support for Shelly 1PM Template ``{"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18}`` (#5716)
|
||||||
* Add support for sensor SCD30 (#5434)
|
* Add support for SPS30 Particle sensor thanks to Gerhard Mutz (#5830)
|
||||||
* Add parameter CFG_HOLDER to status 1 message (#5206)
|
* Add support for VL53L0x time of flight sensor. Might interfere with TSL2561 using same I2C address (#5845)
|
||||||
* Add SetOption32 until SetOption49 diagnostic information to Status 3 report as replacement for second property value in SetOption property name
|
* Add support for Sonoff L1 thanks to reef-actor (#6002)
|
||||||
* Add Resolution property to Status 3 report providing previous SetOption second value property
|
* Add rule Http#Initialized
|
||||||
* Add property MqttCount to status 6 message representing number of Mqtt re-connections
|
* Add rule System#Save executed just before a planned restart
|
||||||
* Add property LinkCount to state and status 11 message representing number of Wifi Link re-connections
|
* Add rule support for single JSON value pair like {"SSerialReceived":"on"} by expanding it to {"SSerialReceived":{"Data":"on"}} allowing for trigger SSerialReceived#Data=on (#5638)
|
||||||
* Add property Downtime to state and status 11 message representing the duration of wifi connection loss
|
* Add define USE_COUNTER to my_user_config.h to save space in sonoff-basic.bin and sonoff-minimal.bin
|
||||||
* Add variable %timestamp% to rules (#4749)
|
* Add define USE_DHT to my_user_config.h to save space in sonoff-basic.bin
|
||||||
* Add rule support for "==", "!=" ">=" and "<=" (#5122)
|
* Add defines USE_EMULATION_WEMO and USE_EMULATION_HUE to my_user_config.h to control emulation features at compile time (#5826)
|
||||||
* Add rule expression enabled by define USE_EXPRESSION in my_user_config.h (#5210)
|
* Add Toggle functionality to button double press when more devices are detected
|
||||||
* Add Power status functionality to LED2 when configured leaving LED1 for Link status indication
|
* Add device OverTemp (>73 Celsius) detection to Energy Monitoring devices with temperature sensor powering off all outputs
|
||||||
* Add user configuration of HLW8012 and HJL-01/BL0937 Energy Monitoring as used in Sonoff Pow and many Tuya based devices
|
* Add Tuya Dimmer 10 second heartbeat serial packet required by some Tuya dimmer secondary MCUs
|
||||||
* Add user configuration of MCP39F501 Energy Monitoring as used in Shelly2
|
* Add all temperature, humidity and pressure for global access
|
||||||
* Add online template configuration using both commands and Configure Template menu option in GUI
|
* Add validation check when loading settings from flash
|
||||||
* Add (S)SerialSend3 escape sequence \x to allow hexadecimal byte value (#3560, #4947)
|
* Add HX711 weight restore after controlled restart or after power restore just before executing command Sensor34 7 (#5367, #5786)
|
||||||
* Add define DS18B20_INTERNAL_PULLUP to select internal input pullup when only one DS18B20 sensor is connected eliminating external resistor (#4738)
|
* Add GUI hexadecimal color options in my_user_config.h (#5586)
|
||||||
* Add button control when no relay configured (#4682)
|
* Add alternative ``IRSend`` command syntax ``IRSend raw,<freq>,<header mark>,<header space>,<bit mark>,<zero space>,<one space>,<bit stream>`` (#5610)
|
||||||
* Add startup delay of 4 seconds to button control (#4829)
|
* Add user configurable ADC0 to Module and Template configuration compatible with current FLAG options (#5671)
|
||||||
* Add core version conditional compile options to provided PWM files (#4917)
|
* Add AriLux RF control GPIO option "ALux IrSel" (159) replacing "Led4i" (59) for full LED control (#5709)
|
||||||
* Add resiliency to saved Settings (#5065)
|
* Add LED GPIO option "LedLink" (157) and "LedLinki" (158) to select dedicated link status LED (#5709)
|
||||||
* Add MHZ19 Temperature as Domoticz Temperature selection (#5128)
|
* Add all 5 PWM channels individually adressable with LEDs. (#5741)
|
||||||
* Add HAss status sensor (#5139)
|
* Add reset of Energy values when connection to sensor is lost for over 4 seconds (#5874, #5881)
|
||||||
* Add status message to former declined group commands (#5145)
|
* Add checkbox to GUI password field enabling visibility during password entry only (#5934)
|
||||||
* Add 0x to IRRemote (SetOption29) and RCSwitch (SetOption28) received hexadecimal data (#5431)
|
|
|
@ -10,6 +10,7 @@
|
||||||
[platformio]
|
[platformio]
|
||||||
src_dir = sonoff
|
src_dir = sonoff
|
||||||
build_dir = .pioenvs
|
build_dir = .pioenvs
|
||||||
|
build_cache_dir = .cache
|
||||||
|
|
||||||
; *** Uncomment one of the lines below to build/upload only one environment
|
; *** Uncomment one of the lines below to build/upload only one environment
|
||||||
;default_envs = sonoff
|
;default_envs = sonoff
|
||||||
|
|
|
@ -1,4 +1,15 @@
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
* 6.6.0.14 20190925
|
||||||
|
* Change command Tariffx to allow time entries like 23 (hours), 1320 (minutes) or 23:00. NOTE: As this is development branch previous tariffs are lost! (#6488)
|
||||||
|
* Remove support for define USE_DS18x20_LEGACY and legacy DS18x20 driver (#6486)
|
||||||
|
* Add initial support for MQTT logging using command MqttLog <loglevel> (#6498)
|
||||||
|
*
|
||||||
|
* 6.6.0.13 20190922
|
||||||
|
* Add command EnergyReset4 x,x to initialize total usage for two tarrifs
|
||||||
|
* Add command EnergyReset5 x,x to initialize total export (or production) for two tarrifs
|
||||||
|
* Add command Sensor34 8,0 and Sensor34 8,1 to disable/enable JSON message on weight change over 4 gram
|
||||||
|
* Add JSON array index support to rules evaluation allowing trigger on ENERGY#POWER[2]>0.60 from JSON ..,"Power":[0.00,0.68],.. (#6160)
|
||||||
|
*
|
||||||
* 6.6.0.12 20190910
|
* 6.6.0.12 20190910
|
||||||
* Redesign command Tariff to now default to 0 (=disabled) and allowing to set both Standard Time (ST) and Daylight Savings Time (DST) start hour
|
* Redesign command Tariff to now default to 0 (=disabled) and allowing to set both Standard Time (ST) and Daylight Savings Time (DST) start hour
|
||||||
* Commands Tariff1 22,23 = Tariff1 (Off-Peak) ST,DST Tariff2 (Standard) 6,7 = Tariff2 ST,DST Tariff9 0/1 = Weekend toggle (1 = Off-Peak during weekend)
|
* Commands Tariff1 22,23 = Tariff1 (Off-Peak) ST,DST Tariff2 (Standard) 6,7 = Tariff2 ST,DST Tariff9 0/1 = Weekend toggle (1 = Off-Peak during weekend)
|
||||||
|
|
|
@ -175,6 +175,8 @@
|
||||||
#define D_JSON_PV2_CURRENT "Pv2Current"
|
#define D_JSON_PV2_CURRENT "Pv2Current"
|
||||||
#define D_JSON_PV2_POWER "Pv2Power"
|
#define D_JSON_PV2_POWER "Pv2Power"
|
||||||
#define D_JSON_SOLAR_POWER "SolarPower"
|
#define D_JSON_SOLAR_POWER "SolarPower"
|
||||||
|
#define D_JSON_USAGE "Usage"
|
||||||
|
#define D_JSON_EXPORT "Export"
|
||||||
|
|
||||||
#define D_RSLT_ENERGY "ENERGY"
|
#define D_RSLT_ENERGY "ENERGY"
|
||||||
#define D_RSLT_HASS_STATE "HASS_STATE"
|
#define D_RSLT_HASS_STATE "HASS_STATE"
|
||||||
|
@ -289,6 +291,7 @@
|
||||||
#define D_JSON_BASE "BASE"
|
#define D_JSON_BASE "BASE"
|
||||||
|
|
||||||
// Commands xdrv_01_mqtt.ino
|
// Commands xdrv_01_mqtt.ino
|
||||||
|
#define D_CMND_MQTTLOG "MqttLog"
|
||||||
#define D_CMND_MQTTHOST "MqttHost"
|
#define D_CMND_MQTTHOST "MqttHost"
|
||||||
#define D_CMND_MQTTPORT "MqttPort"
|
#define D_CMND_MQTTPORT "MqttPort"
|
||||||
#define D_CMND_MQTTRETRY "MqttRetry"
|
#define D_CMND_MQTTRETRY "MqttRetry"
|
||||||
|
|
|
@ -321,11 +321,9 @@
|
||||||
//#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices
|
//#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices
|
||||||
|
|
||||||
// -- One wire sensors ----------------------------
|
// -- One wire sensors ----------------------------
|
||||||
// WARNING: Select none for default one DS18B20 sensor or enable one of the following two options for multiple sensors
|
|
||||||
//#define USE_DS18x20_LEGACY // Optional for more than one DS18x20 sensors with dynamic scan using library OneWire (+1k5 code)
|
|
||||||
#define USE_DS18x20 // Optional for more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code)
|
#define USE_DS18x20 // Optional for more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code)
|
||||||
// #define W1_PARASITE_POWER // If using USE_DS18x20 then optimize for parasite powered sensors
|
// #define W1_PARASITE_POWER // Optimize for parasite powered sensors
|
||||||
// #define DS18B20_INTERNAL_PULLUP // Use INPUT_PULLUP internal pullup resistors for single DS18B20
|
// #define DS18B20_INTERNAL_PULLUP // Use INPUT_PULLUP internal pullup resistor
|
||||||
|
|
||||||
// -- I2C sensors ---------------------------------
|
// -- I2C sensors ---------------------------------
|
||||||
#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram)
|
#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram)
|
||||||
|
@ -498,10 +496,10 @@
|
||||||
#define IR_RCV_MIN_UNKNOWN_SIZE 6 // Set the smallest sized "UNKNOWN" message packets we actually care about (default 6, max 255)
|
#define IR_RCV_MIN_UNKNOWN_SIZE 6 // Set the smallest sized "UNKNOWN" message packets we actually care about (default 6, max 255)
|
||||||
|
|
||||||
// -- Zigbee interface ----------------------------
|
// -- Zigbee interface ----------------------------
|
||||||
//#define USE_ZIGBEE // Enable serial communication with Zigbee CC2530 flashed with ZNP
|
//#define USE_ZIGBEE // Enable serial communication with Zigbee CC2530 flashed with ZNP
|
||||||
#define USE_ZIGBEE_PANID 0x1A63 // arbitrary PAN ID for Zigbee network, must be unique in the home
|
#define USE_ZIGBEE_PANID 0x1A63 // arbitrary PAN ID for Zigbee network, must be unique in the home
|
||||||
#define USE_ZIGBEE_EXTPANID 0xCCCCCCCCCCCCCCCCL // arbitrary extended PAN ID
|
#define USE_ZIGBEE_EXTPANID 0xCCCCCCCCCCCCCCCCL // arbitrary extended PAN ID
|
||||||
#define USE_ZIGBEE_CHANNEL 0x00000800 // Zigbee Channel (11)
|
#define USE_ZIGBEE_CHANNEL 11 // Zigbee Channel (11-26)
|
||||||
#define USE_ZIGBEE_PRECFGKEY_L 0x0F0D0B0907050301L // note: changing requires to re-pair all devices
|
#define USE_ZIGBEE_PRECFGKEY_L 0x0F0D0B0907050301L // note: changing requires to re-pair all devices
|
||||||
#define USE_ZIGBEE_PRECFGKEY_H 0x0D0C0A0806040200L // note: changing requires to re-pair all devices
|
#define USE_ZIGBEE_PRECFGKEY_H 0x0D0C0A0806040200L // note: changing requires to re-pair all devices
|
||||||
#define USE_ZIGBEE_PERMIT_JOIN false // don't allow joining by default
|
#define USE_ZIGBEE_PERMIT_JOIN false // don't allow joining by default
|
||||||
|
|
|
@ -171,18 +171,18 @@ typedef union {
|
||||||
uint8_t spare3 : 1;
|
uint8_t spare3 : 1;
|
||||||
uint8_t spare4 : 1;
|
uint8_t spare4 : 1;
|
||||||
uint8_t spare5 : 1;
|
uint8_t spare5 : 1;
|
||||||
uint8_t spare6 : 1;
|
uint8_t hx711_json_weight_change : 1; // Sensor34 8,x - Enable JSON message on weight change
|
||||||
uint8_t mhz19b_abc_disable : 1; // Disable ABC (Automatic Baseline Correction for MHZ19(B) (0 = Enabled (default), 1 = Disabled with Sensor15 command)
|
uint8_t mhz19b_abc_disable : 1; // Disable ABC (Automatic Baseline Correction for MHZ19(B) (0 = Enabled (default), 1 = Disabled with Sensor15 command)
|
||||||
};
|
};
|
||||||
} SensorCfg1;
|
} SensorCfg1;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t usage1_kWhtotal;
|
uint32_t usage1_kWhtotal;
|
||||||
uint32_t usage1_kWhtoday;
|
uint32_t usage2_kWhtotal;
|
||||||
uint32_t return1_kWhtotal;
|
uint32_t return1_kWhtotal;
|
||||||
uint32_t return2_kWhtotal;
|
uint32_t return2_kWhtotal;
|
||||||
uint32_t last_return_kWhtotal;
|
uint32_t last_return_kWhtotal;
|
||||||
uint32_t free;
|
uint32_t last_usage_kWhtotal;
|
||||||
} EnergyUsage;
|
} EnergyUsage;
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,7 +227,8 @@ struct SYSCFG {
|
||||||
uint8_t weblog_level; // 1AC
|
uint8_t weblog_level; // 1AC
|
||||||
uint8_t mqtt_fingerprint[2][20]; // 1AD
|
uint8_t mqtt_fingerprint[2][20]; // 1AD
|
||||||
uint8_t adc_param_type; // 1D5
|
uint8_t adc_param_type; // 1D5
|
||||||
uint8_t register8[18]; // 1D6 - 18 x 8-bit registers indexed by enum SettingsRegister8
|
uint8_t register8[17]; // 1D6 - 17 x 8-bit registers indexed by enum SettingsRegister8
|
||||||
|
uint8_t mqttlog_level; // 1E7
|
||||||
uint8_t sps30_inuse_hours; // 1E8
|
uint8_t sps30_inuse_hours; // 1E8
|
||||||
char mqtt_host[33]; // 1E9 - Keep together with below as being copied as one chunck with reset 6
|
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
|
uint16_t mqtt_port; // 20A - Keep together
|
||||||
|
@ -373,8 +374,9 @@ struct SYSCFG {
|
||||||
TuyaFnidDpidMap tuya_fnid_map[MAX_TUYA_FUNCTIONS]; // E00 32 bytes
|
TuyaFnidDpidMap tuya_fnid_map[MAX_TUYA_FUNCTIONS]; // E00 32 bytes
|
||||||
uint16_t ina226_r_shunt[4]; // E20
|
uint16_t ina226_r_shunt[4]; // E20
|
||||||
uint16_t ina226_i_fs[4]; // E28
|
uint16_t ina226_i_fs[4]; // E28
|
||||||
|
uint16_t tariff[4][2]; // E30
|
||||||
|
|
||||||
uint8_t free_e30[456]; // E30
|
uint8_t free_e40[440]; // E40
|
||||||
|
|
||||||
uint32_t cfg_timestamp; // FF8
|
uint32_t cfg_timestamp; // FF8
|
||||||
uint32_t cfg_crc32; // FFC
|
uint32_t cfg_crc32; // FFC
|
||||||
|
|
|
@ -113,7 +113,7 @@ const uint16_t SERIALLOG_TIMER = 600; // Seconds to disable SerialLog
|
||||||
const uint8_t OTA_ATTEMPTS = 5; // Number of times to try fetching the new firmware
|
const uint8_t OTA_ATTEMPTS = 5; // Number of times to try fetching the new firmware
|
||||||
|
|
||||||
const uint16_t INPUT_BUFFER_SIZE = 520; // Max number of characters in (serial and http) command buffer
|
const uint16_t INPUT_BUFFER_SIZE = 520; // Max number of characters in (serial and http) command buffer
|
||||||
const uint16_t FLOATSZ = 33; // Max number of characters in float result from dtostrfd
|
const uint16_t FLOATSZ = 16; // Max number of characters in float result from dtostrfd (max 32)
|
||||||
const uint16_t CMDSZ = 24; // Max number of characters in command
|
const uint16_t CMDSZ = 24; // Max number of characters in command
|
||||||
const uint16_t TOPSZ = 100; // Max number of characters in topic string
|
const uint16_t TOPSZ = 100; // Max number of characters in topic string
|
||||||
const uint16_t LOGSZ = 520; // Max number of characters in log
|
const uint16_t LOGSZ = 520; // Max number of characters in log
|
||||||
|
@ -252,11 +252,11 @@ enum SettingsParamIndex { P_HOLD_TIME, P_MAX_POWER_RETRY, P_ex_TUYA_DIMMER_ID, P
|
||||||
P_ex_ENERGY_TARIFF1, P_ex_ENERGY_TARIFF2, // SetOption47 .. SetOption48
|
P_ex_ENERGY_TARIFF1, P_ex_ENERGY_TARIFF2, // SetOption47 .. SetOption48
|
||||||
P_MAX_PARAM8 }; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49
|
P_MAX_PARAM8 }; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49
|
||||||
|
|
||||||
enum SettingsRegister8 { R8_ENERGY_TARIFF1_ST, R8_ENERGY_TARIFF2_ST, R8_ENERGY_TARIFF1_DS, R8_ENERGY_TARIFF2_DS,
|
enum SettingsRegister8 { R8_SPARE00, R8_SPARE01, R8_SPARE02, R8_SPARE03,
|
||||||
R8_SPARE04, R8_SPARE05, R8_SPARE06, R8_SPARE07,
|
R8_SPARE04, R8_SPARE05, R8_SPARE06, R8_SPARE07,
|
||||||
R8_SPARE08, R8_SPARE09, R8_SPARE10, R8_SPARE11,
|
R8_SPARE08, R8_SPARE09, R8_SPARE10, R8_SPARE11,
|
||||||
R8_SPARE12, R8_SPARE13, R8_SPARE14, R8_SPARE15,
|
R8_SPARE12, R8_SPARE13, R8_SPARE14, R8_SPARE15,
|
||||||
R8_SPARE16, R8_SPARE17 }; // Max size is 18 (Settings.register8[])
|
R8_SPARE16 }; // Max size is 17 (Settings.register8[])
|
||||||
|
|
||||||
enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_P1_SMART_METER, DZ_MAX_SENSORS};
|
enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_P1_SMART_METER, DZ_MAX_SENSORS};
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
||||||
#undef CODE_IMAGE
|
#undef CODE_IMAGE
|
||||||
#define CODE_IMAGE 3
|
#define CODE_IMAGE 3
|
||||||
|
|
||||||
|
#undef USE_DISCOVERY // Disable mDNS (+8k code or +23.5k code with core 2_5_x, +0.3k mem)
|
||||||
|
|
||||||
// -- Optional modules -------------------------
|
// -- Optional modules -------------------------
|
||||||
#define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code)
|
#define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code)
|
||||||
#define USE_TUYA_MCU // Add support for Tuya Serial MCU
|
#define USE_TUYA_MCU // Add support for Tuya Serial MCU
|
||||||
|
@ -96,7 +98,6 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
||||||
#define USE_COUNTER // Enable counters
|
#define USE_COUNTER // Enable counters
|
||||||
#undef USE_ADC_VCC // Add Analog input on selected devices
|
#undef USE_ADC_VCC // Add Analog input on selected devices
|
||||||
#define USE_DS18x20 // For more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code)
|
#define USE_DS18x20 // For more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code)
|
||||||
//#define USE_DS18x20_LEGACY // For more than one DS18x20 sensors with dynamic scan using library OneWire (+1k5 code)
|
|
||||||
|
|
||||||
#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram)
|
#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram)
|
||||||
#define USE_SHT // Add I2C emulating code for SHT1X sensor (+1k4 code)
|
#define USE_SHT // Add I2C emulating code for SHT1X sensor (+1k4 code)
|
||||||
|
@ -413,7 +414,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
||||||
* Mandatory define for DS18x20 if changed by above image selections
|
* Mandatory define for DS18x20 if changed by above image selections
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
#if defined(USE_DS18x20) || defined(USE_DS18x20_LEGACY)
|
#if defined(USE_DS18x20)
|
||||||
#else
|
#else
|
||||||
#define USE_DS18B20 // Default DS18B20 sensor needs no external library
|
#define USE_DS18B20 // Default DS18B20 sensor needs no external library
|
||||||
#endif
|
#endif
|
||||||
|
@ -459,7 +460,6 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
||||||
|
|
||||||
#undef USE_COUNTER // Disable counters
|
#undef USE_COUNTER // Disable counters
|
||||||
#undef USE_DS18x20 // Disable DS18x20 sensor
|
#undef USE_DS18x20 // Disable DS18x20 sensor
|
||||||
#undef USE_DS18x20_LEGACY // Disable DS18x20 sensor
|
|
||||||
#undef USE_DS18B20 // Disable internal DS18B20 sensor
|
#undef USE_DS18B20 // Disable internal DS18B20 sensor
|
||||||
#undef USE_I2C // Disable all I2C sensors and devices
|
#undef USE_I2C // Disable all I2C sensors and devices
|
||||||
#undef USE_SPI // Disable all SPI devices
|
#undef USE_SPI // Disable all SPI devices
|
||||||
|
@ -544,7 +544,6 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
||||||
|
|
||||||
#undef USE_COUNTER // Disable counters
|
#undef USE_COUNTER // Disable counters
|
||||||
#undef USE_DS18x20 // Disable DS18x20 sensor
|
#undef USE_DS18x20 // Disable DS18x20 sensor
|
||||||
#undef USE_DS18x20_LEGACY // Disable DS18x20 sensor
|
|
||||||
#undef USE_DS18B20 // Disable internal DS18B20 sensor
|
#undef USE_DS18B20 // Disable internal DS18B20 sensor
|
||||||
#undef USE_I2C // Disable all I2C sensors and devices
|
#undef USE_I2C // Disable all I2C sensors and devices
|
||||||
#undef USE_SPI // Disable all SPI devices
|
#undef USE_SPI // Disable all SPI devices
|
||||||
|
|
|
@ -531,7 +531,7 @@ const uint8_t kGpioNiceList[] PROGMEM = {
|
||||||
GPIO_DHT22, // DHT21, DHT22, AM2301, AM2302, AM2321
|
GPIO_DHT22, // DHT21, DHT22, AM2301, AM2302, AM2321
|
||||||
GPIO_SI7021, // iTead SI7021
|
GPIO_SI7021, // iTead SI7021
|
||||||
#endif
|
#endif
|
||||||
#if defined(USE_DS18B20) || defined(USE_DS18x20) || defined(USE_DS18x20_LEGACY)
|
#if defined(USE_DS18B20) || defined(USE_DS18x20)
|
||||||
GPIO_DSB, // Single wire DS18B20 or DS18S20
|
GPIO_DSB, // Single wire DS18B20 or DS18S20
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,6 @@
|
||||||
#ifndef _SONOFF_VERSION_H_
|
#ifndef _SONOFF_VERSION_H_
|
||||||
#define _SONOFF_VERSION_H_
|
#define _SONOFF_VERSION_H_
|
||||||
|
|
||||||
const uint32_t VERSION = 0x0606000C;
|
const uint32_t VERSION = 0x0606000E;
|
||||||
|
|
||||||
#endif // _SONOFF_VERSION_H_
|
#endif // _SONOFF_VERSION_H_
|
||||||
|
|
|
@ -1571,6 +1571,7 @@ void AddLog(uint32_t loglevel)
|
||||||
if (!web_log_index) web_log_index++; // Index 0 is not allowed as it is the end of char string
|
if (!web_log_index) web_log_index++; // Index 0 is not allowed as it is the end of char string
|
||||||
}
|
}
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
|
if (!global_state.mqtt_down && (loglevel <= Settings.mqttlog_level)) { MqttPublishLogging(mxtime); }
|
||||||
if (!global_state.wifi_down && (loglevel <= syslog_level)) { Syslog(); }
|
if (!global_state.wifi_down && (loglevel <= syslog_level)) { Syslog(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,6 +185,16 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len)
|
||||||
XdrvMailbox.topic = type;
|
XdrvMailbox.topic = type;
|
||||||
XdrvMailbox.data = dataBuf;
|
XdrvMailbox.data = dataBuf;
|
||||||
|
|
||||||
|
#ifdef USE_SCRIPT_SUB_COMMAND
|
||||||
|
// allow overwrite tasmota cmds
|
||||||
|
if (!XdrvCall(FUNC_COMMAND)) {
|
||||||
|
if (!DecodeCommand(kTasmotaCommands, TasmotaCommand)) {
|
||||||
|
if (!XsnsCall(FUNC_COMMAND)) {
|
||||||
|
type = nullptr; // Unknown command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (!DecodeCommand(kTasmotaCommands, TasmotaCommand)) {
|
if (!DecodeCommand(kTasmotaCommands, TasmotaCommand)) {
|
||||||
if (!XdrvCall(FUNC_COMMAND)) {
|
if (!XdrvCall(FUNC_COMMAND)) {
|
||||||
if (!XsnsCall(FUNC_COMMAND)) {
|
if (!XsnsCall(FUNC_COMMAND)) {
|
||||||
|
@ -192,6 +202,8 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == nullptr) {
|
if (type == nullptr) {
|
||||||
|
|
|
@ -243,7 +243,7 @@ void GetFeatures(void)
|
||||||
feature_sns1 |= 0x00000010; // xsns_05_ds18b20.ino
|
feature_sns1 |= 0x00000010; // xsns_05_ds18b20.ino
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_DS18x20_LEGACY
|
#ifdef USE_DS18x20_LEGACY
|
||||||
feature_sns1 |= 0x00000020; // xsns_05_ds18x20_legacy.ino
|
feature_sns1 |= 0x00000020; // xsns_05_ds18x20_legacy.ino - no more supported since 6.6.0.14
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_DS18x20
|
#ifdef USE_DS18x20
|
||||||
feature_sns1 |= 0x00000040; // xsns_05_ds18x20.ino
|
feature_sns1 |= 0x00000040; // xsns_05_ds18x20.ino
|
||||||
|
|
|
@ -120,10 +120,17 @@ String GetBuildDateAndTime(void)
|
||||||
return String(bdt); // 2017-03-07T11:08:02
|
return String(bdt); // 2017-03-07T11:08:02
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String GetMinuteTime(uint32_t minutes)
|
||||||
|
{
|
||||||
|
char tm[6];
|
||||||
|
snprintf_P(tm, sizeof(tm), PSTR("%02d:%02d"), minutes / 60, minutes % 60);
|
||||||
|
|
||||||
|
return String(tm); // 03:45
|
||||||
|
}
|
||||||
|
|
||||||
String GetTimeZone(void)
|
String GetTimeZone(void)
|
||||||
{
|
{
|
||||||
char tz[7];
|
char tz[7];
|
||||||
|
|
||||||
snprintf_P(tz, sizeof(tz), PSTR("%+03d:%02d"), Rtc.time_timezone / 60, abs(Rtc.time_timezone % 60));
|
snprintf_P(tz, sizeof(tz), PSTR("%+03d:%02d"), Rtc.time_timezone / 60, abs(Rtc.time_timezone % 60));
|
||||||
|
|
||||||
return String(tz); // -03:45
|
return String(tz); // -03:45
|
||||||
|
|
|
@ -91,8 +91,48 @@ const char HTTP_SCRIPT_COUNTER[] PROGMEM =
|
||||||
"}"
|
"}"
|
||||||
"wl(u);";
|
"wl(u);";
|
||||||
|
|
||||||
const char HTTP_SCRIPT_ROOT[] PROGMEM =
|
|
||||||
|
|
||||||
|
const char HTTP_SCRIPT_ROOT[] PROGMEM =
|
||||||
|
#ifdef USE_SCRIPT_WEB_DISPLAY
|
||||||
|
"var rfsh=1;"
|
||||||
|
"function la(p){"
|
||||||
|
"var a='';"
|
||||||
|
"if(la.arguments.length==1){"
|
||||||
|
"a=p;"
|
||||||
|
"clearTimeout(lt);"
|
||||||
|
"}"
|
||||||
|
"if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1)
|
||||||
|
"x=new XMLHttpRequest();"
|
||||||
|
"x.onreadystatechange=function(){"
|
||||||
|
"if(x.readyState==4&&x.status==200){"
|
||||||
|
"var s=x.responseText.replace(/{t}/g,\"<table style='width:100%%'>\").replace(/{s}/g,\"<tr><th>\").replace(/{m}/g,\"</th><td>\").replace(/{e}/g,\"</td></tr>\").replace(/{c}/g,\"%%'><div style='text-align:center;font-weight:\");"
|
||||||
|
"eb('l1').innerHTML=s;"
|
||||||
|
"}"
|
||||||
|
"};"
|
||||||
|
"if (rfsh) {"
|
||||||
|
"x.open('GET','.?m=1'+a,true);" // ?m related to WebServer->hasArg("m")
|
||||||
|
"x.send();"
|
||||||
|
"lt=setTimeout(la,%d);" // Settings.web_refresh
|
||||||
|
"}"
|
||||||
|
"}"
|
||||||
|
"function seva(par,ivar){"
|
||||||
|
"la('&sv='+ivar+'_'+par);"
|
||||||
|
"}"
|
||||||
|
"function siva(par,ivar){"
|
||||||
|
"rfsh=1;"
|
||||||
|
"la('&sv='+ivar+'_'+par);"
|
||||||
|
"rfsh=0;"
|
||||||
|
"}"
|
||||||
|
"function pr(f){"
|
||||||
|
"if (f) {"
|
||||||
|
"lt=setTimeout(la,%d);"
|
||||||
|
"rfsh=1;"
|
||||||
|
"} else {"
|
||||||
|
"clearTimeout(lt);"
|
||||||
|
"rfsh=0;"
|
||||||
|
"}"
|
||||||
|
"}"
|
||||||
|
#else // USE_SCRIPT_WEB_DISPLAY
|
||||||
"function la(p){"
|
"function la(p){"
|
||||||
"var a='';"
|
"var a='';"
|
||||||
"if(la.arguments.length==1){"
|
"if(la.arguments.length==1){"
|
||||||
|
@ -111,11 +151,7 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM =
|
||||||
"x.send();"
|
"x.send();"
|
||||||
"lt=setTimeout(la,%d);" // Settings.web_refresh
|
"lt=setTimeout(la,%d);" // Settings.web_refresh
|
||||||
"}"
|
"}"
|
||||||
#ifdef USE_SCRIPT_WEB_DISPLAY
|
#endif // USE_SCRIPT_WEB_DISPLAY
|
||||||
"function seva(par,ivar){"
|
|
||||||
"la('&sv='+ivar+'_'+par);"
|
|
||||||
"}"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_JAVASCRIPT_ES6
|
#ifdef USE_JAVASCRIPT_ES6
|
||||||
|
@ -939,7 +975,11 @@ void HandleRoot(void)
|
||||||
char stemp[5];
|
char stemp[5];
|
||||||
|
|
||||||
WSContentStart_P(S_MAIN_MENU);
|
WSContentStart_P(S_MAIN_MENU);
|
||||||
|
#ifdef USE_SCRIPT_WEB_DISPLAY
|
||||||
|
WSContentSend_P(HTTP_SCRIPT_ROOT, Settings.web_refresh, Settings.web_refresh);
|
||||||
|
#else
|
||||||
WSContentSend_P(HTTP_SCRIPT_ROOT, Settings.web_refresh);
|
WSContentSend_P(HTTP_SCRIPT_ROOT, Settings.web_refresh);
|
||||||
|
#endif
|
||||||
WSContentSendStyle();
|
WSContentSendStyle();
|
||||||
|
|
||||||
WSContentSend_P(PSTR("<div id='l1' name='l1'></div>"));
|
WSContentSend_P(PSTR("<div id='l1' name='l1'></div>"));
|
||||||
|
|
|
@ -39,7 +39,7 @@ const char kMqttCommands[] PROGMEM = "|" // No prefix
|
||||||
D_CMND_TLSKEY "|"
|
D_CMND_TLSKEY "|"
|
||||||
#endif
|
#endif
|
||||||
D_CMND_MQTTHOST "|" D_CMND_MQTTPORT "|" D_CMND_MQTTRETRY "|" D_CMND_STATETEXT "|" D_CMND_MQTTCLIENT "|"
|
D_CMND_MQTTHOST "|" D_CMND_MQTTPORT "|" D_CMND_MQTTRETRY "|" D_CMND_STATETEXT "|" D_CMND_MQTTCLIENT "|"
|
||||||
D_CMND_FULLTOPIC "|" D_CMND_PREFIX "|" D_CMND_GROUPTOPIC "|" D_CMND_TOPIC "|" D_CMND_PUBLISH "|"
|
D_CMND_FULLTOPIC "|" D_CMND_PREFIX "|" D_CMND_GROUPTOPIC "|" D_CMND_TOPIC "|" D_CMND_PUBLISH "|" D_CMND_MQTTLOG "|"
|
||||||
D_CMND_BUTTONTOPIC "|" D_CMND_SWITCHTOPIC "|" D_CMND_BUTTONRETAIN "|" D_CMND_SWITCHRETAIN "|" D_CMND_POWERRETAIN "|" D_CMND_SENSORRETAIN ;
|
D_CMND_BUTTONTOPIC "|" D_CMND_SWITCHTOPIC "|" D_CMND_BUTTONRETAIN "|" D_CMND_SWITCHRETAIN "|" D_CMND_POWERRETAIN "|" D_CMND_SENSORRETAIN ;
|
||||||
|
|
||||||
void (* const MqttCommand[])(void) PROGMEM = {
|
void (* const MqttCommand[])(void) PROGMEM = {
|
||||||
|
@ -53,7 +53,7 @@ void (* const MqttCommand[])(void) PROGMEM = {
|
||||||
&CmndTlsKey,
|
&CmndTlsKey,
|
||||||
#endif
|
#endif
|
||||||
&CmndMqttHost, &CmndMqttPort, &CmndMqttRetry, &CmndStateText, &CmndMqttClient,
|
&CmndMqttHost, &CmndMqttPort, &CmndMqttRetry, &CmndStateText, &CmndMqttClient,
|
||||||
&CmndFullTopic, &CmndPrefix, &CmndGroupTopic, &CmndTopic, &CmndPublish,
|
&CmndFullTopic, &CmndPrefix, &CmndGroupTopic, &CmndTopic, &CmndPublish, &CmndMqttlog,
|
||||||
&CmndButtonTopic, &CmndSwitchTopic, &CmndButtonRetain, &CmndSwitchRetain, &CmndPowerRetain, &CmndSensorRetain };
|
&CmndButtonTopic, &CmndSwitchTopic, &CmndButtonRetain, &CmndSwitchRetain, &CmndPowerRetain, &CmndSensorRetain };
|
||||||
|
|
||||||
struct MQTT {
|
struct MQTT {
|
||||||
|
@ -305,6 +305,35 @@ void MqttUnsubscribe(const char *topic)
|
||||||
MqttUnsubscribeLib(topic);
|
MqttUnsubscribeLib(topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MqttPublishLogging(const char *mxtime)
|
||||||
|
{
|
||||||
|
if (Settings.flag.mqtt_enabled) {
|
||||||
|
if (MqttIsConnected()) {
|
||||||
|
|
||||||
|
char saved_mqtt_data[MESSZ];
|
||||||
|
memcpy(saved_mqtt_data, mqtt_data, sizeof(saved_mqtt_data));
|
||||||
|
// ResponseTime_P(PSTR(",\"Log\":{\"%s\"}}"), log_data); // Will fail as some messages contain JSON
|
||||||
|
Response_P(PSTR("%s%s"), mxtime, log_data); // No JSON and ugly!!
|
||||||
|
|
||||||
|
char romram[33];
|
||||||
|
char stopic[TOPSZ];
|
||||||
|
snprintf_P(romram, sizeof(romram), PSTR("LOGGING"));
|
||||||
|
GetTopic_P(stopic, STAT, mqtt_topic, romram);
|
||||||
|
|
||||||
|
char *me;
|
||||||
|
if (!strcmp(Settings.mqtt_prefix[0], Settings.mqtt_prefix[1])) {
|
||||||
|
me = strstr(stopic, Settings.mqtt_prefix[0]);
|
||||||
|
if (me == stopic) {
|
||||||
|
mqtt_cmnd_publish += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MqttPublishLib(stopic, false);
|
||||||
|
|
||||||
|
memcpy(mqtt_data, saved_mqtt_data, sizeof(saved_mqtt_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MqttPublishDirect(const char* topic, bool retained)
|
void MqttPublishDirect(const char* topic, bool retained)
|
||||||
{
|
{
|
||||||
char sretained[CMDSZ];
|
char sretained[CMDSZ];
|
||||||
|
@ -724,6 +753,14 @@ void CmndMqttPassword(void)
|
||||||
}
|
}
|
||||||
#endif // USE_MQTT_AWS_IOT
|
#endif // USE_MQTT_AWS_IOT
|
||||||
|
|
||||||
|
void CmndMqttlog(void)
|
||||||
|
{
|
||||||
|
if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_ALL)) {
|
||||||
|
Settings.mqttlog_level = XdrvMailbox.payload;
|
||||||
|
}
|
||||||
|
ResponseCmndNumber(Settings.mqttlog_level);
|
||||||
|
}
|
||||||
|
|
||||||
void CmndMqttHost(void)
|
void CmndMqttHost(void)
|
||||||
{
|
{
|
||||||
#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT)
|
#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT)
|
||||||
|
@ -876,7 +913,7 @@ void CmndButtonTopic(void)
|
||||||
|
|
||||||
void CmndSwitchTopic(void)
|
void CmndSwitchTopic(void)
|
||||||
{
|
{
|
||||||
if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.data_len < sizeof(Settings.switch_topic))) {
|
if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0) && (XdrvMailbox.data_len < sizeof(Settings.switch_topic))) {
|
||||||
MakeValidMqtt(0, XdrvMailbox.data);
|
MakeValidMqtt(0, XdrvMailbox.data);
|
||||||
if (!strcmp(XdrvMailbox.data, mqtt_client)) { SetShortcutDefault(); }
|
if (!strcmp(XdrvMailbox.data, mqtt_client)) { SetShortcutDefault(); }
|
||||||
switch (Shortcut()) {
|
switch (Shortcut()) {
|
||||||
|
|
|
@ -82,8 +82,7 @@ struct ENERGY {
|
||||||
|
|
||||||
float start_energy = 0; // 12345.12345 kWh total previous
|
float start_energy = 0; // 12345.12345 kWh total previous
|
||||||
float daily = 0; // 123.123 kWh
|
float daily = 0; // 123.123 kWh
|
||||||
float total = 0; // 12345.12345 kWh tariff 1 + 2
|
float total = 0; // 12345.12345 kWh total energy
|
||||||
float total1 = 0; // 12345.12345 kWh tariff 1 - off-peak
|
|
||||||
float export_active = NAN; // 123.123 KWh
|
float export_active = NAN; // 123.123 KWh
|
||||||
|
|
||||||
unsigned long kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only)
|
unsigned long kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only)
|
||||||
|
@ -93,7 +92,7 @@ struct ENERGY {
|
||||||
|
|
||||||
uint8_t fifth_second = 0;
|
uint8_t fifth_second = 0;
|
||||||
uint8_t command_code = 0;
|
uint8_t command_code = 0;
|
||||||
uint8_t data_valid = 0;
|
uint8_t data_valid[3] = { 0, 0, 0 };
|
||||||
|
|
||||||
uint8_t phase_count = 1; // Number of phases active
|
uint8_t phase_count = 1; // Number of phases active
|
||||||
bool voltage_common = false; // Use single voltage
|
bool voltage_common = false; // Use single voltage
|
||||||
|
@ -130,18 +129,18 @@ Ticker ticker_energy;
|
||||||
|
|
||||||
bool EnergyTariff1Active() // Off-Peak hours
|
bool EnergyTariff1Active() // Off-Peak hours
|
||||||
{
|
{
|
||||||
uint8_t tariff1 = Settings.register8[R8_ENERGY_TARIFF1_ST];
|
uint8_t dst = 0;
|
||||||
uint8_t tariff2 = Settings.register8[R8_ENERGY_TARIFF2_ST];
|
if (IsDst() && (Settings.tariff[0][1] != Settings.tariff[1][1])) {
|
||||||
if (IsDst() && (Settings.register8[R8_ENERGY_TARIFF1_DS] != Settings.register8[R8_ENERGY_TARIFF2_DS])) {
|
dst = 1;
|
||||||
tariff1 = Settings.register8[R8_ENERGY_TARIFF1_DS];
|
|
||||||
tariff2 = Settings.register8[R8_ENERGY_TARIFF2_DS];
|
|
||||||
}
|
}
|
||||||
if (tariff1 != tariff2) {
|
if (Settings.tariff[0][dst] != Settings.tariff[1][dst]) {
|
||||||
return ((RtcTime.hour < tariff2) || // Tarrif1 = Off-Peak
|
uint32_t minutes = MinutesPastMidnight();
|
||||||
(RtcTime.hour >= tariff1) ||
|
return ((minutes < Settings.tariff[1][dst]) || // Tarrif1 = Off-Peak
|
||||||
|
(minutes >= Settings.tariff[0][dst]) ||
|
||||||
(Settings.flag3.energy_weekend && ((RtcTime.day_of_week == 1) ||
|
(Settings.flag3.energy_weekend && ((RtcTime.day_of_week == 1) ||
|
||||||
(RtcTime.day_of_week == 7)))
|
(RtcTime.day_of_week == 7)))
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -155,24 +154,28 @@ void EnergyUpdateToday(void)
|
||||||
Energy.kWhtoday += delta;
|
Energy.kWhtoday += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t energy_diff = Energy.kWhtoday_offset + Energy.kWhtoday - RtcSettings.energy_kWhtoday;
|
|
||||||
|
|
||||||
uint32_t return_diff = 0;
|
|
||||||
if (!isnan(Energy.export_active)) {
|
|
||||||
return_diff = (uint32_t)(Energy.export_active * 1000) - RtcSettings.energy_usage.last_return_kWhtotal;
|
|
||||||
RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy.export_active * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
RtcSettings.energy_kWhtoday = Energy.kWhtoday_offset + Energy.kWhtoday;
|
RtcSettings.energy_kWhtoday = Energy.kWhtoday_offset + Energy.kWhtoday;
|
||||||
Energy.daily = (float)(RtcSettings.energy_kWhtoday) / 100000;
|
Energy.daily = (float)(RtcSettings.energy_kWhtoday) / 100000;
|
||||||
Energy.total = (float)(RtcSettings.energy_kWhtotal + RtcSettings.energy_kWhtoday) / 100000;
|
Energy.total = (float)(RtcSettings.energy_kWhtotal + RtcSettings.energy_kWhtoday) / 100000;
|
||||||
|
|
||||||
if (EnergyTariff1Active()) { // Tarrif1 = Off-Peak
|
if (RtcTime.valid){ // We calc the difference only if we have a valid RTC time.
|
||||||
RtcSettings.energy_usage.usage1_kWhtoday += energy_diff;
|
|
||||||
RtcSettings.energy_usage.return1_kWhtotal += return_diff;
|
uint32_t energy_diff = (uint32_t)(Energy.total * 100000) - RtcSettings.energy_usage.last_usage_kWhtotal;
|
||||||
Energy.total1 = (float)(RtcSettings.energy_usage.usage1_kWhtotal + RtcSettings.energy_usage.usage1_kWhtoday) / 100000;
|
RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy.total * 100000);
|
||||||
} else {
|
|
||||||
RtcSettings.energy_usage.return2_kWhtotal += return_diff;
|
uint32_t return_diff = 0;
|
||||||
|
if (!isnan(Energy.export_active)) {
|
||||||
|
return_diff = (uint32_t)(Energy.export_active * 100000) - RtcSettings.energy_usage.last_return_kWhtotal;
|
||||||
|
RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy.export_active * 100000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EnergyTariff1Active()) { // Tarrif1 = Off-Peak
|
||||||
|
RtcSettings.energy_usage.usage1_kWhtotal += energy_diff;
|
||||||
|
RtcSettings.energy_usage.return1_kWhtotal += return_diff;
|
||||||
|
} else {
|
||||||
|
RtcSettings.energy_usage.usage2_kWhtotal += energy_diff;
|
||||||
|
RtcSettings.energy_usage.return2_kWhtotal += return_diff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +193,14 @@ void EnergyUpdateTotal(float value, bool kwh)
|
||||||
else if (value != Energy.start_energy) {
|
else if (value != Energy.start_energy) {
|
||||||
Energy.kWhtoday = (unsigned long)((value - Energy.start_energy) * multiplier);
|
Energy.kWhtoday = (unsigned long)((value - Energy.start_energy) * multiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Energy.total < (value - 0.01)){ // We subtract a little offset to avoid continuous updates
|
||||||
|
RtcSettings.energy_kWhtotal = (unsigned long)((value * multiplier) - Energy.kWhtoday_offset - Energy.kWhtoday);
|
||||||
|
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
|
||||||
|
Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday_offset + Energy.kWhtoday) / 100000;
|
||||||
|
Settings.energy_kWhtotal_time = (!Energy.kWhtoday_offset) ? LocalTime() : Midnight();
|
||||||
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NRG: Energy Total updated with hardware value"));
|
||||||
|
}
|
||||||
EnergyUpdateToday();
|
EnergyUpdateToday();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,10 +227,6 @@ void Energy200ms(void)
|
||||||
RtcSettings.energy_kWhtoday = 0;
|
RtcSettings.energy_kWhtoday = 0;
|
||||||
Energy.start_energy = 0;
|
Energy.start_energy = 0;
|
||||||
|
|
||||||
RtcSettings.energy_usage.usage1_kWhtotal += RtcSettings.energy_usage.usage1_kWhtoday;
|
|
||||||
Settings.energy_usage.usage1_kWhtotal = RtcSettings.energy_usage.usage1_kWhtotal;
|
|
||||||
RtcSettings.energy_usage.usage1_kWhtoday = 0;
|
|
||||||
|
|
||||||
Energy.kWhtoday_delta = 0;
|
Energy.kWhtoday_delta = 0;
|
||||||
Energy.period = Energy.kWhtoday;
|
Energy.period = Energy.kWhtoday;
|
||||||
EnergyUpdateToday();
|
EnergyUpdateToday();
|
||||||
|
@ -416,18 +423,22 @@ void EnergyMqttShow(void)
|
||||||
}
|
}
|
||||||
#endif // USE_ENERGY_MARGIN_DETECTION
|
#endif // USE_ENERGY_MARGIN_DETECTION
|
||||||
|
|
||||||
void EnergyOverTempCheck()
|
void EnergyEverySecond()
|
||||||
{
|
{
|
||||||
|
// Overtemp check
|
||||||
if (global_update) {
|
if (global_update) {
|
||||||
if (power && (global_temperature != 9999) && (global_temperature > Settings.param[P_OVER_TEMP])) { // Device overtemp, turn off relays
|
if (power && (global_temperature != 9999) && (global_temperature > Settings.param[P_OVER_TEMP])) { // Device overtemp, turn off relays
|
||||||
SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP);
|
SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Energy.data_valid <= ENERGY_WATCHDOG) {
|
|
||||||
Energy.data_valid++;
|
// Invalid data reset
|
||||||
if (Energy.data_valid > ENERGY_WATCHDOG) {
|
uint32_t data_valid = Energy.phase_count;
|
||||||
// Reset energy registers
|
for (uint32_t i = 0; i < Energy.phase_count; i++) {
|
||||||
for (uint32_t i = 0; i < Energy.phase_count; i++) {
|
if (Energy.data_valid[i] <= ENERGY_WATCHDOG) {
|
||||||
|
Energy.data_valid[i]++;
|
||||||
|
if (Energy.data_valid[i] > ENERGY_WATCHDOG) {
|
||||||
|
// Reset energy registers
|
||||||
Energy.voltage[i] = 0;
|
Energy.voltage[i] = 0;
|
||||||
Energy.current[i] = 0;
|
Energy.current[i] = 0;
|
||||||
Energy.active_power[i] = 0;
|
Energy.active_power[i] = 0;
|
||||||
|
@ -435,13 +446,21 @@ void EnergyOverTempCheck()
|
||||||
if (!isnan(Energy.reactive_power[i])) { Energy.reactive_power[i] = 0; }
|
if (!isnan(Energy.reactive_power[i])) { Energy.reactive_power[i] = 0; }
|
||||||
if (!isnan(Energy.frequency[i])) { Energy.frequency[i] = 0; }
|
if (!isnan(Energy.frequency[i])) { Energy.frequency[i] = 0; }
|
||||||
if (!isnan(Energy.power_factor[i])) { Energy.power_factor[i] = 0; }
|
if (!isnan(Energy.power_factor[i])) { Energy.power_factor[i] = 0; }
|
||||||
}
|
|
||||||
if (!isnan(Energy.export_active)) { Energy.export_active = 0; }
|
|
||||||
Energy.start_energy = 0;
|
|
||||||
|
|
||||||
XnrgCall(FUNC_ENERGY_RESET);
|
data_valid--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!data_valid) {
|
||||||
|
if (!isnan(Energy.export_active)) { Energy.export_active = 0; }
|
||||||
|
Energy.start_energy = 0;
|
||||||
|
|
||||||
|
XnrgCall(FUNC_ENERGY_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_ENERGY_MARGIN_DETECTION
|
||||||
|
EnergyMarginCheck();
|
||||||
|
#endif // USE_ENERGY_MARGIN_DETECTION
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
@ -493,60 +512,117 @@ void CmndEnergyReset(void)
|
||||||
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
|
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
|
||||||
Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday_offset + Energy.kWhtoday) / 100000;
|
Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday_offset + Energy.kWhtoday) / 100000;
|
||||||
Settings.energy_kWhtotal_time = (!Energy.kWhtoday_offset) ? LocalTime() : Midnight();
|
Settings.energy_kWhtotal_time = (!Energy.kWhtoday_offset) ? LocalTime() : Midnight();
|
||||||
|
RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy.total * 1000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RtcSettings.energy_usage.usage1_kWhtoday > (Energy.kWhtoday_offset + Energy.kWhtoday)) {
|
|
||||||
RtcSettings.energy_usage.usage1_kWhtoday = Energy.kWhtoday_offset + Energy.kWhtoday;
|
|
||||||
}
|
|
||||||
if (Settings.energy_usage.usage1_kWhtoday > Settings.energy_kWhtoday) {
|
|
||||||
Settings.energy_usage.usage1_kWhtoday = Settings.energy_kWhtoday;
|
|
||||||
RtcSettings.energy_usage.usage1_kWhtoday = Settings.energy_kWhtoday;
|
|
||||||
}
|
|
||||||
if (Settings.energy_usage.usage1_kWhtotal > Settings.energy_kWhtotal) {
|
|
||||||
Settings.energy_usage.usage1_kWhtotal = Settings.energy_kWhtotal;
|
|
||||||
RtcSettings.energy_usage.usage1_kWhtotal = Settings.energy_kWhtotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
char energy_total_chr[FLOATSZ];
|
|
||||||
dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr);
|
|
||||||
char energy_daily_chr[FLOATSZ];
|
|
||||||
dtostrfd(Energy.daily, Settings.flag2.energy_resolution, energy_daily_chr);
|
|
||||||
char energy_yesterday_chr[FLOATSZ];
|
|
||||||
dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr);
|
|
||||||
|
|
||||||
Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s}}"),
|
|
||||||
XdrvMailbox.command, energy_total_chr, energy_yesterday_chr, energy_daily_chr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((XdrvMailbox.index > 3) && (XdrvMailbox.index <= 5)) {
|
||||||
|
char *p;
|
||||||
|
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
|
||||||
|
int32_t position = -1;
|
||||||
|
uint32_t values[2];
|
||||||
|
|
||||||
|
while ((str != nullptr) && (position < 1)) {
|
||||||
|
uint32_t value = strtoul(str, nullptr, 10);
|
||||||
|
position++;
|
||||||
|
values[position] = value *100;
|
||||||
|
str = strtok_r(nullptr, ", ", &p);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (XdrvMailbox.index)
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
// Reset energy_usage.usage totals
|
||||||
|
if (position > -1) {
|
||||||
|
RtcSettings.energy_usage.usage1_kWhtotal = values[0];
|
||||||
|
}
|
||||||
|
if (position > 0) {
|
||||||
|
RtcSettings.energy_usage.usage2_kWhtotal = values[1];
|
||||||
|
}
|
||||||
|
Settings.energy_usage.usage1_kWhtotal = RtcSettings.energy_usage.usage1_kWhtotal;
|
||||||
|
Settings.energy_usage.usage2_kWhtotal = RtcSettings.energy_usage.usage2_kWhtotal;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
// Reset energy_usage.return totals
|
||||||
|
if (position > -1) {
|
||||||
|
RtcSettings.energy_usage.return1_kWhtotal = values[0];
|
||||||
|
}
|
||||||
|
if (position > 0) {
|
||||||
|
RtcSettings.energy_usage.return2_kWhtotal = values[1];
|
||||||
|
}
|
||||||
|
Settings.energy_usage.return1_kWhtotal = RtcSettings.energy_usage.return1_kWhtotal;
|
||||||
|
Settings.energy_usage.return2_kWhtotal = RtcSettings.energy_usage.return2_kWhtotal;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char energy_total_chr[FLOATSZ];
|
||||||
|
dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr);
|
||||||
|
char energy_daily_chr[FLOATSZ];
|
||||||
|
dtostrfd(Energy.daily, Settings.flag2.energy_resolution, energy_daily_chr);
|
||||||
|
char energy_yesterday_chr[FLOATSZ];
|
||||||
|
dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr);
|
||||||
|
|
||||||
|
char energy_usage1_chr[FLOATSZ];
|
||||||
|
dtostrfd((float)Settings.energy_usage.usage1_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_usage1_chr);
|
||||||
|
char energy_usage2_chr[FLOATSZ];
|
||||||
|
dtostrfd((float)Settings.energy_usage.usage2_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_usage2_chr);
|
||||||
|
char energy_return1_chr[FLOATSZ];
|
||||||
|
dtostrfd((float)Settings.energy_usage.return1_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_return1_chr);
|
||||||
|
char energy_return2_chr[FLOATSZ];
|
||||||
|
dtostrfd((float)Settings.energy_usage.return2_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_return2_chr);
|
||||||
|
|
||||||
|
Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s,\"" D_JSON_USAGE "\":[%s,%s],\"" D_JSON_EXPORT "\":[%s,%s]}}"),
|
||||||
|
XdrvMailbox.command, energy_total_chr, energy_yesterday_chr, energy_daily_chr, energy_usage1_chr, energy_usage2_chr, energy_return1_chr, energy_return2_chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmndTariff(void)
|
void CmndTariff(void)
|
||||||
{
|
{
|
||||||
// Tariff1 22,23 - Tariff1 start hour for Standard Time and Daylight Savings Time
|
// Tariff1 22:00,23:00 - Tariff1 start hour for Standard Time and Daylight Savings Time
|
||||||
// Tariff2 6,7 - Tariff2 start hour for Standard Time and Daylight Savings Time
|
// Tariff2 6:00,7:00 - Tariff2 start hour for Standard Time and Daylight Savings Time
|
||||||
|
// Tariffx 1320, 1380 = minutes and also 22:00, 23:00
|
||||||
|
// Tariffx 22, 23 = hours and also 22:00, 23:00
|
||||||
// Tariff9 0/1
|
// Tariff9 0/1
|
||||||
|
|
||||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) {
|
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) {
|
||||||
char *p;
|
uint32_t tariff = XdrvMailbox.index -1;
|
||||||
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
|
|
||||||
uint32_t time_type = 0;
|
uint32_t time_type = 0;
|
||||||
while ((str != nullptr) && (time_type <= 2)) {
|
char *p;
|
||||||
uint8_t value = strtol(str, nullptr, 10);
|
char *str = strtok_r(XdrvMailbox.data, ", ", &p); // 23:15, 22:30
|
||||||
if ((value >= 0) && (value < 24)) {
|
while ((str != nullptr) && (time_type < 2)) {
|
||||||
Settings.register8[R8_ENERGY_TARIFF1_ST + (XdrvMailbox.index -1) + time_type] = value;
|
char *q;
|
||||||
|
uint32_t value = strtol(str, &q, 10); // 23 or 22
|
||||||
|
Settings.tariff[tariff][time_type] = value;
|
||||||
|
if (value < 24) { // Below 24 is hours
|
||||||
|
Settings.tariff[tariff][time_type] *= 60; // Multiply hours by 60 minutes
|
||||||
|
char *minute = strtok_r(nullptr, ":", &q);
|
||||||
|
if (minute) {
|
||||||
|
value = strtol(minute, nullptr, 10); // 15 or 30
|
||||||
|
if (value > 59) {
|
||||||
|
value = 59;
|
||||||
|
}
|
||||||
|
Settings.tariff[tariff][time_type] += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Settings.tariff[tariff][time_type] > 1439) {
|
||||||
|
Settings.tariff[tariff][time_type] = 1439; // Max is 23:59
|
||||||
}
|
}
|
||||||
str = strtok_r(nullptr, ", ", &p);
|
str = strtok_r(nullptr, ", ", &p);
|
||||||
time_type += 2;
|
time_type++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (XdrvMailbox.index == 9) {
|
else if (XdrvMailbox.index == 9) {
|
||||||
Settings.flag3.energy_weekend = XdrvMailbox.payload & 1;
|
Settings.flag3.energy_weekend = XdrvMailbox.payload & 1;
|
||||||
}
|
}
|
||||||
Response_P(PSTR("{\"%s\":{\"Off-Peak\":[%d,%d],\"Standard\":[%d,%d],\"Weekend\":\"%s\"}}"),
|
Response_P(PSTR("{\"%s\":{\"Off-Peak\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Standard\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Weekend\":\"%s\"}}"),
|
||||||
XdrvMailbox.command,
|
XdrvMailbox.command,
|
||||||
Settings.register8[R8_ENERGY_TARIFF1_ST], Settings.register8[R8_ENERGY_TARIFF1_DS],
|
GetMinuteTime(Settings.tariff[0][0]).c_str(),GetMinuteTime(Settings.tariff[0][1]).c_str(),
|
||||||
Settings.register8[R8_ENERGY_TARIFF2_ST], Settings.register8[R8_ENERGY_TARIFF2_DS],
|
GetMinuteTime(Settings.tariff[1][0]).c_str(),GetMinuteTime(Settings.tariff[1][1]).c_str(),
|
||||||
GetStateText(Settings.flag3.energy_weekend));
|
GetStateText(Settings.flag3.energy_weekend));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -766,11 +842,9 @@ void EnergySnsInit(void)
|
||||||
}
|
}
|
||||||
else if (RtcTime.day_of_year == Settings.energy_kWhdoy) {
|
else if (RtcTime.day_of_year == Settings.energy_kWhdoy) {
|
||||||
Energy.kWhtoday_offset = Settings.energy_kWhtoday;
|
Energy.kWhtoday_offset = Settings.energy_kWhtoday;
|
||||||
RtcSettings.energy_usage.usage1_kWhtoday = Settings.energy_usage.usage1_kWhtoday;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Energy.kWhtoday_offset = 0;
|
Energy.kWhtoday_offset = 0;
|
||||||
RtcSettings.energy_usage.usage1_kWhtoday = 0;
|
|
||||||
}
|
}
|
||||||
Energy.kWhtoday = 0;
|
Energy.kWhtoday = 0;
|
||||||
Energy.kWhtoday_delta = 0;
|
Energy.kWhtoday_delta = 0;
|
||||||
|
@ -890,18 +964,22 @@ void EnergyShow(bool json)
|
||||||
dtostrfd(Energy.daily, Settings.flag2.energy_resolution, energy_daily_chr);
|
dtostrfd(Energy.daily, Settings.flag2.energy_resolution, energy_daily_chr);
|
||||||
char energy_yesterday_chr[FLOATSZ];
|
char energy_yesterday_chr[FLOATSZ];
|
||||||
dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr);
|
dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr);
|
||||||
|
|
||||||
char energy_total_chr[3][FLOATSZ];
|
char energy_total_chr[3][FLOATSZ];
|
||||||
dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr[0]);
|
dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr[0]);
|
||||||
|
char export_active_chr[3][FLOATSZ];
|
||||||
|
dtostrfd(Energy.export_active, Settings.flag2.energy_resolution, export_active_chr[0]);
|
||||||
uint8_t energy_total_fields = 1;
|
uint8_t energy_total_fields = 1;
|
||||||
if (Settings.register8[R8_ENERGY_TARIFF1_ST] != Settings.register8[R8_ENERGY_TARIFF2_ST]) {
|
|
||||||
dtostrfd(Energy.total1, Settings.flag2.energy_resolution, energy_total_chr[1]); // Tariff1
|
if (Settings.tariff[0][0] != Settings.tariff[1][0]) {
|
||||||
dtostrfd(Energy.total - Energy.total1, Settings.flag2.energy_resolution, energy_total_chr[2]); // Tariff2
|
dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_total_chr[1]); // Tariff1
|
||||||
|
dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_total_chr[2]); // Tariff2
|
||||||
|
dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal / 100000, Settings.flag2.energy_resolution, export_active_chr[1]); // Tariff1
|
||||||
|
dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal / 100000, Settings.flag2.energy_resolution, export_active_chr[2]); // Tariff2
|
||||||
energy_total_fields = 3;
|
energy_total_fields = 3;
|
||||||
}
|
}
|
||||||
char export_active_chr[FLOATSZ];
|
|
||||||
dtostrfd(Energy.export_active, Settings.flag2.energy_resolution, export_active_chr);
|
|
||||||
|
|
||||||
char value_chr[FLOATSZ *3];
|
char value_chr[FLOATSZ *3]; // Used by EnergyFormatIndex
|
||||||
char value2_chr[FLOATSZ *3];
|
char value2_chr[FLOATSZ *3];
|
||||||
char value3_chr[FLOATSZ *3];
|
char value3_chr[FLOATSZ *3];
|
||||||
|
|
||||||
|
@ -915,7 +993,8 @@ void EnergyShow(bool json)
|
||||||
energy_daily_chr);
|
energy_daily_chr);
|
||||||
|
|
||||||
if (!isnan(Energy.export_active)) {
|
if (!isnan(Energy.export_active)) {
|
||||||
ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), export_active_chr);
|
ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"),
|
||||||
|
EnergyFormatIndex(value_chr, export_active_chr[0], json, energy_total_fields));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_energy_period) {
|
if (show_energy_period) {
|
||||||
|
@ -958,13 +1037,11 @@ void EnergyShow(bool json)
|
||||||
dtostrfd(Energy.total * 1000, 1, energy_total_chr[0]);
|
dtostrfd(Energy.total * 1000, 1, energy_total_chr[0]);
|
||||||
DomoticzSensorPowerEnergy((int)Energy.active_power[0], energy_total_chr[0]); // PowerUsage, EnergyToday
|
DomoticzSensorPowerEnergy((int)Energy.active_power[0], energy_total_chr[0]); // PowerUsage, EnergyToday
|
||||||
|
|
||||||
dtostrfd(Energy.total1 * 1000, 1, energy_total_chr[1]); // Tariff1
|
dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal / 100, 1, energy_total_chr[1]); // Tariff1
|
||||||
dtostrfd((Energy.total - Energy.total1) * 1000, 1, energy_total_chr[2]); // Tariff2
|
dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal / 100, 1, energy_total_chr[2]); // Tariff2
|
||||||
char return1_total_chr[FLOATSZ];
|
dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal / 100, 1, export_active_chr[1]);
|
||||||
dtostrfd(RtcSettings.energy_usage.return1_kWhtotal, 1, return1_total_chr);
|
dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal / 100, 1, export_active_chr[2]);
|
||||||
char return2_total_chr[FLOATSZ];
|
DomoticzSensorP1SmartMeter(energy_total_chr[1], energy_total_chr[2], export_active_chr[1], export_active_chr[2], (int)Energy.active_power[0]);
|
||||||
dtostrfd(RtcSettings.energy_usage.return2_kWhtotal, 1, return2_total_chr);
|
|
||||||
DomoticzSensorP1SmartMeter(energy_total_chr[1], energy_total_chr[2], return1_total_chr, return2_total_chr, (int)Energy.active_power[0]);
|
|
||||||
|
|
||||||
if (Energy.voltage_available) {
|
if (Energy.voltage_available) {
|
||||||
DomoticzSensor(DZ_VOLTAGE, voltage_chr[0]); // Voltage
|
DomoticzSensor(DZ_VOLTAGE, voltage_chr[0]); // Voltage
|
||||||
|
@ -1016,7 +1093,7 @@ void EnergyShow(bool json)
|
||||||
}
|
}
|
||||||
WSContentSend_PD(HTTP_ENERGY_SNS2, energy_daily_chr, energy_yesterday_chr, energy_total_chr[0]);
|
WSContentSend_PD(HTTP_ENERGY_SNS2, energy_daily_chr, energy_yesterday_chr, energy_total_chr[0]);
|
||||||
if (!isnan(Energy.export_active)) {
|
if (!isnan(Energy.export_active)) {
|
||||||
WSContentSend_PD(HTTP_ENERGY_SNS3, export_active_chr);
|
WSContentSend_PD(HTTP_ENERGY_SNS3, export_active_chr[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
XnrgCall(FUNC_WEB_SENSOR);
|
XnrgCall(FUNC_WEB_SENSOR);
|
||||||
|
@ -1066,10 +1143,7 @@ bool Xsns03(uint8_t function)
|
||||||
if (energy_flg) {
|
if (energy_flg) {
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case FUNC_EVERY_SECOND:
|
case FUNC_EVERY_SECOND:
|
||||||
#ifdef USE_ENERGY_MARGIN_DETECTION
|
EnergyEverySecond();
|
||||||
EnergyMarginCheck();
|
|
||||||
#endif // USE_ENERGY_MARGIN_DETECTION
|
|
||||||
EnergyOverTempCheck();
|
|
||||||
break;
|
break;
|
||||||
case FUNC_JSON_APPEND:
|
case FUNC_JSON_APPEND:
|
||||||
EnergyShow(true);
|
EnergyShow(true);
|
||||||
|
|
|
@ -2281,7 +2281,7 @@ void CmndChannel(void)
|
||||||
light_controller.changeChannels(Light.current_color);
|
light_controller.changeChannels(Light.current_color);
|
||||||
coldim = true;
|
coldim = true;
|
||||||
}
|
}
|
||||||
ResponseCmndIdxNumber(Light.current_color[XdrvMailbox.index -1] * 100 / 255);
|
ResponseCmndIdxNumber(changeUIntScale(Light.current_color[XdrvMailbox.index -1],0,255,0,100));
|
||||||
if (coldim) {
|
if (coldim) {
|
||||||
LightPreparePower();
|
LightPreparePower();
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,8 +259,17 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
|
||||||
JsonObject &root = jsonBuf.parseObject(event);
|
JsonObject &root = jsonBuf.parseObject(event);
|
||||||
if (!root.success()) { return false; } // No valid JSON data
|
if (!root.success()) { return false; } // No valid JSON data
|
||||||
|
|
||||||
float value = 0;
|
const char* str_value;
|
||||||
const char* str_value = root[rule_task][rule_name];
|
if ((pos = rule_name.indexOf("[")) > 0) { // "CURRENT[1]"
|
||||||
|
int rule_name_idx = rule_name.substring(pos +1).toInt();
|
||||||
|
if ((rule_name_idx < 1) || (rule_name_idx > 6)) { // Allow indexes 1 to 6
|
||||||
|
rule_name_idx = 1;
|
||||||
|
}
|
||||||
|
rule_name = rule_name.substring(0, pos); // "CURRENT"
|
||||||
|
str_value = root[rule_task][rule_name][rule_name_idx -1]; // "ENERGY" and "CURRENT" and 0
|
||||||
|
} else {
|
||||||
|
str_value = root[rule_task][rule_name]; // "INA219" and "CURRENT"
|
||||||
|
}
|
||||||
|
|
||||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Task %s, Name %s, Value |%s|, TrigCnt %d, TrigSt %d, Source %s, Json %s"),
|
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Task %s, Name %s, Value |%s|, TrigCnt %d, TrigSt %d, Source %s, Json %s"),
|
||||||
// rule_task.c_str(), rule_name.c_str(), rule_svalue, Rules.trigger_count[rule_set], bitRead(Rules.triggers[rule_set], Rules.trigger_count[rule_set]), event.c_str(), (str_value) ? str_value : "none");
|
// rule_task.c_str(), rule_name.c_str(), rule_svalue, Rules.trigger_count[rule_set], bitRead(Rules.triggers[rule_set], Rules.trigger_count[rule_set]), event.c_str(), (str_value) ? str_value : "none");
|
||||||
|
@ -271,6 +280,7 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
|
||||||
Rules.event_value = str_value; // Prepare %value%
|
Rules.event_value = str_value; // Prepare %value%
|
||||||
|
|
||||||
// Step 3: Compare rule (value)
|
// Step 3: Compare rule (value)
|
||||||
|
float value = 0;
|
||||||
if (str_value) {
|
if (str_value) {
|
||||||
value = CharToFloat((char*)str_value);
|
value = CharToFloat((char*)str_value);
|
||||||
int int_value = int(value);
|
int int_value = int(value);
|
||||||
|
|
|
@ -42,8 +42,9 @@ keywords if then else endif, or, and are better readable for beginners (others m
|
||||||
#define SCRIPT_DEBUG 0
|
#define SCRIPT_DEBUG 0
|
||||||
|
|
||||||
#define MAXVARS 50
|
#define MAXVARS 50
|
||||||
#define MAXNVARS 45
|
|
||||||
#define MAXSVARS 5
|
#define MAXSVARS 5
|
||||||
|
#define MAXNVARS MAXVARS-MAXSVARS
|
||||||
|
|
||||||
#define MAXFILT 5
|
#define MAXFILT 5
|
||||||
#define SCRIPT_SVARSIZE 20
|
#define SCRIPT_SVARSIZE 20
|
||||||
#define SCRIPT_MAXSSIZE 48
|
#define SCRIPT_MAXSSIZE 48
|
||||||
|
@ -465,6 +466,10 @@ char *script;
|
||||||
}
|
}
|
||||||
namep++;
|
namep++;
|
||||||
index++;
|
index++;
|
||||||
|
if (index>255) {
|
||||||
|
free(glob_script_mem.script_mem);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy string variables
|
// copy string variables
|
||||||
|
@ -718,7 +723,7 @@ float DoMedian5(uint8_t index, float in) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_LIGHT
|
#ifdef USE_LIGHT
|
||||||
#ifdef USE_WS2812
|
//#ifdef USE_WS2812
|
||||||
uint32_t HSVToRGB(uint16_t hue, uint8_t saturation, uint8_t value) {
|
uint32_t HSVToRGB(uint16_t hue, uint8_t saturation, uint8_t value) {
|
||||||
float r = 0, g = 0, b = 0;
|
float r = 0, g = 0, b = 0;
|
||||||
struct HSV {
|
struct HSV {
|
||||||
|
@ -801,7 +806,7 @@ if (hsv.S == 0) {
|
||||||
return rgb;
|
return rgb;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
//#endif
|
||||||
|
|
||||||
// vtype => ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number
|
// vtype => ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number
|
||||||
// no flash strings here for performance reasons!!!
|
// no flash strings here for performance reasons!!!
|
||||||
|
@ -1103,7 +1108,7 @@ chknext:
|
||||||
fvar=cnt;
|
fvar=cnt;
|
||||||
glob_script_mem.file_flags[cnt].is_open=1;
|
glob_script_mem.file_flags[cnt].is_open=1;
|
||||||
} else {
|
} else {
|
||||||
toLog("file open failed");
|
AddLog_P(LOG_LEVEL_INFO,PSTR("file open failed"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1339,8 +1344,17 @@ chknext:
|
||||||
}
|
}
|
||||||
goto strexit;
|
goto strexit;
|
||||||
}
|
}
|
||||||
|
if (!strncmp(vname,"hx(",3)) {
|
||||||
|
lp=GetNumericResult(lp+3,OPER_EQU,&fvar,0);
|
||||||
|
lp++;
|
||||||
|
len=0;
|
||||||
|
if (sp) {
|
||||||
|
sprintf(sp,"%08x",(uint32_t)fvar);
|
||||||
|
}
|
||||||
|
goto strexit;
|
||||||
|
}
|
||||||
#ifdef USE_LIGHT
|
#ifdef USE_LIGHT
|
||||||
#ifdef USE_WS2812
|
//#ifdef USE_WS2812
|
||||||
if (!strncmp(vname,"hsvrgb(",7)) {
|
if (!strncmp(vname,"hsvrgb(",7)) {
|
||||||
lp=GetNumericResult(lp+7,OPER_EQU,&fvar,0);
|
lp=GetNumericResult(lp+7,OPER_EQU,&fvar,0);
|
||||||
if (fvar<0 || fvar>360) fvar=0;
|
if (fvar<0 || fvar>360) fvar=0;
|
||||||
|
@ -1361,7 +1375,7 @@ chknext:
|
||||||
len=0;
|
len=0;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
#endif
|
//#endif
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -1903,6 +1917,11 @@ char *GetStringResult(char *lp,uint8_t lastop,char *cp,JsonObject *jo) {
|
||||||
char str[SCRIPT_MAXSSIZE],str1[SCRIPT_MAXSSIZE];
|
char str[SCRIPT_MAXSSIZE],str1[SCRIPT_MAXSSIZE];
|
||||||
while (1) {
|
while (1) {
|
||||||
lp=isvar(lp,&vtype,&ind,0,str1,jo);
|
lp=isvar(lp,&vtype,&ind,0,str1,jo);
|
||||||
|
if (vtype!=STR_RES && !(vtype&STYPE)) {
|
||||||
|
// numeric type
|
||||||
|
glob_script_mem.glob_error=1;
|
||||||
|
return lp;
|
||||||
|
}
|
||||||
switch (lastop) {
|
switch (lastop) {
|
||||||
case OPER_EQU:
|
case OPER_EQU:
|
||||||
strlcpy(str,str1,sizeof(str));
|
strlcpy(str,str1,sizeof(str));
|
||||||
|
@ -2015,13 +2034,13 @@ struct T_INDEX ind;
|
||||||
char *ForceStringVar(char *lp,char *dstr) {
|
char *ForceStringVar(char *lp,char *dstr) {
|
||||||
float fvar;
|
float fvar;
|
||||||
char *slp=lp;
|
char *slp=lp;
|
||||||
glob_script_mem.var_not_found=0;
|
glob_script_mem.glob_error=0;
|
||||||
lp=GetStringResult(lp,OPER_EQU,dstr,0);
|
lp=GetStringResult(lp,OPER_EQU,dstr,0);
|
||||||
if (glob_script_mem.var_not_found) {
|
if (glob_script_mem.glob_error) {
|
||||||
// mismatch
|
// mismatch
|
||||||
lp=GetNumericResult(slp,OPER_EQU,&fvar,0);
|
lp=GetNumericResult(slp,OPER_EQU,&fvar,0);
|
||||||
dtostrfd(fvar,6,dstr);
|
dtostrfd(fvar,6,dstr);
|
||||||
glob_script_mem.var_not_found=0;
|
glob_script_mem.glob_error=0;
|
||||||
}
|
}
|
||||||
return lp;
|
return lp;
|
||||||
}
|
}
|
||||||
|
@ -2089,6 +2108,7 @@ void toLog(const char *str) {
|
||||||
AddLog(LOG_LEVEL_INFO);
|
AddLog(LOG_LEVEL_INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void toLogN(const char *cp,uint8_t len) {
|
void toLogN(const char *cp,uint8_t len) {
|
||||||
if (!cp) return;
|
if (!cp) return;
|
||||||
char str[32];
|
char str[32];
|
||||||
|
@ -2281,12 +2301,10 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
|
||||||
if (section) {
|
if (section) {
|
||||||
// we are in section
|
// we are in section
|
||||||
if (*lp=='>') {
|
if (*lp=='>') {
|
||||||
section=0;
|
return 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (*lp=='#') {
|
if (*lp=='#') {
|
||||||
section=0;
|
return 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
glob_script_mem.var_not_found=0;
|
glob_script_mem.var_not_found=0;
|
||||||
|
|
||||||
|
@ -2718,14 +2736,15 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
|
||||||
sindex=index;
|
sindex=index;
|
||||||
// string result
|
// string result
|
||||||
char str[SCRIPT_MAXSSIZE];
|
char str[SCRIPT_MAXSSIZE];
|
||||||
char *slp=lp;
|
|
||||||
lp=getop(lp,&lastop);
|
lp=getop(lp,&lastop);
|
||||||
|
char *slp=lp;
|
||||||
|
glob_script_mem.glob_error=0;
|
||||||
lp=GetStringResult(lp,OPER_EQU,str,jo);
|
lp=GetStringResult(lp,OPER_EQU,str,jo);
|
||||||
if (!js && glob_script_mem.var_not_found) {
|
if (!js && glob_script_mem.glob_error) {
|
||||||
// mismatch
|
// mismatch
|
||||||
lp=GetNumericResult(slp,OPER_EQU,&fvar,0);
|
lp=GetNumericResult(slp,OPER_EQU,&fvar,0);
|
||||||
dtostrfd(fvar,6,str);
|
dtostrfd(fvar,6,str);
|
||||||
glob_script_mem.var_not_found=0;
|
glob_script_mem.glob_error=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!glob_script_mem.var_not_found) {
|
if (!glob_script_mem.var_not_found) {
|
||||||
|
@ -2764,19 +2783,20 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
|
||||||
return 99;
|
return 99;
|
||||||
}
|
}
|
||||||
// check for subroutine
|
// check for subroutine
|
||||||
if (*type=='#') {
|
char *ctype=(char*)type;
|
||||||
|
if (*ctype=='#') {
|
||||||
// check for parameter
|
// check for parameter
|
||||||
type+=tlen;
|
ctype+=tlen;
|
||||||
if (*type=='(') {
|
if (*ctype=='(' && *(lp+tlen)=='(') {
|
||||||
float fparam;
|
float fparam;
|
||||||
numeric=1;
|
numeric=1;
|
||||||
glob_script_mem.glob_error=0;
|
glob_script_mem.glob_error=0;
|
||||||
GetNumericResult((char*)type,OPER_EQU,&fparam,0);
|
GetNumericResult((char*)ctype,OPER_EQU,&fparam,0);
|
||||||
if (glob_script_mem.glob_error==1) {
|
if (glob_script_mem.glob_error==1) {
|
||||||
// was string, not number
|
// was string, not number
|
||||||
numeric=0;
|
numeric=0;
|
||||||
// get the string
|
// get the string
|
||||||
GetStringResult((char*)type+1,OPER_EQU,cmpstr,0);
|
GetStringResult((char*)ctype+1,OPER_EQU,cmpstr,0);
|
||||||
}
|
}
|
||||||
lp+=tlen;
|
lp+=tlen;
|
||||||
if (*lp=='(') {
|
if (*lp=='(') {
|
||||||
|
@ -2807,6 +2827,12 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
lp+=tlen;
|
||||||
|
if (*ctype=='(' || (*lp!=SCRIPT_EOL && *lp!='?')) {
|
||||||
|
// revert
|
||||||
|
section=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2817,11 +2843,17 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
|
||||||
lp++;
|
lp++;
|
||||||
} else {
|
} else {
|
||||||
lp = strchr(lp, SCRIPT_EOL);
|
lp = strchr(lp, SCRIPT_EOL);
|
||||||
if (!lp) break;
|
if (!lp) {
|
||||||
|
if (section) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
lp++;
|
lp++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t script_xsns_index = 0;
|
uint8_t script_xsns_index = 0;
|
||||||
|
@ -3137,13 +3169,13 @@ uint8_t DownloadFile(char *file) {
|
||||||
WiFiClient download_Client;
|
WiFiClient download_Client;
|
||||||
|
|
||||||
if (!SD.exists(file)) {
|
if (!SD.exists(file)) {
|
||||||
toLog("file not found");
|
AddLog_P(LOG_LEVEL_INFO,PSTR("file not found"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
download_file=SD.open(file,FILE_READ);
|
download_file=SD.open(file,FILE_READ);
|
||||||
if (!download_file) {
|
if (!download_file) {
|
||||||
toLog("could not open file");
|
AddLog_P(LOG_LEVEL_INFO,PSTR("could not open file"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3306,6 +3338,36 @@ void ScriptSaveSettings(void) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_SCRIPT_SUB_COMMAND
|
||||||
|
bool Script_SubCmd(void) {
|
||||||
|
if (!bitRead(Settings.rule_enabled, 0)) return false;
|
||||||
|
|
||||||
|
char cmdbuff[128];
|
||||||
|
char *cp=cmdbuff;
|
||||||
|
*cp++='#';
|
||||||
|
strcpy(cp,XdrvMailbox.topic);
|
||||||
|
uint8_t tlen=strlen(XdrvMailbox.topic);
|
||||||
|
cp+=tlen;
|
||||||
|
if (XdrvMailbox.index > 0) {
|
||||||
|
*cp++=XdrvMailbox.index|0x30;
|
||||||
|
tlen++;
|
||||||
|
}
|
||||||
|
if ((XdrvMailbox.payload>0) || (XdrvMailbox.data_len>0)) {
|
||||||
|
*cp++='(';
|
||||||
|
strncpy(cp,XdrvMailbox.data,XdrvMailbox.data_len);
|
||||||
|
cp+=XdrvMailbox.data_len;
|
||||||
|
*cp++=')';
|
||||||
|
*cp=0;
|
||||||
|
}
|
||||||
|
//toLog(cmdbuff);
|
||||||
|
uint32_t res=Run_Scripter(cmdbuff,tlen+1,0);
|
||||||
|
//AddLog_P2(LOG_LEVEL_INFO,">>%d",res);
|
||||||
|
if (res) return false;
|
||||||
|
else return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void execute_script(char *script) {
|
void execute_script(char *script) {
|
||||||
char *svd_sp=glob_script_mem.scriptptr;
|
char *svd_sp=glob_script_mem.scriptptr;
|
||||||
strcat(script,"\n#");
|
strcat(script,"\n#");
|
||||||
|
@ -3327,6 +3389,20 @@ bool ScriptCommand(void) {
|
||||||
|
|
||||||
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kScriptCommands);
|
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kScriptCommands);
|
||||||
if (-1 == command_code) {
|
if (-1 == command_code) {
|
||||||
|
#ifdef USE_SCRIPT_SUB_COMMAND
|
||||||
|
strlcpy(command,XdrvMailbox.topic,CMDSZ);
|
||||||
|
uint32_t pl=XdrvMailbox.payload;
|
||||||
|
char pld[64];
|
||||||
|
strlcpy(pld,XdrvMailbox.data,sizeof(pld));
|
||||||
|
if (Script_SubCmd()) {
|
||||||
|
if (pl>=0) {
|
||||||
|
Response_P(S_JSON_COMMAND_NVALUE, command, pl);
|
||||||
|
} else {
|
||||||
|
Response_P(S_JSON_COMMAND_SVALUE, command, pld);
|
||||||
|
}
|
||||||
|
return serviced;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
serviced = false; // Unknown command
|
serviced = false; // Unknown command
|
||||||
}
|
}
|
||||||
else if ((CMND_SCRIPT == command_code) && (index > 0)) {
|
else if ((CMND_SCRIPT == command_code) && (index > 0)) {
|
||||||
|
@ -3351,15 +3427,15 @@ bool ScriptCommand(void) {
|
||||||
return serviced;
|
return serviced;
|
||||||
}
|
}
|
||||||
snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"Free\":%d}"),command, GetStateText(bitRead(Settings.rule_enabled,0)),glob_script_mem.script_size-strlen(glob_script_mem.script_ram));
|
snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"Free\":%d}"),command, GetStateText(bitRead(Settings.rule_enabled,0)),glob_script_mem.script_size-strlen(glob_script_mem.script_ram));
|
||||||
#ifdef SUPPORT_MQTT_EVENT
|
#ifdef SUPPORT_MQTT_EVENT
|
||||||
} else if (CMND_SUBSCRIBE == command_code) { //MQTT Subscribe command. Subscribe <Event>, <Topic> [, <Key>]
|
} else if (CMND_SUBSCRIBE == command_code) { //MQTT Subscribe command. Subscribe <Event>, <Topic> [, <Key>]
|
||||||
String result = ScriptSubscribe(XdrvMailbox.data, XdrvMailbox.data_len);
|
String result = ScriptSubscribe(XdrvMailbox.data, XdrvMailbox.data_len);
|
||||||
Response_P(S_JSON_COMMAND_SVALUE, command, result.c_str());
|
Response_P(S_JSON_COMMAND_SVALUE, command, result.c_str());
|
||||||
} else if (CMND_UNSUBSCRIBE == command_code) { //MQTT Un-subscribe command. UnSubscribe <Event>
|
} else if (CMND_UNSUBSCRIBE == command_code) { //MQTT Un-subscribe command. UnSubscribe <Event>
|
||||||
String result = ScriptUnsubscribe(XdrvMailbox.data, XdrvMailbox.data_len);
|
String result = ScriptUnsubscribe(XdrvMailbox.data, XdrvMailbox.data_len);
|
||||||
Response_P(S_JSON_COMMAND_SVALUE, command, result.c_str());
|
Response_P(S_JSON_COMMAND_SVALUE, command, result.c_str());
|
||||||
#endif //SUPPORT_MQTT_EVENT
|
#endif //SUPPORT_MQTT_EVENT
|
||||||
}
|
}
|
||||||
return serviced;
|
return serviced;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3614,24 +3690,43 @@ void Script_Check_HTML_Setvars(void) {
|
||||||
|
|
||||||
//toLog(cmdbuf);
|
//toLog(cmdbuf);
|
||||||
execute_script(cmdbuf);
|
execute_script(cmdbuf);
|
||||||
|
Run_Scripter(">E",2,0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char SCRIPT_MSG_BUTTONa[] PROGMEM =
|
||||||
|
"<button type='submit' style=\"width:%d%%\" onclick='seva(%d,\"%s\")'>%s</button>";
|
||||||
|
|
||||||
|
const char SCRIPT_MSG_BUTTONa_TBL[] PROGMEM =
|
||||||
|
"<td style=\"width:%d%%\"><button type='submit' onclick='seva(%d,\"%s\")'>%s</button></td>";
|
||||||
|
|
||||||
|
const char SCRIPT_MSG_BUTTONb[] PROGMEM =
|
||||||
|
"<img width=\"%d%%\"><\img>";
|
||||||
|
|
||||||
|
const char SCRIPT_MSG_BUT_START[] PROGMEM =
|
||||||
|
"<div>";
|
||||||
|
const char SCRIPT_MSG_BUT_START_TBL[] PROGMEM =
|
||||||
|
"<table style='width:100%%'><tr>";
|
||||||
|
|
||||||
|
const char SCRIPT_MSG_BUT_STOP[] PROGMEM =
|
||||||
|
"</div>";
|
||||||
|
const char SCRIPT_MSG_BUT_STOP_TBL[] PROGMEM =
|
||||||
|
"</tr></table>";
|
||||||
|
|
||||||
const char SCRIPT_MSG_SLIDER[] PROGMEM =
|
const char SCRIPT_MSG_SLIDER[] PROGMEM =
|
||||||
"<div><span class='p'>%s</span><center><b>%s</b><span class='q'>%s</span></div>"
|
"<div><span class='p'>%s</span><center><b>%s</b><span class='q'>%s</span></div>"
|
||||||
"<div><input type='range' min='%d' max='%d' value='%d' onchange='seva(value,\"%s\")'></div>";
|
"<div><input type='range' min='%d' max='%d' value='%d' onchange='seva(value,\"%s\")'></div>";
|
||||||
|
|
||||||
const char SCRIPT_MSG_BUTTON[] PROGMEM =
|
|
||||||
"<div><button type='submit' onclick='seva(%d,\"%s\")'>%s</button></div>";
|
|
||||||
|
|
||||||
const char SCRIPT_MSG_CHKBOX[] PROGMEM =
|
const char SCRIPT_MSG_CHKBOX[] PROGMEM =
|
||||||
"<div><center><label><b>%s</b><input type='checkbox' %s onchange='seva(%d,\"%s\")'></label></div>";
|
"<div><center><label><b>%s</b><input type='checkbox' %s onchange='seva(%d,\"%s\")'></label></div>";
|
||||||
|
|
||||||
const char SCRIPT_MSG_TEXTINP[] PROGMEM =
|
const char SCRIPT_MSG_TEXTINP[] PROGMEM =
|
||||||
"<div><center><label><b>%s</b><input type='text' value='%s' style='width:200px' onchange='seva(value,\"%s\")'></label></div>";
|
"<div><center><label><b>%s</b><input type='text' value='%s' style='width:200px' onfocusin='pr(0)' onfocusout='pr(1)' onchange='siva(value,\"%s\")'></label></div>";
|
||||||
|
|
||||||
|
const char SCRIPT_MSG_NUMINP[] PROGMEM =
|
||||||
|
"<div><center><label><b>%s</b><input min='%s' max='%s' step='%s' value='%s' type='number' style='width:200px' onfocusin='pr(0)' onfocusout='pr(1)' onchange='siva(value,\"%s\")'></label></div>";
|
||||||
|
|
||||||
//<input onkeypress="if(event.key == 'Enter') {console.log('Test')}">
|
|
||||||
//<input onBlur="if (this.value == '') { var field = this; setTimeout(function() { field.focus(); }, 0); }" type="text">
|
|
||||||
|
|
||||||
void ScriptGetVarname(char *nbuf,char *sp, uint32_t blen) {
|
void ScriptGetVarname(char *nbuf,char *sp, uint32_t blen) {
|
||||||
uint32_t cnt;
|
uint32_t cnt;
|
||||||
|
@ -3649,6 +3744,7 @@ void ScriptWebShow(void) {
|
||||||
if (web_script==99) {
|
if (web_script==99) {
|
||||||
char line[128];
|
char line[128];
|
||||||
char tmp[128];
|
char tmp[128];
|
||||||
|
uint8_t optflg=0;
|
||||||
char *lp=glob_script_mem.section_ptr+2;
|
char *lp=glob_script_mem.section_ptr+2;
|
||||||
while (lp) {
|
while (lp) {
|
||||||
while (*lp==SCRIPT_EOL) {
|
while (*lp==SCRIPT_EOL) {
|
||||||
|
@ -3669,10 +3765,17 @@ void ScriptWebShow(void) {
|
||||||
}
|
}
|
||||||
cp++;
|
cp++;
|
||||||
}
|
}
|
||||||
|
char *lin=line;
|
||||||
|
if (*lin=='@') {
|
||||||
|
lin++;
|
||||||
|
optflg=1;
|
||||||
|
} else {
|
||||||
|
optflg=0;
|
||||||
|
}
|
||||||
// check for input elements
|
// check for input elements
|
||||||
if (!strncmp(line,"sl(",3)) {
|
if (!strncmp(lin,"sl(",3)) {
|
||||||
// insert slider sl(min max var left mid right)
|
// insert slider sl(min max var left mid right)
|
||||||
char *lp=line;
|
char *lp=lin;
|
||||||
float min;
|
float min;
|
||||||
lp=GetNumericResult(lp+3,OPER_EQU,&min,0);
|
lp=GetNumericResult(lp+3,OPER_EQU,&min,0);
|
||||||
SCRIPT_SKIP_SPACES
|
SCRIPT_SKIP_SPACES
|
||||||
|
@ -3701,8 +3804,8 @@ void ScriptWebShow(void) {
|
||||||
WSContentSend_PD(SCRIPT_MSG_SLIDER,left,mid,right,(uint32_t)min,(uint32_t)max,(uint32_t)val,vname);
|
WSContentSend_PD(SCRIPT_MSG_SLIDER,left,mid,right,(uint32_t)min,(uint32_t)max,(uint32_t)val,vname);
|
||||||
|
|
||||||
|
|
||||||
} else if (!strncmp(line,"ck(",3)) {
|
} else if (!strncmp(lin,"ck(",3)) {
|
||||||
char *lp=line+3;
|
char *lp=lin+3;
|
||||||
char *slp=lp;
|
char *slp=lp;
|
||||||
float val;
|
float val;
|
||||||
lp=GetNumericResult(lp,OPER_EQU,&val,0);
|
lp=GetNumericResult(lp,OPER_EQU,&val,0);
|
||||||
|
@ -3713,7 +3816,7 @@ void ScriptWebShow(void) {
|
||||||
|
|
||||||
char label[SCRIPT_MAXSSIZE];
|
char label[SCRIPT_MAXSSIZE];
|
||||||
lp=GetStringResult(lp,OPER_EQU,label,0);
|
lp=GetStringResult(lp,OPER_EQU,label,0);
|
||||||
char *cp;
|
const char *cp;
|
||||||
uint8_t uval;
|
uint8_t uval;
|
||||||
if (val>0) {
|
if (val>0) {
|
||||||
cp="checked='checked'";
|
cp="checked='checked'";
|
||||||
|
@ -3722,38 +3825,64 @@ void ScriptWebShow(void) {
|
||||||
cp="";
|
cp="";
|
||||||
uval=1;
|
uval=1;
|
||||||
}
|
}
|
||||||
WSContentSend_PD(SCRIPT_MSG_CHKBOX,label,cp,uval,vname);
|
WSContentSend_PD(SCRIPT_MSG_CHKBOX,label,(char*)cp,uval,vname);
|
||||||
|
|
||||||
} else if (!strncmp(line,"bu(",3)) {
|
} else if (!strncmp(lin,"bu(",3)) {
|
||||||
char *lp=line+3;
|
char *lp=lin+3;
|
||||||
char *slp=lp;
|
uint8_t bcnt=0;
|
||||||
float val;
|
char *found=lin;
|
||||||
lp=GetNumericResult(lp,OPER_EQU,&val,0);
|
while (bcnt<4) {
|
||||||
SCRIPT_SKIP_SPACES
|
found=strstr(found,"bu(");
|
||||||
|
if (!found) break;
|
||||||
char vname[16];
|
found+=3;
|
||||||
ScriptGetVarname(vname,slp,sizeof(vname));
|
bcnt++;
|
||||||
|
|
||||||
SCRIPT_SKIP_SPACES
|
|
||||||
char ontxt[SCRIPT_MAXSSIZE];
|
|
||||||
lp=GetStringResult(lp,OPER_EQU,ontxt,0);
|
|
||||||
SCRIPT_SKIP_SPACES
|
|
||||||
char offtxt[SCRIPT_MAXSSIZE];
|
|
||||||
lp=GetStringResult(lp,OPER_EQU,offtxt,0);
|
|
||||||
|
|
||||||
char *cp;
|
|
||||||
uint8_t uval;
|
|
||||||
if (val>0) {
|
|
||||||
cp=ontxt;
|
|
||||||
uval=0;
|
|
||||||
} else {
|
|
||||||
cp=offtxt;
|
|
||||||
uval=1;
|
|
||||||
}
|
}
|
||||||
WSContentSend_PD(SCRIPT_MSG_BUTTON,uval,vname,cp);
|
uint8_t proz=100/bcnt;
|
||||||
|
if (!optflg && bcnt>1) proz-=2;
|
||||||
|
if (optflg) WSContentSend_PD(SCRIPT_MSG_BUT_START_TBL);
|
||||||
|
else WSContentSend_PD(SCRIPT_MSG_BUT_START);
|
||||||
|
for (uint32_t cnt=0;cnt<bcnt;cnt++) {
|
||||||
|
float val;
|
||||||
|
char *slp=lp;
|
||||||
|
lp=GetNumericResult(lp,OPER_EQU,&val,0);
|
||||||
|
SCRIPT_SKIP_SPACES
|
||||||
|
|
||||||
} else if (!strncmp(line,"tx(",3)) {
|
char vname[16];
|
||||||
char *lp=line+3;
|
ScriptGetVarname(vname,slp,sizeof(vname));
|
||||||
|
|
||||||
|
SCRIPT_SKIP_SPACES
|
||||||
|
char ontxt[SCRIPT_MAXSSIZE];
|
||||||
|
lp=GetStringResult(lp,OPER_EQU,ontxt,0);
|
||||||
|
SCRIPT_SKIP_SPACES
|
||||||
|
char offtxt[SCRIPT_MAXSSIZE];
|
||||||
|
lp=GetStringResult(lp,OPER_EQU,offtxt,0);
|
||||||
|
|
||||||
|
char *cp;
|
||||||
|
uint8_t uval;
|
||||||
|
if (val>0) {
|
||||||
|
cp=ontxt;
|
||||||
|
uval=0;
|
||||||
|
} else {
|
||||||
|
cp=offtxt;
|
||||||
|
uval=1;
|
||||||
|
}
|
||||||
|
if (bcnt>1 && cnt==bcnt-1) {
|
||||||
|
if (!optflg) proz+=2;
|
||||||
|
}
|
||||||
|
if (!optflg) {
|
||||||
|
WSContentSend_PD(SCRIPT_MSG_BUTTONa,proz,uval,vname,cp);
|
||||||
|
} else {
|
||||||
|
WSContentSend_PD(SCRIPT_MSG_BUTTONa_TBL,proz,uval,vname,cp);
|
||||||
|
}
|
||||||
|
if (bcnt>1 && cnt<bcnt-1) {
|
||||||
|
if (!optflg) WSContentSend_PD(SCRIPT_MSG_BUTTONb,2);
|
||||||
|
}
|
||||||
|
lp+=4;
|
||||||
|
}
|
||||||
|
if (optflg) WSContentSend_PD(SCRIPT_MSG_BUT_STOP_TBL);
|
||||||
|
else WSContentSend_PD(SCRIPT_MSG_BUT_STOP);
|
||||||
|
} else if (!strncmp(lin,"tx(",3)) {
|
||||||
|
char *lp=lin+3;
|
||||||
char *slp=lp;
|
char *slp=lp;
|
||||||
char str[SCRIPT_MAXSSIZE];
|
char str[SCRIPT_MAXSSIZE];
|
||||||
lp=ForceStringVar(lp,str);
|
lp=ForceStringVar(lp,str);
|
||||||
|
@ -3766,11 +3895,38 @@ void ScriptWebShow(void) {
|
||||||
|
|
||||||
WSContentSend_PD(SCRIPT_MSG_TEXTINP,label,str,vname);
|
WSContentSend_PD(SCRIPT_MSG_TEXTINP,label,str,vname);
|
||||||
|
|
||||||
}
|
} else if (!strncmp(lin,"nm(",3)) {
|
||||||
else {
|
char *lp=lin;
|
||||||
Replace_Cmd_Vars(line,tmp,sizeof(tmp));
|
float min;
|
||||||
if (tmp[0]=='@') {
|
lp=GetNumericResult(lp+3,OPER_EQU,&min,0);
|
||||||
WSContentSend_PD(PSTR("<div>%s</div>"),&tmp[1]);
|
SCRIPT_SKIP_SPACES
|
||||||
|
float max;
|
||||||
|
lp=GetNumericResult(lp,OPER_EQU,&max,0);
|
||||||
|
SCRIPT_SKIP_SPACES
|
||||||
|
float step;
|
||||||
|
lp=GetNumericResult(lp,OPER_EQU,&step,0);
|
||||||
|
SCRIPT_SKIP_SPACES
|
||||||
|
float val;
|
||||||
|
char *slp=lp;
|
||||||
|
lp=GetNumericResult(lp,OPER_EQU,&val,0);
|
||||||
|
SCRIPT_SKIP_SPACES
|
||||||
|
char vname[16];
|
||||||
|
ScriptGetVarname(vname,slp,sizeof(vname));
|
||||||
|
|
||||||
|
char label[SCRIPT_MAXSSIZE];
|
||||||
|
lp=GetStringResult(lp,OPER_EQU,label,0);
|
||||||
|
|
||||||
|
char vstr[16],minstr[16],maxstr[16],stepstr[16];
|
||||||
|
dtostrfd(val,4,vstr);
|
||||||
|
dtostrfd(min,4,minstr);
|
||||||
|
dtostrfd(max,4,maxstr);
|
||||||
|
dtostrfd(step,4,stepstr);
|
||||||
|
WSContentSend_PD(SCRIPT_MSG_NUMINP,label,minstr,maxstr,stepstr,vstr,vname);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Replace_Cmd_Vars(lin,tmp,sizeof(tmp));
|
||||||
|
if (optflg) {
|
||||||
|
WSContentSend_PD(PSTR("<div>%s</div>"),tmp);
|
||||||
} else {
|
} else {
|
||||||
WSContentSend_PD(PSTR("{s}%s{e}"),tmp);
|
WSContentSend_PD(PSTR("{s}%s{e}"),tmp);
|
||||||
}
|
}
|
||||||
|
@ -3954,12 +4110,16 @@ bool Xdrv10(uint8_t function)
|
||||||
break;
|
break;
|
||||||
#ifdef SUPPORT_MQTT_EVENT
|
#ifdef SUPPORT_MQTT_EVENT
|
||||||
case FUNC_MQTT_DATA:
|
case FUNC_MQTT_DATA:
|
||||||
result = ScriptMqttData();
|
if (bitRead(Settings.rule_enabled, 0)) {
|
||||||
|
result = ScriptMqttData();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif //SUPPORT_MQTT_EVENT
|
#endif //SUPPORT_MQTT_EVENT
|
||||||
#ifdef USE_SCRIPT_WEB_DISPLAY
|
#ifdef USE_SCRIPT_WEB_DISPLAY
|
||||||
case FUNC_WEB_SENSOR:
|
case FUNC_WEB_SENSOR:
|
||||||
ScriptWebShow();
|
if (bitRead(Settings.rule_enabled, 0)) {
|
||||||
|
ScriptWebShow();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif //USE_SCRIPT_WEB_DISPLAY
|
#endif //USE_SCRIPT_WEB_DISPLAY
|
||||||
|
|
||||||
|
|
|
@ -364,30 +364,51 @@ void HueLightStatus2(uint8_t device, String *response)
|
||||||
char fname[33];
|
char fname[33];
|
||||||
strcpy(fname, Settings.friendlyname[MAX_FRIENDLYNAMES-1]);
|
strcpy(fname, Settings.friendlyname[MAX_FRIENDLYNAMES-1]);
|
||||||
uint32_t fname_len = strlen(fname);
|
uint32_t fname_len = strlen(fname);
|
||||||
if (fname_len >= 33-3) {
|
if (fname_len > 30) { fname_len = 30; }
|
||||||
fname[33-3] = 0x00;
|
|
||||||
fname_len = 33-3;
|
|
||||||
}
|
|
||||||
fname[fname_len++] = '-';
|
fname[fname_len++] = '-';
|
||||||
fname[fname_len++] = '0' + device - MAX_FRIENDLYNAMES;
|
if (device - MAX_FRIENDLYNAMES < 10) {
|
||||||
|
fname[fname_len++] = '0' + device - MAX_FRIENDLYNAMES;
|
||||||
|
} else {
|
||||||
|
fname[fname_len++] = 'A' + device - MAX_FRIENDLYNAMES - 10;
|
||||||
|
}
|
||||||
|
fname[fname_len] = 0x00;
|
||||||
|
|
||||||
response->replace("{j1", fname);
|
response->replace("{j1", fname);
|
||||||
}
|
}
|
||||||
response->replace("{j2", GetHueDeviceId(device));
|
response->replace("{j2", GetHueDeviceId(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate a unique lightId mixing local IP address and device number
|
// generate a unique lightId mixing local IP address and device number
|
||||||
// it is limited to 16 devices.
|
// it is limited to 32 devices.
|
||||||
// last 24 bits of Mac address + 4 bits of local light
|
// last 24 bits of Mac address + 4 bits of local light + high bit for relays 16-31, relay 32 is mapped to 0
|
||||||
uint32_t EncodeLightId(uint8_t idx)
|
uint32_t EncodeLightId(uint8_t relay_id)
|
||||||
{
|
{
|
||||||
uint8_t mac[6];
|
uint8_t mac[6];
|
||||||
WiFi.macAddress(mac);
|
WiFi.macAddress(mac);
|
||||||
uint32_t id = (mac[3] << 20) | (mac[4] << 12) | (mac[5] << 4) | (idx & 0xF);
|
uint32_t id = 0;
|
||||||
|
|
||||||
|
if (relay_id >= 32) { // for Relay #32, we encode as 0
|
||||||
|
relay_id = 0;
|
||||||
|
}
|
||||||
|
if (relay_id > 15) {
|
||||||
|
id = (1 << 28);
|
||||||
|
}
|
||||||
|
|
||||||
|
id |= (mac[3] << 20) | (mac[4] << 12) | (mac[5] << 4) | (relay_id & 0xF);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t DecodeLightId(uint32_t id) {
|
// get hue_id and decode the relay_id
|
||||||
return id & 0xF;
|
// 4 LSB decode to 1-15, if bit 28 is set, it encodes 16-31, if 0 then 32
|
||||||
|
uint32_t DecodeLightId(uint32_t hue_id) {
|
||||||
|
uint8_t relay_id = hue_id & 0xF;
|
||||||
|
if (hue_id & (1 << 28)) { // check if bit 25 is set, if so we have
|
||||||
|
relay_id += 16;
|
||||||
|
}
|
||||||
|
if (0 == relay_id) { // special value 0 is actually relay #32
|
||||||
|
relay_id = 32;
|
||||||
|
}
|
||||||
|
return relay_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * FIRST_GEN_UA[] = { // list of User-Agents signature
|
static const char * FIRST_GEN_UA[] = { // list of User-Agents signature
|
||||||
|
|
|
@ -75,7 +75,7 @@ public:
|
||||||
XdrvRulesProcess();
|
XdrvRulesProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ZCLFrame parseRawFrame(SBuffer &buf, uint8_t offset, uint8_t len, uint16_t clusterid, uint16_t groupid) { // parse a raw frame and build the ZCL frame object
|
static ZCLFrame parseRawFrame(const SBuffer &buf, uint8_t offset, uint8_t len, uint16_t clusterid, uint16_t groupid) { // parse a raw frame and build the ZCL frame object
|
||||||
uint32_t i = offset;
|
uint32_t i = offset;
|
||||||
ZCLHeaderFrameControl_t frame_control;
|
ZCLHeaderFrameControl_t frame_control;
|
||||||
uint16_t manuf_code = 0;
|
uint16_t manuf_code = 0;
|
||||||
|
|
|
@ -25,7 +25,7 @@ const uint32_t ZIGBEE_BUFFER_SIZE = 256; // Max ZNP frame is SOF+LEN+CMD1+CMD2+
|
||||||
const uint8_t ZIGBEE_SOF = 0xFE;
|
const uint8_t ZIGBEE_SOF = 0xFE;
|
||||||
|
|
||||||
// Status code used for ZigbeeStatus MQTT message
|
// Status code used for ZigbeeStatus MQTT message
|
||||||
// Ex: {"ZigbeeStatus":{"code": 3,"message":"Configured, starting coordinator"}}
|
// Ex: {"ZigbeeStatus":{"Status": 3,"Message":"Configured, starting coordinator"}}
|
||||||
const uint8_t ZIGBEE_STATUS_OK = 0; // Zigbee started and working
|
const uint8_t ZIGBEE_STATUS_OK = 0; // Zigbee started and working
|
||||||
const uint8_t ZIGBEE_STATUS_BOOT = 1; // CC2530 booting
|
const uint8_t ZIGBEE_STATUS_BOOT = 1; // CC2530 booting
|
||||||
const uint8_t ZIGBEE_STATUS_RESET_CONF = 2; // Resetting CC2530 configuration
|
const uint8_t ZIGBEE_STATUS_RESET_CONF = 2; // Resetting CC2530 configuration
|
||||||
|
@ -33,8 +33,9 @@ const uint8_t ZIGBEE_STATUS_STARTING = 3; // Starting CC2530 as co
|
||||||
const uint8_t ZIGBEE_STATUS_PERMITJOIN_CLOSE = 20; // Disable PermitJoin
|
const uint8_t ZIGBEE_STATUS_PERMITJOIN_CLOSE = 20; // Disable PermitJoin
|
||||||
const uint8_t ZIGBEE_STATUS_PERMITJOIN_OPEN_60 = 21; // Enable PermitJoin for 60 seconds
|
const uint8_t ZIGBEE_STATUS_PERMITJOIN_OPEN_60 = 21; // Enable PermitJoin for 60 seconds
|
||||||
const uint8_t ZIGBEE_STATUS_PERMITJOIN_OPEN_XX = 22; // Enable PermitJoin until next boot
|
const uint8_t ZIGBEE_STATUS_PERMITJOIN_OPEN_XX = 22; // Enable PermitJoin until next boot
|
||||||
const uint8_t ZIGBEE_STATUS_DEVICE_VERSION = 50; // Status: CC2530 ZNP Version
|
const uint8_t ZIGBEE_STATUS_DEVICE_ANNOUNCE = 30; // Device announces its address
|
||||||
const uint8_t ZIGBEE_STATUS_DEVICE_INFO = 51; // Status: CC2530 Device Configuration
|
const uint8_t ZIGBEE_STATUS_CC_VERSION = 50; // Status: CC2530 ZNP Version
|
||||||
|
const uint8_t ZIGBEE_STATUS_CC_INFO = 51; // Status: CC2530 Device Configuration
|
||||||
const uint8_t ZIGBEE_STATUS_UNSUPPORTED_VERSION = 98; // Unsupported ZNP version
|
const uint8_t ZIGBEE_STATUS_UNSUPPORTED_VERSION = 98; // Unsupported ZNP version
|
||||||
const uint8_t ZIGBEE_STATUS_ABORT = 99; // Fatal error, Zigbee not working
|
const uint8_t ZIGBEE_STATUS_ABORT = 99; // Fatal error, Zigbee not working
|
||||||
|
|
||||||
|
@ -170,6 +171,8 @@ SBuffer *zigbee_buffer = nullptr;
|
||||||
// Macro to define message to send and receive
|
// Macro to define message to send and receive
|
||||||
#define ZBM(n, x...) const uint8_t n[] PROGMEM = { x };
|
#define ZBM(n, x...) const uint8_t n[] PROGMEM = { x };
|
||||||
|
|
||||||
|
#define USE_ZIGBEE_CHANNEL_MASK (1 << (USE_ZIGBEE_CHANNEL))
|
||||||
|
|
||||||
// ZBS_* Zigbee Send
|
// ZBS_* Zigbee Send
|
||||||
// ZBR_* Zigbee Recv
|
// ZBR_* Zigbee Recv
|
||||||
ZBM(ZBS_RESET, Z_AREQ | Z_SYS, SYS_RESET, 0x00 ) // 410001 SYS_RESET_REQ Hardware reset
|
ZBM(ZBS_RESET, Z_AREQ | Z_SYS, SYS_RESET, 0x00 ) // 410001 SYS_RESET_REQ Hardware reset
|
||||||
|
@ -197,7 +200,7 @@ ZBM(ZBR_EXTPAN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_Success, CONF_EXTEND
|
||||||
ZBM(ZBS_CHANN, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_CHANLIST ) // 260484
|
ZBM(ZBS_CHANN, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_CHANLIST ) // 260484
|
||||||
ZBM(ZBR_CHANN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_Success, CONF_CHANLIST,
|
ZBM(ZBR_CHANN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_Success, CONF_CHANLIST,
|
||||||
0x04 /* len */,
|
0x04 /* len */,
|
||||||
Z_B0(USE_ZIGBEE_CHANNEL), Z_B1(USE_ZIGBEE_CHANNEL), Z_B2(USE_ZIGBEE_CHANNEL), Z_B3(USE_ZIGBEE_CHANNEL),
|
Z_B0(USE_ZIGBEE_CHANNEL_MASK), Z_B1(USE_ZIGBEE_CHANNEL_MASK), Z_B2(USE_ZIGBEE_CHANNEL_MASK), Z_B3(USE_ZIGBEE_CHANNEL_MASK),
|
||||||
) // 6604008404xxxxxxxx
|
) // 6604008404xxxxxxxx
|
||||||
|
|
||||||
ZBM(ZBS_PFGK, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_PRECFGKEY ) // 260462
|
ZBM(ZBS_PFGK, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_PRECFGKEY ) // 260462
|
||||||
|
@ -230,7 +233,7 @@ ZBM(ZBS_W_EXTPAN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_EXTENDED_PAN_I
|
||||||
) // 26052D086263151D004B1200
|
) // 26052D086263151D004B1200
|
||||||
// Write Channel ID
|
// Write Channel ID
|
||||||
ZBM(ZBS_W_CHANN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_CHANLIST, 0x04 /* len */,
|
ZBM(ZBS_W_CHANN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_CHANLIST, 0x04 /* len */,
|
||||||
Z_B0(USE_ZIGBEE_CHANNEL), Z_B1(USE_ZIGBEE_CHANNEL), Z_B2(USE_ZIGBEE_CHANNEL), Z_B3(USE_ZIGBEE_CHANNEL),
|
Z_B0(USE_ZIGBEE_CHANNEL_MASK), Z_B1(USE_ZIGBEE_CHANNEL_MASK), Z_B2(USE_ZIGBEE_CHANNEL_MASK), Z_B3(USE_ZIGBEE_CHANNEL_MASK),
|
||||||
/*0x00, 0x08, 0x00, 0x00*/ ) // 26058404xxxxxxxx
|
/*0x00, 0x08, 0x00, 0x00*/ ) // 26058404xxxxxxxx
|
||||||
// Write Logical Type = 00 = coordinator
|
// Write Logical Type = 00 = coordinator
|
||||||
ZBM(ZBS_W_LOGTYP, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_LOGICAL_TYPE, 0x01 /* len */, 0x00 ) // 2605870100
|
ZBM(ZBS_W_LOGTYP, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_LOGICAL_TYPE, 0x01 /* len */, 0x00 ) // 2605870100
|
||||||
|
@ -258,7 +261,9 @@ ZBM(ZBS_W_ZDODCB, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_ZDO_DIRECT_CB,
|
||||||
ZBM(ZBS_WNV_INITZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_ITEM_INIT, ZNP_HAS_CONFIGURED & 0xFF, ZNP_HAS_CONFIGURED >> 8,
|
ZBM(ZBS_WNV_INITZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_ITEM_INIT, ZNP_HAS_CONFIGURED & 0xFF, ZNP_HAS_CONFIGURED >> 8,
|
||||||
0x01, 0x00 /* InitLen 16 bits */, 0x01 /* len */, 0x00 ) // 2107000F01000100 - 610709
|
0x01, 0x00 /* InitLen 16 bits */, 0x01 /* len */, 0x00 ) // 2107000F01000100 - 610709
|
||||||
// Init succeeded
|
// Init succeeded
|
||||||
ZBM(ZBR_WNV_INIT_OK, Z_SRSP | Z_SYS, SYS_OSAL_NV_ITEM_INIT, Z_Created ) // 610709 - NV Write
|
//ZBM(ZBR_WNV_INIT_OK, Z_SRSP | Z_SYS, SYS_OSAL_NV_ITEM_INIT, Z_Created ) // 610709 - NV Write
|
||||||
|
ZBM(ZBR_WNV_INIT_OK, Z_SRSP | Z_SYS, SYS_OSAL_NV_ITEM_INIT ) // 6107xx, Success if 610700 or 610709 - NV Write
|
||||||
|
|
||||||
// Write ZNP Has Configured
|
// Write ZNP Has Configured
|
||||||
ZBM(ZBS_WNV_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, Z_B0(ZNP_HAS_CONFIGURED), Z_B1(ZNP_HAS_CONFIGURED),
|
ZBM(ZBS_WNV_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, Z_B0(ZNP_HAS_CONFIGURED), Z_B1(ZNP_HAS_CONFIGURED),
|
||||||
0x00 /* offset */, 0x01 /* len */, 0x55 ) // 2109000F000155 - 610900
|
0x00 /* offset */, 0x01 /* len */, 0x55 ) // 2109000F000155 - 610900
|
||||||
|
@ -326,7 +331,8 @@ ZBM(ZBR_PERMITJOIN_AREQ_OPEN_XX, Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND, 0xFF /* Du
|
||||||
ZBM(ZBR_PERMITJOIN_AREQ_RSP, Z_AREQ | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_RSP, 0x00, 0x00 /* srcAddr*/, Z_Success ) // 45B6000000
|
ZBM(ZBR_PERMITJOIN_AREQ_RSP, Z_AREQ | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_RSP, 0x00, 0x00 /* srcAddr*/, Z_Success ) // 45B6000000
|
||||||
|
|
||||||
// Filters for ZCL frames
|
// Filters for ZCL frames
|
||||||
ZBM(ZBR_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) // 4481
|
ZBM(ZBR_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) // 4481
|
||||||
|
ZBM(ZBR_END_DEVICE_ANNCE_IND, Z_AREQ | Z_ZDO, ZDO_END_DEVICE_ANNCE_IND) // 45C1
|
||||||
|
|
||||||
static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
||||||
ZI_LABEL(0)
|
ZI_LABEL(0)
|
||||||
|
@ -345,7 +351,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
||||||
ZI_SEND(ZBS_ZNPHC) // check value of ZNP Has Configured
|
ZI_SEND(ZBS_ZNPHC) // check value of ZNP Has Configured
|
||||||
ZI_WAIT_RECV(2000, ZBR_ZNPHC)
|
ZI_WAIT_RECV(2000, ZBR_ZNPHC)
|
||||||
ZI_SEND(ZBS_VERSION) // check ZNP software version
|
ZI_SEND(ZBS_VERSION) // check ZNP software version
|
||||||
ZI_WAIT_RECV_FUNC(1000, ZBR_VERSION, &Z_ReceiveCheckVersion) // Check version
|
ZI_WAIT_RECV_FUNC(2000, ZBR_VERSION, &Z_ReceiveCheckVersion) // Check version
|
||||||
ZI_SEND(ZBS_PAN) // check PAN ID
|
ZI_SEND(ZBS_PAN) // check PAN ID
|
||||||
ZI_WAIT_RECV(1000, ZBR_PAN)
|
ZI_WAIT_RECV(1000, ZBR_PAN)
|
||||||
ZI_SEND(ZBS_EXTPAN) // check EXT PAN ID
|
ZI_SEND(ZBS_EXTPAN) // check EXT PAN ID
|
||||||
|
@ -453,7 +459,7 @@ ZI_SEND(ZBS_STARTUPFROMAPP) // start coordinator
|
||||||
ZI_WAIT_RECV(1000, ZBR_W_OK)
|
ZI_WAIT_RECV(1000, ZBR_W_OK)
|
||||||
// Now mark the device as ready, writing 0x55 in memory slot 0x0F00
|
// Now mark the device as ready, writing 0x55 in memory slot 0x0F00
|
||||||
ZI_SEND(ZBS_WNV_INITZNPHC) // Init NV ZNP Has Configured
|
ZI_SEND(ZBS_WNV_INITZNPHC) // Init NV ZNP Has Configured
|
||||||
ZI_WAIT_RECV(1000, ZBR_WNV_INIT_OK)
|
ZI_WAIT_RECV_FUNC(1000, ZBR_WNV_INIT_OK, &Z_CheckNVWrite)
|
||||||
ZI_SEND(ZBS_WNV_ZNPHC) // Write NV ZNP Has Configured
|
ZI_SEND(ZBS_WNV_ZNPHC) // Write NV ZNP Has Configured
|
||||||
ZI_WAIT_RECV(1000, ZBR_WNV_OK)
|
ZI_WAIT_RECV(1000, ZBR_WNV_OK)
|
||||||
|
|
||||||
|
@ -487,10 +493,10 @@ int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) {
|
||||||
char hex[20];
|
char hex[20];
|
||||||
Uint64toHex(long_adr, hex, 64);
|
Uint64toHex(long_adr, hex, 64);
|
||||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATUS "\":{"
|
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATUS "\":{"
|
||||||
"\"code\":%d,\"IEEEAddr\":\"%s\",\"ShortAddr\":\"0x%04X\""
|
"\"Status\":%d,\"IEEEAddr\":\"%s\",\"ShortAddr\":\"0x%04X\""
|
||||||
",\"DeviceType\":%d,\"DeviceState\":%d"
|
",\"DeviceType\":%d,\"DeviceState\":%d"
|
||||||
",\"NumAssocDevices\":%d"),
|
",\"NumAssocDevices\":%d"),
|
||||||
ZIGBEE_STATUS_DEVICE_INFO, hex, short_adr, device_type, device_state,
|
ZIGBEE_STATUS_CC_INFO, hex, short_adr, device_type, device_state,
|
||||||
device_associated);
|
device_associated);
|
||||||
|
|
||||||
if (device_associated > 0) {
|
if (device_associated > 0) {
|
||||||
|
@ -512,6 +518,18 @@ int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t Z_CheckNVWrite(int32_t res, class SBuffer &buf) {
|
||||||
|
// Check the status after NV Init "ZNP Has Configured"
|
||||||
|
// Good response should be 610700 or 610709 (Success or Created)
|
||||||
|
// We only filter the response on 6107 and check the code in this function
|
||||||
|
uint8_t status = buf.get8(2);
|
||||||
|
if ((0x00 == status) || (0x09 == status)) {
|
||||||
|
return 0; // Ok, continue
|
||||||
|
} else {
|
||||||
|
return -2; // Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) {
|
int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) {
|
||||||
// check that the version is supported
|
// check that the version is supported
|
||||||
// typical version for ZNP 1.2
|
// typical version for ZNP 1.2
|
||||||
|
@ -528,9 +546,9 @@ int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) {
|
||||||
uint32_t revision = buf.get32(7);
|
uint32_t revision = buf.get32(7);
|
||||||
|
|
||||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATUS "\":{"
|
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATUS "\":{"
|
||||||
"\"code\":%d,\"MajorRel\":%d,\"MinorRel\":%d"
|
"\"Status\":%d,\"MajorRel\":%d,\"MinorRel\":%d"
|
||||||
",\"MaintRel\":%d,\"Revision\":%d}}"),
|
",\"MaintRel\":%d,\"Revision\":%d}}"),
|
||||||
ZIGBEE_STATUS_DEVICE_VERSION, major_rel, minor_rel,
|
ZIGBEE_STATUS_CC_VERSION, major_rel, minor_rel,
|
||||||
maint_rel, revision);
|
maint_rel, revision);
|
||||||
|
|
||||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATUS));
|
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATUS));
|
||||||
|
@ -543,53 +561,90 @@ int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Z_Recv_Default(int32_t res, class SBuffer &buf) {
|
bool Z_ReceiveMatchPrefix(const class SBuffer &buf, const uint8_t *match) {
|
||||||
|
if ( (pgm_read_byte(&match[0]) == buf.get8(0)) &&
|
||||||
|
(pgm_read_byte(&match[1]) == buf.get8(1)) ) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) {
|
||||||
|
Z_ShortAddress srcAddr = buf.get16(2);
|
||||||
|
Z_ShortAddress nwkAddr = buf.get16(4);
|
||||||
|
Z_IEEEAddress ieeeAddr = buf.get64(6);
|
||||||
|
uint8_t capabilities = buf.get8(14);
|
||||||
|
|
||||||
|
char hex[20];
|
||||||
|
Uint64toHex(ieeeAddr, hex, 64);
|
||||||
|
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATUS "\":{"
|
||||||
|
"\"Status\":%d,\"IEEEAddr\":\"%s\",\"ShortAddr\":\"0x%04X\""
|
||||||
|
",\"PowerSource\":%s,\"ReceiveWhenIdle\":%s,\"Security\":%s}}"),
|
||||||
|
ZIGBEE_STATUS_DEVICE_ANNOUNCE, hex, nwkAddr,
|
||||||
|
(capabilities & 0x04) ? "true" : "false",
|
||||||
|
(capabilities & 0x08) ? "true" : "false",
|
||||||
|
(capabilities & 0x40) ? "true" : "false"
|
||||||
|
);
|
||||||
|
|
||||||
|
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLRECEIVED));
|
||||||
|
XdrvRulesProcess();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
|
||||||
|
uint16_t groupid = buf.get16(2);
|
||||||
|
uint16_t clusterid = buf.get16(4);
|
||||||
|
Z_ShortAddress srcaddr = buf.get16(6);
|
||||||
|
uint8_t srcendpoint = buf.get8(8);
|
||||||
|
uint8_t dstendpoint = buf.get8(9);
|
||||||
|
uint8_t wasbroadcast = buf.get8(10);
|
||||||
|
uint8_t linkquality = buf.get8(11);
|
||||||
|
uint8_t securityuse = buf.get8(12);
|
||||||
|
uint32_t timestamp = buf.get32(13);
|
||||||
|
uint8_t seqnumber = buf.get8(17);
|
||||||
|
|
||||||
|
ZCLFrame zcl_received = ZCLFrame::parseRawFrame(buf, 19, buf.get8(18), clusterid, groupid);
|
||||||
|
|
||||||
|
zcl_received.publishMQTTReceived(groupid, clusterid, srcaddr,
|
||||||
|
srcendpoint, dstendpoint, wasbroadcast,
|
||||||
|
linkquality, securityuse, seqnumber,
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
char shortaddr[8];
|
||||||
|
snprintf_P(shortaddr, sizeof(shortaddr), PSTR("0x%04X"), srcaddr);
|
||||||
|
|
||||||
|
DynamicJsonBuffer jsonBuffer;
|
||||||
|
JsonObject& json_root = jsonBuffer.createObject();
|
||||||
|
JsonObject& json = json_root.createNestedObject(shortaddr);
|
||||||
|
if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_REPORT_ATTRIBUTES == zcl_received.getCmdId())) {
|
||||||
|
zcl_received.parseRawAttributes(json);
|
||||||
|
} else if (zcl_received.isClusterSpecificCommand()) {
|
||||||
|
zcl_received.parseClusterSpecificCommand(json);
|
||||||
|
}
|
||||||
|
zcl_received.postProcessAttributes(json);
|
||||||
|
|
||||||
|
String msg("");
|
||||||
|
msg.reserve(100);
|
||||||
|
json_root.printTo(msg);
|
||||||
|
|
||||||
|
Response_P(PSTR("%s"), msg.c_str());
|
||||||
|
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLRECEIVED));
|
||||||
|
XdrvRulesProcess();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
|
||||||
// Default message handler for new messages
|
// Default message handler for new messages
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Z_Recv_Default"));
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Z_Recv_Default"));
|
||||||
if (zigbee.init_phase) {
|
if (zigbee.init_phase) {
|
||||||
// if still during initialization phase, ignore any unexpected message
|
// if still during initialization phase, ignore any unexpected message
|
||||||
return -1; // ignore message
|
return -1; // ignore message
|
||||||
} else {
|
} else {
|
||||||
if ( (pgm_read_byte(&ZBR_AF_INCOMING_MESSAGE[0]) == buf.get8(0)) &&
|
if (Z_ReceiveMatchPrefix(buf, ZBR_AF_INCOMING_MESSAGE)) {
|
||||||
(pgm_read_byte(&ZBR_AF_INCOMING_MESSAGE[1]) == buf.get8(1)) ) {
|
return Z_ReceiveAfIncomingMessage(res, buf);
|
||||||
uint16_t groupid = buf.get16(2);
|
} else if (Z_ReceiveMatchPrefix(buf, ZBR_END_DEVICE_ANNCE_IND)) {
|
||||||
uint16_t clusterid = buf.get16(4);
|
return Z_ReceiveEndDeviceAnnonce(res, buf);
|
||||||
Z_ShortAddress srcaddr = buf.get16(6);
|
|
||||||
uint8_t srcendpoint = buf.get8(8);
|
|
||||||
uint8_t dstendpoint = buf.get8(9);
|
|
||||||
uint8_t wasbroadcast = buf.get8(10);
|
|
||||||
uint8_t linkquality = buf.get8(11);
|
|
||||||
uint8_t securityuse = buf.get8(12);
|
|
||||||
uint32_t timestamp = buf.get32(13);
|
|
||||||
uint8_t seqnumber = buf.get8(17);
|
|
||||||
|
|
||||||
ZCLFrame zcl_received = ZCLFrame::parseRawFrame(buf, 19, buf.get8(18), clusterid, groupid);
|
|
||||||
|
|
||||||
zcl_received.publishMQTTReceived(groupid, clusterid, srcaddr,
|
|
||||||
srcendpoint, dstendpoint, wasbroadcast,
|
|
||||||
linkquality, securityuse, seqnumber,
|
|
||||||
timestamp);
|
|
||||||
|
|
||||||
char shortaddr[8];
|
|
||||||
snprintf_P(shortaddr, sizeof(shortaddr), PSTR("0x%04X"), srcaddr);
|
|
||||||
|
|
||||||
DynamicJsonBuffer jsonBuffer;
|
|
||||||
JsonObject& json_root = jsonBuffer.createObject();
|
|
||||||
JsonObject& json = json_root.createNestedObject(shortaddr);
|
|
||||||
if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_REPORT_ATTRIBUTES == zcl_received.getCmdId())) {
|
|
||||||
zcl_received.parseRawAttributes(json);
|
|
||||||
} else if (zcl_received.isClusterSpecificCommand()) {
|
|
||||||
zcl_received.parseClusterSpecificCommand(json);
|
|
||||||
}
|
|
||||||
zcl_received.postProcessAttributes(json);
|
|
||||||
|
|
||||||
String msg("");
|
|
||||||
msg.reserve(100);
|
|
||||||
json_root.printTo(msg);
|
|
||||||
|
|
||||||
Response_P(PSTR("%s"), msg.c_str());
|
|
||||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLRECEIVED));
|
|
||||||
XdrvRulesProcess();
|
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -753,7 +808,7 @@ void ZigbeeStateMachine_Run(void) {
|
||||||
AddLog_P(cur_d8, (char*) cur_ptr1);
|
AddLog_P(cur_d8, (char*) cur_ptr1);
|
||||||
break;
|
break;
|
||||||
case ZGB_INSTR_MQTT_STATUS:
|
case ZGB_INSTR_MQTT_STATUS:
|
||||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATUS "\":{\"code\":%d,\"message\":\"%s\"}}"),
|
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATUS "\":{\"Status\":%d,\"Message\":\"%s\"}}"),
|
||||||
cur_d8, (char*) cur_ptr1);
|
cur_d8, (char*) cur_ptr1);
|
||||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATUS));
|
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATUS));
|
||||||
XdrvRulesProcess();
|
XdrvRulesProcess();
|
||||||
|
@ -932,7 +987,7 @@ void ZigbeeInput(void)
|
||||||
SBuffer znp_buffer = zigbee_buffer->subBuffer(2, zigbee_frame_len - 3); // remove SOF, LEN and FCS
|
SBuffer znp_buffer = zigbee_buffer->subBuffer(2, zigbee_frame_len - 3); // remove SOF, LEN and FCS
|
||||||
|
|
||||||
ToHex_P((unsigned char*)znp_buffer.getBuffer(), znp_buffer.len(), hex_char, sizeof(hex_char));
|
ToHex_P((unsigned char*)znp_buffer.getBuffer(), znp_buffer.len(), hex_char, sizeof(hex_char));
|
||||||
ResponseTime_P(PSTR(",\"" D_JSON_ZIGBEEZNPRECEIVED "\":\"%s\"}"), hex_char);
|
Response_P(PSTR("{\"" D_JSON_ZIGBEEZNPRECEIVED "\":\"%s\"}"), hex_char);
|
||||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZNPRECEIVED));
|
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZNPRECEIVED));
|
||||||
XdrvRulesProcess();
|
XdrvRulesProcess();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
xdrv_26_sm2135.ino - sm2135 I2C five channel led support for Sonoff-Tasmota
|
||||||
|
|
||||||
|
Copyright (C) 2019 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_LIGHT
|
||||||
|
#ifdef USE_SM2135
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* SM2135 I2C RGBCW Led bulbs like Action LSC SmartLed
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define XDRV_26 26
|
||||||
|
|
||||||
|
#define SM2135_ADDR 0x40 // 0x40 .. 0x46
|
||||||
|
|
||||||
|
//#define SM2135_CURRENT 0x24 // Defaults: 20mA for RGB, 30mA for CW
|
||||||
|
#define SM2135_CURRENT 0x16 // 3 x 15mA for RGB, 2 x 40mA/2 for CW
|
||||||
|
|
||||||
|
#define SM2135_RGB 0x00
|
||||||
|
#define SM2135_CW 0x80
|
||||||
|
|
||||||
|
struct SM2135 {
|
||||||
|
bool found = true;
|
||||||
|
} Sm2135;
|
||||||
|
|
||||||
|
bool Sm2135SetChannels(void)
|
||||||
|
{
|
||||||
|
char *buffer = XdrvMailbox.data;
|
||||||
|
|
||||||
|
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SM1: R %d G %d B %d, C %d W %d"), buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
|
||||||
|
|
||||||
|
if (('\0' == buffer[0]) && ('\0' == buffer[1]) && ('\0' == buffer[2])) {
|
||||||
|
// No color so must be Cold/Warm
|
||||||
|
if ((buffer[3] + buffer[4]) >= (1 * 256)) {
|
||||||
|
// Scale down to 255 total to fix max power usage of 9W (=40mA)
|
||||||
|
// Currently not needed with setting 2 x 40mA/2 = 40mA = 9W = 255 (handled by lights.ino)
|
||||||
|
|
||||||
|
buffer[3] >>= 1; // Divide by 2
|
||||||
|
buffer[4] >>= 1; // Divide by 2
|
||||||
|
}
|
||||||
|
Wire.beginTransmission(SM2135_ADDR);
|
||||||
|
Wire.write(SM2135_CURRENT); // Set current to 40mA
|
||||||
|
Wire.write(SM2135_CW); // Select CW - Shutdown RGB?
|
||||||
|
Wire.endTransmission();
|
||||||
|
delay(1);
|
||||||
|
Wire.beginTransmission(SM2135_ADDR +5);
|
||||||
|
Wire.write(buffer[3]); // Cold
|
||||||
|
Wire.write(buffer[4]); // Warm
|
||||||
|
Wire.endTransmission();
|
||||||
|
} else {
|
||||||
|
// Color
|
||||||
|
if ((buffer[0] + buffer[1] + buffer[2]) >= (3 * 256)) {
|
||||||
|
// Scale down to 765 total to fix max power usage of 9W
|
||||||
|
// Currently not needed with setting 3 x 15mA = 45mA = 11W = 765
|
||||||
|
}
|
||||||
|
Wire.beginTransmission(SM2135_ADDR);
|
||||||
|
Wire.write(SM2135_CURRENT); // Set current to 15mA
|
||||||
|
Wire.write(SM2135_RGB); // Select RGB - Shutdown CW?
|
||||||
|
Wire.write(buffer[0]); // Red
|
||||||
|
Wire.write(buffer[1]); // Green
|
||||||
|
Wire.write(buffer[2]); // Blue
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sm2135ModuleSelected(void)
|
||||||
|
{
|
||||||
|
if (I2cDevice(SM2135_ADDR)) {
|
||||||
|
|
||||||
|
// Make sure it is the SM2135 chip as it's address is also used by HTU21, INA219, INA226
|
||||||
|
// EXPERIMENTAL: Need further testing
|
||||||
|
|
||||||
|
light_type = LT_RGBWC;
|
||||||
|
|
||||||
|
AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "SM2135", SM2135_ADDR);
|
||||||
|
} else {
|
||||||
|
Sm2135.found = false;
|
||||||
|
}
|
||||||
|
return Sm2135.found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Interface
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
bool Xdrv26(uint8_t function)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (i2c_flg && Sm2135.found) {
|
||||||
|
switch (function) {
|
||||||
|
case FUNC_SET_CHANNELS:
|
||||||
|
result = Sm2135SetChannels();
|
||||||
|
break;
|
||||||
|
case FUNC_MODULE_INIT:
|
||||||
|
result = Sm2135ModuleSelected();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_SM2135
|
||||||
|
#endif // USE_LIGHT
|
|
@ -89,7 +89,7 @@ void HlwCfInterrupt(void) // Service Power
|
||||||
Hlw.cf_pulse_last_time = us;
|
Hlw.cf_pulse_last_time = us;
|
||||||
Hlw.energy_period_counter++;
|
Hlw.energy_period_counter++;
|
||||||
}
|
}
|
||||||
Energy.data_valid = 0;
|
Energy.data_valid[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HlwCf1Interrupt(void) // Service Voltage and Current
|
void HlwCf1Interrupt(void) // Service Voltage and Current
|
||||||
|
@ -108,7 +108,7 @@ void HlwCf1Interrupt(void) // Service Voltage and Current
|
||||||
Hlw.cf1_timer = 8; // We need up to HLW_SAMPLE_COUNT samples within 1 second (low current could take up to 0.3 second)
|
Hlw.cf1_timer = 8; // We need up to HLW_SAMPLE_COUNT samples within 1 second (low current could take up to 0.3 second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Energy.data_valid = 0;
|
Energy.data_valid[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************************/
|
/********************************************************************************************/
|
||||||
|
@ -199,7 +199,7 @@ void HlwEvery200ms(void)
|
||||||
|
|
||||||
void HlwEverySecond(void)
|
void HlwEverySecond(void)
|
||||||
{
|
{
|
||||||
if (Energy.data_valid > ENERGY_WATCHDOG) {
|
if (Energy.data_valid[0] > ENERGY_WATCHDOG) {
|
||||||
Hlw.cf1_voltage_pulse_length = 0;
|
Hlw.cf1_voltage_pulse_length = 0;
|
||||||
Hlw.cf1_current_pulse_length = 0;
|
Hlw.cf1_current_pulse_length = 0;
|
||||||
Hlw.cf_power_pulse_length = 0;
|
Hlw.cf_power_pulse_length = 0;
|
||||||
|
|
|
@ -143,7 +143,7 @@ bool CseSerialInput(void)
|
||||||
uint8_t checksum = 0;
|
uint8_t checksum = 0;
|
||||||
for (uint32_t i = 2; i < 23; i++) { checksum += serial_in_buffer[i]; }
|
for (uint32_t i = 2; i < 23; i++) { checksum += serial_in_buffer[i]; }
|
||||||
if (checksum == serial_in_buffer[23]) {
|
if (checksum == serial_in_buffer[23]) {
|
||||||
Energy.data_valid = 0;
|
Energy.data_valid[0] = 0;
|
||||||
CseReceived();
|
CseReceived();
|
||||||
Cse.received = false;
|
Cse.received = false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -175,7 +175,7 @@ bool CseSerialInput(void)
|
||||||
|
|
||||||
void CseEverySecond(void)
|
void CseEverySecond(void)
|
||||||
{
|
{
|
||||||
if (Energy.data_valid > ENERGY_WATCHDOG) {
|
if (Energy.data_valid[0] > ENERGY_WATCHDOG) {
|
||||||
Cse.voltage_cycle = 0;
|
Cse.voltage_cycle = 0;
|
||||||
Cse.current_cycle = 0;
|
Cse.current_cycle = 0;
|
||||||
Cse.power_cycle = 0;
|
Cse.power_cycle = 0;
|
||||||
|
|
|
@ -179,7 +179,7 @@ void PzemEvery200ms(void)
|
||||||
if (data_ready) {
|
if (data_ready) {
|
||||||
float value = 0;
|
float value = 0;
|
||||||
if (PzemRecieve(pzem_responses[Pzem.read_state], &value)) {
|
if (PzemRecieve(pzem_responses[Pzem.read_state], &value)) {
|
||||||
Energy.data_valid = 0;
|
Energy.data_valid[Pzem.phase] = 0;
|
||||||
switch (Pzem.read_state) {
|
switch (Pzem.read_state) {
|
||||||
case 1: // Voltage as 230.2V
|
case 1: // Voltage as 230.2V
|
||||||
Energy.voltage[Pzem.phase] = value;
|
Energy.voltage[Pzem.phase] = value;
|
||||||
|
|
|
@ -455,6 +455,7 @@ void McpParseData(void)
|
||||||
mcp_line_frequency = McpExtractInt(mcp_buffer, 22, 2);
|
mcp_line_frequency = McpExtractInt(mcp_buffer, 22, 2);
|
||||||
|
|
||||||
if (Energy.power_on) { // Powered on
|
if (Energy.power_on) { // Powered on
|
||||||
|
Energy.data_valid[0] = 0;
|
||||||
Energy.frequency[0] = (float)mcp_line_frequency / 1000;
|
Energy.frequency[0] = (float)mcp_line_frequency / 1000;
|
||||||
Energy.voltage[0] = (float)mcp_voltage_rms / 10;
|
Energy.voltage[0] = (float)mcp_voltage_rms / 10;
|
||||||
Energy.active_power[0] = (float)mcp_active_power / 100;
|
Energy.active_power[0] = (float)mcp_active_power / 100;
|
||||||
|
@ -464,12 +465,8 @@ void McpParseData(void)
|
||||||
Energy.current[0] = (float)mcp_current_rms / 10000;
|
Energy.current[0] = (float)mcp_current_rms / 10000;
|
||||||
}
|
}
|
||||||
} else { // Powered off
|
} else { // Powered off
|
||||||
Energy.frequency[0] = 0;
|
Energy.data_valid[0] = ENERGY_WATCHDOG;
|
||||||
Energy.voltage[0] = 0;
|
|
||||||
Energy.active_power[0] = 0;
|
|
||||||
Energy.current[0] = 0;
|
|
||||||
}
|
}
|
||||||
Energy.data_valid = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************************/
|
/********************************************************************************************/
|
||||||
|
@ -527,7 +524,7 @@ void McpSerialInput(void)
|
||||||
|
|
||||||
void McpEverySecond(void)
|
void McpEverySecond(void)
|
||||||
{
|
{
|
||||||
if (Energy.data_valid > ENERGY_WATCHDOG) {
|
if (Energy.data_valid[0] > ENERGY_WATCHDOG) {
|
||||||
mcp_voltage_rms = 0;
|
mcp_voltage_rms = 0;
|
||||||
mcp_current_rms = 0;
|
mcp_current_rms = 0;
|
||||||
mcp_active_power = 0;
|
mcp_active_power = 0;
|
||||||
|
|
|
@ -62,7 +62,7 @@ void PzemAcEverySecond(void)
|
||||||
if (error) {
|
if (error) {
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PAC: PzemAc %d error %d"), PZEM_AC_DEVICE_ADDRESS + PzemAc.phase, error);
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PAC: PzemAc %d error %d"), PZEM_AC_DEVICE_ADDRESS + PzemAc.phase, error);
|
||||||
} else {
|
} else {
|
||||||
Energy.data_valid = 0;
|
Energy.data_valid[PzemAc.phase] = 0;
|
||||||
if (10 == registers) {
|
if (10 == registers) {
|
||||||
|
|
||||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
||||||
|
|
|
@ -62,7 +62,7 @@ void PzemDcEverySecond(void)
|
||||||
if (error) {
|
if (error) {
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PDC: PzemDc %d error %d"), PZEM_DC_DEVICE_ADDRESS + PzemDc.channel, error);
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PDC: PzemDc %d error %d"), PZEM_DC_DEVICE_ADDRESS + PzemDc.channel, error);
|
||||||
} else {
|
} else {
|
||||||
Energy.data_valid = 0;
|
Energy.data_valid[PzemDc.channel] = 0;
|
||||||
if (8 == registers) {
|
if (8 == registers) {
|
||||||
|
|
||||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
||||||
|
|
|
@ -155,6 +155,7 @@ void Ade7953GetData(void)
|
||||||
Energy.voltage[0] = (float)Ade7953.voltage_rms / Settings.energy_voltage_calibration;
|
Energy.voltage[0] = (float)Ade7953.voltage_rms / Settings.energy_voltage_calibration;
|
||||||
|
|
||||||
for (uint32_t channel = 0; channel < 2; channel++) {
|
for (uint32_t channel = 0; channel < 2; channel++) {
|
||||||
|
Energy.data_valid[channel] = 0;
|
||||||
Energy.active_power[channel] = (float)Ade7953.active_power[channel] / (Settings.energy_power_calibration / 10);
|
Energy.active_power[channel] = (float)Ade7953.active_power[channel] / (Settings.energy_power_calibration / 10);
|
||||||
Energy.reactive_power[channel] = (float)reactive_power[channel] / (Settings.energy_power_calibration / 10);
|
Energy.reactive_power[channel] = (float)reactive_power[channel] / (Settings.energy_power_calibration / 10);
|
||||||
Energy.apparent_power[channel] = (float)apparent_power[channel] / (Settings.energy_power_calibration / 10);
|
Energy.apparent_power[channel] = (float)apparent_power[channel] / (Settings.energy_power_calibration / 10);
|
||||||
|
@ -165,13 +166,8 @@ void Ade7953GetData(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Powered off
|
} else { // Powered off
|
||||||
Energy.voltage[0] = 0;
|
Energy.data_valid[0] = ENERGY_WATCHDOG;
|
||||||
for (uint32_t channel = 0; channel < 2; channel++) {
|
Energy.data_valid[1] = ENERGY_WATCHDOG;
|
||||||
Energy.current[channel] = 0;
|
|
||||||
Energy.active_power[channel] = 0;
|
|
||||||
Energy.reactive_power[channel] = 0;
|
|
||||||
Energy.apparent_power[channel] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active_power_sum) {
|
if (active_power_sum) {
|
||||||
|
|
|
@ -85,7 +85,7 @@ void SDM120Every250ms(void)
|
||||||
if (error) {
|
if (error) {
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SDM: SDM120 error %d"), error);
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SDM: SDM120 error %d"), error);
|
||||||
} else {
|
} else {
|
||||||
Energy.data_valid = 0;
|
Energy.data_valid[0] = 0;
|
||||||
|
|
||||||
// 0 1 2 3 4 5 6 7 8
|
// 0 1 2 3 4 5 6 7 8
|
||||||
// SA FC BC Fh Fl Sh Sl Cl Ch
|
// SA FC BC Fh Fl Sh Sl Cl Ch
|
||||||
|
|
|
@ -52,7 +52,7 @@ void Dds2382EverySecond(void)
|
||||||
if (error) {
|
if (error) {
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "DDS2382 response error %d"), error);
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "DDS2382 response error %d"), error);
|
||||||
} else {
|
} else {
|
||||||
Energy.data_valid = 0;
|
Energy.data_valid[0] = 0;
|
||||||
|
|
||||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
||||||
// SA FC BC EnergyTotal ExportActiv ImportActiv Volta Curre APowe RPowe PFact Frequ Crc--
|
// SA FC BC EnergyTotal ExportActiv ImportActiv Volta Curre APowe RPowe PFact Frequ Crc--
|
||||||
|
|
|
@ -78,7 +78,9 @@ void SDM630Every250ms(void)
|
||||||
if (error) {
|
if (error) {
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SDM: SDM630 error %d"), error);
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SDM: SDM630 error %d"), error);
|
||||||
} else {
|
} else {
|
||||||
Energy.data_valid = 0;
|
Energy.data_valid[0] = 0;
|
||||||
|
Energy.data_valid[1] = 0;
|
||||||
|
Energy.data_valid[2] = 0;
|
||||||
|
|
||||||
// 0 1 2 3 4 5 6 7 8
|
// 0 1 2 3 4 5 6 7 8
|
||||||
// SA FC BC Fh Fl Sh Sl Cl Ch
|
// SA FC BC Fh Fl Sh Sl Cl Ch
|
||||||
|
|
|
@ -74,7 +74,11 @@ uint8_t OneWireReset(void)
|
||||||
uint8_t retries = 125;
|
uint8_t retries = 125;
|
||||||
|
|
||||||
//noInterrupts();
|
//noInterrupts();
|
||||||
|
#ifdef DS18B20_INTERNAL_PULLUP
|
||||||
|
pinMode(ds18x20_pin, INPUT_PULLUP);
|
||||||
|
#else
|
||||||
pinMode(ds18x20_pin, INPUT);
|
pinMode(ds18x20_pin, INPUT);
|
||||||
|
#endif
|
||||||
do {
|
do {
|
||||||
if (--retries == 0) {
|
if (--retries == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -84,7 +88,11 @@ uint8_t OneWireReset(void)
|
||||||
pinMode(ds18x20_pin, OUTPUT);
|
pinMode(ds18x20_pin, OUTPUT);
|
||||||
digitalWrite(ds18x20_pin, LOW);
|
digitalWrite(ds18x20_pin, LOW);
|
||||||
delayMicroseconds(480);
|
delayMicroseconds(480);
|
||||||
|
#ifdef DS18B20_INTERNAL_PULLUP
|
||||||
|
pinMode(ds18x20_pin, INPUT_PULLUP);
|
||||||
|
#else
|
||||||
pinMode(ds18x20_pin, INPUT);
|
pinMode(ds18x20_pin, INPUT);
|
||||||
|
#endif
|
||||||
delayMicroseconds(70);
|
delayMicroseconds(70);
|
||||||
uint8_t r = !digitalRead(ds18x20_pin);
|
uint8_t r = !digitalRead(ds18x20_pin);
|
||||||
//interrupts();
|
//interrupts();
|
||||||
|
@ -113,7 +121,11 @@ uint8_t OneWireReadBit(void)
|
||||||
pinMode(ds18x20_pin, OUTPUT);
|
pinMode(ds18x20_pin, OUTPUT);
|
||||||
digitalWrite(ds18x20_pin, LOW);
|
digitalWrite(ds18x20_pin, LOW);
|
||||||
delayMicroseconds(3);
|
delayMicroseconds(3);
|
||||||
|
#ifdef DS18B20_INTERNAL_PULLUP
|
||||||
|
pinMode(ds18x20_pin, INPUT_PULLUP);
|
||||||
|
#else
|
||||||
pinMode(ds18x20_pin, INPUT);
|
pinMode(ds18x20_pin, INPUT);
|
||||||
|
#endif
|
||||||
delayMicroseconds(10);
|
delayMicroseconds(10);
|
||||||
uint8_t r = digitalRead(ds18x20_pin);
|
uint8_t r = digitalRead(ds18x20_pin);
|
||||||
//interrupts();
|
//interrupts();
|
||||||
|
@ -432,7 +444,7 @@ void Ds18x20Show(bool json)
|
||||||
|
|
||||||
if (json) {
|
if (json) {
|
||||||
if (1 == ds18x20_sensors) {
|
if (1 == ds18x20_sensors) {
|
||||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"), ds18x20_types, temperature);
|
ResponseAppend_P(JSON_SNS_TEMP, ds18x20_types, temperature);
|
||||||
} else {
|
} else {
|
||||||
char address[17];
|
char address[17];
|
||||||
for (uint32_t j = 0; j < 6; j++) {
|
for (uint32_t j = 0; j < 6; j++) {
|
||||||
|
|
|
@ -1,245 +0,0 @@
|
||||||
/*
|
|
||||||
xsns_05_ds18x20_legacy.ino - DS18x20 temperature sensor 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_DS18x20_LEGACY
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* DS18B20 - Temperature
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
#define XSNS_05 5
|
|
||||||
|
|
||||||
#define DS18S20_CHIPID 0x10
|
|
||||||
#define DS18B20_CHIPID 0x28
|
|
||||||
#define MAX31850_CHIPID 0x3B
|
|
||||||
|
|
||||||
#define W1_SKIP_ROM 0xCC
|
|
||||||
#define W1_CONVERT_TEMP 0x44
|
|
||||||
#define W1_READ_SCRATCHPAD 0xBE
|
|
||||||
|
|
||||||
#define DS18X20_MAX_SENSORS 8
|
|
||||||
|
|
||||||
#include <OneWire.h>
|
|
||||||
|
|
||||||
OneWire *ds = nullptr;
|
|
||||||
|
|
||||||
uint8_t ds18x20_address[DS18X20_MAX_SENSORS][8];
|
|
||||||
uint8_t ds18x20_index[DS18X20_MAX_SENSORS];
|
|
||||||
uint8_t ds18x20_sensors = 0;
|
|
||||||
char ds18x20_types[9];
|
|
||||||
|
|
||||||
void Ds18x20Init(void)
|
|
||||||
{
|
|
||||||
ds = new OneWire(pin[GPIO_DSB]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Ds18x20Search(void)
|
|
||||||
{
|
|
||||||
uint8_t num_sensors=0;
|
|
||||||
uint8_t sensor = 0;
|
|
||||||
|
|
||||||
ds->reset_search();
|
|
||||||
for (num_sensors = 0; num_sensors < DS18X20_MAX_SENSORS; num_sensors) {
|
|
||||||
if (!ds->search(ds18x20_address[num_sensors])) {
|
|
||||||
ds->reset_search();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// If CRC Ok and Type DS18S20, DS18B20 or MAX31850
|
|
||||||
if ((OneWire::crc8(ds18x20_address[num_sensors], 7) == ds18x20_address[num_sensors][7]) &&
|
|
||||||
((ds18x20_address[num_sensors][0]==DS18S20_CHIPID) || (ds18x20_address[num_sensors][0]==DS18B20_CHIPID) || (ds18x20_address[num_sensors][0]==MAX31850_CHIPID))) {
|
|
||||||
num_sensors++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (uint32_t i = 0; i < num_sensors; i++) {
|
|
||||||
ds18x20_index[i] = i;
|
|
||||||
}
|
|
||||||
for (uint32_t i = 0; i < num_sensors; i++) {
|
|
||||||
for (uint32_t j = i + 1; j < num_sensors; j++) {
|
|
||||||
if (uint32_t(ds18x20_address[ds18x20_index[i]]) > uint32_t(ds18x20_address[ds18x20_index[j]])) {
|
|
||||||
std::swap(ds18x20_index[i], ds18x20_index[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ds18x20_sensors = num_sensors;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t Ds18x20Sensors(void)
|
|
||||||
{
|
|
||||||
return ds18x20_sensors;
|
|
||||||
}
|
|
||||||
|
|
||||||
String Ds18x20Addresses(uint8_t sensor)
|
|
||||||
{
|
|
||||||
char address[20];
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 8; i++) {
|
|
||||||
sprintf(address+2*i, "%02X", ds18x20_address[ds18x20_index[sensor]][i]);
|
|
||||||
}
|
|
||||||
return String(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Ds18x20Convert(void)
|
|
||||||
{
|
|
||||||
ds->reset();
|
|
||||||
ds->write(W1_SKIP_ROM); // Address all Sensors on Bus
|
|
||||||
ds->write(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end
|
|
||||||
// delay(750); // 750ms should be enough for 12bit conv
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Ds18x20Read(uint8_t sensor, float &t)
|
|
||||||
{
|
|
||||||
uint8_t data[12];
|
|
||||||
int8_t sign = 1;
|
|
||||||
uint16_t temp12 = 0;
|
|
||||||
int16_t temp14 = 0;
|
|
||||||
float temp9 = 0.0;
|
|
||||||
uint8_t present = 0;
|
|
||||||
|
|
||||||
t = NAN;
|
|
||||||
|
|
||||||
ds->reset();
|
|
||||||
ds->select(ds18x20_address[ds18x20_index[sensor]]);
|
|
||||||
ds->write(W1_READ_SCRATCHPAD); // Read Scratchpad
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 9; i++) {
|
|
||||||
data[i] = ds->read();
|
|
||||||
}
|
|
||||||
if (OneWire::crc8(data, 8) == data[8]) {
|
|
||||||
switch(ds18x20_address[ds18x20_index[sensor]][0]) {
|
|
||||||
case DS18S20_CHIPID:
|
|
||||||
if (data[1] > 0x80) {
|
|
||||||
data[0] = (~data[0]) +1;
|
|
||||||
sign = -1; // App-Note fix possible sign error
|
|
||||||
}
|
|
||||||
temp9 = (float)(data[0] >> 1) * sign;
|
|
||||||
t = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0));
|
|
||||||
break;
|
|
||||||
case DS18B20_CHIPID:
|
|
||||||
temp12 = (data[1] << 8) + data[0];
|
|
||||||
if (temp12 > 2047) {
|
|
||||||
temp12 = (~temp12) +1;
|
|
||||||
sign = -1;
|
|
||||||
}
|
|
||||||
t = ConvertTemp(sign * temp12 * 0.0625); // Divide by 16
|
|
||||||
break;
|
|
||||||
case MAX31850_CHIPID:
|
|
||||||
temp14 = (data[1] << 8) + (data[0] & 0xFC);
|
|
||||||
t = ConvertTemp(temp14 * 0.0625); // Divide by 16
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (!isnan(t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************************************/
|
|
||||||
|
|
||||||
void Ds18x20Type(uint8_t sensor)
|
|
||||||
{
|
|
||||||
strcpy_P(ds18x20_types, PSTR("DS18x20"));
|
|
||||||
switch(ds18x20_address[ds18x20_index[sensor]][0]) {
|
|
||||||
case DS18S20_CHIPID:
|
|
||||||
strcpy_P(ds18x20_types, PSTR("DS18S20"));
|
|
||||||
break;
|
|
||||||
case DS18B20_CHIPID:
|
|
||||||
strcpy_P(ds18x20_types, PSTR("DS18B20"));
|
|
||||||
break;
|
|
||||||
case MAX31850_CHIPID:
|
|
||||||
strcpy_P(ds18x20_types, PSTR("MAX31850"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Ds18x20Show(bool json)
|
|
||||||
{
|
|
||||||
char stemp[10];
|
|
||||||
float t;
|
|
||||||
|
|
||||||
uint8_t dsxflg = 0;
|
|
||||||
for (uint32_t i = 0; i < Ds18x20Sensors(); i++) {
|
|
||||||
if (Ds18x20Read(i, t)) { // Check if read failed
|
|
||||||
Ds18x20Type(i);
|
|
||||||
char temperature[33];
|
|
||||||
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
|
|
||||||
|
|
||||||
if (json) {
|
|
||||||
if (!dsxflg) {
|
|
||||||
ResponseAppend_P(PSTR(",\"DS18x20\":{"));
|
|
||||||
stemp[0] = '\0';
|
|
||||||
}
|
|
||||||
dsxflg++;
|
|
||||||
ResponseAppend_P(PSTR("%s\"DS%d\":{\"" D_JSON_TYPE "\":\"%s\",\"" D_JSON_ADDRESS "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"),
|
|
||||||
stemp, i +1, ds18x20_types, Ds18x20Addresses(i).c_str(), temperature);
|
|
||||||
strlcpy(stemp, ",", sizeof(stemp));
|
|
||||||
#ifdef USE_DOMOTICZ
|
|
||||||
if ((0 == tele_period) && (1 == dsxflg)) {
|
|
||||||
DomoticzSensor(DZ_TEMP, temperature);
|
|
||||||
}
|
|
||||||
#endif // USE_DOMOTICZ
|
|
||||||
#ifdef USE_KNX
|
|
||||||
if ((0 == tele_period) && (1 == dsxflg)) {
|
|
||||||
KnxSensor(KNX_TEMPERATURE, t);
|
|
||||||
}
|
|
||||||
#endif // USE_KNX
|
|
||||||
#ifdef USE_WEBSERVER
|
|
||||||
} else {
|
|
||||||
snprintf_P(stemp, sizeof(stemp), PSTR("%s%c%d"), ds18x20_types, IndexSeparator(), i +1);
|
|
||||||
WSContentSend_PD(HTTP_SNS_TEMP, stemp, temperature, TempUnit());
|
|
||||||
#endif // USE_WEBSERVER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (json) {
|
|
||||||
if (dsxflg) {
|
|
||||||
ResponseJsonEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ds18x20Search(); // Check for changes in sensors number
|
|
||||||
Ds18x20Convert(); // Start Conversion, takes up to one second
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* Interface
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
bool Xsns05(uint8_t function)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
if (pin[GPIO_DSB] < 99) {
|
|
||||||
switch (function) {
|
|
||||||
case FUNC_INIT:
|
|
||||||
Ds18x20Init();
|
|
||||||
break;
|
|
||||||
case FUNC_PREP_BEFORE_TELEPERIOD:
|
|
||||||
Ds18x20Search(); // Check for changes in sensors number
|
|
||||||
Ds18x20Convert(); // Start Conversion, takes up to one second
|
|
||||||
break;
|
|
||||||
case FUNC_JSON_APPEND:
|
|
||||||
Ds18x20Show(1);
|
|
||||||
break;
|
|
||||||
#ifdef USE_WEBSERVER
|
|
||||||
case FUNC_WEB_SENSOR:
|
|
||||||
Ds18x20Show(0);
|
|
||||||
break;
|
|
||||||
#endif // USE_WEBSERVER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // USE_DS18x20_LEGACY
|
|
|
@ -124,14 +124,11 @@ void Sgp30Show(bool json)
|
||||||
if (sgp30_ready) {
|
if (sgp30_ready) {
|
||||||
char abs_hum[33];
|
char abs_hum[33];
|
||||||
|
|
||||||
if (global_update && global_humidity>0 && global_temperature!=9999) {
|
|
||||||
// has humidity + temperature
|
|
||||||
dtostrfd(sgp30_abshum,4,abs_hum);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json) {
|
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) {
|
if (global_update && global_humidity>0 && global_temperature!=9999) {
|
||||||
|
// has humidity + temperature
|
||||||
|
dtostrfd(sgp30_abshum,4,abs_hum);
|
||||||
ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"),abs_hum);
|
ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"),abs_hum);
|
||||||
}
|
}
|
||||||
ResponseJsonEnd();
|
ResponseJsonEnd();
|
||||||
|
|
|
@ -32,48 +32,53 @@
|
||||||
* - Execute command Sensor34 2 and follow messages shown
|
* - Execute command Sensor34 2 and follow messages shown
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
#define XSNS_34 34
|
#define XSNS_34 34
|
||||||
|
|
||||||
#ifndef HX_MAX_WEIGHT
|
#ifndef HX_MAX_WEIGHT
|
||||||
#define HX_MAX_WEIGHT 20000 // Default max weight in gram
|
#define HX_MAX_WEIGHT 20000 // Default max weight in gram
|
||||||
#endif
|
#endif
|
||||||
#ifndef HX_REFERENCE
|
#ifndef HX_REFERENCE
|
||||||
#define HX_REFERENCE 250 // Default reference weight for calibration in gram
|
#define HX_REFERENCE 250 // Default reference weight for calibration in gram
|
||||||
#endif
|
#endif
|
||||||
#ifndef HX_SCALE
|
#ifndef HX_SCALE
|
||||||
#define HX_SCALE 120 // Default result of measured weight / reference weight when scale is 1
|
#define HX_SCALE 120 // Default result of measured weight / reference weight when scale is 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define HX_TIMEOUT 120 // A reading at default 10Hz (pin RATE to Gnd on HX711) can take up to 100 milliseconds
|
#define HX_TIMEOUT 120 // A reading at default 10Hz (pin RATE to Gnd on HX711) can take up to 100 milliseconds
|
||||||
#define HX_SAMPLES 10 // Number of samples for average calculation
|
#define HX_SAMPLES 10 // Number of samples for average calculation
|
||||||
#define HX_CAL_TIMEOUT 15 // Calibration step window in number of seconds
|
#define HX_CAL_TIMEOUT 15 // Calibration step window in number of seconds
|
||||||
|
|
||||||
#define HX_GAIN_128 1 // Channel A, gain factor 128
|
#define HX_GAIN_128 1 // Channel A, gain factor 128
|
||||||
#define HX_GAIN_32 2 // Channel B, gain factor 32
|
#define HX_GAIN_32 2 // Channel B, gain factor 32
|
||||||
#define HX_GAIN_64 3 // Channel A, gain factor 64
|
#define HX_GAIN_64 3 // Channel A, gain factor 64
|
||||||
|
|
||||||
#define D_JSON_WEIGHT_REF "WeightRef"
|
#define D_JSON_WEIGHT_REF "WeightRef"
|
||||||
#define D_JSON_WEIGHT_CAL "WeightCal"
|
#define D_JSON_WEIGHT_CAL "WeightCal"
|
||||||
#define D_JSON_WEIGHT_MAX "WeightMax"
|
#define D_JSON_WEIGHT_MAX "WeightMax"
|
||||||
#define D_JSON_WEIGHT_ITEM "WeightItem"
|
#define D_JSON_WEIGHT_ITEM "WeightItem"
|
||||||
|
#define D_JSON_WEIGHT_CHANGE "WeightChange"
|
||||||
|
|
||||||
enum HxCalibrationSteps { HX_CAL_END, HX_CAL_LIMBO, HX_CAL_FINISH, HX_CAL_FAIL, HX_CAL_DONE, HX_CAL_FIRST, HX_CAL_RESET, HX_CAL_START };
|
enum HxCalibrationSteps { HX_CAL_END, HX_CAL_LIMBO, HX_CAL_FINISH, HX_CAL_FAIL, HX_CAL_DONE, HX_CAL_FIRST, HX_CAL_RESET, HX_CAL_START };
|
||||||
|
|
||||||
const char kHxCalibrationStates[] PROGMEM = D_HX_CAL_FAIL "|" D_HX_CAL_DONE "|" D_HX_CAL_REFERENCE "|" D_HX_CAL_REMOVE;
|
const char kHxCalibrationStates[] PROGMEM = D_HX_CAL_FAIL "|" D_HX_CAL_DONE "|" D_HX_CAL_REFERENCE "|" D_HX_CAL_REMOVE;
|
||||||
|
|
||||||
long hx_weight = 0;
|
struct HX {
|
||||||
long hx_last_weight = 0;
|
long weight = 0;
|
||||||
long hx_sum_weight = 0;
|
long last_weight = 0;
|
||||||
long hx_offset = 0;
|
long sum_weight = 0;
|
||||||
long hx_scale = 1;
|
long offset = 0;
|
||||||
uint8_t hx_type = 1;
|
long scale = 1;
|
||||||
uint8_t hx_sample_count = 0;
|
long weight_diff = 0;
|
||||||
uint8_t hx_calibrate_step = HX_CAL_END;
|
uint8_t type = 1;
|
||||||
uint8_t hx_calibrate_timer = 0;
|
uint8_t sample_count = 0;
|
||||||
uint8_t hx_calibrate_msg = 0;
|
uint8_t calibrate_step = HX_CAL_END;
|
||||||
uint8_t hx_pin_sck;
|
uint8_t calibrate_timer = 0;
|
||||||
uint8_t hx_pin_dout;
|
uint8_t calibrate_msg = 0;
|
||||||
bool hx_tare_flg = false;
|
uint8_t pin_sck;
|
||||||
|
uint8_t pin_dout;
|
||||||
|
bool tare_flg = false;
|
||||||
|
bool weight_changed = false;
|
||||||
|
} Hx;
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
|
@ -81,8 +86,8 @@ bool HxIsReady(uint16_t timeout)
|
||||||
{
|
{
|
||||||
// A reading can take up to 100 mS or 600mS after power on
|
// A reading can take up to 100 mS or 600mS after power on
|
||||||
uint32_t start = millis();
|
uint32_t start = millis();
|
||||||
while ((digitalRead(hx_pin_dout) == HIGH) && (millis() - start < timeout)) { yield(); }
|
while ((digitalRead(Hx.pin_dout) == HIGH) && (millis() - start < timeout)) { yield(); }
|
||||||
return (digitalRead(hx_pin_dout) == LOW);
|
return (digitalRead(Hx.pin_dout) == LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
long HxRead()
|
long HxRead()
|
||||||
|
@ -93,14 +98,14 @@ long HxRead()
|
||||||
uint8_t filler = 0x00;
|
uint8_t filler = 0x00;
|
||||||
|
|
||||||
// pulse the clock pin 24 times to read the data
|
// pulse the clock pin 24 times to read the data
|
||||||
data[2] = shiftIn(hx_pin_dout, hx_pin_sck, MSBFIRST);
|
data[2] = shiftIn(Hx.pin_dout, Hx.pin_sck, MSBFIRST);
|
||||||
data[1] = shiftIn(hx_pin_dout, hx_pin_sck, MSBFIRST);
|
data[1] = shiftIn(Hx.pin_dout, Hx.pin_sck, MSBFIRST);
|
||||||
data[0] = shiftIn(hx_pin_dout, hx_pin_sck, MSBFIRST);
|
data[0] = shiftIn(Hx.pin_dout, Hx.pin_sck, MSBFIRST);
|
||||||
|
|
||||||
// set the channel and the gain factor for the next reading using the clock pin
|
// set the channel and the gain factor for the next reading using the clock pin
|
||||||
for (unsigned int i = 0; i < HX_GAIN_128; i++) {
|
for (unsigned int i = 0; i < HX_GAIN_128; i++) {
|
||||||
digitalWrite(hx_pin_sck, HIGH);
|
digitalWrite(Hx.pin_sck, HIGH);
|
||||||
digitalWrite(hx_pin_sck, LOW);
|
digitalWrite(Hx.pin_sck, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replicate the most significant bit to pad out a 32-bit signed integer
|
// Replicate the most significant bit to pad out a 32-bit signed integer
|
||||||
|
@ -119,10 +124,10 @@ long HxRead()
|
||||||
|
|
||||||
void HxResetPart(void)
|
void HxResetPart(void)
|
||||||
{
|
{
|
||||||
hx_tare_flg = true;
|
Hx.tare_flg = true;
|
||||||
hx_sum_weight = 0;
|
Hx.sum_weight = 0;
|
||||||
hx_sample_count = 0;
|
Hx.sample_count = 0;
|
||||||
hx_last_weight = 0;
|
Hx.last_weight = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HxReset(void)
|
void HxReset(void)
|
||||||
|
@ -135,8 +140,8 @@ void HxCalibrationStateTextJson(uint8_t msg_id)
|
||||||
{
|
{
|
||||||
char cal_text[30];
|
char cal_text[30];
|
||||||
|
|
||||||
hx_calibrate_msg = msg_id;
|
Hx.calibrate_msg = msg_id;
|
||||||
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, GetTextIndexed(cal_text, sizeof(cal_text), hx_calibrate_msg, kHxCalibrationStates));
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, GetTextIndexed(cal_text, sizeof(cal_text), Hx.calibrate_msg, kHxCalibrationStates));
|
||||||
|
|
||||||
if (msg_id < 3) { MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("Sensor34")); }
|
if (msg_id < 3) { MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("Sensor34")); }
|
||||||
}
|
}
|
||||||
|
@ -156,6 +161,8 @@ void HxCalibrationStateTextJson(uint8_t msg_id)
|
||||||
* Sensor34 6 - Show item weigth in decigram
|
* Sensor34 6 - Show item weigth in decigram
|
||||||
* Sensor34 6 <weight in decigram> - Set item weight
|
* Sensor34 6 <weight in decigram> - Set item weight
|
||||||
* Sensor34 7 - Save current weight to be used as start weight on restart
|
* Sensor34 7 - Save current weight to be used as start weight on restart
|
||||||
|
* Sensor34 8 0 - Disable JSON weight change message
|
||||||
|
* Sensor34 8 1 - Enable JSON weight change message
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
bool HxCommand(void)
|
bool HxCommand(void)
|
||||||
|
@ -177,10 +184,10 @@ bool HxCommand(void)
|
||||||
if (strstr(XdrvMailbox.data, ",") != nullptr) {
|
if (strstr(XdrvMailbox.data, ",") != nullptr) {
|
||||||
Settings.weight_reference = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
|
Settings.weight_reference = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
|
||||||
}
|
}
|
||||||
hx_scale = 1;
|
Hx.scale = 1;
|
||||||
HxReset();
|
HxReset();
|
||||||
hx_calibrate_step = HX_CAL_START;
|
Hx.calibrate_step = HX_CAL_START;
|
||||||
hx_calibrate_timer = 1;
|
Hx.calibrate_timer = 1;
|
||||||
HxCalibrationStateTextJson(3);
|
HxCalibrationStateTextJson(3);
|
||||||
break;
|
break;
|
||||||
case 3: // WeightRef to user reference
|
case 3: // WeightRef to user reference
|
||||||
|
@ -192,7 +199,7 @@ bool HxCommand(void)
|
||||||
case 4: // WeightCal to user calculated value
|
case 4: // WeightCal to user calculated value
|
||||||
if (strstr(XdrvMailbox.data, ",") != nullptr) {
|
if (strstr(XdrvMailbox.data, ",") != nullptr) {
|
||||||
Settings.weight_calibration = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
|
Settings.weight_calibration = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
|
||||||
hx_scale = Settings.weight_calibration;
|
Hx.scale = Settings.weight_calibration;
|
||||||
}
|
}
|
||||||
show_parms = true;
|
show_parms = true;
|
||||||
break;
|
break;
|
||||||
|
@ -209,18 +216,24 @@ bool HxCommand(void)
|
||||||
show_parms = true;
|
show_parms = true;
|
||||||
break;
|
break;
|
||||||
case 7: // WeightSave
|
case 7: // WeightSave
|
||||||
Settings.energy_frequency_calibration = hx_weight;
|
Settings.energy_frequency_calibration = Hx.weight;
|
||||||
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, D_JSON_DONE);
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, D_JSON_DONE);
|
||||||
break;
|
break;
|
||||||
|
case 8: // Json on weight change
|
||||||
|
if (strstr(XdrvMailbox.data, ",") != nullptr) {
|
||||||
|
Settings.SensorBits1.hx711_json_weight_change = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10) & 1;
|
||||||
|
}
|
||||||
|
show_parms = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
serviced = false;
|
show_parms = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_parms) {
|
if (show_parms) {
|
||||||
char item[33];
|
char item[33];
|
||||||
dtostrfd((float)Settings.weight_item / 10, 1, item);
|
dtostrfd((float)Settings.weight_item / 10, 1, item);
|
||||||
Response_P(PSTR("{\"Sensor34\":{\"" D_JSON_WEIGHT_REF "\":%d,\"" D_JSON_WEIGHT_CAL "\":%d,\"" D_JSON_WEIGHT_MAX "\":%d,\"" D_JSON_WEIGHT_ITEM "\":%s}}"),
|
Response_P(PSTR("{\"Sensor34\":{\"" D_JSON_WEIGHT_REF "\":%d,\"" D_JSON_WEIGHT_CAL "\":%d,\"" D_JSON_WEIGHT_MAX "\":%d,\"" D_JSON_WEIGHT_ITEM "\":%s,\"" D_JSON_WEIGHT_CHANGE "\":\"%s\"}}"),
|
||||||
Settings.weight_reference, Settings.weight_calibration, Settings.weight_max * 1000, item);
|
Settings.weight_reference, Settings.weight_calibration, Settings.weight_max * 1000, item, GetStateText(Settings.SensorBits1.hx711_json_weight_change));
|
||||||
}
|
}
|
||||||
|
|
||||||
return serviced;
|
return serviced;
|
||||||
|
@ -230,123 +243,138 @@ bool HxCommand(void)
|
||||||
|
|
||||||
long HxWeight()
|
long HxWeight()
|
||||||
{
|
{
|
||||||
return (hx_calibrate_step < HX_CAL_FAIL) ? hx_weight : 0;
|
return (Hx.calibrate_step < HX_CAL_FAIL) ? Hx.weight : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HxInit(void)
|
void HxInit(void)
|
||||||
{
|
{
|
||||||
hx_type = 0;
|
Hx.type = 0;
|
||||||
if ((pin[GPIO_HX711_DAT] < 99) && (pin[GPIO_HX711_SCK] < 99)) {
|
if ((pin[GPIO_HX711_DAT] < 99) && (pin[GPIO_HX711_SCK] < 99)) {
|
||||||
hx_pin_sck = pin[GPIO_HX711_SCK];
|
Hx.pin_sck = pin[GPIO_HX711_SCK];
|
||||||
hx_pin_dout = pin[GPIO_HX711_DAT];
|
Hx.pin_dout = pin[GPIO_HX711_DAT];
|
||||||
|
|
||||||
pinMode(hx_pin_sck, OUTPUT);
|
pinMode(Hx.pin_sck, OUTPUT);
|
||||||
pinMode(hx_pin_dout, INPUT);
|
pinMode(Hx.pin_dout, INPUT);
|
||||||
|
|
||||||
digitalWrite(hx_pin_sck, LOW);
|
digitalWrite(Hx.pin_sck, LOW);
|
||||||
|
|
||||||
if (HxIsReady(8 * HX_TIMEOUT)) { // Can take 600 milliseconds after power on
|
if (HxIsReady(8 * HX_TIMEOUT)) { // Can take 600 milliseconds after power on
|
||||||
if (!Settings.weight_max) { Settings.weight_max = HX_MAX_WEIGHT / 1000; }
|
if (!Settings.weight_max) { Settings.weight_max = HX_MAX_WEIGHT / 1000; }
|
||||||
if (!Settings.weight_calibration) { Settings.weight_calibration = HX_SCALE; }
|
if (!Settings.weight_calibration) { Settings.weight_calibration = HX_SCALE; }
|
||||||
if (!Settings.weight_reference) { Settings.weight_reference = HX_REFERENCE; }
|
if (!Settings.weight_reference) { Settings.weight_reference = HX_REFERENCE; }
|
||||||
hx_scale = Settings.weight_calibration;
|
Hx.scale = Settings.weight_calibration;
|
||||||
HxRead();
|
HxRead();
|
||||||
HxResetPart();
|
HxResetPart();
|
||||||
hx_type = 1;
|
Hx.type = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HxEvery100mSecond(void)
|
void HxEvery100mSecond(void)
|
||||||
{
|
{
|
||||||
hx_sum_weight += HxRead();
|
Hx.sum_weight += HxRead();
|
||||||
|
|
||||||
hx_sample_count++;
|
Hx.sample_count++;
|
||||||
if (HX_SAMPLES == hx_sample_count) {
|
if (HX_SAMPLES == Hx.sample_count) {
|
||||||
long average = hx_sum_weight / hx_sample_count; // grams
|
long average = Hx.sum_weight / Hx.sample_count; // grams
|
||||||
long value = average - hx_offset; // grams
|
long value = average - Hx.offset; // grams
|
||||||
hx_weight = value / hx_scale; // grams
|
Hx.weight = value / Hx.scale; // grams
|
||||||
if (hx_weight < 0) {
|
if (Hx.weight < 0) {
|
||||||
if (Settings.energy_frequency_calibration) {
|
if (Settings.energy_frequency_calibration) {
|
||||||
long difference = Settings.energy_frequency_calibration + hx_weight;
|
long difference = Settings.energy_frequency_calibration + Hx.weight;
|
||||||
hx_last_weight = difference;
|
Hx.last_weight = difference;
|
||||||
if (difference < 0) { HxReset(); } // Cancel last weight as there seems to be no more weight on the scale
|
if (difference < 0) { HxReset(); } // Cancel last weight as there seems to be no more weight on the scale
|
||||||
}
|
}
|
||||||
hx_weight = 0;
|
Hx.weight = 0;
|
||||||
} else {
|
} else {
|
||||||
hx_last_weight = Settings.energy_frequency_calibration;
|
Hx.last_weight = Settings.energy_frequency_calibration;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hx_tare_flg) {
|
if (Hx.tare_flg) {
|
||||||
hx_tare_flg = false;
|
Hx.tare_flg = false;
|
||||||
hx_offset = average; // grams
|
Hx.offset = average; // grams
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hx_calibrate_step) {
|
if (Hx.calibrate_step) {
|
||||||
hx_calibrate_timer--;
|
Hx.calibrate_timer--;
|
||||||
|
|
||||||
if (HX_CAL_START == hx_calibrate_step) { // Skip reset just initiated
|
if (HX_CAL_START == Hx.calibrate_step) { // Skip reset just initiated
|
||||||
hx_calibrate_step--;
|
Hx.calibrate_step--;
|
||||||
hx_calibrate_timer = HX_CAL_TIMEOUT * (10 / HX_SAMPLES);
|
Hx.calibrate_timer = HX_CAL_TIMEOUT * (10 / HX_SAMPLES);
|
||||||
}
|
}
|
||||||
else if (HX_CAL_RESET == hx_calibrate_step) { // Wait for stable reset
|
else if (HX_CAL_RESET == Hx.calibrate_step) { // Wait for stable reset
|
||||||
if (hx_calibrate_timer) {
|
if (Hx.calibrate_timer) {
|
||||||
if (hx_weight < (long)Settings.weight_reference) {
|
if (Hx.weight < (long)Settings.weight_reference) {
|
||||||
hx_calibrate_step--;
|
Hx.calibrate_step--;
|
||||||
hx_calibrate_timer = HX_CAL_TIMEOUT * (10 / HX_SAMPLES);
|
Hx.calibrate_timer = HX_CAL_TIMEOUT * (10 / HX_SAMPLES);
|
||||||
HxCalibrationStateTextJson(2);
|
HxCalibrationStateTextJson(2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hx_calibrate_step = HX_CAL_FAIL;
|
Hx.calibrate_step = HX_CAL_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (HX_CAL_FIRST == hx_calibrate_step) { // Wait for first reference weight
|
else if (HX_CAL_FIRST == Hx.calibrate_step) { // Wait for first reference weight
|
||||||
if (hx_calibrate_timer) {
|
if (Hx.calibrate_timer) {
|
||||||
if (hx_weight > (long)Settings.weight_reference) {
|
if (Hx.weight > (long)Settings.weight_reference) {
|
||||||
hx_calibrate_step--;
|
Hx.calibrate_step--;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hx_calibrate_step = HX_CAL_FAIL;
|
Hx.calibrate_step = HX_CAL_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (HX_CAL_DONE == hx_calibrate_step) { // Second stable reference weight
|
else if (HX_CAL_DONE == Hx.calibrate_step) { // Second stable reference weight
|
||||||
if (hx_weight > (long)Settings.weight_reference) {
|
if (Hx.weight > (long)Settings.weight_reference) {
|
||||||
hx_calibrate_step = HX_CAL_FINISH; // Calibration done
|
Hx.calibrate_step = HX_CAL_FINISH; // Calibration done
|
||||||
Settings.weight_calibration = hx_weight / Settings.weight_reference;
|
Settings.weight_calibration = Hx.weight / Settings.weight_reference;
|
||||||
hx_weight = 0; // Reset calibration value
|
Hx.weight = 0; // Reset calibration value
|
||||||
HxCalibrationStateTextJson(1);
|
HxCalibrationStateTextJson(1);
|
||||||
} else {
|
} else {
|
||||||
hx_calibrate_step = HX_CAL_FAIL;
|
Hx.calibrate_step = HX_CAL_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HX_CAL_FAIL == hx_calibrate_step) { // Calibration failed
|
if (HX_CAL_FAIL == Hx.calibrate_step) { // Calibration failed
|
||||||
hx_calibrate_step--;
|
Hx.calibrate_step--;
|
||||||
hx_tare_flg = true; // Perform a reset using old scale
|
Hx.tare_flg = true; // Perform a reset using old scale
|
||||||
HxCalibrationStateTextJson(0);
|
HxCalibrationStateTextJson(0);
|
||||||
}
|
}
|
||||||
if (HX_CAL_FINISH == hx_calibrate_step) { // Calibration finished
|
if (HX_CAL_FINISH == Hx.calibrate_step) { // Calibration finished
|
||||||
hx_calibrate_step--;
|
Hx.calibrate_step--;
|
||||||
hx_calibrate_timer = 3 * (10 / HX_SAMPLES);
|
Hx.calibrate_timer = 3 * (10 / HX_SAMPLES);
|
||||||
hx_scale = Settings.weight_calibration;
|
Hx.scale = Settings.weight_calibration;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hx_calibrate_timer) {
|
if (!Hx.calibrate_timer) {
|
||||||
hx_calibrate_step = HX_CAL_END; // End of calibration
|
Hx.calibrate_step = HX_CAL_END; // End of calibration
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hx_weight += hx_last_weight; // grams
|
Hx.weight += Hx.last_weight; // grams
|
||||||
|
|
||||||
|
if (Settings.SensorBits1.hx711_json_weight_change) {
|
||||||
|
if (abs(Hx.weight - Hx.weight_diff) > 4) { // Use 4 gram threshold to decrease "ghost" weights
|
||||||
|
Hx.weight_diff = Hx.weight;
|
||||||
|
Hx.weight_changed = true;
|
||||||
|
}
|
||||||
|
else if (Hx.weight_changed && (Hx.weight == Hx.weight_diff)) {
|
||||||
|
mqtt_data[0] = '\0';
|
||||||
|
ResponseAppendTime();
|
||||||
|
HxShow(true);
|
||||||
|
ResponseJsonEnd();
|
||||||
|
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
|
||||||
|
Hx.weight_changed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hx_sum_weight = 0;
|
Hx.sum_weight = 0;
|
||||||
hx_sample_count = 0;
|
Hx.sample_count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HxSaveBeforeRestart()
|
void HxSaveBeforeRestart()
|
||||||
{
|
{
|
||||||
Settings.energy_frequency_calibration = hx_weight;
|
Settings.energy_frequency_calibration = Hx.weight;
|
||||||
hx_sample_count = HX_SAMPLES +1; // Stop updating hx_weight
|
Hx.sample_count = HX_SAMPLES +1; // Stop updating Hx.weight
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
|
@ -364,14 +392,14 @@ void HxShow(bool json)
|
||||||
|
|
||||||
uint16_t count = 0;
|
uint16_t count = 0;
|
||||||
float weight = 0;
|
float weight = 0;
|
||||||
if (hx_calibrate_step < HX_CAL_FAIL) {
|
if (Hx.calibrate_step < HX_CAL_FAIL) {
|
||||||
if (hx_weight && Settings.weight_item) {
|
if (Hx.weight && Settings.weight_item) {
|
||||||
count = (hx_weight * 10) / Settings.weight_item;
|
count = (Hx.weight * 10) / Settings.weight_item;
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
snprintf_P(scount, sizeof(scount), PSTR(",\"" D_JSON_COUNT "\":%d"), count);
|
snprintf_P(scount, sizeof(scount), PSTR(",\"" D_JSON_COUNT "\":%d"), count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
weight = (float)hx_weight / 1000; // kilograms
|
weight = (float)Hx.weight / 1000; // kilograms
|
||||||
}
|
}
|
||||||
char weight_chr[33];
|
char weight_chr[33];
|
||||||
dtostrfd(weight, Settings.flag2.weight_resolution, weight_chr);
|
dtostrfd(weight, Settings.flag2.weight_resolution, weight_chr);
|
||||||
|
@ -384,9 +412,9 @@ void HxShow(bool json)
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
WSContentSend_PD(HTTP_HX711_COUNT, count);
|
WSContentSend_PD(HTTP_HX711_COUNT, count);
|
||||||
}
|
}
|
||||||
if (hx_calibrate_step) {
|
if (Hx.calibrate_step) {
|
||||||
char cal_text[30];
|
char cal_text[30];
|
||||||
WSContentSend_PD(HTTP_HX711_CAL, GetTextIndexed(cal_text, sizeof(cal_text), hx_calibrate_msg, kHxCalibrationStates));
|
WSContentSend_PD(HTTP_HX711_CAL, GetTextIndexed(cal_text, sizeof(cal_text), Hx.calibrate_msg, kHxCalibrationStates));
|
||||||
}
|
}
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
}
|
}
|
||||||
|
@ -497,11 +525,8 @@ bool Xsns34(uint8_t function)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if (hx_type) {
|
if (Hx.type) {
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case FUNC_INIT:
|
|
||||||
HxInit();
|
|
||||||
break;
|
|
||||||
case FUNC_EVERY_100_MSECOND:
|
case FUNC_EVERY_100_MSECOND:
|
||||||
HxEvery100mSecond();
|
HxEvery100mSecond();
|
||||||
break;
|
break;
|
||||||
|
@ -532,6 +557,9 @@ bool Xsns34(uint8_t function)
|
||||||
break;
|
break;
|
||||||
#endif // USE_HX711_GUI
|
#endif // USE_HX711_GUI
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
|
case FUNC_INIT:
|
||||||
|
HxInit();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Reference in New Issue