Merge branch 'development' of https://github.com/arendst/Sonoff-Tasmota into development

This commit is contained in:
localhost61 2019-04-12 09:40:34 +02:00
commit 1e3b024edc
120 changed files with 2598 additions and 1399 deletions

View File

@ -3,8 +3,9 @@
**Related issue (if applicable):** fixes #<Sonoff-Tasmota issue number goes here>
## Checklist:
- [ ] The pull request is done against the dev branch
- [ ] Only relevant files were touched (Also beware if your editor has auto-formatting feature enabled)
- [ ] The pull request is done against the latest dev branch
- [ ] Only relevant files were touched (Also remember to update _changelog.ino_ file)
- [ ] Only one feature/fix was added per PR.
- [ ] The code change is tested and works.
- [ ] 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).

View File

@ -56,7 +56,57 @@ The process is straight-forward.
7. All pull requests should consider updates to the documentation.
8. Pull requests that address an outstanding issue, particularly an issue deemed to be severe, should be given priority.
9. If a PR is accepted, then it should undergo review and updated based on the feedback provided, then merged.
10. Pull requests that don't meet the above will be denied and closed.
10. By submitting a PR, it is needed to use the provided PR template and check all boxes, performing the required tasks and accepting the CLA.
11. Pull requests that don't meet the above will be denied and closed.
--------------------------------------
## Contributor License Agreement (CLA)
```
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the GPL-3.0 license; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the GPL-3.0 license; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it) is maintained indefinitely
and may be redistributed consistent with this project or the open
source license(s) involved.
```
This Contributor License Agreement (CLA) was adopted on April 1st, 2019.
The text of this license is available under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/). It is based on the Linux [Developer Certificate Of Origin](http://elinux.org/Developer_Certificate_Of_Origin), but is modified to explicitly use the GPL-3.0 license and not mention sign-off (due to GitHub.com keeps an historial, with your user name, of PRs' commits and all editions on PR's comments).
To accept the CLA it is required to put a x between [ ] on `[ ] I accept the CLA` in the PR template when submitting it. The [ ] is an opt-in box, so you have to manually accept it.
**Why a CLA ?**
_"A Contributor Licence Agreement (CLA) is strongly recommended when accepting third party contributions to an open development project, such as an open source software project. In order to redistribute contributions, it is necessary to ensure that the project has the necessary rights to do so. A Contributor Licence Agreement is a lightweight agreement, signed by the copyright holder, that grants the necessary rights for the contribution to be redistributed as part of the project."_ [OSS Watch](http://oss-watch.ac.uk/resources/cla)
A CLA is a legal document in which you state _you are entitled to contribute the code/documentation/translation to the project_ youre contributing to and that _you are willing to have it used in distributions and derivative works_. This means that should there be any kind of legal issue in the future as to the origins and ownership of any particular piece of code, then that project has the necessary forms on file from the contributor(s) saying they were permitted to make this contribution.
CLA is a safety because it also ensures that once you have provided a contribution, you cannot try to withdraw permission for its use at a later date. People can therefore use that software, confident that they will not be asked to stop using pieces of the code at a later date.
A __license__ grants "outbound" rights to the user of project.
A __CLA__ enables a contributor to grant "inbound" rights to a project.
<Other>
<A table should be maintained for relating maintainers and components. When triaging, this is essential to figure out if someone in particular should be consulted about specific changes.>

View File

@ -1,6 +1,6 @@
## Sonoff-Tasmota
Alternative firmware for _ESP8266 based devices_ like [iTead](https://www.itead.cc/) _**Sonoff**_ with **web UI, rules and timers, OTA updates, custome device templates and sensors support**. Allows control over **MQTT**, **HTTP**, **Serial** and **KNX** for integrations with smart home systems. Written for Arduino IDE and PlatformIO.
Alternative firmware for _ESP8266 based devices_ like [iTead](https://www.itead.cc/) _**Sonoff**_ with **web UI, rules and timers, OTA updates, custom device templates and sensor support**. Allows control over **MQTT**, **HTTP**, **Serial** and **KNX** for integrations with smart home systems. Written for Arduino IDE and PlatformIO.
[![GitHub version](https://img.shields.io/github/release/arendst/Sonoff-Tasmota.svg)](https://github.com/arendst/Sonoff-Tasmota/releases/latest)
[![GitHub download](https://img.shields.io/github/downloads/arendst/Sonoff-Tasmota/total.svg)](https://github.com/arendst/Sonoff-Tasmota/releases/latest)
@ -15,7 +15,7 @@ If you like **Sonoff-Tasmota**, give it a star, or fork it and contribute!
See [RELEASENOTES.md](https://github.com/arendst/Sonoff-Tasmota/blob/development/RELEASENOTES.md) for release information.
In addition to the [release webpage](https://github.com/arendst/Sonoff-Tasmota/releases/latest) the binaries can also be OTA downloaded from http://thehackbox.org/tasmota/release/
In addition to the [release webpage](https://github.com/arendst/Sonoff-Tasmota/releases/latest), the binaries can also be OTA downloaded from http://thehackbox.org/tasmota/release/
### Development
[![Dev Version](https://img.shields.io/badge/development%20version-6.5.0.x-blue.svg)](https://github.com/arendst/Sonoff-Tasmota)
@ -29,12 +29,12 @@ The development codebase is checked hourly for changes and if new commits have b
### Disclaimer
:warning: **DANGER OF ELECTROCUTION** :warning:
A Sonoff device is not a toy. It uses Mains AC so there is a danger of electrocution if not installed properly. If you don't know how to install it, please call an electrician. Remember: _**SAFETY FIRST**_. It is not worth to risk yourself, your family and your home if you don't know exactly what you are doing. Never try to flash a Sonoff device while it is connected to MAINS AC.
A Sonoff device is not a toy. It uses Mains AC so there is a danger of electrocution if not installed properly. If you don't know how to install it, please call an electrician. Remember: _**SAFETY FIRST**_. It is not worth risk to yourself, your family, and your home if you don't know exactly what you are doing. Never try to flash a Sonoff device while it is connected to MAINS AC.
We don't take any responsibility nor liability for using this software nor for the installation or any tips, advice, videos, etc. given by any member of this site or any related site.
### Note
Please do not ask to add devices where you can't provide a basic working configuration (other than sonoff). Since there are thousands of them..
Please do not ask to add devices where you can't provide a basic working configuration (other than sonoff). Since there are thousands of them.
### Quick Install
Download one of the released binaries from https://github.com/arendst/Sonoff-Tasmota/releases and flash it to your hardware as documented in the wiki.

View File

@ -71,14 +71,14 @@ Module | Description
49 Neo Coolcam | Neo Coolcam Wifi Smart Socket
50 ESP Switch | ESP Switch 4-gang Wifi Switch with Leds
51 OBI Socket | OBI Wifi Smart Socket
52 Teckin | Teckin SP20 Wifi Smart Switch with Energy Monitoring
52 Teckin | Teckin SP22 Wifi Smart Switch with Energy Monitoring
53 AplicWDP303075 | Aplic WDP 303075 CSL Wifi Smart Switch with Energy Monitoring
54 Tuya Dimmer | MIUO (and other Tuya based) Wifi Dimmer for Incandescent Lights and Led
55 Gosund SP1 v23 | Gosund SP1 v2.3 Wifi Smart Switch with Energy Monitoring
56 ARMTR Dimmer | ARMtronix Wifi dimmer for Incandescent Lights and Led
57 SK03 Outdoor | SK03 Outdoor Wifi Smart Switch with Energy Monitoring
58 PS-16-DZ | PS-16-DZ Wifi dimmer for Incandescent Lights and Led
59 Teckin US | Teckin US and ZooZee SA102 Wifi Smart Switch with Energy Monitoring
59 Teckin US | Teckin SP20 and ZooZee SA102 Wifi Smart Switch with Energy Monitoring
60 Manzoku strip | Manzoku Wifi Smart Power Strip with four Relays
61 OBI Socket 2 | OBI 2 Wifi Smart Socket
62 YTF IR Bridge | YTF Infra Red Wifi Bridge
@ -194,6 +194,7 @@ Core version **2.4.2** binaries can be found at http://thehackbox.org/tasmota/re
| USE_RC_SWITCH | - | - | - | x | x | x | x |
| USE_RF_SENSOR | - | - | - | - | - | x | - | AlectoV2 only
| USE_SM16716 | - | x | x | x | x | x | x |
| USE_HRE | - | - | - | - | - | x | - |
| USE_DISPLAY | - | - | - | - | - | - | x |
| USE_DISPLAY_LCD | - | - | - | - | - | - | x |
| USE_DISPLAY_SSD1306 | - | - | - | - | - | - | x |

1
include/dummy.txt Normal file
View File

@ -0,0 +1 @@

View File

@ -67,9 +67,11 @@ build_flags = ${esp82xx_defaults.build_flags}
[core_2_5_0]
; *** Esp8266 core for Arduino version 2.5.0
platform = espressif8266@2.0.1
platform = espressif8266@~2.0.4
build_flags = ${esp82xx_defaults.build_flags}
-Wl,-Teagle.flash.1m.ld
; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473
-O2
; lwIP 1.4 (Default)
; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
; lwIP 2 - Low Memory
@ -89,6 +91,8 @@ build_flags = ${esp82xx_defaults.build_flags}
platform = https://github.com/platformio/platform-espressif8266.git#feature/stage
build_flags = ${esp82xx_defaults.build_flags}
-Wl,-Teagle.flash.1m.ld
; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473
-O2
; nonos-sdk 22x
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x
; nonos-sdk-pre-v3
@ -343,7 +347,7 @@ board = ${common.board}
board_build.flash_mode = ${common.board_build.flash_mode}
board_build.f_cpu = ${common.board_build.f_cpu}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} -DMY_LANGUAGE=es-AR
build_flags = ${common.build_flags} -DMY_LANGUAGE=es-ES
monitor_speed = ${common.monitor_speed}
upload_port = ${common.upload_port}
upload_resetmethod = ${common.upload_resetmethod}

View File

@ -415,7 +415,7 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t
DEBUG_OUTPUT.println(argFilename);
#endif
//use GET to set the filename if uploading using blob
if (argFilename == F("blob") && hasArg(FPSTR(filename)))
if (argFilename == F("blob") && hasArg(FPSTR(filename)))
argFilename = arg(FPSTR(filename));
}
#ifdef DEBUG_ESP_HTTP_SERVER
@ -510,7 +510,7 @@ readfile:
uint8_t endBuf[boundary.length()];
client.readBytes(endBuf, boundary.length());
if (strstr((const char*)endBuf, boundary.c_str()) != NULL){
if (strstr((const char*)endBuf, boundary.c_str()) != nullptr){
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->totalSize += _currentUpload->currentSize;
@ -571,7 +571,7 @@ readfile:
arg.value = postArgs[iarg].value;
}
_currentArgCount = iarg;
if (postArgs)
if (postArgs)
delete[] postArgs;
return true;
}

View File

@ -1,4 +1,37 @@
/* 6.5.0.1 20190319
/* 6.5.0.7 20190410
* Add command LedMask to assign which relay has access to power LED (#5602, #5612)
*
* 6.5.0.6 20190409
* Add WebColor parameters to Settings making them persistent and remove the need for using a rule
* Add alternative IRSend command syntax IRSend raw,<freq>,<header mark>,<header space>,<bit mark>,<zero space>,<one space>,<bit stream> (#5610)
*
* 6.5.0.5 20190406
* Add compile time GUI hexadecimal only color options in my_user_config.h (#5586)
* Fix template activation and/or module selection regression from 6.5.0.4 (#5598)
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#009800","#222"]} endon
to make color changes persistent)
*
* 6.5.0.4 20190402
* Fix Configure Timer Web GUI (#5568)
* Add validation check when loading settings from flash
* Fixed Display Bug in KNX webmenu for Physical Address
*
* 6.5.0.3 20190328
* Add command Sensor20 1..255 to change Nova Fitness SDS01 working period in minutes (#5452)
* Change some defines to const
* Change IRsend and receive for 64-bit support (#5523)
* Change IRSend Panasonic protocol to 64-bit (#5523)
*
* 6.5.0.2 20190325
* Change UDP initial message handling from string to char using static memory and add debug info (#5505)
* Add optional support for Badger HR-E Water Meter (#5539)
*
* 6.5.0.1 20190319
* Change Web GUI sensor data collection
*
* 6.5.0 20190319
@ -17,7 +50,7 @@
* Change image name BE_MINIMAL to FIRMWARE_MINIMAL and USE_xyz to FIRMWARE_xyz (#5106)
* Change GUI weblog from XML to plain text solving possible empty screens (#5154)
* Fix most compiler warnings
* Fix Display exception 28 when JSON value is NULL received
* Fix Display exception 28 when JSON value is nullptr received
* Fix epaper driver (#4785)
* Fix HAss Sensor Discovery Software Watchdog restart (#4831, #4988)
* Fix allowable MAX_RULE_VARS to 16 (#4933)

View File

@ -69,6 +69,7 @@
#define D_JSON_FLASHCHIPID "FlashChipId"
#define D_JSON_FLASHMODE "FlashMode"
#define D_JSON_FLASHSIZE "FlashSize"
#define D_JSON_FLOWRATE "FlowRate"
#define D_JSON_FREEMEMORY "Free"
#define D_JSON_FREQUENCY "Frequency"
#define D_JSON_FROM "from"
@ -143,6 +144,7 @@
#define D_JSON_TIME "Time"
#define D_JSON_TODAY "Today"
#define D_JSON_TOTAL "Total"
#define D_JSON_TOTAL_USAGE "TotalUsage"
#define D_JSON_TOTAL_REACTIVE "TotalReactivePower"
#define D_JSON_TOTAL_START_TIME "TotalStartTime"
#define D_JSON_TVOC "TVOC"
@ -264,6 +266,7 @@
#define D_CMND_ALTITUDE "Altitude"
#define D_CMND_LEDPOWER "LedPower"
#define D_CMND_LEDSTATE "LedState"
#define D_CMND_LEDMASK "LedMask"
#define D_CMND_I2CSCAN "I2CScan"
#define D_CMND_SERIALSEND "SerialSend"
#define D_CMND_SERIALDELIMITER "SerialDelimiter"
@ -309,6 +312,7 @@
#define D_CMND_WEBLOG "WebLog"
#define D_CMND_WEBREFRESH "WebRefresh"
#define D_CMND_WEBSEND "WebSend"
#define D_CMND_WEBCOLOR "WebColor"
#define D_CMND_EMULATION "Emulation"
// Commands xdrv_03_energy.ino
@ -495,7 +499,6 @@ const char S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE[] PROGMEM = "{\"%s\":\"%d (" D
const char S_JSON_COMMAND_NVALUE[] PROGMEM = "{\"%s\":%d}";
const char S_JSON_COMMAND_LVALUE[] PROGMEM = "{\"%s\":%lu}";
const char S_JSON_COMMAND_SVALUE[] PROGMEM = "{\"%s\":\"%s\"}";
const char S_JSON_COMMAND_HVALUE[] PROGMEM = "{\"%s\":\"#%X\"}";
const char S_JSON_COMMAND_ASTERIX[] PROGMEM = "{\"%s\":\"" D_ASTERIX "\"}";
const char S_JSON_COMMAND_XVALUE[] PROGMEM = "{\"%s\":%s}"; // %s must provide quotes on non-number
@ -506,14 +509,16 @@ const char S_JSON_COMMAND_INDEX_ASTERIX[] PROGMEM = "{\"%s%d\":\"" D_A
const char S_JSON_COMMAND_INDEX_SVALUE_SVALUE[] PROGMEM = "{\"%s%d\":\"%s%s\"}";
const char S_JSON_COMMAND_INDEX_NVALUE_ACTIVE_NVALUE[] PROGMEM = "{\"%s%d\":\"%d (" D_JSON_ACTIVE " %d)\"}";
const char S_JSON_SENSOR_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":%d}";
const char S_JSON_SENSOR_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":\"%s\"}";
const char S_JSON_SENSOR_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":%d}";
const char S_JSON_SENSOR_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":\"%s\"}";
const char S_JSON_DRIVER_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":%d}";
const char S_JSON_DRIVER_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":\"%s\"}";
const char S_JSON_DRIVER_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":%d}";
const char S_JSON_DRIVER_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":\"%s\"}";
const char JSON_SNS_TEMP[] PROGMEM = "%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}";
const char JSON_SNS_TEMPHUM[] PROGMEM = "%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s}";
const char JSON_SNS_TEMP[] PROGMEM = ",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}";
const char JSON_SNS_TEMPHUM[] PROGMEM = ",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s}";
const char JSON_SNS_GNGPM[] PROGMEM = ",\"%s\":{\"" D_JSON_TOTAL_USAGE "\":%s,\"" D_JSON_FLOWRATE "\":%s}";
const char S_LOG_I2C_FOUND_AT[] PROGMEM = D_LOG_I2C "%s " D_FOUND_AT " 0x%x";
@ -561,20 +566,16 @@ const char kOptionBlinkOff[] PROGMEM = "BLINKOFF|" D_BLINKOFF ;
// xdrv_02_webserver.ino
#ifdef USE_WEBSERVER
const char HTTP_SNS_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%s&deg;%c{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_HUM[] PROGMEM = "{s}%s " D_HUMIDITY "{m}%s%%{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_PRESSURE[] PROGMEM = "{s}%s " D_PRESSURE "{m}%s %s{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "{s}%s " D_PRESSUREATSEALEVEL "{m}%s %s{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_ANALOG[] PROGMEM = "{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_ILLUMINANCE[] PROGMEM = "{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#if defined(USE_MHZ19) || defined(USE_SENSEAIR) || defined(USE_AZ7798) || defined(USE_SCD30)
const char HTTP_SNS_CO2[] PROGMEM = "{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_MHZ19
#if defined(USE_SCD30)
const char HTTP_SNS_CO2EAVG[] PROGMEM = "{s}%s " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_SCD30
const char HTTP_SNS_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%s&deg;%c{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_HUM[] PROGMEM = "{s}%s " D_HUMIDITY "{m}%s%%{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_PRESSURE[] PROGMEM = "{s}%s " D_PRESSURE "{m}%s %s{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "{s}%s " D_PRESSUREATSEALEVEL "{m}%s %s{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_ANALOG[] PROGMEM = "{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_ILLUMINANCE[] PROGMEM = "{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_CO2[] PROGMEM = "{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_CO2EAVG[] PROGMEM = "{s}%s " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_GALLONS[] PROGMEM = "{s}%s " D_TOTAL_USAGE "{m}%s " D_UNIT_GALLONS " {e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char HTTP_SNS_GPM[] PROGMEM = "{s}%s " D_FLOW_RATE "{m}%s " D_UNIT_GALLONS_PER_MIN" {e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
const char S_MAIN_MENU[] PROGMEM = D_MAIN_MENU;
const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION;

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Помощен топик"
#define D_FALSE "Невярно"
#define D_FILE "Файл"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Свободна памет"
#define D_FREQUENCY "Честота"
#define D_GAS "Газ"
@ -156,6 +157,7 @@
#define D_TO "към"
#define D_TOGGLE "Превключване"
#define D_TOPIC "Топик"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Предаване"
#define D_TRUE "Вярно"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Базиран на"
#define D_TEMPLATE_FLAGS "Флагове"
#define D_ALLOW_ADC0 "ADC0 вход"
#define D_ALLOW_ADC0_TEMP "ADC0 температура"
#define D_ALLOW_PULLUP "Потребителски избор на pull-up"
#define D_SAVE_CONFIGURATION "Запазване на конфигурацията"
@ -492,6 +495,10 @@
#define D_TX20_SOUTH "Ю"
#define D_TX20_WEST "З"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Няма"
#define D_SENSOR_USER "Потребит."
@ -576,12 +583,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "h"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOMETER_PER_HOUR "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Záložní topic"
#define D_FALSE "Nepravda"
#define D_FILE "Soubor"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Volná paměť"
#define D_FREQUENCY "Kmitočet"
#define D_GAS "Plyn"
@ -156,6 +157,7 @@
#define D_TO "do"
#define D_TOGGLE "Přepni"
#define D_TOPIC "Topic"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Odešli"
#define D_TRUE "Pravda"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Ulož nastavení"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "J"
#define D_TX20_WEST "Z"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Není"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "hod"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Fallback-Topic"
#define D_FALSE "falsch"
#define D_FILE "Datei"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Freier Arbeitsspeicher"
#define D_FREQUENCY "Frequenz"
#define D_GAS "Gas"
@ -156,6 +157,7 @@
#define D_TO "zu"
#define D_TOGGLE "An/Aus"
#define D_TOPIC "topic"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Übertragen"
#define D_TRUE "wahr"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "basiert auf"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 Temperatur"
#define D_ALLOW_PULLUP "Nutzer pull-up Auswahl"
#define D_SAVE_CONFIGURATION "Konfiguration speichern"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "h"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Fallback Topic"
#define D_FALSE "Ψευδές"
#define D_FILE "Αρχείο"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Ελεύθερη μνήμη"
#define D_FREQUENCY "Συχνότητα"
#define D_GAS "Αέριο"
@ -156,6 +157,7 @@
#define D_TO "έως"
#define D_TOGGLE "Εναλλαγή"
#define D_TOPIC "Topic"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Μετάδοση"
#define D_TRUE "Αληθές"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Αποθήκευση ρυθμίσεων"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "Ν"
#define D_TX20_WEST "Δ"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Κανένα"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Fallback Topic"
#define D_FALSE "False"
#define D_FILE "File"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Free Memory"
#define D_FREQUENCY "Frequency"
#define D_GAS "Gas"
@ -156,6 +157,7 @@
#define D_TO "to"
#define D_TOGGLE "Toggle"
#define D_TOPIC "Topic"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Transmit"
#define D_TRUE "True"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Save configuration"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
@ -576,12 +582,15 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -1,5 +1,5 @@
/*
es-AR.h - localization for Spanish - Argentina for Sonoff-Tasmota
es-ES.h - localization for Spanish - Spain for Sonoff-Tasmota
Copyright (C) 2019 Adrian Scillato
@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LANGUAGE_ES_AR_H_
#define _LANGUAGE_ES_AR_H_
#ifndef _LANGUAGE_ES_ES_H_
#define _LANGUAGE_ES_ES_H_
/*************************** ATTENTION *******************************\
*
@ -28,12 +28,12 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
* Updated until v6.3.0.17
* Updated until v6.5.0.7
\*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
#define LANGUAGE_LCID 11274
#define LANGUAGE_LCID 1034
// HTML (ISO 639-1) Language Code
#define D_HTML_LANGUAGE "es"
@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "FallbackTopic"
#define D_FALSE "Falso"
#define D_FILE "Archivo"
#define D_FLOW_RATE "Caudal"
#define D_FREE_MEMORY "Memoria Libre"
#define D_FREQUENCY "Frecuencia"
#define D_GAS "Gas"
@ -156,6 +157,7 @@
#define D_TO "a"
#define D_TOGGLE "Conmutar"
#define D_TOPIC "Topic"
#define D_TOTAL_USAGE "Total Usado"
#define D_TRANSMIT "Transmitir"
#define D_TRUE "Verdadero"
#define D_TVOC "TVOC"
@ -289,8 +291,8 @@
#define D_TELEMETRY_PERIOD "Período de Telemetría"
#define D_OTHER_PARAMETERS "Otros parámetros"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_TEMPLATE "Plantilla"
#define D_ACTIVATE "Activar"
#define D_WEB_ADMIN_PASSWORD "Clave Administrador Web"
#define D_MQTT_ENABLE "Habilitar MQTT"
#define D_FRIENDLY_NAME "Nombre Amigable"
@ -299,13 +301,14 @@
#define D_SINGLE_DEVICE "dispositivo simple"
#define D_MULTI_DEVICE "dispositivo múltiple"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_CONFIGURE_TEMPLATE "Configurar Plantilla"
#define D_TEMPLATE_PARAMETERS "Parámetros de Plantilla"
#define D_TEMPLATE_NAME "Nombre"
#define D_BASE_TYPE "Basada en"
#define D_TEMPLATE_FLAGS "Opciones"
#define D_ALLOW_ADC0 "Entrada ADC0"
#define D_ALLOW_ADC0_TEMP "Temperatura por ADC0"
#define D_ALLOW_PULLUP "Habilitar pull-up"
#define D_SAVE_CONFIGURATION "Grabar configuración"
#define D_CONFIGURATION_SAVED "Configuración grabada"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "O"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Ninguno"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
@ -644,4 +654,4 @@
#define D_UNIT_KWARH "kVArH"
#define D_UNIT_ANGLE "Grados"
#endif // _LANGUAGE_ES_AR_H_
#endif // _LANGUAGE_ES_ES_H_

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Topic de secours"
#define D_FALSE "Faux"
#define D_FILE "Fichier"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Mémoire libre"
#define D_FREQUENCY "Fréquence"
#define D_GAS "Gaz"
@ -156,6 +157,7 @@
#define D_TO "à"
#define D_TOGGLE "Inverser"
#define D_TOPIC "Topic" // Keep MQTT keyword
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Transmettre"
#define D_TRUE "Vrai"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Basé sur"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "Entrée ADC0"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "Pull-up utilisateur"
#define D_SAVE_CONFIGURATION "Enregistrer la configuration"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "O"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Aucun"
#define D_SENSOR_USER "Utilisateur"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "h"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "נושא לחזרה"
#define D_FALSE "שגוי"
#define D_FILE "קובץ"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "זכרון פנוי"
#define D_FREQUENCY "תדר"
#define D_GAS "גז"
@ -156,6 +157,7 @@
#define D_TO "ל"
#define D_TOGGLE "מתג"
#define D_TOPIC "נושא"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "עבר"
#define D_TRUE "נכון"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "מבוסס על"
#define D_TEMPLATE_FLAGS "אפשריות"
#define D_ALLOW_ADC0 "ADC0 כניסת"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "pull-up בחירת משתמש עבור"
#define D_SAVE_CONFIGURATION "שמירת הגדרות"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "משתמש"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "fallback topik"
#define D_FALSE "Hamis"
#define D_FILE "Fájl"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Szabad memória"
#define D_FREQUENCY "Frekvencia"
#define D_GAS "Gáz"
@ -156,6 +157,7 @@
#define D_TO "-nak"
#define D_TOGGLE "Megfordítás"
#define D_TOPIC "Topic"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Továbbít"
#define D_TRUE "Igaz"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Beállítások mentése"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "D"
#define D_TX20_WEST "NY"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Nincs"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "h"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Topic Riserva"
#define D_FALSE "Falso"
#define D_FILE "File"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Memoria Libera"
#define D_FREQUENCY "Frequenza"
#define D_GAS "Gas"
@ -156,6 +157,7 @@
#define D_TO "a"
#define D_TOGGLE "Toggle"
#define D_TOPIC "Topic"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Trasmesso"
#define D_TRUE "Vero"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Salva configurazione"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Nessuno"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Fallback Topic"
#define D_FALSE "거짓"
#define D_FILE "파일"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "남은 메모리"
#define D_FREQUENCY "빈도"
#define D_GAS "가스"
@ -156,6 +157,7 @@
#define D_TO "to"
#define D_TOGGLE "전환"
#define D_TOPIC "Topic"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "전송"
#define D_TRUE "참"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "옵션"
#define D_ALLOW_ADC0 "ADC0 입력"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "설정 저장"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "없음"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "시"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Fallback Topic"
#define D_FALSE "Onwaar"
#define D_FILE "Bestand"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Vrij geheugen"
#define D_FREQUENCY "Frequentie"
#define D_GAS "Gas"
@ -156,6 +157,7 @@
#define D_TO "naar"
#define D_TOGGLE "Toggle" // Wissel, Tuimel
#define D_TOPIC "Topic" // Onderwerp
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Verzend"
#define D_TRUE "Waar"
#define D_TVOC "TVOC"
@ -289,8 +291,8 @@
#define D_TELEMETRY_PERIOD "Telemetry periode"
#define D_OTHER_PARAMETERS "Overige parameters"
#define D_TEMPLATE "Template"
#define D_ACTIVATE "Activate"
#define D_TEMPLATE "Sjabloon"
#define D_ACTIVATE "Activeer"
#define D_WEB_ADMIN_PASSWORD "Web Admin Wachtwoord"
#define D_MQTT_ENABLE "MQTT ingeschakeld"
#define D_FRIENDLY_NAME "Beschrijvende naam"
@ -299,12 +301,13 @@
#define D_SINGLE_DEVICE "een apparaat"
#define D_MULTI_DEVICE "meer apparaten"
#define D_CONFIGURE_TEMPLATE "Configure Template"
#define D_TEMPLATE_PARAMETERS "Template parameters"
#define D_TEMPLATE_NAME "Name"
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_CONFIGURE_TEMPLATE "Configureer Sjabloon"
#define D_TEMPLATE_PARAMETERS "Sjabloon parameters"
#define D_TEMPLATE_NAME "Naam"
#define D_BASE_TYPE "Op basis van"
#define D_TEMPLATE_FLAGS "Opties"
#define D_ALLOW_ADC0 "ADC0 ingang"
#define D_ALLOW_ADC0_TEMP "ADC0 temperatuur"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Bewaar configuratie"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Geen"
#define D_SENSOR_USER "Gebruiker"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "h"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Zastępczy temat"
#define D_FALSE "Fałsz"
#define D_FILE "Plik"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Wolna pamięć"
#define D_FREQUENCY "Frequency"
#define D_GAS "Gas"
@ -156,6 +157,7 @@
#define D_TO "do"
#define D_TOGGLE "Przełącz"
#define D_TOPIC "Temat"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Wyślij"
#define D_TRUE "Prawda"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Zapisz ustawienia"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Brak"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Godz"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Tópico para retornar"
#define D_FALSE "Falso"
#define D_FILE "Arquivo"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Memória livre"
#define D_FREQUENCY "Frequência"
#define D_GAS "Gás"
@ -156,6 +157,7 @@
#define D_TO "Para"
#define D_TOGGLE "Inverter"
#define D_TOPIC "Tópico"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Transmitir"
#define D_TRUE "Verdadeiro"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Gravar configuração"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Nenhum"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "H"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Tópico para retornar"
#define D_FALSE "Falso"
#define D_FILE "Ficheiro"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Memoria Livre"
#define D_FREQUENCY "Frequency"
#define D_GAS "Gás"
@ -156,6 +157,7 @@
#define D_TO "para"
#define D_TOGGLE "Pressionar"
#define D_TOPIC "Tópico"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Transmitir"
#define D_TRUE "Verdadeiro"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Salvar configuração"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Nenhum"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Топик обратной связи"
#define D_FALSE "Ложно"
#define D_FILE "Файл"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Свободная память"
#define D_FREQUENCY "Frequency"
#define D_GAS "Газ"
@ -156,6 +157,7 @@
#define D_TO "до"
#define D_TOGGLE "Переключить"
#define D_TOPIC "Топик"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Передать"
#define D_TRUE "Истина"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Сохранить конфигурацию"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "-нет-"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "А"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Ч"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -75,6 +75,7 @@
#define D_COUNTER "Počítadlo"
#define D_CURRENT "Prúd" // As in Voltage and Current
#define D_DATA "Dáta"
#define D_FLOW_RATE "Flow rate"
#define D_DARKLIGHT "Tmavý"
#define D_DEBUG "Debug"
#define D_DISABLED "Zablokované"
@ -156,6 +157,7 @@
#define D_TO "do"
#define D_TOGGLE "Prepni"
#define D_TOPIC "Topic"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Odošli"
#define D_TRUE "Pravda"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Ulož nastavenia"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "J"
#define D_TX20_WEST "Z"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Žiaden"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "hod"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Reservämne"
#define D_FALSE "Falskt"
#define D_FILE "Fil"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Ledigt minne"
#define D_FREQUENCY "Frekvens"
#define D_GAS "Gas"
@ -156,6 +157,7 @@
#define D_TO "till"
#define D_TOGGLE "Växla"
#define D_TOPIC "Ämne"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Sänd"
#define D_TRUE "Sant"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Spara konfiguration"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "V"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "Ingen"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Tim"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "ink"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Geri İletim Topiği"
#define D_FALSE "False"
#define D_FILE "Dosya"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Boş Hafıza"
#define D_FREQUENCY "Frekans"
#define D_GAS "Gas"
@ -156,6 +157,7 @@
#define D_TO "den"
#define D_TOGGLE "Geçiş Tuşu"
#define D_TOPIC "Başlık"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "İletim"
#define D_TRUE "True"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Ayarları Kaydet"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
@ -576,11 +582,15 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Топік зворотнього зв'язку"
#define D_FALSE "Помилково"
#define D_FILE "Файл"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "Вільна память"
#define D_FREQUENCY "Частота"
#define D_GAS "Газ"
@ -156,6 +157,7 @@
#define D_TO "до"
#define D_TOGGLE "Перекл."
#define D_TOPIC "Топік"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "Передати"
#define D_TRUE "Істина"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "Зберегти конфігурацію"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "-відсутньо-"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "А"
#define D_UNIT_CENTIMETER "cм"
#define D_UNIT_HERTZ "Гц"
#define D_UNIT_HOUR "Г"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "回退主题"
#define D_FALSE "False"
#define D_FILE "文件:"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "空闲内存"
#define D_FREQUENCY "频率"
#define D_GAS "气体"
@ -156,6 +157,7 @@
#define D_TO "to"
#define D_TOGGLE "切换"
#define D_TOPIC "主题"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "发送"
#define D_TRUE "True"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "基于"
#define D_TEMPLATE_FLAGS "选项"
#define D_ALLOW_ADC0 "ADC0 输入"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "用户上拉选择"
#define D_SAVE_CONFIGURATION "保存设置"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "南"
#define D_TX20_WEST "西"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "无"
#define D_SENSOR_USER "User"
@ -576,11 +582,15 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "安"
#define D_UNIT_CENTIMETER "厘米"
#define D_UNIT_HOUR "时"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "千克"
#define D_UNIT_KILOMETER_PER_HOUR "公里/时" // or "km/h"

View File

@ -93,6 +93,7 @@
#define D_FALLBACK_TOPIC "Fallback Topic"
#define D_FALSE "False"
#define D_FILE "文件:"
#define D_FLOW_RATE "Flow rate"
#define D_FREE_MEMORY "可用記憶體"
#define D_FREQUENCY "Frequency"
#define D_GAS "氣體"
@ -156,6 +157,7 @@
#define D_TO "to"
#define D_TOGGLE "切換"
#define D_TOPIC "主題"
#define D_TOTAL_USAGE "Total Usage"
#define D_TRANSMIT "發送"
#define D_TRUE "True"
#define D_TVOC "TVOC"
@ -305,6 +307,7 @@
#define D_BASE_TYPE "Based on"
#define D_TEMPLATE_FLAGS "Options"
#define D_ALLOW_ADC0 "ADC0 input"
#define D_ALLOW_ADC0_TEMP "ADC0 temperature"
#define D_ALLOW_PULLUP "User pull-up selection"
#define D_SAVE_CONFIGURATION "保存設置"
@ -492,6 +495,9 @@
#define D_TX20_SOUTH "S"
#define D_TX20_WEST "W"
//xsns_43_hre.ino
#define D_LOG_HRE "HRE: "
// sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box
#define D_SENSOR_NONE "None"
#define D_SENSOR_USER "User"
@ -576,12 +582,16 @@
#define D_SENSOR_TXD "Serial Tx"
#define D_SENSOR_RXD "Serial Rx"
#define D_SENSOR_ROTARY "Rotary" // Suffix "1A"
#define D_SENSOR_HRE_CLOCK "HRE Clock"
#define D_SENSOR_HRE_DATA "HRE Data"
// Units
#define D_UNIT_AMPERE "安"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "時"
#define D_UNIT_GALLONS "gal"
#define D_UNIT_GALLONS_PER_MIN "g/m"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"

View File

@ -135,6 +135,25 @@
#define WEB_PASSWORD "" // [WebPassword] Web server Admin mode Password for WEB_USERNAME (empty string = Disable)
#define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa
#define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo (single relay/light) or Hue Bridge emulation (multi relay/light) (EMUL_NONE, EMUL_WEMO or EMUL_HUE)
// HTML hex color codes. Only 3 and 6 digit hex string values are supported!! See https://www.w3schools.com/colors/colors_hex.asp
#define COLOR_TEXT "#000" // [WebColor1] Global text color - Black
#define COLOR_BACKGROUND "#fff" // [WebColor2] Global background color - White
#define COLOR_FORM "#f2f2f2" // [WebColor3] Form background color - Greyish
#define COLOR_INPUT_TEXT "#000" // [WebColor4] Input text color - Black
#define COLOR_INPUT "#fff" // [WebColor5] Input background color - White
#define COLOR_CONSOLE_TEXT "#000" // [WebColor6] Console text color - Black
#define COLOR_CONSOLE "#fff" // [WebColor7] Console background color - White
#define COLOR_TEXT_WARNING "#f00" // [WebColor8] Warning text color - Red
#define COLOR_TEXT_SUCCESS "#008000" // [WebColor9] Success text color - Green
#define COLOR_BUTTON_TEXT "#fff" // [WebColor10] Button text color - White
#define COLOR_BUTTON "#1fa3ec" // [WebColor11] Button color - Blueish
#define COLOR_BUTTON_HOVER "#0e70a4" // [WebColor12] Button color when hovered over - Darker blueish
#define COLOR_BUTTON_RESET "#d43535" // [WebColor13] Restart/Reset/Delete button color - Redish
#define COLOR_BUTTON_RESET_HOVER "#931f1f" // [WebColor14] Restart/Reset/Delete button color when hovered over - Darker redish
#define COLOR_BUTTON_SAVE "#47c266" // [WebColor15] Save button color - Greenish
#define COLOR_BUTTON_SAVE_HOVER "#5aaf6f" // [WebColor16] Save button color when hovered over - Darker greenish
#define COLOR_TIMER_TAB_TEXT "#fff" // [WebColor17] Config timer tab text color - White
#define COLOR_TIMER_TAB_BACKGROUND "#999" // [WebColor18] Config timer tab background color - Light grey
// -- mDNS ----------------------------------------
#define MDNS_ENABLED 0 // [SetOption55] Use mDNS (0 = Disable, 1 = Enable)
@ -168,6 +187,7 @@
#define APP_TIMEZONE 1 // [Timezone] +1 hour (Amsterdam) (-13 .. 14 = hours from UTC, 99 = use TIME_DST/TIME_STD)
#define APP_LEDSTATE LED_POWER // [LedState] Function of led
// (LED_OFF, LED_POWER, LED_MQTTSUB, LED_POWER_MQTTSUB, LED_MQTTPUB, LED_POWER_MQTTPUB, LED_MQTT, LED_POWER_MQTT)
#define APP_LEDMASK 0xFFFF // [LedMask] Assign Relay to Power led (0xFFFF is default)
#define APP_PULSETIME 0 // [PulseTime] Time in 0.1 Sec to turn off power for relay 1 (0 = disabled)
#define APP_POWERON_STATE POWER_ALL_SAVED // [PowerOnState] Power On Relay state
// (POWER_ALL_OFF, POWER_ALL_ON, POWER_ALL_SAVED_TOGGLE, POWER_ALL_SAVED, POWER_ALL_ALWAYS_ON, POWER_ALL_OFF_PULSETIME_ON)
@ -204,7 +224,7 @@
//#define MY_LANGUAGE de-DE // German in Germany
//#define MY_LANGUAGE el-GR // Greek in Greece
//#define MY_LANGUAGE en-GB // English in Great Britain. Enabled by Default
//#define MY_LANGUAGE es-AR // Spanish in Argentina
//#define MY_LANGUAGE es-ES // Spanish in Spain
//#define MY_LANGUAGE fr-FR // French in France
//#define MY_LANGUAGE he-HE // Hebrew in Israel
//#define MY_LANGUAGE hu-HU // Hungarian in Hungary
@ -369,6 +389,7 @@
#define TUYA_DIMMER_ID 0 // Default dimmer Id
#define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code)
#define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer
//#define ROTARY_V1 // Add support for MI Desk Lamp
//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger (+1k6 code)
//#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem)
// #define USE_PN532_CAUSE_EVENTS // Cause event execution for PN532_UID= and PN532_DATA=[if defined] (+ 30 bytes code)
@ -415,6 +436,8 @@
#define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code)
//#define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code)
/*********************************************************************************************\
* Debug features are only supported in development branch
\*********************************************************************************************/

View File

@ -20,7 +20,7 @@
#ifndef _SETTINGS_H_
#define _SETTINGS_H_
#define PARAM8_SIZE 18 // Number of param bytes (SetOption)
const uint8_t PARAM8_SIZE = 18; // Number of param bytes (SetOption)
typedef union { // Restricted by MISRA-C Rule 18.4 but so useful...
uint32_t data; // Allow bit manipulation using SetOption
@ -185,12 +185,12 @@ struct SYSCFG {
unsigned long bootcount; // 00C
*/
struct SYSCFG {
uint16_t cfg_holder; // 000 v6 header
uint16_t cfg_size; // 002
uint16_t cfg_holder; // 000 v6 header
uint16_t cfg_size; // 002
unsigned long save_flag; // 004
unsigned long version; // 008
uint16_t bootcount; // 00C
uint16_t cfg_crc; // 00E
uint16_t bootcount; // 00C
uint16_t cfg_crc; // 00E
SysBitfield flag; // 010
int16_t save_data; // 014
int8_t timezone; // 016
@ -330,8 +330,10 @@ struct SYSCFG {
uint8_t rgbwwTable[5]; // 71A
uint8_t user_template_base; // 71F
mytmplt user_template; // 720 29 bytes
uint8_t novasds_period; // 73D
uint8_t web_color[18][3]; // 73E
uint8_t free_73D[87]; // 73D
uint8_t free_774[32]; // 774
uint32_t drivers[3]; // 794
uint32_t monitors; // 7A0
@ -339,9 +341,7 @@ struct SYSCFG {
uint32_t displays; // 7B0
uint32_t energy_kWhtotal_time; // 7B4
unsigned long weight_item; // 7B8 Weight of one item in gram * 10
uint8_t free_7BC[2]; // 7BC
uint16_t ledmask; // 7BC
uint16_t weight_max; // 7BE Total max weight in kilogram
unsigned long weight_reference; // 7C0 Reference weight in gram
unsigned long weight_calibration; // 7C4
@ -396,7 +396,7 @@ struct XDRVMAILBOX {
char *data;
} XdrvMailbox;
#define MAX_RULES_FLAG 7 // Number of bits used in RulesBitfield (tricky I know...)
const uint8_t MAX_RULES_FLAG = 8; // Number of bits used in RulesBitfield (tricky I know...)
typedef union { // Restricted by MISRA-C Rule 18.4 but so useful...
uint16_t data; // Allow bit manipulation
struct {
@ -407,7 +407,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint16_t mqtt_disconnected : 1;
uint16_t wifi_connected : 1;
uint16_t wifi_disconnected : 1;
uint16_t spare07 : 1;
uint16_t http_init : 1;
uint16_t spare08 : 1;
uint16_t spare09 : 1;
uint16_t spare10 : 1;

View File

@ -18,36 +18,36 @@
*/
#ifndef DOMOTICZ_UPDATE_TIMER
#define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) (Optional)
#define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) (Optional)
#endif
#ifndef EMULATION
#define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo (single relay/light) or Hue Bridge emulation (multi relay/light) (EMUL_NONE, EMUL_WEMO or EMUL_HUE)
#define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo (single relay/light) or Hue Bridge emulation (multi relay/light) (EMUL_NONE, EMUL_WEMO or EMUL_HUE)
#endif
#ifndef MTX_ADDRESS1 // Add Display Support for up to eigth Matrices
#define MTX_ADDRESS1 0
#ifndef MTX_ADDRESS1 // Add Display Support for up to eigth Matrices
#define MTX_ADDRESS1 0
#endif
#ifndef MTX_ADDRESS2
#define MTX_ADDRESS2 0
#define MTX_ADDRESS2 0
#endif
#ifndef MTX_ADDRESS3
#define MTX_ADDRESS3 0
#define MTX_ADDRESS3 0
#endif
#ifndef MTX_ADDRESS4
#define MTX_ADDRESS4 0
#define MTX_ADDRESS4 0
#endif
#ifndef MTX_ADDRESS5
#define MTX_ADDRESS5 0
#define MTX_ADDRESS5 0
#endif
#ifndef MTX_ADDRESS6
#define MTX_ADDRESS6 0
#define MTX_ADDRESS6 0
#endif
#ifndef MTX_ADDRESS7
#define MTX_ADDRESS7 0
#define MTX_ADDRESS7 0
#endif
#ifndef MTX_ADDRESS8
#define MTX_ADDRESS8 0
#define MTX_ADDRESS8 0
#endif
#ifndef HOME_ASSISTANT_DISCOVERY_ENABLE
@ -55,17 +55,91 @@
#endif
#ifndef LATITUDE
#define LATITUDE 48.858360 // [Latitude] Your location to be used with sunrise and sunset
#define LATITUDE 48.858360 // [Latitude] Your location to be used with sunrise and sunset
#endif
#ifndef LONGITUDE
#define LONGITUDE 2.294442 // [Longitude] Your location to be used with sunrise and sunset
#define LONGITUDE 2.294442 // [Longitude] Your location to be used with sunrise and sunset
#endif
#ifndef WORKING_PERIOD
#define WORKING_PERIOD 5 // Working period of the SDS Sensor, Takes a reading every X Minutes
#endif
#ifndef COLOR_TEXT
#define COLOR_TEXT "#000" // Global text color - Black
#endif
#ifndef COLOR_BACKGROUND
#define COLOR_BACKGROUND "#fff" // Global background color - White
#endif
#ifndef COLOR_FORM
#define COLOR_FORM "#f2f2f2" // Form background color - Greyish
#endif
#ifndef COLOR_INPUT_TEXT
#define COLOR_INPUT_TEXT "#000" // Input text color - Black
#endif
#ifndef COLOR_INPUT
#define COLOR_INPUT "#fff" // Input background color - White
#endif
#ifndef COLOR_CONSOLE_TEXT
#define COLOR_CONSOLE_TEXT "#000" // Console text color - Black
#endif
#ifndef COLOR_CONSOLE
#define COLOR_CONSOLE "#fff" // Console background color - White
#endif
#ifndef COLOR_TEXT_WARNING
#define COLOR_TEXT_WARNING "#f00" // Warning text color - Red
#endif
#ifndef COLOR_TEXT_SUCCESS
#define COLOR_TEXT_SUCCESS "#008000" // Success text color - Green
#endif
#ifndef COLOR_BUTTON_TEXT
#define COLOR_BUTTON_TEXT "#fff" // Button text color - White
#endif
#ifndef COLOR_BUTTON
#define COLOR_BUTTON "#1fa3ec" // Button color - Blueish
#endif
#ifndef COLOR_BUTTON_HOVER
#define COLOR_BUTTON_HOVER "#0e70a4" // Button color when hovered over - Darker blueish
#endif
#ifndef COLOR_BUTTON_RESET
#define COLOR_BUTTON_RESET "#d43535" // Restart/Reset/Delete button color - Redish
#endif
#ifndef COLOR_BUTTON_RESET_HOVER
#define COLOR_BUTTON_RESET_HOVER "#931f1f" // Restart/Reset/Delete button color when hovered over - Darker redish
#endif
#ifndef COLOR_BUTTON_SAVE
#define COLOR_BUTTON_SAVE "#47c266" // Save button color - Greenish
#endif
#ifndef COLOR_BUTTON_SAVE_HOVER
#define COLOR_BUTTON_SAVE_HOVER "#5aaf6f" // Save button color when hovered over - Darker greenish
#endif
#ifndef COLOR_TIMER_TAB_TEXT
#define COLOR_TIMER_TAB_TEXT "#fff" // Config timer tab text color - White
#endif
#ifndef COLOR_TIMER_TAB_BACKGROUND
#define COLOR_TIMER_TAB_BACKGROUND "#999" // Config timer tab background color - Light grey
#endif
enum WebColors {
COL_TEXT, COL_BACKGROUND, COL_FORM,
COL_INPUT_TEXT, COL_INPUT, COL_CONSOLE_TEXT, COL_CONSOLE,
COL_TEXT_WARNING, COL_TEXT_SUCCESS,
COL_BUTTON_TEXT, COL_BUTTON, COL_BUTTON_HOVER, COL_BUTTON_RESET, COL_BUTTON_RESET_HOVER, COL_BUTTON_SAVE, COL_BUTTON_SAVE_HOVER,
COL_TIMER_TAB_TEXT, COL_TIMER_TAB_BACKGROUND,
COL_LAST };
const char kWebColors[] PROGMEM =
COLOR_TEXT "|" COLOR_BACKGROUND "|" COLOR_FORM "|"
COLOR_INPUT_TEXT "|" COLOR_INPUT "|" COLOR_CONSOLE_TEXT "|" COLOR_CONSOLE "|"
COLOR_TEXT_WARNING "|" COLOR_TEXT_SUCCESS "|"
COLOR_BUTTON_TEXT "|" COLOR_BUTTON "|" COLOR_BUTTON_HOVER "|" COLOR_BUTTON_RESET "|" COLOR_BUTTON_RESET_HOVER "|" COLOR_BUTTON_SAVE "|" COLOR_BUTTON_SAVE_HOVER "|"
COLOR_TIMER_TAB_TEXT "|" COLOR_TIMER_TAB_BACKGROUND;
/*********************************************************************************************\
* RTC memory
\*********************************************************************************************/
#define RTC_MEM_VALID 0xA55A
const uint16_t RTC_MEM_VALID = 0xA55A;
uint32_t rtc_settings_crc = 0;
@ -164,16 +238,18 @@ extern "C" {
extern "C" uint32_t _SPIFFS_end;
// From libraries/EEPROM/EEPROM.cpp EEPROMClass
#define SPIFFS_END ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE
const uint32_t SPIFFS_END = ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE;
// Version 4.2 config = eeprom area
#define SETTINGS_LOCATION SPIFFS_END // No need for SPIFFS as it uses EEPROM area
const uint32_t SETTINGS_LOCATION = SPIFFS_END; // No need for SPIFFS as it uses EEPROM area
// Version 5.2 allow for more flash space
#define CFG_ROTATES 8 // Number of flash sectors used (handles uploads)
const uint8_t CFG_ROTATES = 8; // Number of flash sectors used (handles uploads)
/*********************************************************************************************\
* EEPROM support based on EEPROM library and tuned for Tasmota
* Optional EEPROM support based on EEPROM library and tuned for Tasmota
\*********************************************************************************************/
//#define USE_EEPROM
#ifdef USE_EEPROM
uint32_t eeprom_sector = SPIFFS_END;
uint8_t* eeprom_data = 0;
@ -301,12 +377,12 @@ void EepromEnd(void)
eeprom_size = 0;
eeprom_dirty = false;
}
#endif // USE_EEPROM
/********************************************************************************************/
uint16_t settings_crc = 0;
uint32_t settings_location = SETTINGS_LOCATION;
uint8_t *settings_buffer = NULL;
uint8_t *settings_buffer = nullptr;
/********************************************************************************************/
/*
@ -333,9 +409,9 @@ void SetFlashModeDout(void)
void SettingsBufferFree(void)
{
if (settings_buffer != NULL) {
if (settings_buffer != nullptr) {
free(settings_buffer);
settings_buffer = NULL;
settings_buffer = nullptr;
}
}
@ -368,7 +444,9 @@ void SettingsSaveAll(void)
Settings.power = 0;
}
XsnsCall(FUNC_SAVE_BEFORE_RESTART);
#ifdef USE_EEPROM
EepromCommit();
#endif
SettingsSave(0);
}
@ -411,6 +489,7 @@ void SettingsSave(uint8_t rotate)
Settings.cfg_size = sizeof(SYSCFG);
Settings.cfg_crc = GetSettingsCrc();
#ifdef USE_EEPROM
if (SPIFFS_END == settings_location) {
uint8_t* flash_buffer;
flash_buffer = new uint8_t[SPI_FLASH_SEC_SIZE];
@ -428,6 +507,10 @@ void SettingsSave(uint8_t rotate)
ESP.flashEraseSector(settings_location);
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG));
}
#else
ESP.flashEraseSector(settings_location);
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG));
#endif // USE_EEPROM
if (!stop_flash_rotate && rotate) {
for (uint8_t i = 1; i < CFG_ROTATES; i++) {
@ -456,13 +539,17 @@ void SettingsLoad(void)
settings_location = 0;
uint32_t flash_location = SETTINGS_LOCATION +1;
uint16_t cfg_holder = 0;
for (uint8_t i = 0; i < CFG_ROTATES; i++) {
flash_location--;
ESP.flashRead(flash_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG));
bool valid = false;
if (Settings.version > 0x06000000) {
valid = (Settings.cfg_crc == GetSettingsCrc());
bool almost_valid = (Settings.cfg_crc == GetSettingsCrc());
// Sometimes CRC on pages below FB, overwritten by OTA, is fine but Settings are still invalid. So check cfg_holder too
if (almost_valid && (0 == cfg_holder)) { cfg_holder = Settings.cfg_holder; } // At FB always active cfg_holder
valid = (cfg_holder == Settings.cfg_holder);
} else {
ESP.flashRead((flash_location -1) * SPI_FLASH_SEC_SIZE, (uint32*)&_SettingsH, sizeof(SYSCFGH));
valid = (Settings.cfg_holder == _SettingsH.cfg_holder);
@ -481,7 +568,7 @@ void SettingsLoad(void)
}
if (settings_location > 0) {
ESP.flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG));
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG D_LOADED_FROM_FLASH_AT " %X, " D_COUNT " %d"), settings_location, Settings.save_flag);
AddLog_P2(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG D_LOADED_FROM_FLASH_AT " %X, " D_COUNT " %lu"), settings_location, Settings.save_flag);
}
#ifndef FIRMWARE_MINIMAL
@ -608,6 +695,7 @@ void SettingsDefaultSet2(void)
Settings.blinktime = APP_BLINKTIME;
Settings.blinkcount = APP_BLINKCOUNT;
Settings.ledstate = APP_LEDSTATE;
Settings.ledmask = APP_LEDMASK;
Settings.pulse_timer[0] = APP_PULSETIME;
// for (uint8_t i = 1; i < MAX_PULSETIMERS; i++) { Settings.pulse_timer[i] = 0; }
@ -815,6 +903,10 @@ void SettingsDefaultSet2(void)
Settings.rgbwwTable[j] = 255;
}
Settings.novasds_period = WORKING_PERIOD;
SettingsDefaultWebColor();
memset(&Settings.drivers, 0xFF, 32); // Enable all possible monitors, displays, drivers and sensors
}
@ -885,6 +977,14 @@ void SettingsDefaultSet_5_13_1c(void)
SettingsResetDst();
}
void SettingsDefaultWebColor(void)
{
char scolor[10];
for (uint8_t i = 0; i < COL_LAST; i++) {
WebHexCode(i, GetTextIndexed(scolor, sizeof(scolor), i, kWebColors));
}
}
/********************************************************************************************/
void SettingsDelta(void)
@ -1055,6 +1155,15 @@ void SettingsDelta(void)
if (Settings.version < 0x06040113) {
Settings.param[P_RGB_REMAP] = RGB_REMAP_RGBW;
}
if (Settings.version < 0x06050003) {
Settings.novasds_period = WORKING_PERIOD;
}
if (Settings.version < 0x06050006) {
SettingsDefaultWebColor();
}
if (Settings.version < 0x06050007) {
Settings.ledmask = APP_LEDMASK;
}
Settings.version = VERSION;
SettingsSave(1);

View File

@ -42,109 +42,109 @@
\*********************************************************************************************/
typedef unsigned long power_t; // Power (Relay) type
#define POWER_MASK 0xffffffffUL // Power (Relay) full mask
const uint32_t POWER_MASK = 0xffffffffUL; // Power (Relay) full mask
/*********************************************************************************************\
* Constants
\*********************************************************************************************/
// Changes to the following MAX_ defines will impact settings layout
const uint8_t MAX_SWITCHES = 8; // Max number of switches
const uint8_t MAX_RELAYS = 8; // Max number of relays
const uint8_t MAX_INTERLOCKS = 4; // Max number of interlock groups (MAX_RELAYS / 2)
const uint8_t MAX_LEDS = 4; // Max number of leds
const uint8_t MAX_KEYS = 4; // Max number of keys or buttons
const uint8_t MAX_PWMS = 5; // Max number of PWM channels
const uint8_t MAX_COUNTERS = 4; // Max number of counter sensors
const uint8_t MAX_TIMERS = 16; // Max number of Timers
const uint8_t MAX_PULSETIMERS = 8; // Max number of supported pulse timers
const uint8_t MAX_FRIENDLYNAMES = 4; // Max number of Friendly names
const uint8_t MAX_DOMOTICZ_IDX = 4; // Max number of Domoticz device, key and switch indices
const uint8_t MAX_DOMOTICZ_SNS_IDX = 12; // Max number of Domoticz sensors indices
const uint8_t MAX_KNX_GA = 10; // Max number of KNX Group Addresses to read that can be set
const uint8_t MAX_KNX_CB = 10; // Max number of KNX Group Addresses to write that can be set
const uint8_t MAX_XNRG_DRIVERS = 32; // Max number of allowed energy drivers
const uint8_t MAX_XDSP_DRIVERS = 32; // Max number of allowed display drivers
const uint8_t MAX_XDRV_DRIVERS = 96; // Max number of allowed driver drivers
const uint8_t MAX_XSNS_DRIVERS = 96; // Max number of allowed sensor drivers
const uint8_t MAX_RULE_MEMS = 5; // Max number of saved vars
const uint8_t MAX_RULE_SETS = 3; // Max number of rule sets of size 512 characters
const uint16_t MAX_RULE_SIZE = 512; // Max number of characters in rules
const uint8_t MAX_FAN_SPEED = 4; // Max number of iFan02 fan speeds (0 .. 3)
const char MQTT_TOKEN_PREFIX[] PROGMEM = "%prefix%"; // To be substituted by mqtt_prefix[x]
const char MQTT_TOKEN_TOPIC[] PROGMEM = "%topic%"; // To be substituted by mqtt_topic, mqtt_grptopic, mqtt_buttontopic, mqtt_switchtopic
const char WIFI_HOSTNAME[] = "%s-%04d"; // Expands to <MQTT_TOPIC>-<last 4 decimal chars of MAC address>
const uint8_t CONFIG_FILE_SIGN = 0xA5; // Configuration file signature
const uint8_t CONFIG_FILE_XOR = 0x5A; // Configuration file xor (0 = No Xor)
const uint32_t HLW_PREF_PULSE = 12530; // was 4975us = 201Hz = 1000W
const uint32_t HLW_UREF_PULSE = 1950; // was 1666us = 600Hz = 220V
const uint32_t HLW_IREF_PULSE = 3500; // was 1666us = 600Hz = 4.545A
const uint8_t MQTT_RETRY_SECS = 10; // Minimum seconds to retry MQTT connection
const uint32_t GLOBAL_VALUES_VALID = 300; // Max number of seconds to keep last received values
const power_t APP_POWER = 0; // Default saved power state Off
const uint16_t WS2812_MAX_LEDS = 512; // Max number of LEDs
const uint32_t PWM_RANGE = 1023; // 255..1023 needs to be devisible by 256
//const uint16_t PWM_FREQ = 1000; // 100..1000 Hz led refresh
//const uint16_t PWM_FREQ = 910; // 100..1000 Hz led refresh (iTead value)
const uint16_t PWM_FREQ = 880; // 100..1000 Hz led refresh (BN-SZ01 value)
const uint16_t PWM_MAX = 4000; // [PWM_MAX] Maximum frequency - Default: 4000
const uint16_t PWM_MIN = 100; // [PWM_MIN] Minimum frequency - Default: 100
// For Dimmers use double of your mains AC frequecy (100 for 50Hz and 120 for 60Hz)
// For Controlling Servos use 50 and also set PWM_FREQ as 50 (DO NOT USE THESE VALUES FOR DIMMERS)
//#define PWM_LIGHTSCHEME0_IGNORE_SLEEP // Do not change sleep value for LightAnimate() scheme 0
const uint8_t DEFAULT_POWER_DELTA = 80; // Power change percentage
const uint16_t MAX_POWER_HOLD = 10; // Time in SECONDS to allow max agreed power
const uint16_t MAX_POWER_WINDOW = 30; // Time in SECONDS to disable allow max agreed power
const uint16_t SAFE_POWER_HOLD = 10; // Time in SECONDS to allow max unit safe power
const uint16_t SAFE_POWER_WINDOW = 30; // Time in MINUTES to disable allow max unit safe power
const uint8_t MAX_POWER_RETRY = 5; // Retry count allowing agreed power limit overflow
const uint8_t STATES = 20; // Number of states per second using 50 mSec interval
const uint8_t IMMINENT_RESET_FACTOR = 10; // Factor to extent button hold time for imminent Reset to default 40 seconds using KEY_HOLD_TIME of 40
const uint32_t BOOT_LOOP_TIME = 10; // Number of seconds to stop detecting boot loops
const uint16_t SYSLOG_TIMER = 600; // Seconds to restore syslog_level
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 uint16_t INPUT_BUFFER_SIZE = 520; // Max number of characters in (serial and http) command buffer
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 LOGSZ = 520; // Max number of characters in log
const uint16_t MIN_MESSZ = 893; // Min number of characters in MQTT message
const uint8_t SENSOR_MAX_MISS = 5; // Max number of missed sensor reads before deciding it's offline
#ifdef USE_MQTT_TLS
const uint16_t WEB_LOG_SIZE = 2000; // Max number of characters in weblog
#else
const uint16_t WEB_LOG_SIZE = 4000; // Max number of characters in weblog
#endif
const uint8_t MAX_BACKLOG = 30; // Max number of commands in backlog
const uint32_t MIN_BACKLOG_DELAY = 2; // Minimal backlog delay in 0.1 seconds
const uint32_t SOFT_BAUDRATE = 9600; // Default software serial baudrate
const uint32_t APP_BAUDRATE = 115200; // Default serial baudrate
const uint32_t SERIAL_POLLING = 100; // Serial receive polling in ms
const uint8_t MAX_STATUS = 11; // Max number of status lines
const uint32_t DRIVER_BOOT_DELAY = 1; // Number of milliseconds to retard driver cycles during boot-up time to reduce overall CPU load whilst Wifi is connecting
const uint32_t LOOP_SLEEP_DELAY = 50; // Lowest number of milliseconds to go through the main loop using delay when needed
/*********************************************************************************************\
* Defines
\*********************************************************************************************/
// Changes to the following MAX_ defines will impact settings layout
#define MAX_SWITCHES 8 // Max number of switches
#define MAX_RELAYS 8 // Max number of relays
#define MAX_INTERLOCKS 4 // Max number of interlock groups (MAX_RELAYS / 2)
#define MAX_LEDS 4 // Max number of leds
#define MAX_KEYS 4 // Max number of keys or buttons
#define MAX_PWMS 5 // Max number of PWM channels
#define MAX_COUNTERS 4 // Max number of counter sensors
#define MAX_TIMERS 16 // Max number of Timers
#define MAX_PULSETIMERS 8 // Max number of supported pulse timers
#define MAX_FRIENDLYNAMES 4 // Max number of Friendly names
#define MAX_DOMOTICZ_IDX 4 // Max number of Domoticz device, key and switch indices
#define MAX_DOMOTICZ_SNS_IDX 12 // Max number of Domoticz sensors indices
#define MAX_KNX_GA 10 // Max number of KNX Group Addresses to read that can be set
#define MAX_KNX_CB 10 // Max number of KNX Group Addresses to write that can be set
#define MAX_XNRG_DRIVERS 32 // Max number of allowed energy drivers
#define MAX_XDSP_DRIVERS 32 // Max number of allowed display drivers
#define MAX_XDRV_DRIVERS 96 // Max number of allowed driver drivers
#define MAX_XSNS_DRIVERS 96 // Max number of allowed sensor drivers
#define MAX_RULE_MEMS 5 // Max number of saved vars
#define MAX_RULE_SETS 3 // Max number of rule sets of size 512 characters
#define MAX_RULE_SIZE 512 // Max number of characters in rules
// Changes to the following defines have no impact on settings layout
#define MAX_RULE_TIMERS 8 // Max number of rule timers (4 bytes / timer)
#define MAX_RULE_VARS 5 // Max number of rule variables (10 bytes / variable)
#define MAX_FAN_SPEED 4 // Max number of iFan02 fan speeds (0 .. 3)
#define MQTT_TOKEN_PREFIX "%prefix%" // To be substituted by mqtt_prefix[x]
#define MQTT_TOKEN_TOPIC "%topic%" // To be substituted by mqtt_topic, mqtt_grptopic, mqtt_buttontopic, mqtt_switchtopic
#define MQTT_TOKEN_HOSTNAME "%hostname%" // To be substituted by mqtt_topic, mqtt_grptopic, mqtt_buttontopic, mqtt_switchtopic
#define MQTT_TOKEN_ID "%id%" // To be substituted by mqtt_topic, mqtt_grptopic, mqtt_buttontopic, mqtt_switchtopic
#define WIFI_HOSTNAME "%s-%04d" // Expands to <MQTT_TOPIC>-<last 4 decimal chars of MAC address>
#define CONFIG_FILE_SIGN 0xA5 // Configuration file signature
#define CONFIG_FILE_XOR 0x5A // Configuration file xor (0 = No Xor)
#define HLW_PREF_PULSE 12530 // was 4975us = 201Hz = 1000W
#define HLW_UREF_PULSE 1950 // was 1666us = 600Hz = 220V
#define HLW_IREF_PULSE 3500 // was 1666us = 600Hz = 4.545A
#define MQTT_RETRY_SECS 10 // Minimum seconds to retry MQTT connection
#define GLOBAL_VALUES_VALID 300 // Max number of seconds to keep last received values
#define APP_POWER 0 // Default saved power state Off
#define WS2812_MAX_LEDS 512 // Max number of LEDs
#define PWM_RANGE 1023 // 255..1023 needs to be devisible by 256
//#define PWM_FREQ 1000 // 100..1000 Hz led refresh
//#define PWM_FREQ 910 // 100..1000 Hz led refresh (iTead value)
#define PWM_FREQ 880 // 100..1000 Hz led refresh (BN-SZ01 value)
#define PWM_MAX 4000 // [PWM_MAX] Maximum frequency - Default: 4000
#define PWM_MIN 100 // [PWM_MIN] Minimum frequency - Default: 100
// For Dimmers use double of your mains AC frequecy (100 for 50Hz and 120 for 60Hz)
// For Controlling Servos use 50 and also set PWM_FREQ as 50 (DO NOT USE THESE VALUES FOR DIMMERS)
//#define PWM_LIGHTSCHEME0_IGNORE_SLEEP // Do not change sleep value for LightAnimate() scheme 0
#define DEFAULT_POWER_DELTA 80 // Power change percentage
#define MAX_POWER_HOLD 10 // Time in SECONDS to allow max agreed power
#define MAX_POWER_WINDOW 30 // Time in SECONDS to disable allow max agreed power
#define SAFE_POWER_HOLD 10 // Time in SECONDS to allow max unit safe power
#define SAFE_POWER_WINDOW 30 // Time in MINUTES to disable allow max unit safe power
#define MAX_POWER_RETRY 5 // Retry count allowing agreed power limit overflow
#define STATES 20 // Number of states per second using 50 mSec interval
#define IMMINENT_RESET_FACTOR 10 // Factor to extent button hold time for imminent Reset to default 40 seconds using KEY_HOLD_TIME of 40
#define BOOT_LOOP_TIME 10 // Number of seconds to stop detecting boot loops
#define SYSLOG_TIMER 600 // Seconds to restore syslog_level
#define SERIALLOG_TIMER 600 // Seconds to disable SerialLog
#define OTA_ATTEMPTS 5 // Number of times to try fetching the new firmware
#define INPUT_BUFFER_SIZE 520 // Max number of characters in (serial and http) command buffer
#define CMDSZ 24 // Max number of characters in command
#define TOPSZ 100 // Max number of characters in topic string
#define LOGSZ 520 // Max number of characters in log
#define MIN_MESSZ 893 // Min number of characters in MQTT message
#define SENSOR_MAX_MISS 5 // Max number of missed sensor reads before deciding it's offline
#ifdef USE_MQTT_TLS
#define WEB_LOG_SIZE 2000 // Max number of characters in weblog
#else
#define WEB_LOG_SIZE 4000 // Max number of characters in weblog
#endif
#define MAX_BACKLOG 30 // Max number of commands in backlog
#define MIN_BACKLOG_DELAY 2 // Minimal backlog delay in 0.1 seconds
#define SOFT_BAUDRATE 9600 // Default software serial baudrate
#define APP_BAUDRATE 115200 // Default serial baudrate
#define SERIAL_POLLING 100 // Serial receive polling in ms
#define MAX_STATUS 11 // Max number of status lines
#define DRIVER_BOOT_DELAY 1 // Number of milliseconds to retard driver cycles during boot-up time to reduce overall CPU load whilst Wifi is connecting
#define LOOP_SLEEP_DELAY 50 // Lowest number of milliseconds to go through the main loop using delay when needed
#define NO_EXTRA_4K_HEAP // Allocate 4k heap for WPS in ESP8166/Arduino core v2.4.2 (was always allocated in previous versions)
/*

File diff suppressed because it is too large Load Diff

View File

@ -140,6 +140,7 @@ void KNX_CB_Action(message_t const &msg, void *arg);
#define USE_RF_SENSOR // Add support for RF sensor receiver (434MHz or 868MHz) (+0k8 code)
// #define USE_THEO_V2 // Add support for decoding Theo V2 sensors as documented on https://sidweb.nl using 434MHz RF sensor receiver (+1k4 code)
#define USE_ALECTO_V2 // Add support for decoding Alecto V2 sensors like ACH2010, WS3000 and DKW2012 using 868MHz RF sensor receiver (+1k7 code)
#define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code)
#endif // FIRMWARE_SENSORS
/*********************************************************************************************\
@ -197,6 +198,7 @@ void KNX_CB_Action(message_t const &msg, void *arg);
#undef USE_TX20_WIND_SENSOR // Disable support for La Crosse TX20 anemometer
#undef USE_RC_SWITCH // Disable support for RF transceiver using library RcSwitch
#undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code)
#undef USE_HRE // Disable support for Badger HR-E Water Meter (+1k4 code)
#undef DEBUG_THEO // Disable debug code
#undef USE_DEBUG_DRIVER // Disable debug code
#endif // FIRMWARE_CLASSIC
@ -326,6 +328,7 @@ void KNX_CB_Action(message_t const &msg, void *arg);
#undef USE_TX20_WIND_SENSOR // Disable support for La Crosse TX20 anemometer
#undef USE_RC_SWITCH // Disable support for RF transceiver using library RcSwitch
#undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code)
#undef USE_HRE // Disable support for Badger HR-E Water Meter (+1k4 code)
#undef DEBUG_THEO // Disable debug code
#undef USE_DEBUG_DRIVER // Disable debug code
#endif // FIRMWARE_BASIC
@ -391,6 +394,7 @@ void KNX_CB_Action(message_t const &msg, void *arg);
#undef USE_TX20_WIND_SENSOR // Disable support for La Crosse TX20 anemometer
#undef USE_RC_SWITCH // Disable support for RF transceiver using library RcSwitch
#undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code)
#undef USE_HRE // Disable support for Badger HR-E Water Meter (+1k4 code)
#undef DEBUG_THEO // Disable debug code
#undef USE_DEBUG_DRIVER // Disable debug code
#endif // FIRMWARE_MINIMAL

View File

@ -178,6 +178,8 @@ enum UserSelectablePins {
GPIO_ROT1B, // Rotary switch1 B Pin
GPIO_ROT2A, // Rotary switch2 A Pin
GPIO_ROT2B, // Rotary switch2 B Pin
GPIO_HRE_CLOCK, // Clock/Power line for HR-E Water Meter
GPIO_HRE_DATA, // Data line for HR-E Water Meter
GPIO_SENSOR_END };
// Programmer selectable GPIO functionality
@ -241,6 +243,7 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_CSE7766_TX "|" D_SENSOR_CSE7766_RX "|"
D_SENSOR_ARIRFRCV "|" D_SENSOR_TXD "|" D_SENSOR_RXD "|"
D_SENSOR_ROTARY "1a|" D_SENSOR_ROTARY "1b|" D_SENSOR_ROTARY "2a|" D_SENSOR_ROTARY "2b|"
D_SENSOR_HRE_CLOCK "|" D_SENSOR_HRE_DATA "|"
;
/********************************************************************************************/
@ -335,22 +338,22 @@ typedef struct MYCFGIO {
uint8_t io[MAX_GPIO_PIN - MIN_FLASH_PINS];
} mycfgio;
#define GPIO_FLAG_USED 1 // Currently only one flag used
#define GPIO_FLAG_USED 2 // Currently two flags used
#define GPIO_FLAG_ADC0 1 // Allow ADC0 when define USE_ADC_VCC is disabled
#define GPIO_FLAG_SPARE01 2 // Allow input pull-up control using SetOption62 - Superseded by user template editing
#define GPIO_FLAG_SPARE02 4
#define GPIO_FLAG_SPARE03 8
#define GPIO_FLAG_SPARE04 16
#define GPIO_FLAG_SPARE05 32
#define GPIO_FLAG_SPARE06 64
#define GPIO_FLAG_SPARE07 128
#define GPIO_FLAG_ADC0 1 // Allow ADC0 when define USE_ADC_VCC is disabled
#define GPIO_FLAG_ADC0_TEMP 2 // Allow ADC0 as Temperature sensor when define USE_ADC_VCC is disabled
#define GPIO_FLAG_SPARE02 4
#define GPIO_FLAG_SPARE03 8
#define GPIO_FLAG_SPARE04 16
#define GPIO_FLAG_SPARE05 32
#define GPIO_FLAG_SPARE06 64
#define GPIO_FLAG_SPARE07 128
typedef union {
uint8_t data;
struct {
uint8_t adc0 : 1; // Allow ADC0 when define USE_ADC_VCC is disabled
uint8_t spare01 : 1;
uint8_t adc0 : 1; // Allow ADC0 when define USE_ADC_VCC is disabled
uint8_t adc0_temp : 1; // Allow ADC0 as Temperature sensor when define USE_ADC_VCC is disabled
uint8_t spare02 : 1;
uint8_t spare03 : 1;
uint8_t spare04 : 1;
@ -463,7 +466,9 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_DHT11, // DHT11
GPIO_DHT22, // DHT21, DHT22, AM2301, AM2302, AM2321
GPIO_SI7021, // iTead SI7021
#if defined(USE_DS18B20) || defined(USE_DS18x20) || defined(USE_DS18x20_LEGACY)
GPIO_DSB, // Single wire DS18B20 or DS18S20
#endif
#ifdef USE_WS2812
GPIO_WS2812, // WS2812 Led string
#endif
@ -580,14 +585,22 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_SM16716_DAT, // SM16716 DATA
GPIO_SM16716_SEL, // SM16716 SELECT
#endif // USE_SM16716
#ifdef ROTARY_V1
GPIO_ROT1A, // Rotary switch1 A Pin
GPIO_ROT1B, // Rotary switch1 B Pin
GPIO_ROT2A, // Rotary switch2 A Pin
GPIO_ROT2B, // Rotary switch2 B Pin
GPIO_ARIRFRCV // AliLux RF Receive input
#endif
#ifdef USE_ARILUX_RF
GPIO_ARIRFRCV, // AliLux RF Receive input
#endif
#ifdef USE_HRE
GPIO_HRE_CLOCK,
GPIO_HRE_DATA
#endif
};
const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
const uint8_t kModuleNiceList[] PROGMEM = {
SONOFF_BASIC, // Sonoff Relay Devices
SONOFF_RF,
SONOFF_TH,
@ -639,9 +652,15 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
OBI2,
MANZOKU_EU_4,
ESP_SWITCH, // Switch Devices
#ifdef USE_TUYA_DIMMER
TUYA_DIMMER, // Dimmer Devices
#endif
#ifdef USE_ARMTRONIX_DIMMERS
ARMTRONIX_DIMMERS,
#endif
#ifdef USE_PS_16_DZ
PS_16_DZ,
#endif
H801, // Light Devices
MAGICHOME,
ARILUX_LC01,
@ -649,7 +668,9 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
ARILUX_LC11,
ZENGGE_ZF_WF017,
HUAFAN_SS,
#ifdef ROTARY_V1
MI_DESK_LAMP,
#endif
KMC_70011,
AILIGHT, // Light Bulbs
PHILIPS,

View File

@ -20,11 +20,6 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_
#define VERSION 0x06050001
#define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends"
//#define D_WEBLINK "https://github.com/arendst/Sonoff-Tasmota"
#define D_WEBLINK "https://bit.ly/tasmota"
const uint32_t VERSION = 0x06050007;
#endif // _SONOFF_VERSION_H_

View File

@ -28,7 +28,7 @@ uint32_t syslog_host_hash = 0; // Syslog host name hash
Ticker tickerOSWatch;
#define OSWATCH_RESET_TIME 120
const uint32_t OSWATCH_RESET_TIME = 120;
static unsigned long oswatch_last_loop_time;
uint8_t oswatch_blocked_loop = 0;
@ -108,7 +108,7 @@ void* memchr(const void* ptr, int value, size_t num)
return 0;
}
// http://clc-wiki.net/wiki/C_standard_library:string.h:strspn
// http://clc-wiki.net/wiki/C_standard_library:string.h:strcspn
// Get span until any character in string
size_t strcspn(const char *str1, const char *str2)
{
@ -123,6 +123,77 @@ size_t strcspn(const char *str1, const char *str2)
}
return ret;
}
// https://opensource.apple.com/source/Libc/Libc-583/stdlib/FreeBSD/strtoull.c
// Convert a string to an unsigned long long integer
#ifndef __LONG_LONG_MAX__
#define __LONG_LONG_MAX__ 9223372036854775807LL
#endif
#ifndef ULLONG_MAX
#define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1)
#endif
unsigned long long strtoull(const char *__restrict nptr, char **__restrict endptr, int base)
{
const char *s = nptr;
char c;
do { c = *s++; } while (isspace((unsigned char)c)); // Trim leading spaces
int neg = 0;
if (c == '-') { // Set minus flag and/or skip sign
neg = 1;
c = *s++;
} else {
if (c == '+') {
c = *s++;
}
}
if ((base == 0 || base == 16) && (c == '0') && (*s == 'x' || *s == 'X')) { // Set Hexadecimal
c = s[1];
s += 2;
base = 16;
}
if (base == 0) { base = (c == '0') ? 8 : 10; } // Set Octal or Decimal
unsigned long long acc = 0;
int any = 0;
if (base > 1 && base < 37) {
unsigned long long cutoff = ULLONG_MAX / base;
int cutlim = ULLONG_MAX % base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULLONG_MAX; // Range error
}
else if (any && neg) {
acc = -acc;
}
}
if (endptr != nullptr) { *endptr = (char *)(any ? s - 1 : nptr); }
return acc;
}
#endif // ARDUINO_ESP8266_RELEASE_2_3_0
// Get span until single character in string
@ -139,15 +210,15 @@ size_t strchrspn(const char *str1, int character)
char* subStr(char* dest, char* str, const char *delim, int index)
{
char *act;
char *sub = NULL;
char *sub = nullptr;
char *ptr;
int i;
// Since strtok consumes the first arg, make a copy
strncpy(dest, str, strlen(str)+1);
for (i = 1, act = dest; i <= index; i++, act = NULL) {
for (i = 1, act = dest; i <= index; i++, act = nullptr) {
sub = strtok_r(act, delim, &ptr);
if (sub == NULL) break;
if (sub == nullptr) break;
}
sub = Trim(sub);
return sub;
@ -200,6 +271,27 @@ int TextToInt(char *str)
return strtol(str, &p, radix);
}
char* ulltoa(unsigned long long value, char *str, int radix)
{
char digits[64];
char *dst = str;
int i = 0;
int n = 0;
// if (radix < 2 || radix > 36) { radix = 10; }
do {
n = value % radix;
digits[i++] = (n < 10) ? (char)n+'0' : (char)n-10+'A';
value /= radix;
} while (value != 0);
while (i > 0) { *dst++ = digits[--i]; }
*dst = 0;
return str;
}
char* dtostrfd(double number, unsigned char prec, char *s)
{
if ((isnan(number)) || (isinf(number))) { // Fix for JSON output (https://stackoverflow.com/questions/1423081/json-left-out-infinity-and-nan-json-status-in-ecmascript)
@ -283,6 +375,19 @@ char* RemoveSpace(char* p)
return p;
}
char* LowerCase(char* dest, const char* source)
{
char* write = dest;
const char* read = source;
char ch = '.';
while (ch != '\0') {
ch = *read++;
*write++ = tolower(ch);
}
return dest;
}
char* UpperCase(char* dest, const char* source)
{
char* write = dest;
@ -357,6 +462,14 @@ uint8_t Shortcut(const char* str)
return result;
}
bool ValidIpAddress(const char* str)
{
const char* p = str;
while (*p && ((*p == '.') || ((*p >= '0') && (*p <= '9')))) { p++; }
return (*p == '\0');
}
bool ParseIp(uint32_t* addr, const char* str)
{
uint8_t *part = (uint8_t*)addr;
@ -364,9 +477,9 @@ bool ParseIp(uint32_t* addr, const char* str)
*addr = 0;
for (i = 0; i < 4; i++) {
part[i] = strtoul(str, NULL, 10); // Convert byte
part[i] = strtoul(str, nullptr, 10); // Convert byte
str = strchr(str, '.');
if (str == NULL || *str == '\0') {
if (str == nullptr || *str == '\0') {
break; // No more separators, exit
}
str++; // Point to next character after separator
@ -409,7 +522,7 @@ bool NewerVersion(char* version_str)
return false; // Bail if we can't duplicate. Assume bad.
}
// Loop through the version string, splitting on '.' seperators.
for (char *str = strtok_r(version_dup, ".", &str_ptr); str && i < sizeof(VERSION); str = strtok_r(NULL, ".", &str_ptr), i++) {
for (char *str = strtok_r(version_dup, ".", &str_ptr); str && i < sizeof(VERSION); str = strtok_r(nullptr, ".", &str_ptr), i++) {
int field = atoi(str);
// The fields in a version string can only range from 0-255.
if ((field < 0) || (field > 255)) {
@ -697,6 +810,67 @@ void ShowSource(int source)
}
}
void WebHexCode(uint8_t i, const char* code)
{
char scolor[10];
strlcpy(scolor, code, sizeof(scolor));
char* p = scolor;
if ('#' == p[0]) { p++; } // Skip
if (3 == strlen(p)) { // Convert 3 character to 6 character color code
p[6] = p[3]; // \0
p[5] = p[2]; // 3
p[4] = p[2]; // 3
p[3] = p[1]; // 2
p[2] = p[1]; // 2
p[1] = p[0]; // 1
}
uint32_t color = strtol(p, nullptr, 16);
/*
if (3 == strlen(p)) { // Convert 3 character to 6 character color code
uint32_t w = ((color & 0xF00) << 8) | ((color & 0x0F0) << 4) | (color & 0x00F); // 00010203
color = w | (w << 4); // 00112233
}
*/
Settings.web_color[i][0] = (color >> 16) & 0xFF; // Red
Settings.web_color[i][1] = (color >> 8) & 0xFF; // Green
Settings.web_color[i][2] = color & 0xFF; // Blue
}
uint32_t WebColor(uint8_t i)
{
uint32_t tcolor = (Settings.web_color[i][0] << 16) | (Settings.web_color[i][1] << 8) | Settings.web_color[i][2];
return tcolor;
}
/*********************************************************************************************\
* Response data handling
\*********************************************************************************************/
int Response_P(const char* format, ...) // Content send snprintf_P char data
{
// This uses char strings. Be aware of sending %% if % is needed
va_list args;
va_start(args, format);
int len = vsnprintf_P(mqtt_data, sizeof(mqtt_data), format, args);
va_end(args);
return len;
}
int ResponseAppend_P(const char* format, ...) // Content send snprintf_P char data
{
// This uses char strings. Be aware of sending %% if % is needed
va_list args;
va_start(args, format);
int mlen = strlen(mqtt_data);
int len = vsnprintf_P(mqtt_data + mlen, sizeof(mqtt_data) - mlen, format, args);
va_end(args);
return len + mlen;
}
/*********************************************************************************************\
* GPIO Module and Template management
\*********************************************************************************************/
@ -708,6 +882,22 @@ uint8_t ModuleNr()
return (USER_MODULE == Settings.module) ? 0 : Settings.module +1;
}
bool ValidTemplateModule(uint8_t index)
{
for (uint8_t i = 0; i < sizeof(kModuleNiceList); i++) {
if (index == pgm_read_byte(kModuleNiceList + i)) {
return true;
}
}
return false;
}
bool ValidModule(uint8_t index)
{
if (index == USER_MODULE) { return true; }
return ValidTemplateModule(index);
}
String AnyModuleName(uint8_t index)
{
if (USER_MODULE == index) {
@ -855,6 +1045,10 @@ bool GetUsedInModule(uint8_t val, uint8_t *arr)
bool JsonTemplate(const char* dataBuf)
{
// {"NAME":"Generic","GPIO":[17,254,29,254,7,254,254,254,138,254,139,254,254],"FLAG":1,"BASE":255}
if (strlen(dataBuf) < 9) { return false; } // Workaround exception if empty JSON like {} - Needs checks
StaticJsonBuffer<350> jb; // 331 from https://arduinojson.org/v5/assistant/
JsonObject& obj = jb.parseObject(dataBuf);
if (!obj.success()) { return false; }
@ -875,20 +1069,19 @@ bool JsonTemplate(const char* dataBuf)
}
if (obj[D_JSON_BASE].success()) {
uint8_t base = obj[D_JSON_BASE];
if ((0 == base) || (base >= MAXMODULE)) { base = 17; } else { base--; }
Settings.user_template_base = base; // Default WEMOS
if ((0 == base) || !ValidTemplateModule(base -1)) { base = 18; }
Settings.user_template_base = base -1; // Default WEMOS
}
return true;
}
void TemplateJson()
{
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), Settings.user_template.name);
Response_P(PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), Settings.user_template.name);
for (uint8_t i = 0; i < sizeof(Settings.user_template.gp); i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (i>0)?",":"", Settings.user_template.gp.io[i]);
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Settings.user_template.gp.io[i]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"),
mqtt_data, Settings.user_template.flag, Settings.user_template_base +1);
ResponseAppend_P(PSTR("],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), Settings.user_template.flag, Settings.user_template_base +1);
}
/*********************************************************************************************\
@ -959,7 +1152,7 @@ void SetNextTimeInterval(unsigned long& timer, const unsigned long step)
\*********************************************************************************************/
#ifdef USE_I2C
#define I2C_RETRY_COUNTER 3
const uint8_t I2C_RETRY_COUNTER = 3;
uint32_t i2c_buffer = 0;
@ -1182,7 +1375,7 @@ void SetSeriallog(uint8_t loglevel)
#ifdef USE_WEBSERVER
void GetLog(uint8_t idx, char** entry_pp, size_t* len_p)
{
char* entry_p = NULL;
char* entry_p = nullptr;
size_t len = 0;
if (idx) {
@ -1210,8 +1403,9 @@ void Syslog(void)
// Destroys log_data
char syslog_preamble[64]; // Hostname + Id
if (syslog_host_hash != GetHash(Settings.syslog_host, strlen(Settings.syslog_host))) {
syslog_host_hash = GetHash(Settings.syslog_host, strlen(Settings.syslog_host));
uint32_t current_hash = GetHash(Settings.syslog_host, strlen(Settings.syslog_host));
if (syslog_host_hash != current_hash) {
syslog_host_hash = current_hash;
WiFi.hostByName(Settings.syslog_host, syslog_host_addr); // If sleep enabled this might result in exception so try to do it once using hash
}
if (PortUdp.beginPacket(syslog_host_addr, Settings.syslog_port)) {
@ -1221,6 +1415,7 @@ void Syslog(void)
memcpy(log_data, syslog_preamble, strlen(syslog_preamble));
PortUdp.write(log_data);
PortUdp.endPacket();
delay(1); // Add time for UDP handling (#5512)
} else {
syslog_level = 0;
syslog_timer = SYSLOG_TIMER;

View File

@ -382,12 +382,14 @@ void GetFeatures(void)
feature_sns2 |= 0x00100000; // xsns_40_pn532.ino
#endif
#ifdef USE_MAX44009
feature_sns2 |= 0x00200000;
feature_sns2 |= 0x00200000; // xsns_41_max44009.ino
#endif
#ifdef USE_SCD30
feature_sns2 |= 0x00400000;
feature_sns2 |= 0x00400000; // xsns_42_scd30.ino
#endif
#ifdef USE_HRE
feature_sns2 |= 0x00800000; // xsns_43_hre.ino
#endif
// feature_sns2 |= 0x00800000;
// feature_sns2 |= 0x01000000;
// feature_sns2 |= 0x02000000;
// feature_sns2 |= 0x04000000;

View File

@ -17,8 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define ROTARY_V1
#ifdef ROTARY_V1
/*********************************************************************************************\
* Rotary support
\*********************************************************************************************/
@ -31,6 +30,9 @@ uint8_t rotary_last_position = 128;
uint8_t interrupts_in_use = 0;
uint8_t rotary_changed = 0;
//#define ROTARY_V1
#ifdef ROTARY_V1
/********************************************************************************************/
void update_position(void)

View File

@ -22,10 +22,11 @@
* Timezone by Jack Christensen (https://github.com/JChristensen/Timezone)
\*********************************************************************************************/
#define SECS_PER_MIN ((uint32_t)(60UL))
#define SECS_PER_HOUR ((uint32_t)(3600UL))
#define SECS_PER_DAY ((uint32_t)(SECS_PER_HOUR * 24UL))
#define MINS_PER_HOUR ((uint32_t)(60UL))
const uint32_t SECS_PER_MIN = 60UL;
const uint32_t SECS_PER_HOUR = 3600UL;
const uint32_t SECS_PER_DAY = SECS_PER_HOUR * 24UL;
const uint32_t MINS_PER_HOUR = 60UL;
#define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400)))
extern "C" {
@ -61,7 +62,7 @@ String GetBuildDateAndTime(void)
// sscanf(mdate, "%s %d %d", bdt, &day, &year); // Not implemented in 2.3.0 and probably too much code
uint8_t i = 0;
for (char *str = strtok_r(mdate, " ", &p); str && i < 3; str = strtok_r(NULL, " ", &p)) {
for (char *str = strtok_r(mdate, " ", &p); str && i < 3; str = strtok_r(nullptr, " ", &p)) {
switch (i++) {
case 0: // Month
smonth = str;

View File

@ -25,7 +25,7 @@
* Inspired by (https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/master/olimex/user/user_switch2.c)
\*********************************************************************************************/
#define SWITCH_PROBE_INTERVAL 10 // Time in milliseconds between switch input probe
const uint8_t SWITCH_PROBE_INTERVAL = 10; // Time in milliseconds between switch input probe
#include <Ticker.h>

View File

@ -22,15 +22,15 @@
\*********************************************************************************************/
#ifndef WIFI_RSSI_THRESHOLD
#define WIFI_RSSI_THRESHOLD 10 // Difference in dB between current network and scanned network
#define WIFI_RSSI_THRESHOLD 10 // Difference in dB between current network and scanned network
#endif
#ifndef WIFI_RESCAN_MINUTES
#define WIFI_RESCAN_MINUTES 44 // Number of minutes between wifi network rescan
#define WIFI_RESCAN_MINUTES 44 // Number of minutes between wifi network rescan
#endif
#define WIFI_CONFIG_SEC 180 // seconds before restart
#define WIFI_CHECK_SEC 20 // seconds
#define WIFI_RETRY_OFFSET_SEC 20 // seconds
const uint8_t WIFI_CONFIG_SEC = 180; // seconds before restart
const uint8_t WIFI_CHECK_SEC = 20; // seconds
const uint8_t WIFI_RETRY_OFFSET_SEC = 20; // seconds
/*
// This worked for 2_5_0_BETA2 but fails since then. Waiting for a solution from core team (#4952)

View File

@ -27,21 +27,21 @@
#define XDRV_01 1
#define CHUNKED_BUFFER_SIZE 400 // Chunk buffer size
#ifndef WIFI_SOFT_AP_CHANNEL
#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 11 as used by SmartConfig web GUI
#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 11 as used by SmartConfig web GUI
#endif
#define HTTP_REFRESH_TIME 2345 // milliseconds
#define HTTP_RESTART_RECONNECT_TIME 9000 // milliseconds
#define HTTP_OTA_RESTART_RECONNECT_TIME 20000 // milliseconds
const uint16_t CHUNKED_BUFFER_SIZE = 400; // Chunk buffer size (should be smaller than half mqtt_date size)
const uint16_t HTTP_REFRESH_TIME = 2345; // milliseconds
#define HTTP_RESTART_RECONNECT_TIME 9000 // milliseconds
#define HTTP_OTA_RESTART_RECONNECT_TIME 20000 // milliseconds
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#ifdef USE_RF_FLASH
uint8_t *efm8bb1_update = NULL;
uint8_t *efm8bb1_update = nullptr;
#endif // USE_RF_FLASH
enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1 };
@ -239,21 +239,21 @@ const char HTTP_HEAD_STYLE1[] PROGMEM =
"<style>"
"div,fieldset,input,select{padding:5px;font-size:1em;}"
"fieldset{background-color:#f2f2f2;}" // Also update HTTP_TIMER_STYLE
"fieldset{background:#%06x;}" // COLOR_FORM, Also update HTTP_TIMER_STYLE
"p{margin:0.5em 0;}"
"input{width:100%%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;}"
"input{width:100%%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;background:#%06x;color:#%06x;}" // COLOR_INPUT, COLOR_INPUT_TEXT
"input[type=checkbox],input[type=radio]{width:1em;margin-right:6px;vertical-align:-1px;}"
"select{width:100%%;}"
"textarea{resize:none;width:98%%;height:318px;padding:5px;overflow:auto;}"
"body{text-align:center;font-family:verdana;}"
"select{width:100%%;background:#%06x;color:#%06x;}" // COLOR_INPUT, COLOR_INPUT_TEXT
"textarea{resize:none;width:98%%;height:318px;padding:5px;overflow:auto;background:#%06x;color:#%06x;}" // COLOR_CONSOLE, COLOR_CONSOLE_TEXT
"body{text-align:center;font-family:verdana;background:#%06x;}" // COLOR_BACKGROUND
"td{padding:0px;}";
const char HTTP_HEAD_STYLE2[] PROGMEM =
"button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%%;-webkit-transition-duration:0.4s;transition-duration:0.4s;cursor:pointer;}"
"button:hover{background-color:#0e70a4;}"
".bred{background-color:#d43535;}"
".bred:hover{background-color:#931f1f;}"
".bgrn{background-color:#47c266;}"
".bgrn:hover{background-color:#5aaf6f;}"
"button{border:0;border-radius:0.3rem;background:#%06x;color:#%06x;line-height:2.4rem;font-size:1.2rem;width:100%%;-webkit-transition-duration:0.4s;transition-duration:0.4s;cursor:pointer;}" // COLOR_BUTTON, COLOR_BUTTON_TEXT
"button:hover{background:#%06x;}" // COLOR_BUTTON_HOVER
".bred{background:#%06x;}" // COLOR_BUTTON_RESET
".bred:hover{background:#%06x;}" // COLOR_BUTTON_RESET_HOVER
".bgrn{background:#%06x;}" // COLOR_BUTTON_SAVE
".bgrn:hover{background:#%06x;}" // COLOR_BUTTON_SAVE_HOVER
"a{text-decoration:none;}"
".p{float:left;text-align:left;}"
".q{float:right;text-align:right;}";
@ -262,9 +262,9 @@ const char HTTP_HEAD_STYLE3[] PROGMEM =
"</head>"
"<body>"
"<div style='text-align:left;display:inline-block;min-width:340px;'>"
"<div style='text-align:left;display:inline-block;color:#%06x;min-width:340px;'>" // COLOR_TEXT
#ifdef FIRMWARE_MINIMAL
"<div style='text-align:center;color:red;'><h3>" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "</h3></div>"
"<div style='text-align:center;color:#%06x;'><h3>" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "</h3></div>" // COLOR_TEXT_WARNING
#endif
"<div style='text-align:center;'><noscript>" D_NOSCRIPT "<br/></noscript>"
#ifdef LANGUAGE_MODULE_NAME
@ -299,6 +299,7 @@ const char HTTP_FORM_TEMPLATE_FLAG[] PROGMEM =
"<p></p>" // Keep close so do not use <br/>
"<fieldset><legend><b>&nbsp;" D_TEMPLATE_FLAGS "&nbsp;</b></legend><p>"
"<input id='c0' name='c0' type='checkbox'><b>" D_ALLOW_ADC0 "</b><br/>"
"<input id='c1' name='c1' type='checkbox'><b>" D_ALLOW_ADC0_TEMP "</b><br/>"
"</p></fieldset>";
const char HTTP_FORM_MODULE[] PROGMEM =
@ -333,7 +334,7 @@ const char HTTP_FORM_OTHER[] PROGMEM =
"<p><input id='t2' name='t2' type='checkbox'%s><b>" D_ACTIVATE "</b></p>"
"</fieldset>"
"<br/>"
"<b>" D_WEB_ADMIN_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_WEB_ADMIN_PASSWORD "' value='" D_ASTERIX "'><br/>"
"<b>" D_WEB_ADMIN_PASSWORD "</b><br/><input id='wp' name='wp' type='password' placeholder='" D_WEB_ADMIN_PASSWORD "' value='" D_ASTERIX "'><br/>"
"<br>"
"<input id='b1' name='b1' type='checkbox'%s><b>" D_MQTT_ENABLE "</b><br/>"
"<br/>";
@ -376,7 +377,7 @@ const char HTTP_COUNTER[] PROGMEM =
"<br/><div id='t' name='t' style='text-align:center;'></div>";
const char HTTP_END[] PROGMEM =
"<div style='text-align:right;font-size:11px;'><hr/><a href='" D_WEBLINK "' target='_blank' style='color:#aaa;'>" D_PROGRAMNAME " %s " D_BY " " D_AUTHOR "</a></div>"
"<div style='text-align:right;font-size:11px;'><hr/><a href='https://bit.ly/tasmota' target='_blank' style='color:#aaa;'>Sonoff-Tasmota %s " D_BY " Theo Arends</a></div>"
"</div>"
"</body>"
"</html>";
@ -413,7 +414,7 @@ const char kUploadErrors[] PROGMEM =
#endif
;
#define DNS_PORT 53
const uint16_t DNS_PORT = 53;
enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER, HTTP_MANAGER_RESET_ONLY};
DNSServer *DnsServer;
@ -494,6 +495,7 @@ void StartWebserver(int type, IPAddress ipweb)
}
if (webserver_state != type) {
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), my_hostname, (mdns_begun) ? ".local" : "", ipweb.toString().c_str());
rules_flag.http_init = 1;
}
if (type) { webserver_state = type; }
}
@ -524,7 +526,7 @@ void WifiManagerBegin(bool reset_only)
int channel = WIFI_SOFT_AP_CHANNEL;
if ((channel < 1) || (channel > 13)) { channel = 1; }
WiFi.softAP(my_hostname, NULL, channel);
WiFi.softAP(my_hostname, nullptr, channel);
delay(500); // Without delay I've seen the IP address blank
/* Setup the DNS server redirecting all the domains to the apIP */
@ -689,7 +691,7 @@ void WSContentStart_P(const char* title, bool auth)
WSContentBegin(200, CT_HTML);
if (title != NULL) {
if (title != nullptr) {
char ctitle[strlen_P(title) +1];
strcpy_P(ctitle, title); // Get title from flash to RAM
WSContentSend_P(HTTP_HEAD, Settings.friendlyname[0], ctitle);
@ -701,19 +703,28 @@ void WSContentStart_P(const char* title)
WSContentStart_P(title, true);
}
void WSContentSendStyle_P(const char* style)
void WSContentSendStyle_P(const char* formatP, ...)
{
if (WifiIsInManagerMode()) {
if (WifiConfigCounter()) {
WSContentSend_P(HTTP_SCRIPT_COUNTER);
}
}
WSContentSend_P(HTTP_HEAD_STYLE1);
WSContentSend_P(HTTP_HEAD_STYLE2);
if (style != NULL) {
WSContentSend_P(style);
WSContentSend_P(HTTP_HEAD_STYLE1, WebColor(COL_FORM), WebColor(COL_INPUT), WebColor(COL_INPUT_TEXT), WebColor(COL_INPUT), WebColor(COL_INPUT_TEXT), WebColor(COL_CONSOLE), WebColor(COL_CONSOLE_TEXT), WebColor(COL_BACKGROUND));
WSContentSend_P(HTTP_HEAD_STYLE2, WebColor(COL_BUTTON), WebColor(COL_BUTTON_TEXT), WebColor(COL_BUTTON_HOVER), WebColor(COL_BUTTON_RESET), WebColor(COL_BUTTON_RESET_HOVER), WebColor(COL_BUTTON_SAVE), WebColor(COL_BUTTON_SAVE_HOVER));
if (formatP != nullptr) {
// This uses char strings. Be aware of sending %% if % is needed
va_list arg;
va_start(arg, formatP);
vsnprintf_P(mqtt_data, sizeof(mqtt_data), formatP, arg);
va_end(arg);
_WSContentSendBuffer();
}
WSContentSend_P(HTTP_HEAD_STYLE3, ModuleName().c_str(), Settings.friendlyname[0]);
WSContentSend_P(HTTP_HEAD_STYLE3, WebColor(COL_TEXT),
#ifdef FIRMWARE_MINIMAL
WebColor(COL_TEXT_WARNING),
#endif
ModuleName().c_str(), Settings.friendlyname[0]);
if (Settings.flag3.gui_hostname_ip) {
bool lip = (static_cast<uint32_t>(WiFi.localIP()) != 0);
bool sip = (static_cast<uint32_t>(WiFi.softAPIP()) != 0);
@ -729,7 +740,7 @@ void WSContentSendStyle_P(const char* style)
void WSContentSendStyle(void)
{
WSContentSendStyle_P(NULL);
WSContentSendStyle_P(nullptr);
}
void WSContentButton(uint8_t title_index)
@ -1038,7 +1049,7 @@ void HandleTemplateConfiguration(void)
if (WebServer->hasArg("m")) {
WSContentBegin(200, CT_PLAIN);
for (uint8_t i = 0; i < MAXMODULE; i++) { // "}2'%d'>%s (%d)}3" - "}2'0'>Sonoff Basic (1)}3"
for (uint8_t i = 0; i < sizeof(kModuleNiceList); i++) { // "}2'%d'>%s (%d)}3" - "}2'0'>Sonoff Basic (1)}3"
uint8_t midx = pgm_read_byte(kModuleNiceList + i);
WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, midx, AnyModuleName(midx).c_str(), midx +1);
}
@ -1093,10 +1104,9 @@ void HandleTemplateConfiguration(void)
"<hr/>"));
WSContentSend_P(HTTP_TABLE100);
for (uint8_t i = 0; i < 17; i++) {
if ((i < 6) || ((i > 8) && (i != 11))) { // Ignore flash pins GPIO06, 7, 8 and 11
bool esp8285 = ((9==i)||(10==i));
WSContentSend_P(PSTR("<tr><td><b>%s" D_GPIO "%d%s</b></td><td%s><select id='g%d' name='g%d'></select></td></tr>"),
(esp8285) ? "<font color='red'>" : "", i, (esp8285) ? "</font>" : "", (0==i) ? " style='width:200px'" : "", i, i);
if ((i < 6) || ((i > 8) && (i != 11))) { // Ignore flash pins GPIO06, 7, 8 and 11
WSContentSend_P(PSTR("<tr><td><b><font color='#%06x'>" D_GPIO "%d</font></b></td><td%s><select id='g%d' name='g%d'></select></td></tr>"),
((9==i)||(10==i)) ? WebColor(COL_TEXT_WARNING) : WebColor(COL_TEXT), i, (0==i) ? " style='width:200px'" : "", i, i);
}
}
WSContentSend_P(PSTR("</table>"));
@ -1159,7 +1169,7 @@ void HandleModuleConfiguration(void)
if (WebServer->hasArg("m")) {
WSContentBegin(200, CT_PLAIN);
uint8_t vidx = 0;
for (uint8_t i = 0; i <= MAXMODULE; i++) { // "}2'%d'>%s (%d)}3" - "}2'255'>UserTemplate (0)}3" - "}2'0'>Sonoff Basic (1)}3"
for (uint8_t i = 0; i <= sizeof(kModuleNiceList); i++) { // "}2'%d'>%s (%d)}3" - "}2'255'>UserTemplate (0)}3" - "}2'0'>Sonoff Basic (1)}3"
if (0 == i) {
midx = USER_MODULE;
vidx = 0;
@ -1201,8 +1211,10 @@ void HandleModuleConfiguration(void)
for (uint8_t i = 0; i < sizeof(cmodule); i++) {
if (ValidGPIO(i, cmodule.io[i])) {
snprintf_P(stemp, 3, PINS_WEMOS +i*2);
char sesp8285[40];
snprintf_P(sesp8285, sizeof(sesp8285), PSTR("<font color='#%06x'>ESP8285</font>"), WebColor(COL_TEXT_WARNING));
WSContentSend_P(PSTR("<tr><td style='width:190px'>%s <b>" D_GPIO "%d</b> %s</td><td style='width:176px'><select id='g%d' name='g%d'></select></td></tr>"),
(WEMOS==my_module_type)?stemp:"", i, (0==i)? D_SENSOR_BUTTON "1":(1==i)? D_SERIAL_OUT :(3==i)? D_SERIAL_IN :((9==i)||(10==i))? "<font color='red'>ESP8285</font>" :(12==i)? D_SENSOR_RELAY "1":(13==i)? D_SENSOR_LED "1i":(14==i)? D_SENSOR :"", i, i);
(WEMOS==my_module_type)?stemp:"", i, (0==i)? D_SENSOR_BUTTON "1":(1==i)? D_SERIAL_OUT :(3==i)? D_SERIAL_IN :((9==i)||(10==i))? sesp8285 :(12==i)? D_SENSOR_RELAY "1":(13==i)? D_SENSOR_LED "1i":(14==i)? D_SENSOR :"", i, i);
}
}
WSContentSend_P(PSTR("</table>"));
@ -1359,7 +1371,7 @@ void WifiSaveSettings(void)
WebGetArg("h", tmp, sizeof(tmp));
strlcpy(Settings.hostname, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp, sizeof(Settings.hostname));
if (strstr(Settings.hostname,"%")) {
if (strstr(Settings.hostname, "%") != nullptr) {
strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname));
}
WebGetArg("s1", tmp, sizeof(tmp));
@ -1494,7 +1506,7 @@ void OtherSaveSettings(void)
char webindex[5];
char friendlyname[sizeof(Settings.friendlyname[0])];
WebGetArg("p1", tmp, sizeof(tmp));
WebGetArg("wp", tmp, sizeof(tmp));
strlcpy(Settings.web_password, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.web_password : tmp, sizeof(Settings.web_password));
Settings.flag.mqtt_enabled = WebServer->hasArg("b1");
#ifdef USE_EMULATION
@ -1769,9 +1781,10 @@ void HandleUploadDone(void)
WSContentSend_P(HTTP_SCRIPT_RELOAD_OTA); // Refesh main web ui after OTA upgrade
}
WSContentSendStyle();
WSContentSend_P(PSTR("<div style='text-align:center;'><b>" D_UPLOAD " <font color='"));
WSContentSend_P(PSTR("<div style='text-align:center;'><b>" D_UPLOAD " <font color='#"));
if (upload_error) {
WSContentSend_P(PSTR("red'>" D_FAILED "</font></b><br/><br/>"));
// WSContentSend_P(PSTR(COLOR_TEXT_WARNING "'>" D_FAILED "</font></b><br/><br/>"));
WSContentSend_P(PSTR("%06x'>" D_FAILED "</font></b><br/><br/>"), WebColor(COL_TEXT_WARNING));
#ifdef USE_RF_FLASH
if (upload_error < 14) {
#else
@ -1785,7 +1798,7 @@ void HandleUploadDone(void)
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_UPLOAD ": %s"), error);
stop_flash_rotate = Settings.flag.stop_flash_rotate;
} else {
WSContentSend_P(PSTR("green'>" D_SUCCESSFUL "</font></b><br/>"));
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "</font></b><br/>"), WebColor(COL_TEXT_SUCCESS));
WSContentSend_P(HTTP_MSG_RSTRT);
ShowWebSource(SRC_WEBGUI);
restart_flag = 2; // Always restart to re-enable disabled features during update
@ -1885,10 +1898,10 @@ void HandleUploadLoop(void)
}
#ifdef USE_RF_FLASH
else if (UPL_EFM8BB1 == upload_file_type) {
if (efm8bb1_update != NULL) { // We have carry over data since last write, i. e. a start but not an end
if (efm8bb1_update != nullptr) { // We have carry over data since last write, i. e. a start but not an end
ssize_t result = rf_glue_remnant_with_new_data_and_write(efm8bb1_update, upload.buf, upload.currentSize);
free(efm8bb1_update);
efm8bb1_update = NULL;
efm8bb1_update = nullptr;
if (result != 0) {
upload_error = abs(result); // 2 = Not enough space, 8 = File invalid
return;
@ -1907,7 +1920,7 @@ void HandleUploadLoop(void)
// A remnant has been detected, allocate data for it plus a null termination byte
size_t remnant_sz = upload.currentSize - result;
efm8bb1_update = (uint8_t *) malloc(remnant_sz + 1);
if (efm8bb1_update == NULL) {
if (efm8bb1_update == nullptr) {
upload_error = 2; // Not enough space - Unable to allocate memory to store new RF firmware
return;
}
@ -2136,20 +2149,20 @@ void HandleNotFound(void)
} else
#endif // USE_EMULATION
{
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"),
WebServer->uri().c_str(), (WebServer->method() == HTTP_GET) ? "GET" : "POST", WebServer->args());
WSContentBegin(404, CT_PLAIN);
WSContentSend_P(PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"), WebServer->uri().c_str(), (WebServer->method() == HTTP_GET) ? "GET" : "POST", WebServer->args());
for (uint8_t i = 0; i < WebServer->args(); i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s %s: %s\n"), mqtt_data, WebServer->argName(i).c_str(), WebServer->arg(i).c_str());
WSContentSend_P(PSTR(" %s: %s\n"), WebServer->argName(i).c_str(), WebServer->arg(i).c_str());
}
WSHeaderSend();
WSSend(404, CT_PLAIN, mqtt_data);
WSContentEnd();
}
}
/* Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */
bool CaptivePortal(void)
{
if ((WifiIsInManagerMode()) && !ValidIpAddress(WebServer->hostHeader())) {
// Possible hostHeader: connectivitycheck.gstatic.com or 192.168.4.1
if ((WifiIsInManagerMode()) && !ValidIpAddress(WebServer->hostHeader().c_str())) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED));
WebServer->sendHeader(F("Location"), String("http://") + WebServer->client().localIP().toString(), true);
@ -2160,16 +2173,6 @@ bool CaptivePortal(void)
return false;
}
/** Is this an IP? */
bool ValidIpAddress(String str)
{
for (uint16_t i = 0; i < str.length(); i++) {
int c = str.charAt(i);
if (c != '.' && (c < '0' || c > '9')) { return false; }
}
return true;
}
/*********************************************************************************************/
String UrlEncode(const String& text)
@ -2285,8 +2288,36 @@ int WebSend(char *buffer)
/*********************************************************************************************/
enum WebCommands { CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_WEBREFRESH, CMND_WEBSEND, CMND_EMULATION };
const char kWebCommands[] PROGMEM = D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_EMULATION ;
bool JsonWebColor(const char* dataBuf)
{
// Default (light)
// {"WebColor":["#000000","#ffffff","#f2f2f2","#000000","#ffffff","#000000","#ffffff","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]}
// Alternative (Dark)
// {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]}
char dataBufLc[strlen(dataBuf) +1];
LowerCase(dataBufLc, dataBuf);
RemoveSpace(dataBufLc);
if (strlen(dataBufLc) < 9) { return false; } // Workaround exception if empty JSON like {} - Needs checks
StaticJsonBuffer<450> jb; // 421 from https://arduinojson.org/v5/assistant/
JsonObject& obj = jb.parseObject(dataBufLc);
if (!obj.success()) { return false; }
char parm_lc[10];
if (obj[LowerCase(parm_lc, D_CMND_WEBCOLOR)].success()) {
for (uint8_t i = 0; i < COL_LAST; i++) {
const char* color = obj[parm_lc][i];
if (color != nullptr) {
WebHexCode(i, color);
}
}
}
return true;
}
enum WebCommands { CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_WEBREFRESH, CMND_WEBSEND, CMND_WEBCOLOR, CMND_EMULATION };
const char kWebCommands[] PROGMEM = D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_WEBCOLOR "|" D_CMND_EMULATION ;
const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND ;
bool WebCommand(void)
@ -2301,42 +2332,63 @@ bool WebCommand(void)
if (CMND_WEBSERVER == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { Settings.webserver = XdrvMailbox.payload; }
if (Settings.webserver) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_WEBSERVER "\":\"" D_JSON_ACTIVE_FOR " %s " D_JSON_ON_DEVICE " %s " D_JSON_WITH_IP_ADDRESS " %s\"}"),
Response_P(PSTR("{\"" D_CMND_WEBSERVER "\":\"" D_JSON_ACTIVE_FOR " %s " D_JSON_ON_DEVICE " %s " D_JSON_WITH_IP_ADDRESS " %s\"}"),
(2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str());
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(0));
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(0));
}
}
else if (CMND_WEBPASSWORD == command_code) {
if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.data_len < sizeof(Settings.web_password))) {
strlcpy(Settings.web_password, (SC_CLEAR == Shortcut(XdrvMailbox.data)) ? "" : (SC_DEFAULT == Shortcut(XdrvMailbox.data)) ? WEB_PASSWORD : XdrvMailbox.data, sizeof(Settings.web_password));
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.web_password);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.web_password);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_ASTERIX, command);
Response_P(S_JSON_COMMAND_ASTERIX, command);
}
}
else if (CMND_WEBLOG == command_code) {
if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_ALL)) { Settings.weblog_level = XdrvMailbox.payload; }
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.weblog_level);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.weblog_level);
}
else if (CMND_WEBREFRESH == command_code) {
if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload <= 10000)) { Settings.web_refresh = XdrvMailbox.payload; }
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.web_refresh);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.web_refresh);
}
else if (CMND_WEBSEND == command_code) {
if (XdrvMailbox.data_len > 0) {
uint8_t result = WebSend(XdrvMailbox.data);
char stemp1[20];
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetTextIndexed(stemp1, sizeof(stemp1), result, kWebSendStatus));
Response_P(S_JSON_COMMAND_SVALUE, command, GetTextIndexed(stemp1, sizeof(stemp1), result, kWebSendStatus));
}
}
else if (CMND_WEBCOLOR == command_code) {
if (XdrvMailbox.data_len > 0) {
if (strstr(XdrvMailbox.data, "{") == nullptr) { // If no JSON it must be parameter
if ((XdrvMailbox.data_len > 3) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= COL_LAST)) {
WebHexCode(XdrvMailbox.index -1, XdrvMailbox.data);
}
else if (0 == XdrvMailbox.payload) {
SettingsDefaultWebColor();
}
}
else {
JsonWebColor(XdrvMailbox.data);
}
}
Response_P(PSTR("{\"" D_CMND_WEBCOLOR "\":["));
for (uint8_t i = 0; i < COL_LAST; i++) {
if (i) { ResponseAppend_P(PSTR(",")); }
ResponseAppend_P(PSTR("\"#%06x\""), WebColor(i));
}
ResponseAppend_P(PSTR("]}"));
}
#ifdef USE_EMULATION
else if (CMND_EMULATION == command_code) {
if ((XdrvMailbox.payload >= EMUL_NONE) && (XdrvMailbox.payload < EMUL_MAX)) {
Settings.flag2.emulation = XdrvMailbox.payload;
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.emulation);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.flag2.emulation);
}
#endif // USE_EMULATION
else serviced = false; // Unknown command
@ -2356,7 +2408,7 @@ bool Xdrv01(uint8_t function)
case FUNC_LOOP:
PollDnsWebserver();
#ifdef USE_EMULATION
if (Settings.flag2.emulation) PollUdp();
if (Settings.flag2.emulation) { PollUdp(); }
#endif // USE_EMULATION
break;
case FUNC_COMMAND:

View File

@ -37,6 +37,9 @@ const char kMqttCommands[] PROGMEM =
D_CMND_MQTTUSER "|" D_CMND_MQTTPASSWORD "|" D_CMND_FULLTOPIC "|" D_CMND_PREFIX "|" D_CMND_GROUPTOPIC "|" D_CMND_TOPIC "|" D_CMND_PUBLISH "|"
D_CMND_BUTTONTOPIC "|" D_CMND_SWITCHTOPIC "|" D_CMND_BUTTONRETAIN "|" D_CMND_SWITCHRETAIN "|" D_CMND_POWERRETAIN "|" D_CMND_SENSORRETAIN ;
IPAddress mqtt_host_addr; // MQTT host IP address
uint32_t mqtt_host_hash = 0; // MQTT host name hash
uint16_t mqtt_connect_count = 0; // MQTT re-connect count
uint16_t mqtt_retry_counter = 1; // MQTT connection retry counter
uint8_t mqtt_initial_connection_state = 2; // MQTT connection messages state
@ -50,7 +53,6 @@ bool mqtt_allowed = false; // MQTT enabled and parameters valid
* void MqttDisconnect()
* void MqttSubscribeLib(char *topic)
* bool MqttPublishLib(const char* topic, bool retained)
* void MqttLoop()
\*********************************************************************************************/
#include <PubSubClient.h>
@ -91,11 +93,6 @@ bool MqttPublishLib(const char* topic, bool retained)
return result;
}
void MqttLoop(void)
{
MqttClient.loop();
}
/*********************************************************************************************/
#ifdef USE_DISCOVERY
@ -237,17 +234,17 @@ void MqttPublishPowerState(uint8_t device)
#endif // USE_DOMOTICZ
snprintf_P(scommand, sizeof(scommand), PSTR(D_CMND_FANSPEED));
GetTopic_P(stopic, STAT, mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, scommand, GetFanspeed());
Response_P(S_JSON_COMMAND_NVALUE, scommand, GetFanspeed());
MqttPublish(stopic);
}
} else {
GetPowerDevice(scommand, device, sizeof(scommand), Settings.flag.device_index_enable);
GetTopic_P(stopic, STAT, mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, scommand, GetStateText(bitRead(power, device -1)));
Response_P(S_JSON_COMMAND_SVALUE, scommand, GetStateText(bitRead(power, device -1)));
MqttPublish(stopic);
GetTopic_P(stopic, STAT, mqtt_topic, scommand);
snprintf_P(mqtt_data, sizeof(mqtt_data), GetStateText(bitRead(power, device -1)));
Response_P(GetStateText(bitRead(power, device -1)));
MqttPublish(stopic, Settings.flag.mqtt_power_retain);
}
}
@ -259,7 +256,7 @@ void MqttPublishPowerBlinkState(uint8_t device)
if ((device < 1) || (device > devices_present)) {
device = 1;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"" D_JSON_BLINK " %s\"}"),
Response_P(PSTR("{\"%s\":\"" D_JSON_BLINK " %s\"}"),
GetPowerDevice(scommand, device, sizeof(scommand), Settings.flag.device_index_enable), GetStateText(bitRead(blink_mask, device -1)));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, S_RSLT_POWER);
@ -292,7 +289,7 @@ void MqttConnected(void)
mqtt_connect_count++;
GetTopic_P(stopic, TELE, mqtt_topic, S_LWT);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_ONLINE));
Response_P(PSTR(D_ONLINE));
MqttPublish(stopic, true);
// Satisfy iobroker (#299)
@ -301,7 +298,7 @@ void MqttConnected(void)
GetTopic_P(stopic, CMND, mqtt_topic, PSTR("#"));
MqttSubscribe(stopic);
if (strstr(Settings.mqtt_fulltopic, MQTT_TOKEN_TOPIC) != NULL) {
if (strstr_P(Settings.mqtt_fulltopic, MQTT_TOKEN_TOPIC) != nullptr) {
GetTopic_P(stopic, CMND, Settings.mqtt_grptopic, PSTR("#"));
MqttSubscribe(stopic);
GetFallbackTopic_P(stopic, CMND, PSTR("#"));
@ -312,18 +309,17 @@ void MqttConnected(void)
}
if (mqtt_initial_connection_state) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}"),
Response_P(PSTR("{\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}"),
ModuleName().c_str(), my_version, my_image, GetFallbackTopic_P(stopic, CMND, ""), Settings.mqtt_grptopic);
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "1"));
#ifdef USE_WEBSERVER
if (Settings.webserver) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"),
Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"),
(2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str());
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "2"));
}
#endif // USE_WEBSERVER
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_RESTARTREASON "\":\"%s\"}"),
(GetResetReason() == "Exception") ? ESP.getResetInfo().c_str() : GetResetReason().c_str());
Response_P(PSTR("{\"" D_JSON_RESTARTREASON "\":\"%s\"}"), (GetResetReason() == "Exception") ? ESP.getResetInfo().c_str() : GetResetReason().c_str());
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "3"));
for (uint8_t i = 1; i <= devices_present; i++) {
MqttPublishPowerState(i);
@ -432,13 +428,13 @@ void MqttReconnect(void)
mqtt_retry_counter = Settings.mqtt_retry;
global_state.mqtt_down = 1;
char *mqtt_user = NULL;
char *mqtt_pwd = NULL;
char *mqtt_user = nullptr;
char *mqtt_pwd = nullptr;
if (strlen(Settings.mqtt_user) > 0) mqtt_user = Settings.mqtt_user;
if (strlen(Settings.mqtt_pwd) > 0) mqtt_pwd = Settings.mqtt_pwd;
GetTopic_P(stopic, TELE, mqtt_topic, S_LWT);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_OFFLINE);
Response_P(S_OFFLINE);
#ifdef USE_MQTT_TLS
EspClient = WiFiClientSecure(); // Wifi Secure Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497)
@ -456,6 +452,15 @@ void MqttReconnect(void)
MqttClient.setCallback(MqttDataHandler);
MqttClient.setServer(Settings.mqtt_host, Settings.mqtt_port);
/*
// Skip MQTT host DNS lookup if not needed
uint32_t current_hash = GetHash(Settings.mqtt_host, strlen(Settings.mqtt_host));
if (mqtt_host_hash != current_hash) {
mqtt_host_hash = current_hash;
WiFi.hostByName(Settings.mqtt_host, mqtt_host_addr); // Skips DNS lookup if mqtt_host is IP address string as from mDns
}
MqttClient.setServer(mqtt_host_addr, Settings.mqtt_port);
*/
if (MqttClient.connect(mqtt_client, mqtt_user, mqtt_pwd, stopic, 1, true, mqtt_data)) {
MqttConnected();
} else {
@ -514,21 +519,21 @@ bool MqttCommand(void)
strlcpy(Settings.mqtt_host, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_HOST : dataBuf, sizeof(Settings.mqtt_host));
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_host);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.mqtt_host);
}
else if (CMND_MQTTPORT == command_code) {
if (payload16 > 0) {
Settings.mqtt_port = (1 == payload16) ? MQTT_PORT : payload16;
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.mqtt_port);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.mqtt_port);
}
else if (CMND_MQTTRETRY == command_code) {
if ((payload >= MQTT_RETRY_SECS) && (payload < 32001)) {
Settings.mqtt_retry = payload;
mqtt_retry_counter = Settings.mqtt_retry;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.mqtt_retry);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.mqtt_retry);
}
else if ((CMND_STATETEXT == command_code) && (index > 0) && (index <= 4)) {
if ((data_len > 0) && (data_len < sizeof(Settings.state_text[0]))) {
@ -537,7 +542,7 @@ bool MqttCommand(void)
}
strlcpy(Settings.state_text[index -1], dataBuf, sizeof(Settings.state_text[0]));
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, GetStateText(index -1));
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, GetStateText(index -1));
}
#ifdef USE_MQTT_TLS
else if ((CMND_MQTTFINGERPRINT == command_code) && (index > 0) && (index <= 2)) {
@ -554,7 +559,7 @@ bool MqttCommand(void)
for (uint8_t i = 0; i < sizeof(Settings.mqtt_fingerprint[index -1]); i++) {
snprintf_P(fingerprint, sizeof(fingerprint), PSTR("%s%s%02X"), fingerprint, (i) ? " " : "", Settings.mqtt_fingerprint[index -1][i]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, fingerprint);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, fingerprint);
}
#endif
else if (CMND_MQTTCLIENT == command_code) {
@ -562,22 +567,22 @@ bool MqttCommand(void)
strlcpy(Settings.mqtt_client, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_CLIENT_ID : dataBuf, sizeof(Settings.mqtt_client));
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_client);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.mqtt_client);
}
else if (CMND_MQTTUSER == command_code) {
if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_user))) {
strlcpy(Settings.mqtt_user, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_USER : dataBuf, sizeof(Settings.mqtt_user));
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_user);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.mqtt_user);
}
else if (CMND_MQTTPASSWORD == command_code) {
if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_pwd))) {
strlcpy(Settings.mqtt_pwd, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_PASS : dataBuf, sizeof(Settings.mqtt_pwd));
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_pwd);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.mqtt_pwd);
restart_flag = 2;
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_ASTERIX, command);
Response_P(S_JSON_COMMAND_ASTERIX, command);
}
}
else if (CMND_FULLTOPIC == command_code) {
@ -586,13 +591,13 @@ bool MqttCommand(void)
if (!strcmp(dataBuf, mqtt_client)) SetShortcut(dataBuf, SC_DEFAULT);
strlcpy(stemp1, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_FULLTOPIC : dataBuf, sizeof(stemp1));
if (strcmp(stemp1, Settings.mqtt_fulltopic)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
Response_P((Settings.flag.mqtt_offline) ? S_OFFLINE : "");
MqttPublishPrefixTopic_P(TELE, PSTR(D_LWT), true); // Offline or remove previous retained topic
strlcpy(Settings.mqtt_fulltopic, stemp1, sizeof(Settings.mqtt_fulltopic));
restart_flag = 2;
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_fulltopic);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.mqtt_fulltopic);
}
else if ((CMND_PREFIX == command_code) && (index > 0) && (index <= 3)) {
if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_prefix[0]))) {
@ -601,21 +606,21 @@ bool MqttCommand(void)
// if (Settings.mqtt_prefix[index -1][strlen(Settings.mqtt_prefix[index -1])] == '/') Settings.mqtt_prefix[index -1][strlen(Settings.mqtt_prefix[index -1])] = 0;
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mqtt_prefix[index -1]);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mqtt_prefix[index -1]);
}
else if (CMND_PUBLISH == command_code) {
if (data_len > 0) {
char *mqtt_part = strtok(dataBuf, " ");
if (mqtt_part) {
strlcpy(stemp1, mqtt_part, sizeof(stemp1));
mqtt_part = strtok(NULL, " ");
mqtt_part = strtok(nullptr, " ");
if (mqtt_part) {
strlcpy(mqtt_data, mqtt_part, sizeof(mqtt_data));
} else {
mqtt_data[0] = '\0';
}
MqttPublishDirect(stemp1, (index == 2));
// snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
// Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
mqtt_data[0] = '\0';
}
}
@ -627,7 +632,7 @@ bool MqttCommand(void)
strlcpy(Settings.mqtt_grptopic, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_GRPTOPIC : dataBuf, sizeof(Settings.mqtt_grptopic));
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_grptopic);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.mqtt_grptopic);
}
else if (CMND_TOPIC == command_code) {
if (!grpflg && (data_len > 0) && (data_len < sizeof(Settings.mqtt_topic))) {
@ -635,13 +640,13 @@ bool MqttCommand(void)
if (!strcmp(dataBuf, mqtt_client)) SetShortcut(dataBuf, SC_DEFAULT);
strlcpy(stemp1, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_TOPIC : dataBuf, sizeof(stemp1));
if (strcmp(stemp1, Settings.mqtt_topic)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
Response_P((Settings.flag.mqtt_offline) ? S_OFFLINE : "");
MqttPublishPrefixTopic_P(TELE, PSTR(D_LWT), true); // Offline or remove previous retained topic
strlcpy(Settings.mqtt_topic, stemp1, sizeof(Settings.mqtt_topic));
restart_flag = 2;
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_topic);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.mqtt_topic);
}
else if (CMND_BUTTONTOPIC == command_code) {
if (!grpflg && (data_len > 0) && (data_len < sizeof(Settings.button_topic))) {
@ -654,7 +659,7 @@ bool MqttCommand(void)
default: strlcpy(Settings.button_topic, dataBuf, sizeof(Settings.button_topic));
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.button_topic);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.button_topic);
}
else if (CMND_SWITCHTOPIC == command_code) {
if ((data_len > 0) && (data_len < sizeof(Settings.switch_topic))) {
@ -667,7 +672,7 @@ bool MqttCommand(void)
default: strlcpy(Settings.switch_topic, dataBuf, sizeof(Settings.switch_topic));
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.switch_topic);
Response_P(S_JSON_COMMAND_SVALUE, command, Settings.switch_topic);
}
else if (CMND_BUTTONRETAIN == command_code) {
if ((payload >= 0) && (payload <= 1)) {
@ -678,7 +683,7 @@ bool MqttCommand(void)
}
Settings.flag.mqtt_button_retain = payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag.mqtt_button_retain));
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag.mqtt_button_retain));
}
else if (CMND_SWITCHRETAIN == command_code) {
if ((payload >= 0) && (payload <= 1)) {
@ -689,7 +694,7 @@ bool MqttCommand(void)
}
Settings.flag.mqtt_switch_retain = payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag.mqtt_switch_retain));
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag.mqtt_switch_retain));
}
else if (CMND_POWERRETAIN == command_code) {
if ((payload >= 0) && (payload <= 1)) {
@ -702,7 +707,7 @@ bool MqttCommand(void)
}
Settings.flag.mqtt_power_retain = payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag.mqtt_power_retain));
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag.mqtt_power_retain));
}
else if (CMND_SENSORRETAIN == command_code) {
if ((payload >= 0) && (payload <= 1)) {
@ -713,7 +718,7 @@ bool MqttCommand(void)
}
Settings.flag.mqtt_sensor_retain = payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag.mqtt_sensor_retain));
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag.mqtt_sensor_retain));
}
else serviced = false; // Unknown command
@ -742,7 +747,7 @@ const char HTTP_FORM_MQTT1[] PROGMEM =
const char HTTP_FORM_MQTT2[] PROGMEM =
"<p><b>" D_USER "</b> (" MQTT_USER ")<br/><input id='mu' name='mu' placeholder='" MQTT_USER "' value='%s'></p>"
"<p><b>" D_PASSWORD "</b><br/><input id='mp' name='mp' type='password' placeholder='" D_PASSWORD "' value='" D_ASTERISK_PWD "'></p>"
"<p><b>" D_TOPIC "</b> = %%topic%% (" MQTT_TOPIC ")<br/><input id='mt' name='mt' placeholder='" MQTT_TOPIC "' value='%s'></p>"
"<p><b>" D_TOPIC "</b> = %%topic%% (%s)<br/><input id='mt' name='mt' placeholder='%s' value='%s'></p>"
"<p><b>" D_FULL_TOPIC "</b> (%s)<br/><input id='mf' name='mf' placeholder='%s' value='%s'></p>";
void HandleMqttConfiguration(void)
@ -764,14 +769,11 @@ void HandleMqttConfiguration(void)
WSContentSend_P(HTTP_FORM_MQTT1,
Settings.mqtt_host,
Settings.mqtt_port,
Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client)),
MQTT_CLIENT_ID,
Settings.mqtt_client);
Format(str, MQTT_CLIENT_ID, sizeof(str)), MQTT_CLIENT_ID, Settings.mqtt_client);
WSContentSend_P(HTTP_FORM_MQTT2,
(Settings.mqtt_user[0] == '\0') ? "0" : Settings.mqtt_user,
Settings.mqtt_topic,
MQTT_FULLTOPIC, MQTT_FULLTOPIC,
Settings.mqtt_fulltopic);
Format(str, MQTT_TOPIC, sizeof(str)), MQTT_TOPIC, Settings.mqtt_topic,
MQTT_FULLTOPIC, MQTT_FULLTOPIC, Settings.mqtt_fulltopic);
WSContentSend_P(HTTP_FORM_END);
WSContentSpaceButton(BUTTON_CONFIGURATION);
WSContentStop();
@ -790,7 +792,7 @@ void MqttSaveSettings(void)
strlcpy(stemp2, (!strlen(tmp)) ? MQTT_FULLTOPIC : tmp, sizeof(stemp2));
MakeValidMqtt(1,stemp2);
if ((strcmp(stemp, Settings.mqtt_topic)) || (strcmp(stemp2, Settings.mqtt_fulltopic))) {
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
Response_P((Settings.flag.mqtt_offline) ? S_OFFLINE : "");
MqttPublishPrefixTopic_P(TELE, S_LWT, true); // Offline or remove previous retained topic
}
strlcpy(Settings.mqtt_topic, stemp, sizeof(Settings.mqtt_topic));
@ -820,6 +822,9 @@ bool Xdrv02(uint8_t function)
if (Settings.flag.mqtt_enabled) {
switch (function) {
case FUNC_EVERY_50_MSECOND: // https://github.com/knolleary/pubsubclient/issues/556
MqttClient.loop();
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_ADD_BUTTON:
WSContentSend_P(HTTP_BTN_MENU_MQTT);
@ -828,9 +833,6 @@ bool Xdrv02(uint8_t function)
WebServer->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration);
break;
#endif // USE_WEBSERVER
case FUNC_LOOP:
if (!global_state.mqtt_down) { MqttLoop(); }
break;
case FUNC_COMMAND:
result = MqttCommand();
break;

View File

@ -201,34 +201,34 @@ void EnergyMarginCheck(void)
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{"));
Response_P(PSTR("{"));
jsonflg = false;
if (EnergyMargin(false, Settings.energy_min_power, energy_power_u, flag, energy_min_power_flag)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_POWERLOW "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag));
ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true;
}
if (EnergyMargin(true, Settings.energy_max_power, energy_power_u, flag, energy_max_power_flag)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_POWERHIGH "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag));
ResponseAppend_P(PSTR("%s\"" D_CMND_POWERHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true;
}
if (EnergyMargin(false, Settings.energy_min_voltage, energy_voltage_u, flag, energy_min_voltage_flag)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag));
ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true;
}
if (EnergyMargin(true, Settings.energy_max_voltage, energy_voltage_u, flag, energy_max_voltage_flag)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag));
ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true;
}
if (EnergyMargin(false, Settings.energy_min_current, energy_current_u, flag, energy_min_current_flag)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_CURRENTLOW "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag));
ResponseAppend_P(PSTR("%s%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true;
}
if (EnergyMargin(true, Settings.energy_max_current, energy_current_u, flag, energy_max_current_flag)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag));
ResponseAppend_P(PSTR("%s%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true;
}
if (jsonflg) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_MARGINS), MQTT_TELE_RETAIN);
EnergyMqttShow();
}
@ -243,7 +243,7 @@ void EnergyMarginCheck(void)
} else {
energy_mplh_counter--;
if (!energy_mplh_counter) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_MAXPOWERREACHED "\":\"%d%s\"}"), energy_power_u, (Settings.flag.value_units) ? " " D_UNIT_WATT : "");
Response_P(PSTR("{\"" D_JSON_MAXPOWERREACHED "\":\"%d%s\"}"), energy_power_u, (Settings.flag.value_units) ? " " D_UNIT_WATT : "");
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow();
ExecuteCommandPower(1, POWER_OFF, SRC_MAXPOWER);
@ -266,11 +266,11 @@ void EnergyMarginCheck(void)
if (energy_mplr_counter) {
energy_mplr_counter--;
if (energy_mplr_counter) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1));
Response_P(PSTR("{\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR));
ExecuteCommandPower(1, POWER_ON, SRC_MAXPOWER);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_MAXPOWERREACHEDRETRY "\":\"%s\"}"), GetStateText(0));
Response_P(PSTR("{\"" D_JSON_MAXPOWERREACHEDRETRY "\":\"%s\"}"), GetStateText(0));
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow();
}
@ -284,14 +284,14 @@ void EnergyMarginCheck(void)
energy_daily_u = (uint16_t)(energy_daily * 1000);
if (!energy_max_energy_state && (RtcTime.hour == Settings.energy_max_energy_start)) {
energy_max_energy_state = 1;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1));
Response_P(PSTR("{\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR));
ExecuteCommandPower(1, POWER_ON, SRC_MAXENERGY);
}
else if ((1 == energy_max_energy_state) && (energy_daily_u >= Settings.energy_max_energy)) {
energy_max_energy_state = 2;
dtostrfd(energy_daily, 3, mqtt_data);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_MAXENERGYREACHED "\":\"%s%s\"}"), mqtt_data, (Settings.flag.value_units) ? " " D_UNIT_KILOWATTHOUR : "");
Response_P(PSTR("{\"" D_JSON_MAXENERGYREACHED "\":\"%s%s\"}"), mqtt_data, (Settings.flag.value_units) ? " " D_UNIT_KILOWATTHOUR : "");
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow();
ExecuteCommandPower(1, POWER_OFF, SRC_MAXENERGY);
@ -305,12 +305,12 @@ void EnergyMarginCheck(void)
void EnergyMqttShow(void)
{
// {"Time":"2017-12-16T11:48:55","ENERGY":{"Total":0.212,"Yesterday":0.000,"Today":0.014,"Period":2.0,"Power":22.0,"Factor":1.00,"Voltage":213.6,"Current":0.100}}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
Response_P(PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
int tele_period_save = tele_period;
tele_period = 2;
EnergyShow(true);
tele_period = tele_period_save;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
energy_power_delta = 0;
}
@ -414,7 +414,7 @@ bool EnergyCommand(void)
char energy_yesterday_chr[33];
dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s}}"),
Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s}}"),
command, energy_total_chr, energy_yesterday_chr, energy_daily_chr);
status_flag = true;
}
@ -519,9 +519,9 @@ bool EnergyCommand(void)
}
if (Settings.flag.value_units) {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_LVALUE_SPACE_UNIT, command, nvalue, GetTextIndexed(sunit, sizeof(sunit), unit, kUnitNames));
Response_P(S_JSON_COMMAND_LVALUE_SPACE_UNIT, command, nvalue, GetTextIndexed(sunit, sizeof(sunit), unit, kUnitNames));
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_LVALUE, command, nvalue);
Response_P(S_JSON_COMMAND_LVALUE, command, nvalue);
}
}
@ -637,13 +637,13 @@ void EnergyShow(bool json)
}
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s%s,\"" D_JSON_POWERUSAGE "\":%s"),
mqtt_data, GetDateAndTime(DT_ENERGY).c_str(), energy_total_chr, energy_yesterday_chr, energy_daily_chr, (show_energy_period) ? speriod : "", active_power_chr);
ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s%s,\"" D_JSON_POWERUSAGE "\":%s"),
GetDateAndTime(DT_ENERGY).c_str(), energy_total_chr, energy_yesterday_chr, energy_daily_chr, (show_energy_period) ? speriod : "", active_power_chr);
if (!energy_type_dc) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s%s"),
mqtt_data, apparent_power_chr, reactive_power_chr, power_factor_chr, (!isnan(energy_frequency)) ? sfrequency : "");
ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s%s"),
apparent_power_chr, reactive_power_chr, power_factor_chr, (!isnan(energy_frequency)) ? sfrequency : "");
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"), mqtt_data, voltage_chr, current_chr);
ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"), voltage_chr, current_chr);
#ifdef USE_DOMOTICZ
if (show_energy_period) { // Only send if telemetry
@ -689,15 +689,15 @@ bool Xdrv03(uint8_t function)
}
else if (energy_flg) {
switch (function) {
case FUNC_LOOP:
XnrgCall(FUNC_LOOP);
break;
case FUNC_COMMAND:
result = EnergyCommand();
break;
case FUNC_SET_POWER:
EnergySetPowerSteadyCounter();
break;
case FUNC_LOOP:
XnrgCall(FUNC_LOOP);
break;
case FUNC_SERIAL:
result = XnrgCall(FUNC_SERIAL);
break;

View File

@ -56,7 +56,7 @@
#define XDRV_04 4
#define WS2812_SCHEMES 7 // Number of additional WS2812 schemes supported by xdrv_ws2812.ino
const uint8_t WS2812_SCHEMES = 7; // Number of additional WS2812 schemes supported by xdrv_ws2812.ino
enum LightCommands {
CMND_COLOR, CMND_COLORTEMPERATURE, CMND_DIMMER, CMND_LED, CMND_LEDTABLE, CMND_FADE,
@ -70,23 +70,23 @@ const char kLightCommands[] PROGMEM =
struct LRgbColor {
uint8_t R, G, B;
};
#define MAX_FIXED_COLOR 12
const uint8_t MAX_FIXED_COLOR = 12;
const LRgbColor kFixedColor[MAX_FIXED_COLOR] PROGMEM =
{ 255,0,0, 0,255,0, 0,0,255, 228,32,0, 0,228,32, 0,32,228, 188,64,0, 0,160,96, 160,32,240, 255,255,0, 255,0,170, 255,255,255 };
struct LWColor {
uint8_t W;
};
#define MAX_FIXED_WHITE 4
const uint8_t MAX_FIXED_WHITE = 4;
const LWColor kFixedWhite[MAX_FIXED_WHITE] PROGMEM = { 0, 255, 128, 32 };
struct LCwColor {
uint8_t C, W;
};
#define MAX_FIXED_COLD_WARM 4
const uint8_t MAX_FIXED_COLD_WARM = 4;
const LCwColor kFixedColdWarm[MAX_FIXED_COLD_WARM] PROGMEM = { 0,0, 255,0, 0,255, 128,128 };
uint8_t ledTable[] = {
const uint8_t ledTable[] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4,
@ -132,11 +132,11 @@ unsigned long strip_timer_counter = 0; // Bars and Gradient
* Arilux LC11 Rf support stripped from RCSwitch library
\*********************************************************************************************/
#define ARILUX_RF_TIME_AVOID_DUPLICATE 1000 // Milliseconds
const uint32_t ARILUX_RF_TIME_AVOID_DUPLICATE = 1000; // Milliseconds
#define ARILUX_RF_MAX_CHANGES 51 // Pulses (sync + 2 x 24 bits)
#define ARILUX_RF_SEPARATION_LIMIT 4300 // Microseconds
#define ARILUX_RF_RECEIVE_TOLERANCE 60 // Percentage
const uint8_t ARILUX_RF_MAX_CHANGES = 51; // Pulses (sync + 2 x 24 bits)
const uint32_t ARILUX_RF_SEPARATION_LIMIT = 4300; // Microseconds
const uint32_t ARILUX_RF_RECEIVE_TOLERANCE = 60; // Percentage
unsigned int arilux_rf_timings[ARILUX_RF_MAX_CHANGES];
@ -740,43 +740,42 @@ void LightState(uint8_t append)
int16_t h,s,b;
if (append) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
ResponseAppend_P(PSTR(","));
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{"));
Response_P(PSTR("{"));
}
GetPowerDevice(scommand, light_device, sizeof(scommand), Settings.flag.device_index_enable);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d"),
mqtt_data, scommand, GetStateText(light_power), Settings.light_dimmer);
ResponseAppend_P(PSTR("\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d"), scommand, GetStateText(light_power), Settings.light_dimmer);
if (light_subtype > LST_SINGLE) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_COLOR "\":\"%s\""), mqtt_data, LightGetColor(0, scolor));
ResponseAppend_P(PSTR(",\"" D_CMND_COLOR "\":\"%s\""), LightGetColor(0, scolor));
// Add status for HSB
LightGetHsb(&hsb[0],&hsb[1],&hsb[2], false);
// Scale these percentages up to the numbers expected by the client
h = round(hsb[0] * 360);
s = round(hsb[1] * 100);
b = round(hsb[2] * 100);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_HSBCOLOR "\":\"%d,%d,%d\""), mqtt_data, h,s,b);
ResponseAppend_P(PSTR(",\"" D_CMND_HSBCOLOR "\":\"%d,%d,%d\""), h,s,b);
// Add status for each channel
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_CHANNEL "\":[" ), mqtt_data);
ResponseAppend_P(PSTR(",\"" D_CMND_CHANNEL "\":[" ));
for (uint8_t i = 0; i < light_subtype; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d" ), mqtt_data, (i > 0 ? "," : ""), light_current_color[i] * 100 / 255);
ResponseAppend_P(PSTR("%s%d" ), (i > 0 ? "," : ""), light_current_color[i] * 100 / 255);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]" ), mqtt_data);
ResponseAppend_P(PSTR("]"));
}
if ((LST_COLDWARM == light_subtype) || (LST_RGBWC == light_subtype)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_COLORTEMPERATURE "\":%d"), mqtt_data, LightGetColorTemp());
ResponseAppend_P(PSTR(",\"" D_CMND_COLORTEMPERATURE "\":%d"), LightGetColorTemp());
}
if (append) {
if (light_subtype >= LST_RGB) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_SCHEME "\":%d"), mqtt_data, Settings.light_scheme);
ResponseAppend_P(PSTR(",\"" D_CMND_SCHEME "\":%d"), Settings.light_scheme);
}
if (LT_WS2812 == light_type) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_WIDTH "\":%d"), mqtt_data, Settings.light_width);
ResponseAppend_P(PSTR(",\"" D_CMND_WIDTH "\":%d"), Settings.light_width);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_FADE "\":\"%s\",\"" D_CMND_SPEED "\":%d,\"" D_CMND_LEDTABLE "\":\"%s\""),
mqtt_data, GetStateText(Settings.light_fade), Settings.light_speed, GetStateText(Settings.light_correction));
ResponseAppend_P(PSTR(",\"" D_CMND_FADE "\":\"%s\",\"" D_CMND_SPEED "\":%d,\"" D_CMND_LEDTABLE "\":\"%s\""),
GetStateText(Settings.light_fade), Settings.light_speed, GetStateText(Settings.light_correction));
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
}
}
@ -949,7 +948,7 @@ void LightAnimate(void)
light_new_color[i] = light_current_color[i];
}
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_WAKEUP "\":\"" D_JSON_DONE "\"}"));
Response_P(PSTR("{\"" D_CMND_WAKEUP "\":\"" D_JSON_DONE "\"}"));
MqttPublishPrefixTopic_P(TELE, PSTR(D_CMND_WAKEUP));
light_wakeup_active = 0;
Settings.light_scheme = LS_POWER;
@ -1232,9 +1231,9 @@ bool LightColorEntry(char *buffer, uint8_t buffer_length)
}
memset(&light_entry_color, 0x00, sizeof(light_entry_color));
if (strstr(buffer, ",")) { // Decimal entry
if (strstr(buffer, ",") != nullptr) { // Decimal entry
int8_t i = 0;
for (str = strtok_r(buffer, ",", &p); str && i < 6; str = strtok_r(NULL, ",", &p)) {
for (str = strtok_r(buffer, ",", &p); str && i < 6; str = strtok_r(nullptr, ",", &p)) {
if (i < 5) {
light_entry_color[i++] = atoi(str);
}
@ -1319,7 +1318,7 @@ bool LightCommand(void)
}
}
if (!valid_entry && (XdrvMailbox.index <= 2)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, LightGetColor(0, scolor));
Response_P(S_JSON_COMMAND_SVALUE, command, LightGetColor(0, scolor));
}
if (XdrvMailbox.index >= 3) {
scolor[0] = '\0';
@ -1330,7 +1329,7 @@ bool LightCommand(void)
snprintf_P(scolor, 25, PSTR("%s%02X"), scolor, Settings.ws_color[XdrvMailbox.index -3][i]);
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, scolor);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, scolor);
}
}
else if ((CMND_CHANNEL == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= light_subtype ) ) {
@ -1340,22 +1339,22 @@ bool LightCommand(void)
LightSetColor();
coldim = true;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, light_current_color[XdrvMailbox.index -1] * 100 / 255);
Response_P(S_JSON_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, light_current_color[XdrvMailbox.index -1] * 100 / 255);
}
else if ((CMND_HSBCOLOR == command_code) && ( light_subtype >= LST_RGB)) {
bool validHSB = (XdrvMailbox.data_len > 0);
if (validHSB) {
uint16_t HSB[3];
if (strstr(XdrvMailbox.data, ",")) { // Command with 3 comma separated parameters, Hue (0<H<360), Saturation (0<S<100) AND Brightness (0<B<100)
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Command with 3 comma separated parameters, Hue (0<H<360), Saturation (0<S<100) AND Brightness (0<B<100)
for (int i = 0; i < 3; i++) {
char *substr;
if (0 == i) {
substr = strtok(XdrvMailbox.data, ",");
} else {
substr = strtok(NULL, ",");
substr = strtok(nullptr, ",");
}
if (substr != NULL) {
if (substr != nullptr) {
HSB[i] = atoi(substr);
} else {
validHSB = false;
@ -1393,7 +1392,7 @@ bool LightCommand(void)
char *p;
uint16_t idx = XdrvMailbox.index;
Ws2812ForceSuspend();
for (char *color = strtok_r(XdrvMailbox.data, " ", &p); color; color = strtok_r(NULL, " ", &p)) {
for (char *color = strtok_r(XdrvMailbox.data, " ", &p); color; color = strtok_r(nullptr, " ", &p)) {
if (LightColorEntry(color, strlen(color))) {
Ws2812SetColor(idx, light_entry_color[0], light_entry_color[1], light_entry_color[2], light_entry_color[3]);
idx++;
@ -1405,7 +1404,7 @@ bool LightCommand(void)
Ws2812ForceUpdate();
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, Ws2812GetColor(XdrvMailbox.index, scolor));
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, Ws2812GetColor(XdrvMailbox.index, scolor));
}
else if ((CMND_PIXELS == command_code) && (LT_WS2812 == light_type)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= WS2812_MAX_LEDS)) {
@ -1414,25 +1413,25 @@ bool LightCommand(void)
Ws2812Clear();
light_update = 1;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.light_pixels);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.light_pixels);
}
else if ((CMND_ROTATION == command_code) && (LT_WS2812 == light_type)) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < Settings.light_pixels)) {
Settings.light_rotation = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.light_rotation);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.light_rotation);
}
else if ((CMND_WIDTH == command_code) && (LT_WS2812 == light_type) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 4)) {
if (1 == XdrvMailbox.index) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 4)) {
Settings.light_width = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.light_width);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.light_width);
} else {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 32)) {
Settings.ws_width[XdrvMailbox.index -2] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.ws_width[XdrvMailbox.index -2]);
Response_P(S_JSON_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.ws_width[XdrvMailbox.index -2]);
}
}
#endif // USE_WS2812 ************************************************************************
@ -1454,7 +1453,7 @@ bool LightCommand(void)
// Publish state message for Hass
if (Settings.flag3.hass_tele_on_power) { MqttPublishTeleState(); }
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.light_scheme);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.light_scheme);
}
else if (CMND_WAKEUP == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
@ -1463,7 +1462,7 @@ bool LightCommand(void)
light_wakeup_active = 3;
Settings.light_scheme = LS_WAKEUP;
LightPowerOn();
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_STARTED);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_STARTED);
}
else if ((CMND_COLORTEMPERATURE == command_code) && ((LST_COLDWARM == light_subtype) || (LST_RGBWC == light_subtype))) { // ColorTemp
if (option != '\0') {
@ -1479,7 +1478,7 @@ bool LightCommand(void)
LightSetColorTemp(XdrvMailbox.payload);
coldim = true;
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, LightGetColorTemp());
Response_P(S_JSON_COMMAND_NVALUE, command, LightGetColorTemp());
}
}
else if (CMND_DIMMER == command_code) {
@ -1494,7 +1493,7 @@ bool LightCommand(void)
light_update = 1;
coldim = true;
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.light_dimmer);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.light_dimmer);
}
}
else if (CMND_LEDTABLE == command_code) {
@ -1510,22 +1509,22 @@ bool LightCommand(void)
}
light_update = 1;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.light_correction));
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.light_correction));
}
else if (CMND_RGBWWTABLE == command_code) {
bool validtable = (XdrvMailbox.data_len > 0);
char scolor[25];
if (validtable) {
if (strstr(XdrvMailbox.data, ",")) { // Command with up to 5 comma separated parameters
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Command with up to 5 comma separated parameters
for (int i = 0; i < LST_RGBWC; i++) {
char *substr;
if (0 == i) {
substr = strtok(XdrvMailbox.data, ",");
} else {
substr = strtok(NULL, ",");
substr = strtok(nullptr, ",");
}
if (substr != NULL) {
if (substr != nullptr) {
Settings.rgbwwTable[i] = atoi(substr);
}
}
@ -1536,7 +1535,7 @@ bool LightCommand(void)
for (uint8_t i = 0; i < LST_RGBWC; i++) {
snprintf_P(scolor, 25, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", Settings.rgbwwTable[i]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, scolor);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, scolor);
}
else if (CMND_FADE == command_code) {
switch (XdrvMailbox.payload) {
@ -1548,7 +1547,7 @@ bool LightCommand(void)
Settings.light_fade ^= 1;
break;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.light_fade));
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.light_fade));
}
else if (CMND_SPEED == command_code) { // 1 - fast, 20 - very slow
if (('+' == option) && (Settings.light_speed > 1)) {
@ -1560,20 +1559,19 @@ bool LightCommand(void)
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= STATES)) {
Settings.light_speed = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.light_speed);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.light_speed);
}
else if (CMND_WAKEUPDURATION == command_code) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 3001)) {
Settings.light_wakeup = XdrvMailbox.payload;
light_wakeup_active = 0;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.light_wakeup);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.light_wakeup);
}
else if (CMND_UNDOCA == command_code) { // Theos legacy status
LightGetColor(1, scolor);
scolor[6] = '\0'; // RGB only
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,%d,%d,%d,%d,%d"),
scolor, Settings.light_fade, Settings.light_correction, Settings.light_scheme, Settings.light_speed, Settings.light_width);
Response_P(PSTR("%s,%d,%d,%d,%d,%d"), scolor, Settings.light_fade, Settings.light_correction, Settings.light_scheme, Settings.light_speed, Settings.light_width);
MqttPublishPrefixTopic_P(STAT, XdrvMailbox.topic);
mqtt_data[0] = '\0';
}

View File

@ -26,6 +26,8 @@
#include <IRremoteESP8266.h>
enum IrErrors { IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND, IE_SYNTAX_IRHVAC };
enum IrRemoteCommands { CMND_IRSEND, CMND_IRHVAC };
const char kIrRemoteCommands[] PROGMEM = D_CMND_IRSEND "|" D_CMND_IRHVAC ;
@ -42,19 +44,19 @@ enum IrHvacVendors { VNDR_TOSHIBA, VNDR_MITSUBISHI, VNDR_LG, VNDR_FUJITSU };
const char kIrHvacVendors[] PROGMEM = "Toshiba|Mitsubishi|LG|Fujitsu" ;
// HVAC TOSHIBA_
#define HVAC_TOSHIBA_HDR_MARK 4400
#define HVAC_TOSHIBA_HDR_SPACE 4300
#define HVAC_TOSHIBA_BIT_MARK 543
#define HVAC_TOSHIBA_ONE_SPACE 1623
#define HVAC_MISTUBISHI_ZERO_SPACE 472
#define HVAC_TOSHIBA_RPT_MARK 440
#define HVAC_TOSHIBA_RPT_SPACE 7048 // Above original iremote limit
#define HVAC_TOSHIBA_DATALEN 9
const uint16_t HVAC_TOSHIBA_HDR_MARK = 4400;
const uint16_t HVAC_TOSHIBA_HDR_SPACE = 4300;
const uint16_t HVAC_TOSHIBA_BIT_MARK = 543;
const uint16_t HVAC_TOSHIBA_ONE_SPACE = 1623;
const uint16_t HVAC_MISTUBISHI_ZERO_SPACE = 472;
const uint16_t HVAC_TOSHIBA_RPT_MARK = 440;
const uint16_t HVAC_TOSHIBA_RPT_SPACE = 7048; // Above original iremote limit
const uint8_t HVAC_TOSHIBA_DATALEN = 9;
// HVAC LG
#define HVAC_LG_DATALEN 7
const uint8_t HVAC_LG_DATALEN = 7;
IRMitsubishiAC *mitsubir = NULL;
IRMitsubishiAC *mitsubir = nullptr;
const char kFanSpeedOptions[] = "A12345S";
const char kHvacModeOptions[] = "HDCA";
@ -66,7 +68,7 @@ const char kHvacModeOptions[] = "HDCA";
#include <IRsend.h>
IRsend *irsend = NULL;
IRsend *irsend = nullptr;
bool irsend_active = false;
void IrSendInit(void)
@ -79,18 +81,38 @@ void IrSendInit(void)
#endif //USE_IR_HVAC
}
char* IrUint64toHex(uint64_t value, char *str, uint16_t bits)
{
ulltoa(value, str, 16); // Get 64bit value
int fill = 8;
if ((bits > 3) && (bits < 65)) {
fill = bits / 4; // Max 16
if (bits % 4) { fill++; }
}
int len = strlen(str);
fill -= len;
if (fill > 0) {
memmove(str + fill, str, len +1);
memset(str, '0', fill);
}
memmove(str + 2, str, strlen(str) +1);
str[0] = '0';
str[1] = 'x';
return str;
}
#ifdef USE_IR_RECEIVE
/*********************************************************************************************\
* IR Receive
\*********************************************************************************************/
#define IR_RCV_SAVE_BUFFER 0 // 0 = do not use buffer, 1 = use buffer for decoding
#define IR_TIME_AVOID_DUPLICATE 500 // Milliseconds
const bool IR_RCV_SAVE_BUFFER = false; // false = do not use buffer, true = use buffer for decoding
const uint32_t IR_TIME_AVOID_DUPLICATE = 500; // Milliseconds
#include <IRrecv.h>
IRrecv *irrecv = NULL;
IRrecv *irrecv = nullptr;
unsigned long ir_lasttime = 0;
@ -107,15 +129,16 @@ void IrReceiveInit(void)
void IrReceiveCheck(void)
{
char sirtype[14]; // Max is AIWA_RC_T501
char stemp[16];
int8_t iridx = 0;
decode_results results;
if (irrecv->decode(&results)) {
char hvalue[64];
IrUint64toHex(results.value, hvalue, results.bits); // Get 64bit value as hex 0x00123456
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_IRR "Echo %d, RawLen %d, Overflow %d, Bits %d, Value 0x%08X, Decode %d"),
irsend_active, results.rawlen, results.overflow, results.bits, results.value, results.decode_type);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_IRR "Echo %d, RawLen %d, Overflow %d, Bits %d, Value %s, Decode %d"),
irsend_active, results.rawlen, results.overflow, results.bits, hvalue, results.decode_type);
unsigned long now = millis();
// if ((now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) && (UNKNOWN != results.decode_type) && (results.bits > 0)) {
@ -123,27 +146,26 @@ void IrReceiveCheck(void)
ir_lasttime = now;
iridx = results.decode_type;
if ((iridx < 0) || (iridx > 14)) {
iridx = 0; // UNKNOWN
}
if ((iridx < 0) || (iridx > 14)) { iridx = 0; } // UNKNOWN
char svalue[64];
if (Settings.flag.ir_receive_decimal) {
snprintf_P(stemp, sizeof(stemp), PSTR("%u"), (uint32_t)results.value);
ulltoa(results.value, svalue, 10);
} else {
snprintf_P(stemp, sizeof(stemp), PSTR("\"0x%lX\""), (uint32_t)results.value);
snprintf_P(svalue, sizeof(svalue), PSTR("\"%s\""), hvalue);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":%s"),
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, stemp);
Response_P(PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":%s"),
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, svalue);
if (Settings.flag3.receive_raw) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_IR_RAWDATA "\":["), mqtt_data);
ResponseAppend_P(PSTR(",\"" D_JSON_IR_RAWDATA "\":["));
uint16_t i;
for (i = 1; i < results.rawlen; i++) {
if (i > 1) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data); }
if (i > 1) { ResponseAppend_P(PSTR(",")); }
uint32_t usecs;
for (usecs = results.rawbuf[i] * kRawTick; usecs > UINT16_MAX; usecs -= UINT16_MAX) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%d,0,"), mqtt_data, UINT16_MAX);
ResponseAppend_P(PSTR("%d,0,"), UINT16_MAX);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%d"), mqtt_data, usecs);
ResponseAppend_P(PSTR("%d"), usecs);
if (strlen(mqtt_data) > sizeof(mqtt_data) - 40) { break; } // Quit if char string becomes too long
}
uint16_t extended_length = results.rawlen - 1;
@ -152,10 +174,10 @@ void IrReceiveCheck(void)
// Add two extra entries for multiple larger than UINT16_MAX it is.
extended_length += (usecs / (UINT16_MAX + 1)) * 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s],\"" D_JSON_IR_RAWDATA "Info\":[%d,%d,%d]"), mqtt_data, extended_length, i -1, results.overflow);
ResponseAppend_P(PSTR("],\"" D_JSON_IR_RAWDATA "Info\":[%d,%d,%d]"), extended_length, i -1, results.overflow);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}}"), mqtt_data);
ResponseAppend_P(PSTR("}}"));
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED));
if (iridx) {
@ -181,7 +203,7 @@ void IrReceiveCheck(void)
TOSHIBA
********************/
bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
uint8_t IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
{
uint16_t rawdata[2 + 2 * 8 * HVAC_TOSHIBA_DATALEN + 2];
uint8_t data[HVAC_TOSHIBA_DATALEN] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00};
@ -189,14 +211,14 @@ bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po
char *p;
uint8_t mode;
if (HVAC_Mode == NULL) {
if (HVAC_Mode == nullptr) {
p = (char *)kHvacModeOptions; // default HVAC_HOT
}
else {
p = strchr(kHvacModeOptions, toupper(HVAC_Mode[0]));
}
if (!p) {
return true;
return IE_SYNTAX_IRHVAC;
}
data[6] = (p - kHvacModeOptions) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00
@ -204,14 +226,14 @@ bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po
data[6] = (uint8_t)0x07; // Turn OFF HVAC
}
if (HVAC_FanMode == NULL) {
if (HVAC_FanMode == nullptr) {
p = (char *)kFanSpeedOptions; // default FAN_SPEED_AUTO
}
else {
p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0]));
}
if (!p) {
return true;
return IE_SYNTAX_IRHVAC;
}
mode = p - kFanSpeedOptions + 1;
if ((1 == mode) || (7 == mode)) {
@ -268,7 +290,7 @@ bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po
irsend->sendRaw(rawdata, i, 38);
// interrupts();
return false;
return IE_NO_ERROR;
}
@ -276,35 +298,35 @@ bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po
MITSUBISHI
********************/
bool IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
uint8_t IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
{
char *p;
uint8_t mode;
mitsubir->stateReset();
if (HVAC_Mode == NULL) {
if (HVAC_Mode == nullptr) {
p = (char *)kHvacModeOptions; // default HVAC_HOT
}
else {
p = strchr(kHvacModeOptions, toupper(HVAC_Mode[0]));
}
if (!p) {
return true;
return IE_SYNTAX_IRHVAC;
}
mode = (p - kHvacModeOptions + 1) << 3; // HOT = 0x08, DRY = 0x10, COOL = 0x18, AUTO = 0x20
mitsubir->setMode(mode);
mitsubir->setPower(HVAC_Power);
if (HVAC_FanMode == NULL) {
if (HVAC_FanMode == nullptr) {
p = (char *)kFanSpeedOptions; // default FAN_SPEED_AUTO
}
else {
p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0]));
}
if (!p) {
return true;
return IE_SYNTAX_IRHVAC;
}
mode = p - kFanSpeedOptions; // AUTO = 0, SPEED = 1 .. 5, SILENT = 6
mitsubir->setFan(mode);
@ -316,7 +338,7 @@ bool IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"),
// mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane());
return false;
return IE_NO_ERROR;
}
@ -324,7 +346,7 @@ bool IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC
LG
********************/
bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
uint8_t IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
{
uint32_t LG_Code;
uint8_t data[HVAC_LG_DATALEN];
@ -350,14 +372,14 @@ bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power,
else {
// Set code for HVAC Mode - data[3]
if (HVAC_Mode == NULL) {
if (HVAC_Mode == nullptr) {
p = (char *)kHvacModeOptions; // default HVAC_HOT
}
else {
p = strchr(kHvacModeOptions, toupper(HVAC_Mode[0]));
}
if (!p) {
return true;
return IE_SYNTAX_IRHVAC;
}
mode = (p - kHvacModeOptions) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00
switch (mode) {
@ -394,14 +416,14 @@ bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power,
data[4] = (uint8_t)(Temp - 15);
// Set code for HVAC fan mode - data[5]
if (HVAC_FanMode == NULL) {
if (HVAC_FanMode == nullptr) {
p = (char *)kFanSpeedOptions; // default FAN_SPEED_AUTO
}
else {
p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0]));
}
if (!p) {
return true;
return IE_SYNTAX_IRHVAC;
}
mode = p - kFanSpeedOptions;
if ((mode == 0) || (mode > 3)) {
@ -432,7 +454,7 @@ bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power,
irsend->sendLG(LG_Code, 28);
// interrupts();
return false;
return IE_NO_ERROR;
}
@ -440,7 +462,7 @@ bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power,
Fujitsu
********************/
bool IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
uint8_t IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
{
const char kFujitsuHvacModeOptions[] = "HDCAF";
@ -453,7 +475,7 @@ bool IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po
if (0 == HVAC_Power) {
ac.off();
ac.send();
return false;
return IE_NO_ERROR;
}
uint8_t modes[5] = {FUJITSU_AC_MODE_HEAT, FUJITSU_AC_MODE_DRY, FUJITSU_AC_MODE_COOL, FUJITSU_AC_MODE_AUTO, FUJITSU_AC_MODE_FAN};
@ -462,32 +484,32 @@ bool IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po
ac.setSwing(FUJITSU_AC_SWING_VERT);
char *p;
if (NULL == HVAC_Mode) {
if (nullptr == HVAC_Mode) {
p = (char *)kFujitsuHvacModeOptions;
}
else {
p = strchr(kFujitsuHvacModeOptions, toupper(HVAC_Mode[0]));
}
if (!p) {
return true;
return IE_SYNTAX_IRHVAC;
}
ac.setMode(modes[p - kFujitsuHvacModeOptions]);
if (HVAC_FanMode == NULL) {
if (HVAC_FanMode == nullptr) {
p = (char *)kFanSpeedOptions; // default FAN_SPEED_AUTO
}
else {
p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0]));
}
if (!p) {
return true;
return IE_SYNTAX_IRHVAC;
}
ac.setFanSpeed(fanModes[p - kFanSpeedOptions]);
ac.setTemp(HVAC_Temp);
ac.send();
return false;
return IE_NO_ERROR;
}
#endif // USE_IR_HVAC
@ -499,6 +521,7 @@ bool IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po
/*
* ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
IRsend:
{ "protocol": "RC5", "bits": 12, "data":"0xC86" }
{ "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
IRhvac:
{ "Vendor": "<Toshiba|Mitsubishi>", "Power": <0|1>, "Mode": "<Hot|Cold|Dry|Auto>", "FanSpeed": "<1|2|3|4|5|Auto|Silence>", "Temp": <17..30> }
@ -508,7 +531,7 @@ bool IrSendCommand(void)
{
char command [CMDSZ];
bool serviced = true;
bool error = false;
uint8_t error = IE_NO_ERROR;
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kIrRemoteCommands);
if (-1 == command_code) {
@ -516,92 +539,166 @@ bool IrSendCommand(void)
}
else if (CMND_IRSEND == command_code) {
if (XdrvMailbox.data_len) {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
if (!strstr(XdrvMailbox.data, "{")) { // If no JSON it must be rawdata
// IRSend frequency, rawdata, rawdata ...
if (strstr(XdrvMailbox.data, "{") == nullptr) { // If no JSON it must be rawdata
// IRsend <freq>,<rawdata>,<rawdata> ...
// or
// IRsend raw,<freq>,<zero space>,<bit stream> (one space = zero space *2)
// IRsend raw,<freq>,<zero space>,<zero space multiplier becoming one space>,<bit stream>
// IRsend raw,<freq>,<zero space>,<one space>,<bit stream>
// IRsend raw,<freq>,<header mark>,<header space>,<bit mark>,<zero space>,<one space>,<bit stream>
char *p;
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
uint16_t freq = atoi(str);
if (!freq) { freq = 38000; } // Default to 38kHz
uint16_t count = 0;
char *q = p;
for (; *q; count += (*q++ == ','));
if (count) { // At least two raw data values
count++;
uint16_t raw_array[count]; // It's safe to use stack for up to 240 packets (limited by mqtt_data length)
uint8_t i = 0;
for (str = strtok_r(NULL, ", ", &p); str && i < count; str = strtok_r(NULL, ", ", &p)) {
raw_array[i++] = strtoul(str, NULL, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input
}
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: Count %d, Freq %d, Arr[0] %d, Arr[count -1] %d"), count, freq, raw_array[0], raw_array[count -1]);
irsend_active = true;
irsend->sendRaw(raw_array, count, freq);
if (!count) {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_FAILED);
}
}
else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_RAWDATA);
}
}
else {
char dataBufUc[XdrvMailbox.data_len];
UpperCase(dataBufUc, XdrvMailbox.data);
StaticJsonBuffer<128> jsonBuf;
JsonObject &root = jsonBuf.parseObject(dataBufUc);
if (!root.success()) {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON);
}
else {
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
char parm_uc[10];
const char *protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))];
uint32_t bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS))];
uint32_t data = strtoul(root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA))], NULL, 0);
if (protocol && bits) {
char protocol_text[20];
int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: protocol_text %s, protocol %s, bits %d, data %u (0x%lX), protocol_code %d"),
protocol_text, protocol, bits, data, data, protocol_code);
irsend_active = true;
switch (protocol_code) {
case NEC:
irsend->sendNEC(data, (bits > NEC_BITS) ? NEC_BITS : bits); break;
case SONY:
irsend->sendSony(data, (bits > SONY_20_BITS) ? SONY_20_BITS : bits, 2); break;
case RC5:
irsend->sendRC5(data, bits); break;
case RC6:
irsend->sendRC6(data, bits); break;
case DISH:
irsend->sendDISH(data, (bits > DISH_BITS) ? DISH_BITS : bits); break;
case JVC:
irsend->sendJVC(data, (bits > JVC_BITS) ? JVC_BITS : bits, 1); break;
case SAMSUNG:
irsend->sendSAMSUNG(data, (bits > SAMSUNG_BITS) ? SAMSUNG_BITS : bits); break;
case PANASONIC:
irsend->sendPanasonic(bits, data); break;
default:
irsend_active = false;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_PROTOCOL_NOT_SUPPORTED);
if (p == nullptr) {
error = IE_INVALID_RAWDATA;
} else {
uint16_t freq = atoi(str);
if (!freq && (*str != '0')) { // First parameter is any string
uint16_t count = 0;
char *q = p;
for (; *q; count += (*q++ == ','));
if (count < 2) { // Parameters must be at least 3
error = IE_INVALID_RAWDATA;
} else {
uint16_t parm[count];
for (uint8_t i = 0; i < count; i++) {
parm[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0);
if (!parm[i]) {
if (!i) {
parm[0] = 38000; // Frequency default to 38kHz
} else {
error = IE_INVALID_RAWDATA; // Other parameters may not be 0
break;
}
}
}
if (IE_NO_ERROR == error) {
uint16_t i = 0;
if (count < 4) {
// IRsend raw,0,889,000000100110000001001
uint16_t mark = parm[1] *2; // Protocol where 0 = t, 1 = 2t (RC5)
if (3 == count) {
if (parm[2] < parm[1]) {
// IRsend raw,0,889,2,000000100110000001001
mark = parm[1] * parm[2]; // Protocol where 0 = t1, 1 = t1*t2 (Could be RC5)
} else {
// IRsend raw,0,889,1778,000000100110000001001
mark = parm[2]; // Protocol where 0 = t1, 1 = t2 (Could be RC5)
}
}
uint16_t raw_array[strlen(p)]; // Bits
for (; *p; *p++) {
if (*p == '0') {
raw_array[i++] = parm[1]; // Space
}
else if (*p == '1') {
raw_array[i++] = mark; // Mark
}
}
irsend_active = true;
irsend->sendRaw(raw_array, i, parm[0]);
}
else if (6 == count) { // NEC Protocol
// IRsend raw,0,8620,4260,544,411,1496,010101101000111011001110000000001100110000000001100000000000000010001100
uint16_t raw_array[strlen(p)*2+3]; // Header + bits + end
raw_array[i++] = parm[1]; // Header mark
raw_array[i++] = parm[2]; // Header space
for (; *p; *p++) {
if (*p == '0') {
raw_array[i++] = parm[3]; // Bit mark
raw_array[i++] = parm[4]; // Zero space
}
else if (*p == '1') {
raw_array[i++] = parm[3]; // Bit mark
raw_array[i++] = parm[5]; // One space
}
}
raw_array[i++] = parm[3]; // Trailing mark
irsend_active = true;
irsend->sendRaw(raw_array, i, parm[0]);
}
else {
error = IE_INVALID_RAWDATA; // Invalid number of parameters
}
}
}
} else {
if (!freq) { freq = 38000; } // Default to 38kHz
uint16_t count = 0;
char *q = p;
for (; *q; count += (*q++ == ','));
if (0 == count) {
error = IE_INVALID_RAWDATA;
} else { // At least two raw data values
// IRsend 0,896,876,900,888,894,876,1790,874,872,1810,1736,948,872,880,872,936,872,1792,900,888,1734
count++;
uint16_t raw_array[count]; // It's safe to use stack for up to 240 packets (limited by mqtt_data length)
for (uint16_t i = 0; i < count; i++) {
raw_array[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0); // Allow decimal (20496) and hexadecimal (0x5010) input
}
irsend_active = true;
irsend->sendRaw(raw_array, count, freq);
}
}
else {
error = true;
}
} else {
char dataBufUc[XdrvMailbox.data_len];
UpperCase(dataBufUc, XdrvMailbox.data);
RemoveSpace(dataBufUc);
if (strlen(dataBufUc) < 8) {
error = IE_INVALID_JSON;
} else {
StaticJsonBuffer<128> jsonBuf;
JsonObject &root = jsonBuf.parseObject(dataBufUc);
if (!root.success()) {
error = IE_INVALID_JSON;
} else {
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
char parm_uc[10];
const char *protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))];
uint16_t bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS))];
uint64_t data = strtoull(root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA))], nullptr, 0);
if (protocol && bits) {
char protocol_text[20];
int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols);
char dvalue[64];
char hvalue[64];
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: protocol_text %s, protocol %s, bits %d, data %s (%s), protocol_code %d"),
protocol_text, protocol, bits, ulltoa(data, dvalue, 10), IrUint64toHex(data, hvalue, bits), protocol_code);
irsend_active = true;
switch (protocol_code) {
case NEC:
irsend->sendNEC(data, (bits > NEC_BITS) ? NEC_BITS : bits); break;
case SONY:
irsend->sendSony(data, (bits > SONY_20_BITS) ? SONY_20_BITS : bits, 2); break;
case RC5:
irsend->sendRC5(data, bits); break;
case RC6:
irsend->sendRC6(data, bits); break;
case DISH:
irsend->sendDISH(data, (bits > DISH_BITS) ? DISH_BITS : bits); break;
case JVC:
irsend->sendJVC(data, (bits > JVC_BITS) ? JVC_BITS : bits, 1); break;
case SAMSUNG:
irsend->sendSAMSUNG(data, (bits > SAMSUNG_BITS) ? SAMSUNG_BITS : bits); break;
case PANASONIC:
// irsend->sendPanasonic(bits, data); break;
irsend->sendPanasonic64(data, bits); break;
default:
irsend_active = false;
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_PROTOCOL_NOT_SUPPORTED);
}
} else {
error = IE_SYNTAX_IRSEND;
}
}
}
}
}
else {
error = true;
}
if (error) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_NO " " D_JSON_IR_PROTOCOL ", " D_JSON_IR_BITS " " D_JSON_OR " " D_JSON_IR_DATA "\"}"));
} else {
error = IE_SYNTAX_IRSEND;
}
}
#ifdef USE_IR_HVAC
@ -615,47 +712,65 @@ bool IrSendCommand(void)
if (XdrvMailbox.data_len) {
char dataBufUc[XdrvMailbox.data_len];
UpperCase(dataBufUc, XdrvMailbox.data);
StaticJsonBuffer<164> jsonBufer;
JsonObject &root = jsonBufer.parseObject(dataBufUc);
if (!root.success()) {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON);
}
else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
HVAC_Vendor = root[D_JSON_IRHVAC_VENDOR];
HVAC_Power = root[D_JSON_IRHVAC_POWER];
HVAC_Mode = root[D_JSON_IRHVAC_MODE];
HVAC_FanMode = root[D_JSON_IRHVAC_FANSPEED];
HVAC_Temp = root[D_JSON_IRHVAC_TEMP];
RemoveSpace(dataBufUc);
if (strlen(dataBufUc) < 8) {
error = IE_INVALID_JSON;
} else {
StaticJsonBuffer<164> jsonBufer;
JsonObject &root = jsonBufer.parseObject(dataBufUc);
if (!root.success()) {
error = IE_INVALID_JSON;
} else {
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
HVAC_Vendor = root[D_JSON_IRHVAC_VENDOR];
HVAC_Power = root[D_JSON_IRHVAC_POWER];
HVAC_Mode = root[D_JSON_IRHVAC_MODE];
HVAC_FanMode = root[D_JSON_IRHVAC_FANSPEED];
HVAC_Temp = root[D_JSON_IRHVAC_TEMP];
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"), HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp);
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"), HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp);
char vendor[20];
int vendor_code = GetCommandCode(vendor, sizeof(vendor), HVAC_Vendor, kIrHvacVendors);
switch (vendor_code) {
case VNDR_TOSHIBA:
error = IrHvacToshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
case VNDR_MITSUBISHI:
error = IrHvacMitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
case VNDR_LG:
error = IrHvacLG(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
case VNDR_FUJITSU:
error = IrHvacFujitsu(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
default:
error = true;
char vendor[20];
int vendor_code = GetCommandCode(vendor, sizeof(vendor), HVAC_Vendor, kIrHvacVendors);
switch (vendor_code) {
case VNDR_TOSHIBA:
error = IrHvacToshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
case VNDR_MITSUBISHI:
error = IrHvacMitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
case VNDR_LG:
error = IrHvacLG(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
case VNDR_FUJITSU:
error = IrHvacFujitsu(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
default:
error = IE_SYNTAX_IRHVAC;
}
}
}
}
else {
error = true;
}
if (error) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRHVAC "\":\"" D_JSON_WRONG " " D_JSON_IRHVAC_VENDOR ", " D_JSON_IRHVAC_MODE " " D_JSON_OR " " D_JSON_IRHVAC_FANSPEED "\"}"));
error = IE_SYNTAX_IRHVAC;
}
}
#endif // USE_IR_HVAC
else serviced = false; // Unknown command
switch (error) {
case IE_INVALID_RAWDATA:
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_RAWDATA);
break;
case IE_INVALID_JSON:
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON);
break;
case IE_SYNTAX_IRSEND:
Response_P(PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_NO " " D_JSON_IR_PROTOCOL ", " D_JSON_IR_BITS " " D_JSON_OR " " D_JSON_IR_DATA "\"}"));
break;
#ifdef USE_IR_HVAC
case IE_SYNTAX_IRHVAC:
Response_P(PSTR("{\"" D_CMND_IRHVAC "\":\"" D_JSON_WRONG " " D_JSON_IRHVAC_VENDOR ", " D_JSON_IRHVAC_MODE " " D_JSON_OR " " D_JSON_IRHVAC_FANSPEED "\"}"));
break;
#endif // USE_IR_HVAC
}
return serviced;
}

View File

@ -23,7 +23,7 @@
#define XDRV_06 6
#define SFB_TIME_AVOID_DUPLICATE 2000 // Milliseconds
const uint32_t SFB_TIME_AVOID_DUPLICATE = 2000; // Milliseconds
enum SonoffBridgeCommands {
CMND_RFSYNC, CMND_RFLOW, CMND_RFHIGH, CMND_RFHOST, CMND_RFCODE, CMND_RFKEY, CMND_RFRAW };
@ -51,8 +51,8 @@ unsigned long sonoff_bridge_last_learn_time = 0;
#include "ihx.h"
#include "c2.h"
#define RF_RECORD_NO_START_FOUND -1
#define RF_RECORD_NO_END_FOUND -2
const ssize_t RF_RECORD_NO_START_FOUND = -1;
const ssize_t RF_RECORD_NO_END_FOUND = -2;
ssize_t rf_find_hex_record_start(uint8_t *buf, size_t size)
{
@ -98,7 +98,7 @@ ssize_t rf_glue_remnant_with_new_data_and_write(const uint8_t *remnant_data, uin
glue_record_sz = strlen((const char *) remnant_data) + record_end;
glue_buf = (uint8_t *) malloc(glue_record_sz);
if (glue_buf == NULL) { return -2; } // Not enough space
if (glue_buf == nullptr) { return -2; } // Not enough space
// Assemble new glue buffer
memcpy(glue_buf, remnant_data, strlen((const char *) remnant_data));
@ -208,17 +208,17 @@ void SonoffBridgeReceivedRaw(void)
if (0xB1 == serial_in_buffer[1]) { buckets = serial_in_buffer[2] << 1; } // Bucket sniffing
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RFRAW "\":{\"" D_JSON_DATA "\":\""));
Response_P(PSTR("{\"" D_CMND_RFRAW "\":{\"" D_JSON_DATA "\":\""));
for (int i = 0; i < serial_in_byte_counter; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%02X"), mqtt_data, serial_in_buffer[i]);
ResponseAppend_P(PSTR("%02X"), serial_in_buffer[i]);
if (0xB1 == serial_in_buffer[1]) {
if ((i > 3) && buckets) { buckets--; }
if ((i < 3) || (buckets % 2) || (i == serial_in_byte_counter -2)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s "), mqtt_data);
ResponseAppend_P(PSTR(" "));
}
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"}}"), mqtt_data);
ResponseAppend_P(PSTR("\"}}"));
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_CMND_RFRAW));
XdrvRulesProcess();
}
@ -228,7 +228,7 @@ void SonoffBridgeReceivedRaw(void)
void SonoffBridgeLearnFailed(void)
{
sonoff_bridge_learn_active = 0;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, D_CMND_RFKEY, sonoff_bridge_learn_key, D_JSON_LEARN_FAILED);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, D_CMND_RFKEY, sonoff_bridge_learn_key, D_JSON_LEARN_FAILED);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_RFKEY));
}
@ -254,7 +254,7 @@ void SonoffBridgeReceived(void)
for (uint8_t i = 0; i < 9; i++) {
Settings.rf_code[sonoff_bridge_learn_key][i] = serial_in_buffer[i +1];
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, D_CMND_RFKEY, sonoff_bridge_learn_key, D_JSON_LEARNED);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, D_CMND_RFKEY, sonoff_bridge_learn_key, D_JSON_LEARNED);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_RFKEY));
} else {
SonoffBridgeLearnFailed();
@ -288,7 +288,7 @@ void SonoffBridgeReceived(void)
} else {
snprintf_P(stemp, sizeof(stemp), PSTR("\"%06X\""), received_id);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":%s,\"" D_CMND_RFKEY "\":%s}}"),
Response_P(PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":%s,\"" D_CMND_RFKEY "\":%s}}"),
sync_time, low_time, high_time, stemp, rfkey);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED));
XdrvRulesProcess();
@ -470,7 +470,7 @@ bool SonoffBridgeCommand(void)
} else {
snprintf_P(stemp, sizeof(stemp), PSTR("\"#%X\""), code);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_XVALUE, command, stemp);
Response_P(S_JSON_COMMAND_XVALUE, command, stemp);
}
else if ((CMND_RFKEY == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 16)) {
unsigned long now = millis();
@ -478,11 +478,11 @@ bool SonoffBridgeCommand(void)
sonoff_bridge_learn_active = 0;
if (2 == XdrvMailbox.payload) { // Learn RF data
SonoffBridgeLearn(XdrvMailbox.index);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_START_LEARNING);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_START_LEARNING);
}
else if (3 == XdrvMailbox.payload) { // Unlearn RF data
Settings.rf_code[XdrvMailbox.index][0] = 0; // Reset sync_time MSB
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_SET_TO_DEFAULT);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_SET_TO_DEFAULT);
}
else if (4 == XdrvMailbox.payload) { // Save RF data provided by RFSync, RfLow, RfHigh and last RfCode
for (uint8_t i = 0; i < 6; i++) {
@ -491,7 +491,7 @@ bool SonoffBridgeCommand(void)
Settings.rf_code[XdrvMailbox.index][6] = (sonoff_bridge_last_send_code >> 16) & 0xff;
Settings.rf_code[XdrvMailbox.index][7] = (sonoff_bridge_last_send_code >> 8) & 0xff;
Settings.rf_code[XdrvMailbox.index][8] = sonoff_bridge_last_send_code & 0xff;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_SAVED);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_SAVED);
} else if (5 == XdrvMailbox.payload) { // Show default or learned RF data
uint8_t key = XdrvMailbox.index;
uint8_t index = (0 == Settings.rf_code[key][0]) ? 0 : key; // Use default if sync_time MSB = 0
@ -505,19 +505,19 @@ bool SonoffBridgeCommand(void)
} else {
code |= Settings.rf_code[index][8];
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":\"%06X\"}}"),
Response_P(PSTR("{\"%s%d\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":\"%06X\"}}"),
command, XdrvMailbox.index, sync_time, low_time, high_time, code);
} else {
if ((1 == XdrvMailbox.payload) || (0 == Settings.rf_code[XdrvMailbox.index][0])) { // Test sync_time MSB
SonoffBridgeSend(0, XdrvMailbox.index); // Send default RF data
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_DEFAULT_SENT);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_DEFAULT_SENT);
} else {
SonoffBridgeSend(XdrvMailbox.index, 0); // Send learned RF data
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_LEARNED_SENT);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, D_JSON_LEARNED_SENT);
}
}
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, sonoff_bridge_learn_key, D_JSON_LEARNING_ACTIVE);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, sonoff_bridge_learn_key, D_JSON_LEARNING_ACTIVE);
}
}
else if (CMND_RFRAW == command_code) {
@ -548,7 +548,7 @@ bool SonoffBridgeCommand(void)
sonoff_bridge_receive_raw_flag = 1;
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(sonoff_bridge_receive_raw_flag));
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(sonoff_bridge_receive_raw_flag));
} else serviced = false; // Unknown command
return serviced;

View File

@ -79,8 +79,7 @@ void MqttPublishDomoticzFanState()
int fan_speed = GetFanspeed();
snprintf_P(svalue, sizeof(svalue), PSTR("%d"), fan_speed * 10);
snprintf_P(mqtt_data, sizeof(mqtt_data), DOMOTICZ_MESSAGE,
(int)Settings.domoticz_relay_idx[1], (0 == fan_speed) ? 0 : 2, svalue, DomoticzBatteryQuality(), DomoticzRssiQuality());
Response_P(DOMOTICZ_MESSAGE, (int)Settings.domoticz_relay_idx[1], (0 == fan_speed) ? 0 : 2, svalue, DomoticzBatteryQuality(), DomoticzRssiQuality());
MqttPublish(domoticz_in_topic);
fan_debounce = millis();
@ -106,8 +105,7 @@ void MqttPublishDomoticzPowerState(uint8_t device)
char svalue[8]; // Dimmer value
snprintf_P(svalue, sizeof(svalue), PSTR("%d"), Settings.light_dimmer);
snprintf_P(mqtt_data, sizeof(mqtt_data), DOMOTICZ_MESSAGE,
(int)Settings.domoticz_relay_idx[device -1], (power & (1 << (device -1))) ? 1 : 0, (light_type) ? svalue : "", DomoticzBatteryQuality(), DomoticzRssiQuality());
Response_P(DOMOTICZ_MESSAGE, (int)Settings.domoticz_relay_idx[device -1], (power & (1 << (device -1))) ? 1 : 0, (light_type) ? svalue : "", DomoticzBatteryQuality(), DomoticzRssiQuality());
MqttPublish(domoticz_in_topic);
}
}
@ -301,31 +299,31 @@ bool DomoticzCommand(void)
Settings.domoticz_relay_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE, command, XdrvMailbox.index, Settings.domoticz_relay_idx[XdrvMailbox.index -1]);
Response_P(S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE, command, XdrvMailbox.index, Settings.domoticz_relay_idx[XdrvMailbox.index -1]);
}
else if ((CMND_KEYIDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) {
if (XdrvMailbox.payload >= 0) {
Settings.domoticz_key_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE, command, XdrvMailbox.index, Settings.domoticz_key_idx[XdrvMailbox.index -1]);
Response_P(S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE, command, XdrvMailbox.index, Settings.domoticz_key_idx[XdrvMailbox.index -1]);
}
else if ((CMND_SWITCHIDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) {
if (XdrvMailbox.payload >= 0) {
Settings.domoticz_switch_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_switch_idx[XdrvMailbox.index -1]);
Response_P(S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_switch_idx[XdrvMailbox.index -1]);
}
else if ((CMND_SENSORIDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= DZ_MAX_SENSORS)) {
if (XdrvMailbox.payload >= 0) {
Settings.domoticz_sensor_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_sensor_idx[XdrvMailbox.index -1]);
Response_P(S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_sensor_idx[XdrvMailbox.index -1]);
}
else if (CMND_UPDATETIMER == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.domoticz_update_timer = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_DOMOTICZ "%s\":%d}"), command, Settings.domoticz_update_timer);
Response_P(PSTR("{\"" D_CMND_DOMOTICZ "%s\":%d}"), command, Settings.domoticz_update_timer);
}
else serviced = false; // Unknown command
}
@ -340,7 +338,7 @@ bool DomoticzSendKey(uint8_t key, uint8_t device, uint8_t state, uint8_t svalflg
if (device <= MAX_DOMOTICZ_IDX) {
if ((Settings.domoticz_key_idx[device -1] || Settings.domoticz_switch_idx[device -1]) && (svalflg)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"),
Response_P(PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"),
(key) ? Settings.domoticz_switch_idx[device -1] : Settings.domoticz_key_idx[device -1], (state) ? (2 == state) ? "Toggle" : "On" : "Off");
MqttPublish(domoticz_in_topic);
result = 1;
@ -375,14 +373,14 @@ uint8_t DomoticzHumidityState(char *hum)
void DomoticzSensor(uint8_t idx, char *data)
{
if (Settings.domoticz_sensor_idx[idx]) {
char dmess[90];
char dmess[100];
memcpy(dmess, mqtt_data, sizeof(dmess));
if (DZ_AIRQUALITY == idx) {
snprintf_P(mqtt_data, sizeof(dmess), PSTR("{\"idx\":%d,\"nvalue\":%s,\"Battery\":%d,\"RSSI\":%d}"),
Response_P(PSTR("{\"idx\":%d,\"nvalue\":%s,\"Battery\":%d,\"RSSI\":%d}"),
Settings.domoticz_sensor_idx[idx], data, DomoticzBatteryQuality(), DomoticzRssiQuality());
} else {
snprintf_P(mqtt_data, sizeof(dmess), DOMOTICZ_MESSAGE,
Response_P(DOMOTICZ_MESSAGE,
Settings.domoticz_sensor_idx[idx], 0, data, DomoticzBatteryQuality(), DomoticzRssiQuality());
}
MqttPublish(domoticz_in_topic);

View File

@ -24,17 +24,17 @@
#define XDRV_08 8
#define SERIAL_BRIDGE_BUFFER_SIZE 130
const uint8_t SERIAL_BRIDGE_BUFFER_SIZE = 130;
#include <TasmotaSerial.h>
enum SerialBridgeCommands { CMND_SSERIALSEND, CMND_SBAUDRATE };
const char kSerialBridgeCommands[] PROGMEM = D_CMND_SSERIALSEND "|" D_CMND_SBAUDRATE;
TasmotaSerial *SerialBridgeSerial = NULL;
TasmotaSerial *SerialBridgeSerial = nullptr;
unsigned long serial_bridge_polling_window = 0;
char *serial_bridge_buffer = NULL;
char *serial_bridge_buffer = nullptr;
int serial_bridge_in_byte_counter = 0;
bool serial_bridge_active = true;
bool serial_bridge_raw = false;
@ -68,16 +68,16 @@ void SerialBridgeInput(void)
if (serial_bridge_in_byte_counter && (millis() > (serial_bridge_polling_window + SERIAL_POLLING))) {
serial_bridge_buffer[serial_bridge_in_byte_counter] = 0; // Serial data completed
if (!serial_bridge_raw) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SSERIALRECEIVED "\":\"%s\"}"), serial_bridge_buffer);
Response_P(PSTR("{\"" D_JSON_SSERIALRECEIVED "\":\"%s\"}"), serial_bridge_buffer);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SSERIALRECEIVED "\":\""));
Response_P(PSTR("{\"" D_JSON_SSERIALRECEIVED "\":\""));
for (int i = 0; i < serial_bridge_in_byte_counter; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%02x"), mqtt_data, serial_bridge_buffer[i]);
ResponseAppend_P(PSTR("%02x"), serial_bridge_buffer[i]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"}"), mqtt_data);
ResponseAppend_P(PSTR("\"}"));
}
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED));
// XdrvRulesProcess();
XdrvRulesProcess();
serial_bridge_in_byte_counter = 0;
}
}
@ -144,7 +144,7 @@ bool SerialBridgeCommand(void)
codes += 2;
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
}
else if (CMND_SBAUDRATE == command_code) {
@ -155,7 +155,7 @@ bool SerialBridgeCommand(void)
Settings.sbaudrate = (1 == XdrvMailbox.payload) ? SOFT_BAUDRATE / 1200 : baud;
SerialBridgeSerial->begin(Settings.sbaudrate * 1200); // Reinitialize serial port with new baud rate
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.sbaudrate * 1200);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.sbaudrate * 1200);
}
else serviced = false; // Unknown command
@ -172,12 +172,12 @@ bool Xdrv08(uint8_t function)
if (serial_bridge_active) {
switch (function) {
case FUNC_PRE_INIT:
SerialBridgeInit();
break;
case FUNC_LOOP:
if (SerialBridgeSerial) { SerialBridgeInput(); }
break;
case FUNC_PRE_INIT:
SerialBridgeInit();
break;
case FUNC_COMMAND:
result = SerialBridgeCommand();
break;

View File

@ -287,7 +287,7 @@ void TimerEverySecond(void)
Settings.timer[i].arm = xtimer.repeat;
#ifdef USE_RULES
if (3 == xtimer.power) { // Blink becomes Rule disregarding device and allowing use of Backlog commands
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Clock\":{\"Timer\":%d}}"), i +1);
Response_P(PSTR("{\"Clock\":{\"Timer\":%d}}"), i +1);
XdrvRulesProcess();
} else
#endif // USE_RULES
@ -325,11 +325,11 @@ void PrepShowTimer(uint8_t index)
sign[0] = '-';
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_TIMER "%d\":{\"" D_JSON_TIMER_ARM "\":%d,\"" D_JSON_TIMER_MODE "\":%d,\"" D_JSON_TIMER_TIME "\":\"%s%02d:%02d\",\"" D_JSON_TIMER_WINDOW "\":%d,\"" D_JSON_TIMER_DAYS "\":\"%s\",\"" D_JSON_TIMER_REPEAT "\":%d%s,\"" D_JSON_TIMER_ACTION "\":%d}"),
mqtt_data, index, xtimer.arm, xtimer.mode, sign, hour, xtimer.time % 60, xtimer.window, days, xtimer.repeat, soutput, xtimer.power);
ResponseAppend_P(PSTR("\"" D_CMND_TIMER "%d\":{\"" D_JSON_TIMER_ARM "\":%d,\"" D_JSON_TIMER_MODE "\":%d,\"" D_JSON_TIMER_TIME "\":\"%s%02d:%02d\",\"" D_JSON_TIMER_WINDOW "\":%d,\"" D_JSON_TIMER_DAYS "\":\"%s\",\"" D_JSON_TIMER_REPEAT "\":%d%s,\"" D_JSON_TIMER_ACTION "\":%d}"),
index, xtimer.arm, xtimer.mode, sign, hour, xtimer.time % 60, xtimer.window, days, xtimer.repeat, soutput, xtimer.power);
#else
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_TIMER "%d\":{\"" D_JSON_TIMER_ARM "\":%d,\"" D_JSON_TIMER_TIME "\":\"%02d:%02d\",\"" D_JSON_TIMER_WINDOW "\":%d,\"" D_JSON_TIMER_DAYS "\":\"%s\",\"" D_JSON_TIMER_REPEAT "\":%d%s,\"" D_JSON_TIMER_ACTION "\":%d}"),
mqtt_data, index, xtimer.arm, xtimer.time / 60, xtimer.time % 60, xtimer.window, days, xtimer.repeat, soutput, xtimer.power);
ResponseAppend_P(PSTR("\"" D_CMND_TIMER "%d\":{\"" D_JSON_TIMER_ARM "\":%d,\"" D_JSON_TIMER_TIME "\":\"%02d:%02d\",\"" D_JSON_TIMER_WINDOW "\":%d,\"" D_JSON_TIMER_DAYS "\":\"%s\",\"" D_JSON_TIMER_REPEAT "\":%d%s,\"" D_JSON_TIMER_ACTION "\":%d}"),
index, xtimer.arm, xtimer.time / 60, xtimer.time % 60, xtimer.window, days, xtimer.repeat, soutput, xtimer.power);
#endif // USE_SUNRISE
}
@ -365,7 +365,7 @@ bool TimerCommand(void)
StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(dataBufUc);
if (!root.success()) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_INVALID_JSON "\"}"), index); // JSON decode failed
Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_INVALID_JSON "\"}"), index); // JSON decode failed
error = 1;
}
else {
@ -387,7 +387,7 @@ bool TimerCommand(void)
strlcpy(time_str, root[parm_uc], sizeof(time_str));
const char *substr = strtok(time_str, ":");
if (substr != NULL) {
if (substr != nullptr) {
if (strchr(substr, '-')) {
sign = 1;
substr++;
@ -396,8 +396,8 @@ bool TimerCommand(void)
if (sign) { value += 12; } // Allow entering timer offset from -11:59 to -00:01 converted to 12:01 to 23:59
if (value > 23) { value = 23; }
itime = value * 60;
substr = strtok(NULL, ":");
if (substr != NULL) {
substr = strtok(nullptr, ":");
if (substr != nullptr) {
value = atoi(substr);
if (value < 0) { value = 0; }
if (value > 59) { value = 59; }
@ -439,16 +439,16 @@ bool TimerCommand(void)
}
#ifndef USE_RULES
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_TIMER_NO_DEVICE "\"}"), index); // No outputs defined so nothing to control
Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_TIMER_NO_DEVICE "\"}"), index); // No outputs defined so nothing to control
error = 1;
}
#endif
}
}
if (!error) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{"));
Response_P(PSTR("{"));
PrepShowTimer(index);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
}
}
else if (CMND_TIMERS == command_code) {
@ -461,21 +461,21 @@ bool TimerCommand(void)
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag3.timers_enable));
Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag3.timers_enable));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, command);
uint8_t jsflg = 0;
uint8_t lines = 1;
for (uint8_t i = 0; i < MAX_TIMERS; i++) {
if (!jsflg) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_TIMERS "%d\":{"), lines++);
Response_P(PSTR("{\"" D_CMND_TIMERS "%d\":{"), lines++);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
ResponseAppend_P(PSTR(","));
}
jsflg++;
PrepShowTimer(i +1);
if (jsflg > 3) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}}"), mqtt_data);
ResponseAppend_P(PSTR("}}"));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_TIMERS));
jsflg = 0;
}
@ -489,7 +489,7 @@ bool TimerCommand(void)
}
char lbuff[33];
dtostrfd(((double)Settings.longitude) /1000000, 6, lbuff);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, lbuff);
Response_P(S_JSON_COMMAND_SVALUE, command, lbuff);
}
else if (CMND_LATITUDE == command_code) {
if (XdrvMailbox.data_len) {
@ -497,7 +497,7 @@ bool TimerCommand(void)
}
char lbuff[33];
dtostrfd(((double)Settings.latitude) /1000000, 6, lbuff);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, lbuff);
Response_P(S_JSON_COMMAND_SVALUE, command, lbuff);
}
#endif
else serviced = false; // Unknown command
@ -596,8 +596,8 @@ const char HTTP_TIMER_SCRIPT4[] PROGMEM =
"if(ct<99){st();}" // Save changes
"ct=t;"
"o=document.getElementsByClassName('tl');" // Restore style to all tabs/buttons
"for(i=0;i<o.length;i++){o[i].style.cssText=\"background-color:#999;color:#fff;font-weight:normal;\"}"
"e.style.cssText=\"background-color:transparent;color:#000;font-weight:bold;\";" // Change style to tab/button used to open content
"for(i=0;i<o.length;i++){o[i].style.cssText=\"background:#%06x;color:#%06x;font-weight:normal;\"}" // COLOR_TIMER_TAB_BACKGROUND, COLOR_TIMER_TAB_TEXT
"e.style.cssText=\"background:#%06x;color:#%06x;font-weight:bold;\";" // COLOR_FORM, COLOR_TEXT, Change style to tab/button used to open content
"s=pt[ct];" // Get parameters from array
#ifdef USE_SUNRISE
"p=(s>>29)&3;eb('b'+p).checked=1;" // Set mode
@ -620,7 +620,12 @@ const char HTTP_TIMER_SCRIPT5[] PROGMEM =
"function it(){" // Initialize elements and select first tab
"var b,i,o,s;"
"pt=eb('t0').value.split(',').map(Number);" // Get parameters from hidden area to array
"s='';for(i=0;i<" STR(MAX_TIMERS) ";i++){b='';if(0==i){b=\" id='dP'\";}s+=\"<button type='button' class='tl' onclick='ot(\"+i+\",this)'\"+b+\">\"+(i+1)+\"</button>\"}"
"s='';"
"for(i=0;i<%d;i++){"
"b='';"
"if(0==i){b=\" id='dP'\";}"
"s+=\"<button type='button' class='tl' onclick='ot(\"+i+\",this)'\"+b+\">\"+(i+1)+\"</button>\""
"}"
"eb('bt').innerHTML=s;" // Create tabs
"if(%d>0){" // Create Output and Action drop down boxes
"eb('oa').innerHTML=\"<b>" D_TIMER_OUTPUT "</b>&nbsp;<span><select style='width:60px;' id='d1' name='d1'></select></span>&emsp;<b>" D_TIMER_ACTION "</b>&nbsp;<select style='width:99px;' id='p1' name='p1'></select>\";"
@ -648,7 +653,7 @@ const char HTTP_TIMER_SCRIPT6[] PROGMEM =
"}"
"window.onload=it;";
const char HTTP_TIMER_STYLE[] PROGMEM =
".tl{float:left;border-radius:0;border:1px solid #f2f2f2;padding:1px;width:6.25%%;}"; // Border color needs to be the same as Fieldset background color from HTTP_HEAD_STYLE1 (transparent won't work)
".tl{float:left;border-radius:0;border:1px solid #%06x;padding:1px;width:6.25%%;}"; // COLOR_FORM, Border color needs to be the same as Fieldset background color from HTTP_HEAD_STYLE1 (transparent won't work)
const char HTTP_FORM_TIMER1[] PROGMEM =
"<fieldset style='min-width:470px;text-align:center;'>"
"<legend style='text-align:left;'><b>&nbsp;" D_TIMER_PARAMETERS "&nbsp;</b></legend>"
@ -704,10 +709,10 @@ void HandleTimerConfiguration(void)
WSContentSend_P(HTTP_TIMER_SCRIPT2);
#endif // USE_SUNRISE
WSContentSend_P(HTTP_TIMER_SCRIPT3, devices_present);
WSContentSend_P(HTTP_TIMER_SCRIPT4, devices_present);
WSContentSend_P(HTTP_TIMER_SCRIPT5, devices_present);
WSContentSend_P(HTTP_TIMER_SCRIPT4, WebColor(COL_TIMER_TAB_BACKGROUND), WebColor(COL_TIMER_TAB_TEXT), WebColor(COL_FORM), WebColor(COL_TEXT), devices_present);
WSContentSend_P(HTTP_TIMER_SCRIPT5, MAX_TIMERS, devices_present);
WSContentSend_P(HTTP_TIMER_SCRIPT6, devices_present);
WSContentSendStyle_P(HTTP_TIMER_STYLE);
WSContentSendStyle_P(HTTP_TIMER_STYLE, WebColor(COL_FORM));
WSContentSend_P(HTTP_FORM_TIMER1, (Settings.flag3.timers_enable) ? " checked" : "");
for (uint8_t i = 0; i < MAX_TIMERS; i++) {
WSContentSend_P(PSTR("%s%u"), (i > 0) ? "," : "", Settings.timer[i].data);

View File

@ -369,7 +369,7 @@ bool RuleSetProcess(uint8_t rule_set, String &event_saved)
AddLog_P2(LOG_LEVEL_INFO, PSTR("RUL: %s performs \"%s\""), event_trigger.c_str(), command);
// snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, D_CMND_RULE, D_JSON_INITIATED);
// Response_P(S_JSON_COMMAND_SVALUE, D_CMND_RULE, D_JSON_INITIATED);
// MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_RULE));
ExecuteCommand(command, SRC_RULE);
@ -486,23 +486,25 @@ void RulesEvery50ms(void)
event_data[0] ='\0';
}
}
else if (vars_event) {
for (uint8_t i = 0; i < MAX_RULE_VARS-1; i++) {
if (bitRead(vars_event, i)) {
bitClear(vars_event, i);
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Var%d\":{\"State\":%s}}"), i+1, vars[i]);
RulesProcessEvent(json_event);
break;
else if (vars_event || mems_event){
if (vars_event) {
for (uint8_t i = 0; i < MAX_RULE_VARS; i++) {
if (bitRead(vars_event, i)) {
bitClear(vars_event, i);
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Var%d\":{\"State\":%s}}"), i+1, vars[i]);
RulesProcessEvent(json_event);
break;
}
}
}
}
else if (mems_event) {
for (uint8_t i = 0; i < MAX_RULE_MEMS-1; i++) {
if (bitRead(mems_event, i)) {
bitClear(mems_event, i);
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Mem%d\":{\"State\":%s}}"), i+1, Settings.mems[i]);
RulesProcessEvent(json_event);
break;
if (mems_event) {
for (uint8_t i = 0; i < MAX_RULE_MEMS; i++) {
if (bitRead(mems_event, i)) {
bitClear(mems_event, i);
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Mem%d\":{\"State\":%s}}"), i+1, Settings.mems[i]);
RulesProcessEvent(json_event);
break;
}
}
}
}
@ -520,6 +522,7 @@ void RulesEvery50ms(void)
case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
case 5: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break;
case 6: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
case 7: strncpy_P(json_event, PSTR("{\"HTTP\":{\"Initialized\":1}}"), sizeof(json_event)); break;
}
if (json_event[0]) {
RulesProcessEvent(json_event);
@ -544,7 +547,7 @@ void RulesEvery100ms(void)
tele_period = tele_period_save;
if (strlen(mqtt_data)) {
mqtt_data[0] = '{'; // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
RulesProcess();
}
}
@ -672,10 +675,10 @@ String RulesSubscribe(const char *data, int data_len)
char * pos = strtok(parameters, ",");
if (pos) {
event_name = Trim(pos);
pos = strtok(NULL, ",");
pos = strtok(nullptr, ",");
if (pos) {
topic = Trim(pos);
pos = strtok(NULL, ",");
pos = strtok(nullptr, ",");
if (pos) {
key = Trim(pos);
}
@ -1139,15 +1142,15 @@ bool RulesCommand(void)
}
mqtt_data[0] = '\0';
for (uint8_t i = 0; i < MAX_RULE_TIMERS; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%c\"T%d\":%d"), mqtt_data, (i) ? ',' : '{', i +1, (rules_timer[i]) ? (rules_timer[i] - millis()) / 1000 : 0);
ResponseAppend_P(PSTR("%c\"T%d\":%d"), (i) ? ',' : '{', i +1, (rules_timer[i]) ? (rules_timer[i] - millis()) / 1000 : 0);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
}
else if (CMND_EVENT == command_code) {
if (XdrvMailbox.data_len > 0) {
strlcpy(event_data, XdrvMailbox.data, sizeof(event_data));
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
else if ((CMND_VAR == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) {
@ -1158,7 +1161,7 @@ bool RulesCommand(void)
#endif //USE_EXPRESSION
bitSet(vars_event, index -1);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_MEM == command_code) && (index > 0) && (index <= MAX_RULE_MEMS)) {
if (XdrvMailbox.data_len > 0) {
@ -1169,13 +1172,13 @@ bool RulesCommand(void)
#endif //USE_EXPRESSION
bitSet(mems_event, index -1);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]);
}
else if (CMND_CALC_RESOLUTION == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 7)) {
Settings.flag2.calc_resolution = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.calc_resolution);
Response_P(S_JSON_COMMAND_NVALUE, command, Settings.flag2.calc_resolution);
}
else if ((CMND_ADD == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) {
@ -1183,7 +1186,7 @@ bool RulesCommand(void)
dtostrfd(tempvar, Settings.flag2.calc_resolution, vars[index -1]);
bitSet(vars_event, index -1);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_SUB == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) {
@ -1191,7 +1194,7 @@ bool RulesCommand(void)
dtostrfd(tempvar, Settings.flag2.calc_resolution, vars[index -1]);
bitSet(vars_event, index -1);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_MULT == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) {
@ -1199,11 +1202,11 @@ bool RulesCommand(void)
dtostrfd(tempvar, Settings.flag2.calc_resolution, vars[index -1]);
bitSet(vars_event, index -1);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_SCALE == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) {
if (strstr(XdrvMailbox.data, ",")) { // Process parameter entry
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry
char sub_string[XdrvMailbox.data_len +1];
double valueIN = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 1));
@ -1216,14 +1219,14 @@ bool RulesCommand(void)
bitSet(vars_event, index -1);
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
#ifdef SUPPORT_MQTT_EVENT
} else if (CMND_SUBSCRIBE == command_code) { //MQTT Subscribe command. Subscribe <Event>, <Topic> [, <Key>]
String result = RulesSubscribe(XdrvMailbox.data, XdrvMailbox.data_len);
snprintf_P(mqtt_data, sizeof(mqtt_data), 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>
String result = RulesUnsubscribe(XdrvMailbox.data, XdrvMailbox.data_len);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, result.c_str());
Response_P(S_JSON_COMMAND_SVALUE, command, result.c_str());
#endif //SUPPORT_MQTT_EVENT
}
else serviced = false; // Unknown command
@ -1275,4 +1278,4 @@ bool Xdrv10(uint8_t function)
return result;
}
#endif // USE_RULES
#endif // USE_RULES

View File

@ -880,6 +880,7 @@ void HandleKNXConfiguration(void)
"}"
"}"));
WSContentSendStyle();
KNX_physs_addr.value = Settings.knx_physsical_addr;
WSContentSend_P(HTTP_FORM_KNX, KNX_physs_addr.pa.area, KNX_physs_addr.pa.line, KNX_physs_addr.pa.member);
if ( Settings.flag.knx_enabled ) { WSContentSend_P(PSTR(" checked")); }
WSContentSend_P(HTTP_FORM_KNX1);
@ -1086,7 +1087,7 @@ bool KnxCommand(void)
else if (CMND_KNX_PA == command_code) {
if (XdrvMailbox.data_len) {
if (strstr(XdrvMailbox.data, ".")) { // Process parameter entry
if (strstr(XdrvMailbox.data, ".") != nullptr) { // Process parameter entry
char sub_string[XdrvMailbox.data_len];
int pa_area = atoi(subStr(sub_string, XdrvMailbox.data, ".", 1));
@ -1113,7 +1114,7 @@ bool KnxCommand(void)
else if ((CMND_KNX_GA == command_code) && (index > 0) && (index <= MAX_KNX_GA)) {
if (XdrvMailbox.data_len) {
if (strstr(XdrvMailbox.data, ",")) { // Process parameter entry
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry
char sub_string[XdrvMailbox.data_len];
int ga_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1));
@ -1162,7 +1163,7 @@ bool KnxCommand(void)
else if ((CMND_KNX_CB == command_code) && (index > 0) && (index <= MAX_KNX_CB)) {
if (XdrvMailbox.data_len) {
if (strstr(XdrvMailbox.data, ",")) { // Process parameter entry
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry
char sub_string[XdrvMailbox.data_len];
int cb_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1));
@ -1223,6 +1224,9 @@ bool Xdrv11(uint8_t function)
{
bool result = false;
switch (function) {
case FUNC_LOOP:
if (!global_state.wifi_down) { knx.loop(); } // Process knx events
break;
case FUNC_PRE_INIT:
KNX_INIT();
break;
@ -1236,9 +1240,6 @@ bool Xdrv11(uint8_t function)
break;
#endif // USE_KNX_WEB_MENU
#endif // USE_WEBSERVER
case FUNC_LOOP:
if (!global_state.wifi_down) { knx.loop(); } // Process knx events
break;
case FUNC_EVERY_50_MSECOND:
if (toggle_inhibit) {
toggle_inhibit--;

View File

@ -44,38 +44,37 @@ const char HASS_DISCOVER_BUTTON_SWITCH[] PROGMEM =
"\"pl_not_avail\":\"" D_OFFLINE "\""; // Offline
const char HASS_DISCOVER_BUTTON_SWITCH_TOGGLE[] PROGMEM =
"%s,\"off_delay\":1"; // Hass has no support for TOGGLE, fake it by resetting to OFF after 1s
",\"off_delay\":1"; // Hass has no support for TOGGLE, fake it by resetting to OFF after 1s
const char HASS_DISCOVER_BUTTON_SWITCH_ONOFF[] PROGMEM =
"%s,\"frc_upd\":true," // In ON/OFF case, enable force_update to make automations work
",\"frc_upd\":true," // In ON/OFF case, enable force_update to make automations work
"\"pl_off\":\"%s\""; // OFF
const char HASS_DISCOVER_LIGHT_DIMMER[] PROGMEM =
"%s,\"bri_cmd_t\":\"%s\"," // cmnd/led2/Dimmer
",\"bri_cmd_t\":\"%s\"," // cmnd/led2/Dimmer
"\"bri_stat_t\":\"%s\"," // stat/led2/RESULT
"\"bri_scl\":100," // 100%
"\"on_cmd_type\":\"brightness\"," // power on (first), power on (last), no power on (brightness)
"\"bri_val_tpl\":\"{{value_json." D_CMND_DIMMER "}}\"";
const char HASS_DISCOVER_LIGHT_COLOR[] PROGMEM =
"%s,\"rgb_cmd_t\":\"%s2\"," // cmnd/led2/Color2
",\"rgb_cmd_t\":\"%s2\"," // cmnd/led2/Color2
"\"rgb_stat_t\":\"%s\"," // stat/led2/RESULT
"\"rgb_val_tpl\":\"{{value_json." D_CMND_COLOR ".split(',')[0:3]|join(',')}}\"";
const char HASS_DISCOVER_LIGHT_WHITE[] PROGMEM =
"%s,\"whit_val_cmd_t\":\"%s\"," // cmnd/led2/White
",\"whit_val_cmd_t\":\"%s\"," // cmnd/led2/White
"\"whit_val_stat_t\":\"%s\"," // stat/led2/RESULT
"\"white_value_scale\":100," // (No abbreviation defined)
"\"whit_val_tpl\":\"{{value_json.Channel[3]}}\"";
const char HASS_DISCOVER_LIGHT_CT[] PROGMEM =
"%s,\"clr_temp_cmd_t\":\"%s\"," // cmnd/led2/CT
",\"clr_temp_cmd_t\":\"%s\"," // cmnd/led2/CT
"\"clr_temp_stat_t\":\"%s\"," // stat/led2/RESULT
"\"clr_temp_val_tpl\":\"{{value_json." D_CMND_COLORTEMPERATURE "}}\"";
const char HASS_DISCOVER_LIGHT_SCHEME[] PROGMEM =
"%s,\"fx_cmd_t\":\"%s\"," // cmnd/led2/Scheme
",\"fx_cmd_t\":\"%s\"," // cmnd/led2/Scheme
"\"fx_stat_t\":\"%s\"," // stat/led2/RESULT
"\"fx_val_tpl\":\"{{value_json." D_CMND_SCHEME "}}\","
"\"fx_list\":[\"0\",\"1\",\"2\",\"3\",\"4\"]"; // string list with reference to scheme parameter.
@ -88,47 +87,47 @@ const char HASS_DISCOVER_SENSOR[] PROGMEM =
"\"pl_not_avail\":\"" D_OFFLINE "\""; // Offline
const char HASS_DISCOVER_SENSOR_TEMP[] PROGMEM =
"%s,\"unit_of_meas\":\"°%c\"," // °C / °F
",\"unit_of_meas\":\"°%c\"," // °C / °F
"\"val_tpl\":\"{{value_json['%s'].Temperature}}\""; // "SI7021-14":{"Temperature":null,"Humidity":null} -> {{ value_json['SI7021-14'].Temperature }}
const char HASS_DISCOVER_SENSOR_HUM[] PROGMEM =
"%s,\"unit_of_meas\":\"%%\"," // %
",\"unit_of_meas\":\"%%\"," // %
"\"val_tpl\":\"{{value_json['%s'].Humidity}}\"," // "SI7021-14":{"Temperature":null,"Humidity":null} -> {{ value_json['SI7021-14'].Humidity }}
"\"dev_cla\":\"humidity\""; // humidity
const char HASS_DISCOVER_SENSOR_PRESS[] PROGMEM =
"%s,\"unit_of_meas\":\"%s\"," // PressureUnit() setting
",\"unit_of_meas\":\"%s\"," // PressureUnit() setting
"\"val_tpl\":\"{{value_json['%s'].Pressure}}\"," // "BME280":{"Temperature":19.7,"Humidity":27.8,"Pressure":990.1} -> {{ value_json['BME280'].Pressure }}
"\"dev_cla\":\"pressure\""; // pressure
//ENERGY
const char HASS_DISCOVER_SENSOR_KWH[] PROGMEM =
"%s,\"unit_of_meas\":\"kWh\"," // kWh
",\"unit_of_meas\":\"kWh\"," // kWh
"\"val_tpl\":\"{{value_json['%s'].%s}}\""; // "ENERGY":{"TotalStartTime":null,"Total":null,"Yesterday":null,"Today":null,"Power":null,"ApparentPower":null,"ReactivePower":null,"Factor":null,"Voltage":null,"Current":null} -> {{ value_json['ENERGY'].Total/Yesterday/Today }}
const char HASS_DISCOVER_SENSOR_WATT[] PROGMEM =
"%s,\"unit_of_meas\":\"W\"," // W
",\"unit_of_meas\":\"W\"," // W
"\"val_tpl\":\"{{value_json['%s'].%s}}\""; // "ENERGY":{"TotalStartTime":null,"Total":null,"Yesterday":null,"Today":null,"Power":null,"ApparentPower":null,"ReactivePower":null,"Factor":null,"Voltage":null,"Current":null} -> {{ value_json['ENERGY'].POWER }}
const char HASS_DISCOVER_SENSOR_VOLTAGE[] PROGMEM =
"%s,\"unit_of_meas\":\"V\"," // V
",\"unit_of_meas\":\"V\"," // V
"\"val_tpl\":\"{{value_json['%s'].%s}}\""; // "ENERGY":{"TotalStartTime":null,"Total":null,"Yesterday":null,"Today":null,"Power":null,"ApparentPower":null,"ReactivePower":null,"Factor":null,"Voltage":null,"Current":null} -> {{ value_json['ENERGY'].Voltage }}
const char HASS_DISCOVER_SENSOR_AMPERE[] PROGMEM =
"%s,\"unit_of_meas\":\"A\"," // A
",\"unit_of_meas\":\"A\"," // A
"\"val_tpl\":\"{{value_json['%s'].%s}}\""; // "ENERGY":{"TotalStartTime":null,"Total":null,"Yesterday":null,"Today":null,"Power":null,"ApparentPower":null,"ReactivePower":null,"Factor":null,"Voltage":null,"Current":null} -> {{ value_json['ENERGY'].Current }}
const char HASS_DISCOVER_SENSOR_ANY[] PROGMEM =
"%s,\"unit_of_meas\":\" \"," // " " As unit of measurement to get a value graph in Hass
",\"unit_of_meas\":\" \"," // " " As unit of measurement to get a value graph in Hass
"\"val_tpl\":\"{{value_json['%s'].%s}}\""; // "COUNTER":{"C1":0} -> {{ value_json['COUNTER'].C1 }}
const char HASS_DISCOVER_SENSOR_HASS_STATUS[] PROGMEM =
"%s,\"json_attributes_topic\":\"%s\","
",\"json_attributes_topic\":\"%s\","
"\"unit_of_meas\":\" \"," // " " As unit of measurement to get a value graph in Hass
"\"val_tpl\":\"{{value_json['" D_JSON_RSSI "']}}\"";// "COUNTER":{"C1":0} -> {{ value_json['COUNTER'].C1 }}
const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM =
"%s,\"uniq_id\":\"%s\","
",\"uniq_id\":\"%s\","
"\"device\":{\"identifiers\":[\"%06X\"],"
"\"name\":\"%s\","
"\"model\":\"%s\","
@ -136,11 +135,11 @@ const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM =
"\"manufacturer\":\"Tasmota\"}";
const char HASS_DISCOVER_DEVICE_INFO_SHORT[] PROGMEM =
"%s,\"uniq_id\":\"%s\","
",\"uniq_id\":\"%s\","
"\"device\":{\"identifiers\":[\"%06X\"]}";
const char HASS_DISCOVER_TOPIC_PREFIX[] PROGMEM =
"%s, \"~\":\"%s\"";
",\"~\":\"%s\"";
uint8_t hass_init_step = 0;
uint8_t hass_mode = 0;
@ -166,21 +165,24 @@ static void Shorten(char** s, char *prefix)
}
}
void try_snprintf_P(char *s, int n, const char *format, ... )
void TryResponseAppend_P(const char *format, ... )
{
va_list args;
va_start(args, format);
char dummy[2];
int len = vsnprintf_P(dummy, 1, format, args);
if (len >= n) {
AddLog_P2(LOG_LEVEL_ERROR, PSTR("ERROR: MQTT discovery failed due to too long topic or friendly name. "
"Please shorten topic and friendly name. Failed to format(%u/%u):"), len, n);
int dlen = vsnprintf_P(dummy, 1, format, args);
int mlen = strlen(mqtt_data);
int slen = sizeof(mqtt_data) -1 -mlen;
if (dlen >= slen) {
AddLog_P2(LOG_LEVEL_ERROR, PSTR("HASS: MQTT discovery failed due to too long topic or friendly name. "
"Please shorten topic and friendly name. Failed to format(%u/%u):"), dlen, slen);
va_start(args, format);
vsnprintf_P(log_data, sizeof(log_data), format, args);
AddLog(LOG_LEVEL_ERROR);
} else {
va_start(args, format);
vsnprintf_P(s, n, format, args);
vsnprintf_P(mqtt_data + mlen, slen, format, args);
}
va_end(args);
}
@ -234,30 +236,28 @@ void HAssAnnounceRelayLight(void)
Shorten(&state_topic, prefix);
Shorten(&availability_topic, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_RELAY,
name, command_topic, state_topic, value_template, Settings.state_text[0], Settings.state_text[1], availability_topic);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_DEVICE_INFO_SHORT, mqtt_data,
unique_id, ESP.getChipId());
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix);
Response_P(HASS_DISCOVER_RELAY, name, command_topic, state_topic, value_template, Settings.state_text[0], Settings.state_text[1], availability_topic);
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId());
TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix);
if (is_light) {
char *brightness_command_topic = stemp1;
GetTopic_P(brightness_command_topic, CMND, mqtt_topic, D_CMND_DIMMER);
Shorten(&brightness_command_topic, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_DIMMER, mqtt_data, brightness_command_topic, state_topic);
TryResponseAppend_P(HASS_DISCOVER_LIGHT_DIMMER, brightness_command_topic, state_topic);
if (light_subtype >= LST_RGB) {
char *rgb_command_topic = stemp1;
GetTopic_P(rgb_command_topic, CMND, mqtt_topic, D_CMND_COLOR);
Shorten(&rgb_command_topic, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_COLOR, mqtt_data, rgb_command_topic, state_topic);
TryResponseAppend_P(HASS_DISCOVER_LIGHT_COLOR, rgb_command_topic, state_topic);
char *effect_command_topic = stemp1;
GetTopic_P(effect_command_topic, CMND, mqtt_topic, D_CMND_SCHEME);
Shorten(&effect_command_topic, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_SCHEME, mqtt_data, effect_command_topic, state_topic);
TryResponseAppend_P(HASS_DISCOVER_LIGHT_SCHEME, effect_command_topic, state_topic);
}
if (LST_RGBW == light_subtype) {
@ -265,17 +265,17 @@ void HAssAnnounceRelayLight(void)
GetTopic_P(white_temp_command_topic, CMND, mqtt_topic, D_CMND_WHITE);
Shorten(&white_temp_command_topic, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_WHITE, mqtt_data, white_temp_command_topic, state_topic);
TryResponseAppend_P(HASS_DISCOVER_LIGHT_WHITE, white_temp_command_topic, state_topic);
}
if ((LST_COLDWARM == light_subtype) || (LST_RGBWC == light_subtype)) {
char *color_temp_command_topic = stemp1;
GetTopic_P(color_temp_command_topic, CMND, mqtt_topic, D_CMND_COLORTEMPERATURE);
Shorten(&color_temp_command_topic, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_CT, mqtt_data, color_temp_command_topic, state_topic);
TryResponseAppend_P(HASS_DISCOVER_LIGHT_CT, color_temp_command_topic, state_topic);
}
}
try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
TryResponseAppend_P(PSTR("}"));
}
MqttPublish(stopic, true);
}
@ -315,15 +315,13 @@ void HAssAnnounceButtonSwitch(uint8_t device, char* topic, uint8_t present, uint
FindPrefix(state_topic, availability_topic, prefix);
Shorten(&state_topic, prefix);
Shorten(&availability_topic, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_BUTTON_SWITCH,
name, state_topic, Settings.state_text[toggle?2:1], availability_topic);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_DEVICE_INFO_SHORT, mqtt_data,
unique_id, ESP.getChipId());
if (strlen(prefix) > 0 ) try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix);
if (toggle) try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_BUTTON_SWITCH_TOGGLE, mqtt_data);
else try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_BUTTON_SWITCH_ONOFF, mqtt_data, Settings.state_text[0]);
Response_P(HASS_DISCOVER_BUTTON_SWITCH, name, state_topic, Settings.state_text[toggle?2:1], availability_topic);
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId());
if (strlen(prefix) > 0 ) TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix);
if (toggle) TryResponseAppend_P(HASS_DISCOVER_BUTTON_SWITCH_TOGGLE);
else TryResponseAppend_P(HASS_DISCOVER_BUTTON_SWITCH_ONOFF, Settings.state_text[0]);
try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
TryResponseAppend_P(PSTR("}"));
}
MqttPublish(stopic, true);
}
@ -416,40 +414,30 @@ void HAssAnnounceSensor(const char* sensorname, const char* subsensortype)
Shorten(&state_topic, prefix);
Shorten(&availability_topic, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR,
name, state_topic, availability_topic);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_DEVICE_INFO_SHORT, mqtt_data,
unique_id, ESP.getChipId());
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix);
Response_P(HASS_DISCOVER_SENSOR, name, state_topic, availability_topic);
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId());
TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix);
if (!strcmp_P(subsensortype, PSTR(D_JSON_TEMPERATURE))) {
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_TEMP,
mqtt_data, TempUnit(), sensorname);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_TEMP, TempUnit(), sensorname);
} else if (!strcmp_P(subsensortype, PSTR(D_JSON_HUMIDITY))) {
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_HUM,
mqtt_data, sensorname);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_HUM, sensorname);
} else if (!strcmp_P(subsensortype, PSTR(D_JSON_PRESSURE))) {
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_PRESS,
mqtt_data, PressureUnit().c_str(), sensorname);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_PRESS, PressureUnit().c_str(), sensorname);
} else if (!strcmp_P(subsensortype, PSTR(D_JSON_TOTAL))
|| !strcmp_P(subsensortype, PSTR(D_JSON_TODAY))
|| !strcmp_P(subsensortype, PSTR(D_JSON_YESTERDAY))){
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_KWH,
mqtt_data, sensorname, subsensortype);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_KWH, sensorname, subsensortype);
} else if (!strcmp_P(subsensortype, PSTR(D_JSON_POWERUSAGE))){
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_WATT,
mqtt_data, sensorname, subsensortype);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_WATT, sensorname, subsensortype);
} else if (!strcmp_P(subsensortype, PSTR(D_JSON_VOLTAGE))){
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_VOLTAGE,
mqtt_data, sensorname, subsensortype);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_VOLTAGE, sensorname, subsensortype);
} else if (!strcmp_P(subsensortype, PSTR(D_JSON_CURRENT))){
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_AMPERE,
mqtt_data, sensorname, subsensortype);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_AMPERE, sensorname, subsensortype);
}
else {
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_ANY,
mqtt_data, sensorname, subsensortype);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_ANY, sensorname, subsensortype);
}
try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
TryResponseAppend_P(PSTR("}"));
}
MqttPublish(stopic, true);
}
@ -509,7 +497,7 @@ void HAssAnnounceStatusSensor(void)
mqtt_data[0] = '\0'; // Clear retained message
// Clear or Set topic
snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s"), ESP.getChipId(), "status");
snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_status"), ESP.getChipId());
snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s/config"), unique_id);
if (Settings.flag.hass_discovery) {
@ -518,30 +506,26 @@ void HAssAnnounceStatusSensor(void)
char *state_topic = stemp1;
char *availability_topic = stemp2;
snprintf_P(name, sizeof(name), PSTR("%s %s"), Settings.friendlyname[0], "status");
snprintf_P(name, sizeof(name), PSTR("%s status"), Settings.friendlyname[0]);
GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_HASS_STATE));
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
FindPrefix(state_topic, availability_topic, prefix);
Shorten(&state_topic, prefix);
Shorten(&availability_topic, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR,
name, state_topic, availability_topic);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_HASS_STATUS,
mqtt_data, state_topic);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_DEVICE_INFO, mqtt_data,
unique_id, ESP.getChipId(),
Response_P(HASS_DISCOVER_SENSOR, name, state_topic, availability_topic);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_HASS_STATUS, state_topic);
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP.getChipId(),
Settings.friendlyname[0], ModuleName().c_str(), my_version, my_image);
try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix);
try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix);
TryResponseAppend_P(PSTR("}"));
}
MqttPublish(stopic, true);
}
void HAssPublishStatus(void)
{
snprintf_P(mqtt_data, sizeof(mqtt_data),
PSTR("{\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_BUILDDATETIME "\":\"%s\","
Response_P(PSTR("{\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_BUILDDATETIME "\":\"%s\","
"\"" D_JSON_COREVERSION "\":\"" ARDUINO_ESP8266_RELEASE "\",\"" D_JSON_SDKVERSION "\":\"%s\","
"\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_RESTARTREASON "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\","
"\"WiFi " D_JSON_LINK_COUNT "\":%d,\"WiFi " D_JSON_DOWNTIME "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,"

View File

@ -22,11 +22,11 @@
#define XDRV_13 13
#define DISPLAY_MAX_DRIVERS 16 // Max number of display drivers/models supported by xdsp_interface.ino
#define DISPLAY_MAX_COLS 44 // Max number of columns allowed with command DisplayCols
#define DISPLAY_MAX_ROWS 32 // Max number of lines allowed with command DisplayRows
const uint8_t DISPLAY_MAX_DRIVERS = 16; // Max number of display drivers/models supported by xdsp_interface.ino
const uint8_t DISPLAY_MAX_COLS = 44; // Max number of columns allowed with command DisplayCols
const uint8_t DISPLAY_MAX_ROWS = 32; // Max number of lines allowed with command DisplayRows
#define DISPLAY_LOG_ROWS 32 // Number of lines in display log buffer
const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log buffer
#define D_CMND_DISPLAY "Display"
#define D_CMND_DISP_ADDRESS "Address"
@ -465,7 +465,7 @@ void DisplayText(void)
break;
default:
// unknown escape
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("Unknown Escape"));
Response_P(PSTR("Unknown Escape"));
goto exit;
break;
}
@ -503,9 +503,9 @@ void DisplayClearScreenBuffer(void)
void DisplayFreeScreenBuffer(void)
{
if (disp_screen_buffer != NULL) {
if (disp_screen_buffer != nullptr) {
for (uint8_t i = 0; i < disp_screen_buffer_rows; i++) {
if (disp_screen_buffer[i] != NULL) { free(disp_screen_buffer[i]); }
if (disp_screen_buffer[i] != nullptr) { free(disp_screen_buffer[i]); }
}
free(disp_screen_buffer);
disp_screen_buffer_cols = 0;
@ -518,16 +518,16 @@ void DisplayAllocScreenBuffer(void)
if (!disp_screen_buffer_cols) {
disp_screen_buffer_rows = Settings.display_rows;
disp_screen_buffer = (char**)malloc(sizeof(*disp_screen_buffer) * disp_screen_buffer_rows);
if (disp_screen_buffer != NULL) {
if (disp_screen_buffer != nullptr) {
for (uint8_t i = 0; i < disp_screen_buffer_rows; i++) {
disp_screen_buffer[i] = (char*)malloc(sizeof(*disp_screen_buffer[i]) * (Settings.display_cols[0] +1));
if (disp_screen_buffer[i] == NULL) {
if (disp_screen_buffer[i] == nullptr) {
DisplayFreeScreenBuffer();
break;
}
}
}
if (disp_screen_buffer != NULL) {
if (disp_screen_buffer != nullptr) {
disp_screen_buffer_cols = Settings.display_cols[0] +1;
DisplayClearScreenBuffer();
}
@ -562,9 +562,9 @@ void DisplayClearLogBuffer(void)
void DisplayFreeLogBuffer(void)
{
if (disp_log_buffer != NULL) {
if (disp_log_buffer != nullptr) {
for (uint8_t i = 0; i < DISPLAY_LOG_ROWS; i++) {
if (disp_log_buffer[i] != NULL) { free(disp_log_buffer[i]); }
if (disp_log_buffer[i] != nullptr) { free(disp_log_buffer[i]); }
}
free(disp_log_buffer);
disp_log_buffer_cols = 0;
@ -575,16 +575,16 @@ void DisplayAllocLogBuffer(void)
{
if (!disp_log_buffer_cols) {
disp_log_buffer = (char**)malloc(sizeof(*disp_log_buffer) * DISPLAY_LOG_ROWS);
if (disp_log_buffer != NULL) {
if (disp_log_buffer != nullptr) {
for (uint8_t i = 0; i < DISPLAY_LOG_ROWS; i++) {
disp_log_buffer[i] = (char*)malloc(sizeof(*disp_log_buffer[i]) * (Settings.display_cols[0] +1));
if (disp_log_buffer[i] == NULL) {
if (disp_log_buffer[i] == nullptr) {
DisplayFreeLogBuffer();
break;
}
}
}
if (disp_log_buffer != NULL) {
if (disp_log_buffer != nullptr) {
disp_log_buffer_cols = Settings.display_cols[0] +1;
DisplayClearLogBuffer();
}
@ -608,7 +608,7 @@ void DisplayLogBufferAdd(char* txt)
char* DisplayLogBuffer(char temp_code)
{
char* result = NULL;
char* result = nullptr;
if (disp_log_buffer_cols) {
if (disp_log_buffer_idx != disp_log_buffer_ptr) {
result = disp_log_buffer[disp_log_buffer_ptr];
@ -616,7 +616,7 @@ char* DisplayLogBuffer(char temp_code)
if (DISPLAY_LOG_ROWS == disp_log_buffer_ptr) { disp_log_buffer_ptr = 0; }
char *pch = strchr(result, '~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) { result[pch - result] = temp_code; }
if (pch != nullptr) { result[pch - result] = temp_code; }
}
}
return result;
@ -829,12 +829,12 @@ void DisplayMqttSubscribe(void)
ntopic[0] = '\0';
strlcpy(stopic, Settings.mqtt_fulltopic, sizeof(stopic));
char *tp = strtok(stopic, "/");
while (tp != NULL) {
if (!strcmp_P(tp, PSTR(MQTT_TOKEN_PREFIX))) {
while (tp != nullptr) {
if (!strcmp_P(tp, MQTT_TOKEN_PREFIX)) {
break;
}
strncat_P(ntopic, PSTR("+/"), sizeof(ntopic) - strlen(ntopic) -1); // Add single-level wildcards
tp = strtok(NULL, "/");
tp = strtok(nullptr, "/");
}
strncat(ntopic, Settings.mqtt_prefix[2], sizeof(ntopic) - strlen(ntopic) -1); // Subscribe to tele messages
strncat_P(ntopic, PSTR("/#"), sizeof(ntopic) - strlen(ntopic) -1); // Add multi-level wildcard
@ -921,7 +921,7 @@ bool DisplayCommand(void)
serviced = false; // Unknown command
}
else if (CMND_DISPLAY == command_code) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_DISPLAY "\":{\"" D_CMND_DISP_MODEL "\":%d,\"" D_CMND_DISP_MODE "\":%d,\"" D_CMND_DISP_DIMMER "\":%d,\""
Response_P(PSTR("{\"" D_CMND_DISPLAY "\":{\"" D_CMND_DISP_MODEL "\":%d,\"" D_CMND_DISP_MODE "\":%d,\"" D_CMND_DISP_DIMMER "\":%d,\""
D_CMND_DISP_SIZE "\":%d,\"" D_CMND_DISP_FONT "\":%d,\"" D_CMND_DISP_ROTATE "\":%d,\"" D_CMND_DISP_REFRESH "\":%d,\"" D_CMND_DISP_COLS "\":[%d,%d],\"" D_CMND_DISP_ROWS "\":%d}}"),
Settings.display_model, Settings.display_mode, Settings.display_dimmer, Settings.display_size, Settings.display_font, Settings.display_rotate, Settings.display_refresh,
Settings.display_cols[0], Settings.display_cols[1], Settings.display_rows);
@ -936,7 +936,7 @@ bool DisplayCommand(void)
Settings.display_model = last_display_model;
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_model);
Response_P(S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_model);
}
else if (CMND_DISP_MODE == command_code) {
#ifdef USE_DISPLAY_MODES1TO5
@ -964,7 +964,7 @@ bool DisplayCommand(void)
}
}
#endif // USE_DISPLAY_MODES1TO5
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_mode);
Response_P(S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_mode);
}
else if (CMND_DISP_DIMMER == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
@ -976,19 +976,19 @@ bool DisplayCommand(void)
ExecuteCommandPower(disp_device, POWER_OFF, SRC_DISPLAY);
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_dimmer);
Response_P(S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_dimmer);
}
else if (CMND_DISP_SIZE == command_code) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) {
Settings.display_size = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_size);
Response_P(S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_size);
}
else if (CMND_DISP_FONT == command_code) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) {
Settings.display_font = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_font);
Response_P(S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_font);
}
else if (CMND_DISP_ROTATE == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 4)) {
@ -1011,7 +1011,7 @@ bool DisplayCommand(void)
#endif // USE_DISPLAY_MODES1TO5
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_rotate);
Response_P(S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_rotate);
}
else if (CMND_DISP_TEXT == command_code) {
mqtt_data[0] = '\0';
@ -1026,23 +1026,23 @@ bool DisplayCommand(void)
}
#endif // USE_DISPLAY_MODES1TO5
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("No Text"));
Response_P(PSTR("No Text"));
}
if (mqtt_data[0] == '\0') {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_VALUE, command, XdrvMailbox.data);
Response_P(S_JSON_DISPLAY_COMMAND_VALUE, command, XdrvMailbox.data);
}
}
else if ((CMND_DISP_ADDRESS == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 8)) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) {
Settings.display_address[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.display_address[XdrvMailbox.index -1]);
Response_P(S_JSON_DISPLAY_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.display_address[XdrvMailbox.index -1]);
}
else if (CMND_DISP_REFRESH == command_code) {
if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 7)) {
Settings.display_refresh = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_refresh);
Response_P(S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_refresh);
}
else if ((CMND_DISP_COLS == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_COLS)) {
@ -1054,7 +1054,7 @@ bool DisplayCommand(void)
}
#endif // USE_DISPLAY_MODES1TO5
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.display_cols[XdrvMailbox.index -1]);
Response_P(S_JSON_DISPLAY_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.display_cols[XdrvMailbox.index -1]);
}
else if (CMND_DISP_ROWS == command_code) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_ROWS)) {
@ -1064,7 +1064,7 @@ bool DisplayCommand(void)
DisplayReAllocScreenBuffer();
#endif // USE_DISPLAY_MODES1TO5
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_rows);
Response_P(S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_rows);
}
else serviced = false; // Unknown command
}

View File

@ -200,7 +200,7 @@ bool MP3PlayerCmd(void) {
if (command_code == CMND_MP3_DEVICE) { MP3_CMD(MP3_CMD_DEVICE, XdrvMailbox.payload); }
if (command_code == CMND_MP3_DAC) { MP3_CMD(MP3_CMD_DAC, XdrvMailbox.payload); }
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_MP3_COMMAND_NVALUE, command, XdrvMailbox.payload);
Response_P(S_JSON_MP3_COMMAND_NVALUE, command, XdrvMailbox.payload);
break;
case CMND_MP3_PLAY:
case CMND_MP3_PAUSE:
@ -211,7 +211,7 @@ bool MP3PlayerCmd(void) {
if (command_code == CMND_MP3_PAUSE) { MP3_CMD(MP3_CMD_PAUSE, 0); }
if (command_code == CMND_MP3_STOP) { MP3_CMD(MP3_CMD_STOP, 0); }
if (command_code == CMND_MP3_RESET) { MP3_CMD(MP3_CMD_RESET, 0); }
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_MP3_COMMAND, command, XdrvMailbox.payload);
Response_P(S_JSON_MP3_COMMAND, command, XdrvMailbox.payload);
break;
default:
// else for Unknown command

View File

@ -60,7 +60,7 @@ void PCA9685_Reset(void)
PCA9685_SetPWM(pin,0,false);
pca9685_pin_pwm_value[pin] = 0;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"RESET\":\"OK\"}}"));
Response_P(PSTR("{\"PCA9685\":{\"RESET\":\"OK\"}}"));
}
void PCA9685_SetPWMfreq(double freq) {
@ -127,11 +127,11 @@ bool PCA9685_Command(void)
uint16_t new_freq = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2));
if ((new_freq >= 24) && (new_freq <= 1526)) {
PCA9685_SetPWMfreq(new_freq);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PWMF\":%i, \"Result\":\"OK\"}}"),new_freq);
Response_P(PSTR("{\"PCA9685\":{\"PWMF\":%i, \"Result\":\"OK\"}}"),new_freq);
return serviced;
}
} else { // No parameter was given for setfreq, so we return current setting
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PWMF\":%i}}"),pca9685_freq);
Response_P(PSTR("{\"PCA9685\":{\"PWMF\":%i}}"),pca9685_freq);
return serviced;
}
}
@ -141,20 +141,20 @@ bool PCA9685_Command(void)
if (paramcount > 2) {
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 3), "ON")) {
PCA9685_SetPWM(pin, 4096, false);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,4096);
Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,4096);
serviced = true;
return serviced;
}
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 3), "OFF")) {
PCA9685_SetPWM(pin, 0, false);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,0);
Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,0);
serviced = true;
return serviced;
}
uint16_t pwm = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3));
if ((pin >= 0 && pin <= 15) && (pwm >= 0 && pwm <= 4096)) {
PCA9685_SetPWM(pin, pwm, false);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,pwm);
Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,pwm);
serviced = true;
return serviced;
}
@ -166,12 +166,12 @@ bool PCA9685_Command(void)
void PCA9685_OutputTelemetry(bool telemetry) {
if (0 == pca9685_detected) { return; } // We do not do this if the PCA9685 has not been detected
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"PCA9685\": {"), GetDateAndTime(DT_LOCAL).c_str());
snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"PWM_FREQ\":%i,"),mqtt_data,pca9685_freq);
Response_P(PSTR("{\"" D_JSON_TIME "\":\"%s\",\"PCA9685\": {"), GetDateAndTime(DT_LOCAL).c_str());
ResponseAppend_P(PSTR("\"PWM_FREQ\":%i,"),pca9685_freq);
for (uint8_t pin=0;pin<16;pin++) {
snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"PWM%i\":%i,"),mqtt_data,pin,pca9685_pin_pwm_value[pin]);
ResponseAppend_P(PSTR("\"PWM%i\":%i,"),pin,pca9685_pin_pwm_value[pin]);
}
snprintf_P(mqtt_data,sizeof(mqtt_data),PSTR("%s\"END\":1}}"),mqtt_data);
ResponseAppend_P(PSTR("\"END\":1}}"));
if (telemetry) {
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
}
@ -189,9 +189,9 @@ bool Xdrv15(uint8_t function)
PCA9685_OutputTelemetry(true);
}
break;
case FUNC_COMMAND:
case FUNC_COMMAND_DRIVER:
if (XDRV_15 == XdrvMailbox.index) {
PCA9685_Command();
result = PCA9685_Command();
}
break;
default:

View File

@ -53,7 +53,7 @@ uint8_t tuya_cmd_checksum = 0; // Checksum of tuya command
uint8_t tuya_data_len = 0; // Data lenght of command
int8_t tuya_wifi_state = -2; // Keep MCU wifi-status in sync with WifiState()
char *tuya_buffer = NULL; // Serial receive buffer
char *tuya_buffer = nullptr; // Serial receive buffer
int tuya_byte_counter = 0; // Index in serial receive buffer
/*********************************************************************************************\
@ -284,7 +284,7 @@ void TuyaInit(void)
Settings.param[P_TUYA_DIMMER_ID] = TUYA_DIMMER_ID;
}
tuya_buffer = (char*)(malloc(TUYA_BUFFER_SIZE));
if (tuya_buffer != NULL) {
if (tuya_buffer != nullptr) {
TuyaSerial = new TasmotaSerial(pin[GPIO_TUYA_RX], pin[GPIO_TUYA_TX], 2);
if (TuyaSerial->begin(9600)) {
if (TuyaSerial->hardwareSerial()) { ClaimSerial(); }
@ -393,15 +393,15 @@ bool Xdrv16(uint8_t function)
if (TUYA_DIMMER == my_module_type) {
switch (function) {
case FUNC_LOOP:
if (TuyaSerial) { TuyaSerialInput(); }
break;
case FUNC_MODULE_INIT:
result = TuyaModuleSelected();
break;
case FUNC_INIT:
TuyaInit();
break;
case FUNC_LOOP:
if (TuyaSerial) { TuyaSerialInput(); }
break;
case FUNC_SET_DEVICE_POWER:
result = TuyaSetPower();
break;

View File

@ -61,7 +61,7 @@ void RfReceiveCheck(void)
} else {
snprintf_P(stemp, sizeof(stemp), PSTR("\"0x%lX\""), (uint32_t)data);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_RF_DATA "\":%s,\"" D_JSON_RF_BITS "\":%d,\"" D_JSON_RF_PROTOCOL "\":%d,\"" D_JSON_RF_PULSE "\":%d}}"),
Response_P(PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_RF_DATA "\":%s,\"" D_JSON_RF_BITS "\":%d,\"" D_JSON_RF_PROTOCOL "\":%d,\"" D_JSON_RF_PULSE "\":%d}}"),
stemp, bits, protocol, delay);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED));
XdrvRulesProcess();
@ -107,7 +107,7 @@ bool RfSendCommand(void)
if (root.success()) {
// RFsend {"data":0x501014,"bits":24,"protocol":1,"repeat":10,"pulse":350}
char parm_uc[10];
data = strtoul(root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_DATA))], NULL, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input
data = strtoul(root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_DATA))], nullptr, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input
bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_BITS))];
protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_PROTOCOL))];
repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_REPEAT))];
@ -116,10 +116,10 @@ bool RfSendCommand(void)
// RFsend data, bits, protocol, repeat, pulse
char *p;
uint8_t i = 0;
for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 5; str = strtok_r(NULL, ", ", &p)) {
for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 5; str = strtok_r(nullptr, ", ", &p)) {
switch (i++) {
case 0:
data = strtoul(str, NULL, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input
data = strtoul(str, nullptr, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input
break;
case 1:
bits = atoi(str);
@ -145,7 +145,7 @@ bool RfSendCommand(void)
if (!bits) { bits = 24; } // Default 24 bits
if (data) {
mySwitch.send(data, bits);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RFSEND "\":\"" D_JSON_DONE "\"}"));
Response_P(PSTR("{\"" D_CMND_RFSEND "\":\"" D_JSON_DONE "\"}"));
} else {
error = true;
}
@ -153,7 +153,7 @@ bool RfSendCommand(void)
error = true;
}
if (error) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RFSEND "\":\"" D_JSON_NO " " D_JSON_RF_DATA ", " D_JSON_RF_BITS ", " D_JSON_RF_PROTOCOL ", " D_JSON_RF_REPEAT " " D_JSON_OR " " D_JSON_RF_PULSE "\"}"));
Response_P(PSTR("{\"" D_CMND_RFSEND "\":\"" D_JSON_NO " " D_JSON_RF_DATA ", " D_JSON_RF_BITS ", " D_JSON_RF_PROTOCOL ", " D_JSON_RF_REPEAT " " D_JSON_OR " " D_JSON_RF_PULSE "\"}"));
}
}
else serviced = false; // Unknown command

View File

@ -170,15 +170,15 @@ bool Xdrv18(uint8_t function)
if (ARMTRONIX_DIMMERS == my_module_type) {
switch (function) {
case FUNC_LOOP:
if (ArmtronixSerial) { ArmtronixSerialInput(); }
break;
case FUNC_MODULE_INIT:
result = ArmtronixModuleSelected();
break;
case FUNC_INIT:
ArmtronixInit();
break;
case FUNC_LOOP:
if (ArmtronixSerial) { ArmtronixSerialInput(); }
break;
case FUNC_EVERY_SECOND:
if (ArmtronixSerial) {
if (armtronix_wifi_state!=WifiState()) { ArmtronixSetWifiLed(); }

View File

@ -35,8 +35,8 @@ bool ps16dz_ignore_dim = false; // Flag to skip serial send to preven
//uint64_t ps16dz_seq = 0;
char *ps16dz_tx_buffer = NULL; // Serial transmit buffer
char *ps16dz_rx_buffer = NULL; // Serial receive buffer
char *ps16dz_tx_buffer = nullptr; // Serial transmit buffer
char *ps16dz_rx_buffer = nullptr; // Serial receive buffer
int ps16dz_byte_counter = 0;
/*********************************************************************************************\
@ -135,9 +135,9 @@ bool PS16DZModuleSelected(void)
void PS16DZInit(void)
{
ps16dz_tx_buffer = (char*)(malloc(PS16DZ_BUFFER_SIZE));
if (ps16dz_tx_buffer != NULL) {
if (ps16dz_tx_buffer != nullptr) {
ps16dz_rx_buffer = (char*)(malloc(PS16DZ_BUFFER_SIZE));
if (ps16dz_rx_buffer != NULL) {
if (ps16dz_rx_buffer != nullptr) {
PS16DZSerial = new TasmotaSerial(pin[GPIO_RXD], pin[GPIO_TXD], 2);
if (PS16DZSerial->begin(19200)) {
if (PS16DZSerial->hardwareSerial()) { ClaimSerial(); }
@ -168,10 +168,10 @@ void PS16DZSerialInput(void)
char *end_str;
char *string = ps16dz_rx_buffer+10;
char* token = strtok_r(string, ",", &end_str);
while (token != NULL) {
while (token != nullptr) {
char* end_token;
char* token2 = strtok_r(token, ":", &end_token);
char* token3 = strtok_r(NULL, ":", &end_token);
char* token3 = strtok_r(nullptr, ":", &end_token);
if(!strncmp(token2, "\"switch\"", 8)){
bool ps16dz_power = !strncmp(token3, "\"on\"", 4)?true:false;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PSZ: power received: %s"), token3);
@ -193,10 +193,10 @@ void PS16DZSerialInput(void)
}
}
else if(!strncmp(token2, "\"sequence\"", 10)){
//ps16dz_seq = strtoull(token3+1, NULL, 10);
//ps16dz_seq = strtoull(token3+1, nullptr, 10);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PSZ: sequence received: %s"), token3);
}
token = strtok_r(NULL, ",", &end_str);
token = strtok_r(nullptr, ",", &end_str);
}
}
else if(!strncmp(ps16dz_rx_buffer+3, "SETTING", 7)) {
@ -223,15 +223,15 @@ bool Xdrv19(uint8_t function)
if (PS_16_DZ == my_module_type) {
switch (function) {
case FUNC_LOOP:
if (PS16DZSerial) { PS16DZSerialInput(); }
break;
case FUNC_MODULE_INIT:
result = PS16DZModuleSelected();
break;
case FUNC_INIT:
PS16DZInit();
break;
case FUNC_LOOP:
if (PS16DZSerial) { PS16DZSerialInput(); }
break;
case FUNC_SET_DEVICE_POWER:
result = PS16DZSetPower();
break;

View File

@ -419,28 +419,28 @@ bool DebugCommand(void)
}
else if (CMND_HELP == command_code) {
AddLog_P(LOG_LEVEL_INFO, kDebugCommands);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
else if (CMND_RTCDUMP == command_code) {
DebugRtcDump(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
else if (CMND_CFGDUMP == command_code) {
DebugCfgDump(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
else if (CMND_CFGPEEK == command_code) {
DebugCfgPeek(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
else if (CMND_CFGPOKE == command_code) {
DebugCfgPoke(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
#ifdef USE_DEBUG_SETTING_NAMES
else if (CMND_CFGSHOW == command_code) {
DebugCfgShow(XdrvMailbox.payload);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
#endif // USE_DEBUG_SETTING_NAMES
#ifdef USE_WEBSERVER
@ -448,13 +448,13 @@ bool DebugCommand(void)
if (XdrvMailbox.data_len > 0) {
config_xor_on_set = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, config_xor_on_set);
Response_P(S_JSON_COMMAND_NVALUE, command, config_xor_on_set);
}
#endif // USE_WEBSERVER
#ifdef DEBUG_THEO
else if (CMND_EXCEPTION == command_code) {
if (XdrvMailbox.data_len > 0) ExceptionTest(XdrvMailbox.payload);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
#endif // DEBUG_THEO
else if (CMND_CPUCHECK == command_code) {
@ -462,26 +462,26 @@ bool DebugCommand(void)
CPU_load_check = XdrvMailbox.payload;
CPU_last_millis = CPU_last_loop_time;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, CPU_load_check);
Response_P(S_JSON_COMMAND_NVALUE, command, CPU_load_check);
}
else if (CMND_FREEMEM == command_code) {
if (XdrvMailbox.data_len > 0) {
CPU_show_freemem = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, CPU_show_freemem);
Response_P(S_JSON_COMMAND_NVALUE, command, CPU_show_freemem);
}
else if ((CMND_SETSENSOR == command_code) && (XdrvMailbox.index < MAX_XSNS_DRIVERS)) {
if ((XdrvMailbox.payload >= 0) && XsnsPresent(XdrvMailbox.index)) {
bitWrite(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1);
if (1 == XdrvMailbox.payload) { restart_flag = 2; } // To safely re-enable a sensor currently most sensor need to follow complete restart init cycle
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_XVALUE, command, XsnsGetSensors().c_str());
Response_P(S_JSON_COMMAND_XVALUE, command, XsnsGetSensors().c_str());
}
else if (CMND_FLASHMODE == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
SetFlashMode(XdrvMailbox.payload);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, ESP.getFlashChipMode());
Response_P(S_JSON_COMMAND_NVALUE, command, ESP.getFlashChipMode());
}
else serviced = false; // Unknown command
@ -497,12 +497,12 @@ bool Xdrv99(uint8_t function)
bool result = false;
switch (function) {
case FUNC_PRE_INIT:
CPU_last_millis = millis();
break;
case FUNC_LOOP:
CpuLoadLoop();
break;
case FUNC_PRE_INIT:
CPU_last_millis = millis();
break;
case FUNC_COMMAND:
result = DebugCommand();
break;

View File

@ -210,7 +210,7 @@ bool XdrvRulesProcess(void)
#ifdef USE_DEBUG_DRIVER
void ShowFreeMem(const char *where)
{
char stemp[20];
char stemp[30];
snprintf_P(stemp, sizeof(stemp), where);
XdrvMailbox.data = stemp;
XdrvCall(FUNC_FREE_MEM);

View File

@ -127,7 +127,7 @@ bool LcdPrintLog(void)
if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); }
char* txt = DisplayLogBuffer('\337');
if (txt != NULL) {
if (txt != nullptr) {
uint8_t last_row = Settings.display_rows -1;
for (uint8_t i = 0; i < last_row; i++) {

View File

@ -141,7 +141,7 @@ void Ssd1306PrintLog(void)
if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); }
char* txt = DisplayLogBuffer('\370');
if (txt != NULL) {
if (txt != nullptr) {
uint8_t last_row = Settings.display_rows -1;
oled->clearDisplay();

View File

@ -37,7 +37,7 @@ int16_t mtx_x = 0;
int16_t mtx_y = 0;
//char mtx_buffer[MTX_MAX_SCREEN_BUFFER];
char *mtx_buffer = NULL;
char *mtx_buffer = nullptr;
uint8_t mtx_mode = 0;
uint8_t mtx_loop = 0;
@ -140,9 +140,9 @@ void MatrixScrollUp(char* txt, int loop)
disp_refresh = Settings.display_refresh;
strlcpy(tmpbuf, txt, sizeof(tmpbuf));
char *p = strtok(tmpbuf, separators);
while (p != NULL && wordcounter < 40) {
while (p != nullptr && wordcounter < 40) {
words[wordcounter++] = p;
p = strtok(NULL, separators);
p = strtok(nullptr, separators);
}
for (uint8_t i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
@ -196,7 +196,7 @@ void MatrixInit(uint8_t mode)
void MatrixInitDriver(void)
{
mtx_buffer = (char*)(malloc(MTX_MAX_SCREEN_BUFFER));
if (mtx_buffer != NULL) {
if (mtx_buffer != nullptr) {
if (!Settings.display_model) {
if (I2cDevice(Settings.display_address[1])) {
Settings.display_model = XDSP_03;
@ -239,7 +239,7 @@ void MatrixDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8
void MatrixPrintLog(uint8_t direction)
{
char* txt = (!mtx_done) ? DisplayLogBuffer('\370') : mtx_buffer;
if (txt != NULL) {
if (txt != nullptr) {
if (!mtx_state) { mtx_state = 1; }
if (!mtx_done) {

View File

@ -147,7 +147,7 @@ void Ili9341PrintLog(void)
}
char* txt = DisplayLogBuffer('\370');
if (txt != NULL) {
if (txt != nullptr) {
uint8_t size = Settings.display_size;
uint16_t theight = size * TFT_FONT_HEIGTH;

View File

@ -200,7 +200,7 @@ void EpdPrintLog(void)
}
char* txt = DisplayLogBuffer('\040');
if (txt != NULL) {
if (txt != nullptr) {
uint8_t size = Settings.display_size;
uint16_t theight = size * EPD_FONT_HEIGTH;

View File

@ -32,7 +32,7 @@
#include <TasmotaSerial.h>
TasmotaSerial *PzemSerial = NULL;
TasmotaSerial *PzemSerial = nullptr;
#define PZEM_VOLTAGE (uint8_t)0xB0
#define RESP_VOLTAGE (uint8_t)0xA0

View File

@ -67,7 +67,7 @@
#define MCP_BUFFER_SIZE 60
#include <TasmotaSerial.h>
TasmotaSerial *McpSerial = NULL;
TasmotaSerial *McpSerial = nullptr;
typedef struct mcp_cal_registers_type {
uint16_t gain_current_rms;
@ -92,7 +92,7 @@ typedef struct mcp_cal_registers_type {
uint16_t accumulation_interval;
} mcp_cal_registers_type;
char *mcp_buffer = NULL;
char *mcp_buffer = nullptr;
unsigned long mcp_window = 0;
unsigned long mcp_kWhcounter = 0;
uint32_t mcp_system_configuration = 0x03000000;
@ -652,12 +652,12 @@ int Xnrg04(uint8_t function)
}
else if (XNRG_04 == energy_flg) {
switch (function) {
case FUNC_INIT:
McpSnsInit();
break;
case FUNC_LOOP:
if (McpSerial) { McpSerialInput(); }
break;
case FUNC_INIT:
McpSnsInit();
break;
case FUNC_EVERY_SECOND:
if (McpSerial) { McpEverySecond(); }
break;

View File

@ -31,16 +31,21 @@
#include <Ticker.h>
Ticker TickerMSearch;
bool udp_connected = false;
char packet_buffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP packet
IPAddress ipMulticast(239,255,255,250); // Simple Service Discovery Protocol (SSDP)
uint32_t port_multicast = 1900; // Multicast address and port
bool udp_response_mutex = false; // M-Search response mutex to control re-entry
IPAddress udp_remote_ip; // M-Search remote IP address
uint16_t udp_remote_port; // M-Search remote port
bool udp_connected = false;
bool udp_response_mutex = false; // M-Search response mutex to control re-entry
/*********************************************************************************************\
* UPNP search targets
\*********************************************************************************************/
const char URN_BELKIN_DEVICE[] PROGMEM = "urn:belkin:device:**";
const char UPNP_ROOTDEVICE[] PROGMEM = "upnp:rootdevice";
const char SSDPSEARCH_ALL[] PROGMEM = "ssdpsearch:all";
const char SSDP_ALL[] PROGMEM = "ssdp:all";
/*********************************************************************************************\
* WeMo UPNP support routines
\*********************************************************************************************/
@ -50,12 +55,12 @@ const char WEMO_MSEARCH[] PROGMEM =
"CACHE-CONTROL: max-age=86400\r\n"
"DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n"
"EXT:\r\n"
"LOCATION: http://{r1:80/setup.xml\r\n"
"LOCATION: http://%s:80/setup.xml\r\n"
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
"01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n"
"SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
"ST: {r3\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
"USN: uuid:{r2::{r3\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
"ST: %s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
"USN: uuid:%s::%s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
"X-User-Agent: redsonic\r\n"
"\r\n";
@ -81,15 +86,15 @@ void WemoRespondToMSearch(int echo_type)
TickerMSearch.detach();
if (PortUdp.beginPacket(udp_remote_ip, udp_remote_port)) {
String response = FPSTR(WEMO_MSEARCH);
response.replace("{r1", WiFi.localIP().toString());
response.replace("{r2", WemoUuid());
char type[24];
if (1 == echo_type) { // type1 echo 1g & dot 2g
response.replace("{r3", F("urn:Belkin:device:**"));
strcpy_P(type, URN_BELKIN_DEVICE);
} else { // type2 echo 2g (echo, plus, show)
response.replace("{r3", F("upnp:rootdevice"));
strcpy_P(type, UPNP_ROOTDEVICE);
}
PortUdp.write(response.c_str());
char response[400];
snprintf_P(response, sizeof(response), WEMO_MSEARCH, WiFi.localIP().toString().c_str(), type, WemoUuid().c_str(), type);
PortUdp.write(response);
PortUdp.endPacket();
snprintf_P(message, sizeof(message), PSTR(D_RESPONSE_SENT));
} else {
@ -114,20 +119,20 @@ const char HUE_RESPONSE[] PROGMEM =
"HOST: 239.255.255.250:1900\r\n"
"CACHE-CONTROL: max-age=100\r\n"
"EXT:\r\n"
"LOCATION: http://{r1:80/description.xml\r\n"
"LOCATION: http://%s:80/description.xml\r\n"
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.17.0\r\n"
"hue-bridgeid: {r2\r\n";
"hue-bridgeid: %s\r\n";
const char HUE_ST1[] PROGMEM =
"ST: upnp:rootdevice\r\n"
"USN: uuid:{r3::upnp:rootdevice\r\n"
"USN: uuid:%s::upnp:rootdevice\r\n"
"\r\n";
const char HUE_ST2[] PROGMEM =
"ST: uuid:{r3\r\n"
"USN: uuid:{r3\r\n"
"ST: uuid:%s\r\n"
"USN: uuid:%s\r\n"
"\r\n";
const char HUE_ST3[] PROGMEM =
"ST: urn:schemas-upnp-org:device:basic:1\r\n"
"USN: uuid:{r3\r\n"
"USN: uuid:%s\r\n"
"\r\n";
String HueBridgeId(void)
@ -159,26 +164,20 @@ void HueRespondToMSearch(void)
TickerMSearch.detach();
if (PortUdp.beginPacket(udp_remote_ip, udp_remote_port)) {
String response1 = FPSTR(HUE_RESPONSE);
response1.replace("{r1", WiFi.localIP().toString());
response1.replace("{r2", HueBridgeId());
char response[320];
snprintf_P(response, sizeof(response), HUE_RESPONSE, WiFi.localIP().toString().c_str(), HueBridgeId().c_str());
int len = strlen(response);
String response = response1;
response += FPSTR(HUE_ST1);
response.replace("{r3", HueUuid());
PortUdp.write(response.c_str());
snprintf_P(response + len, sizeof(response) - len, HUE_ST1, HueUuid().c_str());
PortUdp.write(response);
PortUdp.endPacket();
response = response1;
response += FPSTR(HUE_ST2);
response.replace("{r3", HueUuid());
PortUdp.write(response.c_str());
snprintf_P(response + len, sizeof(response) - len, HUE_ST2, HueUuid().c_str(), HueUuid().c_str());
PortUdp.write(response);
PortUdp.endPacket();
response = response1;
response += FPSTR(HUE_ST3);
response.replace("{r3", HueUuid());
PortUdp.write(response.c_str());
snprintf_P(response + len, sizeof(response) - len, HUE_ST3, HueUuid().c_str());
PortUdp.write(response);
PortUdp.endPacket();
snprintf_P(message, sizeof(message), PSTR(D_3_RESPONSE_PACKETS_SENT));
@ -198,6 +197,7 @@ void HueRespondToMSearch(void)
bool UdpDisconnect(void)
{
if (udp_connected) {
PortUdp.flush();
WiFiUDP::stopAll();
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_MULTICAST_DISABLED));
udp_connected = false;
@ -208,7 +208,8 @@ bool UdpDisconnect(void)
bool UdpConnect(void)
{
if (!udp_connected) {
if (PortUdp.beginMulticast(WiFi.localIP(), ipMulticast, port_multicast)) {
// Simple Service Discovery Protocol (SSDP)
if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), 1900)) {
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED));
udp_response_mutex = false;
udp_connected = true;
@ -222,48 +223,53 @@ bool UdpConnect(void)
void PollUdp(void)
{
if (udp_connected && !udp_response_mutex) {
if (udp_connected) {
if (PortUdp.parsePacket()) {
char packet_buffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP/SSDP packet
int len = PortUdp.read(packet_buffer, UDP_BUFFER_SIZE -1);
if (len > 0) {
packet_buffer[len] = 0;
}
String request = packet_buffer;
packet_buffer[len] = 0;
// AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet received"));
// AddLog_P(LOG_LEVEL_DEBUG_MORE, packet_buffer);
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len);
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer);
if (request.indexOf("M-SEARCH") >= 0) {
request.toLowerCase();
request.replace(" ", "");
// AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: M-SEARCH Packet received"));
// AddLog_P(LOG_LEVEL_DEBUG_MORE, request.c_str());
if (devices_present && !udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) {
udp_response_mutex = true;
udp_remote_ip = PortUdp.remoteIP();
udp_remote_port = PortUdp.remotePort();
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: M-SEARCH Packet from %s:%d\n%s"),
// udp_remote_ip.toString().c_str(), udp_remote_port, packet_buffer);
uint32_t response_delay = UDP_MSEARCH_SEND_DELAY + ((millis() &0x7) * 100); // 1500 - 2200 msec
LowerCase(packet_buffer, packet_buffer);
RemoveSpace(packet_buffer);
if (EMUL_WEMO == Settings.flag2.emulation) {
if (request.indexOf(F("urn:belkin:device:**")) > 0) { // type1 echo dot 2g, echo 1g's
udp_response_mutex = true;
TickerMSearch.attach_ms(UDP_MSEARCH_SEND_DELAY, WemoRespondToMSearch, 1);
if (strstr_P(packet_buffer, URN_BELKIN_DEVICE) != nullptr) { // type1 echo dot 2g, echo 1g's
TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 1);
return;
}
else if ((request.indexOf(F("upnp:rootdevice")) > 0) || // type2 Echo 2g (echo & echo plus)
(request.indexOf(F("ssdpsearch:all")) > 0) ||
(request.indexOf(F("ssdp:all")) > 0)) {
udp_response_mutex = true;
TickerMSearch.attach_ms(UDP_MSEARCH_SEND_DELAY, WemoRespondToMSearch, 2);
else if ((strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || // type2 Echo 2g (echo & echo plus)
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 2);
return;
}
} else {
if ((strstr_P(packet_buffer, PSTR(":device:basic:1")) != nullptr) ||
(strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) ||
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
TickerMSearch.attach_ms(response_delay, HueRespondToMSearch);
return;
}
}
else if ((EMUL_HUE == Settings.flag2.emulation) &&
((request.indexOf(F("urn:schemas-upnp-org:device:basic:1")) > 0) ||
(request.indexOf(F("upnp:rootdevice")) > 0) ||
(request.indexOf(F("ssdpsearch:all")) > 0) ||
(request.indexOf(F("ssdp:all")) > 0))) {
udp_response_mutex = true;
TickerMSearch.attach_ms(UDP_MSEARCH_SEND_DELAY, HueRespondToMSearch);
}
udp_response_mutex = false;
}
}
delay(1);
}
}
@ -340,9 +346,9 @@ const char WEMO_METASERVICE_XML[] PROGMEM =
const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM =
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<s:Body>"
"<u:SetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">"
"<BinaryState>{x1</BinaryState>"
"</u:SetBinaryStateResponse>"
"<u:%cetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">"
"<BinaryState>%d</BinaryState>"
"</u:%cetBinaryStateResponse>"
"</s:Body>"
"</s:Envelope>\r\n";
@ -383,15 +389,20 @@ void HandleUpnpEvent(void)
{
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_BASIC_EVENT));
String request = WebServer->arg(0);
String state_xml = FPSTR(WEMO_RESPONSE_STATE_SOAP);
char event[500];
strlcpy(event, WebServer->arg(0).c_str(), sizeof(event));
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), event);
//differentiate get and set state
if (request.indexOf(F("SetBinaryState")) > 0) {
char state = 'G';
if (strstr_P(event, PSTR("SetBinaryState")) != nullptr) {
state = 'S';
uint8_t power = POWER_TOGGLE;
if (request.indexOf(F("State>1</Binary")) > 0) {
if (strstr_P(event, PSTR("State>1</Binary")) != nullptr) {
power = POWER_ON;
}
else if (request.indexOf(F("State>0</Binary")) > 0) {
else if (strstr_P(event, PSTR("State>0</Binary")) != nullptr) {
power = POWER_OFF;
}
if (power != POWER_TOGGLE) {
@ -399,11 +410,9 @@ void HandleUpnpEvent(void)
ExecuteCommandPower(device, power, SRC_WEMO);
}
}
else if(request.indexOf(F("GetBinaryState")) > 0){
state_xml.replace(F("Set"), F("Get"));
}
state_xml.replace("{x1", String(bitRead(power, devices_present -1)));
WSSend(200, CT_XML, state_xml);
snprintf_P(event, sizeof(event), WEMO_RESPONSE_STATE_SOAP, state, bitRead(power, devices_present -1), state);
WSSend(200, CT_XML, event);
}
void HandleUpnpService(void)
@ -837,14 +846,16 @@ void HandleHueApi(String *path)
void HueWemoAddHandlers(void)
{
if (EMUL_WEMO == Settings.flag2.emulation) {
WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
WebServer->on("/eventservice.xml", HandleUpnpService);
WebServer->on("/metainfoservice.xml", HandleUpnpMetaService);
WebServer->on("/setup.xml", HandleUpnpSetupWemo);
}
if (EMUL_HUE == Settings.flag2.emulation) {
WebServer->on("/description.xml", HandleUpnpSetupHue);
if (devices_present) {
if (EMUL_WEMO == Settings.flag2.emulation) {
WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
WebServer->on("/eventservice.xml", HandleUpnpService);
WebServer->on("/metainfoservice.xml", HandleUpnpMetaService);
WebServer->on("/setup.xml", HandleUpnpSetupWemo);
}
if (EMUL_HUE == Settings.flag2.emulation) {
WebServer->on("/description.xml", HandleUpnpSetupHue);
}
}
}

View File

@ -44,7 +44,7 @@
#else // USE_WS2812_DMA
typedef NeoEsp8266BitBang800KbpsMethod selectedNeoSpeedType;
#endif // USE_WS2812_DMA
NeoPixelBus<selectedNeoFeatureType, selectedNeoSpeedType> *strip = NULL;
NeoPixelBus<selectedNeoFeatureType, selectedNeoSpeedType> *strip = nullptr;
struct WsColor {
uint8_t red, green, blue;

View File

@ -107,11 +107,11 @@ void CounterShow(bool json)
if (json) {
if (!header) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"COUNTER\":{"), mqtt_data);
ResponseAppend_P(PSTR(",\"COUNTER\":{"));
stemp[0] = '\0';
}
header++;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"C%d\":%s"), mqtt_data, stemp, i +1, counter);
ResponseAppend_P(PSTR("%s\"C%d\":%s"), stemp, i +1, counter);
strlcpy(stemp, ",", sizeof(stemp));
#ifdef USE_DOMOTICZ
if ((0 == tele_period) && (1 == dsxflg)) {
@ -131,7 +131,7 @@ void CounterShow(bool json)
}
if (json) {
if (header) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
}
}
}

View File

@ -22,7 +22,16 @@
* ADC support
\*********************************************************************************************/
#define XSNS_02 2
#define XSNS_02 2
#define TO_CELSIUS(x) ((x) - 273.15)
#define TO_KELVIN(x) ((x) + 273.15)
#define ANALOG_V33 3.3
#define ANALOG_R21 32000.0
#define ANALOG_R0 10000.0
#define ANALOG_T0 TO_KELVIN(25.0)
#define ANALOG_B 3350.0
uint16_t adc_last_value = 0;
@ -40,26 +49,58 @@ uint16_t AdcRead(void)
#ifdef USE_RULES
void AdcEvery250ms(void)
{
uint16_t new_value = AdcRead();
if ((new_value < adc_last_value -10) || (new_value > adc_last_value +10)) {
adc_last_value = new_value;
uint16_t value = adc_last_value / 10;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"ANALOG\":{\"A0div10\":%d}}"), (value > 99) ? 100 : value);
XdrvRulesProcess();
if (my_module_flag.adc0) {
uint16_t new_value = AdcRead();
if ((new_value < adc_last_value -10) || (new_value > adc_last_value +10)) {
adc_last_value = new_value;
uint16_t value = adc_last_value / 10;
Response_P(PSTR("{\"ANALOG\":{\"A0div10\":%d}}"), (value > 99) ? 100 : value);
XdrvRulesProcess();
}
}
}
#endif // USE_RULES
void AdcShow(bool json)
{
uint16_t analog = AdcRead();
if (my_module_flag.adc0) {
uint16_t analog = AdcRead();
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"ANALOG\":{\"A0\":%d}"), mqtt_data, analog);
if (json) {
ResponseAppend_P(PSTR(",\"ANALOG\":{\"A0\":%d}"), analog);
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(HTTP_SNS_ANALOG, "", 0, analog);
} else {
WSContentSend_PD(HTTP_SNS_ANALOG, "", 0, analog);
#endif // USE_WEBSERVER
}
}
if (my_module_flag.adc0_temp) {
int adc = analogRead(A0);
// Formule used by Shelly 2.5 analog temperature sensor
double Rt = (adc * ANALOG_R21) / (1024.0 * ANALOG_V33 - (double)adc);
double T = ANALOG_B / (ANALOG_B/ANALOG_T0 + log(Rt/ANALOG_R0));
double temp = ConvertTemp(TO_CELSIUS(T));
char temperature[33];
dtostrfd(temp, Settings.flag2.temperature_resolution, temperature);
if (json) {
ResponseAppend_P(JSON_SNS_TEMP, "ANALOG", temperature);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzSensor(DZ_TEMP, temperature);
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, temp);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(HTTP_SNS_TEMP, "", temperature, TempUnit());
#endif // USE_WEBSERVER
}
}
}
@ -71,7 +112,7 @@ bool Xsns02(uint8_t function)
{
bool result = false;
if (my_module_flag.adc0) {
if (my_module_flag.adc0 || my_module_flag.adc0_temp) {
switch (function) {
#ifdef USE_RULES
case FUNC_EVERY_250_MSECOND:

View File

@ -81,7 +81,7 @@ void SonoffScSerialInput(char *rcvstat)
if (!strncasecmp_P(rcvstat, PSTR("AT+UPDATE="), 10)) {
int8_t i = -1;
for (str = strtok_r(rcvstat, ":", &p); str && i < 5; str = strtok_r(NULL, ":", &p)) {
for (str = strtok_r(rcvstat, ":", &p); str && i < 5; str = strtok_r(nullptr, ":", &p)) {
value[i++] = atoi(str);
}
if (value[0] > 0) {
@ -120,8 +120,8 @@ void SonoffScShow(bool json)
dtostrfd(h, Settings.flag2.humidity_resolution, humidity);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SonoffSC\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s,\"" D_JSON_LIGHT "\":%d,\"" D_JSON_NOISE "\":%d,\"" D_JSON_AIRQUALITY "\":%d}"),
mqtt_data, temperature, humidity, sc_value[2], sc_value[3], sc_value[4]);
ResponseAppend_P(PSTR(",\"SonoffSC\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s,\"" D_JSON_LIGHT "\":%d,\"" D_JSON_NOISE "\":%d,\"" D_JSON_AIRQUALITY "\":%d}"),
temperature, humidity, sc_value[2], sc_value[3], sc_value[4]);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzTempHumSensor(temperature, humidity);

View File

@ -205,7 +205,7 @@ void Ds18b20Show(bool json)
char temperature[33];
dtostrfd(ds18b20_temperature, Settings.flag2.temperature_resolution, temperature);
if(json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMP, mqtt_data, ds18b20_types, temperature);
ResponseAppend_P(JSON_SNS_TEMP, ds18b20_types, temperature);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzSensor(DZ_TEMP, temperature);

View File

@ -432,13 +432,13 @@ void Ds18x20Show(bool json)
if (json) {
if (1 == ds18x20_sensors) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, ds18x20_types, temperature);
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"), ds18x20_types, temperature);
} else {
char address[17];
for (uint8_t j = 0; j < 6; j++) {
sprintf(address+2*j, "%02X", ds18x20_sensor[index].address[6-j]); // Skip sensor type and crc
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, ds18x20_types, address, temperature);
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"), ds18x20_types, address, temperature);
}
#ifdef USE_DOMOTICZ
if ((0 == tele_period) && (0 == i)) {

View File

@ -36,7 +36,7 @@
#include <OneWire.h>
OneWire *ds = NULL;
OneWire *ds = nullptr;
uint8_t ds18x20_address[DS18X20_MAX_SENSORS][8];
uint8_t ds18x20_index[DS18X20_MAX_SENSORS];
@ -178,12 +178,12 @@ void Ds18x20Show(bool json)
if (json) {
if (!dsxflg) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"DS18x20\":{"), mqtt_data);
ResponseAppend_P(PSTR(",\"DS18x20\":{"));
stemp[0] = '\0';
}
dsxflg++;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"DS%d\":{\"" D_JSON_TYPE "\":\"%s\",\"" D_JSON_ADDRESS "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"),
mqtt_data, stemp, i +1, ds18x20_types, Ds18x20Addresses(i).c_str(), temperature);
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)) {
@ -205,7 +205,7 @@ void Ds18x20Show(bool json)
}
if (json) {
if (dsxflg) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
}
}
Ds18x20Search(); // Check for changes in sensors number

View File

@ -213,7 +213,7 @@ void DhtShow(bool json)
dtostrfd(Dht[i].h, Settings.flag2.humidity_resolution, humidity);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, Dht[i].stype, temperature, humidity);
ResponseAppend_P(JSON_SNS_TEMPHUM, Dht[i].stype, temperature, humidity);
#ifdef USE_DOMOTICZ
if ((0 == tele_period) && (0 == i)) {
DomoticzTempHumSensor(temperature, humidity);

View File

@ -194,7 +194,7 @@ void ShtShow(bool json)
dtostrfd(sht_humidity, Settings.flag2.humidity_resolution, humidity);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, sht_types, temperature, humidity);
ResponseAppend_P(JSON_SNS_TEMPHUM, sht_types, temperature, humidity);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzTempHumSensor(temperature, humidity);

View File

@ -254,7 +254,7 @@ void HtuShow(bool json)
dtostrfd(htu_humidity, Settings.flag2.humidity_resolution, humidity);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, htu_types, temperature, humidity);
ResponseAppend_P(JSON_SNS_TEMPHUM, htu_types, temperature, humidity);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzTempHumSensor(temperature, humidity);

View File

@ -61,7 +61,7 @@ uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2 };
uint8_t bmp_count = 0;
uint8_t bmp_once = 1;
bmp_sensors_t *bmp_sensors = NULL;
bmp_sensors_t *bmp_sensors = nullptr;
/*********************************************************************************************\
* BMP085 and BME180
@ -99,7 +99,7 @@ typedef struct {
uint16_t cal_ac6;
} bmp180_cal_data_t;
bmp180_cal_data_t *bmp180_cal_data = NULL;
bmp180_cal_data_t *bmp180_cal_data = nullptr;
bool Bmp180Calibration(uint8_t bmp_idx)
{
@ -244,7 +244,7 @@ typedef struct {
int8_t dig_H6;
} Bme280CalibrationData_t;
Bme280CalibrationData_t *Bme280CalibrationData = NULL;
Bme280CalibrationData_t *Bme280CalibrationData = nullptr;
bool Bmx280Calibrate(uint8_t bmp_idx)
{
@ -344,7 +344,7 @@ void Bme280Read(uint8_t bmp_idx)
#include <bme680.h>
struct bme680_dev *gas_sensor = NULL;
struct bme680_dev *gas_sensor = nullptr;
static void BmeDelayMs(uint32_t ms)
{
@ -566,8 +566,7 @@ void BmpShow(bool json)
char json_gas[40];
snprintf_P(json_gas, sizeof(json_gas), PSTR(",\"" D_JSON_GAS "\":%s"), gas_resistance);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s%s}"),
mqtt_data,
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s%s}"),
name,
temperature,
(bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "",
@ -575,8 +574,8 @@ void BmpShow(bool json)
(Settings.altitude != 0) ? json_sealevel : "",
(bmp_sensors[bmp_idx].bmp_model >= 3) ? json_gas : "");
#else
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s}"),
mqtt_data, name, temperature, (bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : "");
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s}"),
name, temperature, (bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : "");
#endif // USE_BME680
#ifdef USE_DOMOTICZ

View File

@ -92,7 +92,7 @@ void Bh1750Show(bool json)
{
if (bh1750_valid) {
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d}"), mqtt_data, bh1750_types, bh1750_illuminance);
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d}"), bh1750_types, bh1750_illuminance);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzSensor(DZ_ILLUMINANCE, bh1750_illuminance);

View File

@ -277,11 +277,11 @@ void Veml6070Show(bool json)
dtostrfd(uvpower, 3, str_uvpower);
if (json) {
#ifdef USE_VEML6070_SHOW_RAW
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_LEVEL "\":%s,\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"),
mqtt_data, veml6070_name, str_uvlevel, str_uvrisk, str_uvrisk_text, str_uvpower);
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_UV_LEVEL "\":%s,\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"),
veml6070_name, str_uvlevel, str_uvrisk, str_uvrisk_text, str_uvpower);
#else
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"),
mqtt_data, veml6070_name, str_uvrisk, str_uvrisk_text, str_uvpower);
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"),
veml6070_name, str_uvrisk, str_uvrisk_text, str_uvpower);
#endif // USE_VEML6070_SHOW_RAW
#ifdef USE_DOMOTICZ
if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, uvlevel); }

View File

@ -188,13 +188,13 @@ void Ads1115GetValues(uint8_t address)
void Ads1115toJSON(char *comma_j)
{
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s{"), mqtt_data,comma_j);
ResponseAppend_P(PSTR("%s{"), comma_j);
char *comma = (char*)"";
for (uint8_t i = 0; i < 4; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"A%d\":%d"), mqtt_data, comma, i, ads1115_values[i]);
ResponseAppend_P(PSTR("%s\"A%d\":%d"), comma, i, ads1115_values[i]);
comma = (char*)",";
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
}
void Ads1115toString(uint8_t address)
@ -212,7 +212,7 @@ void Ads1115Show(bool json)
if (!ads1115_type) { return; }
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"ADS1115\":["), mqtt_data);
ResponseAppend_P(PSTR(",\"ADS1115\":["));
}
char *comma = (char*)"";
@ -234,7 +234,7 @@ void Ads1115Show(bool json)
}
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]"), mqtt_data);
ResponseAppend_P(PSTR("]"));
}
}

View File

@ -99,7 +99,6 @@ void Ads1115Detect(void)
void Ads1115Show(bool json)
{
if (ads1115_type) {
char stemp[10];
uint8_t dsxflg = 0;
for (uint8_t i = 0; i < 4; i++) {
@ -107,12 +106,10 @@ void Ads1115Show(bool json)
if (json) {
if (!dsxflg ) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"ADS1115\":{"), mqtt_data);
stemp[0] = '\0';
ResponseAppend_P(PSTR(",\"ADS1115\":{"));
}
ResponseAppend_P(PSTR("%s\"A%d\":%d"), (dsxflg) ? "," : "", i, adc_value);
dsxflg++;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"A%d\":%d"), mqtt_data, stemp, i, adc_value);
strlcpy(stemp, ",", sizeof(stemp));
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(HTTP_SNS_ANALOG, "ADS1115", i, adc_value);
@ -121,7 +118,7 @@ void Ads1115Show(bool json)
}
if (json) {
if (dsxflg) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
}
}
}

View File

@ -183,7 +183,7 @@ bool Ina219CommandSensor(void)
Settings.ina219_mode = XdrvMailbox.payload;
restart_flag = 2;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_NVALUE, XSNS_13, Settings.ina219_mode);
Response_P(S_JSON_SENSOR_INDEX_NVALUE, XSNS_13, Settings.ina219_mode);
return serviced;
}
@ -240,8 +240,8 @@ void Ina219Show(bool json)
dtostrfd(ina219_current, Settings.flag2.current_resolution, current);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_POWERUSAGE "\":%s}"),
mqtt_data, ina219_types, voltage, current, power);
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_POWERUSAGE "\":%s}"),
ina219_types, voltage, current, power);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzSensor(DZ_VOLTAGE, voltage);

View File

@ -110,7 +110,7 @@ void Sht3xShow(bool json)
snprintf_P(types, sizeof(types), PSTR("%s-0x%02X"), sht3x_sensors[i].types, sht3x_sensors[i].address); // "SHT3X-0xXX"
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, types, temperature, humidity);
ResponseAppend_P(JSON_SNS_TEMPHUM, types, temperature, humidity);
#ifdef USE_DOMOTICZ
if ((0 == tele_period) && (0 == i)) { // We want the same first sensor to report to Domoticz in case a read is missed
DomoticzTempHumSensor(temperature, humidity);

View File

@ -71,8 +71,8 @@ TasmotaSerial *MhzSerial;
const char kMhzModels[] PROGMEM = "|B";
const char ABC_ENABLED[] PROGMEM = "ABC is Enabled";
const char ABC_DISABLED[] PROGMEM = "ABC is Enabled";
const char ABC_ENABLED[] = "ABC is Enabled";
const char ABC_DISABLED[] = "ABC is Disabled";
enum MhzCommands { MHZ_CMND_READPPM, MHZ_CMND_ABCENABLE, MHZ_CMND_ABCDISABLE, MHZ_CMND_ZEROPOINT, MHZ_CMND_RESET, MHZ_CMND_RANGE_1000, MHZ_CMND_RANGE_2000, MHZ_CMND_RANGE_3000, MHZ_CMND_RANGE_5000 };
const uint8_t kMhzCommands[][4] PROGMEM = {
@ -276,42 +276,42 @@ bool MhzCommandSensor(void)
case 0:
Settings.SensorBits1.mhz19b_abc_disable = true;
MhzSendCmd(MHZ_CMND_ABCDISABLE);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_DISABLED);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_DISABLED);
break;
case 1:
Settings.SensorBits1.mhz19b_abc_disable = false;
MhzSendCmd(MHZ_CMND_ABCENABLE);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_ENABLED);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_ENABLED);
break;
case 2:
MhzSendCmd(MHZ_CMND_ZEROPOINT);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_ZERO_POINT_CALIBRATION);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_ZERO_POINT_CALIBRATION);
break;
case 9:
MhzSendCmd(MHZ_CMND_RESET);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RESET);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RESET);
break;
case 1000:
MhzSendCmd(MHZ_CMND_RANGE_1000);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_1000);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_1000);
break;
case 2000:
MhzSendCmd(MHZ_CMND_RANGE_2000);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_2000);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_2000);
break;
case 3000:
MhzSendCmd(MHZ_CMND_RANGE_3000);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_3000);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_3000);
break;
case 5000:
MhzSendCmd(MHZ_CMND_RANGE_5000);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_5000);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_5000);
break;
default:
if (!Settings.SensorBits1.mhz19b_abc_disable) {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_ENABLED);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_ENABLED);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_DISABLED);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_DISABLED);
}
}
@ -342,7 +342,7 @@ void MhzShow(bool json)
GetTextIndexed(model, sizeof(model), mhz_type -1, kMhzModels);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_MODEL "\":\"%s\",\"" D_JSON_CO2 "\":%d,\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, types, model, mhz_last_ppm, temperature);
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_MODEL "\":\"%s\",\"" D_JSON_CO2 "\":%d,\"" D_JSON_TEMPERATURE "\":%s}"), types, model, mhz_last_ppm, temperature);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzSensor(DZ_AIRQUALITY, mhz_last_ppm);

View File

@ -102,8 +102,8 @@ void Tsl2561Show(bool json)
{
if (tsl2561_valid) {
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"TSL2561\":{\"" D_JSON_ILLUMINANCE "\":%u.%03u}"),
mqtt_data, tsl2561_milliLux / 1000, tsl2561_milliLux % 1000);
ResponseAppend_P(PSTR(",\"TSL2561\":{\"" D_JSON_ILLUMINANCE "\":%u.%03u}"),
tsl2561_milliLux / 1000, tsl2561_milliLux % 1000);
#ifdef USE_DOMOTICZ
if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, (tsl2561_milliLux + 500) / 1000); }
#endif // USE_DOMOTICZ

View File

@ -149,11 +149,11 @@ void SenseairShow(bool json)
GetTextIndexed(senseair_types, sizeof(senseair_types), senseair_type -1, kSenseairTypes);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_CO2 "\":%d"), mqtt_data, senseair_types, senseair_co2);
ResponseAppend_P(PSTR("%s,\"%s\":{\"" D_JSON_CO2 "\":%d"), senseair_types, senseair_co2);
if (senseair_type != 2) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s"), mqtt_data, temperature, humidity);
ResponseAppend_P(PSTR("%s,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s"), temperature, humidity);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
ResponseAppend_P(PSTR("}"));
#ifdef USE_DOMOTICZ
if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, senseair_co2);
#endif // USE_DOMOTICZ

View File

@ -132,7 +132,7 @@ void PmsShow(bool json)
{
if (pms_valid) {
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PMS5003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d,\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,\"PB5\":%d,\"PB10\":%d}"), mqtt_data,
ResponseAppend_P(PSTR(",\"PMS5003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d,\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,\"PB5\":%d,\"PB10\":%d}"),
pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard,
pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env,
pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um, pms_data.particles_50um, pms_data.particles_100um);

View File

@ -64,14 +64,14 @@ void MGSShow(bool json)
{
char buffer[33];
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MGS\":{\"NH3\":%s"), mqtt_data, measure_gas(NH3, buffer));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"CO\":%s"), mqtt_data, measure_gas(CO, buffer));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"NO2\":%s"), mqtt_data, measure_gas(NO2, buffer));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"C3H8\":%s"), mqtt_data, measure_gas(C3H8, buffer));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"C4H10\":%s"), mqtt_data, measure_gas(C4H10, buffer));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"CH4\":%s"), mqtt_data, measure_gas(GAS_CH4, buffer));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"H2\":%s"), mqtt_data, measure_gas(H2, buffer));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"C2H5OH\":%s}"), mqtt_data, measure_gas(C2H5OH, buffer));
ResponseAppend_P(PSTR(",\"MGS\":{\"NH3\":%s"), measure_gas(NH3, buffer));
ResponseAppend_P(PSTR(",\"CO\":%s"), measure_gas(CO, buffer));
ResponseAppend_P(PSTR(",\"NO2\":%s"), measure_gas(NO2, buffer));
ResponseAppend_P(PSTR(",\"C3H8\":%s"), measure_gas(C3H8, buffer));
ResponseAppend_P(PSTR(",\"C4H10\":%s"), measure_gas(C4H10, buffer));
ResponseAppend_P(PSTR(",\"CH4\":%s"), measure_gas(GAS_CH4, buffer));
ResponseAppend_P(PSTR(",\"H2\":%s"), measure_gas(H2, buffer));
ResponseAppend_P(PSTR(",\"C2H5OH\":%s}"), measure_gas(C2H5OH, buffer));
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(HTTP_MGS_GAS, "NH3", measure_gas(NH3, buffer));

View File

@ -47,13 +47,11 @@
#define NOVA_SDS_DEVICE_ID 0xFFFF // NodaSDS all sensor response
#endif
TasmotaSerial *NovaSdsSerial;
uint8_t novasds_type = 1;
uint8_t novasds_valid = 0;
struct sds011data {
uint16_t pm100;
uint16_t pm25;
@ -109,7 +107,7 @@ bool NovaSdsCommand(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint16_t sensor
NovaSdsSerial->readBytes(&recbuf[1], 9);
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, recbuf, sizeof(recbuf));
if ( NULL != buffer ) {
if ( nullptr != buffer ) {
// return data to buffer
memcpy(buffer, recbuf, sizeof(recbuf));
}
@ -126,9 +124,9 @@ bool NovaSdsCommand(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint16_t sensor
void NovaSdsSetWorkPeriod(void)
{
// set sensor working period
NovaSdsCommand(NOVA_SDS_WORKING_PERIOD, NOVA_SDS_SET_MODE, WORKING_PERIOD, NOVA_SDS_DEVICE_ID, NULL);
NovaSdsCommand(NOVA_SDS_WORKING_PERIOD, NOVA_SDS_SET_MODE, Settings.novasds_period, NOVA_SDS_DEVICE_ID, nullptr);
// set sensor report only on query
NovaSdsCommand(NOVA_SDS_REPORTING_MODE, NOVA_SDS_SET_MODE, NOVA_SDS_REPORT_QUERY, NOVA_SDS_DEVICE_ID, NULL);
NovaSdsCommand(NOVA_SDS_REPORTING_MODE, NOVA_SDS_SET_MODE, NOVA_SDS_REPORT_QUERY, NOVA_SDS_DEVICE_ID, nullptr);
}
bool NovaSdsReadData(void)
@ -162,7 +160,22 @@ void NovaSdsSecond(void) // Every second
}
}
/*********************************************************************************************/
/*********************************************************************************************\
* Command Sensor20
*
* 1 .. 255 - Set working period in minutes
\*********************************************************************************************/
bool NovaSdsCommandSensor(void)
{
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 256)) {
Settings.novasds_period = XdrvMailbox.payload;
NovaSdsSetWorkPeriod();
}
Response_P(S_JSON_SENSOR_INDEX_NVALUE, XSNS_20, Settings.novasds_period);
return true;
}
void NovaSdsInit(void)
{
@ -195,7 +208,7 @@ void NovaSdsShow(bool json)
char pm2_5[33];
dtostrfd(pm2_5f, 1, pm2_5);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SDS0X1\":{\"PM2.5\":%s,\"PM10\":%s}"), mqtt_data, pm2_5, pm10);
ResponseAppend_P(PSTR(",\"SDS0X1\":{\"PM2.5\":%s,\"PM10\":%s}"), pm2_5, pm10);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzSensor(DZ_VOLTAGE, pm2_5); // PM2.5
@ -226,6 +239,11 @@ bool Xsns20(uint8_t function)
case FUNC_EVERY_SECOND:
NovaSdsSecond();
break;
case FUNC_COMMAND_SENSOR:
if (XSNS_20 == XdrvMailbox.index) {
result = NovaSdsCommandSensor();
}
break;
case FUNC_JSON_APPEND:
NovaSdsShow(1);
break;

View File

@ -71,7 +71,7 @@ void Sgp30Show(bool json)
{
if (sgp30_ready) {
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d}"), mqtt_data, sgp.eCO2, sgp.TVOC);
ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d}"), sgp.eCO2, sgp.TVOC);
#ifdef USE_DOMOTICZ
if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, sgp.eCO2);
#endif // USE_DOMOTICZ

View File

@ -34,7 +34,7 @@ uint8_t sr04_echo_pin = 0;
uint8_t sr04_trig_pin = 0;
real64_t distance;
NewPing* sonar = NULL;
NewPing* sonar = nullptr;
void Sr04Init(void)
{
@ -57,7 +57,7 @@ void Sr04Show(bool json)
dtostrfd(distance, 3, distance_chr);
if(json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SR04\":{\"" D_JSON_DISTANCE "\":%s}"), mqtt_data, distance_chr);
ResponseAppend_P(PSTR(",\"SR04\":{\"" D_JSON_DISTANCE "\":%s}"), distance_chr);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzSensor(DZ_COUNT, distance_chr); // Send distance as Domoticz Counter value

View File

@ -314,11 +314,11 @@ void SDM120Show(bool json)
#endif // USE_SDM220
if (json) {
#ifdef USE_SDM220
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_ACTIVE_POWERUSAGE "\":%s,\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_FREQUENCY "\":%s,\"" D_JSON_POWERFACTOR "\":%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_PHASE_ANGLE "\":%s,\"" D_JSON_IMPORT_ACTIVE "\":%s,\"" D_JSON_EXPORT_ACTIVE "\":%s,\"" D_JSON_IMPORT_REACTIVE "\":%s,\"" D_JSON_EXPORT_REACTIVE "\":%s,\"" D_JSON_TOTAL_REACTIVE "\":%s}"),
mqtt_data, energy_total, active_power, apparent_power, reactive_power, frequency, power_factor, voltage, current, phase_angle, import_active, export_active, import_reactive, export_reactive, total_reactive);
ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_ACTIVE_POWERUSAGE "\":%s,\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_FREQUENCY "\":%s,\"" D_JSON_POWERFACTOR "\":%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_PHASE_ANGLE "\":%s,\"" D_JSON_IMPORT_ACTIVE "\":%s,\"" D_JSON_EXPORT_ACTIVE "\":%s,\"" D_JSON_IMPORT_REACTIVE "\":%s,\"" D_JSON_EXPORT_REACTIVE "\":%s,\"" D_JSON_TOTAL_REACTIVE "\":%s}"),
energy_total, active_power, apparent_power, reactive_power, frequency, power_factor, voltage, current, phase_angle, import_active, export_active, import_reactive, export_reactive, total_reactive);
#else
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_ACTIVE_POWERUSAGE "\":%s,\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_FREQUENCY "\":%s,\"" D_JSON_POWERFACTOR "\":%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"),
mqtt_data, energy_total, active_power, apparent_power, reactive_power, frequency, power_factor, voltage, current);
ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_ACTIVE_POWERUSAGE "\":%s,\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_FREQUENCY "\":%s,\"" D_JSON_POWERFACTOR "\":%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"),
energy_total, active_power, apparent_power, reactive_power, frequency, power_factor, voltage, current);
#endif // USE_SDM220
#ifdef USE_DOMOTICZ
if (0 == tele_period) {

Some files were not shown because too many files have changed in this diff Show More