From d85278f1b2e556acd0a6cfb09cc527f52cde9360 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 13 Mar 2019 18:00:15 +0100 Subject: [PATCH] Prep for release 6.5 Prep for release 6.5 --- .github/ISSUE_TEMPLATE/Bug_report.md | 50 +- .github/ISSUE_TEMPLATE/Custom.md | 39 +- .github/PULL_REQUEST_TEMPLATE.md | 10 + .github/stale.yml | 6 +- API.md | 2 + CODE_OF_CONDUCT.md | 76 + CONTRIBUTING.md | 63 + README.md | 11 +- RELEASENOTES.md | 91 +- SUPPORT.md | 22 + TEMPLATE.md | 86 + arduino/version 2.5.0/boards.txt | 303 +-- arduino/version 2.5.0/platform.txt | 31 +- lib/ArduinoJson-5.11.2/ArduinoJson.h | 8 - lib/ArduinoJson-5.11.2/README.md | 130 -- .../JsonHttpClient/JsonHttpClient.ino | 184 -- .../examples/JsonServer/JsonServer.ino | 76 - .../examples/JsonUdpBeacon/JsonUdpBeacon.ino | 57 - lib/ArduinoJson-5.11.2/library.properties | 9 - lib/ArduinoJson-5.11.2/src/ArduinoJson.h | 12 - .../src/ArduinoJson/Data/ValueSetter.hpp | 51 - .../src/ArduinoJson/Polyfills/isInteger.hpp | 22 - .../src/ArduinoJson/RawJson.hpp | 23 - .../TypeTraits/IsSignedIntegral.hpp | 33 - .../TypeTraits/IsUnsignedIntegral.hpp | 33 - lib/ArduinoJson-5.13.4/ArduinoJson.h | 5 + .../CHANGELOG.md | 317 ++- .../LICENSE.md | 2 +- lib/ArduinoJson-5.13.4/README.md | 110 + .../JsonConfigFile/JsonConfigFile.ino | 144 ++ .../JsonGeneratorExample.ino | 29 +- .../JsonHttpClient/JsonHttpClient.ino | 112 + .../JsonParserExample/JsonParserExample.ino | 31 +- .../examples/JsonServer/JsonServer.ino | 109 + .../examples/JsonUdpBeacon/JsonUdpBeacon.ino | 101 + .../ProgmemExample/ProgmemExample.ino | 38 +- .../examples/StringExample/StringExample.ino | 33 +- .../keywords.txt | 0 lib/ArduinoJson-5.13.4/library.properties | 11 + lib/ArduinoJson-5.13.4/src/ArduinoJson.h | 17 + .../src/ArduinoJson.hpp | 9 +- .../src/ArduinoJson/Configuration.hpp | 10 +- .../src/ArduinoJson/Data/Encoding.hpp | 7 +- .../ArduinoJson/Data/JsonBufferAllocated.hpp | 7 +- .../src/ArduinoJson/Data/JsonFloat.hpp | 7 +- .../src/ArduinoJson/Data/JsonInteger.hpp | 7 +- .../src/ArduinoJson/Data/JsonVariantAs.hpp | 7 +- .../ArduinoJson/Data/JsonVariantContent.hpp | 7 +- .../ArduinoJson/Data/JsonVariantDefault.hpp | 7 +- .../src/ArduinoJson/Data/JsonVariantType.hpp | 7 +- .../src/ArduinoJson/Data/List.hpp | 7 +- .../ArduinoJson/Data/ListConstIterator.hpp | 7 +- .../src/ArduinoJson/Data/ListIterator.hpp | 7 +- .../src/ArduinoJson/Data/ListNode.hpp | 7 +- .../src/ArduinoJson/Data/NonCopyable.hpp | 7 +- .../src/ArduinoJson/Data/ReferenceType.hpp | 7 +- .../src/ArduinoJson/Data/ValueSaver.hpp | 52 + .../ArduinoJson/Deserialization/Comments.hpp | 7 +- .../Deserialization/JsonParser.hpp | 29 +- .../Deserialization/JsonParserImpl.hpp | 35 +- .../Deserialization/StringWriter.hpp | 7 +- .../src/ArduinoJson/DynamicJsonBuffer.hpp | 12 +- .../src/ArduinoJson/JsonArray.hpp | 48 +- .../src/ArduinoJson/JsonArrayImpl.hpp | 7 +- .../src/ArduinoJson/JsonArraySubscript.hpp | 61 +- .../src/ArduinoJson/JsonBuffer.hpp | 24 +- .../src/ArduinoJson/JsonBufferBase.hpp | 21 +- .../src/ArduinoJson/JsonBufferImpl.hpp | 7 +- .../src/ArduinoJson/JsonObject.hpp | 195 +- .../src/ArduinoJson/JsonObjectImpl.hpp | 7 +- .../src/ArduinoJson/JsonObjectSubscript.hpp | 41 +- .../src/ArduinoJson/JsonPair.hpp | 7 +- .../src/ArduinoJson/JsonVariant.hpp | 115 +- .../src/ArduinoJson/JsonVariantBase.hpp | 15 +- .../src/ArduinoJson/JsonVariantCasts.hpp | 9 +- .../ArduinoJson/JsonVariantComparisons.hpp | 41 +- .../src/ArduinoJson/JsonVariantImpl.hpp | 15 +- .../src/ArduinoJson/JsonVariantOr.hpp | 52 + .../src/ArduinoJson/JsonVariantSubscripts.hpp | 35 +- .../src/ArduinoJson/Polyfills/attributes.hpp | 9 +- .../src/ArduinoJson/Polyfills/ctype.hpp | 9 +- .../src/ArduinoJson/Polyfills/isFloat.hpp | 9 +- .../src/ArduinoJson/Polyfills/isInteger.hpp | 19 + .../src/ArduinoJson/Polyfills/math.hpp | 9 +- .../src/ArduinoJson/Polyfills/parseFloat.hpp | 11 +- .../ArduinoJson/Polyfills/parseInteger.hpp | 9 +- .../src/ArduinoJson/RawJson.hpp | 46 + .../ArduinoJson/Serialization/DummyPrint.hpp | 7 +- .../Serialization/DynamicStringBuilder.hpp | 7 +- .../ArduinoJson/Serialization/FloatParts.hpp | 9 +- .../Serialization/IndentedPrint.hpp | 7 +- .../Serialization/JsonPrintable.hpp | 21 +- .../Serialization/JsonSerializer.hpp | 14 +- .../Serialization/JsonSerializerImpl.hpp | 7 +- .../ArduinoJson/Serialization/JsonWriter.hpp | 11 +- .../ArduinoJson/Serialization/Prettyfier.hpp | 7 +- .../Serialization/StaticStringBuilder.hpp | 7 +- .../Serialization/StreamPrintAdapter.hpp | 7 +- .../src/ArduinoJson/StaticJsonBuffer.hpp | 14 +- .../StringTraits/ArduinoStream.hpp | 20 +- .../ArduinoJson/StringTraits/CharPointer.hpp | 32 +- .../ArduinoJson/StringTraits/FlashString.hpp | 25 +- .../ArduinoJson/StringTraits/StdStream.hpp | 20 +- .../ArduinoJson/StringTraits/StdString.hpp | 27 +- .../ArduinoJson/StringTraits/StringTraits.hpp | 28 +- .../src/ArduinoJson/TypeTraits/EnableIf.hpp | 9 +- .../ArduinoJson/TypeTraits/FloatTraits.hpp | 54 +- .../src/ArduinoJson/TypeTraits/IsArray.hpp | 9 +- .../src/ArduinoJson/TypeTraits/IsBaseOf.hpp | 9 +- .../src/ArduinoJson/TypeTraits/IsChar.hpp | 9 +- .../src/ArduinoJson/TypeTraits/IsConst.hpp | 9 +- .../TypeTraits/IsFloatingPoint.hpp | 9 +- .../src/ArduinoJson/TypeTraits/IsIntegral.hpp | 15 +- .../src/ArduinoJson/TypeTraits/IsSame.hpp | 9 +- .../TypeTraits/IsSignedIntegral.hpp | 28 + .../TypeTraits/IsUnsignedIntegral.hpp | 28 + .../src/ArduinoJson/TypeTraits/IsVariant.hpp | 9 +- .../ArduinoJson/TypeTraits/RemoveConst.hpp | 9 +- .../TypeTraits/RemoveReference.hpp | 9 +- .../src/ArduinoJson/version.hpp | 10 + lib/FrogmoreScd30/FrogmoreScd30.cpp | 653 ++++++ lib/FrogmoreScd30/FrogmoreScd30.h | 105 + lib/LinkedList-1.2.3/LICENSE.txt | 21 + lib/LinkedList-1.2.3/LinkedList.h | 325 +++ lib/LinkedList-1.2.3/README.md | 171 ++ .../examples/ClassList/ClassList.pde | 81 + .../SimpleIntegerList/SimpleIntegerList.pde | 58 + lib/LinkedList-1.2.3/keywords.txt | 28 + lib/LinkedList-1.2.3/library.json | 12 + lib/LinkedList-1.2.3/library.properties | 9 + lib/NewPing-1.9.1/README.md | 2 +- .../NewPing15SensorsTimer.pde | 2 +- .../NewPing3Sensors/NewPing3Sensors.pde | 8 +- .../NewPingTimerMedian/NewPingTimerMedian.pde | 2 +- .../examples/TimerExample/TimerExample.pde | 2 +- lib/NewPing-1.9.1/keywords.txt | 1 - lib/NewPing-1.9.1/src/NewPing.cpp | 2 +- lib/NewPing-1.9.1/src/NewPing.h | 6 +- lib/TasmotaModbus-1.1.0/src/TasmotaModbus.cpp | 1 - .../README.md | 0 .../examples/swsertest/swsertest.ino | 0 .../keywords.txt | 1 + .../library.json | 2 +- .../library.properties | 2 +- .../src/TasmotaSerial.cpp | 8 +- .../src/TasmotaSerial.h | 4 +- sonoff/Parsing.cpp | 623 ++++++ sonoff/_changelog.ino | 140 +- sonoff/core_esp8266_timer.c | 10 +- sonoff/core_esp8266_wiring_digital.c | 10 +- sonoff/core_esp8266_wiring_pwm.c | 10 +- sonoff/i18n.h | 35 +- sonoff/language/bg-BG.h | 160 +- sonoff/language/cs-CZ.h | 158 +- sonoff/language/de-DE.h | 160 +- sonoff/language/el-GR.h | 158 +- sonoff/language/en-GB.h | 158 +- sonoff/language/es-AR.h | 160 +- sonoff/language/fr-FR.h | 182 +- sonoff/language/he-HE.h | 158 +- sonoff/language/hu-HU.h | 612 +++--- sonoff/language/it-IT.h | 158 +- sonoff/language/ko-KO.h | 647 ++++++ sonoff/language/nl-NL.h | 158 +- sonoff/language/pl-PL.h | 184 +- sonoff/language/pt-BR.h | 158 +- sonoff/language/pt-PT.h | 158 +- sonoff/language/ru-RU.h | 158 +- sonoff/language/sk-SK.h | 158 +- sonoff/language/sv-SE.h | 210 +- sonoff/language/tr-TR.h | 158 +- sonoff/language/uk-UK.h | 158 +- sonoff/language/zh-CN.h | 256 ++- sonoff/language/zh-TW.h | 158 +- sonoff/my_user_config.h | 38 +- sonoff/settings.h | 143 +- sonoff/settings.ino | 301 ++- sonoff/sonoff.h | 21 +- sonoff/sonoff.ino | 1131 +++++----- sonoff/sonoff_letsencrypt.h | 2 +- sonoff/sonoff_post.h | 58 +- sonoff/sonoff_template.h | 1154 ++++++++-- sonoff/sonoff_version.h | 4 +- sonoff/support.ino | 409 ++-- sonoff/support_button.ino | 242 ++ sonoff/support_features.ino | 36 +- sonoff/support_rotary.ino | 151 ++ sonoff/support_rtc.ino | 101 +- sonoff/support_switch.ino | 221 ++ sonoff/support_wifi.ino | 95 +- sonoff/user_config_override_sample.h | 8 +- sonoff/xdrv_01_webserver.ino | 1951 ++++++++++------- sonoff/xdrv_02_mqtt.ino | 249 ++- sonoff/xdrv_03_energy.ino | 122 +- sonoff/xdrv_04_light.ino | 320 ++- sonoff/xdrv_05_irremote.ino | 112 +- sonoff/xdrv_06_snfbridge.ino | 30 +- sonoff/xdrv_07_domoticz.ino | 126 +- sonoff/xdrv_08_serial_bridge.ino | 95 +- sonoff/xdrv_09_timers.ino | 157 +- sonoff/xdrv_10_rules.ino | 742 ++++++- sonoff/xdrv_11_knx.ino | 397 ++-- sonoff/xdrv_12_home_assistant.ino | 307 +-- sonoff/xdrv_13_display.ino | 71 +- sonoff/xdrv_14_mp3.ino | 10 +- sonoff/xdrv_15_pca9685.ino | 15 +- sonoff/xdrv_16_tuyadimmer.ino | 65 +- sonoff/xdrv_17_rcswitch.ino | 19 +- sonoff/xdrv_18_armtronix_dimmers.ino | 33 +- sonoff/xdrv_19_ps16dz_dimmer.ino | 46 +- sonoff/xdrv_99_debug.ino | 516 +++++ sonoff/xdrv_interface.ino | 46 +- sonoff/xdsp_01_lcd.ino | 32 +- sonoff/xdsp_02_ssd1306.ino | 11 +- sonoff/xdsp_03_matrix.ino | 30 +- sonoff/xdsp_04_ili9341.ino | 13 +- sonoff/xdsp_05_epaper_29.ino | 20 +- sonoff/xdsp_interface.ino | 21 +- sonoff/xnrg_01_hlw8012.ino | 129 +- sonoff/xnrg_02_cse7766.ino | 20 +- sonoff/xnrg_03_pzem004t.ino | 10 +- sonoff/xnrg_04_mcp39f501.ino | 189 +- sonoff/xnrg_05_pzem_ac.ino | 9 +- sonoff/xnrg_06_pzem_dc.ino | 9 +- sonoff/xnrg_interface.ino | 21 +- sonoff/xplg_wemohue.ino | 62 +- sonoff/xplg_ws2812.ino | 80 +- sonoff/xsns_01_counter.ino | 25 +- sonoff/xsns_02_analog.ino | 12 +- sonoff/xsns_04_snfsc.ino | 18 +- sonoff/xsns_05_ds18b20.ino | 24 +- sonoff/xsns_05_ds18x20.ino | 95 +- sonoff/xsns_05_ds18x20_legacy.ino | 32 +- sonoff/xsns_06_dht.ino | 35 +- sonoff/xsns_07_sht1x.ino | 24 +- sonoff/xsns_08_htu21.ino | 13 +- sonoff/xsns_09_bmp.ino | 27 +- sonoff/xsns_10_bh1750.ino | 17 +- sonoff/xsns_11_veml6070.ino | 27 +- sonoff/xsns_12_ads1115.ino | 106 +- sonoff/xsns_12_ads1115_i2cdev.ino | 19 +- sonoff/xsns_13_ina219.ino | 17 +- sonoff/xsns_14_sht3x.ino | 15 +- sonoff/xsns_15_mhz19.ino | 82 +- sonoff/xsns_16_tsl2561.ino | 21 +- sonoff/xsns_17_senseair.ino | 23 +- sonoff/xsns_18_pms5003.ino | 12 +- sonoff/xsns_19_mgs.ino | 13 +- sonoff/xsns_20_novasds.ino | 23 +- sonoff/xsns_21_sgp30.ino | 17 +- sonoff/xsns_22_sr04.ino | 12 +- sonoff/xsns_23_sdm120.ino | 11 +- sonoff/xsns_24_si1145.ino | 15 +- sonoff/xsns_25_sdm630.ino | 11 +- sonoff/xsns_26_lm75ad.ino | 13 +- sonoff/xsns_27_apds9960.ino | 39 +- sonoff/xsns_28_tm1638.ino | 34 +- sonoff/xsns_29_mcp230xx.ino | 38 +- sonoff/xsns_30_mpr121.ino | 34 +- sonoff/xsns_31_ccs811.ino | 14 +- sonoff/xsns_32_mpu6050.ino | 17 +- sonoff/xsns_33_ds3231.ino | 47 +- sonoff/xsns_34_hx711.ino | 81 +- sonoff/xsns_35_tx20.ino | 10 +- sonoff/xsns_36_mgc3130.ino | 20 +- sonoff/xsns_37_rfsensor.ino | 55 +- sonoff/xsns_38_az7798.ino | 14 +- sonoff/xsns_39_max31855.ino | 176 ++ sonoff/xsns_40_pn532.ino | 606 +++++ sonoff/xsns_41_max44009.ino | 179 ++ sonoff/xsns_42_scd30.ino | 494 +++++ sonoff/xsns_interface.ino | 26 +- sonoff/zzzz_debug.ino | 309 +++ tools/decode-config.html | 39 +- tools/decode-config.md | 42 +- tools/decode-config.py | 180 +- tools/decode-status.py | 99 +- tools/fw_server/fw-server.py | 22 +- 278 files changed, 16830 insertions(+), 7725 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 SUPPORT.md create mode 100644 TEMPLATE.md delete mode 100644 lib/ArduinoJson-5.11.2/ArduinoJson.h delete mode 100644 lib/ArduinoJson-5.11.2/README.md delete mode 100644 lib/ArduinoJson-5.11.2/examples/JsonHttpClient/JsonHttpClient.ino delete mode 100644 lib/ArduinoJson-5.11.2/examples/JsonServer/JsonServer.ino delete mode 100644 lib/ArduinoJson-5.11.2/examples/JsonUdpBeacon/JsonUdpBeacon.ino delete mode 100644 lib/ArduinoJson-5.11.2/library.properties delete mode 100644 lib/ArduinoJson-5.11.2/src/ArduinoJson.h delete mode 100644 lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ValueSetter.hpp delete mode 100644 lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/isInteger.hpp delete mode 100644 lib/ArduinoJson-5.11.2/src/ArduinoJson/RawJson.hpp delete mode 100644 lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsSignedIntegral.hpp delete mode 100644 lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp create mode 100644 lib/ArduinoJson-5.13.4/ArduinoJson.h rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/CHANGELOG.md (68%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/LICENSE.md (96%) create mode 100644 lib/ArduinoJson-5.13.4/README.md create mode 100644 lib/ArduinoJson-5.13.4/examples/JsonConfigFile/JsonConfigFile.ino rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/examples/JsonGeneratorExample/JsonGeneratorExample.ino (63%) create mode 100644 lib/ArduinoJson-5.13.4/examples/JsonHttpClient/JsonHttpClient.ino rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/examples/JsonParserExample/JsonParserExample.ino (61%) create mode 100644 lib/ArduinoJson-5.13.4/examples/JsonServer/JsonServer.ino create mode 100644 lib/ArduinoJson-5.13.4/examples/JsonUdpBeacon/JsonUdpBeacon.ino rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/examples/ProgmemExample/ProgmemExample.ino (52%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/examples/StringExample/StringExample.ino (67%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/keywords.txt (100%) create mode 100644 lib/ArduinoJson-5.13.4/library.properties create mode 100644 lib/ArduinoJson-5.13.4/src/ArduinoJson.h rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson.hpp (75%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Configuration.hpp (94%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/Encoding.hpp (80%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/JsonBufferAllocated.hpp (68%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/JsonFloat.hpp (56%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/JsonInteger.hpp (70%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/JsonVariantAs.hpp (80%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/JsonVariantContent.hpp (79%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/JsonVariantDefault.hpp (68%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/JsonVariantType.hpp (84%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/List.hpp (93%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/ListConstIterator.hpp (85%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/ListIterator.hpp (86%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/ListNode.hpp (70%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/NonCopyable.hpp (67%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Data/ReferenceType.hpp (74%) create mode 100644 lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ValueSaver.hpp rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Deserialization/Comments.hpp (88%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Deserialization/JsonParser.hpp (77%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Deserialization/JsonParserImpl.hpp (85%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Deserialization/StringWriter.hpp (79%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/DynamicJsonBuffer.hpp (94%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonArray.hpp (82%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonArrayImpl.hpp (75%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonArraySubscript.hpp (69%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonBuffer.hpp (74%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonBufferBase.hpp (88%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonBufferImpl.hpp (72%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonObject.hpp (57%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonObjectImpl.hpp (79%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonObjectSubscript.hpp (66%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonPair.hpp (53%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonVariant.hpp (72%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonVariantBase.hpp (59%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonVariantCasts.hpp (89%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonVariantComparisons.hpp (75%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonVariantImpl.hpp (87%) create mode 100644 lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantOr.hpp rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/JsonVariantSubscripts.hpp (70%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Polyfills/attributes.hpp (74%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Polyfills/ctype.hpp (50%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Polyfills/isFloat.hpp (75%) create mode 100644 lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/isInteger.hpp rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Polyfills/math.hpp (52%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Polyfills/parseFloat.hpp (89%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Polyfills/parseInteger.hpp (75%) create mode 100644 lib/ArduinoJson-5.13.4/src/ArduinoJson/RawJson.hpp rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/DummyPrint.hpp (64%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp (80%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/FloatParts.hpp (91%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/IndentedPrint.hpp (89%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/JsonPrintable.hpp (80%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/JsonSerializer.hpp (79%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/JsonSerializerImpl.hpp (94%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/JsonWriter.hpp (91%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/Prettyfier.hpp (93%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/StaticStringBuilder.hpp (77%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/Serialization/StreamPrintAdapter.hpp (77%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/StaticJsonBuffer.hpp (89%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/StringTraits/ArduinoStream.hpp (64%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/StringTraits/CharPointer.hpp (54%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/StringTraits/FlashString.hpp (64%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/StringTraits/StdStream.hpp (63%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/StringTraits/StdString.hpp (70%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/StringTraits/StringTraits.hpp (55%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/EnableIf.hpp (58%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/FloatTraits.hpp (68%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/IsArray.hpp (67%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/IsBaseOf.hpp (73%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/IsChar.hpp (69%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/IsConst.hpp (61%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/IsFloatingPoint.hpp (60%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/IsIntegral.hpp (50%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/IsSame.hpp (62%) create mode 100644 lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsSignedIntegral.hpp create mode 100644 lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/IsVariant.hpp (50%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/RemoveConst.hpp (59%) rename lib/{ArduinoJson-5.11.2 => ArduinoJson-5.13.4}/src/ArduinoJson/TypeTraits/RemoveReference.hpp (60%) create mode 100644 lib/ArduinoJson-5.13.4/src/ArduinoJson/version.hpp create mode 100644 lib/FrogmoreScd30/FrogmoreScd30.cpp create mode 100644 lib/FrogmoreScd30/FrogmoreScd30.h create mode 100644 lib/LinkedList-1.2.3/LICENSE.txt create mode 100644 lib/LinkedList-1.2.3/LinkedList.h create mode 100644 lib/LinkedList-1.2.3/README.md create mode 100644 lib/LinkedList-1.2.3/examples/ClassList/ClassList.pde create mode 100644 lib/LinkedList-1.2.3/examples/SimpleIntegerList/SimpleIntegerList.pde create mode 100644 lib/LinkedList-1.2.3/keywords.txt create mode 100644 lib/LinkedList-1.2.3/library.json create mode 100644 lib/LinkedList-1.2.3/library.properties rename lib/{TasmotaSerial-2.2.0 => TasmotaSerial-2.3.0}/README.md (100%) rename lib/{TasmotaSerial-2.2.0 => TasmotaSerial-2.3.0}/examples/swsertest/swsertest.ino (100%) rename lib/{TasmotaSerial-2.2.0 => TasmotaSerial-2.3.0}/keywords.txt (95%) rename lib/{TasmotaSerial-2.2.0 => TasmotaSerial-2.3.0}/library.json (94%) rename lib/{TasmotaSerial-2.2.0 => TasmotaSerial-2.3.0}/library.properties (94%) rename lib/{TasmotaSerial-2.2.0 => TasmotaSerial-2.3.0}/src/TasmotaSerial.cpp (97%) rename lib/{TasmotaSerial-2.2.0 => TasmotaSerial-2.3.0}/src/TasmotaSerial.h (96%) create mode 100644 sonoff/Parsing.cpp create mode 100644 sonoff/language/ko-KO.h create mode 100644 sonoff/support_button.ino create mode 100644 sonoff/support_rotary.ino create mode 100644 sonoff/support_switch.ino create mode 100644 sonoff/xdrv_99_debug.ino create mode 100644 sonoff/xsns_39_max31855.ino create mode 100644 sonoff/xsns_40_pn532.ino create mode 100644 sonoff/xsns_41_max44009.ino create mode 100644 sonoff/xsns_42_scd30.ino create mode 100644 sonoff/zzzz_debug.ino diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 2616af48f..a0ab5e7e3 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -4,31 +4,61 @@ about: Create a report to help us improve --- -**Describe the bug** + + + + + + + + + + + +### BUG DESCRIPTION _A clear and concise description of what the bug is._ -_Also, make sure these boxes are checked [x] before submitting your issue - Thank you!_ -- [ ] _Searched the problem in issues and in the wiki_ -- [ ] _Hardware used_ : -- [ ] _Provide the output of command_``status 0`` : +### REQUESTED INFORMATION +_Make sure these boxes are checked before submitting your issue. Thank you_ + +**FAILURE TO COMPLETE THE REQUESTED INFORMATION WILL RESULT IN YOUR ISSUE BEING CLOSED** + +- [ ] Read the [Contributing Guide and Policy](https://github.com/arendst/Sonoff-Tasmota/blob/development/CONTRIBUTING.md) and [the Code of Conduct](https://github.com/arendst/Sonoff-Tasmota/blob/development/CODE_OF_CONDUCT.md) +- [ ] Searched the problem in issues (https://github.com/arendst/Sonoff-Tasmota/issues) +- [ ] Searched the problem in the wiki (https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting) +- [ ] Searched the problem in the forum (https://groups.google.com/d/forum/sonoffusers) +- [ ] Searched the problem in the chat (https://discord.gg/Ks2Kzd4) +- [ ] Device used (i.e. Sonoff Basic) : _____ +- [ ] Tasmota binary firmware version number used : ____ / (pre-compiled or self-compiled ?) +- [ ] Development IDE - Compiler / Upload tools used : ____ / ____ +- [ ] Provide the output of command ``status 0`` : ``` -STATUS 0 OUTPUT HERE +STATUS 0 OUTPUT HERE: + + +``` +- [ ] Provide the output of console when you experience your issue if apply : +_(Please use_ ``weblog 4`` _for more debug information)_ +``` +CONSOLE OUTPUT HERE: + + ``` -**To Reproduce** +### TO REPRODUCE _Steps to reproduce the behavior:_ -**Expected behavior** +### EXPECTED BEHAVIOUR _A clear and concise description of what you expected to happen._ -**Screenshots** +### SCREENSHOTS _If applicable, add screenshots to help explain your problem._ -**Additional context** +### ADDITIONAL CONTEXT _Add any other context about the problem here._ diff --git a/.github/ISSUE_TEMPLATE/Custom.md b/.github/ISSUE_TEMPLATE/Custom.md index 159549128..44bd847cb 100644 --- a/.github/ISSUE_TEMPLATE/Custom.md +++ b/.github/ISSUE_TEMPLATE/Custom.md @@ -4,16 +4,47 @@ about: Users Troubleshooting Help --- -Make sure these boxes are checked [x] before submitting your issue - Thank you! + + + + + + + + + + + + +### ISSUE DESCRIPTION - TROUBLESHOOTING +_A clear description of what the issue is and be as extensive as possible_ + + +### REQUESTED INFORMATION +_Make sure these boxes are checked before submitting your issue. Thank you_ + +**FAILURE TO COMPLETE THE REQUESTED INFORMATION WILL RESULT IN YOUR ISSUE BEING CLOSED** + +- [ ] Read the [Contributing Guide and Policy](https://github.com/arendst/Sonoff-Tasmota/blob/development/CONTRIBUTING.md) and [the Code of Conduct](https://github.com/arendst/Sonoff-Tasmota/blob/development/CODE_OF_CONDUCT.md) - [ ] Searched the problem in issues (https://github.com/arendst/Sonoff-Tasmota/issues) - [ ] Searched the problem in the wiki (https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting) - [ ] Searched the problem in the forum (https://groups.google.com/d/forum/sonoffusers) - [ ] Searched the problem in the chat (https://discord.gg/Ks2Kzd4) -- [ ] Hardware used : +- [ ] Device used (i.e. Sonoff Basic) : _____ +- [ ] Tasmota binary firmware version number used : ____ / (pre-compiled or self-compiled ?) +- [ ] Development IDE - Compiler / Upload tools used : ____ / ____ - [ ] Provide the output of command ``status 0`` : ``` -STATUS 0 OUTPUT HERE -``` +STATUS 0 OUTPUT HERE: + +``` +- [ ] Provide the output of console when you experience your issue if apply : +_(Please use_ ``weblog 4`` _for more debug information)_ +``` +CONSOLE OUTPUT HERE: + + +``` **(Please, remember to close the issue when the problem has been addressed)** diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..aea7cd816 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,10 @@ +## Description: + +**Related issue (if applicable):** fixes # + +## 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) + - [ ] 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** diff --git a/.github/stale.yml b/.github/stale.yml index 88c5f7c21..484010321 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,9 +1,9 @@ # Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 45 +daysUntilStale: 25 # Number of days of inactivity before a stale Issue or Pull Request is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 15 +daysUntilClose: 5 # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable exemptLabels: @@ -37,4 +37,4 @@ closeComment: > limitPerRun: 30 # Limit to only `issues` or `pulls` -only: issues +#only: issues diff --git a/API.md b/API.md index 23e45369d..caec908c6 100644 --- a/API.md +++ b/API.md @@ -23,6 +23,8 @@ FUNC_JSON_APPEND | | | | x | | Extend tele FUNC_WEB_APPEND | | | | x | | Extend webgui ajax info FUNC_SAVE_BEFORE_RESTART | | | | x | | Just before a planned restart FUNC_COMMAND | x | | x | x | | When a command is not recognized +FUNC_COMMAND_DRIVER | x | 6.4.1.21 | x | | | When command Driver\ is executed +FUNC_COMMAND_SENSOR | x | 6.4.1.21 | | x | | When command Sensor\ is executed FUNC_MQTT_SUBSCRIBE | | 5.12.0k | x | | | At end of MQTT subscriptions FUNC_MQTT_INIT | | 5.12.0k | x | | | Once at end of MQTT connection FUNC_MQTT_DATA | x | 5.12.0k | x | | | Before decoding command diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..1408ce048 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at https://sidweb.nl/cms3/en/contact. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..7cfcdfadb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,63 @@ +# Contributing to Sonoff-Tasmota + +**Any contribution helps our team and makes Tasmota better for the entire community!** + +Everybody is welcome and invited to contribute to Sonoff-Tasmota Project by: + +* Testing newly released features and reporting issues. +* Providing Pull Requests (Features, Proof of Concepts, Language files or Fixes) +* Contributing missing documentation for features and devices on our [Wiki](https://github.com/arendst/Sonoff-Tasmota/wiki/Contributing) + +This document describes rules that are in effect for this repository, meant for handling issues by contributors in the issue tracker and PRs. + +## Opening New Issues + +**Issue tracker is NOT a general discussion forum!** +1. Opening an issue means that a problem exists in the code and should be addressed by the project contributors. +2. When opening an issue, it is required to fill out the presented template. The requested information is important! If the template is ignored or insufficient info about the issue is provided, the issue may be closed. +3. Questions of type "How do I..." or "Can you please help me with..." or "Can Tasmota do..." WILL NOT be handled here. Such questions should be directed at a discussion forum or to the Tasmota Support Chat. All issues of this type will be closed with a simple reference to this contributing policy. +4. Issues about topics already handled in the documentation will be closed in a similar manner. +5. Issues for unmerged PRs will be closed. If there is an issue with a PR, the explanation should be added to the PR itself. +6. Issues with accompanied investigation that shows the root of the problem should be given priority. +7. Duplicate issues will be closed. + +## Triaging of Issues/PR's + +1. Any contributor to the project can participate in the triaging process, if he/she chooses to do so. +2. An issue that needs to be closed, either due to not complying with this policy, or for other reasons, should be closed by a contributor. +3. Issues that are accepted should be marked with appropriate labels. +4. Issues that could impact functionality for many users should be considered severe. +5. Issues caused by the SDK or chip should not be marked severe, as there usually isn’t much to be done. Common sense should be applied when deciding. Such issues should be documented in the Wiki, for reference by users. +6. Issues with feature requests should be discussed for viability/desirability. +7. Feature requests or changes that are meant to address a very specific/limited use case, especially if at the expense of increased code complexity, may be denied, or may be required to be redesigned, generalized, or simplified. +8. Feature requests that are not accompanied by a PR: + * could be closed immediately (denied). + * could be closed after some predetermined period of time (left as candidate for somebody to pick up). +9. In some cases, feedback may be requested from the issue reporter, either as additional info for clarification, additional testing, or other. If no feedback is provided, the issue may be closed by a contributor or after 30 days by the STALE bot. + +## Pull requests + +A Pull Request (PR) is the process where code modifications are managed in GitHub. + +The process is straight-forward. + + - Read [How to get faster PR reviews](https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#best-practices-for-faster-reviews) by Kubernetes (but skip step 0) + - Fork the Sonoff-Tasmota Repository [git repository](https://github.com/arendst/Sonoff-Tasmota). + - Write/Change the code in your Fork for a new feature, bug fix, new sensor, optimization, etc. + - Ensure tests work. + - Create a Pull Request against the [**dev**](https://github.com/arendst/Sonoff-Tasmota/tree/dev) branch of Sonoff-Tasmota. + +1. All pull requests must be done against the dev branch. +2. Only relevant files should be touched (Also beware if your editor has auto-formatting feature enabled). +3. Only one feature/fix should be added per PR. +4. If adding a new functionality (new hardware, new library support) not related to an existing component move it to it's own modules (.ino file). +5. PRs that don't compile (break Travis) or cause coding errors will not be merged. Please fix the issue. Same goes for PRs that are raised against older commit in dev - you might need to rebase and resolve conflicts. +6. All pull requests should undergo peer review by at least one contributor other than the creator, excepts for the owner. +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. + + + + diff --git a/README.md b/README.md index a59f0b69c..b2cf7500c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Sonoff-Tasmota -Alternative firmware for _ESP8266 based devices_ like [iTead](https://www.itead.cc/) _**Sonoff**_ with **web**, **timers**, 'Over The Air' (**OTA**) firmware updates and **sensors support**, allowing control under **Serial**, **HTTP**, **MQTT** and **KNX**, so as to be used on **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, 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. [![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) @@ -24,6 +24,9 @@ A Sonoff device is not a toy. It uses Mains AC so there is a danger of electrocu 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.. + ### 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. @@ -101,6 +104,7 @@ You can contribute to Sonoff-Tasmota by - providing Pull Requests (Features, Proof of Concepts, Language files or Fixes) - testing new released features and report issues - donating to acquire hardware for testing and implementing or out of gratitude +- contributing missing documentation for features and devices on our [Wiki](https://github.com/arendst/Sonoff-Tasmota/wiki) [![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/tasmota) @@ -121,9 +125,11 @@ Libraries used with Sonoff-Tasmota are: - [C2 Programmer](http://app.cear.ufpb.br/~lucas.hartmann/tag/efm8bb1/) - [esp-epaper-29-ws-20171230-gemu](https://github.com/gemu2015/Sonoff-Tasmota/tree/displays/lib) - [esp-knx-ip](https://github.com/envy/esp-knx-ip) +- FrogmoreScd30 - [I2Cdevlib](https://github.com/jrowberg/i2cdevlib) - [IRremoteEsp8266](https://github.com/markszabo/IRremoteESP8266) - [JobaTsl2561](https://github.com/joba-1/Joba_Tsl2561) +- [LinkedList](https://github.com/ivanseidel/LinkedList) - [Liquid Cristal](https://github.com/marcoschwartz/LiquidCrystal_I2C) - [MultiChannelGasSensor](http://wiki.seeedstudio.com/Grove-Multichannel_Gas_Sensor/) - [NeoPixelBus](https://github.com/Makuna/NeoPixelBus) @@ -157,7 +163,8 @@ People helping to keep the show on the road: - Andre Thomas for providing [thehackbox](http://thehackbox.org/tasmota/) OTA support and daily development builds - Joel Stein and digiblur for their Tuya research and driver - Frogmore42 and Jason2866 for providing many issue answers -- Many more providing Tips, Pocs or PRs +- Blakadder for editing the wiki and providing template management +- Many more providing Tips, Wips, Pocs or PRs ### License diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1198a6165..b33fd51f9 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -82,6 +82,15 @@ Module | Description 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 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 +63 Digoo DG-SP202 | Digoo DG-SP202 Dual Wifi Smart Switch with Energy Monitoring +64 KA10 | Smanergy KA10 Wifi Smart Wall Switch with Energy Monitoring +65 Luminea ZX2820 | Luminea ZX2820 Wifi Smart Switch with Energy Monitoring +66 Mi Desk Lamp | Mi Desk Lamp with rotary switch and Wifi +67 SP10 | Tuya SP10 Wifi Smart Switch with Energy Monitoring +68 WAGA CHCZ02MB | WAGA life CHCZ02MB Wifi Smart Switch with Energy Monitoring +69 SYF05 | Sunyesmart SYF05 RGBWW Wifi Led Bulb ## Provided Binary Downloads The following binary downloads have been compiled with ESP8266/Arduino library core version **2.4.2** patched with the Alexa fix. @@ -98,9 +107,6 @@ The following binary downloads have been compiled with ESP8266/Arduino library c | Feature or Sensor | minimal | basic | classic | sonoff | knx | sensors | Remarks |--------------------------------|---------|-------|---------|--------|------|---------|-------- -| ESP/Arduino lib v2.3.0 | 346k | 429k | 482k | 504k | 522k | 535k | -| ESP/Arduino lib v2.4.2 | 366k | 446k | 496k | 522k | 538k | 551k | No wifi sleep -| | | | | | | | | MY_LANGUAGE en-GB | x | x | x | x | x | x | | MQTT_LIBRARY_TYPE PUBSUBCLIENT | x | x | x | x | x | x | | USE_WPS | - | - | x | - | - | - | WPS @@ -150,6 +156,8 @@ The following binary downloads have been compiled with ESP8266/Arduino library c | USE_MPU6050 | - | - | - | - | - | - | | USE_DS3231 | - | - | - | - | - | - | | USE_MGC3130 | - | - | - | - | - | - | +| USE_MAX44009 | - | - | - | - | - | - | +| USE_SCD30 | - | - | - | - | - | - | | | | | | | | | | Feature or Sensor | minimal | basic | classic | sonoff | knx | sensors | | USE_SPI | - | - | - | - | - | - | @@ -169,6 +177,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c | USE_ARMTRONIX_DIMMERS | - | x | - | x | x | x | | USE_PS_16_DZ | - | x | - | x | x | x | | USE_AZ7798 | - | - | - | - | - | - | +| USE_PN532_HSU | - | - | - | - | - | - | | USE_IR_REMOTE | - | - | - | x | x | x | | USE_IR_HVAC | - | - | - | - | - | x | | USE_IR_RECEIVE | - | - | - | x | x | x | @@ -182,80 +191,10 @@ The following binary downloads have been compiled with ESP8266/Arduino library c | USE_TX20_WIND_SENSOR | - | - | - | x | x | x | | USE_RC_SWITCH | - | - | - | x | x | x | | USE_RF_SENSOR | - | - | - | - | - | x | AlectoV2 only +| USE_SM16716 | - | x | x | x | x | x | | USE_DISPLAY | - | - | - | - | - | - | ## Changelog -Version 6.4.1 20181225 - * Change RAM usage BMP/BME I2C sensors - * Change FallbackTopic from cmnd/\/ to cmnd/\_fb/ to discriminate from Topic (#1528) - * Change FallbackTopic detection (#4706) - * Change Hass discovery to short MQTT messages as used by Hass 0.81 and up (#4711) - * Change MQTT GUI password handling (#4723) - * Fix possible dtostrf buffer overflows by increasing buffers - * Fix wifi strongest signal detection (#4704) - * Fix Alexa "this value is outside the range of the device". Needs power cycle and Alexa deletion/discovery cycle. (#3159, #4712) - * Add Slovak language file (#4663) - * Add support for AZ-Instrument 7798 CO2 meter/datalogger (#4672) - * Add define WIFI_SOFT_AP_CHANNEL in my_user_config.h to set Soft Access Point Channel number between 1 and 13 as used by Wifi Manager web GUI (#4673) - * Add define USE_MQTT_TLS_CA_CERT for checking MQTT TLS against root ca using Let's Encrypt cert from sonoff_letsencrypt.h - not supported with core 2.3.0 (#4703) +Version 6.5.0 20190315 -Version 6.4.0 20181217 - * Change GUI Configure Module by using AJAX for data fetch to cut page size (and memory use) by 40%. - In case of web page errors clear your browser cache or do Page Reload (F5 or Ctrl+R) - * Change enforcing flashmode dout but it is still mandatory - * Change bootcount update (being first) flash write to 10 seconds after restart - * Change display and epaper drivers - * Change command WebSend Host header field from IP address to hostname (#4331) - * Change log buffer size from 512 to 520 to accommodate http sensor data (#4354) - * Change default WIFI_CONFIG_TOOL from WIFI_WAIT to WIFI_RETRY in my_user_config.h (#4400) - * Change webgui refresh time delay for Save Settings and local OTA Upload (#4423) - * Change SR-04 driver to use NewPing library (#4488) - * Change MCP230xx driver to support interrupt retention over teleperiod (#4547) - * Change support for MPU6050 using DMP (#4581) - * Fix unintended function overload of WifiState - * Fix wifi connection errors using wifi disconnect and ESP.reset instead of ESP.restart - * Fix Sonoff Pow R2 and Sonoff S31 Serial interface hang caused by Sonoff Basic R2 driver delay implementation (and possibly core bug) - * Fix MQTT connection error after restart - * Fix wifi re-scan connection baseline - * Fix possible strncat buffer overflows - * Fix intermittent Pzem sensor energy overflow calculation error - * Fix shelly2 ghost switching caused by lack of pull-up inputs (#4255) - * Fix hardware serial pin configuration. To keep using hardware serial swap current Rx/Tx pin configuration only (#4280) - * Fix MqttRetry values above 255 seconds (#4424) - * Fix WifiManager functionality on initial installation (#4433) - * Fix ArduinoOTA for Core 2.5.0 (#4620) - * Add minutes to commands Timezone to allow all possible world timezones - * Add more strict checks for GPIO selections - * Add code image and optional commit number to version - * Add dynamic delay to main loop providing time for wifi background tasks - * Add additional start-up delay during initial wifi connection - * Add support for decoding Theo V2 sensors as documented on https://sidweb.nl using 434MHz RF sensor receiver - * Add support for decoding Alecto V2 sensors like ACH2010, WS3000 and DKW2012 weather stations using 868MHz RF sensor receiver - * Add user definition of defines WIFI_RSSI_THRESHOLD (default 10) and WIFI_RESCAN_MINUTES (default 44) - * Add command SetOption58 0/1 to enable IR raw data info in JSON message (#2116) - * Add command IRSend \|0,\,\,.. to allow raw data transmission (#2116) - * Add command SetOption56 0/1 to enable wifi network scan and select highest RSSI (#3173) - * Add command SetOption57 0/1 to enable wifi network re-scan every 44 minutes with a rssi threshold of 10 to select highest RSSI (#3173) - * Add support for SDM220 (#3610) - * Add default sleep 1 to sonoff-basic to lower energy consumption (#4217) - * Add wifi status to Tuya (#4221) - * Add delays to reduce CPU usage at boot time (#4233) - * Add command SetOption24 0/1 to select pressure unit as hPa or mmHg (#4241) - * Add optional hardware serial when GPIO13(Rx) and GPIO15(Tx) are selected removing hardware serial from GPIO01(Tx) and GPIO03(Rx) (#4288) - * Add support for Gosund SP1 v2.3 Power Socket with Energy Monitoring (#4297) - * Add support for Armtronix dimmers. See wiki for info (#4321) - * Add to command WebSend option to send a direct path when command starts with a slash (#4329) - * Add support for LG HVac and IrRemote (#4377) - * Add initial support for Hass sensor discovery (#4380) - * Add support for Fujitsu HVac and IrRemote (#4387) - * Add support for I2C MGC3130 Electric Field Effect sensor by Christian Baars (#3774, #4404) - * Add command CalcRes to set number of decimals (0 - 7) used in commands ADD, SUB, MULT and SCALE (#4420) - * Add CPU average load to state message (#4431) - * Add command SetOption59 0/1 to change state topic from tele/STATE to stat/RESULT (#4450) - * Add support for SM Smart Wifi Dimmer PS-16-DZ (#4465) - * Add support for Teckin US Power Socket with Energy Monitoring (#4481) - * Add command SetOption60 0/1 to select dynamic sleep (0) or sleep (1) (#4497) - * Add support for iFan02 Fanspeed in Domoticz using a selector (#4517) - * Add support for GPIO02 for newer Sonoff Basic (#4518) - * Add Announce Switches to MQTT Discovery (#4531) - * Add support for Manzoku Power Strip (#4590) + * Tbd diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 000000000..46fa03ebc --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,22 @@ +# Sonoff-Tasmota Support + +If you're looking for support on **Sonoff-Tasmota** there are some options available: + +### Documentation: + +* [Wiki Pages](https://github.com/arendst/Sonoff-Tasmota/wiki): For information on how to Flash Tasmota, configure and use it. +* [Troubleshooting Information](https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting): For information on common problems and solutions. +* [Commands Information](https://github.com/arendst/Sonoff-Tasmota/wiki/Commands): For information on all the commands supported by Tasmota. + +### Support's Community: + +* [Tasmota Forum](https://groups.google.com/d/forum/sonoffusers): For usage and discussions. +* [Tasmota Support Chat](https://discord.gg/Ks2Kzd4): For support, troubleshooting and general questions. You have better chances to get fast answers from members of the Tasmota Community. +* [Search in Issues](https://github.com/arendst/Sonoff-Tasmota/issues): You might find an answer to your question by searching current or closed issues. + +### Developers' Community: + +* [Bug Report](https://github.com/arendst/Sonoff-Tasmota/issues/new?template=Bug_report.md): For reporting Bugs of Tasmota Software. +* [Feature Request](https://github.com/arendst/Sonoff-Tasmota/issues/new?template=Feature_request.md): For requesting features/functions to Tasmota Software. +* [Troubleshooting](https://github.com/arendst/Sonoff-Tasmota/issues/new?template=Custom.md): As a last resort, you can open new *Troubleshooting* issue on GitHub if the solution could not be found using the other channels. Just remember: the more info you provide the more chances you'll have to get an accurate answer. +* [Issue a question](https://github.com/arendst/Sonoff-Tasmota/issues/new/choose): As a last resort, you can open new *Question* issue on GitHub if the answer could not be found using the other channels. Just remember: the more info you provide the more chances you'll have to get an accurate answer. diff --git a/TEMPLATE.md b/TEMPLATE.md new file mode 100644 index 000000000..67431f651 --- /dev/null +++ b/TEMPLATE.md @@ -0,0 +1,86 @@ +## Sonoff-Tasmota template information +Sonoff-Tasmota uses Device or Module information to control peripherals connected to GPIOs. This information is stored in the ``sonoff_template.h`` file as a device specific template. The template contains information about what GPIO should be connected to what peripheral and what GPIO may be configured online using the ``GPIO`` command or GUI Configure Module menu. In addition a device may need specific coding to process the data from these peripherals. The module number as provided by the ``Modules`` command is used to select this coding. + +Starting with version 6.4.1.16 Sonoff-Tasmota Modules can be extended by users online using a template. To provide easy processing by Sonoff-Tasmota a user template is written as JSON text and could look like this: + +{"NAME":"UserModule1","GPIO":[17,148,29,149,7,255,255,255,138,255,139,255,255],"FLAG":0,"BASE":18} + +The four properties with UPPERCASE property names have the following functionality: + +Property name | Property value description +--------------|------------------------------------------------------------------------------------------------------------------- +NAME | Up to 14 characters for the Module name +GPIO | Up to 13 decimal numbers from 0 to 255 representing GPIO0 to GPIO5, GPIO09, GPIO10 and GPIO12 to GPIO16 +FLAG | 8 bit mask flag register +BASE | Module number of a hard-coded device to be used when device specific functionality is needed + +The above example, based on the Generic Module does not allow ADC0 input. + +## GPIO functionality +The GPIO functionality numbers are the same is shown by command ``GPIOs``. In addition code 255 is added to select a GPIO as user configurable via the GUI Configure Module menu. + +## FLAG functionality +The FLAG value is an 8-bit mask where each bit controls a features. Add FLAG values to set multiple bits. + +FLAG | Mask | Feature description +-----|----------|------------------------------ + 1 | xxxxxxx1 | Allowing to use Analog0 (ADC0) as input if define USE_ADC_VCC in ``my_user_config.h`` is disabled + 2 | xxxxxx1x | Enable GUI pull-up control message + 4 | xxxxx1xx | Not used + 8 | xxxx1xxx | Not used + 16 | xxx1xxxx | Not used + 32 | xx1xxxxx | Not used + 64 | x1xxxxxx | Not used + 128 | 1xxxxxxx | Not used + +## BASE functionality +The following table lists hard-coded device specific functionality. Notice that not all device modules need special handling. + +BASE | Module | Description +-----|----------------|---------------------------------------------- + 4 | Sonoff Dual | Process relay and button via hardware serial interface using GPIO01 and GPIO03. Change baudrate to 19200 bps. Process buttons as single press only + 9 | Sonoff Touch | Invert ledstate 1 functionality + 10 | Sonoff LED | Set light type to 2 PWM channels disregarding SetOption15. Fix device specific LED instabilities by disabling GPIO04, GPIO5 and GPIO14 + 12 | 4 Channel | See 4 + 13 | Motor C/AC | Force all relays ON at Power On and disable command ``PowerOnState`` + 15 | EXS Relay(s) | Enable pulse latching using even/odd numbered relay pairs + 18 | Generic | Show Wemos specific pin information in GUI + 19 | H801 | Change hardware UART Tx from GPIO01 to GPIO02 + 20 | Sonoff SC | Enable and Process data via hardware serial interface using GPIO01 and GPIO03. Change baudrate to 19200 bps + 21 | Sonoff BN-SZ | Set light type to 1 PWM channel disregarding SetOption15 + 22 | Sonoff 4CH Pro | Button handling disregarding SetOption13 only allowing single press to enable RF learning while holding the button + 24 | Sonoff Bridge | Enable and Process data via hardware serial interface using GPIO01 and GPIO03. Change baudrate to 19200 bps. Process 16 buttons in web GUI. Enable EFM8BB1 firmware upload + 25 | Sonoff B1 | Set light type to RGBWC using MY92x1 + 26 | AiLight | Set light type to RGBW using MY92x1 + 27 | Sonoff T1 1CH | See 9 + 28 | Sonoff T1 2CH | See 9 + 29 | Sonoff T1 3CH | See 9 + 38 | Sonoff Dual R2 | Process buttons as single press only + 43 | Sonoff iFan02 | Enable command ``Fanspeed``. Disable Interlock and PulseTime. Tune status information, MQTT data and GUI. Sync with microcontroller. Process Domoticz Fan state + 47 | Xiaomi Philips | Process Color Temperature using PWM2 and Intensity using PWM1 + 53 | Tuya Dimmer | Enable and Process data via software or hardware serial interface using GPIO 148 and 149 or forced GPIO01 and GPIO03. Change baudrate to 9600 bps. Process all Buttons + 55 | ARMTR Dimmer | Enable and Process data via software or hardware serial interface using GPIO 148 and 149. Change baudrate to 115200 bps. + 57 | PS-16-DZ | Enable and Process data via software or hardware serial interface using GPIO 148 and 149. Change baudrate to 19200 bps. + 61 | YTF IR Bridge | Disable serial interface to stop loopback + 65 | Mi Desk Lamp | Process rotary and Button1 data specific to this device + +## Usage +A user provided template can be stored in Sonoff-Tasmota using the ``Template`` command. It has the following options. + +Command | Payload | Description +---------|----------|--------------------------------------- +Template | | Show current user template +Template | 0 | Copy active module template to user template +Template | 1 .. 69 | Copy hard-coded module template to user template + +The following command will store a complete template based on the Generic module +``Template {"NAME":"UserModule1","GPIO":[17,148,29,149,7,255,255,255,138,255,139,255,255],"FLAG":0,"BASE":18}`` + +The following command will update the name of a stored template +``Template {"NAME":"UserModule2"}`` + +The following command will update the flag of a stored template +``Template {"FLAG":1}`` + +The following command will update the base of a stored template to Generic +``Template {"BASE":0}`` \ No newline at end of file diff --git a/arduino/version 2.5.0/boards.txt b/arduino/version 2.5.0/boards.txt index 2334302b8..300a608c4 100644 --- a/arduino/version 2.5.0/boards.txt +++ b/arduino/version 2.5.0/boards.txt @@ -54,12 +54,12 @@ generic.menu.vt.heap=Heap generic.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM generic.menu.vt.iram=IRAM generic.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -generic.menu.exception.enabled=Enabled -generic.menu.exception.enabled.build.exception_flags=-fexceptions -generic.menu.exception.enabled.build.stdcpp_lib=-lstdc++ generic.menu.exception.disabled=Disabled generic.menu.exception.disabled.build.exception_flags=-fno-exceptions -generic.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +generic.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +generic.menu.exception.enabled=Enabled +generic.menu.exception.enabled.build.exception_flags=-fexceptions +generic.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc generic.menu.ResetMethod.ck=ck generic.menu.ResetMethod.ck.upload.resetmethod=ck generic.menu.ResetMethod.nodemcu=nodemcu @@ -75,14 +75,18 @@ generic.menu.FlashFreq.40=40MHz generic.menu.FlashFreq.40.build.flash_freq=40 generic.menu.FlashFreq.80=80MHz generic.menu.FlashFreq.80.build.flash_freq=80 -generic.menu.FlashMode.qio=QIO -generic.menu.FlashMode.qio.build.flash_mode=qio -generic.menu.FlashMode.qout=QOUT -generic.menu.FlashMode.qout.build.flash_mode=qout +generic.menu.FlashMode.dout=DOUT (compatible) +generic.menu.FlashMode.dout.build.flash_mode=dout +generic.menu.FlashMode.dout.build.flash_flags=-DFLASHMODE_DOUT generic.menu.FlashMode.dio=DIO generic.menu.FlashMode.dio.build.flash_mode=dio -generic.menu.FlashMode.dout=DOUT -generic.menu.FlashMode.dout.build.flash_mode=dout +generic.menu.FlashMode.dio.build.flash_flags=-DFLASHMODE_DIO +generic.menu.FlashMode.qout=QOUT +generic.menu.FlashMode.qout.build.flash_mode=qout +generic.menu.FlashMode.qout.build.flash_flags=-DFLASHMODE_QOUT +generic.menu.FlashMode.qio=QIO (fast) +generic.menu.FlashMode.qio.build.flash_mode=qio +generic.menu.FlashMode.qio.build.flash_flags=-DFLASHMODE_QIO generic.menu.eesz.512K=512K (no SPIFFS) generic.menu.eesz.512K.build.flash_size=512K generic.menu.eesz.512K.build.flash_size_bytes=0x80000 @@ -490,12 +494,12 @@ esp8285.menu.vt.heap=Heap esp8285.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM esp8285.menu.vt.iram=IRAM esp8285.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -esp8285.menu.exception.enabled=Enabled -esp8285.menu.exception.enabled.build.exception_flags=-fexceptions -esp8285.menu.exception.enabled.build.stdcpp_lib=-lstdc++ esp8285.menu.exception.disabled=Disabled esp8285.menu.exception.disabled.build.exception_flags=-fno-exceptions -esp8285.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +esp8285.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +esp8285.menu.exception.enabled=Enabled +esp8285.menu.exception.enabled.build.exception_flags=-fexceptions +esp8285.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc esp8285.menu.ResetMethod.ck=ck esp8285.menu.ResetMethod.ck.upload.resetmethod=ck esp8285.menu.ResetMethod.nodemcu=nodemcu @@ -508,6 +512,7 @@ esp8285.menu.CrystalFreq.26=26 MHz esp8285.menu.CrystalFreq.40=40 MHz esp8285.menu.CrystalFreq.40.build.extra_flags=-DF_CRYSTAL=40000000 -DESP8266 esp8285.build.flash_mode=dout +esp8285.build.flash_flags=-DFLASHMODE_DOUT esp8285.build.flash_freq=40 esp8285.menu.eesz.1M=1M (no SPIFFS) esp8285.menu.eesz.1M.build.flash_size=1M @@ -764,13 +769,14 @@ espduino.menu.vt.heap=Heap espduino.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM espduino.menu.vt.iram=IRAM espduino.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -espduino.menu.exception.enabled=Enabled -espduino.menu.exception.enabled.build.exception_flags=-fexceptions -espduino.menu.exception.enabled.build.stdcpp_lib=-lstdc++ espduino.menu.exception.disabled=Disabled espduino.menu.exception.disabled.build.exception_flags=-fno-exceptions -espduino.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +espduino.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +espduino.menu.exception.enabled=Enabled +espduino.menu.exception.enabled.build.exception_flags=-fexceptions +espduino.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc espduino.build.flash_mode=dio +espduino.build.flash_flags=-DFLASHMODE_DIO espduino.build.flash_freq=40 espduino.menu.eesz.4M=4M (no SPIFFS) espduino.menu.eesz.4M.build.flash_size=4M @@ -946,14 +952,15 @@ huzzah.menu.vt.heap=Heap huzzah.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM huzzah.menu.vt.iram=IRAM huzzah.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -huzzah.menu.exception.enabled=Enabled -huzzah.menu.exception.enabled.build.exception_flags=-fexceptions -huzzah.menu.exception.enabled.build.stdcpp_lib=-lstdc++ huzzah.menu.exception.disabled=Disabled huzzah.menu.exception.disabled.build.exception_flags=-fno-exceptions -huzzah.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +huzzah.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +huzzah.menu.exception.enabled=Enabled +huzzah.menu.exception.enabled.build.exception_flags=-fexceptions +huzzah.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc huzzah.upload.resetmethod=nodemcu huzzah.build.flash_mode=qio +huzzah.build.flash_flags=-DFLASHMODE_QIO huzzah.build.flash_freq=40 huzzah.menu.eesz.4M=4M (no SPIFFS) huzzah.menu.eesz.4M.build.flash_size=4M @@ -1129,14 +1136,15 @@ inventone.menu.vt.heap=Heap inventone.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM inventone.menu.vt.iram=IRAM inventone.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -inventone.menu.exception.enabled=Enabled -inventone.menu.exception.enabled.build.exception_flags=-fexceptions -inventone.menu.exception.enabled.build.stdcpp_lib=-lstdc++ inventone.menu.exception.disabled=Disabled inventone.menu.exception.disabled.build.exception_flags=-fno-exceptions -inventone.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +inventone.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +inventone.menu.exception.enabled=Enabled +inventone.menu.exception.enabled.build.exception_flags=-fexceptions +inventone.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc inventone.upload.resetmethod=nodemcu inventone.build.flash_mode=dio +inventone.build.flash_flags=-DFLASHMODE_DIO inventone.build.flash_freq=40 inventone.menu.eesz.4M=4M (no SPIFFS) inventone.menu.eesz.4M.build.flash_size=4M @@ -1312,17 +1320,18 @@ cw01.menu.vt.heap=Heap cw01.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM cw01.menu.vt.iram=IRAM cw01.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -cw01.menu.exception.enabled=Enabled -cw01.menu.exception.enabled.build.exception_flags=-fexceptions -cw01.menu.exception.enabled.build.stdcpp_lib=-lstdc++ cw01.menu.exception.disabled=Disabled cw01.menu.exception.disabled.build.exception_flags=-fno-exceptions -cw01.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +cw01.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +cw01.menu.exception.enabled=Enabled +cw01.menu.exception.enabled.build.exception_flags=-fexceptions +cw01.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc cw01.upload.resetmethod=nodemcu cw01.menu.CrystalFreq.26=26 MHz cw01.menu.CrystalFreq.40=40 MHz cw01.menu.CrystalFreq.40.build.extra_flags=-DF_CRYSTAL=40000000 -DESP8266 -cw01.build.flash_mode=qio +cw01.build.flash_mode=dio +cw01.build.flash_flags=-DFLASHMODE_DIO cw01.build.flash_freq=40 cw01.menu.eesz.4M=4M (no SPIFFS) cw01.menu.eesz.4M.build.flash_size=4M @@ -1498,13 +1507,14 @@ espresso_lite_v1.menu.vt.heap=Heap espresso_lite_v1.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM espresso_lite_v1.menu.vt.iram=IRAM espresso_lite_v1.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -espresso_lite_v1.menu.exception.enabled=Enabled -espresso_lite_v1.menu.exception.enabled.build.exception_flags=-fexceptions -espresso_lite_v1.menu.exception.enabled.build.stdcpp_lib=-lstdc++ espresso_lite_v1.menu.exception.disabled=Disabled espresso_lite_v1.menu.exception.disabled.build.exception_flags=-fno-exceptions -espresso_lite_v1.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +espresso_lite_v1.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +espresso_lite_v1.menu.exception.enabled=Enabled +espresso_lite_v1.menu.exception.enabled.build.exception_flags=-fexceptions +espresso_lite_v1.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc espresso_lite_v1.build.flash_mode=dio +espresso_lite_v1.build.flash_flags=-DFLASHMODE_DIO espresso_lite_v1.build.flash_freq=40 espresso_lite_v1.menu.eesz.4M=4M (no SPIFFS) espresso_lite_v1.menu.eesz.4M.build.flash_size=4M @@ -1684,13 +1694,14 @@ espresso_lite_v2.menu.vt.heap=Heap espresso_lite_v2.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM espresso_lite_v2.menu.vt.iram=IRAM espresso_lite_v2.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -espresso_lite_v2.menu.exception.enabled=Enabled -espresso_lite_v2.menu.exception.enabled.build.exception_flags=-fexceptions -espresso_lite_v2.menu.exception.enabled.build.stdcpp_lib=-lstdc++ espresso_lite_v2.menu.exception.disabled=Disabled espresso_lite_v2.menu.exception.disabled.build.exception_flags=-fno-exceptions -espresso_lite_v2.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +espresso_lite_v2.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +espresso_lite_v2.menu.exception.enabled=Enabled +espresso_lite_v2.menu.exception.enabled.build.exception_flags=-fexceptions +espresso_lite_v2.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc espresso_lite_v2.build.flash_mode=dio +espresso_lite_v2.build.flash_flags=-DFLASHMODE_DIO espresso_lite_v2.build.flash_freq=40 espresso_lite_v2.menu.eesz.4M=4M (no SPIFFS) espresso_lite_v2.menu.eesz.4M.build.flash_size=4M @@ -1870,13 +1881,14 @@ phoenix_v1.menu.vt.heap=Heap phoenix_v1.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM phoenix_v1.menu.vt.iram=IRAM phoenix_v1.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -phoenix_v1.menu.exception.enabled=Enabled -phoenix_v1.menu.exception.enabled.build.exception_flags=-fexceptions -phoenix_v1.menu.exception.enabled.build.stdcpp_lib=-lstdc++ phoenix_v1.menu.exception.disabled=Disabled phoenix_v1.menu.exception.disabled.build.exception_flags=-fno-exceptions -phoenix_v1.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +phoenix_v1.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +phoenix_v1.menu.exception.enabled=Enabled +phoenix_v1.menu.exception.enabled.build.exception_flags=-fexceptions +phoenix_v1.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc phoenix_v1.build.flash_mode=dio +phoenix_v1.build.flash_flags=-DFLASHMODE_DIO phoenix_v1.build.flash_freq=40 phoenix_v1.menu.eesz.4M=4M (no SPIFFS) phoenix_v1.menu.eesz.4M.build.flash_size=4M @@ -2056,13 +2068,14 @@ phoenix_v2.menu.vt.heap=Heap phoenix_v2.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM phoenix_v2.menu.vt.iram=IRAM phoenix_v2.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -phoenix_v2.menu.exception.enabled=Enabled -phoenix_v2.menu.exception.enabled.build.exception_flags=-fexceptions -phoenix_v2.menu.exception.enabled.build.stdcpp_lib=-lstdc++ phoenix_v2.menu.exception.disabled=Disabled phoenix_v2.menu.exception.disabled.build.exception_flags=-fno-exceptions -phoenix_v2.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +phoenix_v2.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +phoenix_v2.menu.exception.enabled=Enabled +phoenix_v2.menu.exception.enabled.build.exception_flags=-fexceptions +phoenix_v2.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc phoenix_v2.build.flash_mode=dio +phoenix_v2.build.flash_flags=-DFLASHMODE_DIO phoenix_v2.build.flash_freq=40 phoenix_v2.menu.eesz.4M=4M (no SPIFFS) phoenix_v2.menu.eesz.4M.build.flash_size=4M @@ -2242,14 +2255,15 @@ nodemcu.menu.vt.heap=Heap nodemcu.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM nodemcu.menu.vt.iram=IRAM nodemcu.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -nodemcu.menu.exception.enabled=Enabled -nodemcu.menu.exception.enabled.build.exception_flags=-fexceptions -nodemcu.menu.exception.enabled.build.stdcpp_lib=-lstdc++ nodemcu.menu.exception.disabled=Disabled nodemcu.menu.exception.disabled.build.exception_flags=-fno-exceptions -nodemcu.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +nodemcu.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +nodemcu.menu.exception.enabled=Enabled +nodemcu.menu.exception.enabled.build.exception_flags=-fexceptions +nodemcu.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc nodemcu.upload.resetmethod=nodemcu nodemcu.build.flash_mode=qio +nodemcu.build.flash_flags=-DFLASHMODE_QIO nodemcu.build.flash_freq=40 nodemcu.menu.eesz.4M=4M (no SPIFFS) nodemcu.menu.eesz.4M.build.flash_size=4M @@ -2425,14 +2439,15 @@ nodemcuv2.menu.vt.heap=Heap nodemcuv2.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM nodemcuv2.menu.vt.iram=IRAM nodemcuv2.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -nodemcuv2.menu.exception.enabled=Enabled -nodemcuv2.menu.exception.enabled.build.exception_flags=-fexceptions -nodemcuv2.menu.exception.enabled.build.stdcpp_lib=-lstdc++ nodemcuv2.menu.exception.disabled=Disabled nodemcuv2.menu.exception.disabled.build.exception_flags=-fno-exceptions -nodemcuv2.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +nodemcuv2.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +nodemcuv2.menu.exception.enabled=Enabled +nodemcuv2.menu.exception.enabled.build.exception_flags=-fexceptions +nodemcuv2.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc nodemcuv2.upload.resetmethod=nodemcu nodemcuv2.build.flash_mode=dio +nodemcuv2.build.flash_flags=-DFLASHMODE_DIO nodemcuv2.build.flash_freq=40 nodemcuv2.menu.eesz.4M=4M (no SPIFFS) nodemcuv2.menu.eesz.4M.build.flash_size=4M @@ -2608,14 +2623,15 @@ modwifi.menu.vt.heap=Heap modwifi.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM modwifi.menu.vt.iram=IRAM modwifi.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -modwifi.menu.exception.enabled=Enabled -modwifi.menu.exception.enabled.build.exception_flags=-fexceptions -modwifi.menu.exception.enabled.build.stdcpp_lib=-lstdc++ modwifi.menu.exception.disabled=Disabled modwifi.menu.exception.disabled.build.exception_flags=-fno-exceptions -modwifi.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +modwifi.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +modwifi.menu.exception.enabled=Enabled +modwifi.menu.exception.enabled.build.exception_flags=-fexceptions +modwifi.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc modwifi.upload.resetmethod=ck modwifi.build.flash_mode=qio +modwifi.build.flash_flags=-DFLASHMODE_QIO modwifi.build.flash_freq=40 modwifi.menu.eesz.2M=2M (no SPIFFS) modwifi.menu.eesz.2M.build.flash_size=2M @@ -2801,14 +2817,15 @@ thing.menu.vt.heap=Heap thing.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM thing.menu.vt.iram=IRAM thing.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -thing.menu.exception.enabled=Enabled -thing.menu.exception.enabled.build.exception_flags=-fexceptions -thing.menu.exception.enabled.build.stdcpp_lib=-lstdc++ thing.menu.exception.disabled=Disabled thing.menu.exception.disabled.build.exception_flags=-fno-exceptions -thing.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +thing.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +thing.menu.exception.enabled=Enabled +thing.menu.exception.enabled.build.exception_flags=-fexceptions +thing.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc thing.upload.resetmethod=ck thing.build.flash_mode=qio +thing.build.flash_flags=-DFLASHMODE_QIO thing.build.flash_freq=40 thing.menu.eesz.512K=512K (no SPIFFS) thing.menu.eesz.512K.build.flash_size=512K @@ -2984,14 +3001,15 @@ thingdev.menu.vt.heap=Heap thingdev.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM thingdev.menu.vt.iram=IRAM thingdev.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -thingdev.menu.exception.enabled=Enabled -thingdev.menu.exception.enabled.build.exception_flags=-fexceptions -thingdev.menu.exception.enabled.build.stdcpp_lib=-lstdc++ thingdev.menu.exception.disabled=Disabled thingdev.menu.exception.disabled.build.exception_flags=-fno-exceptions -thingdev.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +thingdev.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +thingdev.menu.exception.enabled=Enabled +thingdev.menu.exception.enabled.build.exception_flags=-fexceptions +thingdev.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc thingdev.upload.resetmethod=nodemcu thingdev.build.flash_mode=dio +thingdev.build.flash_flags=-DFLASHMODE_DIO thingdev.build.flash_freq=40 thingdev.menu.eesz.512K=512K (no SPIFFS) thingdev.menu.eesz.512K.build.flash_size=512K @@ -3167,14 +3185,15 @@ esp210.menu.vt.heap=Heap esp210.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM esp210.menu.vt.iram=IRAM esp210.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -esp210.menu.exception.enabled=Enabled -esp210.menu.exception.enabled.build.exception_flags=-fexceptions -esp210.menu.exception.enabled.build.stdcpp_lib=-lstdc++ esp210.menu.exception.disabled=Disabled esp210.menu.exception.disabled.build.exception_flags=-fno-exceptions -esp210.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +esp210.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +esp210.menu.exception.enabled=Enabled +esp210.menu.exception.enabled.build.exception_flags=-fexceptions +esp210.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc esp210.upload.resetmethod=ck esp210.build.flash_mode=qio +esp210.build.flash_flags=-DFLASHMODE_QIO esp210.build.flash_freq=40 esp210.menu.eesz.4M=4M (no SPIFFS) esp210.menu.eesz.4M.build.flash_size=4M @@ -3350,14 +3369,15 @@ d1_mini.menu.vt.heap=Heap d1_mini.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM d1_mini.menu.vt.iram=IRAM d1_mini.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -d1_mini.menu.exception.enabled=Enabled -d1_mini.menu.exception.enabled.build.exception_flags=-fexceptions -d1_mini.menu.exception.enabled.build.stdcpp_lib=-lstdc++ d1_mini.menu.exception.disabled=Disabled d1_mini.menu.exception.disabled.build.exception_flags=-fno-exceptions -d1_mini.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +d1_mini.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +d1_mini.menu.exception.enabled=Enabled +d1_mini.menu.exception.enabled.build.exception_flags=-fexceptions +d1_mini.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc d1_mini.upload.resetmethod=nodemcu d1_mini.build.flash_mode=dio +d1_mini.build.flash_flags=-DFLASHMODE_DIO d1_mini.build.flash_freq=40 d1_mini.menu.eesz.4M=4M (no SPIFFS) d1_mini.menu.eesz.4M.build.flash_size=4M @@ -3533,14 +3553,15 @@ d1_mini_pro.menu.vt.heap=Heap d1_mini_pro.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM d1_mini_pro.menu.vt.iram=IRAM d1_mini_pro.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -d1_mini_pro.menu.exception.enabled=Enabled -d1_mini_pro.menu.exception.enabled.build.exception_flags=-fexceptions -d1_mini_pro.menu.exception.enabled.build.stdcpp_lib=-lstdc++ d1_mini_pro.menu.exception.disabled=Disabled d1_mini_pro.menu.exception.disabled.build.exception_flags=-fno-exceptions -d1_mini_pro.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +d1_mini_pro.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +d1_mini_pro.menu.exception.enabled=Enabled +d1_mini_pro.menu.exception.enabled.build.exception_flags=-fexceptions +d1_mini_pro.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc d1_mini_pro.upload.resetmethod=nodemcu d1_mini_pro.build.flash_mode=dio +d1_mini_pro.build.flash_flags=-DFLASHMODE_DIO d1_mini_pro.build.flash_freq=40 d1_mini_pro.menu.eesz.16M14M=16M (14M SPIFFS) d1_mini_pro.menu.eesz.16M14M.build.flash_size=16M @@ -3699,14 +3720,15 @@ d1_mini_lite.menu.vt.heap=Heap d1_mini_lite.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM d1_mini_lite.menu.vt.iram=IRAM d1_mini_lite.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -d1_mini_lite.menu.exception.enabled=Enabled -d1_mini_lite.menu.exception.enabled.build.exception_flags=-fexceptions -d1_mini_lite.menu.exception.enabled.build.stdcpp_lib=-lstdc++ d1_mini_lite.menu.exception.disabled=Disabled d1_mini_lite.menu.exception.disabled.build.exception_flags=-fno-exceptions -d1_mini_lite.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +d1_mini_lite.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +d1_mini_lite.menu.exception.enabled=Enabled +d1_mini_lite.menu.exception.enabled.build.exception_flags=-fexceptions +d1_mini_lite.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc d1_mini_lite.upload.resetmethod=nodemcu d1_mini_lite.build.flash_mode=dout +d1_mini_lite.build.flash_flags=-DFLASHMODE_DOUT d1_mini_lite.build.flash_freq=40 d1_mini_lite.menu.eesz.1M=1M (no SPIFFS) d1_mini_lite.menu.eesz.1M.build.flash_size=1M @@ -3922,14 +3944,15 @@ d1.menu.vt.heap=Heap d1.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM d1.menu.vt.iram=IRAM d1.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -d1.menu.exception.enabled=Enabled -d1.menu.exception.enabled.build.exception_flags=-fexceptions -d1.menu.exception.enabled.build.stdcpp_lib=-lstdc++ d1.menu.exception.disabled=Disabled d1.menu.exception.disabled.build.exception_flags=-fno-exceptions -d1.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +d1.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +d1.menu.exception.enabled=Enabled +d1.menu.exception.enabled.build.exception_flags=-fexceptions +d1.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc d1.upload.resetmethod=nodemcu d1.build.flash_mode=dio +d1.build.flash_flags=-DFLASHMODE_DIO d1.build.flash_freq=40 d1.menu.eesz.4M=4M (no SPIFFS) d1.menu.eesz.4M.build.flash_size=4M @@ -4105,17 +4128,18 @@ espino.menu.vt.heap=Heap espino.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM espino.menu.vt.iram=IRAM espino.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -espino.menu.exception.enabled=Enabled -espino.menu.exception.enabled.build.exception_flags=-fexceptions -espino.menu.exception.enabled.build.stdcpp_lib=-lstdc++ espino.menu.exception.disabled=Disabled espino.menu.exception.disabled.build.exception_flags=-fno-exceptions -espino.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +espino.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +espino.menu.exception.enabled=Enabled +espino.menu.exception.enabled.build.exception_flags=-fexceptions +espino.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc espino.menu.ResetMethod.ck=ck espino.menu.ResetMethod.ck.upload.resetmethod=ck espino.menu.ResetMethod.nodemcu=nodemcu espino.menu.ResetMethod.nodemcu.upload.resetmethod=nodemcu espino.build.flash_mode=qio +espino.build.flash_flags=-DFLASHMODE_QIO espino.build.flash_freq=40 espino.menu.eesz.4M=4M (no SPIFFS) espino.menu.eesz.4M.build.flash_size=4M @@ -4291,14 +4315,15 @@ espinotee.menu.vt.heap=Heap espinotee.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM espinotee.menu.vt.iram=IRAM espinotee.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -espinotee.menu.exception.enabled=Enabled -espinotee.menu.exception.enabled.build.exception_flags=-fexceptions -espinotee.menu.exception.enabled.build.stdcpp_lib=-lstdc++ espinotee.menu.exception.disabled=Disabled espinotee.menu.exception.disabled.build.exception_flags=-fno-exceptions -espinotee.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +espinotee.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +espinotee.menu.exception.enabled=Enabled +espinotee.menu.exception.enabled.build.exception_flags=-fexceptions +espinotee.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc espinotee.upload.resetmethod=nodemcu espinotee.build.flash_mode=qio +espinotee.build.flash_flags=-DFLASHMODE_QIO espinotee.build.flash_freq=40 espinotee.menu.eesz.4M=4M (no SPIFFS) espinotee.menu.eesz.4M.build.flash_size=4M @@ -4491,14 +4516,15 @@ wifinfo.menu.vt.heap=Heap wifinfo.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM wifinfo.menu.vt.iram=IRAM wifinfo.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -wifinfo.menu.exception.enabled=Enabled -wifinfo.menu.exception.enabled.build.exception_flags=-fexceptions -wifinfo.menu.exception.enabled.build.stdcpp_lib=-lstdc++ wifinfo.menu.exception.disabled=Disabled wifinfo.menu.exception.disabled.build.exception_flags=-fno-exceptions -wifinfo.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +wifinfo.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +wifinfo.menu.exception.enabled=Enabled +wifinfo.menu.exception.enabled.build.exception_flags=-fexceptions +wifinfo.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc wifinfo.upload.resetmethod=nodemcu wifinfo.build.flash_mode=qio +wifinfo.build.flash_flags=-DFLASHMODE_QIO wifinfo.menu.FlashFreq.40=40MHz wifinfo.menu.FlashFreq.40.build.flash_freq=40 wifinfo.menu.FlashFreq.80=80MHz @@ -4729,14 +4755,15 @@ arduino-esp8266.menu.vt.heap=Heap arduino-esp8266.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM arduino-esp8266.menu.vt.iram=IRAM arduino-esp8266.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -arduino-esp8266.menu.exception.enabled=Enabled -arduino-esp8266.menu.exception.enabled.build.exception_flags=-fexceptions -arduino-esp8266.menu.exception.enabled.build.stdcpp_lib=-lstdc++ arduino-esp8266.menu.exception.disabled=Disabled arduino-esp8266.menu.exception.disabled.build.exception_flags=-fno-exceptions -arduino-esp8266.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +arduino-esp8266.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +arduino-esp8266.menu.exception.enabled=Enabled +arduino-esp8266.menu.exception.enabled.build.exception_flags=-fexceptions +arduino-esp8266.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc arduino-esp8266.upload.resetmethod=ck arduino-esp8266.build.flash_mode=qio +arduino-esp8266.build.flash_flags=-DFLASHMODE_QIO arduino-esp8266.build.flash_freq=40 arduino-esp8266.menu.eesz.4M=4M (no SPIFFS) arduino-esp8266.menu.eesz.4M.build.flash_size=4M @@ -4913,14 +4940,15 @@ gen4iod.menu.vt.heap=Heap gen4iod.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM gen4iod.menu.vt.iram=IRAM gen4iod.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -gen4iod.menu.exception.enabled=Enabled -gen4iod.menu.exception.enabled.build.exception_flags=-fexceptions -gen4iod.menu.exception.enabled.build.stdcpp_lib=-lstdc++ gen4iod.menu.exception.disabled=Disabled gen4iod.menu.exception.disabled.build.exception_flags=-fno-exceptions -gen4iod.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +gen4iod.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +gen4iod.menu.exception.enabled=Enabled +gen4iod.menu.exception.enabled.build.exception_flags=-fexceptions +gen4iod.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc gen4iod.upload.resetmethod=nodemcu gen4iod.build.flash_mode=dio +gen4iod.build.flash_flags=-DFLASHMODE_DIO gen4iod.build.flash_freq=80 gen4iod.menu.eesz.512K=512K (no SPIFFS) gen4iod.menu.eesz.512K.build.flash_size=512K @@ -5097,14 +5125,15 @@ oak.menu.vt.heap=Heap oak.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM oak.menu.vt.iram=IRAM oak.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -oak.menu.exception.enabled=Enabled -oak.menu.exception.enabled.build.exception_flags=-fexceptions -oak.menu.exception.enabled.build.stdcpp_lib=-lstdc++ oak.menu.exception.disabled=Disabled oak.menu.exception.disabled.build.exception_flags=-fno-exceptions -oak.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +oak.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +oak.menu.exception.enabled=Enabled +oak.menu.exception.enabled.build.exception_flags=-fexceptions +oak.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc oak.upload.resetmethod=none oak.build.flash_mode=dio +oak.build.flash_flags=-DFLASHMODE_DIO oak.build.flash_freq=40 oak.menu.eesz.4M=4M (no SPIFFS) oak.menu.eesz.4M.build.flash_size=4M @@ -5280,14 +5309,15 @@ wifiduino.menu.vt.heap=Heap wifiduino.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM wifiduino.menu.vt.iram=IRAM wifiduino.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -wifiduino.menu.exception.enabled=Enabled -wifiduino.menu.exception.enabled.build.exception_flags=-fexceptions -wifiduino.menu.exception.enabled.build.stdcpp_lib=-lstdc++ wifiduino.menu.exception.disabled=Disabled wifiduino.menu.exception.disabled.build.exception_flags=-fno-exceptions -wifiduino.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +wifiduino.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +wifiduino.menu.exception.enabled=Enabled +wifiduino.menu.exception.enabled.build.exception_flags=-fexceptions +wifiduino.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc wifiduino.upload.resetmethod=nodemcu wifiduino.build.flash_mode=dio +wifiduino.build.flash_flags=-DFLASHMODE_DIO wifiduino.build.flash_freq=40 wifiduino.menu.eesz.4M=4M (no SPIFFS) wifiduino.menu.eesz.4M.build.flash_size=4M @@ -5463,25 +5493,29 @@ wifi_slot.menu.vt.heap=Heap wifi_slot.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM wifi_slot.menu.vt.iram=IRAM wifi_slot.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -wifi_slot.menu.exception.enabled=Enabled -wifi_slot.menu.exception.enabled.build.exception_flags=-fexceptions -wifi_slot.menu.exception.enabled.build.stdcpp_lib=-lstdc++ wifi_slot.menu.exception.disabled=Disabled wifi_slot.menu.exception.disabled.build.exception_flags=-fno-exceptions -wifi_slot.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +wifi_slot.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +wifi_slot.menu.exception.enabled=Enabled +wifi_slot.menu.exception.enabled.build.exception_flags=-fexceptions +wifi_slot.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc wifi_slot.upload.resetmethod=nodemcu wifi_slot.menu.FlashFreq.40=40MHz wifi_slot.menu.FlashFreq.40.build.flash_freq=40 wifi_slot.menu.FlashFreq.80=80MHz wifi_slot.menu.FlashFreq.80.build.flash_freq=80 -wifi_slot.menu.FlashMode.qio=QIO -wifi_slot.menu.FlashMode.qio.build.flash_mode=qio -wifi_slot.menu.FlashMode.qout=QOUT -wifi_slot.menu.FlashMode.qout.build.flash_mode=qout +wifi_slot.menu.FlashMode.dout=DOUT (compatible) +wifi_slot.menu.FlashMode.dout.build.flash_mode=dout +wifi_slot.menu.FlashMode.dout.build.flash_flags=-DFLASHMODE_DOUT wifi_slot.menu.FlashMode.dio=DIO wifi_slot.menu.FlashMode.dio.build.flash_mode=dio -wifi_slot.menu.FlashMode.dout=DOUT -wifi_slot.menu.FlashMode.dout.build.flash_mode=dout +wifi_slot.menu.FlashMode.dio.build.flash_flags=-DFLASHMODE_DIO +wifi_slot.menu.FlashMode.qout=QOUT +wifi_slot.menu.FlashMode.qout.build.flash_mode=qout +wifi_slot.menu.FlashMode.qout.build.flash_flags=-DFLASHMODE_QOUT +wifi_slot.menu.FlashMode.qio=QIO (fast) +wifi_slot.menu.FlashMode.qio.build.flash_mode=qio +wifi_slot.menu.FlashMode.qio.build.flash_flags=-DFLASHMODE_QIO wifi_slot.menu.eesz.1M=1M (no SPIFFS) wifi_slot.menu.eesz.1M.build.flash_size=1M wifi_slot.menu.eesz.1M.build.flash_size_bytes=0x100000 @@ -5743,14 +5777,15 @@ wiolink.menu.vt.heap=Heap wiolink.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM wiolink.menu.vt.iram=IRAM wiolink.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -wiolink.menu.exception.enabled=Enabled -wiolink.menu.exception.enabled.build.exception_flags=-fexceptions -wiolink.menu.exception.enabled.build.stdcpp_lib=-lstdc++ wiolink.menu.exception.disabled=Disabled wiolink.menu.exception.disabled.build.exception_flags=-fno-exceptions -wiolink.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +wiolink.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +wiolink.menu.exception.enabled=Enabled +wiolink.menu.exception.enabled.build.exception_flags=-fexceptions +wiolink.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc wiolink.upload.resetmethod=nodemcu wiolink.build.flash_mode=qio +wiolink.build.flash_flags=-DFLASHMODE_QIO wiolink.build.flash_freq=40 wiolink.menu.eesz.4M=4M (no SPIFFS) wiolink.menu.eesz.4M.build.flash_size=4M @@ -5926,14 +5961,15 @@ espectro.menu.vt.heap=Heap espectro.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM espectro.menu.vt.iram=IRAM espectro.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM -espectro.menu.exception.enabled=Enabled -espectro.menu.exception.enabled.build.exception_flags=-fexceptions -espectro.menu.exception.enabled.build.stdcpp_lib=-lstdc++ espectro.menu.exception.disabled=Disabled espectro.menu.exception.disabled.build.exception_flags=-fno-exceptions -espectro.menu.exception.disabled.build.stdcpp_lib=-lstdc++-nox +espectro.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +espectro.menu.exception.enabled=Enabled +espectro.menu.exception.enabled.build.exception_flags=-fexceptions +espectro.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc espectro.upload.resetmethod=nodemcu espectro.build.flash_mode=dio +espectro.build.flash_flags=-DFLASHMODE_DIO espectro.build.flash_freq=40 espectro.menu.eesz.4M=4M (no SPIFFS) espectro.menu.eesz.4M.build.flash_size=4M @@ -6083,4 +6119,3 @@ espectro.menu.baud.512000.windows=512000 espectro.menu.baud.512000.upload.speed=512000 espectro.menu.baud.921600=921600 espectro.menu.baud.921600.upload.speed=921600 - diff --git a/arduino/version 2.5.0/platform.txt b/arduino/version 2.5.0/platform.txt index 39988668a..8e9d8b51c 100644 --- a/arduino/version 2.5.0/platform.txt +++ b/arduino/version 2.5.0/platform.txt @@ -5,11 +5,11 @@ # For more info: # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification -name=ESP8266 Boards (2.5.0-beta2) -version=2.5.0-beta2 - - +name=ESP8266 Boards (2.5.0) +version=2.5.0 +runtime.tools.xtensa-lx106-elf-gcc.path={runtime.platform.path}/tools/xtensa-lx106-elf +runtime.tools.esptool.path={runtime.platform.path}/tools/esptool runtime.tools.signing={runtime.platform.path}/tools/signing.py compiler.warning_flags=-w @@ -24,10 +24,8 @@ build.lwip_flags=-DLWIP_OPEN_SRC build.vtable_flags=-DVTABLES_IN_FLASH -#build.exception_flags=-fexceptions build.exception_flags=-fno-exceptions -#build.stdcpp_lib=-lstdc++ -build.stdcpp_lib=-lstdc++-nox +build.stdcpp_lib=-lstdc++ #build.float=-u _printf_float -u _scanf_float build.float= @@ -39,7 +37,7 @@ compiler.libc.path={runtime.platform.path}/tools/sdk/libc/xtensa-lx106-elf compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include" "-I{compiler.sdk.path}/{build.lwip_include}" "-I{compiler.libc.path}/include" "-I{build.path}/core" compiler.c.cmd=xtensa-lx106-elf-gcc -compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 {build.exception_flags} -ffunction-sections -fdata-sections {build.exception_flags} +compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections {build.exception_flags} compiler.S.cmd=xtensa-lx106-elf-gcc compiler.S.flags=-c -g -x assembler-with-cpp -MMD -mlongcalls @@ -80,31 +78,31 @@ compiler.elf2hex.extra_flags= ## generate file with git version number ## needs bash, git, and echo recipe.hooks.core.prebuild.1.pattern=python "{runtime.tools.signing}" --mode header --publickey "{build.source.path}/public.key" --out "{build.path}/core/Updater_Signing.h" - - +recipe.hooks.core.prebuild.2.pattern=bash -c "mkdir -p {build.path}/core && echo \#define ARDUINO_ESP8266_GIT_VER 0x`git --git-dir {runtime.platform.path}/.git rev-parse --short=8 HEAD 2>/dev/null || echo ffffffff` >{build.path}/core/core_version.h" +recipe.hooks.core.prebuild.3.pattern=bash -c "mkdir -p {build.path}/core && echo \#define ARDUINO_ESP8266_GIT_DESC `cd "{runtime.platform.path}"; git describe --tags 2>/dev/null || echo unix-{version}` >>{build.path}/core/core_version.h" ## windows-compatible version without git recipe.hooks.core.prebuild.1.pattern.windows=cmd.exe /c rem cannot sign on windows - - +recipe.hooks.core.prebuild.2.pattern.windows=cmd.exe /c mkdir {build.path}\core & (echo #define ARDUINO_ESP8266_GIT_VER 0x00000000 & echo #define ARDUINO_ESP8266_GIT_DESC win-{version} ) > {build.path}\core\core_version.h +recipe.hooks.core.prebuild.3.pattern.windows=cmd.exe /c if exist {build.source.path}\public.key echo #error Cannot automatically build signed binaries on Windows > {build.path}\core\Updater_Signing.h ## Build the app.ld linker file recipe.hooks.linking.prelink.1.pattern="{compiler.path}{compiler.c.cmd}" -CC -E -P {build.vtable_flags} "{runtime.platform.path}/tools/sdk/ld/eagle.app.v6.common.ld.h" -o "{build.path}/local.eagle.app.v6.common.ld" ## Compile c files -recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {build.flash_flags} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" ## Compile c++ files -recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {build.flash_flags} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" ## Compile S files -recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" +recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {build.flash_flags} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" ## Create archives recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" ## Combine gc-sections, archives, and objects -recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" -Wl,-Map "-Wl,{build.path}/{build.project_name}.map" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{archive_file_path}" {compiler.c.elf.libs} -Wl,--end-group "-L{build.path}" +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {build.exception_flags} -Wl,-Map "-Wl,{build.path}/{build.project_name}.map" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{archive_file_path}" {compiler.c.elf.libs} -Wl,--end-group "-L{build.path}" ## Create eeprom recipe.objcopy.eep.pattern= @@ -154,3 +152,4 @@ tools.espupload.upload.protocol=espupload tools.espupload.upload.params.verbose= tools.espupload.upload.params.quiet= tools.espupload.upload.pattern="{cmd}" "{path}/espupload.py" -f "{build.path}/{build.project_name}.bin" + diff --git a/lib/ArduinoJson-5.11.2/ArduinoJson.h b/lib/ArduinoJson-5.11.2/ArduinoJson.h deleted file mode 100644 index 896503a6c..000000000 --- a/lib/ArduinoJson-5.11.2/ArduinoJson.h +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright Benoit Blanchon 2014-2017 -// MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! - -#include "src/ArduinoJson.h" diff --git a/lib/ArduinoJson-5.11.2/README.md b/lib/ArduinoJson-5.11.2/README.md deleted file mode 100644 index 6ee8a37a6..000000000 --- a/lib/ArduinoJson-5.11.2/README.md +++ /dev/null @@ -1,130 +0,0 @@ -[![Build status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/master?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/master) [![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=master)](https://travis-ci.org/bblanchon/ArduinoJson) [![Coverage Status](https://img.shields.io/coveralls/bblanchon/ArduinoJson.svg)](https://coveralls.io/r/bblanchon/ArduinoJson?branch=master) [![Star this project](http://githubbadges.com/star.svg?user=bblanchon&repo=ArduinoJson&style=flat&color=fff&background=007ec6)](https://github.com/bblanchon/ArduinoJson) - -![ArduinoJson's logo](banner.svg) - -ArduinoJson - C++ JSON library for IoT -==================== - -*An elegant and efficient JSON library for embedded systems.* - -It's designed to have the most intuitive API, the smallest footprint and is able to work without any allocation on the heap (no malloc). - -It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library in any other C++ project. -For instance, it supports Aduino's `String` and `Stream`, but also `std::string`, `std::istream` and `std::ostream`. - -Features --------- - -* JSON decoding (comments are supported) -* JSON encoding (with optional indentation) -* Elegant API, very easy to use -* Fixed memory allocation (zero malloc) -* No data duplication (zero copy) -* Portable (written in C++98) -* Self-contained (no external dependency) -* Small footprint -* Header-only library -* MIT License - -Works on --------- - -* Arduino boards: Uno, Due, Mini, Micro, Yun... -* ESP8266, ESP32 -* Teensy -* RedBearLab boards (BLE Nano...) -* Intel Edison and Galileo -* WeMos boards: D1... -* Computers: Windows, Linux, OSX... -* PlatformIO -* Particle -* Energia - -Quick start ------------ - -#### Decoding / Parsing - -```c++ -char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}"; - -StaticJsonBuffer<200> jsonBuffer; - -JsonObject& root = jsonBuffer.parseObject(json); - -const char* sensor = root["sensor"]; -long time = root["time"]; -double latitude = root["data"][0]; -double longitude = root["data"][1]; -``` - -[See JsonParserExample.ino](examples/JsonParserExample/JsonParserExample.ino) - -Use [ArduinoJson Assistant](https://bblanchon.github.io/ArduinoJson/assistant/) to compute the buffer size. - -#### Encoding / Generating - -```c++ -StaticJsonBuffer<200> jsonBuffer; - -JsonObject& root = jsonBuffer.createObject(); -root["sensor"] = "gps"; -root["time"] = 1351824120; - -JsonArray& data = root.createNestedArray("data"); -data.add(48.756080); -data.add(2.302038); - -root.printTo(Serial); -// This prints: -// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]} -``` - -[See JsonGeneratorExample.ino](examples/JsonGeneratorExample/JsonGeneratorExample.ino) - -Use [ArduinoJson Assistant](https://bblanchon.github.io/ArduinoJson/assistant/) to compute the buffer size. - - -Documentation -------------- - -The documentation is available online in the [ArduinoJson Website](https://bblanchon.github.io/ArduinoJson/). - -The [ArduinoJson Assistant](https://bblanchon.github.io/ArduinoJson/assistant/) helps you get started with the library. - - -Donators --------- - -Special thanks to the following persons and companies who made generous donations to the library author: - -* Robert Murphy USA -* Surge Communications USA -* Alex Scott United Kingdom -* Firepick Services LLC USA -* A B Doodkorte Netherlands -* Scott Smith USA -* Johann Stieger Austria -* Gustavo Donizeti Gini Brazil -* Charles-Henri Hallard France -* Martijn van den Burg Netherlands -* Nick Koumaris Greece -* Jon Williams USA -* Kestutis Liaugminas Lithuania -* Darlington Adibe Nigeria -* Yoeri Kroon Netherlands -* Andrew Melvin United Kingdom -* Doanh Luong Vietnam -* Christoph Schmidt Germany -* OpenEVSE LLC USA -* Prokhoryatov Alexey Russia -* Google Inc. USA -* Charles Haynes Australia -* Charles Walker USA -* Günther Jehle Liechtenstein -* Patrick Elliott - - ---- - -Found this library useful? Please star this project or [help me back with a donation!](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=donate%40benoitblanchon%2efr&lc=GB&item_name=Benoit%20Blanchon&item_number=Arduino%20JSON¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted) :smile: diff --git a/lib/ArduinoJson-5.11.2/examples/JsonHttpClient/JsonHttpClient.ino b/lib/ArduinoJson-5.11.2/examples/JsonHttpClient/JsonHttpClient.ino deleted file mode 100644 index 5edb817f1..000000000 --- a/lib/ArduinoJson-5.11.2/examples/JsonHttpClient/JsonHttpClient.ino +++ /dev/null @@ -1,184 +0,0 @@ -// Sample Arduino Json Web Client -// Downloads and parse http://jsonplaceholder.typicode.com/users/1 -// -// Copyright Benoit Blanchon 2014-2017 -// MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! - -#include -#include -#include - -EthernetClient client; - -const char* server = "jsonplaceholder.typicode.com"; // server's address -const char* resource = "/users/1"; // http resource -const unsigned long BAUD_RATE = 9600; // serial connection speed -const unsigned long HTTP_TIMEOUT = 10000; // max respone time from server -const size_t MAX_CONTENT_SIZE = 512; // max size of the HTTP response - -// The type of data that we want to extract from the page -struct UserData { - char name[32]; - char company[32]; -}; - -// ARDUINO entry point #1: runs once when you press reset or power the board -void setup() { - initSerial(); - initEthernet(); -} - -// ARDUINO entry point #2: runs over and over again forever -void loop() { - if (connect(server)) { - if (sendRequest(server, resource) && skipResponseHeaders()) { - UserData userData; - if (readReponseContent(&userData)) { - printUserData(&userData); - } - } - } - disconnect(); - wait(); -} - -// Initialize Serial port -void initSerial() { - Serial.begin(BAUD_RATE); - while (!Serial) { - ; // wait for serial port to initialize - } - Serial.println("Serial ready"); -} - -// Initialize Ethernet library -void initEthernet() { - byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; - if (!Ethernet.begin(mac)) { - Serial.println("Failed to configure Ethernet"); - return; - } - Serial.println("Ethernet ready"); - delay(1000); -} - -// Open connection to the HTTP server -bool connect(const char* hostName) { - Serial.print("Connect to "); - Serial.println(hostName); - - bool ok = client.connect(hostName, 80); - - Serial.println(ok ? "Connected" : "Connection Failed!"); - return ok; -} - -// Send the HTTP GET request to the server -bool sendRequest(const char* host, const char* resource) { - Serial.print("GET "); - Serial.println(resource); - - client.print("GET "); - client.print(resource); - client.println(" HTTP/1.0"); - client.print("Host: "); - client.println(host); - client.println("Connection: close"); - client.println(); - - return true; -} - -// Skip HTTP headers so that we are at the beginning of the response's body -bool skipResponseHeaders() { - // HTTP headers end with an empty line - char endOfHeaders[] = "\r\n\r\n"; - - client.setTimeout(HTTP_TIMEOUT); - bool ok = client.find(endOfHeaders); - - if (!ok) { - Serial.println("No response or invalid response!"); - } - - return ok; -} - -// Parse the JSON from the input string and extract the interesting values -// Here is the JSON we need to parse -// { -// "id": 1, -// "name": "Leanne Graham", -// "username": "Bret", -// "email": "Sincere@april.biz", -// "address": { -// "street": "Kulas Light", -// "suite": "Apt. 556", -// "city": "Gwenborough", -// "zipcode": "92998-3874", -// "geo": { -// "lat": "-37.3159", -// "lng": "81.1496" -// } -// }, -// "phone": "1-770-736-8031 x56442", -// "website": "hildegard.org", -// "company": { -// "name": "Romaguera-Crona", -// "catchPhrase": "Multi-layered client-server neural-net", -// "bs": "harness real-time e-markets" -// } -// } -bool readReponseContent(struct UserData* userData) { - // Compute optimal size of the JSON buffer according to what we need to parse. - // See https://bblanchon.github.io/ArduinoJson/assistant/ - const size_t BUFFER_SIZE = - JSON_OBJECT_SIZE(8) // the root object has 8 elements - + JSON_OBJECT_SIZE(5) // the "address" object has 5 elements - + JSON_OBJECT_SIZE(2) // the "geo" object has 2 elements - + JSON_OBJECT_SIZE(3) // the "company" object has 3 elements - + MAX_CONTENT_SIZE; // additional space for strings - - // Allocate a temporary memory pool - DynamicJsonBuffer jsonBuffer(BUFFER_SIZE); - - JsonObject& root = jsonBuffer.parseObject(client); - - if (!root.success()) { - Serial.println("JSON parsing failed!"); - return false; - } - - // Here were copy the strings we're interested in - strcpy(userData->name, root["name"]); - strcpy(userData->company, root["company"]["name"]); - // It's not mandatory to make a copy, you could just use the pointers - // Since, they are pointing inside the "content" buffer, so you need to make - // sure it's still in memory when you read the string - - return true; -} - -// Print the data extracted from the JSON -void printUserData(const struct UserData* userData) { - Serial.print("Name = "); - Serial.println(userData->name); - Serial.print("Company = "); - Serial.println(userData->company); -} - -// Close the connection with the HTTP server -void disconnect() { - Serial.println("Disconnect"); - client.stop(); -} - -// Pause for a 1 minute -void wait() { - Serial.println("Wait 60 seconds"); - delay(60000); -} diff --git a/lib/ArduinoJson-5.11.2/examples/JsonServer/JsonServer.ino b/lib/ArduinoJson-5.11.2/examples/JsonServer/JsonServer.ino deleted file mode 100644 index 555842b82..000000000 --- a/lib/ArduinoJson-5.11.2/examples/JsonServer/JsonServer.ino +++ /dev/null @@ -1,76 +0,0 @@ -// Sample Arduino Json Web Server -// Created by Benoit Blanchon. -// Heavily inspired by "Web Server" from David A. Mellis and Tom Igoe - -#include -#include -#include - -byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; -IPAddress ip(192, 168, 0, 177); -EthernetServer server(80); - -bool readRequest(EthernetClient& client) { - bool currentLineIsBlank = true; - while (client.connected()) { - if (client.available()) { - char c = client.read(); - if (c == '\n' && currentLineIsBlank) { - return true; - } else if (c == '\n') { - currentLineIsBlank = true; - } else if (c != '\r') { - currentLineIsBlank = false; - } - } - } - return false; -} - -JsonObject& prepareResponse(JsonBuffer& jsonBuffer) { - JsonObject& root = jsonBuffer.createObject(); - - JsonArray& analogValues = root.createNestedArray("analog"); - for (int pin = 0; pin < 6; pin++) { - int value = analogRead(pin); - analogValues.add(value); - } - - JsonArray& digitalValues = root.createNestedArray("digital"); - for (int pin = 0; pin < 14; pin++) { - int value = digitalRead(pin); - digitalValues.add(value); - } - - return root; -} - -void writeResponse(EthernetClient& client, JsonObject& json) { - client.println("HTTP/1.1 200 OK"); - client.println("Content-Type: application/json"); - client.println("Connection: close"); - client.println(); - - json.prettyPrintTo(client); -} - -void setup() { - Ethernet.begin(mac, ip); - server.begin(); -} - -void loop() { - EthernetClient client = server.available(); - if (client) { - bool success = readRequest(client); - if (success) { - // Use https://bblanchon.github.io/ArduinoJson/assistant/ to - // compute the right size for the buffer - StaticJsonBuffer<500> jsonBuffer; - JsonObject& json = prepareResponse(jsonBuffer); - writeResponse(client, json); - } - delay(1); - client.stop(); - } -} diff --git a/lib/ArduinoJson-5.11.2/examples/JsonUdpBeacon/JsonUdpBeacon.ino b/lib/ArduinoJson-5.11.2/examples/JsonUdpBeacon/JsonUdpBeacon.ino deleted file mode 100644 index b3bd5fc50..000000000 --- a/lib/ArduinoJson-5.11.2/examples/JsonUdpBeacon/JsonUdpBeacon.ino +++ /dev/null @@ -1,57 +0,0 @@ -// Send a JSON object on UDP at regular interval -// -// You can easily test this program with netcat: -// $ nc -ulp 8888 -// -// by Benoit Blanchon, MIT License 2015-2017 - -#include -#include -#include - -byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; -IPAddress localIp(192, 168, 0, 177); -IPAddress remoteIp(192, 168, 0, 109); -unsigned int remotePort = 8888; -unsigned localPort = 8888; -EthernetUDP udp; - -JsonObject& buildJson(JsonBuffer& jsonBuffer) { - JsonObject& root = jsonBuffer.createObject(); - - JsonArray& analogValues = root.createNestedArray("analog"); - for (int pin = 0; pin < 6; pin++) { - int value = analogRead(pin); - analogValues.add(value); - } - - JsonArray& digitalValues = root.createNestedArray("digital"); - for (int pin = 0; pin < 14; pin++) { - int value = digitalRead(pin); - digitalValues.add(value); - } - - return root; -} - -void sendJson(JsonObject& json) { - udp.beginPacket(remoteIp, remotePort); - json.printTo(udp); - udp.println(); - udp.endPacket(); -} - -void setup() { - Ethernet.begin(mac, localIp); - udp.begin(localPort); -} - -void loop() { - delay(1000); - - // Use https://bblanchon.github.io/ArduinoJson/assistant/ to - // compute the right size for the buffer - StaticJsonBuffer<300> jsonBuffer; - JsonObject& json = buildJson(jsonBuffer); - sendJson(json); -} diff --git a/lib/ArduinoJson-5.11.2/library.properties b/lib/ArduinoJson-5.11.2/library.properties deleted file mode 100644 index 9809a3c0b..000000000 --- a/lib/ArduinoJson-5.11.2/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=ArduinoJson -version=5.11.2 -author=Benoit Blanchon -maintainer=Benoit Blanchon -sentence=An efficient and elegant JSON library for Arduino. -paragraph=Like this project? Please star it on GitHub! -category=Data Processing -url=https://bblanchon.github.io/ArduinoJson/ -architectures=* diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson.h b/lib/ArduinoJson-5.11.2/src/ArduinoJson.h deleted file mode 100644 index c1ec7c02f..000000000 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright Benoit Blanchon 2014-2017 -// MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! - -#pragma once - -#include "ArduinoJson.hpp" - -using namespace ArduinoJson; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ValueSetter.hpp b/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ValueSetter.hpp deleted file mode 100644 index 7eb3ed63b..000000000 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ValueSetter.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright Benoit Blanchon 2014-2017 -// MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! - -#pragma once - -#include "../JsonBuffer.hpp" -#include "../JsonVariant.hpp" -#include "../StringTraits/StringTraits.hpp" -#include "../TypeTraits/EnableIf.hpp" - -namespace ArduinoJson { -namespace Internals { - -template -struct ValueSetter { - template - static bool set(JsonBuffer*, TDestination& destination, TSourceRef source) { - destination = source; - return true; - } -}; - -template -struct ValueSetter::should_duplicate>::type> { - template - static bool set(JsonBuffer* buffer, TDestination& destination, - TSourceRef source) { - const char* copy = buffer->strdup(source); - if (!copy) return false; - destination = copy; - return true; - } -}; - -template -struct ValueSetter::should_duplicate>::type> { - template - static bool set(JsonBuffer*, TDestination& destination, TSourceRef source) { - // unsigned char* -> char* - destination = reinterpret_cast(source); - return true; - } -}; -} -} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/isInteger.hpp b/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/isInteger.hpp deleted file mode 100644 index ea39f2a63..000000000 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/isInteger.hpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright Benoit Blanchon 2014-2017 -// MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! - -#pragma once - -#include "./ctype.hpp" - -namespace ArduinoJson { -namespace Polyfills { - -inline bool isInteger(const char* s) { - if (!s) return false; - if (issign(*s)) s++; - while (isdigit(*s)) s++; - return *s == '\0'; -} -} -} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/RawJson.hpp b/lib/ArduinoJson-5.11.2/src/ArduinoJson/RawJson.hpp deleted file mode 100644 index 6db195c32..000000000 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/RawJson.hpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright Benoit Blanchon 2014-2017 -// MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! - -#pragma once - -namespace ArduinoJson { - -// A special type of data that can be used to insert pregenerated JSON portions. -class RawJson { - public: - explicit RawJson(const char* str) : _str(str) {} - operator const char*() const { - return _str; - } - - private: - const char* _str; -}; -} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsSignedIntegral.hpp b/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsSignedIntegral.hpp deleted file mode 100644 index fde6e13b0..000000000 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsSignedIntegral.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright Benoit Blanchon 2014-2017 -// MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! - -#pragma once - -#include "../Configuration.hpp" -#include "IsSame.hpp" - -namespace ArduinoJson { -namespace TypeTraits { - -// A meta-function that returns true if T is an integral type. -template -struct IsSignedIntegral { - static const bool value = TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || -#if ARDUINOJSON_USE_LONG_LONG - TypeTraits::IsSame::value || -#endif - -#if ARDUINOJSON_USE_INT64 - TypeTraits::IsSame::value || -#endif - false; -}; -} -} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp b/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp deleted file mode 100644 index 173763e05..000000000 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright Benoit Blanchon 2014-2017 -// MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! - -#pragma once - -#include "../Configuration.hpp" -#include "IsSame.hpp" - -namespace ArduinoJson { -namespace TypeTraits { - -// A meta-function that returns true if T is an integral type. -template -struct IsUnsignedIntegral { - static const bool value = TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || -#if ARDUINOJSON_USE_LONG_LONG - TypeTraits::IsSame::value || -#endif - -#if ARDUINOJSON_USE_INT64 - TypeTraits::IsSame::value || -#endif - false; -}; -} -} diff --git a/lib/ArduinoJson-5.13.4/ArduinoJson.h b/lib/ArduinoJson-5.13.4/ArduinoJson.h new file mode 100644 index 000000000..9f78b9f18 --- /dev/null +++ b/lib/ArduinoJson-5.13.4/ArduinoJson.h @@ -0,0 +1,5 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include "src/ArduinoJson.h" diff --git a/lib/ArduinoJson-5.11.2/CHANGELOG.md b/lib/ArduinoJson-5.13.4/CHANGELOG.md similarity index 68% rename from lib/ArduinoJson-5.11.2/CHANGELOG.md rename to lib/ArduinoJson-5.13.4/CHANGELOG.md index 490e25c8c..3616b176a 100644 --- a/lib/ArduinoJson-5.11.2/CHANGELOG.md +++ b/lib/ArduinoJson-5.13.4/CHANGELOG.md @@ -1,6 +1,78 @@ ArduinoJson: change log ======================= +v5.13.4 +------- + +* Removed spurious files in the Particle library + +v5.13.3 +------- + +* Improved float serialization when `-fsingle-precision-constant` is used +* Fixed `JsonVariant::is()` that returned true for empty strings +* Fixed `JsonVariant::is()` (closes #763) + +v5.13.2 +------- + +* Fixed `JsonBuffer::parse()` not respecting nesting limit correctly (issue #693) +* Fixed inconsistencies in nesting level counting (PR #695 from Zhenyu Wu) +* Fixed null values that could be pass to `strcmp()` (PR #745 from Mike Karlesky) +* Added macros `ARDUINOJSON_VERSION`, `ARDUINOJSON_VERSION_MAJOR`... + +v5.13.1 +------- + +* Fixed `JsonVariant::operator|(int)` that returned the default value if the variant contained a double (issue #675) +* Allowed non-quoted key to contain underscores (issue #665) + +v5.13.0 +------- + +* Changed the rules of string duplication (issue #658) +* `RawJson()` accepts any kind of string and obeys to the same rules for duplication +* Changed the return type of `strdup()` to `const char*` to prevent double duplication +* Marked `strdup()` as deprecated + +> ### New rules for string duplication +> +> | type | duplication | +> |:---------------------------|:------------| +> | const char* | no | +> | char* | ~~no~~ yes | +> | String | yes | +> | std::string | yes | +> | const __FlashStringHelper* | yes | +> +> These new rules make `JsonBuffer::strdup()` useless. + +v5.12.0 +------- + +* Added `JsonVariant::operator|` to return a default value (see below) +* Added a clear error message when compiled as C instead of C++ (issue #629) +* Added detection of MPLAB XC compiler (issue #629) +* Added detection of Keil ARM Compiler (issue #629) +* Added an example that shows how to save and load a configuration file +* Reworked all other examples + +> ### How to use the new feature? +> +> If you have a block like this: +> +> ```c++ +> const char* ssid = root["ssid"]; +> if (!ssid) +> ssid = "default ssid"; +> ``` +> +> You can simplify like that: +> +> ```c++ +> const char* ssid = root["ssid"] | "default ssid"; +> ``` + v5.11.2 ------- @@ -42,27 +114,26 @@ v5.10.0 * Fixed error `IsBaseOf is not a member of ArduinoJson::TypeTraits` (issue #495) * Fixed error `forming reference to reference` (issue #495) -### BREAKING CHANGES :warning: - -| Old syntax | New syntax | -|---------------------------------|---------------------| -| `double_with_n_digits(3.14, 2)` | `3.14` | -| `float_with_n_digits(3.14, 2)` | `3.14f` | -| `obj.set("key", 3.14, 2)` | `obj["key"] = 3.14` | -| `arr.add(3.14, 2)` | `arr.add(3.14)` | - -| Input | Old output | New output | -|-----------|------------|------------| -| `3.14159` | `3.14` | `3.14159` | -| `42.0` | `42.00` | `42` | -| `0.0` | `0.00` | `0` | - -| Expression | Old result | New result | -|--------------------------------|------------|------------| -| `JsonVariant(42).is()` | `true` | `true` | -| `JsonVariant(42).is()` | `false` | `true` | -| `JsonVariant(42).is()` | `false` | `true` | - +> ### BREAKING CHANGES :warning: +> +> | Old syntax | New syntax | +> |:--------------------------------|:--------------------| +> | `double_with_n_digits(3.14, 2)` | `3.14` | +> | `float_with_n_digits(3.14, 2)` | `3.14f` | +> | `obj.set("key", 3.14, 2)` | `obj["key"] = 3.14` | +> | `arr.add(3.14, 2)` | `arr.add(3.14)` | +> +> | Input | Old output | New output | +> |:----------|:-----------|:-----------| +> | `3.14159` | `3.14` | `3.14159` | +> | `42.0` | `42.00` | `42` | +> | `0.0` | `0.00` | `0` | +> +> | Expression | Old result | New result | +> |:-------------------------------|:-----------|:-----------| +> | `JsonVariant(42).is()` | `true` | `true` | +> | `JsonVariant(42).is()` | `false` | `true` | +> | `JsonVariant(42).is()` | `false` | `true` | v5.9.0 ------ @@ -116,24 +187,23 @@ v5.8.0 * Added support for `Stream` (issue #300) * Reduced memory consumption by not duplicating spaces and comments -### BREAKING CHANGES :warning: - -`JsonBuffer::parseObject()` and `JsonBuffer::parseArray()` have been pulled down to the derived classes `DynamicJsonBuffer` and `StaticJsonBufferBase`. - -This means that if you have code like: - -```c++ -void myFunction(JsonBuffer& jsonBuffer); -``` - -you need to replace it with one of the following: - -```c++ -void myFunction(DynamicJsonBuffer& jsonBuffer); -void myFunction(StaticJsonBufferBase& jsonBuffer); -template void myFunction(TJsonBuffer& jsonBuffer); -``` - +> ### BREAKING CHANGES :warning: +> +> `JsonBuffer::parseObject()` and `JsonBuffer::parseArray()` have been pulled down to the derived classes `DynamicJsonBuffer` and `StaticJsonBufferBase`. +> +> This means that if you have code like: +> +> ```c++ +> void myFunction(JsonBuffer& jsonBuffer); +> ``` +> +> you need to replace it with one of the following: +> +> ```c++ +> void myFunction(DynamicJsonBuffer& jsonBuffer); +> void myFunction(StaticJsonBufferBase& jsonBuffer); +> template void myFunction(TJsonBuffer& jsonBuffer); +> ``` v5.7.3 ------ @@ -166,27 +236,26 @@ v5.7.0 * Added example `StringExample.ino` to show where `String` can be used * Increased default nesting limit to 50 when compiled for a computer (issue #349) -### BREAKING CHANGES :warning: - -The non-template functions `JsonObject::get()` and `JsonArray.get()` have been removed. This means that you need to explicitely tell the type you expect in return. - -Old code: - -```c++ -#define ARDUINOJSON_USE_ARDUINO_STRING 0 -JsonVariant value1 = myObject.get("myKey"); -JsonVariant value2 = myArray.get(0); -``` - -New code: - -```c++ -#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 -#define ARDUINOJSON_ENABLE_STD_STRING 1 -JsonVariant value1 = myObject.get("myKey"); -JsonVariant value2 = myArray.get(0); -``` - +> ### BREAKING CHANGES :warning: +> +> The non-template functions `JsonObject::get()` and `JsonArray.get()` have been removed. This means that you need to explicitely tell the type you expect in return. +> +> Old code: +> +> ```c++ +> #define ARDUINOJSON_USE_ARDUINO_STRING 0 +> JsonVariant value1 = myObject.get("myKey"); +> JsonVariant value2 = myArray.get(0); +> ``` +> +> New code: +> +> ```c++ +> #define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 +> #define ARDUINOJSON_ENABLE_STD_STRING 1 +> JsonVariant value1 = myObject.get("myKey"); +> JsonVariant value2 = myArray.get(0); +> ``` v5.6.7 ------ @@ -278,8 +347,9 @@ v5.1.0 * Added support of `long long` (issue #171) * Moved all build settings to `ArduinoJson/Configuration.hpp` -**BREAKING CHANGE**: -If you defined `ARDUINOJSON_ENABLE_STD_STREAM`, you now need to define it to `1`. +> ### BREAKING CHANGE :warning: +> +> If you defined `ARDUINOJSON_ENABLE_STD_STREAM`, you now need to define it to `1`. v5.0.8 ------ @@ -293,10 +363,10 @@ v5.0.7 * Made library easier to use from a CMake project: simply `add_subdirectory(ArduinoJson/src)` * Changed `String` to be a `typedef` of `std::string` (issues #142 and #161) -### BREAKING CHANGES :warning: - -- `JsonVariant(true).as()` now returns `"true"` instead of `"1"` -- `JsonVariant(false).as()` now returns `"false"` instead of `"0"` +> ### BREAKING CHANGES :warning: +> +> - `JsonVariant(true).as()` now returns `"true"` instead of `"1"` +> - `JsonVariant(false).as()` now returns `"false"` instead of `"0"` v5.0.6 ------ @@ -350,11 +420,11 @@ v5.0.0 * Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators (issue #66) * Switched to new the library layout (requires Arduino 1.0.6 or above) -### BREAKING CHANGES :warning: - -- `JsonObject::add()` was renamed to `set()` -- `JsonArray::at()` and `JsonObject::at()` were renamed to `get()` -- Number of digits of floating point value are now set with `double_with_n_digits()` +> ### BREAKING CHANGES :warning: +> +> - `JsonObject::add()` was renamed to `set()` +> - `JsonArray::at()` and `JsonObject::at()` were renamed to `get()` +> - Number of digits of floating point value are now set with `double_with_n_digits()` **Personal note about the `String` class**: Support of the `String` class has been added to the library because many people use it in their programs. @@ -407,106 +477,7 @@ v4.0 * Unified parser and generator API (issue #23) * Updated library layout, now requires Arduino 1.0.6 or newer -**BREAKING CHANGE**: API changed significantly, see [Migrating code to the new API](https://github.com/bblanchon/ArduinoJson/wiki/Migrating-code-to-the-new-API). +> ### BREAKING CHANGES :warning: +> +> API changed significantly since v3, see [Migrating code to the new API](https://arduinojson.org/doc/migration/). - -v3.4 ----- - -* Fixed escaped char parsing (issue #16) - - -v3.3 ----- - -* Added indented output for the JSON generator (issue #11), see example bellow. -* Added `IndentedPrint`, a decorator for `Print` to allow indented output - -Example: - - JsonOject<2> json; - json["key"] = "value"; - json.prettyPrintTo(Serial); - -v3.2 ----- - -* Fixed a bug when adding nested object in `JsonArray` (bug introduced in v3.1). - -v3.1 ----- - -* Calling `Generator::JsonObject::add()` twice with the same `key` now replaces the `value` -* Added `Generator::JsonObject::operator[]`, see bellow the new API -* Added `Generator::JsonObject::remove()` (issue #9) - -Old generator API: - - JsonObject<3> root; - root.add("sensor", "gps"); - root.add("time", 1351824120); - root.add("data", array); - -New generator API: - - JsonObject<3> root; - root["sensor"] = "gps"; - root["time"] = 1351824120; - root["data"] = array; - -v3.0 ----- - -* New parser API, see bellow -* Renamed `JsonHashTable` into `JsonObject` -* Added iterators for `JsonArray` and `JsonObject` (issue #4) - -Old parser API: - - JsonHashTable root = parser.parseHashTable(json); - - char* sensor = root.getString("sensor"); - long time = root.getLong("time"); - double latitude = root.getArray("data").getDouble(0); - double longitude = root.getArray("data").getDouble(1); - -New parser API: - - JsonObject root = parser.parse(json); - - char* sensor = root["sensor"]; - long time = root["time"]; - double latitude = root["data"][0]; - double longitude = root["data"][1]; - -v2.1 ----- - -* Fixed case `#include "jsmn.cpp"` which caused an error in Linux (issue #6) -* Fixed a buffer overrun in JSON Parser (issue #5) - -v2.0 ----- - -* Added JSON encoding (issue #2) -* Renamed the library `ArduinoJsonParser` becomes `ArduinoJson` - -**Breaking change**: you need to add the following line at the top of your program. - - using namespace ArduinoJson::Parser; - -v1.2 ----- - -* Fixed error in JSON parser example (issue #1) - -v1.1 ----- - -* Example: changed `char* json` into `char[] json` so that the bytes are not write protected -* Fixed parsing bug when the JSON contains multi-dimensional arrays - -v1.0 ----- - -Initial release diff --git a/lib/ArduinoJson-5.11.2/LICENSE.md b/lib/ArduinoJson-5.13.4/LICENSE.md similarity index 96% rename from lib/ArduinoJson-5.11.2/LICENSE.md rename to lib/ArduinoJson-5.13.4/LICENSE.md index 9f35ed446..f0c4b5ae7 100644 --- a/lib/ArduinoJson-5.11.2/LICENSE.md +++ b/lib/ArduinoJson-5.13.4/LICENSE.md @@ -1,7 +1,7 @@ The MIT License (MIT) --------------------- -Copyright © 2014-2017 Benoit BLANCHON +Copyright © 2014-2018 Benoit BLANCHON Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/lib/ArduinoJson-5.13.4/README.md b/lib/ArduinoJson-5.13.4/README.md new file mode 100644 index 000000000..8ddc698fc --- /dev/null +++ b/lib/ArduinoJson-5.13.4/README.md @@ -0,0 +1,110 @@ +![ArduinoJson](banner.svg) + +--- + +[![Build status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/master?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/master) [![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=master)](https://travis-ci.org/bblanchon/ArduinoJson) [![Coverage Status](https://img.shields.io/coveralls/bblanchon/ArduinoJson.svg)](https://coveralls.io/r/bblanchon/ArduinoJson?branch=master) [![Star this project](http://githubbadges.com/star.svg?user=bblanchon&repo=ArduinoJson&style=flat&color=fff&background=007ec6)](https://github.com/bblanchon/ArduinoJson) + +ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things). + +## Features + +* JSON decoding (comments are supported) +* JSON encoding (with optional indentation) +* Elegant API, easy to use +* Fixed memory allocation (zero malloc) +* No data duplication (zero copy) +* Portable (written in C++98, can be used in any C++ project) +* Self-contained (no external dependency) +* Small footprint +* Input and output streams +* [100% code coverage](https://coveralls.io/github/bblanchon/ArduinoJson) +* [Header-only library](https://en.wikipedia.org/wiki/Header-only) +* [MIT License](https://en.wikipedia.org/wiki/MIT_License) +* [Comprehensive documentation](https://arduinojson.org?utm_source=github&utm_medium=readme) + +## Compatibility + +ArduinoJson works on the following hardware: + +* Arduino boards: [Uno](https://www.arduino.cc/en/Main/ArduinoBoardUno), [Due](https://www.arduino.cc/en/Main/ArduinoBoardDue), [Mini](https://www.arduino.cc/en/Main/ArduinoBoardMini), [Micro](https://www.arduino.cc/en/Main/ArduinoBoardMicro), [Yun](https://www.arduino.cc/en/Main/ArduinoBoardYun)... +* Espressif chips: [ESP8266](https://en.wikipedia.org/wiki/ESP8266), [ESP32](https://en.wikipedia.org/wiki/ESP32) +* WeMos boards: [D1](https://wiki.wemos.cc/products:d1:d1), [D1 mini](https://wiki.wemos.cc/products:d1:d1_mini), ... +* RedBearLab boards: [BLE Nano](http://redbearlab.com/blenano/), [BLE Mini](http://redbearlab.com/blemini/), [WiFi Micro](https://redbear.cc/product/wifi/wifi-micro.html), [LOLIN32](https://wiki.wemos.cc/products:lolin32:lolin32)... +* [Teensy](https://www.pjrc.com/teensy/) boards +* Intel boards: Edison, Galileo... +* Particle boards: [Photon](https://www.particle.io/products/hardware/photon-wifi-dev-kit), [Electron](https://www.particle.io/products/hardware/electron-cellular-dev-kit)... +* Texas Instruments boards: [MSP430](http://www.ti.com/microcontrollers/msp430-ultra-low-power-mcus/overview/overview.html)... + +ArduinoJson compiles with zero warning on the following compilers, IDEs, and platforms: + +* [Arduino IDE](https://www.arduino.cc/en/Main/Software) +* [PlatformIO](http://platformio.org/) +* [Energia](http://energia.nu/) +* [Visual Micro](http://www.visualmicro.com/) +* [Atmel Studio](http://www.atmel.com/microsite/atmel-studio/) +* [IAR Embedded Workbench](https://www.iar.com/iar-embedded-workbench/) +* [Atollic TrueSTUDIO](https://atollic.com/truestudio/) +* [Keil uVision](http://www.keil.com/) +* [MPLAB X IDE](http://www.microchip.com/mplab/mplab-x-ide) +* [GCC](https://gcc.gnu.org/) +* [Clang](https://clang.llvm.org/) +* [Visual Studio](https://www.visualstudio.com/) + +## Quickstart + +### Deserialization + +Here is a program that parses a JSON document with ArduinoJson. + +```c++ +char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}"; + +StaticJsonBuffer<200> jsonBuffer; + +JsonObject& root = jsonBuffer.parseObject(json); + +const char* sensor = root["sensor"]; +long time = root["time"]; +double latitude = root["data"][0]; +double longitude = root["data"][1]; +``` + +See the [tutorial on arduinojson.org](https://arduinojson.org/doc/decoding/?utm_source=github&utm_medium=readme) + +### Serialization + +Here is a program that generates a JSON document with ArduinoJson: + +```c++ +StaticJsonBuffer<200> jsonBuffer; + +JsonObject& root = jsonBuffer.createObject(); +root["sensor"] = "gps"; +root["time"] = 1351824120; + +JsonArray& data = root.createNestedArray("data"); +data.add(48.756080); +data.add(2.302038); + +root.printTo(Serial); +// This prints: +// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]} +``` + +See the [tutorial on arduinojson.org](https://arduinojson.org/doc/encoding/?utm_source=github&utm_medium=readme) + +## Documentation + +The documentation is available on [arduinojson.org](https://arduinojson.org/?utm_source=github&utm_medium=readme), here are some shortcuts: + +* The [Examples](https://arduinojson.org/example/?utm_source=github&utm_medium=readme) show how to use the library in various situations. +* The [API Reference](https://arduinojson.org/api/?utm_source=github&utm_medium=readme) contains the description of each class and function. +* The [FAQ](https://arduinojson.org/faq/?utm_source=github&utm_medium=readme) has the answer to virtually every question. +* The [ArduinoJson Assistant](https://arduinojson.org/assistant/?utm_source=github&utm_medium=readme) writes programs for you! + +--- + +Do you like this library? Please [star this project on GitHub](https://github.com/bblanchon/ArduinoJson/stargazers)! + +What? You don't like it but you *love* it? +We don't take donations anymore, but [we sell a book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme), so you can help and learn at the same time! \ No newline at end of file diff --git a/lib/ArduinoJson-5.13.4/examples/JsonConfigFile/JsonConfigFile.ino b/lib/ArduinoJson-5.13.4/examples/JsonConfigFile/JsonConfigFile.ino new file mode 100644 index 000000000..2ccf7d673 --- /dev/null +++ b/lib/ArduinoJson-5.13.4/examples/JsonConfigFile/JsonConfigFile.ino @@ -0,0 +1,144 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License +// +// This example shows how to store your project configuration in a file. +// It uses the SD library but can be easily modified for any other file-system. +// +// The file contains a JSON document with the following content: +// { +// "hostname": "examples.com", +// "port": 2731 +// } + +#include +#include +#include + +// Configuration that we'll store on disk +struct Config { + char hostname[64]; + int port; +}; + +const char *filename = "/config.txt"; // <- SD library uses 8.3 filenames +Config config; // <- global configuration object + +// Loads the configuration from a file +void loadConfiguration(const char *filename, Config &config) { + // Open file for reading + File file = SD.open(filename); + + // Allocate the memory pool on the stack. + // Don't forget to change the capacity to match your JSON document. + // Use arduinojson.org/assistant to compute the capacity. + StaticJsonBuffer<512> jsonBuffer; + + // Parse the root object + JsonObject &root = jsonBuffer.parseObject(file); + + if (!root.success()) + Serial.println(F("Failed to read file, using default configuration")); + + // Copy values from the JsonObject to the Config + config.port = root["port"] | 2731; + strlcpy(config.hostname, // <- destination + root["hostname"] | "example.com", // <- source + sizeof(config.hostname)); // <- destination's capacity + + // Close the file (File's destructor doesn't close the file) + file.close(); +} + +// Saves the configuration to a file +void saveConfiguration(const char *filename, const Config &config) { + // Delete existing file, otherwise the configuration is appended to the file + SD.remove(filename); + + // Open file for writing + File file = SD.open(filename, FILE_WRITE); + if (!file) { + Serial.println(F("Failed to create file")); + return; + } + + // Allocate the memory pool on the stack + // Don't forget to change the capacity to match your JSON document. + // Use https://arduinojson.org/assistant/ to compute the capacity. + StaticJsonBuffer<256> jsonBuffer; + + // Parse the root object + JsonObject &root = jsonBuffer.createObject(); + + // Set the values + root["hostname"] = config.hostname; + root["port"] = config.port; + + // Serialize JSON to file + if (root.printTo(file) == 0) { + Serial.println(F("Failed to write to file")); + } + + // Close the file (File's destructor doesn't close the file) + file.close(); +} + +// Prints the content of a file to the Serial +void printFile(const char *filename) { + // Open file for reading + File file = SD.open(filename); + if (!file) { + Serial.println(F("Failed to read file")); + return; + } + + // Extract each characters by one by one + while (file.available()) { + Serial.print((char)file.read()); + } + Serial.println(); + + // Close the file (File's destructor doesn't close the file) + file.close(); +} + +void setup() { + // Initialize serial port + Serial.begin(9600); + while (!Serial) continue; + + // Initialize SD library + while (!SD.begin()) { + Serial.println(F("Failed to initialize SD library")); + delay(1000); + } + + // Should load default config if run for the first time + Serial.println(F("Loading configuration...")); + loadConfiguration(filename, config); + + // Create configuration file + Serial.println(F("Saving configuration...")); + saveConfiguration(filename, config); + + // Dump config file + Serial.println(F("Print config file...")); + printFile(filename); +} + +void loop() { + // not used in this example +} + +// See also +// -------- +// +// https://arduinojson.org/ contains the documentation for all the functions +// used above. It also includes an FAQ that will help you solve any +// serialization or deserialization problem. +// +// The book "Mastering ArduinoJson" contains a case study of a project that has +// a complex configuration with nested members. +// Contrary to this example, the project in the book uses the SPIFFS filesystem. +// Learn more at https://arduinojson.org/book/ +// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤ diff --git a/lib/ArduinoJson-5.11.2/examples/JsonGeneratorExample/JsonGeneratorExample.ino b/lib/ArduinoJson-5.13.4/examples/JsonGeneratorExample/JsonGeneratorExample.ino similarity index 63% rename from lib/ArduinoJson-5.11.2/examples/JsonGeneratorExample/JsonGeneratorExample.ino rename to lib/ArduinoJson-5.13.4/examples/JsonGeneratorExample/JsonGeneratorExample.ino index 0f636faf8..7b38227b3 100644 --- a/lib/ArduinoJson-5.11.2/examples/JsonGeneratorExample/JsonGeneratorExample.ino +++ b/lib/ArduinoJson-5.13.4/examples/JsonGeneratorExample/JsonGeneratorExample.ino @@ -1,23 +1,21 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License // -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! +// This example shows how to generate a JSON document with ArduinoJson. #include void setup() { + // Initialize Serial port Serial.begin(9600); - while (!Serial) { - // wait serial port initialization - } + while (!Serial) continue; // Memory pool for JSON object tree. // // Inside the brackets, 200 is the size of the pool in bytes. - // If the JSON object is more complex, you need to increase that value. - // See https://bblanchon.github.io/ArduinoJson/assistant/ + // Don't forget to change this value to match your JSON document. + // Use arduinojson.org/assistant to compute the capacity. StaticJsonBuffer<200> jsonBuffer; // StaticJsonBuffer allocates memory on the stack, it can be @@ -68,3 +66,16 @@ void setup() { void loop() { // not used in this example } + +// See also +// -------- +// +// https://arduinojson.org/ contains the documentation for all the functions +// used above. It also includes an FAQ that will help you solve any +// serialization problem. +// +// The book "Mastering ArduinoJson" contains a tutorial on serialization. +// It begins with a simple example, like the one above, and then adds more +// features like serializing directly to a file or an HTTP request. +// Learn more at https://arduinojson.org/book/ +// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤ diff --git a/lib/ArduinoJson-5.13.4/examples/JsonHttpClient/JsonHttpClient.ino b/lib/ArduinoJson-5.13.4/examples/JsonHttpClient/JsonHttpClient.ino new file mode 100644 index 000000000..4ce1c20d1 --- /dev/null +++ b/lib/ArduinoJson-5.13.4/examples/JsonHttpClient/JsonHttpClient.ino @@ -0,0 +1,112 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License +// +// This example shows how to parse a JSON document in an HTTP response. +// It uses the Ethernet library, but can be easily adapted for Wifi. +// +// It performs a GET resquest on arduinojson.org/example.json +// Here is the expected response: +// { +// "sensor": "gps", +// "time": 1351824120, +// "data": [ +// 48.756080, +// 2.302038 +// ] +// } + +#include +#include +#include + +void setup() { + // Initialize Serial port + Serial.begin(9600); + while (!Serial) continue; + + // Initialize Ethernet library + byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; + if (!Ethernet.begin(mac)) { + Serial.println(F("Failed to configure Ethernet")); + return; + } + delay(1000); + + Serial.println(F("Connecting...")); + + // Connect to HTTP server + EthernetClient client; + client.setTimeout(10000); + if (!client.connect("arduinojson.org", 80)) { + Serial.println(F("Connection failed")); + return; + } + + Serial.println(F("Connected!")); + + // Send HTTP request + client.println(F("GET /example.json HTTP/1.0")); + client.println(F("Host: arduinojson.org")); + client.println(F("Connection: close")); + if (client.println() == 0) { + Serial.println(F("Failed to send request")); + return; + } + + // Check HTTP status + char status[32] = {0}; + client.readBytesUntil('\r', status, sizeof(status)); + if (strcmp(status, "HTTP/1.1 200 OK") != 0) { + Serial.print(F("Unexpected response: ")); + Serial.println(status); + return; + } + + // Skip HTTP headers + char endOfHeaders[] = "\r\n\r\n"; + if (!client.find(endOfHeaders)) { + Serial.println(F("Invalid response")); + return; + } + + // Allocate JsonBuffer + // Use arduinojson.org/assistant to compute the capacity. + const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60; + DynamicJsonBuffer jsonBuffer(capacity); + + // Parse JSON object + JsonObject& root = jsonBuffer.parseObject(client); + if (!root.success()) { + Serial.println(F("Parsing failed!")); + return; + } + + // Extract values + Serial.println(F("Response:")); + Serial.println(root["sensor"].as()); + Serial.println(root["time"].as()); + Serial.println(root["data"][0].as()); + Serial.println(root["data"][1].as()); + + // Disconnect + client.stop(); +} + +void loop() { + // not used in this example +} + +// See also +// -------- +// +// https://arduinojson.org/ contains the documentation for all the functions +// used above. It also includes an FAQ that will help you solve any +// serialization problem. +// +// The book "Mastering ArduinoJson" contains a tutorial on deserialization +// showing how to parse the response from Yahoo Weather. In the last chapter, +// it shows how to parse the huge documents from OpenWeatherMap +// and Weather Underground. +// Learn more at https://arduinojson.org/book/ +// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤ diff --git a/lib/ArduinoJson-5.11.2/examples/JsonParserExample/JsonParserExample.ino b/lib/ArduinoJson-5.13.4/examples/JsonParserExample/JsonParserExample.ino similarity index 61% rename from lib/ArduinoJson-5.11.2/examples/JsonParserExample/JsonParserExample.ino rename to lib/ArduinoJson-5.13.4/examples/JsonParserExample/JsonParserExample.ino index 719d2ee28..6c16211b5 100644 --- a/lib/ArduinoJson-5.11.2/examples/JsonParserExample/JsonParserExample.ino +++ b/lib/ArduinoJson-5.13.4/examples/JsonParserExample/JsonParserExample.ino @@ -1,23 +1,21 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License // -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! +// This example shows how to deserialize a JSON document with ArduinoJson. #include void setup() { + // Initialize serial port Serial.begin(9600); - while (!Serial) { - // wait serial port initialization - } + while (!Serial) continue; // Memory pool for JSON object tree. // - // Inside the brackets, 200 is the size of the pool in bytes, - // If the JSON object is more complex, you need to increase that value. - // See https://bblanchon.github.io/ArduinoJson/assistant/ + // Inside the brackets, 200 is the size of the pool in bytes. + // Don't forget to change this value to match your JSON document. + // Use arduinojson.org/assistant to compute the capacity. StaticJsonBuffer<200> jsonBuffer; // StaticJsonBuffer allocates memory on the stack, it can be @@ -65,3 +63,16 @@ void setup() { void loop() { // not used in this example } + +// See also +// -------- +// +// https://arduinojson.org/ contains the documentation for all the functions +// used above. It also includes an FAQ that will help you solve any +// deserialization problem. +// +// The book "Mastering ArduinoJson" contains a tutorial on deserialization. +// It begins with a simple example, like the one above, and then adds more +// features like deserializing directly from a file or an HTTP request. +// Learn more at https://arduinojson.org/book/ +// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤ diff --git a/lib/ArduinoJson-5.13.4/examples/JsonServer/JsonServer.ino b/lib/ArduinoJson-5.13.4/examples/JsonServer/JsonServer.ino new file mode 100644 index 000000000..e693ae176 --- /dev/null +++ b/lib/ArduinoJson-5.13.4/examples/JsonServer/JsonServer.ino @@ -0,0 +1,109 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License +// +// This example shows how to implement an HTTP server that sends JSON document +// in the responses. +// It uses the Ethernet library but can be easily adapted for Wifi. +// +// It sends the value of the analog and digital pins. +// The JSON document looks like the following: +// { +// "analog": [ 0, 1, 2, 3, 4, 5 ], +// "digital": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ] +// } + +#include +#include +#include + +byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +EthernetServer server(80); + +void setup() { + // Initialize serial port + Serial.begin(9600); + while (!Serial) continue; + + // Initialize Ethernet libary + if (!Ethernet.begin(mac)) { + Serial.println(F("Failed to initialize Ethernet library")); + return; + } + + // Start to listen + server.begin(); + + Serial.println(F("Server is ready.")); + Serial.print(F("Please connect to http://")); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // Wait for an incomming connection + EthernetClient client = server.available(); + + // Do we have a client? + if (!client) return; + + Serial.println(F("New client")); + + // Read the request (we ignore the content in this example) + while (client.available()) client.read(); + + // Allocate JsonBuffer + // Use arduinojson.org/assistant to compute the capacity. + StaticJsonBuffer<500> jsonBuffer; + + // Create the root object + JsonObject& root = jsonBuffer.createObject(); + + // Create the "analog" array + JsonArray& analogValues = root.createNestedArray("analog"); + for (int pin = 0; pin < 6; pin++) { + // Read the analog input + int value = analogRead(pin); + + // Add the value at the end of the array + analogValues.add(value); + } + + // Create the "digital" array + JsonArray& digitalValues = root.createNestedArray("digital"); + for (int pin = 0; pin < 14; pin++) { + // Read the digital input + int value = digitalRead(pin); + + // Add the value at the end of the array + digitalValues.add(value); + } + + Serial.print(F("Sending: ")); + root.printTo(Serial); + Serial.println(); + + // Write response headers + client.println("HTTP/1.0 200 OK"); + client.println("Content-Type: application/json"); + client.println("Connection: close"); + client.println(); + + // Write JSON document + root.prettyPrintTo(client); + + // Disconnect + client.stop(); +} + +// See also +// -------- +// +// https://arduinojson.org/ contains the documentation for all the functions +// used above. It also includes an FAQ that will help you solve any +// serialization problem. +// +// The book "Mastering ArduinoJson" contains a tutorial on serialization. +// It begins with a simple example, then adds more features like serializing +// directly to a file or an HTTP client. +// Learn more at https://arduinojson.org/book/ +// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤ diff --git a/lib/ArduinoJson-5.13.4/examples/JsonUdpBeacon/JsonUdpBeacon.ino b/lib/ArduinoJson-5.13.4/examples/JsonUdpBeacon/JsonUdpBeacon.ino new file mode 100644 index 000000000..b2328a62d --- /dev/null +++ b/lib/ArduinoJson-5.13.4/examples/JsonUdpBeacon/JsonUdpBeacon.ino @@ -0,0 +1,101 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License +// +// This example shows how to send a JSON document to a UDP socket. +// At regular interval, it sends a UDP packet that contains the status of +// analog and digital pins. +// The JSON document looks like the following: +// { +// "analog": [ 0, 1, 2, 3, 4, 5 ], +// "digital": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ] +// } +// +// If you want to test this program, you need to be able to receive the UDP +// packets. +// For example, you can run netcat on your computer +// $ ncat -ulp 8888 +// See https://nmap.org/ncat/ + +#include +#include +#include + +byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +IPAddress remoteIp(192, 168, 0, 108); // <- EDIT!!!! +unsigned short remotePort = 8888; +unsigned short localPort = 8888; +EthernetUDP udp; + +void setup() { + // Initialize serial port + Serial.begin(9600); + while (!Serial) continue; + + // Initialize Ethernet libary + if (!Ethernet.begin(mac)) { + Serial.println(F("Failed to initialize Ethernet library")); + return; + } + + // Enable UDP + udp.begin(localPort); +} + +void loop() { + // Allocate JsonBuffer + // Use arduinojson.org/assistant to compute the capacity. + StaticJsonBuffer<500> jsonBuffer; + + // Create the root object + JsonObject& root = jsonBuffer.createObject(); + + // Create the "analog" array + JsonArray& analogValues = root.createNestedArray("analog"); + for (int pin = 0; pin < 6; pin++) { + // Read the analog input + int value = analogRead(pin); + + // Add the value at the end of the array + analogValues.add(value); + } + + // Create the "digital" array + JsonArray& digitalValues = root.createNestedArray("digital"); + for (int pin = 0; pin < 14; pin++) { + // Read the digital input + int value = digitalRead(pin); + + // Add the value at the end of the array + digitalValues.add(value); + } + + // Log + Serial.print(F("Sending to ")); + Serial.print(remoteIp); + Serial.print(F(" on port ")); + Serial.println(remotePort); + root.printTo(Serial); + + // Send UDP packet + udp.beginPacket(remoteIp, remotePort); + root.printTo(udp); + udp.println(); + udp.endPacket(); + + // Wait + delay(10000); +} + +// See also +// -------- +// +// https://arduinojson.org/ contains the documentation for all the functions +// used above. It also includes an FAQ that will help you solve any +// serialization problem. +// +// The book "Mastering ArduinoJson" contains a tutorial on serialization. +// It begins with a simple example, then adds more features like serializing +// directly to a file or any stream. +// Learn more at https://arduinojson.org/book/ +// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤ diff --git a/lib/ArduinoJson-5.11.2/examples/ProgmemExample/ProgmemExample.ino b/lib/ArduinoJson-5.13.4/examples/ProgmemExample/ProgmemExample.ino similarity index 52% rename from lib/ArduinoJson-5.11.2/examples/ProgmemExample/ProgmemExample.ino rename to lib/ArduinoJson-5.13.4/examples/ProgmemExample/ProgmemExample.ino index 195b014fb..ddde8fd1d 100644 --- a/lib/ArduinoJson-5.11.2/examples/ProgmemExample/ProgmemExample.ino +++ b/lib/ArduinoJson-5.13.4/examples/ProgmemExample/ProgmemExample.ino @@ -1,21 +1,19 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License // -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! +// This example shows the different ways you can use Flash strings with +// ArduinoJson. +// +// Use Flash strings sparingly, because ArduinoJson duplicates them in the +// JsonBuffer. Prefer plain old char*, as they are more efficient in term of +// code size, speed, and memory usage. #include -// About -// ----- -// This example shows the different ways you can use PROGMEM with ArduinoJson. -// Please don't see this as an invitation to use PROGMEM. -// On the contrary, you should always use char[] when possible, it's much more -// efficient in term of code size, speed and memory usage. - void setup() { -#ifdef PROGMEM +#ifdef PROGMEM // <- check that Flash strings are supported + DynamicJsonBuffer jsonBuffer; // You can use a Flash String as your JSON input. @@ -39,6 +37,9 @@ void setup() { // JsonBuffer. root["sensor"] = F("gps"); + // It works with RawJson too: + root["sensor"] = RawJson(F("\"gps\"")); + // You can compare the content of a JsonVariant to a Flash String if (root["sensor"] == F("gps")) { // ... @@ -54,3 +55,16 @@ void setup() { void loop() { // not used in this example } + +// See also +// -------- +// +// https://arduinojson.org/ contains the documentation for all the functions +// used above. It also includes an FAQ that will help you solve any memory +// problem. +// +// The book "Mastering ArduinoJson" contains a quick C++ course that explains +// how your microcontroller stores strings in memory. It also tells why you +// should not abuse Flash strings with ArduinoJson. +// Learn more at https://arduinojson.org/book/ +// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤ diff --git a/lib/ArduinoJson-5.11.2/examples/StringExample/StringExample.ino b/lib/ArduinoJson-5.13.4/examples/StringExample/StringExample.ino similarity index 67% rename from lib/ArduinoJson-5.11.2/examples/StringExample/StringExample.ino rename to lib/ArduinoJson-5.13.4/examples/StringExample/StringExample.ino index 50b8db6ec..fc7503d0e 100644 --- a/lib/ArduinoJson-5.11.2/examples/StringExample/StringExample.ino +++ b/lib/ArduinoJson-5.13.4/examples/StringExample/StringExample.ino @@ -1,19 +1,15 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License // -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! +// This example shows the different ways you can use String with ArduinoJson. +// +// Use String objects sparingly, because ArduinoJson duplicates them in the +// JsonBuffer. Prefer plain old char[], as they are more efficient in term of +// code size, speed, and memory usage. #include -// About -// ----- -// This example shows the different ways you can use String with ArduinoJson. -// Please don't see this as an invitation to use String. -// On the contrary, you should always use char[] when possible, it's much more -// efficient in term of code size, speed and memory usage. - void setup() { DynamicJsonBuffer jsonBuffer; @@ -44,6 +40,9 @@ void setup() { // WARNING: the content of the String will be duplicated in the JsonBuffer. root["sensor"] = sensor; + // It works with RawJson too: + root["sensor"] = RawJson(sensor); + // You can also concatenate strings // WARNING: the content of the String will be duplicated in the JsonBuffer. root[String("sen") + "sor"] = String("gp") + "s"; @@ -61,3 +60,15 @@ void setup() { void loop() { // not used in this example } + +// See also +// -------- +// +// https://arduinojson.org/ contains the documentation for all the functions +// used above. It also includes an FAQ that will help you solve any problem. +// +// The book "Mastering ArduinoJson" contains a quick C++ course that explains +// how your microcontroller stores strings in memory. On several occasions, it +// shows how you can avoid String in your program. +// Learn more at https://arduinojson.org/book/ +// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤ diff --git a/lib/ArduinoJson-5.11.2/keywords.txt b/lib/ArduinoJson-5.13.4/keywords.txt similarity index 100% rename from lib/ArduinoJson-5.11.2/keywords.txt rename to lib/ArduinoJson-5.13.4/keywords.txt diff --git a/lib/ArduinoJson-5.13.4/library.properties b/lib/ArduinoJson-5.13.4/library.properties new file mode 100644 index 000000000..67ccbb95e --- /dev/null +++ b/lib/ArduinoJson-5.13.4/library.properties @@ -0,0 +1,11 @@ +name=ArduinoJson +version=5.13.4 +author=Benoit Blanchon +maintainer=Benoit Blanchon +sentence=An efficient and elegant JSON library for Arduino. +paragraph=ArduinoJson supports ✔ serialization, ✔ deserialization, ✔ fixed allocation, ✔ zero-copy, ✔ streams, and more. It is the most popular Arduino library on GitHub ❤❤❤❤❤. Check out arduinojson.org for a comprehensive documentation. +category=Data Processing +url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties +architectures=* +repository=https://github.com/bblanchon/ArduinoJson.git +license=MIT diff --git a/lib/ArduinoJson-5.13.4/src/ArduinoJson.h b/lib/ArduinoJson-5.13.4/src/ArduinoJson.h new file mode 100644 index 000000000..3782aeabc --- /dev/null +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson.h @@ -0,0 +1,17 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#ifdef __cplusplus + +#include "ArduinoJson.hpp" + +using namespace ArduinoJson; + +#else + +#error ArduinoJson requires a C++ compiler, please change file extension to .cc or .cpp + +#endif diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson.hpp similarity index 75% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson.hpp index 949fa5ca0..c493c06a9 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson.hpp @@ -1,12 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once +#include "ArduinoJson/version.hpp" + #include "ArduinoJson/DynamicJsonBuffer.hpp" #include "ArduinoJson/JsonArray.hpp" #include "ArduinoJson/JsonObject.hpp" diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Configuration.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Configuration.hpp similarity index 94% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Configuration.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Configuration.hpp index a1015a6f3..82483adfa 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Configuration.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Configuration.hpp @@ -1,15 +1,13 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once // Small or big machine? #ifndef ARDUINOJSON_EMBEDDED_MODE -#if defined(ARDUINO) || defined(__IAR_SYSTEMS_ICC__) +#if defined(ARDUINO) || defined(__IAR_SYSTEMS_ICC__) || defined(__XC) || \ + defined(__ARMCC_VERSION) #define ARDUINOJSON_EMBEDDED_MODE 1 #else #define ARDUINOJSON_EMBEDDED_MODE 0 diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/Encoding.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/Encoding.hpp similarity index 80% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/Encoding.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/Encoding.hpp index dba785aae..a0efa2c74 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/Encoding.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/Encoding.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonBufferAllocated.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonBufferAllocated.hpp similarity index 68% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonBufferAllocated.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonBufferAllocated.hpp index ff74adc55..443aae4df 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonBufferAllocated.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonBufferAllocated.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonFloat.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonFloat.hpp similarity index 56% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonFloat.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonFloat.hpp index a4a8e937f..0ed42140f 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonFloat.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonFloat.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonInteger.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonInteger.hpp similarity index 70% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonInteger.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonInteger.hpp index 574a5e109..c8ddd00b4 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonInteger.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonInteger.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantAs.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantAs.hpp similarity index 80% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantAs.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantAs.hpp index 3f19fd23a..8f202c5eb 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantAs.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantAs.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantContent.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantContent.hpp similarity index 79% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantContent.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantContent.hpp index b27716299..c525a6060 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantContent.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantContent.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantDefault.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantDefault.hpp similarity index 68% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantDefault.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantDefault.hpp index a59fd46c9..57ecc83ee 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantDefault.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantDefault.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantType.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantType.hpp similarity index 84% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantType.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantType.hpp index ba6a24999..21f890e52 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/JsonVariantType.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/JsonVariantType.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/List.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/List.hpp similarity index 93% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/List.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/List.hpp index 8a24666ec..506308cc3 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/List.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/List.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ListConstIterator.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ListConstIterator.hpp similarity index 85% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ListConstIterator.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ListConstIterator.hpp index bce1bfa5e..a6af685e5 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ListConstIterator.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ListConstIterator.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ListIterator.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ListIterator.hpp similarity index 86% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ListIterator.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ListIterator.hpp index a491866f0..01fa287f7 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ListIterator.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ListIterator.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ListNode.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ListNode.hpp similarity index 70% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ListNode.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ListNode.hpp index 712e15e1f..c0907120e 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ListNode.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ListNode.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/NonCopyable.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/NonCopyable.hpp similarity index 67% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/NonCopyable.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/NonCopyable.hpp index 98ebd8fb3..73f3d8edb 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/NonCopyable.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/NonCopyable.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ReferenceType.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ReferenceType.hpp similarity index 74% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ReferenceType.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ReferenceType.hpp index bbc9046be..1e491172f 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Data/ReferenceType.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ReferenceType.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ValueSaver.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ValueSaver.hpp new file mode 100644 index 000000000..9750f1ac5 --- /dev/null +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Data/ValueSaver.hpp @@ -0,0 +1,52 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "../JsonBuffer.hpp" +#include "../JsonVariant.hpp" +#include "../StringTraits/StringTraits.hpp" +#include "../TypeTraits/EnableIf.hpp" + +namespace ArduinoJson { +namespace Internals { + +template +struct ValueSaver { + template + static bool save(JsonBuffer*, Destination& destination, Source source) { + destination = source; + return true; + } +}; + +template +struct ValueSaver< + Source, typename EnableIf::should_duplicate>::type> { + template + static bool save(JsonBuffer* buffer, Destination& dest, Source source) { + if (!StringTraits::is_null(source)) { + typename StringTraits::duplicate_t dup = + StringTraits::duplicate(source, buffer); + if (!dup) return false; + dest = dup; + } else { + dest = reinterpret_cast(0); + } + return true; + } +}; + +// const char*, const signed char*, const unsigned char* +template +struct ValueSaver< + Char*, typename EnableIf::should_duplicate>::type> { + template + static bool save(JsonBuffer*, Destination& dest, Char* source) { + dest = reinterpret_cast(source); + return true; + } +}; +} +} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/Comments.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/Comments.hpp similarity index 88% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/Comments.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/Comments.hpp index 9f281da49..c2c48ebcc 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/Comments.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/Comments.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/JsonParser.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/JsonParser.hpp similarity index 77% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/JsonParser.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/JsonParser.hpp index 3e605ef25..4cbaf454c 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/JsonParser.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/JsonParser.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -47,19 +44,18 @@ class JsonParser { const char *parseString(); bool parseAnythingTo(JsonVariant *destination); - FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); inline bool parseArrayTo(JsonVariant *destination); inline bool parseObjectTo(JsonVariant *destination); inline bool parseStringTo(JsonVariant *destination); - static inline bool isInRange(char c, char min, char max) { + static inline bool isBetween(char c, char min, char max) { return min <= c && c <= max; } - static inline bool isLetterOrNumber(char c) { - return isInRange(c, '0', '9') || isInRange(c, 'a', 'z') || - isInRange(c, 'A', 'Z') || c == '+' || c == '-' || c == '.'; + static inline bool canBeInNonQuotedString(char c) { + return isBetween(c, '0', '9') || isBetween(c, '_', 'z') || + isBetween(c, 'A', 'Z') || c == '+' || c == '-' || c == '.'; } static inline bool isQuote(char c) { @@ -74,7 +70,7 @@ class JsonParser { template struct JsonParserBuilder { - typedef typename Internals::StringTraits::Reader InputReader; + typedef typename StringTraits::Reader InputReader; typedef JsonParser TParser; static TParser makeParser(TJsonBuffer *buffer, TString &json, @@ -84,10 +80,9 @@ struct JsonParserBuilder { }; template -struct JsonParserBuilder< - TJsonBuffer, TChar *, - typename TypeTraits::EnableIf::value>::type> { - typedef typename Internals::StringTraits::Reader TReader; +struct JsonParserBuilder::value>::type> { + typedef typename StringTraits::Reader TReader; typedef StringWriter TWriter; typedef JsonParser TParser; @@ -103,5 +98,5 @@ inline typename JsonParserBuilder::TParser makeParser( return JsonParserBuilder::makeParser(buffer, json, nestingLimit); } -} -} +} // namespace Internals +} // namespace ArduinoJson diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/JsonParserImpl.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/JsonParserImpl.hpp similarity index 85% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/JsonParserImpl.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/JsonParserImpl.hpp index 1c41bdaac..504267355 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/JsonParserImpl.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/JsonParserImpl.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -20,18 +17,9 @@ inline bool ArduinoJson::Internals::JsonParser::eat( } template -inline bool ArduinoJson::Internals::JsonParser< - TReader, TWriter>::parseAnythingTo(JsonVariant *destination) { - if (_nestingLimit == 0) return false; - _nestingLimit--; - bool success = parseAnythingToUnsafe(destination); - _nestingLimit++; - return success; -} - -template -inline bool ArduinoJson::Internals::JsonParser< - TReader, TWriter>::parseAnythingToUnsafe(JsonVariant *destination) { +inline bool +ArduinoJson::Internals::JsonParser::parseAnythingTo( + JsonVariant *destination) { skipSpacesAndComments(_reader); switch (_reader.current()) { @@ -49,6 +37,9 @@ inline bool ArduinoJson::Internals::JsonParser< template inline ArduinoJson::JsonArray & ArduinoJson::Internals::JsonParser::parseArray() { + if (_nestingLimit == 0) return JsonArray::invalid(); + _nestingLimit--; + // Create an empty array JsonArray &array = _buffer->createArray(); @@ -70,6 +61,7 @@ ArduinoJson::Internals::JsonParser::parseArray() { SUCCESS_EMPTY_ARRAY: SUCCES_NON_EMPTY_ARRAY: + _nestingLimit++; return array; ERROR_INVALID_VALUE: @@ -92,6 +84,9 @@ inline bool ArduinoJson::Internals::JsonParser::parseArrayTo( template inline ArduinoJson::JsonObject & ArduinoJson::Internals::JsonParser::parseObject() { + if (_nestingLimit == 0) return JsonObject::invalid(); + _nestingLimit--; + // Create an empty object JsonObject &object = _buffer->createObject(); @@ -118,6 +113,7 @@ ArduinoJson::Internals::JsonParser::parseObject() { SUCCESS_EMPTY_OBJECT: SUCCESS_NON_EMPTY_OBJECT: + _nestingLimit++; return object; ERROR_INVALID_KEY: @@ -142,8 +138,7 @@ inline bool ArduinoJson::Internals::JsonParser::parseObjectTo( template inline const char * ArduinoJson::Internals::JsonParser::parseString() { - typename TypeTraits::RemoveReference::type::String str = - _writer.startString(); + typename RemoveReference::type::String str = _writer.startString(); skipSpacesAndComments(_reader); char c = _reader.current(); @@ -169,7 +164,7 @@ ArduinoJson::Internals::JsonParser::parseString() { } } else { // no quotes for (;;) { - if (!isLetterOrNumber(c)) break; + if (!canBeInNonQuotedString(c)) break; _reader.move(); str.append(c); c = _reader.current(); diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/StringWriter.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/StringWriter.hpp similarity index 79% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/StringWriter.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/StringWriter.hpp index 42ee640d8..fd5507ea5 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Deserialization/StringWriter.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Deserialization/StringWriter.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/DynamicJsonBuffer.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/DynamicJsonBuffer.hpp similarity index 94% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/DynamicJsonBuffer.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/DynamicJsonBuffer.hpp index 65e744bf2..bdbd5dd90 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/DynamicJsonBuffer.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/DynamicJsonBuffer.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -22,6 +19,7 @@ #endif namespace ArduinoJson { +namespace Internals { class DefaultAllocator { public: void* allocate(size_t size) { @@ -154,6 +152,7 @@ class DynamicJsonBufferBase Block* _head; size_t _nextBlockCapacity; }; +} #if defined(__clang__) #pragma clang diagnostic pop @@ -166,5 +165,6 @@ class DynamicJsonBufferBase // Implements a JsonBuffer with dynamic memory allocation. // You are strongly encouraged to consider using StaticJsonBuffer which is much // more suitable for embedded systems. -typedef DynamicJsonBufferBase DynamicJsonBuffer; +typedef Internals::DynamicJsonBufferBase + DynamicJsonBuffer; } diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonArray.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonArray.hpp similarity index 82% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonArray.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonArray.hpp index 27404fb7b..2acd2a1a5 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonArray.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonArray.hpp @@ -1,16 +1,13 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once #include "Data/JsonBufferAllocated.hpp" #include "Data/List.hpp" #include "Data/ReferenceType.hpp" -#include "Data/ValueSetter.hpp" +#include "Data/ValueSaver.hpp" #include "JsonVariant.hpp" #include "Serialization/JsonPrintable.hpp" #include "StringTraits/StringTraits.hpp" @@ -29,7 +26,9 @@ namespace ArduinoJson { // Forward declarations class JsonObject; class JsonBuffer; +namespace Internals { class JsonArraySubscript; +} // An array of JsonVariant. // @@ -50,28 +49,26 @@ class JsonArray : public Internals::JsonPrintable, : Internals::List(buffer) {} // Gets the value at the specified index - const JsonArraySubscript operator[](size_t index) const; + const Internals::JsonArraySubscript operator[](size_t index) const; // Gets or sets the value at specified index - JsonArraySubscript operator[](size_t index); + Internals::JsonArraySubscript operator[](size_t index); // Adds the specified value at the end of the array. // // bool add(TValue); // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value, bool>::type add( - const T &value) { + bool add(const T &value) { return add_impl(value); } // // bool add(TValue); - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - bool add(const T *value) { - return add_impl(value); + bool add(T *value) { + return add_impl(value); } // // bool add(TValue value, uint8_t decimals); @@ -84,28 +81,25 @@ class JsonArray : public Internals::JsonPrintable, // Sets the value at specified index. // - // bool add(size_t index, TValue); + // bool add(size_t index, const TValue&); // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value, bool>::type set( - size_t index, const T &value) { + bool set(size_t index, const T &value) { return set_impl(index, value); } // // bool add(size_t index, TValue); - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - bool set(size_t index, const T *value) { - return set_impl(index, value); + bool set(size_t index, T *value) { + return set_impl(index, value); } // // bool set(size_t index, TValue value, uint8_t decimals); // TValue = float, double template - typename TypeTraits::EnableIf::value, - bool>::type + typename Internals::EnableIf::value, bool>::type set(size_t index, T value, uint8_t decimals) { return set_impl(index, JsonVariant(value, decimals)); } @@ -211,14 +205,14 @@ class JsonArray : public Internals::JsonPrintable, bool set_impl(size_t index, TValueRef value) { iterator it = begin() += index; if (it == end()) return false; - return Internals::ValueSetter::set(_buffer, *it, value); + return Internals::ValueSaver::save(_buffer, *it, value); } template bool add_impl(TValueRef value) { iterator it = Internals::List::add(); if (it == end()) return false; - return Internals::ValueSetter::set(_buffer, *it, value); + return Internals::ValueSaver::save(_buffer, *it, value); } }; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonArrayImpl.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonArrayImpl.hpp similarity index 75% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonArrayImpl.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonArrayImpl.hpp index 6ebd39baa..924b7ea7a 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonArrayImpl.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonArrayImpl.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonArraySubscript.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonArraySubscript.hpp similarity index 69% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonArraySubscript.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonArraySubscript.hpp index 5bd6208a5..afb4dc1ec 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonArraySubscript.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonArraySubscript.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -16,6 +13,7 @@ #endif namespace ArduinoJson { +namespace Internals { class JsonArraySubscript : public JsonVariantBase { public: FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) @@ -28,10 +26,9 @@ class JsonArraySubscript : public JsonVariantBase { // Replaces the value // - // operator=(TValue) + // operator=(const TValue&) // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template FORCE_INLINE JsonArraySubscript& operator=(const T& src) { _array.set(_index, src); @@ -39,9 +36,9 @@ class JsonArraySubscript : public JsonVariantBase { } // // operator=(TValue) - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - FORCE_INLINE JsonArraySubscript& operator=(const T* src) { + FORCE_INLINE JsonArraySubscript& operator=(T* src) { _array.set(_index, src); return *this; } @@ -51,7 +48,7 @@ class JsonArraySubscript : public JsonVariantBase { } template - FORCE_INLINE typename Internals::JsonVariantAs::type as() const { + FORCE_INLINE typename JsonVariantAs::type as() const { return _array.get(_index); } @@ -62,19 +59,18 @@ class JsonArraySubscript : public JsonVariantBase { // Replaces the value // - // bool set(TValue) + // bool set(const TValue&) // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template FORCE_INLINE bool set(const TValue& value) { return _array.set(_index, value); } // // bool set(TValue) - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - FORCE_INLINE bool set(const TValue* value) { + FORCE_INLINE bool set(TValue* value) { return _array.set(_index, value); } // @@ -91,21 +87,6 @@ class JsonArraySubscript : public JsonVariantBase { const size_t _index; }; -#if ARDUINOJSON_ENABLE_STD_STREAM -inline std::ostream& operator<<(std::ostream& os, - const JsonArraySubscript& source) { - return source.printTo(os); -} -#endif - -inline JsonArraySubscript JsonArray::operator[](size_t index) { - return JsonArraySubscript(*this, index); -} - -inline const JsonArraySubscript JsonArray::operator[](size_t index) const { - return JsonArraySubscript(*const_cast(this), index); -} - template inline JsonArraySubscript JsonVariantSubscripts::operator[]( size_t index) { @@ -118,7 +99,23 @@ inline const JsonArraySubscript JsonVariantSubscripts::operator[]( return impl()->template as()[index]; } -} // namespace ArduinoJson +#if ARDUINOJSON_ENABLE_STD_STREAM +inline std::ostream& operator<<(std::ostream& os, + const JsonArraySubscript& source) { + return source.printTo(os); +} +#endif +} + +inline Internals::JsonArraySubscript JsonArray::operator[](size_t index) { + return Internals::JsonArraySubscript(*this, index); +} + +inline const Internals::JsonArraySubscript JsonArray::operator[]( + size_t index) const { + return Internals::JsonArraySubscript(*const_cast(this), index); +} +} #ifdef _MSC_VER #pragma warning(pop) diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonBuffer.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonBuffer.hpp similarity index 74% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonBuffer.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonBuffer.hpp index 06bda0ef4..26101e086 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonBuffer.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonBuffer.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -41,20 +38,21 @@ class JsonBuffer : Internals::NonCopyable { // Duplicates a string // - // char* strdup(TValue); + // const char* strdup(TValue); // TValue = const std::string&, const String&, template - typename TypeTraits::EnableIf::value, - char *>::type - strdup(const TString &src) { + DEPRECATED("char* are duplicated, you don't need strdup() anymore") + typename Internals::EnableIf::value, + const char *>::type strdup(const TString &src) { return Internals::StringTraits::duplicate(src, this); } // - // char* strdup(TValue); - // TValue = const char*, const char[N], const FlashStringHelper* + // const char* strdup(TValue); + // TValue = char*, const char*, const FlashStringHelper* template - char *strdup(const TString *src) { - return Internals::StringTraits::duplicate(src, this); + DEPRECATED("char* are duplicated, you don't need strdup() anymore") + const char *strdup(TString *src) { + return Internals::StringTraits::duplicate(src, this); } // Allocates n bytes in the JsonBuffer. diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonBufferBase.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonBufferBase.hpp similarity index 88% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonBufferBase.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonBufferBase.hpp index 480cd8307..1e771bfdb 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonBufferBase.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonBufferBase.hpp @@ -1,15 +1,13 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once #include "Deserialization/JsonParser.hpp" namespace ArduinoJson { +namespace Internals { template class JsonBufferBase : public JsonBuffer { public: @@ -28,8 +26,8 @@ class JsonBufferBase : public JsonBuffer { // JsonArray& parseArray(TString); // TString = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - JsonArray &>::type + typename Internals::EnableIf::value, + JsonArray &>::type parseArray(const TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { return Internals::makeParser(that(), json, nestingLimit).parseArray(); @@ -65,8 +63,8 @@ class JsonBufferBase : public JsonBuffer { // JsonObject& parseObject(TString); // TString = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - JsonObject &>::type + typename Internals::EnableIf::value, + JsonObject &>::type parseObject(const TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { return Internals::makeParser(that(), json, nestingLimit).parseObject(); @@ -94,8 +92,8 @@ class JsonBufferBase : public JsonBuffer { // JsonVariant parse(TString); // TString = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - JsonVariant>::type + typename Internals::EnableIf::value, + JsonVariant>::type parse(const TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { return Internals::makeParser(that(), json, nestingLimit).parseVariant(); @@ -126,3 +124,4 @@ class JsonBufferBase : public JsonBuffer { } }; } +} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonBufferImpl.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonBufferImpl.hpp similarity index 72% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonBufferImpl.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonBufferImpl.hpp index 98d5de595..cdea374bb 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonBufferImpl.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonBufferImpl.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonObject.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonObject.hpp similarity index 57% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonObject.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonObject.hpp index a3e30ab27..caf698a3e 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonObject.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonObject.hpp @@ -1,16 +1,13 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once #include "Data/JsonBufferAllocated.hpp" #include "Data/List.hpp" #include "Data/ReferenceType.hpp" -#include "Data/ValueSetter.hpp" +#include "Data/ValueSaver.hpp" #include "JsonPair.hpp" #include "Serialization/JsonPrintable.hpp" #include "StringTraits/StringTraits.hpp" @@ -29,6 +26,10 @@ namespace ArduinoJson { // Forward declarations class JsonArray; class JsonBuffer; +namespace Internals { +template +class JsonObjectSubscript; +} // A dictionary of JsonVariant indexed by string (char*) // @@ -45,25 +46,24 @@ class JsonObject : public Internals::JsonPrintable, // Create an empty JsonArray attached to the specified JsonBuffer. // You should not use this constructor directly. // Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject(). - explicit JsonObject(JsonBuffer* buffer) throw() - : Internals::List(buffer) {} + explicit JsonObject(JsonBuffer* buffer) throw() + : Internals::List(buffer) {} // Gets or sets the value associated with the specified key. // // JsonObjectSubscript operator[](TKey) // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - JsonObjectSubscript >::type - operator[](const TString& key) { - return JsonObjectSubscript(*this, key); + Internals::JsonObjectSubscript operator[]( + const TString& key) { + return Internals::JsonObjectSubscript(*this, key); } // // JsonObjectSubscript operator[](TKey) - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[N], const FlashStringHelper* template - JsonObjectSubscript operator[](const TString* key) { - return JsonObjectSubscript(*this, key); + Internals::JsonObjectSubscript operator[](TString* key) { + return Internals::JsonObjectSubscript(*this, key); } // Gets the value associated with the specified key. @@ -71,21 +71,19 @@ class JsonObject : public Internals::JsonPrintable, // const JsonObjectSubscript operator[](TKey) const; // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf< - !TypeTraits::IsArray::value, - const JsonObjectSubscript >::type - operator[](const TString& key) const { - return JsonObjectSubscript(*const_cast(this), - key); + const Internals::JsonObjectSubscript operator[]( + const TString& key) const { + return Internals::JsonObjectSubscript( + *const_cast(this), key); } // // const JsonObjectSubscript operator[](TKey) const; // TKey = const char*, const char[N], const FlashStringHelper* template - const JsonObjectSubscript operator[]( - const TString* key) const { - return JsonObjectSubscript(*const_cast(this), - key); + const Internals::JsonObjectSubscript operator[]( + TString* key) const { + return Internals::JsonObjectSubscript( + *const_cast(this), key); } // Sets the specified key with the specified value. @@ -93,43 +91,35 @@ class JsonObject : public Internals::JsonPrintable, // bool set(TKey, TValue); // TKey = const std::string&, const String& // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value && - !TypeTraits::IsArray::value, - bool>::type - set(const TString& key, const TValue& value) { + bool set(const TString& key, const TValue& value) { return set_impl(key, value); } // // bool set(TKey, TValue); // TKey = const std::string&, const String& - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - typename TypeTraits::EnableIf::value, - bool>::type - set(const TString& key, const TValue* value) { - return set_impl(key, value); + bool set(const TString& key, TValue* value) { + return set_impl(key, value); } // - // bool set(TKey, TValue); - // TKey = const char*, const char[N], const FlashStringHelper* + // bool set(TKey, const TValue&); + // TKey = char*, const char*, const FlashStringHelper* // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value, bool>::type - set(const TString* key, const TValue& value) { - return set_impl(key, value); + bool set(TString* key, const TValue& value) { + return set_impl(key, value); } // // bool set(TKey, TValue); - // TKey = const char*, const char[N], const FlashStringHelper* - // TValue = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - bool set(const TString* key, const TValue* value) { - return set_impl(key, value); + bool set(TString* key, TValue* value) { + return set_impl(key, value); } // // bool set(TKey, TValue, uint8_t decimals); @@ -137,50 +127,43 @@ class JsonObject : public Internals::JsonPrintable, // TValue = float, double template DEPRECATED("Second argument is not supported anymore") - typename TypeTraits::EnableIf::value && - !TypeTraits::IsArray::value, - bool>::type + typename Internals::EnableIf::value, + bool>::type set(const TString& key, TValue value, uint8_t) { return set_impl(key, JsonVariant(value)); } // // bool set(TKey, TValue, uint8_t decimals); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, const FlashStringHelper* // TValue = float, double template DEPRECATED("Second argument is not supported anymore") - typename TypeTraits::EnableIf::value, - bool>::type - set(const TString* key, TValue value, uint8_t) { - return set_impl(key, - JsonVariant(value)); + typename Internals::EnableIf::value, + bool>::type + set(TString* key, TValue value, uint8_t) { + return set_impl(key, JsonVariant(value)); } // Gets the value associated with the specified key. // - // TValue get(TKey); + // TValue get(TKey) const; // TKey = const std::string&, const String& // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf< - !TypeTraits::IsArray::value, - typename Internals::JsonVariantAs::type>::type - get(const TString& key) const { + typename Internals::JsonVariantAs::type get( + const TString& key) const { return get_impl(key); } // - // TValue get(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TValue get(TKey) const; + // TKey = char*, const char*, const FlashStringHelper* // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename Internals::JsonVariantAs::type get( - const TString* key) const { - return get_impl(key); + typename Internals::JsonVariantAs::type get(TString* key) const { + return get_impl(key); } // Checks the type of the value associated with the specified key. @@ -189,23 +172,19 @@ class JsonObject : public Internals::JsonPrintable, // bool is(TKey) const; // TKey = const std::string&, const String& // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value, - bool>::type - is(const TString& key) const { + bool is(const TString& key) const { return is_impl(key); } // // bool is(TKey) const; - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, const FlashStringHelper* // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - bool is(const TString* key) const { - return is_impl(key); + bool is(TString* key) const { + return is_impl(key); } // Creates and adds a JsonArray. @@ -213,16 +192,14 @@ class JsonObject : public Internals::JsonPrintable, // JsonArray& createNestedArray(TKey); // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - JsonArray&>::type - createNestedArray(const TString& key) { + JsonArray& createNestedArray(const TString& key) { return createNestedArray_impl(key); } // JsonArray& createNestedArray(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[], const FlashStringHelper* template - JsonArray& createNestedArray(const TString* key) { - return createNestedArray_impl(key); + JsonArray& createNestedArray(TString* key) { + return createNestedArray_impl(key); } // Creates and adds a JsonObject. @@ -230,17 +207,15 @@ class JsonObject : public Internals::JsonPrintable, // JsonObject& createNestedObject(TKey); // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - JsonObject&>::type - createNestedObject(const TString& key) { + JsonObject& createNestedObject(const TString& key) { return createNestedObject_impl(key); } // // JsonObject& createNestedObject(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[], const FlashStringHelper* template - JsonObject& createNestedObject(const TString* key) { - return createNestedObject_impl(key); + JsonObject& createNestedObject(TString* key) { + return createNestedObject_impl(key); } // Tells weither the specified key is present and associated with a value. @@ -248,17 +223,15 @@ class JsonObject : public Internals::JsonPrintable, // bool containsKey(TKey); // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - bool>::type - containsKey(const TString& key) const { + bool containsKey(const TString& key) const { return findKey(key) != end(); } // // bool containsKey(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[], const FlashStringHelper* template - bool containsKey(const TString* key) const { - return findKey(key) != end(); + bool containsKey(TString* key) const { + return findKey(key) != end(); } // Removes the specified key and the associated value. @@ -266,17 +239,15 @@ class JsonObject : public Internals::JsonPrintable, // void remove(TKey); // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - void>::type - remove(const TString& key) { + void remove(const TString& key) { remove(findKey(key)); } // // void remove(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[], const FlashStringHelper* template - void remove(const TString* key) { - remove(findKey(key)); + void remove(TString* key) { + remove(findKey(key)); } // // void remove(iterator) @@ -315,16 +286,22 @@ class JsonObject : public Internals::JsonPrintable, template bool set_impl(TStringRef key, TValueRef value) { + // ignore null key + if (Internals::StringTraits::is_null(key)) return false; + + // search a matching key iterator it = findKey(key); if (it == end()) { + // add the key it = Internals::List::add(); if (it == end()) return false; - bool key_ok = - Internals::ValueSetter::set(_buffer, it->key, key); + Internals::ValueSaver::save(_buffer, it->key, key); if (!key_ok) return false; } - return Internals::ValueSetter::set(_buffer, it->value, value); + + // save the value + return Internals::ValueSaver::save(_buffer, it->value, value); } template @@ -347,5 +324,5 @@ struct JsonVariantDefault { return JsonObject::invalid(); } }; -} -} +} // namespace Internals +} // namespace ArduinoJson diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonObjectImpl.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonObjectImpl.hpp similarity index 79% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonObjectImpl.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonObjectImpl.hpp index 9741bfadd..e7689b507 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonObjectImpl.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonObjectImpl.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonObjectSubscript.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonObjectSubscript.hpp similarity index 66% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonObjectSubscript.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonObjectSubscript.hpp index 99dfe7cd0..6ac476370 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonObjectSubscript.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonObjectSubscript.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -17,6 +14,7 @@ #endif namespace ArduinoJson { +namespace Internals { template class JsonObjectSubscript @@ -34,23 +32,20 @@ class JsonObjectSubscript // Set the specified value // - // operator=(TValue); + // operator=(const TValue&); // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - FORCE_INLINE - typename TypeTraits::EnableIf::value, - this_type&>::type - operator=(const TValue& src) { + FORCE_INLINE typename EnableIf::value, this_type&>::type + operator=(const TValue& src) { _object.set(_key, src); return *this; } // // operator=(TValue); - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - FORCE_INLINE this_type& operator=(const TValue* src) { + FORCE_INLINE this_type& operator=(TValue* src) { _object.set(_key, src); return *this; } @@ -60,7 +55,7 @@ class JsonObjectSubscript } template - FORCE_INLINE typename Internals::JsonVariantAs::type as() const { + FORCE_INLINE typename JsonVariantAs::type as() const { return _object.get(_key); } @@ -71,20 +66,17 @@ class JsonObjectSubscript // Sets the specified value. // - // bool set(TValue); + // bool set(const TValue&); // TValue = bool, char, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - FORCE_INLINE - typename TypeTraits::EnableIf::value, - bool>::type - set(const TValue& value) { + FORCE_INLINE typename EnableIf::value, bool>::type set( + const TValue& value) { return _object.set(_key, value); } // // bool set(TValue); - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char, const FlashStringHelper* template FORCE_INLINE bool set(const TValue* value) { return _object.set(_key, value); @@ -110,7 +102,8 @@ inline std::ostream& operator<<(std::ostream& os, return source.printTo(os); } #endif -} // namespace ArduinoJson +} +} #ifdef _MSC_VER #pragma warning(pop) diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonPair.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonPair.hpp similarity index 53% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonPair.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonPair.hpp index 5a32601c0..417243045 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonPair.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonPair.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariant.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariant.hpp similarity index 72% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariant.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariant.hpp index 9037d54d1..43c51b770 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariant.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariant.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -39,7 +36,7 @@ class JsonObject; // - a char, short, int or a long (signed or unsigned) // - a string (const char*) // - a reference to a JsonArray or JsonObject -class JsonVariant : public JsonVariantBase { +class JsonVariant : public Internals::JsonVariantBase { template friend class Internals::JsonSerializer; @@ -59,8 +56,8 @@ class JsonVariant : public JsonVariantBase { // JsonVariant(double value); // JsonVariant(float value); template - JsonVariant(T value, typename TypeTraits::EnableIf< - TypeTraits::IsFloatingPoint::value>::type * = 0) { + JsonVariant(T value, typename Internals::EnableIf< + Internals::IsFloatingPoint::value>::type * = 0) { using namespace Internals; _type = JSON_FLOAT; _content.asFloat = static_cast(value); @@ -68,8 +65,8 @@ class JsonVariant : public JsonVariantBase { template DEPRECATED("Second argument is not supported anymore") JsonVariant(T value, uint8_t, - typename TypeTraits::EnableIf< - TypeTraits::IsFloatingPoint::value>::type * = 0) { + typename Internals::EnableIf< + Internals::IsFloatingPoint::value>::type * = 0) { using namespace Internals; _type = JSON_FLOAT; _content.asFloat = static_cast(value); @@ -82,9 +79,11 @@ class JsonVariant : public JsonVariantBase { // JsonVariant(signed long) // JsonVariant(signed char) template - JsonVariant(T value, typename TypeTraits::EnableIf< - TypeTraits::IsSignedIntegral::value || - TypeTraits::IsSame::value>::type * = 0) { + JsonVariant( + T value, + typename Internals::EnableIf::value || + Internals::IsSame::value>::type * = + 0) { using namespace Internals; if (value >= 0) { _type = JSON_POSITIVE_INTEGER; @@ -99,8 +98,8 @@ class JsonVariant : public JsonVariantBase { // JsonVariant(unsigned long) template JsonVariant(T value, - typename TypeTraits::EnableIf< - TypeTraits::IsUnsignedIntegral::value>::type * = 0) { + typename Internals::EnableIf< + Internals::IsUnsignedIntegral::value>::type * = 0) { using namespace Internals; _type = JSON_POSITIVE_INTEGER; _content.asInteger = static_cast(value); @@ -113,14 +112,14 @@ class JsonVariant : public JsonVariantBase { template JsonVariant( const TChar *value, - typename TypeTraits::EnableIf::value>::type * = + typename Internals::EnableIf::value>::type * = 0) { _type = Internals::JSON_STRING; _content.asString = reinterpret_cast(value); } // Create a JsonVariant containing an unparsed string - JsonVariant(RawJson value) { + JsonVariant(Internals::RawJsonString value) { _type = Internals::JSON_UNPARSED; _content.asString = value; } @@ -147,14 +146,13 @@ class JsonVariant : public JsonVariantBase { // unsigned int as() const; // unsigned long as() const; template - const typename TypeTraits::EnableIf::value, T>::type + const typename Internals::EnableIf::value, T>::type as() const { return variantAsInteger(); } // bool as() const template - const typename TypeTraits::EnableIf::value, - T>::type + const typename Internals::EnableIf::value, T>::type as() const { return variantAsInteger() != 0; } @@ -162,8 +160,8 @@ class JsonVariant : public JsonVariantBase { // double as() const; // float as() const; template - const typename TypeTraits::EnableIf::value, - T>::type + const typename Internals::EnableIf::value, + T>::type as() const { return variantAsFloat(); } @@ -171,9 +169,9 @@ class JsonVariant : public JsonVariantBase { // const char* as() const; // const char* as() const; template - typename TypeTraits::EnableIf::value || - TypeTraits::IsSame::value, - const char *>::type + typename Internals::EnableIf::value || + Internals::IsSame::value, + const char *>::type as() const { return variantAsString(); } @@ -181,7 +179,7 @@ class JsonVariant : public JsonVariantBase { // std::string as() const; // String as() const; template - typename TypeTraits::EnableIf::has_append, T>::type + typename Internals::EnableIf::has_append, T>::type as() const { const char *cstr = variantAsString(); if (cstr) return T(cstr); @@ -193,9 +191,9 @@ class JsonVariant : public JsonVariantBase { // JsonArray& as const; // JsonArray& as const; template - typename TypeTraits::EnableIf< - TypeTraits::IsSame::type, - JsonArray>::value, + typename Internals::EnableIf< + Internals::IsSame::type, + JsonArray>::value, JsonArray &>::type as() const { return variantAsArray(); @@ -203,9 +201,9 @@ class JsonVariant : public JsonVariantBase { // // const JsonArray& as const; template - typename TypeTraits::EnableIf< - TypeTraits::IsSame::type, - const JsonArray>::value, + typename Internals::EnableIf< + Internals::IsSame::type, + const JsonArray>::value, const JsonArray &>::type as() const { return variantAsArray(); @@ -214,9 +212,9 @@ class JsonVariant : public JsonVariantBase { // JsonObject& as const; // JsonObject& as const; template - typename TypeTraits::EnableIf< - TypeTraits::IsSame::type, - JsonObject>::value, + typename Internals::EnableIf< + Internals::IsSame::type, + JsonObject>::value, JsonObject &>::type as() const { return variantAsObject(); @@ -225,9 +223,9 @@ class JsonVariant : public JsonVariantBase { // JsonObject& as const; // JsonObject& as const; template - typename TypeTraits::EnableIf< - TypeTraits::IsSame::type, - const JsonObject>::value, + typename Internals::EnableIf< + Internals::IsSame::type, + const JsonObject>::value, const JsonObject &>::type as() const { return variantAsObject(); @@ -235,8 +233,8 @@ class JsonVariant : public JsonVariantBase { // // JsonVariant as const; template - typename TypeTraits::EnableIf::value, - T>::type + typename Internals::EnableIf::value, + T>::type as() const { return *this; } @@ -254,33 +252,34 @@ class JsonVariant : public JsonVariantBase { // bool is() const; // bool is() const; template - typename TypeTraits::EnableIf::value, bool>::type - is() const { + typename Internals::EnableIf::value, bool>::type is() + const { return variantIsInteger(); } // // bool is() const; // bool is() const; template - typename TypeTraits::EnableIf::value, - bool>::type + typename Internals::EnableIf::value, bool>::type is() const { return variantIsFloat(); } // // bool is() const template - typename TypeTraits::EnableIf::value, bool>::type + typename Internals::EnableIf::value, bool>::type is() const { return variantIsBoolean(); } // // bool is() const; // bool is() const; + // bool is() const; template - typename TypeTraits::EnableIf::value || - TypeTraits::IsSame::value, - bool>::type + typename Internals::EnableIf::value || + Internals::IsSame::value || + Internals::StringTraits::has_append, + bool>::type is() const { return variantIsString(); } @@ -289,11 +288,10 @@ class JsonVariant : public JsonVariantBase { // bool is const; // bool is const; template - typename TypeTraits::EnableIf< - TypeTraits::IsSame< - typename TypeTraits::RemoveConst< - typename TypeTraits::RemoveReference::type>::type, - JsonArray>::value, + typename Internals::EnableIf< + Internals::IsSame::type>::type, + JsonArray>::value, bool>::type is() const { return variantIsArray(); @@ -303,11 +301,10 @@ class JsonVariant : public JsonVariantBase { // bool is const; // bool is const; template - typename TypeTraits::EnableIf< - TypeTraits::IsSame< - typename TypeTraits::RemoveConst< - typename TypeTraits::RemoveReference::type>::type, - JsonObject>::value, + typename Internals::EnableIf< + Internals::IsSame::type>::type, + JsonObject>::value, bool>::type is() const { return variantIsObject(); @@ -357,4 +354,4 @@ DEPRECATED("Decimal places are ignored, use the double value instead") inline JsonVariant double_with_n_digits(double value, uint8_t) { return JsonVariant(value); } -} +} // namespace ArduinoJson diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantBase.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantBase.hpp similarity index 59% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantBase.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantBase.hpp index a010e253f..44acf2e14 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantBase.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantBase.hpp @@ -1,23 +1,24 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once #include "JsonVariantCasts.hpp" #include "JsonVariantComparisons.hpp" +#include "JsonVariantOr.hpp" #include "JsonVariantSubscripts.hpp" #include "Serialization/JsonPrintable.hpp" namespace ArduinoJson { +namespace Internals { template -class JsonVariantBase : public Internals::JsonPrintable, +class JsonVariantBase : public JsonPrintable, public JsonVariantCasts, public JsonVariantComparisons, + public JsonVariantOr, public JsonVariantSubscripts, - public TypeTraits::JsonVariantTag {}; + public JsonVariantTag {}; +} } diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantCasts.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantCasts.hpp similarity index 89% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantCasts.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantCasts.hpp index b3b41b4ba..68f5bd7dd 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantCasts.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantCasts.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -11,6 +8,7 @@ #include "Polyfills/attributes.hpp" namespace ArduinoJson { +namespace Internals { template class JsonVariantCasts { @@ -58,3 +56,4 @@ class JsonVariantCasts { } }; } +} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantComparisons.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantComparisons.hpp similarity index 75% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantComparisons.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantComparisons.hpp index eb0ef5c2c..47f9d6322 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantComparisons.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantComparisons.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -12,6 +9,7 @@ #include "TypeTraits/IsVariant.hpp" namespace ArduinoJson { +namespace Internals { template class JsonVariantComparisons { @@ -23,10 +21,8 @@ class JsonVariantComparisons { } template - friend - typename TypeTraits::EnableIf::value, - bool>::type - operator==(TComparand comparand, const JsonVariantComparisons &variant) { + friend typename EnableIf::value, bool>::type + operator==(TComparand comparand, const JsonVariantComparisons &variant) { return variant.equals(comparand); } @@ -37,10 +33,8 @@ class JsonVariantComparisons { } template - friend - typename TypeTraits::EnableIf::value, - bool>::type - operator!=(TComparand comparand, const JsonVariantComparisons &variant) { + friend typename EnableIf::value, bool>::type + operator!=(TComparand comparand, const JsonVariantComparisons &variant) { return !variant.equals(comparand); } @@ -97,7 +91,7 @@ class JsonVariantComparisons { } template - const typename Internals::JsonVariantAs::type as() const { + const typename JsonVariantAs::type as() const { return impl()->template as(); } @@ -107,17 +101,16 @@ class JsonVariantComparisons { } template - typename TypeTraits::EnableIf::value, - bool>::type - equals(const TString &comparand) const { + typename EnableIf::has_equals, bool>::type equals( + const TString &comparand) const { const char *value = as(); - return Internals::StringTraits::equals(comparand, value); + return StringTraits::equals(comparand, value); } template - typename TypeTraits::EnableIf::value && - !TypeTraits::IsString::value, - bool>::type + typename EnableIf::value && + !StringTraits::has_equals, + bool>::type equals(const TComparand &comparand) const { return as() == comparand; } @@ -136,9 +129,11 @@ class JsonVariantComparisons { if (is() && right.template is()) return as() == right.template as(); if (is() && right.template is()) - return strcmp(as(), right.template as()) == 0; + return StringTraits::equals(as(), + right.template as()); return false; } }; -} +} // namespace Internals +} // namespace ArduinoJson diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantImpl.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantImpl.hpp similarity index 87% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantImpl.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantImpl.hpp index eb6a4735d..31f96ce1a 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantImpl.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantImpl.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -61,7 +58,7 @@ inline T JsonVariant::variantAsInteger() const { return T(~_content.asInteger + 1); case JSON_STRING: case JSON_UNPARSED: - return Polyfills::parseInteger(_content.asString); + return parseInteger(_content.asString); default: return T(_content.asFloat); } @@ -89,7 +86,7 @@ inline T JsonVariant::variantAsFloat() const { return -static_cast(_content.asInteger); case JSON_STRING: case JSON_UNPARSED: - return Polyfills::parseFloat(_content.asString); + return parseFloat(_content.asString); default: return static_cast(_content.asFloat); } @@ -109,7 +106,7 @@ inline bool JsonVariant::variantIsInteger() const { using namespace Internals; return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER || - (_type == JSON_UNPARSED && Polyfills::isInteger(_content.asString)); + (_type == JSON_UNPARSED && isInteger(_content.asString)); } inline bool JsonVariant::variantIsFloat() const { @@ -117,7 +114,7 @@ inline bool JsonVariant::variantIsFloat() const { return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER || - (_type == JSON_UNPARSED && Polyfills::isFloat(_content.asString)); + (_type == JSON_UNPARSED && isFloat(_content.asString)); } #if ARDUINOJSON_ENABLE_STD_STREAM diff --git a/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantOr.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantOr.hpp new file mode 100644 index 000000000..d8022fcb2 --- /dev/null +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantOr.hpp @@ -0,0 +1,52 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "Data/JsonVariantAs.hpp" +#include "Polyfills/attributes.hpp" +#include "TypeTraits/EnableIf.hpp" +#include "TypeTraits/IsIntegral.hpp" + +namespace ArduinoJson { +namespace Internals { + +template +class JsonVariantOr { + public: + // Returns the default value if the JsonVariant is undefined of incompatible + template + typename EnableIf::value, T>::type operator|( + const T &defaultValue) const { + if (impl()->template is()) + return impl()->template as(); + else + return defaultValue; + } + + // Returns the default value if the JsonVariant is undefined of incompatible + // Special case for string: null is treated as undefined + const char *operator|(const char *defaultValue) const { + const char *value = impl()->template as(); + return value ? value : defaultValue; + } + + // Returns the default value if the JsonVariant is undefined of incompatible + // Special case for integers: we also accept double + template + typename EnableIf::value, Integer>::type operator|( + const Integer &defaultValue) const { + if (impl()->template is()) + return impl()->template as(); + else + return defaultValue; + } + + private: + const TImpl *impl() const { + return static_cast(this); + } +}; +} // namespace Internals +} // namespace ArduinoJson diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantSubscripts.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantSubscripts.hpp similarity index 70% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantSubscripts.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantSubscripts.hpp index 2143236a6..279ee019f 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/JsonVariantSubscripts.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/JsonVariantSubscripts.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -13,6 +10,7 @@ #include "TypeTraits/EnableIf.hpp" namespace ArduinoJson { +namespace Internals { // Forward declarations. class JsonArraySubscript; @@ -44,19 +42,18 @@ class JsonVariantSubscripts { // const JsonObjectSubscript operator[](TKey) const; // TKey = const std::string&, const String& template - FORCE_INLINE typename TypeTraits::EnableIf< - Internals::StringTraits::has_equals, - const JsonObjectSubscript >::type - operator[](const TString &key) const { + FORCE_INLINE + typename EnableIf::has_equals, + const JsonObjectSubscript >::type + operator[](const TString &key) const { return impl()->template as()[key]; } // // const JsonObjectSubscript operator[](TKey) const; // TKey = const std::string&, const String& template - FORCE_INLINE typename TypeTraits::EnableIf< - Internals::StringTraits::has_equals, - JsonObjectSubscript >::type + FORCE_INLINE typename EnableIf::has_equals, + JsonObjectSubscript >::type operator[](const TString &key) { return impl()->template as()[key]; } @@ -64,9 +61,8 @@ class JsonVariantSubscripts { // JsonObjectSubscript operator[](TKey); // TKey = const char*, const char[N], const FlashStringHelper* template - FORCE_INLINE typename TypeTraits::EnableIf< - Internals::StringTraits::has_equals, - JsonObjectSubscript >::type + FORCE_INLINE typename EnableIf::has_equals, + JsonObjectSubscript >::type operator[](const TString *key) { return impl()->template as()[key]; } @@ -74,10 +70,10 @@ class JsonVariantSubscripts { // JsonObjectSubscript operator[](TKey); // TKey = const char*, const char[N], const FlashStringHelper* template - FORCE_INLINE typename TypeTraits::EnableIf< - Internals::StringTraits::has_equals, - const JsonObjectSubscript >::type - operator[](const TString *key) const { + FORCE_INLINE + typename EnableIf::has_equals, + const JsonObjectSubscript >::type + operator[](const TString *key) const { return impl()->template as()[key]; } @@ -87,3 +83,4 @@ class JsonVariantSubscripts { } }; } +} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/attributes.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/attributes.hpp similarity index 74% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/attributes.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/attributes.hpp index e4f9406ac..b49091ddc 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/attributes.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/attributes.hpp @@ -1,15 +1,12 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once #ifdef _MSC_VER // Visual Studio -#define FORCE_INLINE __forceinline +#define FORCE_INLINE // __forceinline causes C4714 when returning std::string #define NO_INLINE __declspec(noinline) #define DEPRECATED(msg) __declspec(deprecated(msg)) diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/ctype.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/ctype.hpp similarity index 50% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/ctype.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/ctype.hpp index f13e3edf6..2d52703cd 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/ctype.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/ctype.hpp @@ -1,14 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once namespace ArduinoJson { -namespace Polyfills { +namespace Internals { inline bool isdigit(char c) { return '0' <= c && c <= '9'; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/isFloat.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/isFloat.hpp similarity index 75% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/isFloat.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/isFloat.hpp index f6b9c97d9..973b89fe9 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/isFloat.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/isFloat.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -11,7 +8,7 @@ #include "./ctype.hpp" namespace ArduinoJson { -namespace Polyfills { +namespace Internals { inline bool isFloat(const char* s) { if (!s) return false; diff --git a/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/isInteger.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/isInteger.hpp new file mode 100644 index 000000000..8049079a7 --- /dev/null +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/isInteger.hpp @@ -0,0 +1,19 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "./ctype.hpp" + +namespace ArduinoJson { +namespace Internals { + +inline bool isInteger(const char* s) { + if (!s || !*s) return false; + if (issign(*s)) s++; + while (isdigit(*s)) s++; + return *s == '\0'; +} +} // namespace Internals +} // namespace ArduinoJson diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/math.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/math.hpp similarity index 52% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/math.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/math.hpp index 9dbd161d6..48773edd2 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/math.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/math.hpp @@ -1,14 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once namespace ArduinoJson { -namespace Polyfills { +namespace Internals { template bool isNaN(T x) { return x != x; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/parseFloat.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/parseFloat.hpp similarity index 89% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/parseFloat.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/parseFloat.hpp index e5d99f1bf..49b0f6fcd 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/parseFloat.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/parseFloat.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -12,11 +9,11 @@ #include "./math.hpp" namespace ArduinoJson { -namespace Polyfills { +namespace Internals { template inline T parseFloat(const char* s) { - typedef TypeTraits::FloatTraits traits; + typedef FloatTraits traits; typedef typename traits::mantissa_type mantissa_t; typedef typename traits::exponent_type exponent_t; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/parseInteger.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/parseInteger.hpp similarity index 75% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/parseInteger.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/parseInteger.hpp index 023d7bcbd..e8f197494 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Polyfills/parseInteger.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Polyfills/parseInteger.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -13,7 +10,7 @@ #include "./ctype.hpp" namespace ArduinoJson { -namespace Polyfills { +namespace Internals { template T parseInteger(const char *s) { if (!s) return 0; // NULL diff --git a/lib/ArduinoJson-5.13.4/src/ArduinoJson/RawJson.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/RawJson.hpp new file mode 100644 index 000000000..4beb980ee --- /dev/null +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/RawJson.hpp @@ -0,0 +1,46 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +namespace ArduinoJson { + +namespace Internals { +// A special type of data that can be used to insert pregenerated JSON portions. +template +class RawJsonString { + public: + explicit RawJsonString(T str) : _str(str) {} + operator T() const { + return _str; + } + + private: + T _str; +}; + +template +struct StringTraits, void> { + static bool is_null(RawJsonString source) { + return StringTraits::is_null(static_cast(source)); + } + + typedef RawJsonString duplicate_t; + + template + static duplicate_t duplicate(RawJsonString source, Buffer* buffer) { + return duplicate_t(StringTraits::duplicate(source, buffer)); + } + + static const bool has_append = false; + static const bool has_equals = false; + static const bool should_duplicate = StringTraits::should_duplicate; +}; +} + +template +inline Internals::RawJsonString RawJson(T str) { + return Internals::RawJsonString(str); +} +} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/DummyPrint.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/DummyPrint.hpp similarity index 64% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/DummyPrint.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/DummyPrint.hpp index 656aa9ed6..9fdf2d6a0 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/DummyPrint.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/DummyPrint.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp similarity index 80% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp index a344588de..41be6392c 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/FloatParts.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/FloatParts.hpp similarity index 91% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/FloatParts.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/FloatParts.hpp index fa650723d..c14e3b553 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/FloatParts.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/FloatParts.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -59,7 +56,7 @@ struct FloatParts { } static int16_t normalize(TFloat& value) { - typedef TypeTraits::FloatTraits traits; + typedef FloatTraits traits; int16_t powersOf10 = 0; int8_t index = sizeof(TFloat) == 8 ? 8 : 5; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/IndentedPrint.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/IndentedPrint.hpp similarity index 89% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/IndentedPrint.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/IndentedPrint.hpp index 66ca6ac2f..864f9aaa4 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/IndentedPrint.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/IndentedPrint.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonPrintable.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonPrintable.hpp similarity index 80% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonPrintable.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonPrintable.hpp index f33e5584e..43d413a85 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonPrintable.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonPrintable.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -32,9 +29,8 @@ template class JsonPrintable { public: template - typename TypeTraits::EnableIf::value, - size_t>::type - printTo(Print &print) const { + typename EnableIf::has_append, size_t>::type printTo( + Print &print) const { JsonWriter writer(print); JsonSerializer >::serialize(downcast(), writer); return writer.bytesWritten(); @@ -59,8 +55,8 @@ class JsonPrintable { } template - typename TypeTraits::EnableIf::has_append, size_t>::type - printTo(TString &str) const { + typename EnableIf::has_append, size_t>::type printTo( + TString &str) const { DynamicStringBuilder sb(str); return printTo(sb); } @@ -82,15 +78,14 @@ class JsonPrintable { } template - typename TypeTraits::EnableIf::value, - size_t>::type + typename EnableIf::has_append, size_t>::type prettyPrintTo(Print &print) const { IndentedPrint indentedPrint(print); return prettyPrintTo(indentedPrint); } template - typename TypeTraits::EnableIf::has_append, size_t>::type + typename EnableIf::has_append, size_t>::type prettyPrintTo(TString &str) const { DynamicStringBuilder sb(str); return prettyPrintTo(sb); diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonSerializer.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonSerializer.hpp similarity index 79% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonSerializer.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonSerializer.hpp index 86ed73ee1..0cb537f7d 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonSerializer.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonSerializer.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -12,14 +9,15 @@ namespace ArduinoJson { class JsonArray; -class JsonArraySubscript; class JsonObject; -template -class JsonObjectSubscript; class JsonVariant; namespace Internals { +class JsonArraySubscript; +template +class JsonObjectSubscript; + template class JsonSerializer { public: diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonSerializerImpl.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonSerializerImpl.hpp similarity index 94% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonSerializerImpl.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonSerializerImpl.hpp index f544488af..0faae2769 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonSerializerImpl.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonSerializerImpl.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonWriter.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonWriter.hpp similarity index 91% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonWriter.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonWriter.hpp index 2d54a2a0b..146d51dcb 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/JsonWriter.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/JsonWriter.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -82,14 +79,14 @@ class JsonWriter { template void writeFloat(TFloat value) { - if (Polyfills::isNaN(value)) return writeRaw("NaN"); + if (isNaN(value)) return writeRaw("NaN"); if (value < 0.0) { writeRaw('-'); value = -value; } - if (Polyfills::isInfinity(value)) return writeRaw("Infinity"); + if (isInfinity(value)) return writeRaw("Infinity"); FloatParts parts(value); diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/Prettyfier.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/Prettyfier.hpp similarity index 93% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/Prettyfier.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/Prettyfier.hpp index 377138b4f..8b4f0d2eb 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/Prettyfier.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/Prettyfier.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/StaticStringBuilder.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/StaticStringBuilder.hpp similarity index 77% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/StaticStringBuilder.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/StaticStringBuilder.hpp index 2df932fd4..9617bbd97 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/StaticStringBuilder.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/StaticStringBuilder.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/StreamPrintAdapter.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/StreamPrintAdapter.hpp similarity index 77% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/StreamPrintAdapter.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/StreamPrintAdapter.hpp index 9c2f86fd7..60f0af4a3 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/Serialization/StreamPrintAdapter.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/Serialization/StreamPrintAdapter.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StaticJsonBuffer.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StaticJsonBuffer.hpp similarity index 89% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/StaticJsonBuffer.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/StaticJsonBuffer.hpp index 8eaa4bb53..267d9d018 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StaticJsonBuffer.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StaticJsonBuffer.hpp @@ -1,15 +1,13 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once #include "JsonBufferBase.hpp" namespace ArduinoJson { +namespace Internals { class StaticJsonBufferBase : public JsonBufferBase { public: @@ -93,6 +91,7 @@ class StaticJsonBufferBase : public JsonBufferBase { size_t _capacity; size_t _size; }; +} #if defined(__clang__) #pragma clang diagnostic push @@ -108,9 +107,10 @@ class StaticJsonBufferBase : public JsonBufferBase { // The template paramenter CAPACITY specifies the capacity of the buffer in // bytes. template -class StaticJsonBuffer : public StaticJsonBufferBase { +class StaticJsonBuffer : public Internals::StaticJsonBufferBase { public: - explicit StaticJsonBuffer() : StaticJsonBufferBase(_buffer, CAPACITY) {} + explicit StaticJsonBuffer() + : Internals::StaticJsonBufferBase(_buffer, CAPACITY) {} private: char _buffer[CAPACITY]; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/ArduinoStream.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/ArduinoStream.hpp similarity index 64% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/ArduinoStream.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/ArduinoStream.hpp index 87d1672d5..5db0852b8 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/ArduinoStream.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/ArduinoStream.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -46,14 +43,17 @@ struct ArduinoStreamTraits { return c; } }; + + static const bool has_append = false; + static const bool has_equals = false; }; template -struct StringTraits::type>::value>::type> +struct StringTraits< + TStream, + // match any type that is derived from Stream: + typename EnableIf< + IsBaseOf::type>::value>::type> : ArduinoStreamTraits {}; } } diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/CharPointer.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/CharPointer.hpp similarity index 54% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/CharPointer.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/CharPointer.hpp index 203e3924e..98896ccfb 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/CharPointer.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/CharPointer.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -33,26 +30,35 @@ struct CharPointerTraits { }; static bool equals(const TChar* str, const char* expected) { - return strcmp(reinterpret_cast(str), expected) == 0; + const char* actual = reinterpret_cast(str); + if (!actual || !expected) return actual == expected; + return strcmp(actual, expected) == 0; } + static bool is_null(const TChar* str) { + return !str; + } + + typedef const char* duplicate_t; + template - static char* duplicate(const TChar* str, Buffer* buffer) { + static duplicate_t duplicate(const TChar* str, Buffer* buffer) { if (!str) return NULL; size_t size = strlen(reinterpret_cast(str)) + 1; void* dup = buffer->alloc(size); if (dup != NULL) memcpy(dup, str, size); - return static_cast(dup); + return static_cast(dup); } static const bool has_append = false; static const bool has_equals = true; - static const bool should_duplicate = false; + static const bool should_duplicate = !IsConst::value; }; +// char*, unsigned char*, signed char* +// const char*, const unsigned char*, const signed char* template -struct StringTraits::value>::type> +struct StringTraits::value>::type> : CharPointerTraits {}; -} -} +} // namespace Internals +} // namespace ArduinoJson diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/FlashString.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/FlashString.hpp similarity index 64% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/FlashString.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/FlashString.hpp index 37e36b8d2..0701b9ba2 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/FlashString.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/FlashString.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -34,23 +31,31 @@ struct StringTraits { }; static bool equals(const __FlashStringHelper* str, const char* expected) { - return strcmp_P(expected, (const char*)str) == 0; + const char* actual = reinterpret_cast(str); + if (!actual || !expected) return actual == expected; + return strcmp_P(expected, actual) == 0; } + static bool is_null(const __FlashStringHelper* str) { + return !str; + } + + typedef const char* duplicate_t; + template - static char* duplicate(const __FlashStringHelper* str, Buffer* buffer) { + static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) { if (!str) return NULL; size_t size = strlen_P((const char*)str) + 1; void* dup = buffer->alloc(size); if (dup != NULL) memcpy_P(dup, (const char*)str, size); - return static_cast(dup); + return static_cast(dup); } static const bool has_append = false; static const bool has_equals = true; static const bool should_duplicate = true; }; -} -} +} // namespace Internals +} // namespace ArduinoJson #endif diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/StdStream.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/StdStream.hpp similarity index 63% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/StdStream.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/StdStream.hpp index 35049d941..227c74406 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/StdStream.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/StdStream.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -45,14 +42,17 @@ struct StdStreamTraits { return _stream.eof() ? '\0' : static_cast(_stream.get()); } }; + + static const bool has_append = false; + static const bool has_equals = false; }; template -struct StringTraits::type>::value>::type> +struct StringTraits< + TStream, + // match any type that is derived from std::istream: + typename EnableIf::type>::value>::type> : StdStreamTraits {}; } } diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/StdString.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/StdString.hpp similarity index 70% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/StdString.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/StdString.hpp index 959c47466..35f4461d8 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/StdString.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/StdString.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -22,13 +19,20 @@ namespace Internals { template struct StdStringTraits { + typedef const char* duplicate_t; + template - static char* duplicate(const TString& str, Buffer* buffer) { + static duplicate_t duplicate(const TString& str, Buffer* buffer) { if (!str.c_str()) return NULL; // <- Arduino string can return NULL size_t size = str.length() + 1; void* dup = buffer->alloc(size); if (dup != NULL) memcpy(dup, str.c_str(), size); - return static_cast(dup); + return static_cast(dup); + } + + static bool is_null(const TString& str) { + // Arduino's String::c_str() can return NULL + return !str.c_str(); } struct Reader : CharPointerTraits::Reader { @@ -36,7 +40,10 @@ struct StdStringTraits { }; static bool equals(const TString& str, const char* expected) { - return 0 == strcmp(str.c_str(), expected); + // Arduino's String::c_str() can return NULL + const char* actual = str.c_str(); + if (!actual || !expected) return actual == expected; + return 0 == strcmp(actual, expected); } static void append(TString& str, char c) { @@ -64,7 +71,7 @@ struct StringTraits : StdStringTraits { template <> struct StringTraits : StdStringTraits {}; #endif -} -} +} // namespace Internals +} // namespace ArduinoJson #endif diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/StringTraits.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/StringTraits.hpp similarity index 55% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/StringTraits.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/StringTraits.hpp index 55bacca26..dd5694b2e 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/StringTraits/StringTraits.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/StringTraits/StringTraits.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -12,13 +9,17 @@ #include "../TypeTraits/EnableIf.hpp" #include "../TypeTraits/IsBaseOf.hpp" #include "../TypeTraits/IsChar.hpp" +#include "../TypeTraits/IsConst.hpp" #include "../TypeTraits/RemoveReference.hpp" namespace ArduinoJson { namespace Internals { template -struct StringTraits {}; +struct StringTraits { + static const bool has_append = false; + static const bool has_equals = false; +}; template struct StringTraits : StringTraits {}; @@ -33,18 +34,3 @@ struct StringTraits : StringTraits {}; #include "FlashString.hpp" #include "StdStream.hpp" #include "StdString.hpp" - -namespace ArduinoJson { -namespace TypeTraits { -template -struct IsString { - static const bool value = false; -}; - -template -struct IsString::has_equals>::type> { - static const bool value = Internals::StringTraits::has_equals; -}; -} -} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/EnableIf.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/EnableIf.hpp similarity index 58% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/EnableIf.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/EnableIf.hpp index 654b308e6..83fc5e07f 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/EnableIf.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/EnableIf.hpp @@ -1,14 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that return the type T if Condition is true. template diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/FloatTraits.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/FloatTraits.hpp similarity index 68% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/FloatTraits.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/FloatTraits.hpp index a52e1e879..648cc82fd 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/FloatTraits.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/FloatTraits.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -13,7 +10,7 @@ #include "../Polyfills/math.hpp" namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { template struct FloatTraits {}; @@ -47,28 +44,46 @@ struct FloatTraits { static T positiveBinaryPowerOfTen(int index) { static T factors[] = { - 1e1, 1e2, 1e4, 1e8, 1e16, 1e32, - // workaround to support platforms with single precision literals - forge(0x4D384F03, 0xE93FF9F5), forge(0x5A827748, 0xF9301D32), - forge(0x75154FDD, 0x7F73BF3C)}; + 1e1, + 1e2, + 1e4, + 1e8, + 1e16, + forge(0x4693B8B5, 0xB5056E17), // 1e32 + forge(0x4D384F03, 0xE93FF9F5), // 1e64 + forge(0x5A827748, 0xF9301D32), // 1e128 + forge(0x75154FDD, 0x7F73BF3C) // 1e256 + }; return factors[index]; } static T negativeBinaryPowerOfTen(int index) { static T factors[] = { - 1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32, - // workaround to support platforms with single precision literals - forge(0x32A50FFD, 0x44F4A73D), forge(0x255BBA08, 0xCF8C979D), - forge(0x0AC80628, 0x64AC6F43)}; + forge(0x3FB99999, 0x9999999A), // 1e-1 + forge(0x3F847AE1, 0x47AE147B), // 1e-2 + forge(0x3F1A36E2, 0xEB1C432D), // 1e-4 + forge(0x3E45798E, 0xE2308C3A), // 1e-8 + forge(0x3C9CD2B2, 0x97D889BC), // 1e-16 + forge(0x3949F623, 0xD5A8A733), // 1e-32 + forge(0x32A50FFD, 0x44F4A73D), // 1e-64 + forge(0x255BBA08, 0xCF8C979D), // 1e-128 + forge(0x0AC80628, 0x64AC6F43) // 1e-256 + }; return factors[index]; } static T negativeBinaryPowerOfTenPlusOne(int index) { static T factors[] = { - 1e0, 1e-1, 1e-3, 1e-7, 1e-15, 1e-31, - // workaround to support platforms with single precision literals - forge(0x32DA53FC, 0x9631D10D), forge(0x25915445, 0x81B7DEC2), - forge(0x0AFE07B2, 0x7DD78B14)}; + 1e0, + forge(0x3FB99999, 0x9999999A), // 1e-1 + forge(0x3F50624D, 0xD2F1A9FC), // 1e-3 + forge(0x3E7AD7F2, 0x9ABCAF48), // 1e-7 + forge(0x3CD203AF, 0x9EE75616), // 1e-15 + forge(0x398039D6, 0x65896880), // 1e-31 + forge(0x32DA53FC, 0x9631D10D), // 1e-63 + forge(0x25915445, 0x81B7DEC2), // 1e-127 + forge(0x0AFE07B2, 0x7DD78B14) // 1e-255 + }; return factors[index]; } @@ -80,6 +95,9 @@ struct FloatTraits { return forge(0x7ff00000, 0x00000000); } + // constructs a double floating point values from its binary representation + // we use this function to workaround platforms with single precision literals + // (for example, when -fsingle-precision-constant is passed to GCC) static T forge(uint32_t msb, uint32_t lsb) { union { uint64_t integerBits; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsArray.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsArray.hpp similarity index 67% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsArray.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsArray.hpp index 713808aed..259923115 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsArray.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsArray.hpp @@ -1,14 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that return the type T without the const modifier template diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsBaseOf.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsBaseOf.hpp similarity index 73% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsBaseOf.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsBaseOf.hpp index 9e68debc3..bf24e965e 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsBaseOf.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsBaseOf.hpp @@ -1,14 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that returns true if Derived inherits from TBase is an // integral type. diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsChar.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsChar.hpp similarity index 69% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsChar.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsChar.hpp index bd1b5fdd5..d97cec213 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsChar.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsChar.hpp @@ -1,16 +1,13 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once #include "IsSame.hpp" namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that returns true if T is a charater template diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsConst.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsConst.hpp similarity index 61% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsConst.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsConst.hpp index 7ffed8443..512ee5ca0 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsConst.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsConst.hpp @@ -1,14 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that return the type T without the const modifier template diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsFloatingPoint.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsFloatingPoint.hpp similarity index 60% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsFloatingPoint.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsFloatingPoint.hpp index c04ce2a63..e41a6824c 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsFloatingPoint.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsFloatingPoint.hpp @@ -1,16 +1,13 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once #include "IsSame.hpp" namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that returns true if T is a floating point type template diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsIntegral.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsIntegral.hpp similarity index 50% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsIntegral.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsIntegral.hpp index e34add52e..17ae5f284 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsIntegral.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsIntegral.hpp @@ -1,9 +1,6 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once @@ -12,14 +9,14 @@ #include "IsUnsignedIntegral.hpp" namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that returns true if T is an integral type. template struct IsIntegral { - static const bool value = TypeTraits::IsSignedIntegral::value || - TypeTraits::IsUnsignedIntegral::value || - TypeTraits::IsSame::value; + static const bool value = IsSignedIntegral::value || + IsUnsignedIntegral::value || + IsSame::value; // CAUTION: differs from std::is_integral as it doesn't include bool }; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsSame.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsSame.hpp similarity index 62% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsSame.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsSame.hpp index d96a5b554..06567c93b 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsSame.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsSame.hpp @@ -1,14 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that returns true if types T and U are the same. template diff --git a/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsSignedIntegral.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsSignedIntegral.hpp new file mode 100644 index 000000000..7334eb9c7 --- /dev/null +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsSignedIntegral.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "../Configuration.hpp" +#include "IsSame.hpp" + +namespace ArduinoJson { +namespace Internals { + +// A meta-function that returns true if T is an integral type. +template +struct IsSignedIntegral { + static const bool value = + IsSame::value || IsSame::value || + IsSame::value || IsSame::value || +#if ARDUINOJSON_USE_LONG_LONG + IsSame::value || +#endif +#if ARDUINOJSON_USE_INT64 + IsSame::value || +#endif + false; +}; +} +} diff --git a/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp new file mode 100644 index 000000000..938423f5c --- /dev/null +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "../Configuration.hpp" +#include "IsSame.hpp" + +namespace ArduinoJson { +namespace Internals { + +// A meta-function that returns true if T is an integral type. +template +struct IsUnsignedIntegral { + static const bool value = + IsSame::value || IsSame::value || + IsSame::value || IsSame::value || +#if ARDUINOJSON_USE_LONG_LONG + IsSame::value || +#endif +#if ARDUINOJSON_USE_INT64 + IsSame::value || +#endif + false; +}; +} +} diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsVariant.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsVariant.hpp similarity index 50% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsVariant.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsVariant.hpp index 8297cf5cd..f8b299f7a 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/IsVariant.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/IsVariant.hpp @@ -1,16 +1,13 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once #include "IsBaseOf.hpp" namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { class JsonVariantTag {}; diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/RemoveConst.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/RemoveConst.hpp similarity index 59% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/RemoveConst.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/RemoveConst.hpp index 0186234ef..39d4cb5a5 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/RemoveConst.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/RemoveConst.hpp @@ -1,14 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that return the type T without the const modifier template diff --git a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/RemoveReference.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/RemoveReference.hpp similarity index 60% rename from lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/RemoveReference.hpp rename to lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/RemoveReference.hpp index 4968997e7..395a12889 100644 --- a/lib/ArduinoJson-5.11.2/src/ArduinoJson/TypeTraits/RemoveReference.hpp +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/TypeTraits/RemoveReference.hpp @@ -1,14 +1,11 @@ -// Copyright Benoit Blanchon 2014-2017 +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 // MIT License -// -// Arduino JSON library -// https://bblanchon.github.io/ArduinoJson/ -// If you like this project, please add a star! #pragma once namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { // A meta-function that return the type T without the reference modifier. template diff --git a/lib/ArduinoJson-5.13.4/src/ArduinoJson/version.hpp b/lib/ArduinoJson-5.13.4/src/ArduinoJson/version.hpp new file mode 100644 index 000000000..34c78461d --- /dev/null +++ b/lib/ArduinoJson-5.13.4/src/ArduinoJson/version.hpp @@ -0,0 +1,10 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#define ARDUINOJSON_VERSION "5.13.4" +#define ARDUINOJSON_VERSION_MAJOR 5 +#define ARDUINOJSON_VERSION_MINOR 13 +#define ARDUINOJSON_VERSION_REVISION 4 diff --git a/lib/FrogmoreScd30/FrogmoreScd30.cpp b/lib/FrogmoreScd30/FrogmoreScd30.cpp new file mode 100644 index 000000000..32bbee5ba --- /dev/null +++ b/lib/FrogmoreScd30/FrogmoreScd30.cpp @@ -0,0 +1,653 @@ +/* +# Copyright (c) 2019 Frogmore42 +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#include +#include +#include +#include +#include + +#define COMMAND_SCD30_CONTINUOUS_MEASUREMENT 0x0010 +#define COMMAND_SCD30_MEASUREMENT_INTERVAL 0x4600 +#define COMMAND_SCD30_GET_DATA_READY 0x0202 +#define COMMAND_SCD30_READ_MEASUREMENT 0x0300 +#define COMMAND_SCD30_CALIBRATION_TYPE 0x5306 +#define COMMAND_SCD30_FORCED_RECALIBRATION_FACTOR 0x5204 +#define COMMAND_SCD30_TEMPERATURE_OFFSET 0x5403 +#define COMMAND_SCD30_ALTITUDE_COMPENSATION 0x5102 +#define COMMAND_SCD30_SOFT_RESET 0xD304 +#define COMMAND_SCD30_GET_FW_VERSION 0xD100 +#define COMMAND_SCD30_STOP_MEASUREMENT 0x0104 + +#define SCD30_DATA_REGISTER_BYTES 2 +#define SCD30_DATA_REGISTER_WITH_CRC 3 +#define SCD30_MEAS_BYTES 18 + +#ifdef SCD30_DEBUG +enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; +char scd30log_data[180]; +#endif + +void FrogmoreScd30::begin(TwoWire *pWire, uint8_t i2cAddress) +{ + this->i2cAddress = i2cAddress; + if (pWire == NULL) + { + this->pWire = &Wire; + } + else + { + this->pWire = pWire; + } + + co2NewDataLocation = -1; // indicates there is no data, so the 1st data point needs to fill up the median filter + this->pWire->setClockStretchLimit(200000); + this->ambientPressure = 0; +} + +void FrogmoreScd30::begin(uint8_t i2cAddress) +{ + begin(NULL, i2cAddress); +} + +void FrogmoreScd30::begin(TwoWire *pWire) +{ + begin(pWire, SCD30_ADDRESS); +} + +void FrogmoreScd30::begin(void) +{ + begin(NULL, SCD30_ADDRESS); +} + +/*--------------------------------------------------------------------------- + Function : opt_med5() In : pointer to array of 5 values + Out : a uint16_t which is the middle value of the sorted array + Job : optimized search of the median of 5 values + Notice : found on sci.image.processing cannot go faster unless assumptions are made on the nature of the input signal. + ---------------------------------------------------------------------------*/ +#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); } +#define PIX_SWAP(a,b) { uint16_t temp=(a);(a)=(b);(b)=temp; } + +uint16_t opt_med5(uint16_t * p) +{ + PIX_SORT(p[0], p[1]); + PIX_SORT(p[3], p[4]); + PIX_SORT(p[0], p[3]); + PIX_SORT(p[1], p[4]); + PIX_SORT(p[1], p[2]); + PIX_SORT(p[2], p[3]); + PIX_SORT(p[1], p[2]); + return(p[2]); +} + +// twi_status() attempts to read out any data left that is holding SDA low, so a new transaction can take place +// something like (http://www.forward.com.au/pfod/ArduinoProgramming/I2C_ClearBus/index.html) +int FrogmoreScd30::clearI2CBus(void) +{ +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "clearI2CBus"); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + return (twi_status()); +} + +#ifdef SCD30_DEBUG +void FrogmoreScd30::AddLog(uint8_t loglevel) +{ + if (loglevel <= LOG_LEVEL_INFO) + { + Serial.printf("%s\r\n", scd30log_data); + } +} +#endif + +uint8_t FrogmoreScd30::computeCRC8(uint8_t data[], uint8_t len) +// Computes the CRC that the SCD30 uses +{ + uint8_t crc = 0xFF; //Init with 0xFF + + for (uint8_t x = 0 ; x < len ; x++) + { + crc ^= data[x]; // XOR-in the next input byte + for (uint8_t i = 0 ; i < 8 ; i++) + { + if ((crc & 0x80) != 0) + crc = (uint8_t)((crc << 1) ^ 0x31); + else + crc <<= 1; + } + } + + return crc; //No output reflection +} + +// Sends stream of bytes to device +int FrogmoreScd30::sendBytes(void *pInput, uint8_t len) +{ + uint8_t *pBytes = (uint8_t *) pInput; + int result; + uint8_t errorBytes = 0; // number of bytes that had an error in transmission +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30SendBytes: data: 0x %02X %02X %02X | 0x %02X %02X %02X | 0x %02X %02X %02X", pBytes[0], pBytes[1], pBytes[2], pBytes[3], pBytes[4], pBytes[5], pBytes[6], pBytes[7], pBytes[8]); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + pWire->beginTransmission(this->i2cAddress); + errorBytes = len - (pWire->write(pBytes, len)); + result = pWire->endTransmission(); + if (errorBytes || result) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30SendBytes: errorBytes: %d | Wire.end: %d", errorBytes, result); + AddLog(LOG_LEVEL_INFO); +#endif + } + + result <<= 8; // leave room for error bytes number + result |= errorBytes; // low byte has number of bytes that were not written correctly + return (result); +} + +// Gets a number of bytes from device +int FrogmoreScd30::getBytes(void *pOutput, uint8_t len) +{ + uint8_t *pBytes = (uint8_t *) pOutput; + uint8_t result; + + result = pWire->requestFrom(this->i2cAddress, len); + if (len != result) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30GetBytes: wire request expected %d got: %d", len, result); + AddLog(LOG_LEVEL_INFO); +#endif + return (ERROR_SCD30_NOT_ENOUGH_BYTES_ERROR); + } + + if (pWire->available()) + { + for (int x = 0; x < len; x++) + { + pBytes[x] = pWire->read(); + } +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30GetBytes: data: 0x %02X %02X %02X | 0x %02X %02X %02X | 0x %02X %02X %02X", pBytes[0], pBytes[1], pBytes[2], pBytes[3], pBytes[4], pBytes[5], pBytes[6], pBytes[7], pBytes[8]); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + return (ERROR_SCD30_NO_ERROR); + } + + return (ERROR_SCD30_UNKNOWN_ERROR); +} + +//Sends just a command, no arguments, no CRC +int FrogmoreScd30::sendCommand(uint16_t command) +{ + uint8_t data[2]; + data[0] = command >> 8; + data[1] = command & 0xFF; + int error = sendBytes(data, sizeof(data)); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30SendCommand: Scd30SendBytes failed: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + } + return (error); +} + +//Sends a command along with arguments and CRC +int FrogmoreScd30::sendCommandArguments(uint16_t command, uint16_t arguments) +{ + uint8_t data[5]; + data[0] = command >> 8; + data[1] = command & 0xFF; + data[2] = arguments >> 8; + data[3] = arguments & 0xFF; + data[4] = computeCRC8(&data[2], 2); //Calc CRC on the arguments only, not the command + int error = sendBytes(data, sizeof(data)); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30SendCommandArguments: Scd30SendBytes failed: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + } + return (error); +} + +int FrogmoreScd30::get16BitRegCheckCRC(void* pInput, uint16_t *pData) +{ + uint8_t *pBytes = (uint8_t *) pInput; + uint8_t expectedCRC = computeCRC8(pBytes, SCD30_DATA_REGISTER_BYTES); + if (expectedCRC != pBytes[SCD30_DATA_REGISTER_BYTES]) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30get16BitRegCheckCRC: expected: 0x%02X, but got: 0x%02X", expectedCRC, pBytes[SCD30_DATA_REGISTER_BYTES]); + AddLog(LOG_LEVEL_INFO); + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30get16BitRegCheckCRC: data: 0x%02X, 0x%02X, 0x%02X", pBytes[0], pBytes[1], pBytes[2]); + AddLog(LOG_LEVEL_INFO); +#endif + return (ERROR_SCD30_CRC_ERROR); + } + *pData = (uint16_t) pBytes[0] << 8 | pBytes[1]; // data from SCD30 is Big-Endian + return (ERROR_SCD30_NO_ERROR); +} + +// gets 32 bits, (2) 16-bit chunks, and validates the CRCs +// +int FrogmoreScd30::get32BitRegCheckCRC(void *pInput, float *pData) +{ + uint16_t tempU16High; + uint16_t tempU16Low; + uint8_t *pBytes = (uint8_t *) pInput; + uint32_t rawInt = 0; + + int error = get16BitRegCheckCRC(pBytes, &tempU16High); + if (error) { + return (error); + } + + error = get16BitRegCheckCRC(pBytes + SCD30_DATA_REGISTER_WITH_CRC, &tempU16Low); + if (error) { + return (error); + } + + // data from SCD is Big-Endian + rawInt |= tempU16High; + rawInt <<= 16; + rawInt |= tempU16Low; + + *pData = * (float *) &rawInt; +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "get32BitRegCheckCRC: got: tempUs 0x%lX, %lX", tempU16High, tempU16Low); + AddLog(LOG_LEVEL_DEBUG); +#endif + + if (isnan(*pData) || isinf(*pData)) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "get32BitRegCheckCRC: not a floating point number: rawInt 0x%lX", rawInt); + AddLog(LOG_LEVEL_INFO); +#endif + return (ERROR_SCD30_NOT_A_NUMBER_ERROR); + } + + return (ERROR_SCD30_NO_ERROR); +} + +//Gets two bytes (and check CRC) from SCD30 +int FrogmoreScd30::readRegister(uint16_t registerAddress, uint16_t* pData) +{ + int error = sendCommand(registerAddress); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadRegister: SendCommand error: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + return (error); + } + delay(1); // the SCD30 uses clock streching to give it time to prepare data, waiting here makes it work + uint8_t data[SCD30_DATA_REGISTER_WITH_CRC]; + error = getBytes(data, sizeof(data)); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadRegister: Scd30GetBytes error: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + return (error); + } + uint16 regValue; + error = get16BitRegCheckCRC(data, ®Value); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadRegister: Scd30get16BitRegCheckCRC error: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + return (error); + } + + *pData = regValue; + return (ERROR_SCD30_NO_ERROR); +} + +int FrogmoreScd30::softReset(void) +{ + return (sendCommand(COMMAND_SCD30_SOFT_RESET)); +} + +int FrogmoreScd30::getAltitudeCompensation(uint16_t *pHeight_meter) +{ + return (readRegister(COMMAND_SCD30_ALTITUDE_COMPENSATION, pHeight_meter)); +} + +int FrogmoreScd30::getAmbientPressure(uint16_t *pAirPressure_mbar) +{ + *pAirPressure_mbar = ambientPressure; + return (ERROR_SCD30_NO_ERROR); +} + +int FrogmoreScd30::getCalibrationType(uint16_t *pIsAuto) +{ + uint16_t value = 0; + int error = readRegister(COMMAND_SCD30_CALIBRATION_TYPE, &value); + if (!error) + { + *pIsAuto = value != 0; + } + return (error); +} + +int FrogmoreScd30::getFirmwareVersion(uint8_t *pMajor, uint8_t *pMinor) +{ + uint16_t value; + int error = readRegister(COMMAND_SCD30_GET_FW_VERSION, &value); + if (!error) + { + *pMajor = value >> 8; + *pMinor = value & 0xFF; + } + return (error); +} + +int FrogmoreScd30::getForcedRecalibrationFactor(uint16_t *pCo2_ppm) +{ + return (readRegister(COMMAND_SCD30_FORCED_RECALIBRATION_FACTOR, pCo2_ppm)); +} + +int FrogmoreScd30::getMeasurementInterval(uint16_t *pTime_sec) +{ + return (readRegister(COMMAND_SCD30_MEASUREMENT_INTERVAL, pTime_sec)); +} + +int FrogmoreScd30::getTemperatureOffset(float *pOffset_degC) +{ + uint16_t value; + int error = readRegister(COMMAND_SCD30_TEMPERATURE_OFFSET, &value); + if (!error) + { + // result is in centi-degrees, need to convert to degrees + *pOffset_degC = (float) value / 100.0; + } + return (error); +} + +int FrogmoreScd30::getTemperatureOffset(uint16_t *pOffset_centiDegC) +{ + uint16_t value; + int error = readRegister(COMMAND_SCD30_TEMPERATURE_OFFSET, &value); + if (!error) + { + // result is in centi-degrees, need to convert to degrees + *pOffset_centiDegC = value; + } + return (error); +} + +int FrogmoreScd30::setAltitudeCompensation(uint16_t height_meter) +{ + return (sendCommandArguments(COMMAND_SCD30_ALTITUDE_COMPENSATION, height_meter)); +} + +int FrogmoreScd30::setAmbientPressure(uint16_t airPressure_mbar) +{ + ambientPressure = airPressure_mbar; + return (beginMeasuring(ambientPressure)); +} + +int FrogmoreScd30::setAutoSelfCalibration(void) +{ + bool isAuto = true; + return (setCalibrationType(isAuto)); +} + +int FrogmoreScd30::setCalibrationType(bool isAuto) +{ + bool value = !!isAuto; // using NOT operator twice makes sure value is 0 or 1 + return (sendCommandArguments(COMMAND_SCD30_CALIBRATION_TYPE, value)); +} + +int FrogmoreScd30::setForcedRecalibrationFactor(uint16_t co2_ppm) +{ + return (sendCommandArguments(COMMAND_SCD30_FORCED_RECALIBRATION_FACTOR, co2_ppm)); +} + +int FrogmoreScd30::setManualCalibration(void) +{ + bool isAuto = false; + return (setCalibrationType(isAuto)); +} + +int FrogmoreScd30::setMeasurementInterval(uint16_t time_sec) +{ + if (time_sec < 2) time_sec = 2; + if (time_sec > 1800) time_sec = 1800; + return (sendCommandArguments(COMMAND_SCD30_MEASUREMENT_INTERVAL, time_sec)); +} + +int FrogmoreScd30::setTemperatureOffset(float offset_degC) +{ + uint16_t offset_centiDegC; + if (offset_degC >= 0) + { + offset_centiDegC = (uint16_t) offset_degC * 100; + return (sendCommandArguments(COMMAND_SCD30_TEMPERATURE_OFFSET, offset_centiDegC)); + } + else + { + return (ERROR_SCD30_INVALID_VALUE); + } + +} + +int FrogmoreScd30::setTemperatureOffset(uint16_t offset_centiDegC) +{ + return (sendCommandArguments(COMMAND_SCD30_TEMPERATURE_OFFSET, offset_centiDegC)); +} + +int FrogmoreScd30::beginMeasuring(void) +{ + return (beginMeasuring(ambientPressure)); +} + +int FrogmoreScd30::beginMeasuring(uint16_t airPressure_mbar) +{ + ambientPressure = airPressure_mbar; + return(sendCommandArguments(COMMAND_SCD30_CONTINUOUS_MEASUREMENT, ambientPressure)); +} + +int FrogmoreScd30::isDataAvailable(bool *pIsAvailable) +{ + uint16_t isDataAvailable = false; + int error = readRegister(COMMAND_SCD30_GET_DATA_READY, &isDataAvailable); + if (!error) + { + *pIsAvailable = isDataAvailable != 0; + } + return (error); +} + +int FrogmoreScd30::readMeasurement( + uint16 *pCO2_ppm, + uint16 *pCO2EAvg_ppm, + float *pTemperature, + float *pHumidity +) +{ + bool isAvailable = false; + int error = 0; + float tempCO2; + float tempHumidity; + float tempTemperature; + + error = isDataAvailable(&isAvailable); + if (error) + { + return (error); + } + + if (!isAvailable) + { + return (ERROR_SCD30_NO_DATA); + } + +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: have data"); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + + error = sendCommand(COMMAND_SCD30_READ_MEASUREMENT); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: send command failed: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + return (error); + } + delay(1); // the SCD30 uses clock streching to give it time to prepare data, waiting here makes it work + + uint8_t bytes[SCD30_MEAS_BYTES]; + // there are (6) 16-bit values, each with a CRC in the measurement data + // the chip does not seem to like sending this data, except all at once + error = getBytes(bytes, SCD30_MEAS_BYTES); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: Scd30GetBytes command failed: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + return (error); + } + +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: Scd30GetBytes data: 0x %02X %02X %02X | 0x %02X %02X %02X | 0x %02X %02X %02X", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8]); + AddLog(LOG_LEVEL_DEBUG_MORE); + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: Scd30GetBytes data: 0x %02X %02X %02X | 0x %02X %02X %02X | 0x %02X %02X %02X", bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], bytes[16], bytes[17]); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + + error = get32BitRegCheckCRC(&bytes[0], &tempCO2); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: Scd30Get32BitsCheckCRC 1st command failed: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + return (error); + } + + error = get32BitRegCheckCRC(&bytes[6], &tempTemperature); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: Scd30Get32BitsCheckCRC 2nd command failed: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + return (error); + } + + error = get32BitRegCheckCRC(&bytes[12], &tempHumidity); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: Scd30Get32BitsCheckCRC 3rd command failed: 0x%lX", error); + AddLog(LOG_LEVEL_INFO); +#endif + return (error); + } + + if (tempCO2 == 0) + { + return (ERROR_SCD30_CO2_ZERO); + } + + if (co2NewDataLocation < 0) + { + co2EAverage = tempCO2; + for (int x = 0; x < SCD30_MEDIAN_FILTER_SIZE; x++) + { + co2History[x] = tempCO2; + co2NewDataLocation = 1; + } + } + else + { + co2History[co2NewDataLocation++] = tempCO2; + if (co2NewDataLocation >= SCD30_MEDIAN_FILTER_SIZE) + { + co2NewDataLocation = 0; + } + } + +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: co2History: %ld, %ld, %ld, %ld, %ld", co2History[0], co2History[1], co2History[2], co2History[3], co2History[4]); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + // copy array since the median filter function will re-arrange it + uint16_t temp[SCD30_MEDIAN_FILTER_SIZE]; + for (int x = 0; x < SCD30_MEDIAN_FILTER_SIZE; x++) + { + temp[x] = co2History[x]; + } +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: temp: %ld, %ld, %ld, %ld, %ld", temp[0], temp[1], temp[2], temp[3], temp[4]); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + + *pCO2_ppm = opt_med5(temp); +#ifdef SCD30_DEBUG + snprintf_P(scd30log_data, sizeof(scd30log_data), "Scd30ReadMeasurement: CO2_ppm: %ld", *pCO2_ppm); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + if (pCO2EAvg_ppm) + { + int16_t delta = (int16_t) *pCO2_ppm - (int16_t) co2EAverage; + int16_t change = delta / 32; + co2EAverage += change; +#if 0 + uint16_t remain = co2EAverage % 5; + uint16_t dividend = co2EAverage / 5; + uint16_t co2EAReported = dividend * 5; + if (remain > 2) + { + co2EAReported += 5; + } + *pCO2EAvg_ppm = co2EAReported; +#else + *pCO2EAvg_ppm = co2EAverage; +#endif + + } + + *pTemperature = tempTemperature; + *pHumidity = tempHumidity; + return (ERROR_SCD30_NO_ERROR); +} + +int FrogmoreScd30::stopMeasuring(void) +{ + return (sendCommand(COMMAND_SCD30_STOP_MEASUREMENT)); +} + diff --git a/lib/FrogmoreScd30/FrogmoreScd30.h b/lib/FrogmoreScd30/FrogmoreScd30.h new file mode 100644 index 000000000..d1f2d1309 --- /dev/null +++ b/lib/FrogmoreScd30/FrogmoreScd30.h @@ -0,0 +1,105 @@ +/* +# Copyright (c) 2019 Frogmore42 +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#pragma once + +#include "Arduino.h" + +//#define SCD30_DEBUG + +#define SCD30_ADDRESS 0x61 +#define ERROR_SCD30_NO_ERROR 0 +#define ERROR_SCD30_NO_DATA 0x80000000 +#define ERROR_SCD30_CO2_ZERO 0x90000000 +#define ERROR_SCD30_UNKNOWN_ERROR 0x1000000 +#define ERROR_SCD30_CRC_ERROR 0x2000000 +#define ERROR_SCD30_NOT_ENOUGH_BYTES_ERROR 0x3000000 +#define ERROR_SCD30_NOT_FOUND_ERROR 0x4000000 +#define ERROR_SCD30_NOT_A_NUMBER_ERROR 0x5000000 +#define ERROR_SCD30_INVALID_VALUE 0x6000000 + +#define SCD30_MEDIAN_FILTER_SIZE 5 + +class FrogmoreScd30 +{ + public: + FrogmoreScd30() {}; + // Constructors + // the SCD30 only lists a single i2c address, so not necesary to specify + // + void begin(void); + void begin(uint8_t _i2cAddress); + void begin(TwoWire *pWire); + void begin(TwoWire *pWire, uint8_t _i2cAddress); + + int softReset(void); + int clearI2CBus(void); // this is a HARD reset of the IC2 bus to restore communication, it will disrupt the bus + + int getAltitudeCompensation(uint16_t *pHeight_meter); + int getAmbientPressure(uint16_t *pAirPressure_mbar); + int getCalibrationType(uint16_t *pIsAuto); + int getFirmwareVersion(uint8_t *pMajor, uint8_t *pMinor); + int getForcedRecalibrationFactor(uint16_t *pCo2_ppm); + int getMeasurementInterval(uint16_t *pTime_sec); + int getTemperatureOffset(float *pOffset_degC); + int getTemperatureOffset(uint16_t *pOffset_centiDegC); + + int setAltitudeCompensation(uint16_t height_meter); + int setAmbientPressure(uint16_t airPressure_mbar); + int setAutoSelfCalibration(void); + int setCalibrationType(bool isAuto); + int setForcedRecalibrationFactor(uint16_t co2_ppm); + int setManualCalibration(void); + int setMeasurementInterval(uint16_t time_sec); + int setTemperatureOffset(float offset_degC); + int setTemperatureOffset(uint16_t offset_centiDegC); + + int beginMeasuring(void); + int beginMeasuring(uint16_t airPressure_mbar); // also sets ambient pressure offset in mbar/hPascal + int isDataAvailable(bool *pIsAvailable); + int readMeasurement( + uint16 *pCO2_ppm, + uint16 *pCO2EAvg_ppm, + float *pTemperature, + float *pHumidity + ); + int stopMeasuring(void); + + private: + uint8_t i2cAddress; + TwoWire *pWire; + uint16_t ambientPressure; + uint16_t co2AvgExtra; + uint16_t co2History[SCD30_MEDIAN_FILTER_SIZE]; + uint16_t co2EAverage; + int8_t co2NewDataLocation; // location to put new CO2 data for median filter + + uint8_t computeCRC8(uint8_t data[], uint8_t len); + int sendBytes(void *pInput, uint8_t len); + int getBytes(void *pOutput, uint8_t len); + int sendCommand(uint16_t command); + int sendCommandArguments(uint16_t command, uint16_t arguments); + int get16BitRegCheckCRC(void* pInput, uint16_t* pData); + int get32BitRegCheckCRC(void* pInput, float* pData); + int readRegister(uint16_t registerAddress, uint16_t* pData); +#ifdef SCD30_DEBUG + void AddLog(uint8_t loglevel); +#endif +}; \ No newline at end of file diff --git a/lib/LinkedList-1.2.3/LICENSE.txt b/lib/LinkedList-1.2.3/LICENSE.txt new file mode 100644 index 000000000..5c02604a0 --- /dev/null +++ b/lib/LinkedList-1.2.3/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Ivan Seidel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/LinkedList-1.2.3/LinkedList.h b/lib/LinkedList-1.2.3/LinkedList.h new file mode 100644 index 000000000..371b14ac7 --- /dev/null +++ b/lib/LinkedList-1.2.3/LinkedList.h @@ -0,0 +1,325 @@ +/* + LinkedList.h - V1.1 - Generic LinkedList implementation + Works better with FIFO, because LIFO will need to + search the entire List to find the last one; + + For instructions, go to https://github.com/ivanseidel/LinkedList + + Created by Ivan Seidel Gomes, March, 2013. + Released into the public domain. +*/ + + +#ifndef LinkedList_h +#define LinkedList_h + +#include + +template +struct ListNode +{ + T data; + ListNode *next; +}; + +template +class LinkedList{ + +protected: + int _size; + ListNode *root; + ListNode *last; + + // Helps "get" method, by saving last position + ListNode *lastNodeGot; + int lastIndexGot; + // isCached should be set to FALSE + // everytime the list suffer changes + bool isCached; + + ListNode* getNode(int index); + +public: + LinkedList(); + ~LinkedList(); + + /* + Returns current size of LinkedList + */ + virtual int size(); + /* + Adds a T object in the specified index; + Unlink and link the LinkedList correcly; + Increment _size + */ + virtual bool add(int index, T); + /* + Adds a T object in the end of the LinkedList; + Increment _size; + */ + virtual bool add(T); + /* + Adds a T object in the start of the LinkedList; + Increment _size; + */ + virtual bool unshift(T); + /* + Set the object at index, with T; + Increment _size; + */ + virtual bool set(int index, T); + /* + Remove object at index; + If index is not reachable, returns false; + else, decrement _size + */ + virtual T remove(int index); + /* + Remove last object; + */ + virtual T pop(); + /* + Remove first object; + */ + virtual T shift(); + /* + Get the index'th element on the list; + Return Element if accessible, + else, return false; + */ + virtual T get(int index); + + /* + Clear the entire array + */ + virtual void clear(); + +}; + +// Initialize LinkedList with false values +template +LinkedList::LinkedList() +{ + root=NULL; + last=NULL; + _size=0; + + lastNodeGot = root; + lastIndexGot = 0; + isCached = false; +} + +// Clear Nodes and free Memory +template +LinkedList::~LinkedList() +{ + ListNode* tmp; + while(root!=NULL) + { + tmp=root; + root=root->next; + delete tmp; + } + last = NULL; + _size=0; + isCached = false; +} + +/* + Actualy "logic" coding +*/ + +template +ListNode* LinkedList::getNode(int index){ + + int _pos = 0; + ListNode* current = root; + + // Check if the node trying to get is + // immediatly AFTER the previous got one + if(isCached && lastIndexGot <= index){ + _pos = lastIndexGot; + current = lastNodeGot; + } + + while(_pos < index && current){ + current = current->next; + + _pos++; + } + + // Check if the object index got is the same as the required + if(_pos == index){ + isCached = true; + lastIndexGot = index; + lastNodeGot = current; + + return current; + } + + return false; +} + +template +int LinkedList::size(){ + return _size; +} + +template +bool LinkedList::add(int index, T _t){ + + if(index >= _size) + return add(_t); + + if(index == 0) + return unshift(_t); + + ListNode *tmp = new ListNode(), + *_prev = getNode(index-1); + tmp->data = _t; + tmp->next = _prev->next; + _prev->next = tmp; + + _size++; + isCached = false; + + return true; +} + +template +bool LinkedList::add(T _t){ + + ListNode *tmp = new ListNode(); + tmp->data = _t; + tmp->next = NULL; + + if(root){ + // Already have elements inserted + last->next = tmp; + last = tmp; + }else{ + // First element being inserted + root = tmp; + last = tmp; + } + + _size++; + isCached = false; + + return true; +} + +template +bool LinkedList::unshift(T _t){ + + if(_size == 0) + return add(_t); + + ListNode *tmp = new ListNode(); + tmp->next = root; + tmp->data = _t; + root = tmp; + + _size++; + isCached = false; + + return true; +} + +template +bool LinkedList::set(int index, T _t){ + // Check if index position is in bounds + if(index < 0 || index >= _size) + return false; + + getNode(index)->data = _t; + return true; +} + +template +T LinkedList::pop(){ + if(_size <= 0) + return T(); + + isCached = false; + + if(_size >= 2){ + ListNode *tmp = getNode(_size - 2); + T ret = tmp->next->data; + delete(tmp->next); + tmp->next = NULL; + last = tmp; + _size--; + return ret; + }else{ + // Only one element left on the list + T ret = root->data; + delete(root); + root = NULL; + last = NULL; + _size = 0; + return ret; + } +} + +template +T LinkedList::shift(){ + if(_size <= 0) + return T(); + + if(_size > 1){ + ListNode *_next = root->next; + T ret = root->data; + delete(root); + root = _next; + _size --; + isCached = false; + + return ret; + }else{ + // Only one left, then pop() + return pop(); + } + +} + +template +T LinkedList::remove(int index){ + if (index < 0 || index >= _size) + { + return T(); + } + + if(index == 0) + return shift(); + + if (index == _size-1) + { + return pop(); + } + + ListNode *tmp = getNode(index - 1); + ListNode *toDelete = tmp->next; + T ret = toDelete->data; + tmp->next = tmp->next->next; + delete(toDelete); + _size--; + isCached = false; + return ret; +} + + +template +T LinkedList::get(int index){ + ListNode *tmp = getNode(index); + + return (tmp ? tmp->data : T()); +} + +template +void LinkedList::clear(){ + while(size() > 0) + shift(); +} + +#endif diff --git a/lib/LinkedList-1.2.3/README.md b/lib/LinkedList-1.2.3/README.md new file mode 100644 index 000000000..bdb16fdbd --- /dev/null +++ b/lib/LinkedList-1.2.3/README.md @@ -0,0 +1,171 @@ +# LinkedList + +This library was developed targeting **`Arduino`** applications. However, works just great with any C++. + +Implementing a buffer for objects takes time. If we are not in the mood, we just create an `array[1000]` with enough size. + +The objective of this library is to create a pattern for projects. +If you need to use a List of: `int`, `float`, `objects`, `Lists` or `Wales`. **This is what you are looking for.** + +With a simple but powerful caching algorithm, you can get subsequent objects much faster than usual. Tested without any problems with Lists bigger than 2000 members. + +## Installation + +1. [Download](https://github.com/ivanseidel/LinkedList/archive/master.zip) the Latest release from gitHub. +2. Unzip and modify the Folder name to "LinkedList" (Remove the '-version') +3. Paste the modified folder on your Library folder (On your `Libraries` folder inside Sketchbooks or Arduino software). +4. Reopen the Arduino software. + +**If you are here, because another Library requires this class, just don't waste time reading bellow. Install and ready.** + +------------------------- + +## Getting started + +### The `LinkedList` class + +In case you don't know what a LinkedList is and what it's used for, take a quick look at [Wikipedia::LinkedList](https://en.wikipedia.org/wiki/Linked_list) before continuing. + +#### To declare a LinkedList object +```c++ +// Instantiate a LinkedList that will hold 'integer' +LinkedList myLinkedList = LinkedList(); + +// Or just this +LinkedList myLinkedList; + +// But if you are instantiating a pointer LinkedList... +LinkedList *myLinkedList = new LinkedList(); + +// If you want a LinkedList with any other type such as 'MyClass' +// Make sure you call delete(MyClass) when you remove! +LinkedList *myLinkedList = new LinkedList(); +``` + +#### Getting the size of the linked list +```c++ +// To get the size of a linked list, make use of the size() method +int theSize = myList.size(); + +// Notice that if it's pointer to the linked list, you should use -> instead +int theSize = myList->size(); +``` + +#### Adding elements + +```c++ +// add(obj) method will insert at the END of the list +myList.add(myObject); + +// add(index, obj) method will try to insert the object at the specified index +myList.add(0, myObject); // Add at the beginning +myList.add(3, myObject); // Add at index 3 + +// unshift(obj) method will insert the object at the beginning +myList.unshift(myObject); +``` + +#### Getting elements + +```c++ +// get(index) will return the element at index +// (notice that the start element is 0, not 1) + +// Get the FIRST element +myObject = myList.get(0); + +// Get the third element +myObject = myList.get(2); + +// Get the LAST element +myObject = myList.get(myList.size() - 1); +``` + +#### Changing elements +```c++ +// set(index, obj) method will change the object at index to obj + +// Change the first element to myObject +myList.set(0, myObject); + +// Change the third element to myObject +myList.set(2, myObject); + +// Change the LAST element of the list +myList.set(myList.size() - 1, myObject); +``` + +#### Removing elements +```c++ +// remove(index) will remove and return the element at index + +// Remove the first object +myList.remove(0); + +// Get and Delete the third element +myDeletedObject = myList.remove(2); + +// pop() will remove and return the LAST element +myDeletedObject = myList.pop(); + +// shift() will remove and return the FIRST element +myDeletedObject = myList.shift(); + +// clear() will erase the entire list, leaving it with 0 elements +// NOTE: Clear wont DELETE/FREE memory from Pointers, if you +// are using Classes/Poiners, manualy delete and free those. +myList.clear(); +``` + +------------------------ + +## Library Reference + +### `ListNode` struct + +- `T` `ListNode::data` - The object data + +- `ListNode` `*next` - Pointer to the next Node + +### `LinkedList` class + +**`boolean` methods returns if succeeded** + +- `LinkedList::LinkedList()` - Constructor. + +- `LinkedList::~LinkedList()` - Destructor. Clear Nodes to minimize memory. Does not free pointer memory. + +- `int` `LinkedList::size()` - Returns the current size of the list. + +- `bool` `LinkedList::add(T)` - Add element T at the END of the list. + +- `bool` `LinkedList::add(int index, T)` - Add element T at `index` of the list. + +- `bool` `LinkedList::unshift(T)` - Add element T at the BEGINNING of the list. + +- `bool` `LinkedList::set(int index, T)` - Set the element at `index` to T. + +- `T` `LinkedList::remove(int index)` - Remove element at `index`. Return the removed element. Does not free pointer memory + +- `T` `LinkedList::pop()` - Remove the LAST element. Return the removed element. + +- `T` `LinkedList::shift()` - Remove the FIRST element. Return the removed element. + +- `T` `LinkedList::get(int index)` - Return the element at `index`. + +- `void` `LinkedList::clear()` - Removes all elements. Does not free pointer memory. + +- **protected** `int` `LinkedList::_size` - Holds the cached size of the list. + +- **protected** `ListNode` `LinkedList::*root` - Holds the root node of the list. + +- **protected** `ListNode` `LinkedList::*last` - Holds the last node of the list. + +- **protected** `ListNode*` `LinkedList::getNode(int index)` - Returns the `index` node of the list. + +### Version History + +* `1.1 (2013-07-20)`: Cache implemented. Getting subsequent objects is now O(N). Before, O(N^2). +* `1.0 (2013-07-20)`: Original release + +![LinkedList](https://d2weczhvl823v0.cloudfront.net/ivanseidel/LinkedList/trend.png) diff --git a/lib/LinkedList-1.2.3/examples/ClassList/ClassList.pde b/lib/LinkedList-1.2.3/examples/ClassList/ClassList.pde new file mode 100644 index 000000000..9a8ea9d99 --- /dev/null +++ b/lib/LinkedList-1.2.3/examples/ClassList/ClassList.pde @@ -0,0 +1,81 @@ +/* + LinkedList Example + Link: http://github.com/ivanseidel/LinkedList + + Example Created by + Tom Stewart, github.com/tastewar + + Edited by: + Ivan Seidel, github.com/ivanseidel +*/ + +#include + +// Let's define a new class +class Animal { + public: + char *name; + bool isMammal; +}; + +char catname[]="kitty"; +char dogname[]="doggie"; +char emuname[]="emu"; + +LinkedList myAnimalList = LinkedList(); + +void setup() +{ + + Serial.begin(9600); + Serial.println("Hello!" ); + + // Create a Cat + Animal *cat = new Animal(); + cat->name = catname; + cat->isMammal = true; + + // Create a dog + Animal *dog = new Animal(); + dog->name = dogname; + dog->isMammal = true; + + // Create a emu + Animal *emu = new Animal(); + emu->name = emuname; + emu->isMammal = false; // just an example; no offense to pig lovers + + // Add animals to list + myAnimalList.add(cat); + myAnimalList.add(emu); + myAnimalList.add(dog); +} + +void loop() { + + Serial.print("There are "); + Serial.print(myAnimalList.size()); + Serial.print(" animals in the list. The mammals are: "); + + int current = 0; + Animal *animal; + for(int i = 0; i < myAnimalList.size(); i++){ + + // Get animal from list + animal = myAnimalList.get(i); + + // If its a mammal, then print it's name + if(animal->isMammal){ + + // Avoid printing spacer on the first element + if(current++) + Serial.print(", "); + + // Print animal name + Serial.print(animal->name); + } + } + Serial.println("."); + + while (true); // nothing else to do, loop forever +} \ No newline at end of file diff --git a/lib/LinkedList-1.2.3/examples/SimpleIntegerList/SimpleIntegerList.pde b/lib/LinkedList-1.2.3/examples/SimpleIntegerList/SimpleIntegerList.pde new file mode 100644 index 000000000..1bcbe9c37 --- /dev/null +++ b/lib/LinkedList-1.2.3/examples/SimpleIntegerList/SimpleIntegerList.pde @@ -0,0 +1,58 @@ +/* + LinkedList Example + Link: http://github.com/ivanseidel/LinkedList + + Example Created by + Tom Stewart, github.com/tastewar + + Edited by: + Ivan Seidel, github.com/ivanseidel +*/ +#include + +LinkedList myList = LinkedList(); + +void setup() +{ + + Serial.begin(9600); + Serial.println("Hello!"); + + // Add some stuff to the list + int k = -240, + l = 123, + m = -2, + n = 222; + myList.add(n); + myList.add(0); + myList.add(l); + myList.add(17); + myList.add(k); + myList.add(m); +} + +void loop() { + + int listSize = myList.size(); + + Serial.print("There are "); + Serial.print(listSize); + Serial.print(" integers in the list. The negative ones are: "); + + // Print Negative numbers + for (int h = 0; h < listSize; h++) { + + // Get value from list + int val = myList.get(h); + + // If the value is negative, print it + if (val < 0) { + Serial.print(" "); + Serial.print(val); + } + } + + while (true); // nothing else to do, loop forever +} + + diff --git a/lib/LinkedList-1.2.3/keywords.txt b/lib/LinkedList-1.2.3/keywords.txt new file mode 100644 index 000000000..3ae496859 --- /dev/null +++ b/lib/LinkedList-1.2.3/keywords.txt @@ -0,0 +1,28 @@ +####################################### +# Syntax Coloring +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +LinkedList KEYWORD1 +ListNode KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +size KEYWORD2 +add KEYWORD2 +unshift KEYWORD2 +set KEYWORD2 +remove KEYWORD2 +pop KEYWORD2 +shift KEYWORD2 +get KEYWORD2 +clear KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/LinkedList-1.2.3/library.json b/lib/LinkedList-1.2.3/library.json new file mode 100644 index 000000000..4179b248d --- /dev/null +++ b/lib/LinkedList-1.2.3/library.json @@ -0,0 +1,12 @@ +{ + "name": "LinkedList", + "keywords": "pattern", + "description": "A fully implemented LinkedList (int, float, objects, Lists or Wales) made to work with Arduino projects", + "repository": + { + "type": "git", + "url": "https://github.com/ivanseidel/LinkedList.git" + }, + "frameworks": "arduino", + "platforms": "*" +} diff --git a/lib/LinkedList-1.2.3/library.properties b/lib/LinkedList-1.2.3/library.properties new file mode 100644 index 000000000..77b1423c0 --- /dev/null +++ b/lib/LinkedList-1.2.3/library.properties @@ -0,0 +1,9 @@ +name=LinkedList +version=1.2.3 +author=Ivan Seidel +maintainer=Ivan Seidel +sentence=A fully implemented LinkedList made to work with Arduino projects +paragraph=The objective of this library is to create a pattern for projects. If you need to use a List of: int, float, objects, Lists or Wales. This is what you are looking for. +category=Data Processing +url=https://github.com/ivanseidel/LinkedList +architectures=* diff --git a/lib/NewPing-1.9.1/README.md b/lib/NewPing-1.9.1/README.md index 8760c35ff..5044422a4 100644 --- a/lib/NewPing-1.9.1/README.md +++ b/lib/NewPing-1.9.1/README.md @@ -1,3 +1,3 @@ # NewPing Arduino Library for Arduino -## See the [NewPing Wiki](https://bitbucket.org/teckel12/arduino-new-ping/wiki/Home) for documentation \ No newline at end of file +## See the [NewPing Wiki](https://bitbucket.org/teckel12/arduino-new-ping/wiki/Home) for documentation diff --git a/lib/NewPing-1.9.1/examples/NewPing15SensorsTimer/NewPing15SensorsTimer.pde b/lib/NewPing-1.9.1/examples/NewPing15SensorsTimer/NewPing15SensorsTimer.pde index a42c792b8..f34c6d7d3 100644 --- a/lib/NewPing-1.9.1/examples/NewPing15SensorsTimer/NewPing15SensorsTimer.pde +++ b/lib/NewPing-1.9.1/examples/NewPing15SensorsTimer/NewPing15SensorsTimer.pde @@ -75,4 +75,4 @@ void oneSensorCycle() { // Sensor ping cycle complete, do something with the res Serial.print("cm "); } Serial.println(); -} \ No newline at end of file +} diff --git a/lib/NewPing-1.9.1/examples/NewPing3Sensors/NewPing3Sensors.pde b/lib/NewPing-1.9.1/examples/NewPing3Sensors/NewPing3Sensors.pde index 061d7f3ee..c55832084 100644 --- a/lib/NewPing-1.9.1/examples/NewPing3Sensors/NewPing3Sensors.pde +++ b/lib/NewPing-1.9.1/examples/NewPing3Sensors/NewPing3Sensors.pde @@ -8,8 +8,8 @@ #define MAX_DISTANCE 200 // Maximum distance (in cm) to ping. NewPing sonar[SONAR_NUM] = { // Sensor object array. - NewPing(4, 5, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping. - NewPing(6, 7, MAX_DISTANCE), + NewPing(4, 5, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping. + NewPing(6, 7, MAX_DISTANCE), NewPing(8, 9, MAX_DISTANCE) }; @@ -17,7 +17,7 @@ void setup() { Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results. } -void loop() { +void loop() { for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through each sensor and display results. delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings. Serial.print(i); @@ -26,4 +26,4 @@ void loop() { Serial.print("cm "); } Serial.println(); -} \ No newline at end of file +} diff --git a/lib/NewPing-1.9.1/examples/NewPingTimerMedian/NewPingTimerMedian.pde b/lib/NewPing-1.9.1/examples/NewPingTimerMedian/NewPingTimerMedian.pde index 5908f5858..16fe3fff3 100644 --- a/lib/NewPing-1.9.1/examples/NewPingTimerMedian/NewPingTimerMedian.pde +++ b/lib/NewPing-1.9.1/examples/NewPingTimerMedian/NewPingTimerMedian.pde @@ -57,4 +57,4 @@ void oneSensorCycle() { // All iterations complete, calculate the median. } Serial.print(uS[it >> 1]); Serial.println("cm"); -} \ No newline at end of file +} diff --git a/lib/NewPing-1.9.1/examples/TimerExample/TimerExample.pde b/lib/NewPing-1.9.1/examples/TimerExample/TimerExample.pde index 35e1db227..58dc5219f 100644 --- a/lib/NewPing-1.9.1/examples/TimerExample/TimerExample.pde +++ b/lib/NewPing-1.9.1/examples/TimerExample/TimerExample.pde @@ -22,4 +22,4 @@ void loop() { void toggleLED() { digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Toggle the LED. -} \ No newline at end of file +} diff --git a/lib/NewPing-1.9.1/keywords.txt b/lib/NewPing-1.9.1/keywords.txt index 0487ff26d..abf479714 100644 --- a/lib/NewPing-1.9.1/keywords.txt +++ b/lib/NewPing-1.9.1/keywords.txt @@ -28,4 +28,3 @@ convert_cm KEYWORD2 ################################### # Constants (LITERAL1) ################################### - diff --git a/lib/NewPing-1.9.1/src/NewPing.cpp b/lib/NewPing-1.9.1/src/NewPing.cpp index 05c8af4c6..e71f6181f 100644 --- a/lib/NewPing-1.9.1/src/NewPing.cpp +++ b/lib/NewPing-1.9.1/src/NewPing.cpp @@ -153,7 +153,7 @@ boolean NewPing::ping_trigger() { #if ONE_PIN_ENABLED == true pinMode(_triggerPin, OUTPUT); // Set trigger pin to output. #endif - + digitalWrite(_triggerPin, LOW); // Set the trigger pin low, should already be low, but this will make sure it is. delayMicroseconds(4); // Wait for pin to go low. digitalWrite(_triggerPin, HIGH); // Set trigger pin high, this tells the sensor to send out a ping. diff --git a/lib/NewPing-1.9.1/src/NewPing.h b/lib/NewPing-1.9.1/src/NewPing.h index 9afb261ac..49db4349a 100644 --- a/lib/NewPing-1.9.1/src/NewPing.h +++ b/lib/NewPing-1.9.1/src/NewPing.h @@ -15,7 +15,7 @@ // Blog: http://arduino.cc/forum/index.php/topic,106043.0.html // // DISCLAIMER: -// This software is furnished "as is", without technical support, and with no +// This software is furnished "as is", without technical support, and with no // warranty, express or implied, as to its usefulness for any purpose. // // BACKGROUND: @@ -23,7 +23,7 @@ // it worked. Quickly I realized the problem wasn't the sensor, it was the // available ping and ultrasonic libraries causing the problem. The NewPing // library totally fixes these problems, adds many new features, and breaths -// new life into these very affordable distance sensors. +// new life into these very affordable distance sensors. // // FEATURES: // * Works with many different ultrasonic sensors: SR04, SRF05, SRF06, DYP-ME007, URM37 & Parallax PING)))™. @@ -47,7 +47,7 @@ // max_cm_distance - [Optional] Maximum distance you wish to sense. Default=500cm. // // METHODS: -// sonar.ping([max_cm_distance]) - Send a ping and get the echo time (in microseconds) as a result. [max_cm_distance] allows you to optionally set a new max distance. +// sonar.ping([max_cm_distance]) - Send a ping and get the echo time (in microseconds) as a result. [max_cm_distance] allows you to optionally set a new max distance. // sonar.ping_in([max_cm_distance]) - Send a ping and get the distance in whole inches. [max_cm_distance] allows you to optionally set a new max distance. // sonar.ping_cm([max_cm_distance]) - Send a ping and get the distance in whole centimeters. [max_cm_distance] allows you to optionally set a new max distance. // sonar.ping_median(iterations [, max_cm_distance]) - Do multiple pings (default=5), discard out of range pings and return median in microseconds. [max_cm_distance] allows you to optionally set a new max distance. diff --git a/lib/TasmotaModbus-1.1.0/src/TasmotaModbus.cpp b/lib/TasmotaModbus-1.1.0/src/TasmotaModbus.cpp index 0be2c9de3..207fc07f8 100644 --- a/lib/TasmotaModbus-1.1.0/src/TasmotaModbus.cpp +++ b/lib/TasmotaModbus-1.1.0/src/TasmotaModbus.cpp @@ -27,7 +27,6 @@ TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin) : TasmotaSerial( uint16_t CalculateCRC(uint8_t *frame, uint8_t num) { uint16_t crc = 0xFFFF; - uint16_t flag; for (uint8_t i = 0; i < num; i++) { crc ^= frame[i]; diff --git a/lib/TasmotaSerial-2.2.0/README.md b/lib/TasmotaSerial-2.3.0/README.md similarity index 100% rename from lib/TasmotaSerial-2.2.0/README.md rename to lib/TasmotaSerial-2.3.0/README.md diff --git a/lib/TasmotaSerial-2.2.0/examples/swsertest/swsertest.ino b/lib/TasmotaSerial-2.3.0/examples/swsertest/swsertest.ino similarity index 100% rename from lib/TasmotaSerial-2.2.0/examples/swsertest/swsertest.ino rename to lib/TasmotaSerial-2.3.0/examples/swsertest/swsertest.ino diff --git a/lib/TasmotaSerial-2.2.0/keywords.txt b/lib/TasmotaSerial-2.3.0/keywords.txt similarity index 95% rename from lib/TasmotaSerial-2.2.0/keywords.txt rename to lib/TasmotaSerial-2.3.0/keywords.txt index 87974971e..9cf6d825c 100644 --- a/lib/TasmotaSerial-2.2.0/keywords.txt +++ b/lib/TasmotaSerial-2.3.0/keywords.txt @@ -14,6 +14,7 @@ TasmotaSerial KEYWORD1 ####################################### begin KEYWORD2 +hardwareSerial KEYWORD2 read KEYWORD2 write KEYWORD2 available KEYWORD2 diff --git a/lib/TasmotaSerial-2.2.0/library.json b/lib/TasmotaSerial-2.3.0/library.json similarity index 94% rename from lib/TasmotaSerial-2.2.0/library.json rename to lib/TasmotaSerial-2.3.0/library.json index 23a2ddab9..fad36bcc6 100644 --- a/lib/TasmotaSerial-2.2.0/library.json +++ b/lib/TasmotaSerial-2.3.0/library.json @@ -1,6 +1,6 @@ { "name": "TasmotaSerial", - "version": "2.2.0", + "version": "2.3.0", "keywords": [ "serial", "io", "TasmotaSerial" ], diff --git a/lib/TasmotaSerial-2.2.0/library.properties b/lib/TasmotaSerial-2.3.0/library.properties similarity index 94% rename from lib/TasmotaSerial-2.2.0/library.properties rename to lib/TasmotaSerial-2.3.0/library.properties index 54c79e218..095077d8e 100644 --- a/lib/TasmotaSerial-2.2.0/library.properties +++ b/lib/TasmotaSerial-2.3.0/library.properties @@ -1,5 +1,5 @@ name=TasmotaSerial -version=2.2.0 +version=2.3.0 author=Theo Arends maintainer=Theo Arends sentence=Implementation of software serial with hardware serial fallback for ESP8266. diff --git a/lib/TasmotaSerial-2.2.0/src/TasmotaSerial.cpp b/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.cpp similarity index 97% rename from lib/TasmotaSerial-2.2.0/src/TasmotaSerial.cpp rename to lib/TasmotaSerial-2.3.0/src/TasmotaSerial.cpp index 3df42f834..eecdeb124 100644 --- a/lib/TasmotaSerial-2.2.0/src/TasmotaSerial.cpp +++ b/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.cpp @@ -1,7 +1,7 @@ /* TasmotaSerial.cpp - Minimal implementation of software serial for Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -100,7 +100,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal m_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE); if (m_buffer == NULL) return; // Use getCycleCount() loop to get as exact timing as possible - m_bit_time = ESP.getCpuFreqMHz() *1000000 /TM_SERIAL_BAUDRATE; + m_bit_time = F_CPU / TM_SERIAL_BAUDRATE; pinMode(m_rx_pin, INPUT); tms_obj_list[m_rx_pin] = this; attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING); @@ -145,7 +145,7 @@ bool TasmotaSerial::begin(long speed, int stop_bits) { } } else { // Use getCycleCount() loop to get as exact timing as possible - m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed; + m_bit_time = F_CPU / speed; m_high_speed = (speed > 9600); } return m_valid; @@ -257,7 +257,7 @@ void TasmotaSerial::rxRead() TM_SERIAL_WAIT; } // Store the received value in the buffer unless we have an overflow - int next = (m_in_pos+1) % TM_SERIAL_BUFFER_SIZE; + unsigned int next = (m_in_pos+1) % TM_SERIAL_BUFFER_SIZE; if (next != (int)m_out_pos) { m_buffer[m_in_pos] = rec; m_in_pos = next; diff --git a/lib/TasmotaSerial-2.2.0/src/TasmotaSerial.h b/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.h similarity index 96% rename from lib/TasmotaSerial-2.2.0/src/TasmotaSerial.h rename to lib/TasmotaSerial-2.3.0/src/TasmotaSerial.h index de991526a..9481ef370 100644 --- a/lib/TasmotaSerial-2.2.0/src/TasmotaSerial.h +++ b/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.h @@ -1,7 +1,7 @@ /* TasmotaSerial.h - Minimal implementation of software serial for Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,7 +22,7 @@ /*********************************************************************************************\ * TasmotaSerial supports up to 115200 baud with fixed buffer size of 64 bytes using optional no iram * - * Based on EspSoftwareSerial v3.3.1 by Peter Lerup (https://github.com/plerup/espsoftwareserial) + * Based on EspSoftwareSerial v3.4.3 by Peter Lerup (https://github.com/plerup/espsoftwareserial) \*********************************************************************************************/ #define TM_SERIAL_BAUDRATE 9600 // Default baudrate diff --git a/sonoff/Parsing.cpp b/sonoff/Parsing.cpp new file mode 100644 index 000000000..22c59acda --- /dev/null +++ b/sonoff/Parsing.cpp @@ -0,0 +1,623 @@ +/* + Parsing.cpp - HTTP request parsing. + + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling) +*/ + +// Use patched Parsing.cpp to fix ALEXA parsing issue in v2.4.2 +#include +#if defined(ARDUINO_ESP8266_RELEASE_2_4_2) +#warning **** Tasmota is using v2.4.2 patched Parsing.cpp as planned **** + +#include +#include "WiFiServer.h" +#include "WiFiClient.h" +#include "ESP8266WebServer.h" +#include "detail/mimetable.h" + +//#define DEBUG_ESP_HTTP_SERVER +#ifdef DEBUG_ESP_PORT +#define DEBUG_OUTPUT DEBUG_ESP_PORT +#else +#define DEBUG_OUTPUT Serial +#endif + +static const char Content_Type[] PROGMEM = "Content-Type"; +static const char filename[] PROGMEM = "filename"; + +static char* readBytesWithTimeout(WiFiClient& client, size_t maxLength, size_t& dataLength, int timeout_ms) +{ + char *buf = nullptr; + dataLength = 0; + while (dataLength < maxLength) { + int tries = timeout_ms; + size_t newLength; + while (!(newLength = client.available()) && tries--) delay(1); + if (!newLength) { + break; + } + if (!buf) { + buf = (char *) malloc(newLength + 1); + if (!buf) { + return nullptr; + } + } + else { + char* newBuf = (char *) realloc(buf, dataLength + newLength + 1); + if (!newBuf) { + free(buf); + return nullptr; + } + buf = newBuf; + } + client.readBytes(buf + dataLength, newLength); + dataLength += newLength; + buf[dataLength] = '\0'; + } + return buf; +} + +bool ESP8266WebServer::_parseRequest(WiFiClient& client) { + // Read the first line of HTTP request + String req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + //reset header value + for (int i = 0; i < _headerKeysCount; ++i) { + _currentHeaders[i].value =String(); + } + + // First line of HTTP request looks like "GET /path HTTP/1.1" + // Retrieve the "/path" part by finding the spaces + int addr_start = req.indexOf(' '); + int addr_end = req.indexOf(' ', addr_start + 1); + if (addr_start == -1 || addr_end == -1) { +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("Invalid request: "); + DEBUG_OUTPUT.println(req); +#endif + return false; + } + + String methodStr = req.substring(0, addr_start); + String url = req.substring(addr_start + 1, addr_end); + String versionEnd = req.substring(addr_end + 8); + _currentVersion = atoi(versionEnd.c_str()); + String searchStr = ""; + int hasSearch = url.indexOf('?'); + if (hasSearch != -1){ + searchStr = url.substring(hasSearch + 1); + url = url.substring(0, hasSearch); + } + _currentUri = url; + _chunked = false; + + HTTPMethod method = HTTP_GET; + if (methodStr == F("POST")) { + method = HTTP_POST; + } else if (methodStr == F("DELETE")) { + method = HTTP_DELETE; + } else if (methodStr == F("OPTIONS")) { + method = HTTP_OPTIONS; + } else if (methodStr == F("PUT")) { + method = HTTP_PUT; + } else if (methodStr == F("PATCH")) { + method = HTTP_PATCH; + } + _currentMethod = method; + +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("method: "); + DEBUG_OUTPUT.print(methodStr); + DEBUG_OUTPUT.print(" url: "); + DEBUG_OUTPUT.print(url); + DEBUG_OUTPUT.print(" search: "); + DEBUG_OUTPUT.println(searchStr); +#endif + + //attach handler + RequestHandler* handler; + for (handler = _firstHandler; handler; handler = handler->next()) { + if (handler->canHandle(_currentMethod, _currentUri)) + break; + } + _currentHandler = handler; + + String formData; + // below is needed only when POST type request + if (method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){ + String boundaryStr; + String headerName; + String headerValue; + bool isForm = false; + bool isEncoded = false; + uint32_t contentLength = 0; + //parse headers + while(1){ + req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + if (req == "") break;//no moar headers + int headerDiv = req.indexOf(':'); + if (headerDiv == -1){ + break; + } + headerName = req.substring(0, headerDiv); + headerValue = req.substring(headerDiv + 1); + headerValue.trim(); + _collectHeader(headerName.c_str(),headerValue.c_str()); + + #ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("headerName: "); + DEBUG_OUTPUT.println(headerName); + DEBUG_OUTPUT.print("headerValue: "); + DEBUG_OUTPUT.println(headerValue); + #endif + + if (headerName.equalsIgnoreCase(FPSTR(Content_Type))){ + using namespace mime; + if (headerValue.startsWith(FPSTR(mimeTable[txt].mimeType))){ + isForm = false; + } else if (headerValue.startsWith(F("application/x-www-form-urlencoded"))){ + isForm = false; + isEncoded = true; + } else if (headerValue.startsWith(F("multipart/"))){ + boundaryStr = headerValue.substring(headerValue.indexOf('=') + 1); + boundaryStr.replace("\"",""); + isForm = true; + } + } else if (headerName.equalsIgnoreCase(F("Content-Length"))){ + contentLength = headerValue.toInt(); + } else if (headerName.equalsIgnoreCase(F("Host"))){ + _hostHeader = headerValue; + } + } + + if (!isForm){ + size_t plainLength; + char* plainBuf = readBytesWithTimeout(client, contentLength, plainLength, HTTP_MAX_POST_WAIT); + if (plainLength < contentLength) { + free(plainBuf); + return false; + } + if (contentLength > 0) { + if(isEncoded){ + //url encoded form + if (searchStr != "") searchStr += '&'; + searchStr += plainBuf; + } + _parseArguments(searchStr); + if(!isEncoded||(0==_currentArgCount)){ // @20180124OF01: Workarround for Alexa Bug + //plain post json or other data + RequestArgument& arg = _currentArgs[_currentArgCount++]; + arg.key = F("plain"); + arg.value = String(plainBuf); + } + + #ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("Plain: "); + DEBUG_OUTPUT.println(plainBuf); + #endif + free(plainBuf); + } else { + // No content - but we can still have arguments in the URL. + _parseArguments(searchStr); + } + } + + if (isForm){ + _parseArguments(searchStr); + if (!_parseForm(client, boundaryStr, contentLength)) { + return false; + } + } + } else { + String headerName; + String headerValue; + //parse headers + while(1){ + req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + if (req == "") break;//no moar headers + int headerDiv = req.indexOf(':'); + if (headerDiv == -1){ + break; + } + headerName = req.substring(0, headerDiv); + headerValue = req.substring(headerDiv + 2); + _collectHeader(headerName.c_str(),headerValue.c_str()); + + #ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("headerName: "); + DEBUG_OUTPUT.println(headerName); + DEBUG_OUTPUT.print("headerValue: "); + DEBUG_OUTPUT.println(headerValue); + #endif + + if (headerName.equalsIgnoreCase("Host")){ + _hostHeader = headerValue; + } + } + _parseArguments(searchStr); + } + client.flush(); + +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("Request: "); + DEBUG_OUTPUT.println(url); + DEBUG_OUTPUT.print(" Arguments: "); + DEBUG_OUTPUT.println(searchStr); +#endif + + return true; +} + +bool ESP8266WebServer::_collectHeader(const char* headerName, const char* headerValue) { + for (int i = 0; i < _headerKeysCount; i++) { + if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) { + _currentHeaders[i].value=headerValue; + return true; + } + } + return false; +} + +void ESP8266WebServer::_parseArguments(String data) { +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("args: "); + DEBUG_OUTPUT.println(data); +#endif + if (_currentArgs) + delete[] _currentArgs; + _currentArgs = 0; + if (data.length() == 0) { + _currentArgCount = 0; + _currentArgs = new RequestArgument[1]; + return; + } + _currentArgCount = 1; + + for (int i = 0; i < (int)data.length(); ) { + i = data.indexOf('&', i); + if (i == -1) + break; + ++i; + ++_currentArgCount; + } +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("args count: "); + DEBUG_OUTPUT.println(_currentArgCount); +#endif + + _currentArgs = new RequestArgument[_currentArgCount+1]; + int pos = 0; + int iarg; + for (iarg = 0; iarg < _currentArgCount;) { + int equal_sign_index = data.indexOf('=', pos); + int next_arg_index = data.indexOf('&', pos); +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("pos "); + DEBUG_OUTPUT.print(pos); + DEBUG_OUTPUT.print("=@ "); + DEBUG_OUTPUT.print(equal_sign_index); + DEBUG_OUTPUT.print(" &@ "); + DEBUG_OUTPUT.println(next_arg_index); +#endif + if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) { +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("arg missing value: "); + DEBUG_OUTPUT.println(iarg); +#endif + if (next_arg_index == -1) + break; + pos = next_arg_index + 1; + continue; + } + RequestArgument& arg = _currentArgs[iarg]; + arg.key = urlDecode(data.substring(pos, equal_sign_index)); + arg.value = urlDecode(data.substring(equal_sign_index + 1, next_arg_index)); +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("arg "); + DEBUG_OUTPUT.print(iarg); + DEBUG_OUTPUT.print(" key: "); + DEBUG_OUTPUT.print(arg.key); + DEBUG_OUTPUT.print(" value: "); + DEBUG_OUTPUT.println(arg.value); +#endif + ++iarg; + if (next_arg_index == -1) + break; + pos = next_arg_index + 1; + } + _currentArgCount = iarg; +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("args count: "); + DEBUG_OUTPUT.println(_currentArgCount); +#endif + +} + +void ESP8266WebServer::_uploadWriteByte(uint8_t b){ + if (_currentUpload->currentSize == HTTP_UPLOAD_BUFLEN){ + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); + _currentUpload->totalSize += _currentUpload->currentSize; + _currentUpload->currentSize = 0; + } + _currentUpload->buf[_currentUpload->currentSize++] = b; +} + +uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){ + int res = client.read(); + if(res == -1){ + while(!client.available() && client.connected()) + yield(); + res = client.read(); + } + return (uint8_t)res; +} + +bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){ + (void) len; +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("Parse Form: Boundary: "); + DEBUG_OUTPUT.print(boundary); + DEBUG_OUTPUT.print(" Length: "); + DEBUG_OUTPUT.println(len); +#endif + String line; + int retry = 0; + do { + line = client.readStringUntil('\r'); + ++retry; + } while (line.length() == 0 && retry < 3); + + client.readStringUntil('\n'); + //start reading the form + if (line == ("--"+boundary)){ + RequestArgument* postArgs = new RequestArgument[32]; + int postArgsLen = 0; + while(1){ + String argName; + String argValue; + String argType; + String argFilename; + bool argIsFile = false; + + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){ + int nameStart = line.indexOf('='); + if (nameStart != -1){ + argName = line.substring(nameStart+2); + nameStart = argName.indexOf('='); + if (nameStart == -1){ + argName = argName.substring(0, argName.length() - 1); + } else { + argFilename = argName.substring(nameStart+2, argName.length() - 1); + argName = argName.substring(0, argName.indexOf('"')); + argIsFile = true; +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("PostArg FileName: "); + DEBUG_OUTPUT.println(argFilename); +#endif + //use GET to set the filename if uploading using blob + if (argFilename == F("blob") && hasArg(FPSTR(filename))) + argFilename = arg(FPSTR(filename)); + } +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("PostArg Name: "); + DEBUG_OUTPUT.println(argName); +#endif + using namespace mime; + argType = FPSTR(mimeTable[txt].mimeType); + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase(FPSTR(Content_Type))){ + argType = line.substring(line.indexOf(':')+2); + //skip next line + client.readStringUntil('\r'); + client.readStringUntil('\n'); + } +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("PostArg Type: "); + DEBUG_OUTPUT.println(argType); +#endif + if (!argIsFile){ + while(1){ + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + if (line.startsWith("--"+boundary)) break; + if (argValue.length() > 0) argValue += "\n"; + argValue += line; + } +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("PostArg Value: "); + DEBUG_OUTPUT.println(argValue); + DEBUG_OUTPUT.println(); +#endif + + RequestArgument& arg = postArgs[postArgsLen++]; + arg.key = argName; + arg.value = argValue; + + if (line == ("--"+boundary+"--")){ +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.println("Done Parsing POST"); +#endif + break; + } + } else { + _currentUpload.reset(new HTTPUpload()); + _currentUpload->status = UPLOAD_FILE_START; + _currentUpload->name = argName; + _currentUpload->filename = argFilename; + _currentUpload->type = argType; + _currentUpload->totalSize = 0; + _currentUpload->currentSize = 0; +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("Start File: "); + DEBUG_OUTPUT.print(_currentUpload->filename); + DEBUG_OUTPUT.print(" Type: "); + DEBUG_OUTPUT.println(_currentUpload->type); +#endif + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); + _currentUpload->status = UPLOAD_FILE_WRITE; + uint8_t argByte = _uploadReadByte(client); +readfile: + while(argByte != 0x0D){ + if (!client.connected()) return _parseFormUploadAborted(); + _uploadWriteByte(argByte); + argByte = _uploadReadByte(client); + } + + argByte = _uploadReadByte(client); + if (!client.connected()) return _parseFormUploadAborted(); + if (argByte == 0x0A){ + argByte = _uploadReadByte(client); + if (!client.connected()) return _parseFormUploadAborted(); + if ((char)argByte != '-'){ + //continue reading the file + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + goto readfile; + } else { + argByte = _uploadReadByte(client); + if (!client.connected()) return _parseFormUploadAborted(); + if ((char)argByte != '-'){ + //continue reading the file + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + _uploadWriteByte((uint8_t)('-')); + goto readfile; + } + } + + uint8_t endBuf[boundary.length()]; + client.readBytes(endBuf, boundary.length()); + + if (strstr((const char*)endBuf, boundary.c_str()) != NULL){ + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); + _currentUpload->totalSize += _currentUpload->currentSize; + _currentUpload->status = UPLOAD_FILE_END; + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("End File: "); + DEBUG_OUTPUT.print(_currentUpload->filename); + DEBUG_OUTPUT.print(" Type: "); + DEBUG_OUTPUT.print(_currentUpload->type); + DEBUG_OUTPUT.print(" Size: "); + DEBUG_OUTPUT.println(_currentUpload->totalSize); +#endif + line = client.readStringUntil(0x0D); + client.readStringUntil(0x0A); + if (line == "--"){ +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.println("Done Parsing POST"); +#endif + break; + } + continue; + } else { + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + _uploadWriteByte((uint8_t)('-')); + _uploadWriteByte((uint8_t)('-')); + uint32_t i = 0; + while(i < boundary.length()){ + _uploadWriteByte(endBuf[i++]); + } + argByte = _uploadReadByte(client); + goto readfile; + } + } else { + _uploadWriteByte(0x0D); + goto readfile; + } + break; + } + } + } + } + + int iarg; + int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount; + for (iarg = 0; iarg < totalArgs; iarg++){ + RequestArgument& arg = postArgs[postArgsLen++]; + arg.key = _currentArgs[iarg].key; + arg.value = _currentArgs[iarg].value; + } + if (_currentArgs) delete[] _currentArgs; + _currentArgs = new RequestArgument[postArgsLen]; + for (iarg = 0; iarg < postArgsLen; iarg++){ + RequestArgument& arg = _currentArgs[iarg]; + arg.key = postArgs[iarg].key; + arg.value = postArgs[iarg].value; + } + _currentArgCount = iarg; + if (postArgs) + delete[] postArgs; + return true; + } +#ifdef DEBUG_ESP_HTTP_SERVER + DEBUG_OUTPUT.print("Error: line: "); + DEBUG_OUTPUT.println(line); +#endif + return false; +} + +String ESP8266WebServer::urlDecode(const String& text) +{ + String decoded = ""; + char temp[] = "0x00"; + unsigned int len = text.length(); + unsigned int i = 0; + while (i < len) + { + char decodedChar; + char encodedChar = text.charAt(i++); + if ((encodedChar == '%') && (i + 1 < len)) + { + temp[2] = text.charAt(i++); + temp[3] = text.charAt(i++); + + decodedChar = strtol(temp, NULL, 16); + } + else { + if (encodedChar == '+') + { + decodedChar = ' '; + } + else { + decodedChar = encodedChar; // normal ascii char + } + } + decoded += decodedChar; + } + return decoded; +} + +bool ESP8266WebServer::_parseFormUploadAborted(){ + _currentUpload->status = UPLOAD_FILE_ABORTED; + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); + return false; +} + +#endif // ARDUINO_ESP8266_RELEASE \ No newline at end of file diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 158d0c5fe..0ef542e5e 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,142 @@ -/* 6.4.1 20181223 +/* 6.5.0 20190315 + * + * 6.4.1.21 20190309 + * Fix exception on GUI Configure Logging and Configure Other (#5424) + * Add support for sensor SCD30 (#5434) + * Add support for commands in sensor drivers + * Add 0x to IRRemote (SetOption29) and RCSwitch (SetOption28) received hexadecimal data (#5431) + * Add button control when no relay configured (#4682) + * + * 6.4.1.20 20190304 + * Changed webserver content handling from single String to small Chunks increasing RAM + * Changed logging message handling + * Fix additional characters in fallbacktopic, hostname and mqttclient on core 2.5.0 (#5359, #5417) + * Add command Template 255 to copy module configuration over to current active template and store as user template named Merged (#5371) + * + * 6.4.1.19 20190222 + * Add command SetOption37 for RGBCW color mapping (#5326) + * Add Korean language translations (#5344) + * Fix Energy TotalStartTime when commands EnergyReset0 and/or EnergyReset3 used (#5373) + * Fix DS18S20 temperature calculation (#5375) + * Fix float calculations in range from 0 to -1 (#5386) + * + * 6.4.1.18 20190221 + * Fix some exceptions and watchdogs due to lack of stack space - part 1 (#5215) + * Fix some exceptions and watchdogs due to lack of stack space - part 2 + * Add command SetOption62 0/1 to disable retain on Button or Swith hold messages (#5299) + * Add option WifiConfig 7 to allow reset of device in AP mode without admin password (#5297) + * Fix command WebSend when using a port number as regression from 6.4.1.17 (#5304) + * + * 6.4.1.17 20190214 + * Change template update by removing possibility to add user module config keeping template as defined (#5222) + * Fix regression from 6.4.1.16 where GPIO9 and GPIO10 connected devices did not work (#5197) + * Fix GUI wifi password acception starting with asteriks (*) (#5231, #5242) + * Add rule expression enabled by define USE_EXPRESSION in my_user_config.h (#5210) + * Add Configure Template menu option to GUI (#5222) + * Remove command SetOption62 as it's functionality is replaced by user changing the device template (#5255) + * Add property LinkCount to state and status 11 message representing number of Wifi Link re-connections + * Add property MqttCount to status 6 message representing number of Mqtt re-connections + * Add property Downtime to state and status 11 message representing the duration of wifi connection loss + * Fix command WebSend intermittent results (#5273) + * + * 6.4.1.16 20190211 + * Initial support for online template change using command Template or GUI Configure Other (#5177) + * Add parameter CFG_HOLDER to status 1 message (#5206) + * Update GUI + * + * 6.4.1.15 20190208 + * Change image name BE_MINIMAL to FIRMWARE_MINIMAL (#5106) + * Change image names USE_xyz to FIRMWARE_xyz (#5106) + * Add command SerialDelimiter 128 to filter reception of only characters between ASCII 32 and 127 (#5131) + * Add status message to former declined group commands (#5145) + * + * 6.4.1.14 20190203 + * Add SetOption32 until SetOption49 diagnostic information to Status 3 report as replacement for second property value in SetOption property name + * Add Resolution property to Status 3 report providing previous SetOption second value property + * Fix IR local echo + * Add user configuration of HLW8012 and HJL-01/BL0937 Energy Monitoring as used in Sonoff S31, Pow Ra and many Tuya based devices + * Add user configuration of MCP39F501 Energy Monitoring as used in Shelly2 + * Add support for multiple ADS1115 I2C devices (#5083) + * Add rule support for "==", "!=" ">=" and "<=" (#5122) + * Add Hass status sensor (#5139) + * Change GUI weblog solving possible empty screens (#5154) + * Change PN532 support from I2C to Serial for more stability (#5162) + * Add MHZ19 Temperature as Domoticz Temperature selection (#5128) + * + * 6.4.1.13 20190130 + * Add command SetOption36 to control boot loop default restoration (#4645, #5063) + * Add resiliency to saved Settings (#5065) + * + * 6.4.1.12 20190128 + * Change code use of boolean to bool and byte to uint8_t + * Change code uint8_t flags to bool flags + * + * 6.4.1.11 20190124 + * Remove command SetOption14 as it has been superseded by command Interlock + * Remove command SetOption63 as it has been superseded by command Interlock + * Add command Interlock 0 / 1 / 1,2 3,4 .. to control interlock ON/OFF and add up to 8 relays in 1 to 4 interlock groups (#5014) + * Add core version conditional compile options to provided PWM files (#4917) + * Add support for inverted buttons and inverted buttons without pullup (#4914) + * + * 6.4.1.10 20190121 + * Fix Hass discovery of MHZ19(B) sensors (#4992) + * Fix Hass Software Watchdog exception during discovery (#4988) + * Add support for MAX44009 Ambient Light sensor (#4907) + * + * 6.4.1.9 20190115 + * Add support for Mi LED Desk Lamp with rotary switch (#4887) + * Fix mDNS addService (#4938, #4951) + * Fix allowable MAX_RULE_VARS to 16 (#4933) + * Add (S)SerialSend3 escape sequence \x to allow hexadecimal byte value (#3560, #4947) + * Add SerialBridge command SSerialSend5 + * + * 6.4.1.8 20190107 + * Change sonoff_template.h layout regarding optional module flags like ADC0 + * Add command SetOption62 1 to force no Button/Switch pullup on dedicated modules. Currently only supported on Shelly2 (#4841) + * Fix Display exception 28 when JSON value is NULL received + * Fix Home Assistant Sensor Discovery Software Watchdog restart (#4831) + * Add support for OBI Power Socket 2 (#4829) + * Add support for YTF IR Bridge (#4855) + * Change web authentication (#4865) + * Add support for Digoo DG-SP202 Smart Socket with Energy monitoring (#4891) + * Add support for Smanergy KA10 Smart Wall Socket with Energy monitoring + * Add support for Luminea ZX2820 Smart Socket with Energy monitoring (#4921) + * Add define MDNS_ENABLE to control initial mDNS state (#4923) + * Add split interlock part 1 (#4910) + * + * 6.4.1.7 20190106 + * Fix HLW8012, HJL01 and BL0937 based energy sensors low Power (below 10W) measurement regression from 6.4.1.6 + * Add Power status functionality to LED2 when configured leaving LED1 for Link status indication + * Add no pull-up control to Shelly 2 module (default is pull-up, change GPIO2 to Switch3n for no pull-up) (#4841) + * Add 4 seconds startup delay to button control (#4829) + * Change button driver making it modular + * + * 6.4.1.6 20190105 + * Add commands PowerCal, VoltageCal and CurrentCal for HLW8012, HJL01 and BL0937 based energy sensors + * + * 6.4.1.5 20190103 + * Remove command SetOption35 0-255 for mDNS start-up delay (#4793) + * Add command SetOption55 0/1 to disable/enable mDNS (#4793) + * + * 6.4.1.4 20190101 + * Update Copyright (C) 2019 + * Fix epaper driver (#4785) + * Add support for Near Field Communication (NFC) controller PN532 using I2C (#4791) + * + * 6.4.1.3 20181229 + * Change sonoff_template.h module lay-out by removing non-configurable GPIOs + * Add support for MAX31855 K-Type thermocouple sensor using softSPI (#4764) + * + * 6.4.1.2 20181228 + * Change switch driver making it modular and introduce input filter (#4665, #4724) + * Add define DS18B20_INTERNAL_PULLUP to select internal input pullup when only one DS18B20 sensor is connected eliminating external resistor (#4738) + * Add variable %timestamp% to rules (#4749) + * + * 6.4.1.1 20181224 + * Fix most compiler warnings + * Change switch input detection by optimizing switch debounce (#4724) + * + * 6.4.1 20181224 * Change RAM usage BMP/BME I2C sensors * Change FallbackTopic from cmnd// to cmnd/_fb/ to discriminate from Topic (#1528) * Change FallbackTopic detection (#4706) diff --git a/sonoff/core_esp8266_timer.c b/sonoff/core_esp8266_timer.c index 81c3a76e0..bf852784c 100644 --- a/sonoff/core_esp8266_timer.c +++ b/sonoff/core_esp8266_timer.c @@ -19,10 +19,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -// Use PWM from core 2.4.0 as all other version produce LED flickering when settings are saved to flash. Still true for 2.5.0 -//#include -//#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) -//#warning **** Tasmota is using v2.4.0 timer.c as planned **** +// Use PWM from core 2.4.0 as all versions below 2.5.0-beta3 produce LED flickering when settings are saved to flash +#include +#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) +#warning **** Tasmota is using v2.4.0 timer.c as planned **** #include "wiring_private.h" #include "pins_arduino.h" @@ -108,4 +108,4 @@ void ICACHE_RAM_ATTR timer0_detachInterrupt(void) { ETS_CCOMPARE0_DISABLE(); } -//#endif // ARDUINO_ESP8266_RELEASE +#endif // ARDUINO_ESP8266_RELEASE diff --git a/sonoff/core_esp8266_wiring_digital.c b/sonoff/core_esp8266_wiring_digital.c index 33de53c75..f8d521748 100644 --- a/sonoff/core_esp8266_wiring_digital.c +++ b/sonoff/core_esp8266_wiring_digital.c @@ -19,10 +19,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -// Use PWM from core 2.4.0 as all other version produce LED flickering when settings are saved to flash. Still true for 2.5.0 -//#include -//#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) -//#warning **** Tasmota is using v2.4.0 wiring_digital.c as planned **** +// Use PWM from core 2.4.0 as all versions below 2.5.0-beta3 produce LED flickering when settings are saved to flash +#include +#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) +#warning **** Tasmota is using v2.4.0 wiring_digital.c as planned **** #define ARDUINO_MAIN #include "wiring_private.h" @@ -214,4 +214,4 @@ extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead") extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt"))); extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt"))); -//#endif // ARDUINO_ESP8266_RELEASE +#endif // ARDUINO_ESP8266_RELEASE diff --git a/sonoff/core_esp8266_wiring_pwm.c b/sonoff/core_esp8266_wiring_pwm.c index 780190059..d7e179b9b 100644 --- a/sonoff/core_esp8266_wiring_pwm.c +++ b/sonoff/core_esp8266_wiring_pwm.c @@ -19,10 +19,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -// Use PWM from core 2.4.0 as all other version produce flicker when settings are saved to flash. Still true for 2.5.0 -//#include -//#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) -//#warning **** Tasmota is using v2.4.0 wiring_pwm.c as planned **** +// Use PWM from core 2.4.0 as all versions below 2.5.0-beta3 produce LED flickering when settings are saved to flash +#include +#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) +#warning **** Tasmota is using v2.4.0 wiring_pwm.c as planned **** #include "wiring_private.h" #include "pins_arduino.h" @@ -226,4 +226,4 @@ extern void analogWrite(uint8_t pin, int val) __attribute__ ((weak, alias("__ana extern void analogWriteFreq(uint32_t freq) __attribute__ ((weak, alias("__analogWriteFreq"))); extern void analogWriteRange(uint32_t range) __attribute__ ((weak, alias("__analogWriteRange"))); -//#endif // ARDUINO_ESP8266_RELEASE +#endif // ARDUINO_ESP8266_RELEASE diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 2347cba22..73e228124 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -1,7 +1,7 @@ /* i18n.h - internationalization for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,6 +44,7 @@ #define D_JSON_CHANNEL "Channel" #define D_JSON_CO2 "CarbonDioxide" #define D_JSON_COMMAND "Command" +#define D_JSON_CONFIG_HOLDER "CfgHolder" #define D_JSON_CONNECT_FAILED "Connect failed" #define D_JSON_COREVERSION "Core" #define D_JSON_COUNT "Count" @@ -53,6 +54,7 @@ #define D_JSON_DISTANCE "Distance" #define D_JSON_DNSSERVER "DNSServer" #define D_JSON_DONE "Done" +#define D_JSON_DOWNTIME "Downtime" #define D_JSON_ECO2 "eCO2" #define D_JSON_EMPTY "Empty" #define D_JSON_ENDDST "EndDST" // End Daylight Savings Time @@ -72,6 +74,7 @@ #define D_JSON_FROM "from" #define D_JSON_GAS "Gas" #define D_JSON_GATEWAY "Gateway" +#define D_JSON_GROUPS "Groups" #define D_JSON_HEAPSIZE "Heap" #define D_JSON_HIGH "High" #define D_JSON_HOST_NOT_FOUND "Host not found" @@ -87,11 +90,14 @@ #define D_JSON_INFRARED "Infrared" #define D_JSON_UNKNOWN "Unknown" #define D_JSON_LIGHT "Light" +#define D_JSON_LINK_COUNT "LinkCount" #define D_JSON_LOCAL_TIME "Local" #define D_JSON_LOW "Low" #define D_JSON_MAC "Mac" #define D_JSON_MASK "Mask" #define D_JSON_MINIMAL "minimal" +#define D_JSON_MODEL "Model" +#define D_JSON_MQTT_COUNT "MqttCount" #define D_JSON_NO "No" #define D_JSON_NOISE "Noise" #define D_JSON_NONE "None" @@ -106,9 +112,12 @@ #define D_JSON_PRESSURE "Pressure" #define D_JSON_PRESSUREATSEALEVEL "SeaPressure" #define D_JSON_PRESSURE_UNIT "PressureUnit" +#define D_JSON_PROBETEMPERATURE "ProbeTemperature" #define D_JSON_PROGRAMFLASHSIZE "ProgramFlashSize" #define D_JSON_PROGRAMSIZE "ProgramSize" +#define D_JSON_REFERENCETEMPERATURE "ReferenceTemperature" #define D_JSON_RESET "Reset" +#define D_JSON_RESOLUTION "Resolution" #define D_JSON_RESTARTING "Restarting" #define D_JSON_RESTARTREASON "RestartReason" #define D_JSON_RSSI "RSSI" @@ -155,6 +164,7 @@ #define D_JSON_ZERO_POINT_CALIBRATION "Zero Point Calibration" #define D_RSLT_ENERGY "ENERGY" +#define D_RSLT_HASS_STATE "HASS_STATE" #define D_RSLT_INFO "INFO" #define D_RSLT_MARGINS "MARGINS" #define D_RSLT_POWER "POWER" @@ -164,6 +174,8 @@ #define D_RSLT_UPTIME "UPTIME" #define D_RSLT_WARNING "WARNING" +#define D_LOG_SOME_SETTINGS_RESET "Some settings have been reset" + // Commands sonoff.ino #define D_CMND_BACKLOG "Backlog" #define D_CMND_DELAY "Delay" @@ -236,8 +248,10 @@ #define D_WCFG_4_RETRY "Retry" #define D_WCFG_5_WAIT "Wait" #define D_WCFG_6_SERIAL "Serial" + #define D_WCFG_7_WIFIMANAGER_RESET_ONLY "ManagerRst" #define D_CMND_FRIENDLYNAME "FriendlyName" #define D_CMND_SWITCHMODE "SwitchMode" +#define D_CMND_INTERLOCK "Interlock" #define D_CMND_TELEPERIOD "TelePeriod" #define D_CMND_RESTART "Restart" #define D_JSON_ONE_TO_RESTART "1 to restart" @@ -254,7 +268,11 @@ #define D_CMND_SERIALSEND "SerialSend" #define D_CMND_SERIALDELIMITER "SerialDelimiter" #define D_CMND_BAUDRATE "Baudrate" -#define D_LOG_SOME_SETTINGS_RESET "Some settings have been reset" +#define D_CMND_TEMPLATE "Template" + #define D_JSON_NAME "NAME" + #define D_JSON_GPIO "GPIO" + #define D_JSON_FLAG "FLAG" + #define D_JSON_BASE "BASE" // Commands xdrv_01_mqtt.ino #define D_CMND_MQTTHOST "MqttHost" @@ -405,6 +423,7 @@ /********************************************************************************************/ #define D_ASTERIX "********" +#define D_ASTERISK_PWD "****" #ifndef MY_LANGUAGE #include "language/en-GB.h" @@ -522,7 +541,8 @@ const char kWifiConfig[MAX_WIFI_OPTION][WCFG_MAX_STRING_LENGTH] PROGMEM = { D_WCFG_3_WPSCONFIG, D_WCFG_4_RETRY, D_WCFG_5_WAIT, - D_WCFG_6_SERIAL }; + D_WCFG_6_SERIAL, + D_WCFG_7_WIFIMANAGER_RESET_ONLY }; const char kPrefixes[3][PRFX_MAX_STRING_LENGTH] PROGMEM = { D_CMND, D_STAT, @@ -548,12 +568,17 @@ const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "%s{s}%s " D_PRESSUREATSEALEVEL "{m} const char HTTP_SNS_ANALOG[] PROGMEM = "%s{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; // {s} = , {m} = , {e} = const char HTTP_SNS_ILLUMINANCE[] PROGMEM = "%s{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = -#if defined(USE_MHZ19) || defined(USE_SENSEAIR) || defined(USE_AZ7798) +#if defined(USE_MHZ19) || defined(USE_SENSEAIR) || defined(USE_AZ7798) || defined(USE_SCD30) const char HTTP_SNS_CO2[] PROGMEM = "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = , {m} = , {e} = -#endif // USE_WEBSERVER +#endif // USE_MHZ19 + +#if defined(USE_SCD30) +const char HTTP_SNS_CO2EAVG[] PROGMEM = "%s{s}%s " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = , {m} = , {e} = +#endif // USE_SCD30 const char S_MAIN_MENU[] PROGMEM = D_MAIN_MENU; const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION; +const char S_CONFIGURE_TEMPLATE[] PROGMEM = D_CONFIGURE_TEMPLATE; const char S_CONFIGURE_MODULE[] PROGMEM = D_CONFIGURE_MODULE; const char S_CONFIGURE_WIFI[] PROGMEM = D_CONFIGURE_WIFI; const char S_NO_NETWORKS_FOUND[] PROGMEM = D_NO_NETWORKS_FOUND; diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index 222c62b58..6d44af3ff 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -1,7 +1,7 @@ /* bg-BG.h - localization for Bulgaria - Bulgarian for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v6.4.0.1 + * Updated until v6.4.1.18 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -148,6 +148,7 @@ #define D_STOP "Стоп" #define D_SUBNET_MASK "Маска на подмрежата" #define D_SUBSCRIBE_TO "Записване за" +#define D_UNSUBSCRIBE_FROM "Отписване от" #define D_SUCCESSFUL "Успешно" #define D_SUNRISE "Изгрев" #define D_SUNSET "Залез" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Параметри на модула" #define D_MODULE_TYPE "Тип на модула" +#define D_PULLUP_ENABLE "Без pull-up за бутон/ключ" #define D_GPIO "GPIO" #define D_SERIAL_IN "Сериен вход" #define D_SERIAL_OUT "Сериен изход" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Период на телеметрия" #define D_OTHER_PARAMETERS "Други параметри" +#define D_TEMPLATE "Модел" +#define D_ACTIVATE "Активирай" #define D_WEB_ADMIN_PASSWORD "Парола на уеб администратора" #define D_MQTT_ENABLE "Активиране на MQTT" #define D_FRIENDLY_NAME "Приятелско име" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "Единично" #define D_MULTI_DEVICE "Мулти" +#define D_CONFIGURE_TEMPLATE "Конфигуриране на модел" +#define D_TEMPLATE_PARAMETERS "Параметри на модел" +#define D_TEMPLATE_NAME "Име" +#define D_BASE_TYPE "Базиран на" +#define D_TEMPLATE_FLAGS "Флагове" +#define D_ALLOW_ADC0 "ADC0 вход" +#define D_ALLOW_PULLUP "Потребителски избор на pull-up" + #define D_SAVE_CONFIGURATION "Запазване на конфигурацията" #define D_CONFIGURATION_SAVED "Конфигурацията е запазена" #define D_CONFIGURATION_RESET "Конфигурацията е изчистена" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "Ю" #define D_TX20_WEST "З" -// sonoff_template.h -#define D_SENSOR_NONE "Няма" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 плейър" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Ключ" // Suffix "1" -#define D_SENSOR_BUTTON "Бутон" // Suffix "1" -#define D_SENSOR_RELAY "Реле" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Брояч" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "Подсветка" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF датчик" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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 "Потребит." +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 плейър" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Ключ" // Suffix "1" +#define D_SENSOR_BUTTON "Бутон" // Suffix "1" +#define D_SENSOR_RELAY "Реле" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Брояч" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "Подсветка" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF датчик" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 45f55af6a..e4053ea75 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -1,7 +1,7 @@ /* cs-CZ.h - localization for Czech with diacritics - Czech for Sonoff-Tasmota - Copyright (C) 2018 Vladimír Synek + Copyright (C) 2019 Vladimír Synek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Stop" #define D_SUBNET_MASK "Maska podsítě" #define D_SUBSCRIBE_TO "Přihlaš se do" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "úspěšné." #define D_SUNRISE "Svítání" #define D_SUNSET "Soumrak" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Nastavení modulu" #define D_MODULE_TYPE "Typ modulu" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial In" #define D_SERIAL_OUT "Serial Out" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Interval telemetrie" #define D_OTHER_PARAMETERS "Další nastavení" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Heslo Web administrátora" #define D_MQTT_ENABLE "MQTT aktivní" #define D_FRIENDLY_NAME "Friendly Name" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "single device" #define D_MULTI_DEVICE "multi device" +#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_SAVE_CONFIGURATION "Ulož nastavení" #define D_CONFIGURATION_SAVED "Nastavení uloženo" #define D_CONFIGURATION_RESET "Nastavení resetováno" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "J" #define D_TX20_WEST "Z" -// sonoff_template.h -#define D_SENSOR_NONE "Není" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Spínač" // Suffix "1" -#define D_SENSOR_BUTTON "Tlačítko" // Suffix "1" -#define D_SENSOR_RELAY "Relé" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1", -#define D_SENSOR_COUNTER "Počítadlo" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Spínač" // Suffix "1" +#define D_SENSOR_BUTTON "Tlačítko" // Suffix "1" +#define D_SENSOR_RELAY "Relé" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1", +#define D_SENSOR_COUNTER "Počítadlo" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 23d8de9ed..d93f77b89 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -1,7 +1,7 @@ /* de-DE.h - localization for German - Germany for Sonoff-Tasmota - Copyright (C) 2018 VinceMasuka + Copyright (C) 2019 VinceMasuka This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v6.3.0.17 + * Updated until v6.4.1.18 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -148,6 +148,7 @@ #define D_STOP "Stop" #define D_SUBNET_MASK "Subnetzmaske" #define D_SUBSCRIBE_TO "abonniere" +#define D_UNSUBSCRIBE_FROM "löse abo. von" #define D_SUCCESSFUL "erfolgreich" #define D_SUNRISE "Sonnenaufgang" #define D_SUNSET "Sonnenuntergang" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Geräte-Einstellungen" #define D_MODULE_TYPE "Gerätetyp" +#define D_PULLUP_ENABLE "Kein Taster/Schalter Pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "serieller Eingang [serial in]" #define D_SERIAL_OUT "serieller Ausgang [serial out]" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Telemetrieperiode" #define D_OTHER_PARAMETERS "Sonstige Einstellungen" +#define D_TEMPLATE "Vorlage" +#define D_ACTIVATE "Aktivieren" #define D_WEB_ADMIN_PASSWORD "Passwort für Web Oberfläche" #define D_MQTT_ENABLE "MQTT aktivieren" #define D_FRIENDLY_NAME "Name [friendly name]" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "Einzelnes Gerät" #define D_MULTI_DEVICE "Mehrfachgerät" +#define D_CONFIGURE_TEMPLATE "Vorlage konfigurieren" +#define D_TEMPLATE_PARAMETERS "Vorlage Parameter" +#define D_TEMPLATE_NAME "Name" +#define D_BASE_TYPE "basiert auf" +#define D_TEMPLATE_FLAGS "Options" +#define D_ALLOW_ADC0 "ADC0 input" +#define D_ALLOW_PULLUP "Nutzer pull-up Auswahl" + #define D_SAVE_CONFIGURATION "Konfiguration speichern" #define D_CONFIGURATION_SAVED "Konfiguration gespeichert" #define D_CONFIGURATION_RESET "Konfiguration zurücksetzen" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "None" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRSend" -#define D_SENSOR_SWITCH "Switch " // Suffix "1" -#define D_SENSOR_BUTTON "Button " // Suffix "1" -#define D_SENSOR_RELAY "Relay " // Suffix "1i" -#define D_SENSOR_LED "LED " // Suffix "1i" -#define D_SENSOR_PWM "PWM " // Suffix "1" -#define D_SENSOR_COUNTER "Counter" // Suffix "1" -#define D_SENSOR_IRRECV "IRRecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Switch" // Suffix "1" +#define D_SENSOR_BUTTON "Button" // Suffix "1" +#define D_SENSOR_RELAY "Relay" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Counter" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index a8b48ed35..8a3fe75a5 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -1,7 +1,7 @@ /* el-GR.h - localization for Greek - Greece for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends (translated by Nick Galfas) + Copyright (C) 2019 Theo Arends (translated by Nick Galfas) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Τερματισμός" #define D_SUBNET_MASK "Μάσκα υποδικτύου" #define D_SUBSCRIBE_TO "Εγγραφή στο" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Επιτυχές" #define D_SUNRISE "Σούρουπο" #define D_SUNSET "Ηλιοβασίλεμα" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Παράμετροι μονάδας" #define D_MODULE_TYPE "Τύπος μονάδας" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial In" #define D_SERIAL_OUT "Serial Out" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Περίοδος τηλεμετρίας" #define D_OTHER_PARAMETERS "Άλλες παράμετροι" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Κωδικός διαχειριστή" #define D_MQTT_ENABLE "Ενεργοποίηση MQTT" #define D_FRIENDLY_NAME "Φιλική ονομασία" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "μονή συσκευή" #define D_MULTI_DEVICE "πολλαπλές συσκευές" +#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_SAVE_CONFIGURATION "Αποθήκευση ρυθμίσεων" #define D_CONFIGURATION_SAVED "Οι ρυθμίσεις αποθηκεύτηκαν" #define D_CONFIGURATION_RESET "Επαναφορά ρυθμίσεων" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "Ν" #define D_TX20_WEST "Δ" -// sonoff_template.h -#define D_SENSOR_NONE "Κανένα" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Διακόπτης" // Suffix "1" -#define D_SENSOR_BUTTON "Κουμπί" // Suffix "1" -#define D_SENSOR_RELAY "Ρελέ" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Μετρητής" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Διακόπτης" // Suffix "1" +#define D_SENSOR_BUTTON "Κουμπί" // Suffix "1" +#define D_SENSOR_RELAY "Ρελέ" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Μετρητής" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 2ea9c249a..e459cd02d 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -1,7 +1,7 @@ /* en-GB.h - localization for English - United Kingdom for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Stop" #define D_SUBNET_MASK "Subnet Mask" #define D_SUBSCRIBE_TO "Subscribe to" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Successful" #define D_SUNRISE "Sunrise" #define D_SUNSET "Sunset" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Module parameters" #define D_MODULE_TYPE "Module type" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial In" #define D_SERIAL_OUT "Serial Out" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Telemetry period" #define D_OTHER_PARAMETERS "Other parameters" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Web Admin Password" #define D_MQTT_ENABLE "MQTT enable" #define D_FRIENDLY_NAME "Friendly Name" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "single device" #define D_MULTI_DEVICE "multi device" +#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_SAVE_CONFIGURATION "Save configuration" #define D_CONFIGURATION_SAVED "Configuration saved" #define D_CONFIGURATION_RESET "Configuration reset" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "None" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Switch" // Suffix "1" -#define D_SENSOR_BUTTON "Button" // Suffix "1" -#define D_SENSOR_RELAY "Relay" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Counter" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Switch" // Suffix "1" +#define D_SENSOR_BUTTON "Button" // Suffix "1" +#define D_SENSOR_RELAY "Relay" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Counter" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 435f230ad..9f2187bbf 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -1,7 +1,7 @@ /* es-AR.h - localization for Spanish - Argentina for Sonoff-Tasmota - Copyright (C) 2018 Adrian Scillato + Copyright (C) 2019 Adrian Scillato This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Detener" #define D_SUBNET_MASK "Máscara Subred" #define D_SUBSCRIBE_TO "Suscribir a" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Exitosa" #define D_SUNRISE "Salida del Sol" #define D_SUNSET "Puesta del Sol" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Parámetros del módulo" #define D_MODULE_TYPE "Tipo de módulo" +#define D_PULLUP_ENABLE "Botón/Llave sin pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial In" #define D_SERIAL_OUT "Serial Out" @@ -287,6 +289,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_WEB_ADMIN_PASSWORD "Clave Administrador Web" #define D_MQTT_ENABLE "Habilitar MQTT" #define D_FRIENDLY_NAME "Nombre Amigable" @@ -295,6 +299,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_SAVE_CONFIGURATION "Grabar configuración" #define D_CONFIGURATION_SAVED "Configuración grabada" #define D_CONFIGURATION_RESET "Configuración restablecida" @@ -462,7 +474,7 @@ #define D_HX_CAL_REFERENCE "Poner Peso de Referencia" #define D_HX_CAL_DONE "Calibrado" #define D_HX_CAL_FAIL "Falló Calibración" -#define D_RESET_HX711 "Restableces Escala" +#define D_RESET_HX711 "Restablecer Escala" #define D_CONFIGURE_HX711 "Configurar Escala" #define D_HX711_PARAMETERS "Parámetros de Escala" #define D_ITEM_WEIGHT "Peso" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "O" -// sonoff_template.h -#define D_SENSOR_NONE "Ninguno" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IR TX" -#define D_SENSOR_SWITCH "Llave" // Suffix "1" -#define D_SENSOR_BUTTON "Botón" // Suffix "1" -#define D_SENSOR_RELAY "Relé" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Contador" // Suffix "1" -#define D_SENSOR_IRRECV "IR RX" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IR Tx" +#define D_SENSOR_SWITCH "Llave" // Suffix "1" +#define D_SENSOR_BUTTON "Botón" // Suffix "1" +#define D_SENSOR_RELAY "Relé" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Contador" // Suffix "1" +#define D_SENSOR_IRRECV "IR Rx" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 0638b408a..6b26a6212 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -1,7 +1,7 @@ /* fr-FR.h - localization for French - France for Sonoff-Tasmota - Copyright (C) 2018 Olivier Francais + Copyright (C) 2019 Olivier Francais This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v6.3.0.17 + * Updated until v6.4.1.18 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -98,8 +98,8 @@ #define D_GAS "Gaz" #define D_GATEWAY "Passerelle" #define D_GROUP "Groupe" -#define D_HOST "Host" -#define D_HOSTNAME "Hostname" +#define D_HOST "Hôte" +#define D_HOSTNAME "Nom d'Hôte" #define D_HUMIDITY "Humidité" #define D_ILLUMINANCE "Éclairement" #define D_IMMEDIATE "immédiat" // Button immediate @@ -138,7 +138,7 @@ #define D_RESTARTING "Redémarre" #define D_RESTART_REASON "Raison du redémarrage" #define D_RESTORE "restaurer" -#define D_RETAINED "retenu" +#define D_RETAINED "persistant" // MQTT #define D_RULE "Règle" #define D_SAVE "Enregistrer" #define D_SENSOR "Capteur" @@ -147,7 +147,8 @@ #define D_STD_TIME "STD" #define D_STOP "Stop" #define D_SUBNET_MASK "Masque sous-réseau" -#define D_SUBSCRIBE_TO "Souscrire à" +#define D_SUBSCRIBE_TO "S'abonner à" +#define D_UNSUBSCRIBE_FROM "Se désabonner de" #define D_SUCCESSFUL "Réussi" #define D_SUNRISE "Lever du jour" #define D_SUNSET "Tombée de la nuit" @@ -184,7 +185,7 @@ #define D_LEVEL_10 "level 1-0" #define D_LEVEL_01 "level 0-1" #define D_SERIAL_LOGGING_DISABLED "Journalisation série désactivée" -#define D_SYSLOG_LOGGING_REENABLED "Jounalisation syslog réactivée" +#define D_SYSLOG_LOGGING_REENABLED "Jounalisation SysLog réactivée" #define D_SET_BAUDRATE_TO "Définir le débit à" #define D_RECEIVED_TOPIC "Topic reçu" // Terme MQTT @@ -209,7 +210,7 @@ #define D_QUERY_DONE "Requête terminée. Services MQTT trouvés" #define D_MQTT_SERVICE_FOUND "Service MQTT trouvé sur" #define D_FOUND_AT "trouvé à" -#define D_SYSLOG_HOST_NOT_FOUND "Host syslog introuvable" +#define D_SYSLOG_HOST_NOT_FOUND "Hôte SysLog introuvable" // settings.ino #define D_SAVED_TO_FLASH_AT "Enregistré en flash à" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Paramètres module" #define D_MODULE_TYPE "Type de module" +#define D_PULLUP_ENABLE "Inter. sans pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Entrée série" #define D_SERIAL_OUT "Sortie série" @@ -280,13 +282,15 @@ #define D_LOGGING_PARAMETERS "Paramètres du journal" #define D_SERIAL_LOG_LEVEL "Niveau de journalisation série" #define D_WEB_LOG_LEVEL "Niveau de journalisation web" -#define D_SYS_LOG_LEVEL "Niveau Syslog" +#define D_SYS_LOG_LEVEL "Niveau SysLog" #define D_MORE_DEBUG "Plus de debug" -#define D_SYSLOG_HOST "Hôte Syslog" -#define D_SYSLOG_PORT "Port Syslog" +#define D_SYSLOG_HOST "Hôte SysLog" +#define D_SYSLOG_PORT "Port SysLog" #define D_TELEMETRY_PERIOD "Période télémétrie" #define D_OTHER_PARAMETERS "Autres paramètres" +#define D_TEMPLATE "Modèle" +#define D_ACTIVATE "Activer" #define D_WEB_ADMIN_PASSWORD "Mot de passe Web Admin" #define D_MQTT_ENABLE "MQTT activé" #define D_FRIENDLY_NAME "Surnom" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "module unique" #define D_MULTI_DEVICE "multi module" +#define D_CONFIGURE_TEMPLATE "Configuration du modèle" +#define D_TEMPLATE_PARAMETERS "Paramètres du modèle" +#define D_TEMPLATE_NAME "Nom" +#define D_BASE_TYPE "Basé sur" +#define D_TEMPLATE_FLAGS "Options" +#define D_ALLOW_ADC0 "Entrée ADC0" +#define D_ALLOW_PULLUP "Pull-up utilisateur" + #define D_SAVE_CONFIGURATION "Enregistrer la configuration" #define D_CONFIGURATION_SAVED "Configuration enregistrée" #define D_CONFIGURATION_RESET "Configuration réinitialisée" @@ -330,7 +342,7 @@ #define D_UPLOAD_ERR_3 "L'octet magique n'est pas 0xE9" #define D_UPLOAD_ERR_4 "La taille du programme à flasher est plus grande que la taille réelle de la mémoire flash" #define D_UPLOAD_ERR_5 "Erreur de comparaison du buffer de téléchargement" -#define D_UPLOAD_ERR_6 "Téléchargement échoué. Activer Weblog 3" +#define D_UPLOAD_ERR_6 "Téléchargement échoué. Activer WebLog 3" #define D_UPLOAD_ERR_7 "Téléchargement annulé" #define D_UPLOAD_ERR_8 "Fichier invalide" #define D_UPLOAD_ERR_9 "Fichier trop grand" @@ -341,7 +353,7 @@ #define D_UPLOAD_ERROR_CODE "Code d'erreur téléchargement" #define D_ENTER_COMMAND "Saisir une commande" -#define D_ENABLE_WEBLOG_FOR_RESPONSE "Activer Weblog 2 si une réponse est attendue" +#define D_ENABLE_WEBLOG_FOR_RESPONSE "Activer WebLog 2 si une réponse est attendue" #define D_NEED_USER_AND_PASSWORD "Nécessite utilisateur=&password=" // xdrv_01_mqtt.ino @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "O" -// sonoff_template.h -#define D_SENSOR_NONE "Aucun" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "ÉmetIR" -#define D_SENSOR_SWITCH "Inter." // Suffix "1" -#define D_SENSOR_BUTTON "Bouton" // Suffix "1" -#define D_SENSOR_RELAY "Relais" // Suffix "1i" -#define D_SENSOR_LED "LED" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Compteur" // Suffix "1" -#define D_SENSOR_IRRECV "RécptIR" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "RétroÉcl" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "ÉmetIR" +#define D_SENSOR_SWITCH "Inter." // Suffix "1" +#define D_SENSOR_BUTTON "Bouton" // Suffix "1" +#define D_SENSOR_RELAY "Relais" // Suffix "1i" +#define D_SENSOR_LED "LED" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Compteur" // Suffix "1" +#define D_SENSOR_IRRECV "RécptIR" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "RétroÉcl" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h index cd1b0e92e..9f3458889 100644 --- a/sonoff/language/he-HE.h +++ b/sonoff/language/he-HE.h @@ -1,7 +1,7 @@ /* he-HE.h - localization for Hebrew - Israel for Sonoff-Tasmota - Copyright (C) 2018 Yuval Mejahez + Copyright (C) 2019 Yuval Mejahez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "עצירה" #define D_SUBNET_MASK "רשת מסכת משנה" #define D_SUBSCRIBE_TO "הרשם ל" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "הצליח" #define D_SUNRISE "זריחה" #define D_SUNSET "שקיעה" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "מודול פרמטרים" #define D_MODULE_TYPE "סוג מודול" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO " רגל " #define D_SERIAL_IN "כניסת סריאל" #define D_SERIAL_OUT "יציאת סריאל" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Telemetry period" #define D_OTHER_PARAMETERS "פרמטרים שונים" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "סיסמת מנהל - אתר" #define D_MQTT_ENABLE "MQTT אפשר" #define D_FRIENDLY_NAME "שם ידידותי" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "התקן בודד" #define D_MULTI_DEVICE "התקנים" +#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_SAVE_CONFIGURATION "שמירת הגדרות" #define D_CONFIGURATION_SAVED "הגדרות נשמרו" #define D_CONFIGURATION_RESET "איפוס הגדרות" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "None" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "מתג" // Suffix "1" -#define D_SENSOR_BUTTON "לחצן" // Suffix "1" -#define D_SENSOR_RELAY "ממסר" // Suffix "1i" -#define D_SENSOR_LED "לד" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "מונה" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "מתג" // Suffix "1" +#define D_SENSOR_BUTTON "לחצן" // Suffix "1" +#define D_SENSOR_RELAY "ממסר" // Suffix "1i" +#define D_SENSOR_LED "לד" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "מונה" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 244d55776..649796121 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -1,7 +1,7 @@ /* hu-HU.h - localization for Hungarian in Hungary for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -52,36 +52,36 @@ // Common #define D_ADMIN "Admin" -#define D_AIR_QUALITY "Levegő minőség" +#define D_AIR_QUALITY "Levegőminőség" #define D_AP "AP" // Access Point #define D_AS "mint" #define D_AUTO "AUTO" #define D_BLINK "Villogás" -#define D_BLINKOFF "Villogás Ki" -#define D_BOOT_COUNT "Bootolások száma" +#define D_BLINKOFF "Villogás ki" +#define D_BOOT_COUNT "Újraindulások száma" #define D_BRIGHTLIGHT "Max. fényerő" -#define D_BSSID "BSSId" +#define D_BSSID "BSSID" #define D_BUTTON "Gomb" -#define D_BY "tőle:" // Written by me +#define D_BY "by" // Written by me #define D_BYTES "Byte-ok" #define D_CELSIUS "Celsius" -#define D_CHANNEL "Channel" +#define D_CHANNEL "Csatorna" #define D_CO2 "Szén-dioxid" #define D_CODE "kód" // Button code -#define D_COLDLIGHT "Hideg" +#define D_COLDLIGHT "Hideg fény" #define D_COMMAND "Parancs" -#define D_CONNECTED "Csatlakozva" +#define D_CONNECTED "Csatlakoztatva" #define D_COUNT "Szám" #define D_COUNTER "Számláló" -#define D_CURRENT "Áram" // As in Voltage and Current +#define D_CURRENT "Áramerősség" // As in Voltage and Current #define D_DATA "Adat" #define D_DARKLIGHT "Min. fényerő" #define D_DEBUG "Debug" #define D_DISABLED "Letiltva" -#define D_DISTANCE "Distance" -#define D_DNS_SERVER "DNS Szerver" +#define D_DISTANCE "Távolság" +#define D_DNS_SERVER "DNS szerver" #define D_DONE "Kész" -#define D_DST_TIME "DST" +#define D_DST_TIME "nyári idő" #define D_ECO2 "eCO2" #define D_EMULATION "Emuláció" #define D_ENABLED "Engedélyezve" @@ -90,24 +90,24 @@ #define D_FAHRENHEIT "Fahrenheit" #define D_FAILED "Sikertelen" #define D_FALLBACK "Fallback" -#define D_FALLBACK_TOPIC "Fallback Téma" +#define D_FALLBACK_TOPIC "fallback topik" #define D_FALSE "Hamis" -#define D_FILE "File" -#define D_FREE_MEMORY "Szabad Memória" -#define D_FREQUENCY "Frequency" +#define D_FILE "Fájl" +#define D_FREE_MEMORY "Szabad memória" +#define D_FREQUENCY "Frekvencia" #define D_GAS "Gáz" -#define D_GATEWAY "Gateway" +#define D_GATEWAY "Átjáró" #define D_GROUP "Csoport" -#define D_HOST "Host" -#define D_HOSTNAME "Hostname" +#define D_HOST "Hoszt" +#define D_HOSTNAME "Hosztnév" #define D_HUMIDITY "Páratartalom" #define D_ILLUMINANCE "Megvilágítás" #define D_IMMEDIATE "azonnali" // Button immediate #define D_INDEX "Index" #define D_INFO "Info" -#define D_INFRARED "Infrared" +#define D_INFRARED "Infravörös" #define D_INITIALIZED "Inicializálva" -#define D_IP_ADDRESS "IP Cím" +#define D_IP_ADDRESS "IP cím" #define D_LIGHT "Fény" #define D_LWT "LWT" #define D_MODULE "Modul" @@ -117,89 +117,90 @@ #define D_NONE "nincs" #define D_OFF "Ki" #define D_OFFLINE "Offline" -#define D_OK "Ok" +#define D_OK "OK" #define D_ON "Be" #define D_ONLINE "Online" #define D_PASSWORD "Jelszó" #define D_PORT "Port" -#define D_POWER_FACTOR "Teljesítmény tényező" +#define D_POWER_FACTOR "Teljesítménytényező" #define D_POWERUSAGE "Energiafelhasználás" -#define D_POWERUSAGE_ACTIVE "Active Power" -#define D_POWERUSAGE_APPARENT "Apparent Power" -#define D_POWERUSAGE_REACTIVE "Reactive Power" +#define D_POWERUSAGE_ACTIVE "Aktív teljesítmény" +#define D_POWERUSAGE_APPARENT "Látszólagos teljesítmény" +#define D_POWERUSAGE_REACTIVE "Reaktív teljesítmény" #define D_PRESSURE "Nyomás" #define D_PRESSUREATSEALEVEL "Tengerszinti nyomás" -#define D_PROGRAM_FLASH_SIZE "Program Flash Méret" -#define D_PROGRAM_SIZE "Program Méret" +#define D_PROGRAM_FLASH_SIZE "Program flash méret" +#define D_PROGRAM_SIZE "Program méret" #define D_PROJECT "Projekt" -#define D_RAIN "Rain" +#define D_RAIN "Eső" #define D_RECEIVED "Érkezett" #define D_RESTART "Újraindítás" #define D_RESTARTING "Újraindítás" -#define D_RESTART_REASON "Újraindítás oka:" +#define D_RESTART_REASON "Utolsó újraindulás oka" #define D_RESTORE "Visszaállítás" -#define D_RETAINED "mentve" -#define D_RULE "Rule" +#define D_RETAINED "retained" +#define D_RULE "Szabály" #define D_SAVE "Mentés" #define D_SENSOR "Szenzor" -#define D_SSID "SSId" +#define D_SSID "SSID" #define D_START "" #define D_STD_TIME "STD" #define D_STOP "Leállítás" -#define D_SUBNET_MASK "Subnet Mask" -#define D_SUBSCRIBE_TO "Feliratkozás a" +#define D_SUBNET_MASK "Alhálózati maszk" +#define D_SUBSCRIBE_TO "Feliratkozás a(z)" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Sikeres" -#define D_SUNRISE "Sunrise" -#define D_SUNSET "Sunset" +#define D_SUNRISE "Napkelte" +#define D_SUNSET "Napnyugta" #define D_TEMPERATURE "Hőmérséklet" #define D_TO "-nak" -#define D_TOGGLE "Toggle" -#define D_TOPIC "Téma" +#define D_TOGGLE "Megfordítás" +#define D_TOPIC "Topic" #define D_TRANSMIT "Továbbít" #define D_TRUE "Igaz" #define D_TVOC "TVOC" -#define D_UPGRADE "frissítés" +#define D_UPGRADE "Frissítés" #define D_UPLOAD "Feltöltés" #define D_UPTIME "Üzemidő" #define D_USER "Felhasználó" #define D_UTC_TIME "UTC" -#define D_UV_INDEX "UV Index" -#define D_UV_INDEX_1 "Low" -#define D_UV_INDEX_2 "Mid" -#define D_UV_INDEX_3 "High" -#define D_UV_INDEX_4 "Danger" -#define D_UV_INDEX_5 "BurnL1/2" -#define D_UV_INDEX_6 "BurnL3" -#define D_UV_INDEX_7 "OoR" -#define D_UV_LEVEL "UV Szint" -#define D_UV_POWER "UV Power" +#define D_UV_INDEX "UV index" +#define D_UV_INDEX_1 "alacsony" +#define D_UV_INDEX_2 "közepes" +#define D_UV_INDEX_3 "magas" +#define D_UV_INDEX_4 "veszélyes" +#define D_UV_INDEX_5 "égés L1/2" +#define D_UV_INDEX_6 "égés L3" +#define D_UV_INDEX_7 "tartományon kívül" +#define D_UV_LEVEL "UV szint" +#define D_UV_POWER "UV teljesítmény" #define D_VERSION "Verzió" #define D_VOLTAGE "Feszültség" -#define D_WEIGHT "Weight" -#define D_WARMLIGHT "Meleg" -#define D_WEB_SERVER "Web Szerver" +#define D_WEIGHT "Tömeg" +#define D_WARMLIGHT "Meleg fény" +#define D_WEB_SERVER "Webszerver" // sonoff.ino -#define D_WARNING_MINIMAL_VERSION "VIGYÁZZ Ez a verzió nem támogat tartós beállításokat" +#define D_WARNING_MINIMAL_VERSION "VIGYÁZZ! Ez a verzió nem támogat tartós beállításokat" #define D_LEVEL_10 "szint 1-0" #define D_LEVEL_01 "szint 0-1" -#define D_SERIAL_LOGGING_DISABLED "Serial logolás kikapcsolva" -#define D_SYSLOG_LOGGING_REENABLED "Syslog logolás újra-engedélyezve" +#define D_SERIAL_LOGGING_DISABLED "Soros naplózás kikapcsolva" +#define D_SYSLOG_LOGGING_REENABLED "Syslog logolás újraengedélyezve" #define D_SET_BAUDRATE_TO "Baudrate beállítása" -#define D_RECEIVED_TOPIC "Érkezett Téma" -#define D_DATA_SIZE "Adat Méret" +#define D_RECEIVED_TOPIC "Érkezett topic" +#define D_DATA_SIZE "Adatméret" #define D_ANALOG_INPUT "Analóg" // support.ino #define D_OSWATCH "osWatch" -#define D_BLOCKED_LOOP "Blocked Loop" +#define D_BLOCKED_LOOP "Tiltott hurok" #define D_WPS_FAILED_WITH_STATUS "WPSconfig SIKERTELEN státusz:" #define D_ACTIVE_FOR_3_MINUTES "aktválás 3 percre" #define D_FAILED_TO_START "sikertelen indítás" #define D_PATCH_ISSUE_2186 "Patch issue 2186" -#define D_CONNECTING_TO_AP "Csatlakozás az (AP): " -#define D_IN_MODE "be mód" +#define D_CONNECTING_TO_AP "AP-hoz csatlakozás:" +#define D_IN_MODE "mód:" #define D_CONNECT_FAILED_NO_IP_ADDRESS "Sikertelen csatlakozás, nincs kiosztott IP cím" #define D_CONNECT_FAILED_AP_NOT_REACHED "Sikertelen csatlakozás, AP nem elérhető" #define D_CONNECT_FAILED_WRONG_PASSWORD "Sikertelen csatlakozás, hibás AP jelszó" @@ -207,150 +208,161 @@ #define D_ATTEMPTING_CONNECTION "Csatlakozás..." #define D_CHECKING_CONNECTION "Kapcsolat ellenőrzése..." #define D_QUERY_DONE "Lekérés kész. MQTT szolgáltatás aktív" -#define D_MQTT_SERVICE_FOUND "élő MQTT szolgáltatás a" -#define D_FOUND_AT "a" -#define D_SYSLOG_HOST_NOT_FOUND "Syslog Host nem található" +#define D_MQTT_SERVICE_FOUND "élő MQTT szolgáltatás a(z)" +#define D_FOUND_AT "a(z)" +#define D_SYSLOG_HOST_NOT_FOUND "Syslog hoszt nem található" // settings.ino -#define D_SAVED_TO_FLASH_AT "Flash-re mentve a" -#define D_LOADED_FROM_FLASH_AT "Flash-ről betöltve a" +#define D_SAVED_TO_FLASH_AT "Flash-re mentve a(z)" +#define D_LOADED_FROM_FLASH_AT "Flash-ről betöltve a(z)" #define D_USE_DEFAULTS "Alapértelmezett beáll. használata" #define D_ERASED_SECTOR "Szektor törlése" // xdrv_02_webserver.ino -#define D_NOSCRIPT "To use Tasmota, please enable JavaScript" -#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "MINIMAL firmware - frissítsd!" -#define D_WEBSERVER_ACTIVE_ON "Web szerver aktív a" -#define D_WITH_IP_ADDRESS "IP címe:" -#define D_WEBSERVER_STOPPED "Webs zerver leállítva" -#define D_FILE_NOT_FOUND "File Nem Található" +#define D_NOSCRIPT "A Tasmota használatához engedélyezd a Javascriptet!" +#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "MINIMÁLIS firmware - frissítsd!" +#define D_WEBSERVER_ACTIVE_ON "Webszerver aktív:" +#define D_WITH_IP_ADDRESS "IP cím:" +#define D_WEBSERVER_STOPPED "Webszerver leállítva" +#define D_FILE_NOT_FOUND "Fájl nem található" #define D_REDIRECTED "Átírányítás captive portálra" -#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager AccessPoint(AP) és Station(ST) beállítása" +#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "WifiManager AccessPoint(AP) és Station(ST) beállítása" #define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager AccessPoint(AP) beállítása" #define D_TRYING_TO_CONNECT "Csatlakozás a hálózatra..." #define D_RESTART_IN "Újraindítás..." #define D_SECONDS "másodperc" -#define D_DEVICE_WILL_RESTART "Az eszköz hamarosan újraindul" -#define D_BUTTON_TOGGLE "Toggle" -#define D_CONFIGURATION "Konfigurációk" +#define D_DEVICE_WILL_RESTART "Az eszköz hamarosan újraindul..." +#define D_BUTTON_TOGGLE "Megfordítás" +#define D_CONFIGURATION "Beállítások" #define D_INFORMATION "Információ" -#define D_FIRMWARE_UPGRADE "Firmware Frissítés" +#define D_FIRMWARE_UPGRADE "Firmware frissítés" #define D_CONSOLE "Konzol" -#define D_CONFIRM_RESTART "Újraindítás megerősítése" +#define D_CONFIRM_RESTART "Biztosan újraindítsam a modult?" -#define D_CONFIGURE_MODULE "Eszköz konfiguráció" +#define D_CONFIGURE_MODULE "Eszközbeállítások" #define D_CONFIGURE_WIFI "WiFi konfiguráció" #define D_CONFIGURE_MQTT "MQTT konfiguráció" #define D_CONFIGURE_DOMOTICZ "Domoticz konfiguráció" -#define D_CONFIGURE_LOGGING "Logolás konfiguráció" -#define D_CONFIGURE_OTHER "Egyéb konfiguráció" -#define D_CONFIRM_RESET_CONFIGURATION "Konfig resetelés megerősítve?" -#define D_RESET_CONFIGURATION "Konfiguráció reset" -#define D_BACKUP_CONFIGURATION "Konfiguráció backup" -#define D_RESTORE_CONFIGURATION "Konfiguráció visszaállítás" +#define D_CONFIGURE_LOGGING "Naplózás beállításai" +#define D_CONFIGURE_OTHER "Egyéb beállítások" +#define D_CONFIRM_RESET_CONFIGURATION "Biztosan töröljem a beállításokat?" +#define D_RESET_CONFIGURATION "Beállítások törlése" +#define D_BACKUP_CONFIGURATION "Beállítások mentése" +#define D_RESTORE_CONFIGURATION "Beállítások visszatöltése" #define D_MAIN_MENU "Menü" #define D_MODULE_PARAMETERS "Modul paraméterek" -#define D_MODULE_TYPE "Modul típus" +#define D_MODULE_TYPE "Alkalmazott modul" +#define D_PULLUP_ENABLE "Nincs felhúzó ellenállás" #define D_GPIO "GPIO" -#define D_SERIAL_IN "Serial In" -#define D_SERIAL_OUT "Serial Out" +#define D_SERIAL_IN "Soros BE" +#define D_SERIAL_OUT "Soros KI" -#define D_WIFI_PARAMETERS "Wifi paraméterek" -#define D_SCAN_FOR_WIFI_NETWORKS "Wifi hálózat keresése" +#define D_WIFI_PARAMETERS "WiFi paraméterek" +#define D_SCAN_FOR_WIFI_NETWORKS "WiFi hálózat keresése" #define D_SCAN_DONE "Keresés kész" #define D_NO_NETWORKS_FOUND "Nincs elérhető hálózat" -#define D_REFRESH_TO_SCAN_AGAIN "Frissíts az újra kereséshez" -#define D_DUPLICATE_ACCESSPOINT "Duplicate AccessPoint" -#define D_SKIPPING_LOW_QUALITY "Kihagyás, alacsony jelminőség" +#define D_REFRESH_TO_SCAN_AGAIN "Frissíts az újrakereséshez" +#define D_DUPLICATE_ACCESSPOINT "Duplikált access point" +#define D_SKIPPING_LOW_QUALITY "Rossz, alacsony jelminőség" #define D_RSSI "RSSI" #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" #define D_AP1_SSID "AP1 SSID" -#define D_AP1_PASSWORD "AP1 Jelszó" +#define D_AP1_PASSWORD "AP1 megosztott kulcs" #define D_AP2_SSID "AP2 SSID" -#define D_AP2_PASSWORD "AP2 Jelszó" +#define D_AP2_PASSWORD "AP2 megosztott kulcs" #define D_MQTT_PARAMETERS "MQTT paraméterek" #define D_CLIENT "Kliens" -#define D_FULL_TOPIC "Teljes téma" +#define D_FULL_TOPIC "Teljes topic" -#define D_LOGGING_PARAMETERS "Logolás paraméterek" -#define D_SERIAL_LOG_LEVEL "Serial logolás szint" -#define D_WEB_LOG_LEVEL "Web logolás szint" +#define D_LOGGING_PARAMETERS "Naplózási paraméterek" +#define D_SERIAL_LOG_LEVEL "Soros naplózási szint" +#define D_WEB_LOG_LEVEL "Web naplózási szint" #define D_SYS_LOG_LEVEL "Syslog szint" -#define D_MORE_DEBUG "Részletes debug" -#define D_SYSLOG_HOST "Syslog host" +#define D_MORE_DEBUG "Részletes hibakeresés" +#define D_SYSLOG_HOST "Syslog hoszt" #define D_SYSLOG_PORT "Syslog port" -#define D_TELEMETRY_PERIOD "Telemetria (sec)" +#define D_TELEMETRY_PERIOD "Telemetria (mp.)" -#define D_OTHER_PARAMETERS "Egyéb paraméterek" -#define D_WEB_ADMIN_PASSWORD "Web Admin Jelszó" -#define D_MQTT_ENABLE "MQTT engedélyezés" +#define D_OTHER_PARAMETERS "Egyéb beállítások" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" +#define D_WEB_ADMIN_PASSWORD "Web admin jelszó" +#define D_MQTT_ENABLE "MQTT engedélyezése" #define D_FRIENDLY_NAME "Név" #define D_BELKIN_WEMO "Belkin WeMo" #define D_HUE_BRIDGE "Hue Bridge" #define D_SINGLE_DEVICE "single device" #define D_MULTI_DEVICE "multi device" -#define D_SAVE_CONFIGURATION "Konfiguráció mentése" -#define D_CONFIGURATION_SAVED "Konfiguráció elmentve" -#define D_CONFIGURATION_RESET "Konfiguráció visszaállítása" +#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_PROGRAM_VERSION "Program Verzió" -#define D_BUILD_DATE_AND_TIME "Build Dátum & Idő" -#define D_CORE_AND_SDK_VERSION "Core/SDK Verzió" -#define D_FLASH_WRITE_COUNT "Flashelések száma" -#define D_MAC_ADDRESS "MAC Cím" -#define D_MQTT_HOST "MQTT Host" -#define D_MQTT_PORT "MQTT Port" -#define D_MQTT_CLIENT "MQTT Cliens" -#define D_MQTT_USER "MQTT Felhasználó" -#define D_MQTT_TOPIC "MQTT Téma" -#define D_MQTT_GROUP_TOPIC "MQTT Csoport Téma" -#define D_MQTT_FULL_TOPIC "MQTT Teljes téma" -#define D_MDNS_DISCOVERY "mDNS Láthatóság" -#define D_MDNS_ADVERTISE "mDNS Hírdetés" -#define D_ESP_CHIP_ID "ESP Chip Id" -#define D_FLASH_CHIP_ID "Flash Chip Id" -#define D_FLASH_CHIP_SIZE "Flash Méret" -#define D_FREE_PROGRAM_SPACE "Szabad Program Hely" +#define D_SAVE_CONFIGURATION "Beállítások mentése" +#define D_CONFIGURATION_SAVED "Beállítások elmentve" +#define D_CONFIGURATION_RESET "Beállítások visszaállítása" -#define D_UPGRADE_BY_WEBSERVER "Frissítés web szerverrel" -#define D_OTA_URL "OTA Url" +#define D_PROGRAM_VERSION "Program verzió" +#define D_BUILD_DATE_AND_TIME "Build ideje" +#define D_CORE_AND_SDK_VERSION "Core/SDK verzió" +#define D_FLASH_WRITE_COUNT "Flash írások száma" +#define D_MAC_ADDRESS "MAC cím" +#define D_MQTT_HOST "MQTT hoszt" +#define D_MQTT_PORT "MQTT port" +#define D_MQTT_CLIENT "MQTT kliens" +#define D_MQTT_USER "MQTT felhasználó" +#define D_MQTT_TOPIC "MQTT topic" +#define D_MQTT_GROUP_TOPIC "MQTT csoport topic" +#define D_MQTT_FULL_TOPIC "MQTT teljes topic" +#define D_MDNS_DISCOVERY "mDNS láthatóság" +#define D_MDNS_ADVERTISE "mDNS hirdetés" +#define D_ESP_CHIP_ID "ESP chip ID" +#define D_FLASH_CHIP_ID "Flash chip ID" +#define D_FLASH_CHIP_SIZE "Flash mérete" +#define D_FREE_PROGRAM_SPACE "Szabad programhely" + +#define D_UPGRADE_BY_WEBSERVER "Frissítés távoli szerverről" +#define D_OTA_URL "OTA URL" #define D_START_UPGRADE "Frissítés" -#define D_UPGRADE_BY_FILE_UPLOAD "Frissítés file feltöltéssel" +#define D_UPGRADE_BY_FILE_UPLOAD "Frissítés helyi fájllal" #define D_UPLOAD_STARTED "Feltöltés elindítva" #define D_UPGRADE_STARTED "Frissítés elindítva" #define D_UPLOAD_DONE "Feltöltés kész" -#define D_UPLOAD_ERR_1 "Nincs file kijelölve" +#define D_UPLOAD_ERR_1 "Nincs fájl kijelölve" #define D_UPLOAD_ERR_2 "Nincs elég memória" -#define D_UPLOAD_ERR_3 "Magic byte is not 0xE9" -#define D_UPLOAD_ERR_4 "Program flash méret nagyobb a valós flash méretnél" -#define D_UPLOAD_ERR_5 "Feltöltés buffer hiba" -#define D_UPLOAD_ERR_6 "Feltöltés sikertelen. Endegélyezz 3-mas logolást" +#define D_UPLOAD_ERR_3 "A \"magic byte\" nem 0xE9" +#define D_UPLOAD_ERR_4 "A program flashméret nagyobb a valós flashméretnél" +#define D_UPLOAD_ERR_5 "Feltöltési buffer hiba" +#define D_UPLOAD_ERR_6 "Feltöltés sikertelen. Endegélyezd a 3. szintű naplózást" #define D_UPLOAD_ERR_7 "Feltöltés megszakítva" -#define D_UPLOAD_ERR_8 "Érvénytelen file" -#define D_UPLOAD_ERR_9 "File túl nagy" -#define D_UPLOAD_ERR_10 "Failed to init RF chip" -#define D_UPLOAD_ERR_11 "Failed to erase RF chip" -#define D_UPLOAD_ERR_12 "Failed to write to RF chip" -#define D_UPLOAD_ERR_13 "Failed to decode RF firmware" -#define D_UPLOAD_ERROR_CODE "Feltöltés hiba kód" +#define D_UPLOAD_ERR_8 "Érvénytelen fájl" +#define D_UPLOAD_ERR_9 "A fájl túl nagy" +#define D_UPLOAD_ERR_10 "Az RF chip inicializálása sikertelen" +#define D_UPLOAD_ERR_11 "Az RF chip törlése sikertelen" +#define D_UPLOAD_ERR_12 "Az RF chip írása sikertelen" +#define D_UPLOAD_ERR_13 "Az RF firmware dekódolása sikertelen" +#define D_UPLOAD_ERROR_CODE "Feltöltési hibakód" -#define D_ENTER_COMMAND "Parancsolj" -#define D_ENABLE_WEBLOG_FOR_RESPONSE "Engedélyezz 2-es weblogolást több információért" -#define D_NEED_USER_AND_PASSWORD "Kell felhasználó=&jelszó=" +#define D_ENTER_COMMAND "Kérem a parancsot..." +#define D_ENABLE_WEBLOG_FOR_RESPONSE "Engedélyezz 2-es szintű webnaplózást több információért" +#define D_NEED_USER_AND_PASSWORD "Szükséges a user=&password= paraméter" // xdrv_01_mqtt.ino #define D_FINGERPRINT "TLS fingerprint hitelesítése..." -#define D_TLS_CONNECT_FAILED_TO "TLS Csatlakozás sikertelen a" +#define D_TLS_CONNECT_FAILED_TO "TLS csatlakozás sikertelen a(z)" #define D_RETRY_IN "Újrapróbálás" -#define D_VERIFIED "Hitelesítve Fingerprint" -#define D_INSECURE "Nem biztonságos kapcsolat érvénytelen Fingerprint miatt" -#define D_CONNECT_FAILED_TO "Sikertelen csatlakozás a" +#define D_VERIFIED "Fingerprint hitelesítve" +#define D_INSECURE "Nem biztonságos kapcsolat érvénytelen fingerprint miatt" +#define D_CONNECT_FAILED_TO "Sikertelen csatlakozás a(z)" // xplg_wemohue.ino #define D_MULTICAST_DISABLED "Multicast kikapcsolva" @@ -369,8 +381,8 @@ #define D_HUE_BRIDGE_SETUP "Hue beállítás" #define D_HUE_API_NOT_IMPLEMENTED "Hue API nincs implementálva" #define D_HUE_API "Hue API" -#define D_HUE_POST_ARGS "Hue POST args" -#define D_3_RESPONSE_PACKETS_SENT "3 válaszcsomagok elküldve" +#define D_HUE_POST_ARGS "Hue POST argumentumok" +#define D_3_RESPONSE_PACKETS_SENT "3 válaszcsomag elküldve" // xdrv_07_domoticz.ino #define D_DOMOTICZ_PARAMETERS "Domoticz paraméterek" @@ -378,71 +390,71 @@ #define D_DOMOTICZ_KEY_IDX "Key idx" #define D_DOMOTICZ_SWITCH_IDX "Kapcsoló idx" #define D_DOMOTICZ_SENSOR_IDX "Szenzor idx" - #define D_DOMOTICZ_TEMP "Temp" - #define D_DOMOTICZ_TEMP_HUM "Hőm,Párat" - #define D_DOMOTICZ_TEMP_HUM_BARO "Hőm,Párat,Légny" - #define D_DOMOTICZ_POWER_ENERGY "Teljesítmény,Energia" + #define D_DOMOTICZ_TEMP "Hőmérséklet" + #define D_DOMOTICZ_TEMP_HUM "Hőmérséklet, páratartalom" + #define D_DOMOTICZ_TEMP_HUM_BARO "Hőmérséklet, páratartalom, légnyomás" + #define D_DOMOTICZ_POWER_ENERGY "Teljesítmény, energia" #define D_DOMOTICZ_ILLUMINANCE "Fényerő" #define D_DOMOTICZ_COUNT "Szám/PM1" #define D_DOMOTICZ_VOLTAGE "Feszültség/PM2.5" #define D_DOMOTICZ_CURRENT "Áram/PM10" #define D_DOMOTICZ_AIRQUALITY "Légminőség" -#define D_DOMOTICZ_UPDATE_TIMER "Update időzítő" +#define D_DOMOTICZ_UPDATE_TIMER "Frissítési időzítő" // xdrv_09_timers.ino -#define D_CONFIGURE_TIMER "Configure Timer" -#define D_TIMER_PARAMETERS "Timer parameters" -#define D_TIMER_ENABLE "Enable Timers" -#define D_TIMER_ARM "Arm" -#define D_TIMER_TIME "Time" -#define D_TIMER_DAYS "Days" -#define D_TIMER_REPEAT "Repeat" -#define D_TIMER_OUTPUT "Output" -#define D_TIMER_ACTION "Action" +#define D_CONFIGURE_TIMER "Időzítő beállításai" +#define D_TIMER_PARAMETERS "Időzítő paraméterei" +#define D_TIMER_ENABLE "Időzítők engedélyezve" +#define D_TIMER_ARM "Be" +#define D_TIMER_TIME "Idő" +#define D_TIMER_DAYS "Napok" +#define D_TIMER_REPEAT "Ismétlés" +#define D_TIMER_OUTPUT "Kimenet" +#define D_TIMER_ACTION "Művelet" // xdrv_10_knx.ino -#define D_CONFIGURE_KNX "Configure KNX" -#define D_KNX_PARAMETERS "KNX Parameters" -#define D_KNX_GENERAL_CONFIG "General" -#define D_KNX_PHYSICAL_ADDRESS "Physical Address" -#define D_KNX_PHYSICAL_ADDRESS_NOTE "( Must be unique on the KNX network )" -#define D_KNX_ENABLE "Enable KNX" -#define D_KNX_GROUP_ADDRESS_TO_WRITE "Data to Send to Group Addresses" -#define D_ADD "Add" -#define D_DELETE "Delete" -#define D_REPLY "Reply" -#define D_KNX_GROUP_ADDRESS_TO_READ "Group Addresses to Receive Data from" +#define D_CONFIGURE_KNX "KNX beállításai" +#define D_KNX_PARAMETERS "KNX paraméterei" +#define D_KNX_GENERAL_CONFIG "Általános" +#define D_KNX_PHYSICAL_ADDRESS "Fizikai cím" +#define D_KNX_PHYSICAL_ADDRESS_NOTE "(egyedinek kell lennie a KNX hálózaton)" +#define D_KNX_ENABLE "KNX engedélyezése" +#define D_KNX_GROUP_ADDRESS_TO_WRITE "Íráshoz használt csoportcímek" +#define D_ADD "Hozzáadás" +#define D_DELETE "Törlés" +#define D_REPLY "Válasz" +#define D_KNX_GROUP_ADDRESS_TO_READ "Fogadáshoz használt csoportcímek" #define D_LOG_KNX "KNX: " -#define D_RECEIVED_FROM "Received from" -#define D_KNX_COMMAND_WRITE "Write" -#define D_KNX_COMMAND_READ "Read" -#define D_KNX_COMMAND_OTHER "Other" -#define D_SENT_TO "sent to" -#define D_KNX_WARNING "The group address ( 0 / 0 / 0 ) is reserved and can not be used." +#define D_RECEIVED_FROM "Fogadva tőle:" +#define D_KNX_COMMAND_WRITE "Írás" +#define D_KNX_COMMAND_READ "Olvasás" +#define D_KNX_COMMAND_OTHER "Egyáb" +#define D_SENT_TO "küldve neki:" +#define D_KNX_WARNING "A csoportcím ( 0 / 0 / 0 ) fenntartott és nem használható." #define D_KNX_ENHANCEMENT "Communication Enhancement" #define D_KNX_TX_SLOT "KNX TX" #define D_KNX_RX_SLOT "KNX RX" // xdrv_03_energy.ino -#define D_ENERGY_TODAY "Mai Energia" -#define D_ENERGY_YESTERDAY "Tegnapi Energia" -#define D_ENERGY_TOTAL "Összes Energia" +#define D_ENERGY_TODAY "Mai energia" +#define D_ENERGY_YESTERDAY "Tegnapi energia" +#define D_ENERGY_TOTAL "Összes energia" // xsns_05_ds18b20.ino -#define D_SENSOR_BUSY "Szenzor elfoglalt" +#define D_SENSOR_BUSY "Szenzor foglalt" #define D_SENSOR_CRC_ERROR "Szenzor CRC hiba" #define D_SENSORS_FOUND "Szenzorok megtalálva" // xsns_06_dht.ino -#define D_TIMEOUT_WAITING_FOR "Timeout waiting for" -#define D_START_SIGNAL_LOW "start signal low" -#define D_START_SIGNAL_HIGH "start signal high" -#define D_PULSE "pulse" -#define D_CHECKSUM_FAILURE "Checksum failure" +#define D_TIMEOUT_WAITING_FOR "Időtúllépés, várakozás" +#define D_START_SIGNAL_LOW "startjel alacsony" +#define D_START_SIGNAL_HIGH "startjel magas" +#define D_PULSE "impulzus" +#define D_CHECKSUM_FAILURE "Checksum hiba" // xsns_07_sht1x.ino -#define D_SENSOR_DID_NOT_ACK_COMMAND "Szenzor nem ismerte el(ACK) a parancsot" -#define D_SHT1X_FOUND "SHT1X found" +#define D_SENSOR_DID_NOT_ACK_COMMAND "A szenzor nem nyugtázta a parancsot" +#define D_SHT1X_FOUND "SHT1X megtalálva" // xsns_18_pms5003.ino #define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter @@ -450,102 +462,126 @@ #define D_PARTICALS_BEYOND "Részecskék" // xsns_32_mpu6050.ino -#define D_AX_AXIS "Accel. X-Axis" -#define D_AY_AXIS "Accel. Y-Axis" -#define D_AZ_AXIS "Accel. Z-Axis" -#define D_GX_AXIS "Gyro X-Axis" -#define D_GY_AXIS "Gyro Y-Axis" -#define D_GZ_AXIS "Gyro Z-Axis" +#define D_AX_AXIS "Gyorsulásm. X-tengely" +#define D_AY_AXIS "Gyorsulásm. Y-tengely" +#define D_AZ_AXIS "Gyorsulásm. Z-tengely" +#define D_GX_AXIS "Giroszkóp X-tengely" +#define D_GY_AXIS "Giroszkóp Y-tengely" +#define D_GZ_AXIS "Giroszkóp Z-tengely" // xsns_34_hx711.ino -#define D_HX_CAL_REMOVE "Remove weigth" -#define D_HX_CAL_REFERENCE "Load reference weigth" -#define D_HX_CAL_DONE "Calibrated" -#define D_HX_CAL_FAIL "Calibration failed" -#define D_RESET_HX711 "Reset Scale" -#define D_CONFIGURE_HX711 "Configure Scale" -#define D_HX711_PARAMETERS "Scale parameters" -#define D_ITEM_WEIGHT "Item weight" -#define D_REFERENCE_WEIGHT "Reference weigth" -#define D_CALIBRATE "Calibrate" -#define D_CALIBRATION "Calibration" +#define D_HX_CAL_REMOVE "Távolítsa el a súlyt" +#define D_HX_CAL_REFERENCE "Helyezze fel a referenciasúlyt" +#define D_HX_CAL_DONE "Kalibrálva" +#define D_HX_CAL_FAIL "Kalibrálási hiba" +#define D_RESET_HX711 "Skála újrabeállítása" +#define D_CONFIGURE_HX711 "Skála konfigurálása" +#define D_HX711_PARAMETERS "Skálaparaméterek" +#define D_ITEM_WEIGHT "Tárgy tömege" +#define D_REFERENCE_WEIGHT "Referenciatömeg" +#define D_CALIBRATE "Kalibrálás" +#define D_CALIBRATION "Kalibrálás" //xsns_35_tx20.ino -#define D_TX20_WIND_DIRECTION "Wind Direction" -#define D_TX20_WIND_SPEED "Wind Speed" -#define D_TX20_WIND_SPEED_AVG "Wind Speed Avg" -#define D_TX20_WIND_SPEED_MAX "Wind Speed Max" -#define D_TX20_NORTH "N" -#define D_TX20_EAST "E" -#define D_TX20_SOUTH "S" -#define D_TX20_WEST "W" +#define D_TX20_WIND_DIRECTION "Szélirány" +#define D_TX20_WIND_SPEED "Szélsebesség" +#define D_TX20_WIND_SPEED_AVG "Átlag szélsebesség" +#define D_TX20_WIND_SPEED_MAX "Max. szélsebesség" +#define D_TX20_NORTH "É" +#define D_TX20_EAST "K" +#define D_TX20_SOUTH "D" +#define D_TX20_WEST "NY" -// sonoff_template.h -#define D_SENSOR_NONE "Nincs" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRadó" -#define D_SENSOR_SWITCH "Kapcsoló" // Suffix "1" -#define D_SENSOR_BUTTON "Gomb" // Suffix "1" -#define D_SENSOR_RELAY "Relé" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Számláló" // Suffix "1" -#define D_SENSOR_IRRECV "IRvevő" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "Háttérvil" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 lejátszó" +#define D_SENSOR_IRSEND "IR adó" +#define D_SENSOR_SWITCH "Kapcsoló" // Suffix "1" +#define D_SENSOR_BUTTON "Gomb" // Suffix "1" +#define D_SENSOR_RELAY "Relé" // Suffix "1i" +#define D_SENSOR_LED "LED" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Számláló" // Suffix "1" +#define D_SENSOR_IRRECV "IR vevő" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "Háttérfény" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" -#define D_UNIT_HOUR "ó" +#define D_UNIT_HOUR "h" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h" @@ -559,12 +595,12 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" -#define D_UNIT_MINUTE "p" +#define D_UNIT_MINUTE "min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" -#define D_UNIT_SECOND "m" +#define D_UNIT_SECOND "s" #define D_UNIT_SECTORS "szektorok" #define D_UNIT_VA "VA" #define D_UNIT_VAR "VAr" @@ -599,13 +635,13 @@ #define D_LOG_WIFI "WIF: " // Wifi //SDM220 -#define D_PHASE_ANGLE "Phase Angle" -#define D_IMPORT_ACTIVE "Import Active" -#define D_EXPORT_ACTIVE "Export Active" -#define D_IMPORT_REACTIVE "Import Reactive" -#define D_EXPORT_REACTIVE "Export Reactive" -#define D_TOTAL_REACTIVE "Total Reactive" +#define D_PHASE_ANGLE "Fázisszög" +#define D_IMPORT_ACTIVE "Bejövő aktív" +#define D_EXPORT_ACTIVE "Kimenő aktív" +#define D_IMPORT_REACTIVE "Bejövő reaktív" +#define D_EXPORT_REACTIVE "Kimenő reaktív" +#define D_TOTAL_REACTIVE "Összes reaktív" #define D_UNIT_KWARH "kVArh" -#define D_UNIT_ANGLE "Deg" +#define D_UNIT_ANGLE "fok" #endif // _LANGUAGE_HU_HU_H_ diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index a6d0d693c..4d735426f 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -1,7 +1,7 @@ /* it-IT.h - localization for Italian - Italy for Sonoff-Tasmota - Copyright (C) 2018 Gennaro Tortone - some mods by Antonio Fragola + Copyright (C) 2019 Gennaro Tortone - some mods by Antonio Fragola This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Stop" #define D_SUBNET_MASK "Maschera sottorete" #define D_SUBSCRIBE_TO "Sottoscrivi a" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Riuscito" #define D_SUNRISE "Alba" #define D_SUNSET "Tramonto" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Parametri del modulo" #define D_MODULE_TYPE "Tipo modulo" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial In" #define D_SERIAL_OUT "Serial Out" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Periodo Telemetria" #define D_OTHER_PARAMETERS "Altri parametri" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Password Amministratore Web" #define D_MQTT_ENABLE "Abilita MQTT" #define D_FRIENDLY_NAME "Nome confidenziale" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "dispositivo singolo" #define D_MULTI_DEVICE "dispositivo multiplo" +#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_SAVE_CONFIGURATION "Salva configurazione" #define D_CONFIGURATION_SAVED "Configurazione salvata" #define D_CONFIGURATION_RESET "Configurazione azzerata" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "Nessuno" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Switch" // Suffix "1" -#define D_SENSOR_BUTTON "Button" // Suffix "1" -#define D_SENSOR_RELAY "Relay" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Counter" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Switch" // Suffix "1" +#define D_SENSOR_BUTTON "Button" // Suffix "1" +#define D_SENSOR_RELAY "Relay" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Counter" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/ko-KO.h b/sonoff/language/ko-KO.h new file mode 100644 index 000000000..fb85e5ca2 --- /dev/null +++ b/sonoff/language/ko-KO.h @@ -0,0 +1,647 @@ +/* + ko-KO.h - localization for Korean - Korean for Sonoff-Tasmota + + Copyright (C) 2019 Theo Arends (translated by NyaamZ) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _LANGUAGE_KO_KO_H_ +#define _LANGUAGE_KO_KO_H_ + +/*************************** ATTENTION *******************************\ + * + * Due to memory constraints only UTF-8 is supported. + * To save code space keep text as short as possible. + * Time and Date provided by SDK can not be localized (yet). + * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. + * Use online command Prefix to translate cmnd, stat and tele. + * + * Updated until v6.2.1.11 +\*********************************************************************/ + +//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) +// https://www.science.co.il/language/Locale-codes.php +#define LANGUAGE_LCID 1042 +// HTML (ISO 639-1) Language Code +#define D_HTML_LANGUAGE "ko" + +// "2017-03-07T11:08:02" - ISO8601:2004 +#define D_YEAR_MONTH_SEPARATOR "-" +#define D_MONTH_DAY_SEPARATOR "-" +#define D_DATE_TIME_SEPARATOR "T" +#define D_HOUR_MINUTE_SEPARATOR ":" +#define D_MINUTE_SECOND_SEPARATOR ":" + +#define D_DAY3LIST "일 월 화 수 목 금 토 " +#define D_MONTH3LIST "1월 2월 3월 4월 5월 6월 7월 8월 9월 10월11월12월" + +// Non JSON decimal separator +#define D_DECIMAL_SEPARATOR "." + +// Common +#define D_ADMIN "Admin" +#define D_AIR_QUALITY "공기질" +#define D_AP "AP" // Access Point +#define D_AS "as" +#define D_AUTO "자동" +#define D_BLINK "깜박임" +#define D_BLINKOFF "깜박임 끄기" +#define D_BOOT_COUNT "가동횟수" +#define D_BRIGHTLIGHT "밝기" +#define D_BSSID "BSSId" +#define D_BUTTON "버튼" +#define D_BY "by" // Written by me +#define D_BYTES "Bytes" +#define D_CELSIUS "섭씨" +#define D_CHANNEL "채널" +#define D_CO2 "이산화탄소" +#define D_CODE "코드" // Button code +#define D_COLDLIGHT "차갑게" +#define D_COMMAND "명령" +#define D_CONNECTED "연결됨" +#define D_COUNT "횟수" +#define D_COUNTER "Counter" +#define D_CURRENT "전류" // As in Voltage and Current +#define D_DATA "데이터" +#define D_DARKLIGHT "어둡게" +#define D_DEBUG "디버그" +#define D_DISABLED "사용 불가" +#define D_DISTANCE "거리" +#define D_DNS_SERVER "DNS 서버" +#define D_DONE "완료" +#define D_DST_TIME "DST" +#define D_ECO2 "eCO2" +#define D_EMULATION "에뮬레이션" +#define D_ENABLED "사용 가능" +#define D_ERASE "삭제" +#define D_ERROR "에러" +#define D_FAHRENHEIT "화씨" +#define D_FAILED "실패" +#define D_FALLBACK "Fallback" +#define D_FALLBACK_TOPIC "Fallback Topic" +#define D_FALSE "거짓" +#define D_FILE "파일" +#define D_FREE_MEMORY "남은 메모리" +#define D_FREQUENCY "빈도" +#define D_GAS "가스" +#define D_GATEWAY "게이트웨이" +#define D_GROUP "그룹" +#define D_HOST "호스트" +#define D_HOSTNAME "호스트이름" +#define D_HUMIDITY "습도" +#define D_ILLUMINANCE "조도" +#define D_IMMEDIATE "immediate" // Button immediate +#define D_INDEX "인덱스" +#define D_INFO "정보" +#define D_INFRARED "적외선" +#define D_INITIALIZED "초기화 완료" +#define D_IP_ADDRESS "IP 주소" +#define D_LIGHT "밝게" +#define D_LWT "LWT" +#define D_MODULE "모듈" +#define D_MQTT "MQTT" +#define D_MULTI_PRESS "multi-press" +#define D_NOISE "소음" +#define D_NONE "없음" +#define D_OFF "꺼짐" +#define D_OFFLINE "오프라인" +#define D_OK "Ok" +#define D_ON "켜짐" +#define D_ONLINE "온라인" +#define D_PASSWORD "비밀번호" +#define D_PORT "포트" +#define D_POWER_FACTOR "Power Factor" +#define D_POWERUSAGE "전원" +#define D_POWERUSAGE_ACTIVE "Active Power" +#define D_POWERUSAGE_APPARENT "Apparent Power" +#define D_POWERUSAGE_REACTIVE "Reactive Power" +#define D_PRESSURE "기압" +#define D_PRESSUREATSEALEVEL "해수면기압" +#define D_PROGRAM_FLASH_SIZE "플래시 용량" +#define D_PROGRAM_SIZE "프로그램 용량" +#define D_PROJECT "프로젝트" +#define D_RAIN "비" +#define D_RECEIVED "받음" +#define D_RESTART "재시작" +#define D_RESTARTING "재시작 중" +#define D_RESTART_REASON "재시작 이유" +#define D_RESTORE "복구" +#define D_RETAINED "보류" +#define D_RULE "규칙" +#define D_SAVE "저장" +#define D_SENSOR "센서" +#define D_SSID "SSId" +#define D_START "시작" +#define D_STD_TIME "STD" +#define D_STOP "정지" +#define D_SUBNET_MASK "서브넷 마스크" +#define D_SUBSCRIBE_TO "구독" +#define D_UNSUBSCRIBE_FROM "구독 해제" +#define D_SUCCESSFUL "성공" +#define D_SUNRISE "일출" +#define D_SUNSET "일몰" +#define D_TEMPERATURE "온도" +#define D_TO "to" +#define D_TOGGLE "전환" +#define D_TOPIC "Topic" +#define D_TRANSMIT "전송" +#define D_TRUE "참" +#define D_TVOC "TVOC" +#define D_UPGRADE "업그레이드" +#define D_UPLOAD "업로드" +#define D_UPTIME "가동시간" +#define D_USER "User" +#define D_UTC_TIME "UTC" +#define D_UV_INDEX "UV 색인" +#define D_UV_INDEX_1 "낮음" +#define D_UV_INDEX_2 "보통" +#define D_UV_INDEX_3 "높음" +#define D_UV_INDEX_4 "위험" +#define D_UV_INDEX_5 "BurnL1/2" +#define D_UV_INDEX_6 "BurnL3" +#define D_UV_INDEX_7 "OoR" // Out of Range +#define D_UV_LEVEL "UV 레벨" +#define D_UV_POWER "UV 파워" +#define D_VERSION "버전" +#define D_VOLTAGE "전압" +#define D_WEIGHT "무게" +#define D_WARMLIGHT "따뜻하게" +#define D_WEB_SERVER "웹 서버" + +// sonoff.ino +#define D_WARNING_MINIMAL_VERSION "경고: 이 버전은 영구 설정을 지원하지 않습니다" +#define D_LEVEL_10 "level 1-0" +#define D_LEVEL_01 "level 0-1" +#define D_SERIAL_LOGGING_DISABLED "Serial log 사용 안함" +#define D_SYSLOG_LOGGING_REENABLED "Syslog log 다시 사용" + +#define D_SET_BAUDRATE_TO "Set Baudrate to" +#define D_RECEIVED_TOPIC "Received Topic" +#define D_DATA_SIZE "데이터 용량" +#define D_ANALOG_INPUT "아날로그" + +// support.ino +#define D_OSWATCH "osWatch" +#define D_BLOCKED_LOOP "Blocked Loop" +#define D_WPS_FAILED_WITH_STATUS "WPS설정 실패" +#define D_ACTIVE_FOR_3_MINUTES "3분동안 활성화" +#define D_FAILED_TO_START "시작 실패" +#define D_PATCH_ISSUE_2186 "Patch issue 2186" +#define D_CONNECTING_TO_AP "AP에 연결 중" +#define D_IN_MODE "in mode" +#define D_CONNECT_FAILED_NO_IP_ADDRESS "IP 주소가 수신되지 않아 연결이 실패했습니다" +#define D_CONNECT_FAILED_AP_NOT_REACHED "연결이 닿지 않아 AP에 연결할 수 없습니다" +#define D_CONNECT_FAILED_WRONG_PASSWORD "비밀번호가 틀려 AP에 연결할 수 없습니다" +#define D_CONNECT_FAILED_AP_TIMEOUT "시간초과로 AP에 연결할 수 없습니다" +#define D_ATTEMPTING_CONNECTION "연결 시도 중..." +#define D_CHECKING_CONNECTION "연결 체크 중..." +#define D_QUERY_DONE "쿼리 완료. MQTT 서비스 발견" +#define D_MQTT_SERVICE_FOUND "MQTT 서비스 발견" +#define D_FOUND_AT "다음에서 발견" +#define D_SYSLOG_HOST_NOT_FOUND "Syslog 호스트가 발견되지 않았습니다" + +// settings.ino +#define D_SAVED_TO_FLASH_AT "플래시에 저장" +#define D_LOADED_FROM_FLASH_AT "플래시에서 로드" +#define D_USE_DEFAULTS "디폴트 사용" +#define D_ERASED_SECTOR "삭제된 섹터" + +// xdrv_02_webserver.ino +#define D_NOSCRIPT "Tasmota를 사용하려면 JavaScript를 활성화 하십시오." +#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "MINIMAL firmware - 업그레이드가 필요합니다" +#define D_WEBSERVER_ACTIVE_ON "Web 서버 작동 중" +#define D_WITH_IP_ADDRESS "IP 주소" +#define D_WEBSERVER_STOPPED "Web 서버 멈춤" +#define D_FILE_NOT_FOUND "파일을 찾을 수 없습니다" +#define D_REDIRECTED "인증 페이지로 리디렉션" +#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "와이파이 매니저가 AccessPoint와 keep Station을 설정" +#define D_WIFIMANAGER_SET_ACCESSPOINT "와이파이 매니저가 AccessPoint를 설정" +#define D_TRYING_TO_CONNECT "장치를 네트워크에 연결하려고 시도 중" + +#define D_RESTART_IN "재시작" +#define D_SECONDS "초" +#define D_DEVICE_WILL_RESTART "이 장치는 몇 초 후 재시작됩니다" +#define D_BUTTON_TOGGLE "켜기/끄기" +#define D_CONFIGURATION "설정" +#define D_INFORMATION "정보" +#define D_FIRMWARE_UPGRADE "펌웨어 업그레이드" +#define D_CONSOLE "콘솔" +#define D_CONFIRM_RESTART "재시작" + +#define D_CONFIGURE_MODULE "모듈 설정" +#define D_CONFIGURE_WIFI "WiFi 설정" +#define D_CONFIGURE_MQTT "MQTT 설정" +#define D_CONFIGURE_DOMOTICZ "Domoticz 설정" +#define D_CONFIGURE_LOGGING "로그 설정" +#define D_CONFIGURE_OTHER "기타 설정" +#define D_CONFIRM_RESET_CONFIGURATION "설정 초기화 확인" +#define D_RESET_CONFIGURATION "설정 초기화" +#define D_BACKUP_CONFIGURATION "백업 설정" +#define D_RESTORE_CONFIGURATION "복원 설정" +#define D_MAIN_MENU "메인 메뉴" + +#define D_MODULE_PARAMETERS "모듈 상세" +#define D_MODULE_TYPE "모듈 타입" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" +#define D_GPIO "GPIO" +#define D_SERIAL_IN "Serial In" +#define D_SERIAL_OUT "Serial Out" + +#define D_WIFI_PARAMETERS "Wifi 상세" +#define D_SCAN_FOR_WIFI_NETWORKS "Wifi 네트워크를 검색 중" +#define D_SCAN_DONE "검색 완료" +#define D_NO_NETWORKS_FOUND "발견된 네트워크가 없습니다" +#define D_REFRESH_TO_SCAN_AGAIN "검색 재시도" +#define D_DUPLICATE_ACCESSPOINT "중복된 AccessPoint" +#define D_SKIPPING_LOW_QUALITY "약한 네트워크 신호 무시" +#define D_RSSI "RSSI" +#define D_WEP "WEP" +#define D_WPA_PSK "WPA PSK" +#define D_WPA2_PSK "WPA2 PSK" +#define D_AP1_SSID "AP1 SSId" +#define D_AP1_PASSWORD "AP1 비밀번호" +#define D_AP2_SSID "AP2 SSId" +#define D_AP2_PASSWORD "AP2 비밀번호" + +#define D_MQTT_PARAMETERS "MQTT 상세" +#define D_CLIENT "클라이언트" +#define D_FULL_TOPIC "Full Topic" + +#define D_LOGGING_PARAMETERS "로그 상세" +#define D_SERIAL_LOG_LEVEL "시리얼 로그 레벨" +#define D_WEB_LOG_LEVEL "Web 로그 레벨" +#define D_SYS_LOG_LEVEL "Syslog 로그 레벨" +#define D_MORE_DEBUG "More debug" +#define D_SYSLOG_HOST "Syslog 호스트" +#define D_SYSLOG_PORT "Syslog 포트" +#define D_TELEMETRY_PERIOD "보고 주기" + +#define D_OTHER_PARAMETERS "기타 상세" +#define D_TEMPLATE "템플릿" +#define D_ACTIVATE "활성" +#define D_WEB_ADMIN_PASSWORD "Web Admin 비밀번호" +#define D_MQTT_ENABLE "MQTT 사용" +#define D_FRIENDLY_NAME "별칭" +#define D_BELKIN_WEMO "Belkin WeMo" +#define D_HUE_BRIDGE "Hue Bridge" +#define D_SINGLE_DEVICE "single device" +#define D_MULTI_DEVICE "multi device" + +#define D_CONFIGURE_TEMPLATE "템플릿 설정" +#define D_TEMPLATE_PARAMETERS "템플릿 상세" +#define D_TEMPLATE_NAME "이름" +#define D_BASE_TYPE "Based on" +#define D_TEMPLATE_FLAGS "옵션" +#define D_ALLOW_ADC0 "ADC0 입력" +#define D_ALLOW_PULLUP "User pull-up selection" + +#define D_SAVE_CONFIGURATION "설정 저장" +#define D_CONFIGURATION_SAVED "설정 저장 완료" +#define D_CONFIGURATION_RESET "설정 초기화" + +#define D_PROGRAM_VERSION "프로그램 버전" +#define D_BUILD_DATE_AND_TIME "빌드 날짜" +#define D_CORE_AND_SDK_VERSION "Core/SDK 버전" +#define D_FLASH_WRITE_COUNT "플래시 쓰기 횟수" +#define D_MAC_ADDRESS "MAC 주소" +#define D_MQTT_HOST "MQTT 호스트" +#define D_MQTT_PORT "MQTT 포트" +#define D_MQTT_CLIENT "MQTT 클라이언트" +#define D_MQTT_USER "MQTT 아이디" +#define D_MQTT_TOPIC "MQTT Topic" +#define D_MQTT_GROUP_TOPIC "MQTT Group Topic" +#define D_MQTT_FULL_TOPIC "MQTT Full Topic" +#define D_MDNS_DISCOVERY "mDNS Discovery" +#define D_MDNS_ADVERTISE "mDNS Advertise" +#define D_ESP_CHIP_ID "ESP Chip Id" +#define D_FLASH_CHIP_ID "Flash Chip Id" +#define D_FLASH_CHIP_SIZE "Flash 용량" +#define D_FREE_PROGRAM_SPACE "여유 프로그램 공간" + +#define D_UPGRADE_BY_WEBSERVER "웹 서버에서 업그레이드" +#define D_OTA_URL "OTA Url" +#define D_START_UPGRADE "업그레이드 시작" +#define D_UPGRADE_BY_FILE_UPLOAD "업로드 된 파일로 업그레이드" +#define D_UPLOAD_STARTED "업로드 시작됨" +#define D_UPGRADE_STARTED "업그레이드 시작됨" +#define D_UPLOAD_DONE "업그레이드 완료" +#define D_UPLOAD_ERR_1 "파일이 선택되지 않았습니다" +#define D_UPLOAD_ERR_2 "용량이 충분하지 않습니다" +#define D_UPLOAD_ERR_3 "Magic 바이트가 0xE9가 아닙니다" +#define D_UPLOAD_ERR_4 "플래시 프로그램이 실제 플래시 용량보다 큽니다" +#define D_UPLOAD_ERR_5 "업로드 버퍼가 일치하지 않습니다" +#define D_UPLOAD_ERR_6 "업로드 실패. 로그 3 사용" +#define D_UPLOAD_ERR_7 "업로드 중단" +#define D_UPLOAD_ERR_8 "파일이 유효하지 않습니다" +#define D_UPLOAD_ERR_9 "용량이 초과되었습니다" +#define D_UPLOAD_ERR_10 "RF chip 초기화 실패" +#define D_UPLOAD_ERR_11 "RF chip 삭제 실패" +#define D_UPLOAD_ERR_12 "RF chip 쓰기 실패" +#define D_UPLOAD_ERR_13 "RF 펌웨어 decode 실패" +#define D_UPLOAD_ERROR_CODE "업로드 에러 코드" + +#define D_ENTER_COMMAND "명령 입력" +#define D_ENABLE_WEBLOG_FOR_RESPONSE "응답이 있다면 Weblog 2를 사용" +#define D_NEED_USER_AND_PASSWORD "user=<아이디>&password=<비밀번호> 필요" + +// xdrv_01_mqtt.ino +#define D_FINGERPRINT "TLS 지문 확인..." +#define D_TLS_CONNECT_FAILED_TO "TLS 연결 실패" +#define D_RETRY_IN "재시도 중" +#define D_VERIFIED "지문 확인 완료" +#define D_INSECURE "유효하지 않은 지문으로 연결이 되지 않았습니다" +#define D_CONNECT_FAILED_TO "연결 실패" + +// xplg_wemohue.ino +#define D_MULTICAST_DISABLED "Multicast 사용 불가" +#define D_MULTICAST_REJOINED "Multicast (다시)가입됨" +#define D_MULTICAST_JOIN_FAILED "Multicast 가입 실패" +#define D_FAILED_TO_SEND_RESPONSE "요청 전송 실패" + +#define D_WEMO "WeMo" +#define D_WEMO_BASIC_EVENT "WeMo 기본 이벤트" +#define D_WEMO_EVENT_SERVICE "WeMo 이벤트 서비스" +#define D_WEMO_META_SERVICE "WeMo meta 서비스" +#define D_WEMO_SETUP "WeMo 설정" +#define D_RESPONSE_SENT "요청 전송됨" + +#define D_HUE "Hue" +#define D_HUE_BRIDGE_SETUP "Hue 설정" +#define D_HUE_API_NOT_IMPLEMENTED "Hue API가 포함되지 않음" +#define D_HUE_API "Hue API" +#define D_HUE_POST_ARGS "Hue POST args" +#define D_3_RESPONSE_PACKETS_SENT "3 요청 패킷이 전송됨" + +// xdrv_07_domoticz.ino +#define D_DOMOTICZ_PARAMETERS "Domoticz 상세" +#define D_DOMOTICZ_IDX "Idx" +#define D_DOMOTICZ_KEY_IDX "Key idx" +#define D_DOMOTICZ_SWITCH_IDX "스위치 idx" +#define D_DOMOTICZ_SENSOR_IDX "센서 idx" + #define D_DOMOTICZ_TEMP "온도" + #define D_DOMOTICZ_TEMP_HUM "온도,습도" + #define D_DOMOTICZ_TEMP_HUM_BARO "온도,습도,기압" + #define D_DOMOTICZ_POWER_ENERGY "전력,전력량" + #define D_DOMOTICZ_ILLUMINANCE "조도" + #define D_DOMOTICZ_COUNT "횟수/PM1" + #define D_DOMOTICZ_VOLTAGE "전압/PM2.5" + #define D_DOMOTICZ_CURRENT "전류/PM10" + #define D_DOMOTICZ_AIRQUALITY "공기질" +#define D_DOMOTICZ_UPDATE_TIMER "타이머 갱신" + +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "타이머 설정" +#define D_TIMER_PARAMETERS "타이머 상세" +#define D_TIMER_ENABLE "타이머 사용" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "시간" +#define D_TIMER_DAYS "일" +#define D_TIMER_REPEAT "반복" +#define D_TIMER_OUTPUT "출력" +#define D_TIMER_ACTION "행동" + +// xdrv_10_knx.ino +#define D_CONFIGURE_KNX "KNX 설정" +#define D_KNX_PARAMETERS "KNX 상세" +#define D_KNX_GENERAL_CONFIG "일반" +#define D_KNX_PHYSICAL_ADDRESS "물리적 주소" +#define D_KNX_PHYSICAL_ADDRESS_NOTE "( KNX 네트워크 상에서 반드시 고유한 이름이어야 합니다 )" +#define D_KNX_ENABLE "KNX 사용" +#define D_KNX_GROUP_ADDRESS_TO_WRITE "그룹 주소로 데이타를 보냅니다" +#define D_ADD "추가" +#define D_DELETE "삭제" +#define D_REPLY "응답" +#define D_KNX_GROUP_ADDRESS_TO_READ "받은 데이터의 그룹 주소" +#define D_LOG_KNX "KNX: " +#define D_RECEIVED_FROM "다음에서 받음" +#define D_KNX_COMMAND_WRITE "쓰기" +#define D_KNX_COMMAND_READ "읽기" +#define D_KNX_COMMAND_OTHER "기타" +#define D_SENT_TO "다음으로 보내기" +#define D_KNX_WARNING "그룹 주소 ( 0 / 0 / 0 )은 예약되어 사용할 수 없습니다" +#define D_KNX_ENHANCEMENT "커뮤니케이션 강화" +#define D_KNX_TX_SLOT "KNX TX" +#define D_KNX_RX_SLOT "KNX RX" + +// xdrv_03_energy.ino +#define D_ENERGY_TODAY "금일 전력 사용량" +#define D_ENERGY_YESTERDAY "어제 전력 사용량" +#define D_ENERGY_TOTAL "총 전력 사용량" + +// xsns_05_ds18b20.ino +#define D_SENSOR_BUSY "센서가 사용 중" +#define D_SENSOR_CRC_ERROR "센서 CRC 에러" +#define D_SENSORS_FOUND "센서 발견" + +// xsns_06_dht.ino +#define D_TIMEOUT_WAITING_FOR "대기 시간 초과" +#define D_START_SIGNAL_LOW "시작 신호 낮음" +#define D_START_SIGNAL_HIGH "시작 신호 높음" +#define D_PULSE "pulse" +#define D_CHECKSUM_FAILURE "체크섬 실패" + +// xsns_07_sht1x.ino +#define D_SENSOR_DID_NOT_ACK_COMMAND "센서가 ACK 명령을 수행하지 않음" +#define D_SHT1X_FOUND "SHT1X 발견" + +// xsns_18_pms5003.ino +#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter +#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter +#define D_PARTICALS_BEYOND "입자" + +// xsns_32_mpu6050.ino +#define D_AX_AXIS "Accel. X-Axis" +#define D_AY_AXIS "Accel. Y-Axis" +#define D_AZ_AXIS "Accel. Z-Axis" +#define D_GX_AXIS "Gyro X-Axis" +#define D_GY_AXIS "Gyro Y-Axis" +#define D_GZ_AXIS "Gyro Z-Axis" + +// xsns_34_hx711.ino +#define D_HX_CAL_REMOVE "중량 제거" +#define D_HX_CAL_REFERENCE "참조 중량 로드" +#define D_HX_CAL_DONE "교정됨" +#define D_HX_CAL_FAIL "교정 실패" +#define D_RESET_HX711 "스케일 초기화" +#define D_CONFIGURE_HX711 "스케일 설정" +#define D_HX711_PARAMETERS "스케일 상세" +#define D_ITEM_WEIGHT "아이템 중량" +#define D_REFERENCE_WEIGHT "참조 중량" +#define D_CALIBRATE "교정" +#define D_CALIBRATION "교정" + +//xsns_35_tx20.ino +#define D_TX20_WIND_DIRECTION "풍향" +#define D_TX20_WIND_SPEED "풍속" +#define D_TX20_WIND_SPEED_AVG "평균 풍속" +#define D_TX20_WIND_SPEED_MAX "최대 풍속" +#define D_TX20_NORTH "N" +#define D_TX20_EAST "E" +#define D_TX20_SOUTH "S" +#define D_TX20_WEST "W" + +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Switch" // Suffix "1" +#define D_SENSOR_BUTTON "Button" // Suffix "1" +#define D_SENSOR_RELAY "Relay" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Counter" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" + +// Units +#define D_UNIT_AMPERE "A" +#define D_UNIT_CENTIMETER "cm" +#define D_UNIT_HERTZ "Hz" +#define D_UNIT_HOUR "시" +#define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" +#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h" +#define D_UNIT_KILOOHM "kOhm" +#define D_UNIT_KILOWATTHOUR "kWh" +#define D_UNIT_LUX "lx" +#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3" +#define D_UNIT_MICROMETER "마이크로미터" +#define D_UNIT_MICROSECOND "마이크로초" +#define D_UNIT_MILLIAMPERE "mA" +#define D_UNIT_MILLIMETER "mm" +#define D_UNIT_MILLIMETER_MERCURY "mmHg" +#define D_UNIT_MILLISECOND "밀리초" +#define D_UNIT_MINUTE "분" +#define D_UNIT_PARTS_PER_BILLION "ppb" +#define D_UNIT_PARTS_PER_DECILITER "ppd" +#define D_UNIT_PARTS_PER_MILLION "ppm" +#define D_UNIT_PRESSURE "hPa" +#define D_UNIT_SECOND "초" +#define D_UNIT_SECTORS "섹터" +#define D_UNIT_VA "VA" +#define D_UNIT_VAR "VAr" +#define D_UNIT_VOLT "V" +#define D_UNIT_WATT "W" +#define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" + +// Log message prefix +#define D_LOG_APPLICATION "APP: " // Application +#define D_LOG_BRIDGE "BRG: " // Bridge +#define D_LOG_CONFIG "CFG: " // Settings +#define D_LOG_COMMAND "CMD: " // Command +#define D_LOG_DEBUG "DBG: " // Debug +#define D_LOG_DHT "DHT: " // DHT sensor +#define D_LOG_DOMOTICZ "DOM: " // Domoticz +#define D_LOG_DSB "DSB: " // DS18xB20 sensor +#define D_LOG_HTTP "HTP: " // HTTP webserver +#define D_LOG_I2C "I2C: " // I2C +#define D_LOG_IRR "IRR: " // Infra Red Received +#define D_LOG_LOG "LOG: " // Logging +#define D_LOG_MODULE "MOD: " // Module +#define D_LOG_MDNS "DNS: " // mDNS +#define D_LOG_MQTT "MQT: " // MQTT +#define D_LOG_OTHER "OTH: " // Other +#define D_LOG_RESULT "RSL: " // Result +#define D_LOG_RFR "RFR: " // RF Received +#define D_LOG_SERIAL "SER: " // Serial +#define D_LOG_SHT1 "SHT: " // SHT1x sensor +#define D_LOG_UPLOAD "UPL: " // Upload +#define D_LOG_UPNP "UPP: " // UPnP +#define D_LOG_WIFI "WIF: " // Wifi + +//SDM220 +#define D_PHASE_ANGLE "Phase Angle" +#define D_IMPORT_ACTIVE "Import Active" +#define D_EXPORT_ACTIVE "Export Active" +#define D_IMPORT_REACTIVE "Import Reactive" +#define D_EXPORT_REACTIVE "Export Reactive" +#define D_TOTAL_REACTIVE "Total Reactive" +#define D_UNIT_KWARH "kVArh" +#define D_UNIT_ANGLE "Deg" + +#endif // _LANGUAGE_KO_KO_H_ diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index b3bf10989..dd3fb1806 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -1,7 +1,7 @@ /* nl-NL.h - localization for Dutch - Nederland for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Stop" #define D_SUBNET_MASK "Subnet Masker" #define D_SUBSCRIBE_TO "Abonneer op" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Gelukt" #define D_SUNRISE "Zonsopgang" #define D_SUNSET "Zonsondergang" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Module parameters" #define D_MODULE_TYPE "Module soort" +#define D_PULLUP_ENABLE "Geen schakelaar pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serieel In" #define D_SERIAL_OUT "Serieel Uit" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Telemetry periode" #define D_OTHER_PARAMETERS "Overige parameters" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Web Admin Wachtwoord" #define D_MQTT_ENABLE "MQTT ingeschakeld" #define D_FRIENDLY_NAME "Beschrijvende naam" @@ -295,6 +299,14 @@ #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_ALLOW_PULLUP "User pull-up selection" + #define D_SAVE_CONFIGURATION "Bewaar configuratie" #define D_CONFIGURATION_SAVED "Configuratie opgeslagen" #define D_CONFIGURATION_RESET "Configuratie ge-reset" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "Geen" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Speler" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Switch" // Suffix "1" -#define D_SENSOR_BUTTON "Button" // Suffix "1" -#define D_SENSOR_RELAY "Relais" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Teller" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Speler" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Switch" // Suffix "1" +#define D_SENSOR_BUTTON "Button" // Suffix "1" +#define D_SENSOR_RELAY "Relais" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Teller" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index d80826751..24e2f60ae 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -1,7 +1,7 @@ /* pl-PL-d.h - localization for Polish with diacritics - Poland for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends (translated by roblad - Robert L., upgraded by R. Turala) + Copyright (C) 2019 Theo Arends (translated by roblad - Robert L., upgraded by R. Turala) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -62,7 +62,7 @@ #define D_BRIGHTLIGHT "Jasny" #define D_BSSID "BSSId" #define D_BUTTON "Przycisk" -#define D_BY "przez" // Written by me +#define D_BY "by" // Written by me #define D_BYTES "Bajtow" #define D_CELSIUS "Celsiusza" #define D_CHANNEL "Kanał" @@ -139,7 +139,7 @@ #define D_RESTART_REASON "Przyczyna restartu" #define D_RESTORE "Przywracanie" #define D_RETAINED "Zachowane" -#define D_RULE "Rule" +#define D_RULE "Reguła" #define D_SAVE "Zapisz" #define D_SENSOR "Czujnik" #define D_SSID "SSID" @@ -148,6 +148,7 @@ #define D_STOP "Stop" #define D_SUBNET_MASK "Maska podsieci" #define D_SUBSCRIBE_TO "Subskrybuj do" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Powodzenie" #define D_SUNRISE "Wschód słońca" #define D_SUNSET "Zachód słońca" @@ -235,7 +236,7 @@ #define D_BUTTON_TOGGLE "Przełącznik" #define D_CONFIGURATION "Konfiguracja" #define D_INFORMATION "Informacje" -#define D_FIRMWARE_UPGRADE "Uaktualnienie oprogramowania" +#define D_FIRMWARE_UPGRADE "Aktualizacja oprogramowania" #define D_CONSOLE "Konsola" #define D_CONFIRM_RESTART "Potwierdź restart" @@ -248,11 +249,12 @@ #define D_CONFIRM_RESET_CONFIGURATION "Potwierdź reset ustawień" #define D_RESET_CONFIGURATION "Reset ustawień" #define D_BACKUP_CONFIGURATION "Kopia ustawień" -#define D_RESTORE_CONFIGURATION "Przywrócenie ustawień" +#define D_RESTORE_CONFIGURATION "Przywracanie ustawień" #define D_MAIN_MENU "Menu główne" -#define D_MODULE_PARAMETERS "Parametery modułu" +#define D_MODULE_PARAMETERS "Parametry modułu" #define D_MODULE_TYPE "Typ modułu" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial In" #define D_SERIAL_OUT "Serial Out" @@ -273,28 +275,38 @@ #define D_AP2_SSID "AP2 SSID" #define D_AP2_PASSWORD "Hasło AP2" -#define D_MQTT_PARAMETERS "Parametery MQTT" +#define D_MQTT_PARAMETERS "Parametry MQTT" #define D_CLIENT "Klient" -#define D_FULL_TOPIC "Pełen temat" +#define D_FULL_TOPIC "Pełny temat" #define D_LOGGING_PARAMETERS "Opcje dziennika" #define D_SERIAL_LOG_LEVEL "Serial poziom dziennika" #define D_WEB_LOG_LEVEL "Web poziom dziennika" #define D_SYS_LOG_LEVEL "System poziom dziennika" -#define D_MORE_DEBUG "Więcej informacji debugujacych" +#define D_MORE_DEBUG "Więcej informacji debug" #define D_SYSLOG_HOST "Syslog host" #define D_SYSLOG_PORT "Syslog port" #define D_TELEMETRY_PERIOD "Okres telemetrii" -#define D_OTHER_PARAMETERS "Inne parametery" +#define D_OTHER_PARAMETERS "Inne parametry" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Hasło administratora Web" #define D_MQTT_ENABLE "MQTT aktywne" -#define D_FRIENDLY_NAME "Przyjazna nazwa" +#define D_FRIENDLY_NAME "Twoja nazwa" #define D_BELKIN_WEMO "Belkin WeMo" #define D_HUE_BRIDGE "Hue Bridge" #define D_SINGLE_DEVICE "single device" #define D_MULTI_DEVICE "multi device" +#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_SAVE_CONFIGURATION "Zapisz ustawienia" #define D_CONFIGURATION_SAVED "Ustawienia zapisane" #define D_CONFIGURATION_RESET "Ustawienia zresetowane" @@ -390,18 +402,18 @@ #define D_DOMOTICZ_UPDATE_TIMER "Zaktualizuj czasomierz" // xdrv_09_timers.ino -#define D_CONFIGURE_TIMER "Skonfiguruj harmonogram" +#define D_CONFIGURE_TIMER "Konfiguruj harmonogram" #define D_TIMER_PARAMETERS "Parametry harmonogramów" #define D_TIMER_ENABLE "Włącz Harmonogramy" #define D_TIMER_ARM "Włącz" -#define D_TIMER_TIME "Czas" +#define D_TIMER_TIME "Według godziny" #define D_TIMER_DAYS "Dni" #define D_TIMER_REPEAT "Powtarzaj" #define D_TIMER_OUTPUT "Wyjście" #define D_TIMER_ACTION "Akcja" // xdrv_10_knx.ino -#define D_CONFIGURE_KNX "Skonfiguruj KNX" +#define D_CONFIGURE_KNX "Konfiguruj KNX" #define D_KNX_PARAMETERS "Parametry KNX" #define D_KNX_GENERAL_CONFIG "Ogólne" #define D_KNX_PHYSICAL_ADDRESS "Adres Fizyczny" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "Brak" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Przela" // Suffix "1" -#define D_SENSOR_BUTTON "Przyci" // Suffix "1" -#define D_SENSOR_RELAY "Przek" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Liczni" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Przela" // Suffix "1" +#define D_SENSOR_BUTTON "Przyci" // Suffix "1" +#define D_SENSOR_RELAY "Przek" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Liczni" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index 7add978f0..3d24e2dbc 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -1,7 +1,7 @@ /* pt-BR.h - localization for Portuguese - Brazil for Sonoff-Tasmota - Copyright (C) 2018 Fabiano Bovo + Copyright (C) 2019 Fabiano Bovo This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Parar" #define D_SUBNET_MASK "Máscara sub rede" #define D_SUBSCRIBE_TO "Subescrever para" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Successo" #define D_SUNRISE "Nascer do sol" #define D_SUNSET "Por do sol" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Parâmetros do módulo" #define D_MODULE_TYPE "Tipo de módulo" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Entrada serial" #define D_SERIAL_OUT "Saída serial" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Período de telemetria" #define D_OTHER_PARAMETERS "Outros parâmetros" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Senha de WEB Admin" #define D_MQTT_ENABLE "MQTT habilitado" #define D_FRIENDLY_NAME "Nome amigável" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "Dispositivo único" #define D_MULTI_DEVICE "Múltiplos dispositivos" +#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_SAVE_CONFIGURATION "Gravar configuração" #define D_CONFIGURATION_SAVED "Configuração gravada" #define D_CONFIGURATION_RESET "Reinicialização da configuração" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "Nenhum" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Interruptor" // Suffix "1" -#define D_SENSOR_BUTTON "Botão" // Suffix "1" -#define D_SENSOR_RELAY "Relé" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Contador" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHz Rx" -#define D_SENSOR_MHZ_TX "MHz Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAIR Rx" -#define D_SENSOR_SAIR_TX "SAIR Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "Luz de fundo" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Interruptor" // Suffix "1" +#define D_SENSOR_BUTTON "Botão" // Suffix "1" +#define D_SENSOR_RELAY "Relé" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Contador" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "Luz de fundo" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index 9869762b8..d675efe54 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -1,7 +1,7 @@ /* pt-PT.h - localization for Portuguese - Portugal for Sonoff-Tasmota - Copyright (C) 2018 Paulo Paiva + Copyright (C) 2019 Paulo Paiva This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Parar" #define D_SUBNET_MASK "Mascara sub rede" #define D_SUBSCRIBE_TO "Subescrever para" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Successo" #define D_SUNRISE "Sunrise" #define D_SUNSET "Sunset" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Parametros do Módulo" #define D_MODULE_TYPE "Tipo de Módulo" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial Entrada" #define D_SERIAL_OUT "Serial Saída" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Periodo de Telemetria" #define D_OTHER_PARAMETERS "Outros parametros" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Palavra Chave de WEB Admin" #define D_MQTT_ENABLE "MQTT habilitado" #define D_FRIENDLY_NAME "Nome amigável" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "dispositivo único" #define D_MULTI_DEVICE "multiplos dispositivos" +#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_SAVE_CONFIGURATION "Salvar configuração" #define D_CONFIGURATION_SAVED "Configuração guardada" #define D_CONFIGURATION_RESET "Reinicialização da configuração" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "Nenhum" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Interruptor" // Suffix "1" -#define D_SENSOR_BUTTON "Botão" // Suffix "1" -#define D_SENSOR_RELAY "Relé" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Contador" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "Luz negra" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Interruptor" // Suffix "1" +#define D_SENSOR_BUTTON "Botão" // Suffix "1" +#define D_SENSOR_RELAY "Relé" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Contador" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "Luz negra" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index d0a3f6933..50eabbc35 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -1,7 +1,7 @@ /* ru-RU.h - localization for Russian - Rissia for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends / roman-vn + Copyright (C) 2019 Theo Arends / roman-vn This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Стоп" #define D_SUBNET_MASK "Маска Подсети" #define D_SUBSCRIBE_TO "Подписаться на" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Успешно" #define D_SUNRISE "Sunrise" #define D_SUNSET "Sunset" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Параметры модуля" #define D_MODULE_TYPE "Тип модуля" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial вход" #define D_SERIAL_OUT "Serial выход" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Период телеметрии" #define D_OTHER_PARAMETERS "Параметры Прочие" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Пароль Web администратора" #define D_MQTT_ENABLE "MQTT активен" #define D_FRIENDLY_NAME "Дружественное Имя" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "одиночное" #define D_MULTI_DEVICE "мульти" +#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_SAVE_CONFIGURATION "Сохранить конфигурацию" #define D_CONFIGURATION_SAVED "Конфигурация сохранена " #define D_CONFIGURATION_RESET "Конфигурация сброшена" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "-нет-" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Свич" // Suffix "1" -#define D_SENSOR_BUTTON "Кнопка" // Suffix "1" -#define D_SENSOR_RELAY "Реле" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Счетчик" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Свич" // Suffix "1" +#define D_SENSOR_BUTTON "Кнопка" // Suffix "1" +#define D_SENSOR_RELAY "Реле" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Счетчик" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/sk-SK.h b/sonoff/language/sk-SK.h index f46372426..4f741ac51 100644 --- a/sonoff/language/sk-SK.h +++ b/sonoff/language/sk-SK.h @@ -1,7 +1,7 @@ /* sk-SK.h - localization for Slovak with diacritics - Slovak for Sonoff-Tasmota - Copyright (C) 2018 Vladimír Jendroľ + Copyright (C) 2019 Vladimír Jendroľ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Stop" #define D_SUBNET_MASK "Maska podsiete" #define D_SUBSCRIBE_TO "Prihlásiť do" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "úspešné." #define D_SUNRISE "Svitanie" #define D_SUNSET "Súmrak" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Nastavenia modulu" #define D_MODULE_TYPE "Typ modulu" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial In" #define D_SERIAL_OUT "Serial Out" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Interval telemetrie" #define D_OTHER_PARAMETERS "Ostatné nastavenia" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Heslo Web administrátora" #define D_MQTT_ENABLE "MQTT aktívne" #define D_FRIENDLY_NAME "Friendly Name" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "single device" #define D_MULTI_DEVICE "multi device" +#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_SAVE_CONFIGURATION "Ulož nastavenia" #define D_CONFIGURATION_SAVED "Nastavenia uložené" #define D_CONFIGURATION_RESET "Nastavenia resetované" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "J" #define D_TX20_WEST "Z" -// sonoff_template.h -#define D_SENSOR_NONE "Žiaden" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Spínač" // Suffix "1" -#define D_SENSOR_BUTTON "Tlačidlo" // Suffix "1" -#define D_SENSOR_RELAY "Relé" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1", -#define D_SENSOR_COUNTER "Počítadlo" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Senzor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Spínač" // Suffix "1" +#define D_SENSOR_BUTTON "Tlačidlo" // Suffix "1" +#define D_SENSOR_RELAY "Relé" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1", +#define D_SENSOR_COUNTER "Počítadlo" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Senzor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/sv-SE.h b/sonoff/language/sv-SE.h index f36162a4b..dd6b31469 100644 --- a/sonoff/language/sv-SE.h +++ b/sonoff/language/sv-SE.h @@ -1,7 +1,7 @@ /* sv-SE.h - localization for Swedish - Svenska for Sonoff-Tasmota - Copyright (C) 2018 Gunnar Norin + Copyright (C) 2019 Gunnar Norin This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -132,11 +132,11 @@ #define D_PROGRAM_FLASH_SIZE "Program-flashstorlek" #define D_PROGRAM_SIZE "Programstorlek" #define D_PROJECT "Projekt" -#define D_RAIN "Rain" +#define D_RAIN "Regn" #define D_RECEIVED "Mottagen" #define D_RESTART "Omstart" #define D_RESTARTING "Startar om" -#define D_RESTART_REASON "Restart Reason" +#define D_RESTART_REASON "Omstartsorsak" #define D_RESTORE "återställ" #define D_RETAINED "bevarad" #define D_RULE "Regel" @@ -148,6 +148,7 @@ #define D_STOP "Stoppa" #define D_SUBNET_MASK "Nätmask" #define D_SUBSCRIBE_TO "Prenumera på" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Lyckat" #define D_SUNRISE "Soluppgång" #define D_SUNSET "Solnedgång" @@ -168,13 +169,13 @@ #define D_UV_INDEX_2 "Med" #define D_UV_INDEX_3 "Hög" #define D_UV_INDEX_4 "Farligt" -#define D_UV_INDEX_5 "BurnL1/2" -#define D_UV_INDEX_6 "BurnL3" -#define D_UV_INDEX_7 "OoR" // Out of Range +#define D_UV_INDEX_5 "Skadligt" +#define D_UV_INDEX_6 "Extremt" +#define D_UV_INDEX_7 "UO" // Out of Range #define D_UV_LEVEL "UV nivå" #define D_UV_POWER "UV kraft" #define D_VERSION "Version" -#define D_VOLTAGE "Voltage" +#define D_VOLTAGE "Volttal" #define D_WEIGHT "Vikt" #define D_WARMLIGHT "Varm" #define D_WEB_SERVER "Webbserver" @@ -197,7 +198,7 @@ #define D_WPS_FAILED_WITH_STATUS "WPS-konfigurering MISSLYCKADES med status" #define D_ACTIVE_FOR_3_MINUTES "aktiv för 3 minuter" #define D_FAILED_TO_START "misslyckades att starta" -#define D_PATCH_ISSUE_2186 "Patch issue 2186" +#define D_PATCH_ISSUE_2186 "Laga problem 2186" #define D_CONNECTING_TO_AP "Ansluter till AP" #define D_IN_MODE "i läge" #define D_CONNECT_FAILED_NO_IP_ADDRESS "Anslutning misslyckades mottog ingen IP-adress" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Modulparameterar" #define D_MODULE_TYPE "Modultyp" +#define D_PULLUP_ENABLE "Ingen knapp/brytare pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Seriell in" #define D_SERIAL_OUT "Seriell ut" @@ -280,13 +282,15 @@ #define D_LOGGING_PARAMETERS "Loggningsparametrar" #define D_SERIAL_LOG_LEVEL "Seriell loggnivå" #define D_WEB_LOG_LEVEL "Webb loggnivå" -#define D_SYS_LOG_LEVEL "Syslog-nivp" +#define D_SYS_LOG_LEVEL "Syslog-nivå" #define D_MORE_DEBUG "Mer debugging" #define D_SYSLOG_HOST "Syslog-värd" #define D_SYSLOG_PORT "Syslog-port" #define D_TELEMETRY_PERIOD "Telemetriperiod" #define D_OTHER_PARAMETERS "Andra parametrar" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Webbadmin-lösenord" #define D_MQTT_ENABLE "MQTT aktivera" #define D_FRIENDLY_NAME "Läsbart namn" @@ -295,13 +299,21 @@ #define D_SINGLE_DEVICE "soloenhet" #define D_MULTI_DEVICE "multienhet" +#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_SAVE_CONFIGURATION "Spara konfiguration" #define D_CONFIGURATION_SAVED "Konfiguration sparad" #define D_CONFIGURATION_RESET "Konfiguration nollställd" #define D_PROGRAM_VERSION "Programversion" -#define D_BUILD_DATE_AND_TIME "Build datum & tid" -#define D_CORE_AND_SDK_VERSION "Core/SDK Version" +#define D_BUILD_DATE_AND_TIME "Kompilerings datum & tid" +#define D_CORE_AND_SDK_VERSION "Core/SDK version" #define D_FLASH_WRITE_COUNT "Flash-skrivningsräknare" #define D_MAC_ADDRESS "MAC-adress" #define D_MQTT_HOST "MQTT-värd" @@ -338,11 +350,11 @@ #define D_UPLOAD_ERR_11 "Misslyckades rensa RF chip" #define D_UPLOAD_ERR_12 "Misslyckades skriva till RF chip" #define D_UPLOAD_ERR_13 "Misslyckades avkoda RF firmware" -#define D_UPLOAD_ERROR_CODE "Upladdningsfelkod" +#define D_UPLOAD_ERROR_CODE "Uppladdningsfelkod" #define D_ENTER_COMMAND "Ange kommando" -#define D_ENABLE_WEBLOG_FOR_RESPONSE "Aktivera weblog 2 om svar förväntas" -#define D_NEED_USER_AND_PASSWORD "Behöver användarnamn=&lösenord=" +#define D_ENABLE_WEBLOG_FOR_RESPONSE "Aktivera webblogg 2 om svar förväntas" +#define D_NEED_USER_AND_PASSWORD "Behöver user=&password=" // xdrv_01_mqtt.ino #define D_FINGERPRINT "Verifierar TLS fingeravtryck..." @@ -391,14 +403,14 @@ // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Konfigurera timer" -#define D_TIMER_PARAMETERS "timerparametrar" +#define D_TIMER_PARAMETERS "Timerparametrar" #define D_TIMER_ENABLE "Aktivera timer" #define D_TIMER_ARM "Aktivera" #define D_TIMER_TIME "Tid" #define D_TIMER_DAYS "Dagar" #define D_TIMER_REPEAT "Repetera" -#define D_TIMER_OUTPUT "Output" -#define D_TIMER_ACTION "Action" +#define D_TIMER_OUTPUT "Utgång" +#define D_TIMER_ACTION "Åtgärd" // xdrv_10_knx.ino #define D_CONFIGURE_KNX "Konfigurera KNX" @@ -476,77 +488,101 @@ #define D_TX20_WIND_SPEED_AVG "Vindstyrka medel" #define D_TX20_WIND_SPEED_MAX "Vindstyrka max" #define D_TX20_NORTH "N" -#define D_TX20_EAST "E" +#define D_TX20_EAST "Ö" #define D_TX20_SOUTH "S" -#define D_TX20_WEST "W" +#define D_TX20_WEST "V" -// sonoff_template.h -#define D_SENSOR_NONE "Ingen" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3-spelare" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Omkopplare" // Suffix "1" -#define D_SENSOR_BUTTON "Knapp" // Suffix "1" -#define D_SENSOR_RELAY "Relä" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Räknare" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3-spelare" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Omkopplare" // Suffix "1" +#define D_SENSOR_BUTTON "Knapp" // Suffix "1" +#define D_SENSOR_RELAY "Relä" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Räknare" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" -#define D_UNIT_HOUR "Hr" -#define D_UNIT_INCREMENTS "inc" +#define D_UNIT_HOUR "Tim" +#define D_UNIT_INCREMENTS "ink" #define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h" #define D_UNIT_KILOOHM "kOhm" @@ -599,12 +635,12 @@ #define D_LOG_WIFI "WIF: " // Wifi //SDM220 -#define D_PHASE_ANGLE "Phase Angle" -#define D_IMPORT_ACTIVE "Import Active" -#define D_EXPORT_ACTIVE "Export Active" -#define D_IMPORT_REACTIVE "Import Reactive" -#define D_EXPORT_REACTIVE "Export Reactive" -#define D_TOTAL_REACTIVE "Total Reactive" +#define D_PHASE_ANGLE "Fasvinkel" +#define D_IMPORT_ACTIVE "Import aktiv" +#define D_EXPORT_ACTIVE "Export aktiv" +#define D_IMPORT_REACTIVE "Import reaktiv" +#define D_EXPORT_REACTIVE "Export reaktiv" +#define D_TOTAL_REACTIVE "Total reaktiv" #define D_UNIT_KWARH "kVArh" #define D_UNIT_ANGLE "Deg" diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index 06d82b9cb..f6f61ec56 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -1,7 +1,7 @@ /* tr-TR.h - localization for Turkish - Turkey for Sonoff-Tasmota - Copyright (C) 2018 Ali Sait Teke and Theo Arends + Copyright (C) 2019 Ali Sait Teke and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Durdur" #define D_SUBNET_MASK "Altağ Geçidi Maskesi" #define D_SUBSCRIBE_TO "Abone olunan" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Başarıyla Tamamlandı" #define D_SUNRISE "Gün doğumu" #define D_SUNSET "Gün batımı" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Modül parametreleri" #define D_MODULE_TYPE "Modul türü" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial In" #define D_SERIAL_OUT "Serial Out" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Telemetri peryodu" #define D_OTHER_PARAMETERS "Diğer parametreler" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Web Yönetici Şifresi" #define D_MQTT_ENABLE "MQTT aktif" #define D_FRIENDLY_NAME "Kullanıcı Dostu İsim" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "tekli cihaz" #define D_MULTI_DEVICE "çoklu cihaz" +#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_SAVE_CONFIGURATION "Ayarları Kaydet" #define D_CONFIGURATION_SAVED "Ayarlar kaydedildi" #define D_CONFIGURATION_RESET "Ayarlar resetlendi" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "None" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Switch" // Suffix "1" -#define D_SENSOR_BUTTON "Button" // Suffix "1" -#define D_SENSOR_RELAY "Relay" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Counter" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Switch" // Suffix "1" +#define D_SENSOR_BUTTON "Button" // Suffix "1" +#define D_SENSOR_RELAY "Relay" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Counter" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index 509c90753..71b7665c1 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -1,7 +1,7 @@ /* uk-UK.h - localization for Ukrainian - Ukrain for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends / vadym-adik + Copyright (C) 2019 Theo Arends / vadym-adik This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "Стоп" #define D_SUBNET_MASK "Маска Підмережі" #define D_SUBSCRIBE_TO "Підписатись на" +#define D_UNSUBSCRIBE_FROM "Unsubscribe from" #define D_SUCCESSFUL "Успішно" #define D_SUNRISE "Схід сонця" #define D_SUNSET "Захід сонця" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "Параметри модулю" #define D_MODULE_TYPE "Тип модулю" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "Serial вхід" #define D_SERIAL_OUT "Serial вихід" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "Період телеметрії" #define D_OTHER_PARAMETERS "Параметри Інше" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "Гасло Web адміністратора" #define D_MQTT_ENABLE "MQTT активний" #define D_FRIENDLY_NAME "Дружнє Ім'я" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "одиночне" #define D_MULTI_DEVICE "мульти" +#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_SAVE_CONFIGURATION "Зберегти конфігурацію" #define D_CONFIGURATION_SAVED "Конфігурація збережена " #define D_CONFIGURATION_RESET "Конфігурація скинута" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "-відсутньо-" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Перемикач" // Suffix "1" -#define D_SENSOR_BUTTON "Кнопка" // Suffix "1" -#define D_SENSOR_RELAY "Реле" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Лічильник" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Перемикач" // Suffix "1" +#define D_SENSOR_BUTTON "Кнопка" // Suffix "1" +#define D_SENSOR_RELAY "Реле" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Лічильник" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 05bedca81..586591278 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -1,7 +1,7 @@ /* zh-CN.h - localization for Chinese (Simplified) - China for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends (translated by killadm) + Copyright (C) 2019 Theo Arends (translated by killadm) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -65,7 +65,7 @@ #define D_BY "汉化: killadm 作者:" // Written by me #define D_BYTES "大小:" #define D_CELSIUS "摄氏" -#define D_CHANNEL "Channel" +#define D_CHANNEL "频道" #define D_CO2 "二氧化碳" #define D_CODE "代码" // Button code #define D_COLDLIGHT "冷" @@ -132,7 +132,7 @@ #define D_PROGRAM_FLASH_SIZE "固件 Flash 大小" #define D_PROGRAM_SIZE "固件大小" #define D_PROJECT "项目:" -#define D_RAIN "Rain" +#define D_RAIN "降水量" #define D_RECEIVED "已接收" #define D_RESTART "重启" #define D_RESTARTING "正在重启" @@ -148,6 +148,7 @@ #define D_STOP "停止" #define D_SUBNET_MASK "子网掩码" #define D_SUBSCRIBE_TO "订阅" +#define D_UNSUBSCRIBE_FROM "退订" #define D_SUCCESSFUL "成功" #define D_SUNRISE "日出" #define D_SUNSET "日落" @@ -164,18 +165,18 @@ #define D_USER "用户名" #define D_UTC_TIME "UTC" #define D_UV_INDEX "紫外线指数" -#define D_UV_INDEX_1 "Low" -#define D_UV_INDEX_2 "Mid" -#define D_UV_INDEX_3 "High" -#define D_UV_INDEX_4 "Danger" +#define D_UV_INDEX_1 "低" +#define D_UV_INDEX_2 "中" +#define D_UV_INDEX_3 "高" +#define D_UV_INDEX_4 "危险" #define D_UV_INDEX_5 "BurnL1/2" #define D_UV_INDEX_6 "BurnL3" #define D_UV_INDEX_7 "OoR" #define D_UV_LEVEL "紫外线水平" -#define D_UV_POWER "UV Power" +#define D_UV_POWER "紫外线功率 " #define D_VERSION "版本" #define D_VOLTAGE "电压" -#define D_WEIGHT "Weight" +#define D_WEIGHT "重量" #define D_WARMLIGHT "暖" #define D_WEB_SERVER "Web Server" @@ -218,7 +219,7 @@ #define D_ERASED_SECTOR "擦除扇区" // webserver.ino -#define D_NOSCRIPT "To use Tasmota, please enable JavaScript" +#define D_NOSCRIPT "Tasmota要求浏览器支持 JavaScript" #define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "当前是精简版固件 - 请升级" #define D_WEBSERVER_ACTIVE_ON "Web 服务器地址:" #define D_WITH_IP_ADDRESS "IP 地址:" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "模块设置" #define D_MODULE_TYPE "模块类型" +#define D_PULLUP_ENABLE "没有按钮/开关上拉" #define D_GPIO "GPIO" #define D_SERIAL_IN "串口输入(RX)" #define D_SERIAL_OUT "串口输出(TX)" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "上报周期" #define D_OTHER_PARAMETERS "其他设置" +#define D_TEMPLATE "模板" +#define D_ACTIVATE "启用" #define D_WEB_ADMIN_PASSWORD "WEB 管理密码" #define D_MQTT_ENABLE "启用MQTT" #define D_FRIENDLY_NAME "昵称" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "单设备" #define D_MULTI_DEVICE "多设备" +#define D_CONFIGURE_TEMPLATE "模板配置" +#define D_TEMPLATE_PARAMETERS "模板参数" +#define D_TEMPLATE_NAME "名称" +#define D_BASE_TYPE "基于" +#define D_TEMPLATE_FLAGS "选项" +#define D_ALLOW_ADC0 "ADC0 输入" +#define D_ALLOW_PULLUP "用户上拉选择" + #define D_SAVE_CONFIGURATION "保存设置" #define D_CONFIGURATION_SAVED "设置已保存" #define D_CONFIGURATION_RESET "设置已重置" @@ -450,104 +462,128 @@ #define D_PARTICALS_BEYOND "颗粒物直径大于" // xsns_32_mpu6050.ino -#define D_AX_AXIS "Accel. X-Axis" -#define D_AY_AXIS "Accel. Y-Axis" -#define D_AZ_AXIS "Accel. Z-Axis" -#define D_GX_AXIS "Gyro X-Axis" -#define D_GY_AXIS "Gyro Y-Axis" -#define D_GZ_AXIS "Gyro Z-Axis" +#define D_AX_AXIS "加速度计X轴分量" +#define D_AY_AXIS "加速度计Y轴分量" +#define D_AZ_AXIS "加速度计Z轴分量" +#define D_GX_AXIS "绕X轴旋转的角速度" +#define D_GY_AXIS "绕Y轴旋转的角速度" +#define D_GZ_AXIS "绕Z轴旋转的角速度" // xsns_34_hx711.ino -#define D_HX_CAL_REMOVE "Remove weigth" -#define D_HX_CAL_REFERENCE "Load reference weigth" -#define D_HX_CAL_DONE "Calibrated" -#define D_HX_CAL_FAIL "Calibration failed" -#define D_RESET_HX711 "Reset Scale" -#define D_CONFIGURE_HX711 "Configure Scale" -#define D_HX711_PARAMETERS "Scale parameters" -#define D_ITEM_WEIGHT "Item weight" -#define D_REFERENCE_WEIGHT "Reference weigth" -#define D_CALIBRATE "Calibrate" -#define D_CALIBRATION "Calibration" +#define D_HX_CAL_REMOVE "去除重量" +#define D_HX_CAL_REFERENCE "加载参考重量" +#define D_HX_CAL_DONE "已校准" +#define D_HX_CAL_FAIL "校准失败" +#define D_RESET_HX711 "秤重置" +#define D_CONFIGURE_HX711 "秤配置" +#define D_HX711_PARAMETERS "秤参数" +#define D_ITEM_WEIGHT "物品中粮" +#define D_REFERENCE_WEIGHT "参考重量" +#define D_CALIBRATE "校准" +#define D_CALIBRATION "校准" //xsns_35_tx20.ino -#define D_TX20_WIND_DIRECTION "Wind Direction" -#define D_TX20_WIND_SPEED "Wind Speed" -#define D_TX20_WIND_SPEED_AVG "Wind Speed Avg" -#define D_TX20_WIND_SPEED_MAX "Wind Speed Max" -#define D_TX20_NORTH "N" -#define D_TX20_EAST "E" -#define D_TX20_SOUTH "S" -#define D_TX20_WEST "W" +#define D_TX20_WIND_DIRECTION "风向" +#define D_TX20_WIND_SPEED "风速" +#define D_TX20_WIND_SPEED_AVG "平均风速" +#define D_TX20_WIND_SPEED_MAX "最高风速" +#define D_TX20_NORTH "北" +#define D_TX20_EAST "东" +#define D_TX20_SOUTH "南" +#define D_TX20_WEST "西" -// sonoff_template.h -#define D_SENSOR_NONE "无" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Switch" // Suffix "1" -#define D_SENSOR_BUTTON "Button" // Suffix "1" -#define D_SENSOR_RELAY "Relay" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Counter" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Switch" // Suffix "1" +#define D_SENSOR_BUTTON "Button" // Suffix "1" +#define D_SENSOR_RELAY "Relay" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Counter" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "安" #define D_UNIT_CENTIMETER "厘米" #define D_UNIT_HOUR "时" #define D_UNIT_INCREMENTS "inc" -#define D_UNIT_KILOGRAM "kg" -#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h" +#define D_UNIT_KILOGRAM "千克" +#define D_UNIT_KILOMETER_PER_HOUR "公里/时" // or "km/h" #define D_UNIT_KILOOHM "千欧" #define D_UNIT_KILOWATTHOUR "千瓦时" #define D_UNIT_LUX "勒克斯" @@ -555,8 +591,8 @@ #define D_UNIT_MICROMETER "微米" #define D_UNIT_MICROSECOND "微秒" #define D_UNIT_MILLIAMPERE "毫安" -#define D_UNIT_MILLIMETER "mm" -#define D_UNIT_MILLIMETER_MERCURY "mmHg" +#define D_UNIT_MILLIMETER "毫米" +#define D_UNIT_MILLIMETER_MERCURY "毫米汞柱" #define D_UNIT_MILLISECOND "毫秒" #define D_UNIT_MINUTE "分" #define D_UNIT_PARTS_PER_BILLION "ppb" @@ -565,13 +601,13 @@ #define D_UNIT_PRESSURE "百帕" #define D_UNIT_SECOND "秒" #define D_UNIT_SECTORS "扇区" -#define D_UNIT_VA "VA" -#define D_UNIT_VAR "VAr" +#define D_UNIT_VA "伏安" +#define D_UNIT_VAR "无功伏安" #define D_UNIT_VOLT "伏" #define D_UNIT_WATT "瓦" #define D_UNIT_WATTHOUR "瓦时" #define D_UNIT_HERTZ "赫兹" -#define D_UNIT_WATT_METER_QUADRAT "W/m²" +#define D_UNIT_WATT_METER_QUADRAT "瓦/平米" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application @@ -599,13 +635,13 @@ #define D_LOG_WIFI "WIF: " // Wifi //SDM220 -#define D_PHASE_ANGLE "Phase Angle" -#define D_IMPORT_ACTIVE "Import Active" -#define D_EXPORT_ACTIVE "Export Active" -#define D_IMPORT_REACTIVE "Import Reactive" -#define D_EXPORT_REACTIVE "Export Reactive" -#define D_TOTAL_REACTIVE "Total Reactive" -#define D_UNIT_KWARH "kVArh" -#define D_UNIT_ANGLE "Deg" +#define D_PHASE_ANGLE "相位角" +#define D_IMPORT_ACTIVE "有功输入" +#define D_EXPORT_ACTIVE "有功输出" +#define D_IMPORT_REACTIVE "无功输入" +#define D_EXPORT_REACTIVE "无功输出" +#define D_TOTAL_REACTIVE "总无功功率" +#define D_UNIT_KWARH "千乏时" +#define D_UNIT_ANGLE "度" #endif // _LANGUAGE_ZH_CN_H_ diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 2780181aa..ae6d4df07 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -1,7 +1,7 @@ /* zh-TW.h - localization for Chinese (Traditional) - Taiwan for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends (translated by dannydu) + Copyright (C) 2019 Theo Arends (translated by dannydu) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,6 +148,7 @@ #define D_STOP "停止" #define D_SUBNET_MASK "子網遮罩" #define D_SUBSCRIBE_TO "訂閱" +#define D_UNSUBSCRIBE_FROM "退訂" #define D_SUCCESSFUL "成功" #define D_SUNRISE "Sunrise" #define D_SUNSET "Sunset" @@ -253,6 +254,7 @@ #define D_MODULE_PARAMETERS "模塊設置" #define D_MODULE_TYPE "模塊類型" +#define D_PULLUP_ENABLE "No Button/Switch pull-up" #define D_GPIO "GPIO" #define D_SERIAL_IN "串口輸入(RX)" #define D_SERIAL_OUT "串口輸出(TX)" @@ -287,6 +289,8 @@ #define D_TELEMETRY_PERIOD "上報周期" #define D_OTHER_PARAMETERS "其他設置" +#define D_TEMPLATE "Template" +#define D_ACTIVATE "Activate" #define D_WEB_ADMIN_PASSWORD "WEB管理密碼" #define D_MQTT_ENABLE "啟用MQTT" #define D_FRIENDLY_NAME "昵稱" @@ -295,6 +299,14 @@ #define D_SINGLE_DEVICE "單設備" #define D_MULTI_DEVICE "多設備" +#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_SAVE_CONFIGURATION "保存設置" #define D_CONFIGURATION_SAVED "設置已保存" #define D_CONFIGURATION_RESET "設置已重置" @@ -480,66 +492,90 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" -// sonoff_template.h -#define D_SENSOR_NONE "None" -#define D_SENSOR_DHT11 "DHT11" -#define D_SENSOR_AM2301 "AM2301" -#define D_SENSOR_SI7021 "SI7021" -#define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_WS2812 "WS2812" -#define D_SENSOR_DFR562 "MP3 Player" -#define D_SENSOR_IRSEND "IRsend" -#define D_SENSOR_SWITCH "Switch" // Suffix "1" -#define D_SENSOR_BUTTON "Button" // Suffix "1" -#define D_SENSOR_RELAY "Relay" // Suffix "1i" -#define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_PWM "PWM" // Suffix "1" -#define D_SENSOR_COUNTER "Counter" // Suffix "1" -#define D_SENSOR_IRRECV "IRrecv" -#define D_SENSOR_MHZ_RX "MHZ Rx" -#define D_SENSOR_MHZ_TX "MHZ Tx" -#define D_SENSOR_PZEM004_RX "PZEM004 Rx" -#define D_SENSOR_PZEM016_RX "PZEM016 Rx" -#define D_SENSOR_PZEM017_RX "PZEM017 Rx" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" -#define D_SENSOR_SAIR_RX "SAir Rx" -#define D_SENSOR_SAIR_TX "SAir Tx" -#define D_SENSOR_SPI_CS "SPI CS" -#define D_SENSOR_SPI_DC "SPI DC" -#define D_SENSOR_BACKLIGHT "BkLight" -#define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" -#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" -#define D_SENSOR_SBR_RX "SerBr Rx" -#define D_SENSOR_SBR_TX "SerBr Tx" -#define D_SENSOR_SR04_TRIG "SR04 Tri" -#define D_SENSOR_SR04_ECHO "SR04 Ech" -#define D_SENSOR_SDM120_TX "SDM120/220 Tx" -#define D_SENSOR_SDM120_RX "SDM120/220 Rx" -#define D_SENSOR_SDM630_TX "SDM630 Tx" -#define D_SENSOR_SDM630_RX "SDM630 Rx" -#define D_SENSOR_TM1638_CLK "TM16 CLK" -#define D_SENSOR_TM1638_DIO "TM16 DIO" -#define D_SENSOR_TM1638_STB "TM16 STB" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" -#define D_SENSOR_TX20_TX "TX20" -#define D_SENSOR_RFSEND "RFSend" -#define D_SENSOR_RFRECV "RFrecv" -#define D_SENSOR_TUYA_TX "Tuya Tx" -#define D_SENSOR_TUYA_RX "Tuya Rx" -#define D_SENSOR_MGC3130_XFER "MGC3130 Xfer" -#define D_SENSOR_MGC3130_RESET "MGC3130 Reset" -#define D_SENSOR_SSPI_MISO "SSPI MISO" -#define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" -#define D_SENSOR_SSPI_CS "SSPI CS" -#define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ Rx" -#define D_SENSOR_AZ_TX "AZ Tx" +// 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" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "Switch" // Suffix "1" +#define D_SENSOR_BUTTON "Button" // Suffix "1" +#define D_SENSOR_RELAY "Relay" // Suffix "1i" +#define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "Counter" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_TX20_TX "TX20" +#define D_SENSOR_RFSEND "RFSend" +#define D_SENSOR_RFRECV "RFrecv" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" +#define D_SENSOR_SSPI_MISO "SSPI MISO" +#define D_SENSOR_SSPI_MOSI "SSPI MOSI" +#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_CS "SSPI CS" +#define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" +#define D_SENSOR_MAX31855_CS "MX31855 CS" +#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_DO "MX31855 DO" +#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_CF1 "HLWBL CF1" +#define D_SENSOR_HLW_CF "HLW8012 CF" +#define D_SENSOR_HJL_CF "BL0937 CF" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 CLK" +#define D_SENSOR_SM16716_DAT "SM16716 DAT" +#define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 5fcbecabf..5214ad46c 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -1,7 +1,7 @@ /* my_user_config.h - user specific configuration for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -54,9 +54,10 @@ #define SAVE_DATA 1 // [SaveData] Save changed parameters to Flash (0 = disable, 1 - 3600 seconds) #define SAVE_STATE 1 // [SetOption0] Save changed power state to Flash (0 = disable, 1 = enable) +#define BOOT_LOOP_OFFSET 1 // [SetOption36] Number of boot loops before starting restoring defaults (0 = disable, 1..200 = boot loops offset) // -- Wifi ---------------------------------------- -#define WIFI_IP_ADDRESS "0.0.0.0" // [IpAddress1] Set to 0.0.0.0 for using DHCP or IP address +#define WIFI_IP_ADDRESS "0.0.0.0" // [IpAddress1] Set to 0.0.0.0 for using DHCP or enter a static IP address #define WIFI_GATEWAY "192.168.1.1" // [IpAddress2] If not using DHCP set Gateway IP address #define WIFI_SUBNETMASK "255.255.255.0" // [IpAddress3] If not using DHCP set Network mask #define WIFI_DNS "192.168.1.1" // [IpAddress4] If not using DHCP set DNS IP address (might be equal to WIFI_GATEWAY) @@ -121,6 +122,7 @@ // -- MQTT - Telemetry ---------------------------- #define TELE_PERIOD 300 // [TelePeriod] Telemetry (0 = disable, 10 - 3600 seconds) +#define TELE_ON_POWER 0 // [SetOption59] send tele/STATE together with stat/RESULT (0 = Disable, 1 = Enable) // -- MQTT - Domoticz ----------------------------- #define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) @@ -134,6 +136,9 @@ #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) +// -- mDNS ---------------------------------------- +#define MDNS_ENABLED 0 // [SetOption55] Use mDNS (0 = Disable, 1 = Enable) + // -- Time - Up to three NTP servers in your region #define NTP_SERVER1 "pool.ntp.org" // [NtpServer1] Select first NTP server by name or IP address (129.250.35.250) #define NTP_SERVER2 "nl.pool.ntp.org" // [NtpServer2] Select second NTP server by name or IP address (5.39.184.5) @@ -204,6 +209,7 @@ //#define MY_LANGUAGE he-HE // Hebrew in Israel //#define MY_LANGUAGE hu-HU // Hungarian in Hungary //#define MY_LANGUAGE it-IT // Italian in Italy +//#define MY_LANGUAGE ko-KO // Korean in Korea //#define MY_LANGUAGE nl-NL // Dutch in the Netherlands //#define MY_LANGUAGE pl-PL // Polish in Poland //#define MY_LANGUAGE pt-BR // Portuguese in Brazil @@ -243,7 +249,7 @@ #define DOMOTICZ_OUT_TOPIC "domoticz/out" // Domoticz Output Topic // -- MQTT - Home Assistant Discovery ------------- -#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+2k code) +#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+7k code) #define HOME_ASSISTANT_DISCOVERY_PREFIX "homeassistant" // Home Assistant discovery prefix // -- MQTT - TLS ---------------------------------- @@ -274,6 +280,8 @@ // -- Rules --------------------------------------- #define USE_RULES // Add support for rules (+4k4 code) +// #define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem) +// #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code) // -- Internal Analog input ----------------------- #define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices @@ -283,6 +291,7 @@ //#define USE_DS18x20_LEGACY // Optional for more than one DS18x20 sensors with dynamic scan using library OneWire (+1k5 code) #define USE_DS18x20 // Optional for more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code) // #define W1_PARASITE_POWER // If using USE_DS18x20 then optimize for parasite powered sensors +// #define DS18B20_INTERNAL_PULLUP // Use INPUT_PULLUP internal pullup resistors for single DS18B20 // -- I2C sensors --------------------------------- #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) @@ -321,6 +330,8 @@ // #define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code) // #define USE_RTC_ADDR 0x68 // Default I2C address 0x68 // #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) +// #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) +// #define USE_SCD30 // Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) // #define USE_DISPLAY // Add I2C Display Support (+2k code) #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 @@ -335,7 +346,6 @@ #define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module - #endif // USE_I2C // -- SPI sensors --------------------------------- @@ -370,6 +380,10 @@ #define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) #define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer //#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) +// #define USE_PN532_DATA_FUNCTION // Add sensor40 command support for erase, setting data block content (+1k7 code, 388 bytes mem) +// #define USE_PN532_DATA_RAW // Allow DATA block to be used by non-alpha-numberic data (+ 80 bytes code, 48 bytes ram) // Power monitoring sensors ----------------------- #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) @@ -378,6 +392,8 @@ #define USE_MCP39F501 // Add support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code) // -- Low level interface devices ----------------- +//#define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI + #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k3 code, 0k3 mem, 48 iram) // #define USE_IR_HVAC // Support for HVAC (Toshiba, Mitsubishi and LG) system using IR (+3k5 code) #define USE_IR_RECEIVE // Support for IR receiver (+7k2 code, 264 iram) @@ -407,6 +423,8 @@ // #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 weather stations using 868MHz RF sensor receiver (+1k7 code) +#define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code) + /*********************************************************************************************\ * Debug features are only supported in development branch \*********************************************************************************************/ @@ -419,12 +437,12 @@ * See RELEASENOTES.md for selected features \*********************************************************************************************/ -//#define USE_CLASSIC // Create sonoff-classic with initial configuration tools WPS, SmartConfig and WifiManager -//#define USE_BASIC // Create sonoff-basic with no sensors -//#define USE_SENSORS // Create sonoff-sensors with useful sensors enabled -//#define USE_KNX_NO_EMULATION // Create sonoff-knx with KNX but without Emulation -//#define USE_DISPLAYS // Create sonoff-display with display drivers enabled -//#define BE_MINIMAL // Create sonoff-minimal as intermediate firmware for OTA-MAGIC +//#define FIRMWARE_CLASSIC // Create sonoff-classic with initial configuration tools WPS, SmartConfig and WifiManager +//#define FIRMWARE_BASIC // Create sonoff-basic with no sensors +//#define FIRMWARE_SENSORS // Create sonoff-sensors with useful sensors enabled +//#define FIRMWARE_KNX_NO_EMULATION // Create sonoff-knx with KNX but without Emulation +//#define FIRMWARE_DISPLAYS // Create sonoff-display with display drivers enabled +//#define FIRMWARE_MINIMAL // Create sonoff-minimal as intermediate firmware for OTA-MAGIC /*********************************************************************************************\ * No user configurable items below diff --git a/sonoff/settings.h b/sonoff/settings.h index 4de813d18..342ff1612 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -1,7 +1,7 @@ /* settings.h - setting variables for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,57 +25,57 @@ typedef union { // Restricted by MISRA-C Rule 18.4 but so useful... uint32_t data; // Allow bit manipulation using SetOption struct { // SetOption0 .. SetOption31 - uint32_t save_state : 1; // bit 0 - uint32_t button_restrict : 1; // bit 1 - uint32_t value_units : 1; // bit 2 - uint32_t mqtt_enabled : 1; // bit 3 - uint32_t mqtt_response : 1; // bit 4 - uint32_t mqtt_power_retain : 1; // CMND_POWERRETAIN - uint32_t mqtt_button_retain : 1; // CMND_BUTTONRETAIN - uint32_t mqtt_switch_retain : 1; // CMND_SWITCHRETAIN - uint32_t temperature_conversion : 1; // bit 8 - uint32_t mqtt_sensor_retain : 1; // CMND_SENSORRETAIN - uint32_t mqtt_offline : 1; // bit 10 - uint32_t button_swap : 1; // bit 11 (v5.1.6) - uint32_t stop_flash_rotate : 1; // bit 12 (v5.2.0) - uint32_t button_single : 1; // bit 13 (v5.4.0) - uint32_t interlock : 1; // bit 14 (v5.6.0) - uint32_t pwm_control : 1; // bit 15 (v5.8.1) - uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) - uint32_t decimal_text : 1; // bit 17 (v5.8.1) - uint32_t light_signal : 1; // bit 18 (v5.10.0c) - uint32_t hass_discovery : 1; // bit 19 (v5.11.1a) - uint32_t not_power_linked : 1; // bit 20 (v5.11.1f) - uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i) - uint32_t mqtt_serial : 1; // bit 22 (v5.12.0f) - uint32_t mqtt_serial_raw : 1; // bit 23 (v6.1.1c) // Was rules_enabled until 5.14.0b - uint32_t pressure_conversion : 1; // bit 24 (v6.3.0.2) // Was rules_once until 5.14.0b - uint32_t knx_enabled : 1; // bit 25 (v5.12.0l) KNX - uint32_t device_index_enable : 1; // bit 26 (v5.13.1a) - uint32_t knx_enable_enhancement : 1; // bit 27 (v5.14.0a) KNX - uint32_t rf_receive_decimal : 1; // bit 28 (v6.0.0a) - uint32_t ir_receive_decimal : 1; // bit 29 (v6.0.0a) - uint32_t hass_light : 1; // bit 30 (v6.0.0b) - uint32_t global_state : 1; // bit 31 (v6.1.0) + uint32_t save_state : 1; // bit 0 - SetOption0 - Save power state and use after restart + uint32_t button_restrict : 1; // bit 1 - SetOption1 - Control button multipress + uint32_t value_units : 1; // bit 2 - SetOption2 - Add units to JSON status messages + uint32_t mqtt_enabled : 1; // bit 3 - SetOption3 - Control MQTT + uint32_t mqtt_response : 1; // bit 4 - SetOption4 - Switch between MQTT RESULT or COMMAND + uint32_t mqtt_power_retain : 1; // bit 5 - CMND_POWERRETAIN + uint32_t mqtt_button_retain : 1; // bit 6 - CMND_BUTTONRETAIN + uint32_t mqtt_switch_retain : 1; // bit 7 - CMND_SWITCHRETAIN + uint32_t temperature_conversion : 1; // bit 8 - SetOption8 - Switch between Celsius or Fahrenheit + uint32_t mqtt_sensor_retain : 1; // bit 9 - CMND_SENSORRETAIN + uint32_t mqtt_offline : 1; // bit 10 - SetOption10 - Control MQTT LWT message format + uint32_t button_swap : 1; // bit 11 (v5.1.6) - SetOption11 - Swap button single and double press functionality + uint32_t stop_flash_rotate : 1; // bit 12 (v5.2.0) - SetOption12 - Switch between dynamic or fixed slot flash save location + uint32_t button_single : 1; // bit 13 (v5.4.0) - SetOption13 - Support only single press to speed up button press recognition + uint32_t interlock : 1; // bit 14 (v5.6.0) - CMND_INTERLOCK + uint32_t pwm_control : 1; // bit 15 (v5.8.1) - SetOption15 - Switch between commands PWM or COLOR/DIMMER/CT/CHANNEL + uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) - SetOption16 - Switch between clockwise or counter-clockwise + uint32_t decimal_text : 1; // bit 17 (v5.8.1) - SetOption17 - Switch between decimal or hexadecimal output + uint32_t light_signal : 1; // bit 18 (v5.10.0c) - SetOption18 - Pair light signal with CO2 sensor + uint32_t hass_discovery : 1; // bit 19 (v5.11.1a) - SetOption19 - Control Home Assistantautomatic discovery (See SetOption59) + uint32_t not_power_linked : 1; // bit 20 (v5.11.1f) - SetOption20 - Control power in relation to Dimmer/Color/Ct changes + uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i) - SetOption21 - Show voltage even if powered off + uint32_t mqtt_serial : 1; // bit 22 (v5.12.0f) - CMND_SERIALSEND and CMND_SERIALLOG + uint32_t mqtt_serial_raw : 1; // bit 23 (v6.1.1c) - CMND_SERIALSEND3 + uint32_t pressure_conversion : 1; // bit 24 (v6.3.0.2) - SetOption24 - Switch between hPa or mmHg pressure unit + uint32_t knx_enabled : 1; // bit 25 (v5.12.0l) - CMND_KNX_ENABLED + uint32_t device_index_enable : 1; // bit 26 (v5.13.1a) - SetOption26 - Switch between POWER or POWER1 + uint32_t knx_enable_enhancement : 1; // bit 27 (v5.14.0a) - CMND_KNX_ENHANCED + uint32_t rf_receive_decimal : 1; // bit 28 (v6.0.0a) - SetOption28 - RF receive data format + uint32_t ir_receive_decimal : 1; // bit 29 (v6.0.0a) - SetOption29 - IR receive data format + uint32_t hass_light : 1; // bit 30 (v6.0.0b) - SetOption30 - Enforce HAss autodiscovery as light + uint32_t global_state : 1; // bit 31 (v6.1.0) - SetOption31 - Control link led blinking }; } SysBitfield; typedef union { // Restricted by MISRA-C Rule 18.4 but so useful... uint32_t data; // Allow bit manipulation using SetOption struct { // SetOption50 .. SetOption81 - uint32_t timers_enable : 1; // bit 0 (v6.1.1b) - uint32_t user_esp8285_enable : 1; // bit 1 (v6.1.1.14) - uint32_t time_append_timezone : 1; // bit 2 (v6.2.1.2) - uint32_t gui_hostname_ip : 1; // bit 3 (v6.2.1.20) - uint32_t tuya_apply_o20 : 1; // bit 4 (v6.3.0.4) - uint32_t spare5 : 1; - uint32_t use_wifi_scan : 1; // bit 6 (v6.3.0.10) - uint32_t use_wifi_rescan : 1; // bit 7 (v6.3.0.10) - uint32_t receive_raw : 1; // bit 8 (v6.3.0.11) - uint32_t hass_tele_on_power : 1; // bit 9 (v6.3.0.13) + uint32_t timers_enable : 1; // bit 0 (v6.1.1b) - CMND_TIMERS + uint32_t user_esp8285_enable : 1; // bit 1 (v6.1.1.14) - SetOption51 - Enable ESP8285 user GPIO's + uint32_t time_append_timezone : 1; // bit 2 (v6.2.1.2) - SetOption52 - Append timezone to JSON time + uint32_t gui_hostname_ip : 1; // bit 3 (v6.2.1.20) - SetOption53 - Show hostanme and IP address in GUI main menu + uint32_t tuya_apply_o20 : 1; // bit 4 (v6.3.0.4) - SetOption54 - Apply SetOption20 settings to Tuya device + uint32_t mdns_enabled : 1; // bit 5 (v6.4.1.4) - SetOption55 - Control mDNS service + uint32_t use_wifi_scan : 1; // bit 6 (v6.3.0.10) - SetOption56 - Scan wifi network at restart for configured AP's + uint32_t use_wifi_rescan : 1; // bit 7 (v6.3.0.10) - SetOption57 - Scan wifi network every 44 minutes for configured AP's + uint32_t receive_raw : 1; // bit 8 (v6.3.0.11) - SetOption58 - Add IR Raw data to JSON message + uint32_t hass_tele_on_power : 1; // bit 9 (v6.3.0.13) - SetOption59 - Send tele/%topic%/STATE in addition to stat/%topic%/RESULT uint32_t sleep_normal : 1; // bit 10 (v6.3.0.15) - SetOption60 - Enable normal sleep instead of dynamic sleep - uint32_t button_switch_force_local : 1;// bit 11 - uint32_t spare12 : 1; + uint32_t button_switch_force_local : 1;// bit 11 (v6.3.0.16) - SetOption61 - Force local operation when button/switch topic is set + uint32_t no_hold_retain : 1; // bit 12 (v6.4.1.19) - SetOption62 - Don't use retain flag on HOLD messages uint32_t spare13 : 1; uint32_t spare14 : 1; uint32_t spare15 : 1; @@ -163,6 +163,20 @@ typedef union { }; } Mcp230xxCfg; +typedef union { + uint8_t data; + struct { + uint8_t spare0 : 1; + uint8_t spare1 : 1; + uint8_t spare2 : 1; + uint8_t spare3 : 1; + uint8_t spare4 : 1; + uint8_t spare5 : 1; + uint8_t spare6 : 1; + uint8_t mhz19b_abc_disable : 1; // Disable ABC (Automatic Baseline Correction for MHZ19(B) (0 = Enabled (default), 1 = Disabled with Sensor15 command) + }; +} SensorCfg1; + /* struct SYSCFG { unsigned long cfg_holder; // 000 Pre v6 header @@ -183,21 +197,21 @@ struct SYSCFG { char ota_url[101]; // 017 char mqtt_prefix[3][11]; // 07C uint8_t baudrate; // 09D - byte seriallog_level; // 09E + uint8_t seriallog_level; // 09E uint8_t sta_config; // 09F - byte sta_active; // 0A0 + uint8_t sta_active; // 0A0 char sta_ssid[2][33]; // 0A1 - Keep together with sta_pwd as being copied as one chunck with reset 4/5 char sta_pwd[2][65]; // 0E3 - Keep together with sta_ssid as being copied as one chunck with reset 4/5 char hostname[33]; // 165 char syslog_host[33]; // 186 uint8_t rule_stop; // 1A7 uint16_t syslog_port; // 1A8 - byte syslog_level; // 1AA + uint8_t syslog_level; // 1AA uint8_t webserver; // 1AB - byte weblog_level; // 1AC + uint8_t weblog_level; // 1AC uint8_t mqtt_fingerprint[2][20]; // 1AD - byte free_1D5[20]; // 1D5 Free since 5.12.0e + uint8_t free_1D5[20]; // 1D5 Free since 5.12.0e char mqtt_host[33]; // 1E9 uint16_t mqtt_port; // 20A @@ -271,6 +285,7 @@ struct SYSCFG { uint8_t ws_color[4][3]; // 475 uint8_t ws_width[3]; // 481 myio my_gp; // 484 + uint8_t test_step; // 495 uint16_t light_pixels; // 496 uint8_t light_color[5]; // 498 uint8_t light_correction; // 49D @@ -281,15 +296,13 @@ struct SYSCFG { uint8_t light_speed; // 4A2 uint8_t light_scheme; // 4A3 uint8_t light_width; // 4A4 - byte knx_GA_registered; // 4A5 Number of Group Address to read + uint8_t knx_GA_registered; // 4A5 Number of Group Address to read uint16_t light_wakeup; // 4A6 - byte knx_CB_registered; // 4A8 Number of Group Address to write + uint8_t knx_CB_registered; // 4A8 Number of Group Address to write char web_password[33]; // 4A9 - - uint8_t ex_switchmode[4]; // 4CA Free since 6.0.0a - + uint8_t interlock[MAX_INTERLOCKS]; // 4CA char ntp_server[3][33]; // 4CE - byte ina219_mode; // 531 + uint8_t ina219_mode; // 531 uint16_t pulse_timer[MAX_PULSETIMERS]; // 532 uint16_t button_debounce; // 542 uint32_t ip_address[4]; // 544 @@ -308,17 +321,17 @@ struct SYSCFG { uint16_t knx_physsical_addr; // 6B8 (address_t is a uint16_t) uint16_t knx_GA_addr[MAX_KNX_GA]; // 6BA (address_t is a uint16_t) x KNX_max_GA uint16_t knx_CB_addr[MAX_KNX_CB]; // 6CE (address_t is a uint16_t) x KNX_max_CB - byte knx_GA_param[MAX_KNX_GA]; // 6E2 Type of Input (relay changed, button pressed, sensor read <-teleperiod) - byte knx_CB_param[MAX_KNX_CB]; // 6EC Type of Output (set relay, toggle relay, reply sensor value) + uint8_t knx_GA_param[MAX_KNX_GA]; // 6E2 Type of Input (relay changed, button pressed, sensor read <-teleperiod) + uint8_t knx_CB_param[MAX_KNX_CB]; // 6EC Type of Output (set relay, toggle relay, reply sensor value) Mcp230xxCfg mcp230xx_config[16]; // 6F6 uint8_t mcp230xx_int_prio; // 716 - - byte free_717[1]; // 717 - + SensorCfg1 SensorBits1; // 717 On/Off settings used by Sensor Commands uint16_t mcp230xx_int_timer; // 718 uint8_t rgbwwTable[5]; // 71A + uint8_t user_template_base; // 71F + mytmplt user_template; // 720 29 bytes - byte free_71F[117]; // 71F + uint8_t free_73D[87]; // 73D uint32_t drivers[3]; // 794 uint32_t monitors; // 7A0 @@ -327,7 +340,7 @@ struct SYSCFG { uint32_t energy_kWhtotal_time; // 7B4 unsigned long weight_item; // 7B8 Weight of one item in gram * 10 - byte free_7BC[2]; // 7BC + uint8_t free_7BC[2]; // 7BC uint16_t weight_max; // 7BE Total max weight in kilogram unsigned long weight_reference; // 7C0 Reference weight in gram @@ -347,7 +360,7 @@ struct RTCRBT { struct RTCMEM { uint16_t valid; // 290 (RTC memory offset 100) - byte oswatch_blocked_loop; // 292 + uint8_t oswatch_blocked_loop; // 292 uint8_t ota_loader; // 293 unsigned long energy_kWhtoday; // 294 unsigned long energy_kWhtotal; // 298 @@ -377,7 +390,7 @@ struct XDRVMAILBOX { uint16_t data_len; uint16_t payload16; int16_t payload; - uint8_t grpflg; + bool grpflg; uint8_t notused; char *topic; char *data; diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 46c1d849d..dff0d849f 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -1,7 +1,7 @@ /* settings.ino - user settings for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -97,7 +97,7 @@ void RtcSettingsLoad(void) RtcSettings.valid = RTC_MEM_VALID; RtcSettings.energy_kWhtoday = Settings.energy_kWhtoday; RtcSettings.energy_kWhtotal = Settings.energy_kWhtotal; - for (byte i = 0; i < MAX_COUNTERS; i++) { + for (uint8_t i = 0; i < MAX_COUNTERS; i++) { RtcSettings.pulse_counter[i] = Settings.pulse_counter[i]; } RtcSettings.power = Settings.power; @@ -106,7 +106,7 @@ void RtcSettingsLoad(void) rtc_settings_crc = GetRtcSettingsCrc(); } -boolean RtcSettingsValid(void) +bool RtcSettingsValid(void) { return (RTC_MEM_VALID == RtcSettings.valid); } @@ -147,7 +147,7 @@ void RtcRebootLoad(void) rtc_reboot_crc = GetRtcRebootCrc(); } -boolean RtcRebootValid(void) +bool RtcRebootValid(void) { return (RTC_MEM_VALID == RtcReboot.valid); } @@ -171,6 +171,139 @@ extern "C" uint32_t _SPIFFS_end; // Version 5.2 allow for more flash space #define CFG_ROTATES 8 // Number of flash sectors used (handles uploads) +/*********************************************************************************************\ + * EEPROM support based on EEPROM library and tuned for Tasmota +\*********************************************************************************************/ + +uint32_t eeprom_sector = SPIFFS_END; +uint8_t* eeprom_data = 0; +size_t eeprom_size = 0; +bool eeprom_dirty = false; + +void EepromBegin(size_t size) +{ + if (size <= 0) { return; } + if (size > SPI_FLASH_SEC_SIZE - sizeof(Settings) -4) { size = SPI_FLASH_SEC_SIZE - sizeof(Settings) -4; } + size = (size + 3) & (~3); + + // In case begin() is called a 2nd+ time, don't reallocate if size is the same + if (eeprom_data && size != eeprom_size) { + delete[] eeprom_data; + eeprom_data = new uint8_t[size]; + } else if (!eeprom_data) { + eeprom_data = new uint8_t[size]; + } + eeprom_size = size; + + size_t flash_offset = SPI_FLASH_SEC_SIZE - eeprom_size; + uint8_t* flash_buffer; + flash_buffer = new uint8_t[SPI_FLASH_SEC_SIZE]; + noInterrupts(); + spi_flash_read(eeprom_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast(flash_buffer), SPI_FLASH_SEC_SIZE); + interrupts(); + memcpy(eeprom_data, flash_buffer + flash_offset, eeprom_size); + delete[] flash_buffer; + + eeprom_dirty = false; // make sure dirty is cleared in case begin() is called 2nd+ time +} + +size_t EepromLength(void) +{ + return eeprom_size; +} + +uint8_t EepromRead(int const address) +{ + if (address < 0 || (size_t)address >= eeprom_size) { return 0; } + if (!eeprom_data) { return 0; } + + return eeprom_data[address]; +} + +// Prototype needed for Arduino IDE - https://forum.arduino.cc/index.php?topic=406509.0 +template T EepromGet(int const address, T &t); +template T EepromGet(int const address, T &t) +{ + if (address < 0 || address + sizeof(T) > eeprom_size) { return t; } + if (!eeprom_data) { return 0; } + + memcpy((uint8_t*) &t, eeprom_data + address, sizeof(T)); + return t; +} + +void EepromWrite(int const address, uint8_t const value) +{ + if (address < 0 || (size_t)address >= eeprom_size) { return; } + if (!eeprom_data) { return; } + + // Optimise eeprom_dirty. Only flagged if data written is different. + uint8_t* pData = &eeprom_data[address]; + if (*pData != value) { + *pData = value; + eeprom_dirty = true; + } +} + +// Prototype needed for Arduino IDE - https://forum.arduino.cc/index.php?topic=406509.0 +template void EepromPut(int const address, const T &t); +template void EepromPut(int const address, const T &t) +{ + if (address < 0 || address + sizeof(T) > eeprom_size) { return; } + if (!eeprom_data) { return; } + + // Optimise eeprom_dirty. Only flagged if data written is different. + if (memcmp(eeprom_data + address, (const uint8_t*)&t, sizeof(T)) != 0) { + eeprom_dirty = true; + memcpy(eeprom_data + address, (const uint8_t*)&t, sizeof(T)); + } +} + +bool EepromCommit(void) +{ + bool ret = false; + if (!eeprom_size) { return false; } + if (!eeprom_dirty) { return true; } + if (!eeprom_data) { return false; } + + size_t flash_offset = SPI_FLASH_SEC_SIZE - eeprom_size; + uint8_t* flash_buffer; + flash_buffer = new uint8_t[SPI_FLASH_SEC_SIZE]; + noInterrupts(); + spi_flash_read(eeprom_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast(flash_buffer), SPI_FLASH_SEC_SIZE); + memcpy(flash_buffer + flash_offset, eeprom_data, eeprom_size); + if (spi_flash_erase_sector(eeprom_sector) == SPI_FLASH_RESULT_OK) { + if (spi_flash_write(eeprom_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast(flash_buffer), SPI_FLASH_SEC_SIZE) == SPI_FLASH_RESULT_OK) { + eeprom_dirty = false; + ret = true; + } + } + interrupts(); + delete[] flash_buffer; + + return ret; +} + +uint8_t * EepromGetDataPtr() +{ + eeprom_dirty = true; + return &eeprom_data[0]; +} + +void EepromEnd(void) +{ + if (!eeprom_size) { return; } + + EepromCommit(); + if (eeprom_data) { + delete[] eeprom_data; + } + eeprom_data = 0; + eeprom_size = 0; + eeprom_dirty = false; +} + +/********************************************************************************************/ + uint16_t settings_crc = 0; uint32_t settings_location = SETTINGS_LOCATION; uint8_t *settings_buffer = NULL; @@ -235,6 +368,7 @@ void SettingsSaveAll(void) Settings.power = 0; } XsnsCall(FUNC_SAVE_BEFORE_RESTART); + EepromCommit(); SettingsSave(0); } @@ -247,7 +381,7 @@ uint32_t GetSettingsAddress(void) return settings_location * SPI_FLASH_SEC_SIZE; } -void SettingsSave(byte rotate) +void SettingsSave(uint8_t rotate) { /* Save configuration in eeprom or one of 7 slots below * @@ -257,7 +391,7 @@ void SettingsSave(byte rotate) * stop_flash_rotate 0 = Allow flash slot rotation (SetOption12 0) * stop_flash_rotate 1 = Allow only eeprom flash slot use (SetOption12 1) */ -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL if ((GetSettingsCrc() != settings_crc) || rotate) { if (1 == rotate) { // Use eeprom flash slot only and disable flash rotate from now on (upgrade) stop_flash_rotate = 1; @@ -276,53 +410,86 @@ void SettingsSave(byte rotate) Settings.save_flag++; Settings.cfg_size = sizeof(SYSCFG); Settings.cfg_crc = GetSettingsCrc(); - ESP.flashEraseSector(settings_location); - ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG)); + + if (SPIFFS_END == settings_location) { + uint8_t* flash_buffer; + flash_buffer = new uint8_t[SPI_FLASH_SEC_SIZE]; + if (eeprom_data && eeprom_size) { + size_t flash_offset = SPI_FLASH_SEC_SIZE - eeprom_size; + memcpy(flash_buffer + flash_offset, eeprom_data, eeprom_size); // Write dirty EEPROM data + } else { + ESP.flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)flash_buffer, SPI_FLASH_SEC_SIZE); // Read EEPROM area + } + memcpy(flash_buffer, &Settings, sizeof(Settings)); + ESP.flashEraseSector(settings_location); + ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)flash_buffer, SPI_FLASH_SEC_SIZE); + delete[] flash_buffer; + } else { + ESP.flashEraseSector(settings_location); + ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG)); + } + if (!stop_flash_rotate && rotate) { - for (byte i = 1; i < CFG_ROTATES; i++) { + for (uint8_t i = 1; i < CFG_ROTATES; i++) { ESP.flashEraseSector(settings_location -i); // Delete previous configurations by resetting to 0xFF delay(1); } } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_CONFIG D_SAVED_TO_FLASH_AT " %X, " D_COUNT " %d, " D_BYTES " %d"), - settings_location, Settings.save_flag, sizeof(SYSCFG)); - AddLog(LOG_LEVEL_DEBUG); + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG D_SAVED_TO_FLASH_AT " %X, " D_COUNT " %d, " D_BYTES " %d"), settings_location, Settings.save_flag, sizeof(SYSCFG)); settings_crc = Settings.cfg_crc; } -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL RtcSettingsSave(); } void SettingsLoad(void) { -/* Load configuration from eeprom or one of 7 slots below if first load does not stop_flash_rotate - */ + // Load configuration from eeprom or one of 7 slots below if first valid load does not stop_flash_rotate struct SYSCFGH { uint16_t cfg_holder; // 000 uint16_t cfg_size; // 002 unsigned long save_flag; // 004 } _SettingsH; + unsigned long save_flag = 0; - bool bad_crc = false; - settings_location = SETTINGS_LOCATION +1; - for (byte i = 0; i < CFG_ROTATES; i++) { - settings_location--; - ESP.flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG)); - ESP.flashRead((settings_location -1) * SPI_FLASH_SEC_SIZE, (uint32*)&_SettingsH, sizeof(SYSCFGH)); - if (Settings.version > 0x06000000) { bad_crc = (Settings.cfg_crc != GetSettingsCrc()); } - if (Settings.flag.stop_flash_rotate || bad_crc || (Settings.cfg_holder != _SettingsH.cfg_holder) || (Settings.save_flag > _SettingsH.save_flag)) { - break; + settings_location = 0; + uint32_t flash_location = SETTINGS_LOCATION +1; + 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()); + } else { + ESP.flashRead((flash_location -1) * SPI_FLASH_SEC_SIZE, (uint32*)&_SettingsH, sizeof(SYSCFGH)); + valid = (Settings.cfg_holder == _SettingsH.cfg_holder); } + if (valid) { + if (Settings.save_flag > save_flag) { + save_flag = Settings.save_flag; + settings_location = flash_location; + if (Settings.flag.stop_flash_rotate && (0 == i)) { // Stop only if eeprom area should be used and it is valid + break; + } + } + } + delay(1); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_CONFIG D_LOADED_FROM_FLASH_AT " %X, " D_COUNT " %d"), settings_location, Settings.save_flag); - AddLog(LOG_LEVEL_DEBUG); + 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); + } -#ifndef BE_MINIMAL - if (bad_crc || (Settings.cfg_holder != (uint16_t)CFG_HOLDER)) { SettingsDefault(); } +#ifndef FIRMWARE_MINIMAL + if (!settings_location || (Settings.cfg_holder != (uint16_t)CFG_HOLDER)) { // Init defaults if cfg_holder differs from user settings in my_user_config.h + SettingsDefault(); + } settings_crc = GetSettingsCrc(); -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL RtcSettingsLoad(); } @@ -334,7 +501,7 @@ void SettingsErase(uint8_t type) 1 = Erase SDK parameter area at end of linker memory model (0x0FDxxx - 0x0FFFFF) solving possible wifi errors */ -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL bool result; uint32_t _sectorStart = (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 1; @@ -344,10 +511,9 @@ void SettingsErase(uint8_t type) _sectorEnd = SETTINGS_LOCATION +5; } - boolean _serialoutput = (LOG_LEVEL_DEBUG_MORE <= seriallog_level); + bool _serialoutput = (LOG_LEVEL_DEBUG_MORE <= seriallog_level); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_ERASE " %d " D_UNIT_SECTORS), _sectorEnd - _sectorStart); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " %d " D_UNIT_SECTORS), _sectorEnd - _sectorStart); for (uint32_t _sector = _sectorStart; _sector < _sectorEnd; _sector++) { result = ESP.flashEraseSector(_sector); @@ -363,7 +529,7 @@ void SettingsErase(uint8_t type) } OsWatchLoop(); } -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL } // Copied from 2.4.0 as 2.3.0 is incomplete @@ -416,6 +582,8 @@ void SettingsDefaultSet2(void) // Settings.flag.value_units = 0; // Settings.flag.stop_flash_rotate = 0; Settings.save_data = SAVE_DATA; + Settings.param[P_BOOT_LOOP_OFFSET] = BOOT_LOOP_OFFSET; + Settings.param[P_RGB_REMAP] = RGB_REMAP_RGBW; Settings.sleep = APP_SLEEP; if (Settings.sleep < 50) { Settings.sleep = 50; // Default to 50 for sleep, for now @@ -423,8 +591,10 @@ void SettingsDefaultSet2(void) // Module // Settings.flag.interlock = 0; + Settings.interlock[0] = 0xFF; // Legacy support using all relays in one interlock group Settings.module = MODULE; -// for (byte i = 0; i < MAX_GPIO_PIN; i++) { Settings.my_gp.io[i] = 0; } + ModuleDefault(WEMOS); +// for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { Settings.my_gp.io[i] = GPIO_NONE; } strlcpy(Settings.friendlyname[0], FRIENDLY_NAME, sizeof(Settings.friendlyname[0])); strlcpy(Settings.friendlyname[1], FRIENDLY_NAME"2", sizeof(Settings.friendlyname[1])); strlcpy(Settings.friendlyname[2], FRIENDLY_NAME"3", sizeof(Settings.friendlyname[2])); @@ -439,7 +609,7 @@ void SettingsDefaultSet2(void) Settings.blinkcount = APP_BLINKCOUNT; Settings.ledstate = APP_LEDSTATE; Settings.pulse_timer[0] = APP_PULSETIME; -// for (byte i = 1; i < MAX_PULSETIMERS; i++) { Settings.pulse_timer[i] = 0; } +// for (uint8_t i = 1; i < MAX_PULSETIMERS; i++) { Settings.pulse_timer[i] = 0; } // Serial Settings.baudrate = APP_BAUDRATE / 1200; @@ -470,6 +640,7 @@ void SettingsDefaultSet2(void) Settings.webserver = WEB_SERVER; Settings.weblog_level = WEB_LOG_LEVEL; strlcpy(Settings.web_password, WEB_PASSWORD, sizeof(Settings.web_password)); + Settings.flag3.mdns_enabled = MDNS_ENABLED; // Button // Settings.flag.button_restrict = 0; @@ -478,7 +649,7 @@ void SettingsDefaultSet2(void) Settings.param[P_HOLD_TIME] = KEY_HOLD_TIME; // Default 4 seconds hold time // Switch - for (byte i = 0; i < MAX_SWITCHES; i++) { Settings.switchmode[i] = SWITCH_MODE; } + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { Settings.switchmode[i] = SWITCH_MODE; } // MQTT Settings.flag.mqtt_enabled = MQTT_USE; @@ -487,6 +658,7 @@ void SettingsDefaultSet2(void) Settings.flag.mqtt_button_retain = MQTT_BUTTON_RETAIN; Settings.flag.mqtt_switch_retain = MQTT_SWITCH_RETAIN; Settings.flag3.button_switch_force_local = MQTT_BUTTON_SWITCH_FORCE_LOCAL; + Settings.flag3.hass_tele_on_power = TELE_ON_POWER; // Settings.flag.mqtt_sensor_retain = 0; // Settings.flag.mqtt_offline = 0; // Settings.flag.mqtt_serial = 0; @@ -512,12 +684,12 @@ void SettingsDefaultSet2(void) char fingerprint[60]; strlcpy(fingerprint, MQTT_FINGERPRINT1, sizeof(fingerprint)); char *p = fingerprint; - for (byte i = 0; i < 20; i++) { + for (uint8_t i = 0; i < 20; i++) { Settings.mqtt_fingerprint[0][i] = strtol(p, &p, 16); } strlcpy(fingerprint, MQTT_FINGERPRINT2, sizeof(fingerprint)); p = fingerprint; - for (byte i = 0; i < 20; i++) { + for (uint8_t i = 0; i < 20; i++) { Settings.mqtt_fingerprint[1][i] = strtol(p, &p, 16); } Settings.tele_period = TELE_PERIOD; @@ -553,17 +725,17 @@ void SettingsDefaultSet2(void) RtcSettings.energy_kWhtotal = 0; // RF Bridge -// for (byte i = 0; i < 17; i++) { Settings.rf_code[i][0] = 0; } +// for (uint8_t i = 0; i < 17; i++) { Settings.rf_code[i][0] = 0; } memcpy_P(Settings.rf_code[0], kDefaultRfCode, 9); // Domoticz Settings.domoticz_update_timer = DOMOTICZ_UPDATE_TIMER; -// for (byte i = 0; i < MAX_DOMOTICZ_IDX; i++) { +// for (uint8_t i = 0; i < MAX_DOMOTICZ_IDX; i++) { // Settings.domoticz_relay_idx[i] = 0; // Settings.domoticz_key_idx[i] = 0; // Settings.domoticz_switch_idx[i] = 0; // } -// for (byte i = 0; i < MAX_DOMOTICZ_SNS_IDX; i++) { +// for (uint8_t i = 0; i < MAX_DOMOTICZ_SNS_IDX; i++) { // Settings.domoticz_sensor_idx[i] = 0; // } @@ -578,7 +750,7 @@ void SettingsDefaultSet2(void) // Rules // Settings.rule_enabled = 0; // Settings.rule_once = 0; -// for (byte i = 1; i < MAX_RULE_SETS; i++) { Settings.rules[i][0] = '\0'; } +// for (uint8_t i = 1; i < MAX_RULE_SETS; i++) { Settings.rules[i][0] = '\0'; } Settings.flag2.calc_resolution = CALC_RESOLUTION; // Home Assistant @@ -596,7 +768,7 @@ void SettingsDefaultSet2(void) //Settings.flag.decimal_text = 0; Settings.pwm_frequency = PWM_FREQ; Settings.pwm_range = PWM_RANGE; - for (byte i = 0; i < MAX_PWMS; i++) { + for (uint8_t i = 0; i < MAX_PWMS; i++) { Settings.light_color[i] = 255; // Settings.pwm_value[i] = 0; } @@ -625,8 +797,8 @@ void SettingsDefaultSet2(void) strlcpy(Settings.ntp_server[0], NTP_SERVER1, sizeof(Settings.ntp_server[0])); strlcpy(Settings.ntp_server[1], NTP_SERVER2, sizeof(Settings.ntp_server[1])); strlcpy(Settings.ntp_server[2], NTP_SERVER3, sizeof(Settings.ntp_server[2])); - for (byte j = 0; j < 3; j++) { - for (byte i = 0; i < strlen(Settings.ntp_server[j]); i++) { + for (uint8_t j = 0; j < 3; j++) { + for (uint8_t i = 0; i < strlen(Settings.ntp_server[j]); i++) { if (Settings.ntp_server[j][i] == ',') { Settings.ntp_server[j][i] = '.'; } @@ -639,7 +811,7 @@ void SettingsDefaultSet2(void) Settings.button_debounce = KEY_DEBOUNCE_TIME; Settings.switch_debounce = SWITCH_DEBOUNCE_TIME; - for (byte j = 0; j < 5; j++) { + for (uint8_t j = 0; j < 5; j++) { Settings.rgbwwTable[j] = 255; } @@ -720,7 +892,7 @@ void SettingsDelta(void) if (Settings.version != VERSION) { // Fix version dependent changes if (Settings.version < 0x05050000) { - for (byte i = 0; i < 17; i++) { Settings.rf_code[i][0] = 0; } + for (uint8_t i = 0; i < 17; i++) { Settings.rf_code[i][0] = 0; } memcpy_P(Settings.rf_code[0], kDefaultRfCode, 9); } if (Settings.version < 0x05080000) { @@ -742,12 +914,12 @@ void SettingsDelta(void) Settings.altitude = 0; } if (Settings.version < 0x0508000B) { - for (byte i = 0; i < MAX_GPIO_PIN; i++) { // Move GPIO_LEDs + for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { // Move GPIO_LEDs if ((Settings.my_gp.io[i] >= 25) && (Settings.my_gp.io[i] <= 32)) { // Was GPIO_LED1 Settings.my_gp.io[i] += 23; // Move GPIO_LED1 } } - for (byte i = 0; i < MAX_PWMS; i++) { // Move pwm_value and reset additional pulse_timerrs + for (uint8_t i = 0; i < MAX_PWMS; i++) { // Move pwm_value and reset additional pulse_timerrs Settings.pwm_value[i] = Settings.pulse_timer[4 +i]; Settings.pulse_timer[4 +i] = 0; } @@ -778,7 +950,7 @@ void SettingsDelta(void) char fingerprint[60]; memcpy(fingerprint, Settings.mqtt_fingerprint, sizeof(fingerprint)); char *p = fingerprint; - for (byte i = 0; i < 20; i++) { + for (uint8_t i = 0; i < 20; i++) { Settings.mqtt_fingerprint[0][i] = strtol(p, &p, 16); Settings.mqtt_fingerprint[1][i] = Settings.mqtt_fingerprint[0][i]; } @@ -813,7 +985,7 @@ void SettingsDelta(void) SettingsDefaultSet_5_13_1c(); } if (Settings.version < 0x050E0002) { - for (byte i = 1; i < MAX_RULE_SETS; i++) { Settings.rules[i][0] = '\0'; } + for (uint8_t i = 1; i < MAX_RULE_SETS; i++) { Settings.rules[i][0] = '\0'; } Settings.rule_enabled = Settings.flag.mqtt_serial_raw; // Was rules_enabled until 5.14.0b Settings.rule_once = Settings.flag.pressure_conversion; // Was rules_once until 5.14.0b } @@ -822,14 +994,14 @@ void SettingsDelta(void) Settings.cfg_crc = GetSettingsCrc(); } if (Settings.version < 0x06000002) { - for (byte i = 0; i < MAX_SWITCHES; i++) { + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { if (i < 4) { - Settings.switchmode[i] = Settings.ex_switchmode[i]; + Settings.switchmode[i] = Settings.interlock[i]; } else { Settings.switchmode[i] = SWITCH_MODE; } } - for (byte i = 0; i < MAX_GPIO_PIN; i++) { + for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { if (Settings.my_gp.io[i] >= GPIO_SWT5) { // Move up from GPIO_SWT5 to GPIO_KEY1 Settings.my_gp.io[i] += 4; } @@ -848,7 +1020,7 @@ void SettingsDelta(void) Settings.switch_debounce = SWITCH_DEBOUNCE_TIME; } if (Settings.version < 0x0602010A) { - for (byte j = 0; j < 5; j++) { + for (uint8_t j = 0; j < 5; j++) { Settings.rgbwwTable[j] = 255; } } @@ -866,6 +1038,23 @@ void SettingsDelta(void) Settings.sleep = 50; // Default to 50 for sleep, for now } } + if (Settings.version < 0x06040105) { + Settings.flag3.mdns_enabled = MDNS_ENABLED; + Settings.param[P_MDNS_DELAYED_START] = 0; + } + if (Settings.version < 0x0604010B) { + Settings.interlock[0] = 0xFF; // Legacy support using all relays in one interlock group + for (uint8_t i = 1; i < MAX_INTERLOCKS; i++) { Settings.interlock[i] = 0; } + } + if (Settings.version < 0x0604010D) { + Settings.param[P_BOOT_LOOP_OFFSET] = BOOT_LOOP_OFFSET; + } + if (Settings.version < 0x06040110) { + ModuleDefault(WEMOS); + } + if (Settings.version < 0x06040113) { + Settings.param[P_RGB_REMAP] = RGB_REMAP_RGBW; + } Settings.version = VERSION; SettingsSave(1); diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 7c2de21e6..6c44f54fd 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -1,7 +1,7 @@ /* sonoff.h - Master header file for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -51,6 +51,7 @@ typedef unsigned long power_t; // Power (Relay) type // 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 @@ -103,6 +104,7 @@ typedef unsigned long power_t; // Power (Relay) type #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 @@ -167,6 +169,15 @@ typedef unsigned long power_t; // Power (Relay) type #define NEO_RGBW 5 // Neopixel RGBW leds #define NEO_GRBW 6 // Neopixel GRBW leds +#define LT_SM16716 16 // Lights that use SM16716 will have this bit set in light_type + +#define RGB_REMAP_RGBW 0 +#define RGB_REMAP_RBGW 6 +#define RGB_REMAP_GRBW 24 +#define RGB_REMAP_GBRW 30 +#define RGB_REMAP_BRGW 48 +#define RGB_REMAP_BGRW 54 + #define MQTT_PUBSUBCLIENT 1 // Mqtt PubSubClient library #define MQTT_TASMOTAMQTT 2 // Mqtt TasmotaMqtt library based on esp-mqtt-arduino - soon obsolete #define MQTT_ESPMQTTARDUINO 3 // Mqtt esp-mqtt-arduino library by Ingo Randolf - obsolete but define is present for debugging purposes @@ -208,7 +219,7 @@ enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_RESTART, DT_ENERGY }; enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; -enum WifiConfigOptions {WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL, MAX_WIFI_OPTION}; +enum WifiConfigOptions {WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL, WIFI_MANAGER_RESET_ONLY, MAX_WIFI_OPTION}; enum SwitchModeOptions {TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, MAX_SWITCH_OPTION}; @@ -226,7 +237,7 @@ enum ButtonStates { PRESSED, NOT_PRESSED }; enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER }; -enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_MAX_PARAM8}; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49 +enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_MAX_PARAM8}; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49 enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_MAX_SENSORS}; @@ -241,7 +252,7 @@ enum LightSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MA enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, - FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART, FUNC_COMMAND, + FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR, FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_BUTTON_PRESSED, @@ -260,5 +271,7 @@ const uint8_t kIFan02Speed[MAX_FAN_SPEED][3] = {{6,6,6}, {7,6,6}, {7,7,6}, {7,6, \*********************************************************************************************/ extern uint8_t light_device; // Light device number +extern uint8_t light_power; // Light power +extern uint8_t rotary_changed; // Rotary switch changed #endif // _SONOFF_H_ diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index be5964a94..82c306c90 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -1,7 +1,7 @@ /* sonoff.ino - Sonoff-Tasmota firmware for iTead Sonoff, Wemos and NodeMCU hardware - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -75,7 +75,7 @@ enum TasmotaCommands { CMND_MODULE, CMND_MODULES, CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE, CMND_COUNTERDEBOUNCE, CMND_BUTTONDEBOUNCE, CMND_SWITCHDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG, CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME, - CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, + CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, CMND_INTERLOCK, CMND_TEMPLATE, CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_TIMESTD, CMND_TIMEDST, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE, CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_SERIALDELIMITER, CMND_DRIVER }; const char kTasmotaCommands[] PROGMEM = @@ -85,7 +85,7 @@ const char kTasmotaCommands[] PROGMEM = D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" D_CMND_COUNTER "|" D_CMND_COUNTERTYPE "|" D_CMND_COUNTERDEBOUNCE "|" D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|" D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" - D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" + D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TEMPLATE "|" D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER "|" D_CMND_DRIVER; @@ -108,8 +108,6 @@ unsigned long state_250msecond = 0; // State 250msecond timer unsigned long pulse_timer[MAX_PULSETIMERS] = { 0 }; // Power off timer unsigned long blink_timer = 0; // Power cycle timer unsigned long backlog_delay = 0; // Command backlog delay -unsigned long button_debounce = 0; // Button debounce timer -unsigned long switch_debounce = 0; // Switch debounce timer power_t power = 0; // Current copy of Settings.power power_t blink_power; // Blink power state power_t blink_mask = 0; // Blink relay active mask @@ -130,57 +128,48 @@ uint32_t global_update = 0; // Timestamp of last global temperat float global_temperature = 0; // Provide a global temperature to be used by some sensors float global_humidity = 0; // Provide a global humidity to be used by some sensors char *ota_url; // OTA url string pointer -uint16_t dual_button_code = 0; // Sonoff dual received code uint16_t mqtt_cmnd_publish = 0; // ignore flag for publish command uint16_t blink_counter = 0; // Number of blink cycles uint16_t seriallog_timer = 0; // Timer to disable Seriallog uint16_t syslog_timer = 0; // Timer to re-enable syslog_level -uint16_t holdbutton[MAX_KEYS] = { 0 }; // Timer for button hold -uint16_t switch_no_pullup = 0; // Switch pull-up bitmask flags int16_t save_data_counter; // Counter and flag for config save to Flash RulesBitfield rules_flag; // Rule state flags (16 bits) -uint8_t serial_local = 0; // Handle serial locally; -uint8_t fallback_topic_flag = 0; // Use Topic or FallbackTopic uint8_t state_250mS = 0; // State 250msecond per second flag uint8_t latching_relay_pulse = 0; // Latching relay pulse timer uint8_t backlog_index = 0; // Command backlog index uint8_t backlog_pointer = 0; // Command backlog pointer -uint8_t backlog_mutex = 0; // Command backlog pending -uint8_t interlock_mutex = 0; // Interlock power command pending uint8_t sleep; // Current copy of Settings.sleep -uint8_t stop_flash_rotate = 0; // Allow flash configuration rotation -uint8_t blinkstate = 0; // LED state uint8_t blinkspeed = 1; // LED blink rate -uint8_t lastbutton[MAX_KEYS] = { NOT_PRESSED, NOT_PRESSED, NOT_PRESSED, NOT_PRESSED }; // Last button states -uint8_t multiwindow[MAX_KEYS] = { 0 }; // Max time between button presses to record press count -uint8_t multipress[MAX_KEYS] = { 0 }; // Number of button presses within multiwindow -uint8_t lastwallswitch[MAX_SWITCHES]; // Last wall switch states -uint8_t holdwallswitch[MAX_SWITCHES] = { 0 }; // Timer for wallswitch push button hold -uint8_t virtualswitch[MAX_SWITCHES]; // Virtual switch states uint8_t pin[GPIO_MAX]; // Possible pin configurations uint8_t led_inverted = 0; // LED inverted flag (1 = (0 = On, 1 = Off)) uint8_t pwm_inverted = 0; // PWM inverted flag (1 = inverted) uint8_t counter_no_pullup = 0; // Counter input pullup flag (1 = No pullup) -uint8_t dht_flg = 0; // DHT configured uint8_t energy_flg = 0; // Energy monitor configured -uint8_t i2c_flg = 0; // I2C configured -uint8_t spi_flg = 0; // SPI configured -uint8_t soft_spi_flg = 0; // Software SPI configured uint8_t light_type = 0; // Light types -uint8_t ntp_force_sync = 0; // Force NTP sync -byte serial_in_byte; // Received byte -byte dual_hex_code = 0; // Sonoff dual input flag -byte ota_retry_counter = OTA_ATTEMPTS; // OTA retry counter -byte web_log_index = 1; // Index in Web log buffer (should never be 0) -byte reset_web_log_flag = 0; // Reset web console log -byte devices_present = 0; // Max number of devices supported -byte seriallog_level; // Current copy of Settings.seriallog_level -byte syslog_level; // Current copy of Settings.syslog_level -byte mdns_delayed_start = 0; // mDNS delayed start -boolean latest_uptime_flag = true; // Signal latest uptime -boolean pwm_present = false; // Any PWM channel configured with SetOption15 0 -boolean mdns_begun = false; // mDNS active -mytmplt my_module; // Active copy of Module name and GPIOs (23 x 8 bits) +uint8_t serial_in_byte; // Received byte +uint8_t ota_retry_counter = OTA_ATTEMPTS; // OTA retry counter +uint8_t web_log_index = 1; // Index in Web log buffer (should never be 0) +uint8_t devices_present = 0; // Max number of devices supported +uint8_t seriallog_level; // Current copy of Settings.seriallog_level +uint8_t syslog_level; // Current copy of Settings.syslog_level +uint8_t my_module_type; // Current copy of Settings.module or user template type +//uint8_t mdns_delayed_start = 0; // mDNS delayed start +bool serial_local = false; // Handle serial locally; +bool fallback_topic_flag = false; // Use Topic or FallbackTopic +bool backlog_mutex = false; // Command backlog pending +bool interlock_mutex = false; // Interlock power command pending +bool stop_flash_rotate = false; // Allow flash configuration rotation +bool blinkstate = false; // LED state +bool latest_uptime_flag = true; // Signal latest uptime +bool pwm_present = false; // Any PWM channel configured with SetOption15 0 +bool dht_flg = false; // DHT configured +bool i2c_flg = false; // I2C configured +bool spi_flg = false; // SPI configured +bool soft_spi_flg = false; // Software SPI configured +bool ntp_force_sync = false; // Force NTP sync +bool reset_web_log_flag = false; // Reset web console log +myio my_module; // Active copy of Module GPIOs (17 x 8 bits) +gpio_flag my_module_flag; // Active copy of Module GPIO flags StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits) char my_version[33]; // Composed version string char my_image[33]; // Code image and/or commit @@ -193,7 +182,6 @@ char log_data[LOGSZ]; // Logging char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer String backlog[MAX_BACKLOG]; // Command backlog - /********************************************************************************************/ char* Format(char* output, const char* input, int size) @@ -212,12 +200,13 @@ char* Format(char* output, const char* input, int size) if (token != NULL) { digits = atoi(token); if (digits) { + char tmp[size]; if (strchr(token, 'd')) { - snprintf_P(output, size, PSTR("%s%c0%dd"), output, '%', digits); - snprintf_P(output, size, output, ESP.getChipId() & 0x1fff); // %04d - short chip ID in dec, like in hostname + snprintf_P(tmp, size, PSTR("%s%c0%dd"), output, '%', digits); + snprintf_P(output, size, tmp, ESP.getChipId() & 0x1fff); // %04d - short chip ID in dec, like in hostname } else { - snprintf_P(output, size, PSTR("%s%c0%dX"), output, '%', digits); - snprintf_P(output, size, output, ESP.getChipId()); // %06X - full chip ID in hex + snprintf_P(tmp, size, PSTR("%s%c0%dX"), output, '%', digits); + snprintf_P(output, size, tmp, ESP.getChipId()); // %06X - full chip ID in hex } } else { if (strchr(token, 'd')) { @@ -227,7 +216,7 @@ char* Format(char* output, const char* input, int size) } } } - if (!digits) strlcpy(output, input, size); + if (!digits) { strlcpy(output, input, size); } return output; } @@ -240,12 +229,12 @@ char* GetOtaUrl(char *otaurl, size_t otaurl_size) snprintf_P(otaurl, otaurl_size, Settings.ota_url, ESP.getChipId()); } else { - snprintf(otaurl, otaurl_size, Settings.ota_url); + strlcpy(otaurl, Settings.ota_url, otaurl_size); } return otaurl; } -char* GetTopic_P(char *stopic, byte prefix, char *topic, const char* subtopic) +char* GetTopic_P(char *stopic, uint8_t prefix, char *topic, const char* subtopic) { /* prefix 0 = Cmnd prefix 1 = Stat @@ -269,7 +258,7 @@ char* GetTopic_P(char *stopic, byte prefix, char *topic, const char* subtopic) if ((0 == prefix) && (-1 == fulltopic.indexOf(F(MQTT_TOKEN_PREFIX)))) { fulltopic += F("/" MQTT_TOKEN_PREFIX); // Need prefix for commands to handle mqtt topic loops } - for (byte i = 0; i < 3; i++) { + for (uint8_t i = 0; i < 3; i++) { if ('\0' == Settings.mqtt_prefix[i][0]) { snprintf_P(Settings.mqtt_prefix[i], sizeof(Settings.mqtt_prefix[i]), kPrefixes[i]); } @@ -288,14 +277,14 @@ char* GetTopic_P(char *stopic, byte prefix, char *topic, const char* subtopic) return stopic; } -char* GetFallbackTopic_P(char *stopic, byte prefix, const char* subtopic) +char* GetFallbackTopic_P(char *stopic, uint8_t prefix, const char* subtopic) { return GetTopic_P(stopic, prefix +4, NULL, subtopic); } -char* GetStateText(byte state) +char* GetStateText(uint8_t state) { - if (state > 3) state = 1; + if (state > 3) { state = 1; } return Settings.state_text[state]; } @@ -313,7 +302,7 @@ void SetLatchingRelay(power_t lpower, uint8_t state) latching_relay_pulse = 2; // max 200mS (initiated by stateloop()) } - for (byte i = 0; i < devices_present; i++) { + for (uint8_t i = 0; i < devices_present; i++) { uint8_t port = (i << 1) + ((latching_power >> i) &1); if (pin[GPIO_REL1 +port] < 99) { digitalWrite(pin[GPIO_REL1 +port], bitRead(rel_inverted, port) ? !state : state); @@ -331,16 +320,20 @@ void SetDevicePower(power_t rpower, int source) power = (1 << devices_present) -1; rpower = power; } - if (Settings.flag.interlock) { // Allow only one or no relay set - power_t mask = 1; - uint8_t count = 0; - for (byte i = 0; i < devices_present; i++) { - if (rpower & mask) count++; - mask <<= 1; - } - if (count > 1) { - power = 0; - rpower = 0; + + if (Settings.flag.interlock) { // Allow only one or no relay set + for (uint8_t i = 0; i < MAX_INTERLOCKS; i++) { + power_t mask = 1; + uint8_t count = 0; + for (uint8_t j = 0; j < devices_present; j++) { + if ((Settings.interlock[i] & mask) && (rpower & mask)) { count++; } + mask <<= 1; + } + if (count > 1) { + mask = ~Settings.interlock[i]; // Turn interlocked group off as there would be multiple relays on + power &= mask; + rpower &= mask; + } } } @@ -352,7 +345,7 @@ void SetDevicePower(power_t rpower, int source) if (XdrvCall(FUNC_SET_DEVICE_POWER)) { // Set power state and stop if serviced // Serviced } - else if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) { + else if ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { Serial.write(0xA0); Serial.write(0x04); Serial.write(rpower &0xFF); @@ -360,11 +353,11 @@ void SetDevicePower(power_t rpower, int source) Serial.write('\n'); Serial.flush(); } - else if (EXS_RELAY == Settings.module) { + else if (EXS_RELAY == my_module_type) { SetLatchingRelay(rpower, 1); } else { - for (byte i = 0; i < devices_present; i++) { + for (uint8_t i = 0; i < devices_present; i++) { state = rpower &1; if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) { digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? !state : state); @@ -376,7 +369,16 @@ void SetDevicePower(power_t rpower, int source) void SetLedPower(uint8_t state) { - if (state) state = 1; + if (state) { state = 1; } + + uint8_t led_pin = 0; + if (pin[GPIO_LED2] < 99) { led_pin = 1; } + digitalWrite(pin[GPIO_LED1 + led_pin], (bitRead(led_inverted, led_pin)) ? !state : state); +} + +void SetLedLink(uint8_t state) +{ + if (state) { state = 1; } digitalWrite(pin[GPIO_LED1], (bitRead(led_inverted, 0)) ? !state : state); } @@ -384,7 +386,7 @@ uint8_t GetFanspeed(void) { uint8_t fanspeed = 0; -// if (SONOFF_IFAN02 == Settings.module) { +// if (SONOFF_IFAN02 == my_module_type) { /* Fanspeed is controlled by relay 2, 3 and 4 as in Sonoff 4CH. 000x = 0 001x = 1 @@ -399,7 +401,7 @@ uint8_t GetFanspeed(void) void SetFanspeed(uint8_t fanspeed) { - for (byte i = 0; i < MAX_FAN_SPEED -1; i++) { + for (uint8_t i = 0; i < MAX_FAN_SPEED -1; i++) { uint8_t state = kIFan02Speed[fanspeed][i]; // uint8_t state = pgm_read_byte(kIFan02Speed +(speed *3) +i); ExecuteCommandPower(i +2, state, SRC_IGNORE); // Use relay 2, 3 and 4 @@ -428,8 +430,10 @@ uint16_t GetPulseTimer(uint8_t index) /********************************************************************************************/ -void MqttDataHandler(char* topic, byte* data, unsigned int data_len) +void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) { + if (data_len > MQTT_MAX_PACKET_SIZE) { return; } // Do not allow more data than would be feasable within stack space + char *str; if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1])) { @@ -450,19 +454,21 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) char stemp1[TOPSZ]; char *p; char *type = NULL; - byte jsflg = 0; - byte lines = 1; - uint8_t grpflg = 0; -// uint8_t user_append_index = 0; + uint8_t lines = 1; + bool jsflg = false; + bool grpflg = false; +// bool user_append_index = false; uint16_t i = 0; uint16_t index; uint32_t address; +#ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("MqttDataHandler")); +#endif strlcpy(topicBuf, topic, sizeof(topicBuf)); for (i = 0; i < data_len; i++) { - if (!isspace(data[i])) break; + if (!isspace(data[i])) { break; } } data_len -= i; memcpy(dataBuf, data +i, sizeof(dataBuf)); @@ -470,12 +476,10 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) if (topicBuf[0] != '/') { ShowSource(SRC_MQTT); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_RESULT D_RECEIVED_TOPIC " %s, " D_DATA_SIZE " %d, " D_DATA " %s"), - topicBuf, data_len, dataBuf); - AddLog(LOG_LEVEL_DEBUG_MORE); -// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) Serial.println(dataBuf); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_RESULT D_RECEIVED_TOPIC " %s, " D_DATA_SIZE " %d, " D_DATA " %s"), topicBuf, data_len, dataBuf); +// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) { Serial.println(dataBuf); } - if (XdrvMqttData(topicBuf, sizeof(topicBuf), dataBuf, sizeof(dataBuf))) return; + if (XdrvMqttData(topicBuf, sizeof(topicBuf), dataBuf, sizeof(dataBuf))) { return; } grpflg = (strstr(topicBuf, Settings.mqtt_grptopic) != NULL); @@ -495,20 +499,18 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } if (i < strlen(type)) { index = atoi(type +i); -// user_append_index = 1; +// user_append_index = true; } type[i] = '\0'; } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_RESULT D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " %s, " D_DATA " %s"), - grpflg, index, type, dataBuf); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_RESULT D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " %s, " D_DATA " %s"), grpflg, index, type, dataBuf); if (type != NULL) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}")); - if (Settings.ledstate &0x02) blinks++; + if (Settings.ledstate &0x02) { blinks++; } - if (!strcmp(dataBuf,"?")) data_len = 0; + if (!strcmp(dataBuf,"?")) { data_len = 0; } int16_t payload = -99; // No payload uint16_t payload16 = 0; long payload32 = strtol(dataBuf, &p, 10); @@ -523,13 +525,22 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) int temp_payload = GetStateNumber(dataBuf); if (temp_payload > -1) { payload = temp_payload; } -// snprintf_P(log_data, sizeof(log_data), PSTR("RSLT: Payload %d, Payload16 %d"), payload, payload16); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RSLT: Payload %d, Payload16 %d"), payload, payload16); int command_code = GetCommandCode(command, sizeof(command), type, kTasmotaCommands); if (-1 == command_code) { - if (!XdrvCommand(grpflg, type, index, dataBuf, data_len, payload, payload16)) { - type = NULL; // Unknown command +// XdrvMailbox.valid = 1; + XdrvMailbox.index = index; + XdrvMailbox.data_len = data_len; + XdrvMailbox.payload16 = payload16; + XdrvMailbox.payload = payload; + XdrvMailbox.grpflg = grpflg; + XdrvMailbox.topic = type; + XdrvMailbox.data = dataBuf; + if (!XdrvCall(FUNC_COMMAND)) { + if (!XsnsCall(FUNC_COMMAND)) { + type = NULL; // Unknown command + } } } else if (CMND_BACKLOG == command_code) { @@ -571,13 +582,13 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, bl_delay); } else if ((CMND_POWER == command_code) && (index > 0) && (index <= devices_present)) { - if ((payload < 0) || (payload > 4)) payload = 9; + if ((payload < 0) || (payload > 4)) { payload = 9; } // Settings.flag.device_index_enable = user_append_index; ExecuteCommandPower(index, payload, SRC_IGNORE); - fallback_topic_flag = 0; + fallback_topic_flag = false; return; } - else if ((CMND_FANSPEED == command_code) && (SONOFF_IFAN02 == Settings.module)) { + else if ((CMND_FANSPEED == command_code) && (SONOFF_IFAN02 == my_module_type)) { if (data_len > 0) { if ('-' == dataBuf[0]) { payload = (int16_t)GetFanspeed() -1; @@ -596,7 +607,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) else if (CMND_STATUS == command_code) { if ((payload < 0) || (payload > MAX_STATUS)) payload = 99; PublishStatus(payload); - fallback_topic_flag = 0; + fallback_topic_flag = false; return; } else if (CMND_STATE == command_code) { @@ -621,9 +632,9 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) // We also need at least 3 chars to make a valid version number string. if (((1 == data_len) && (1 == payload)) || ((data_len >= 3) && NewerVersion(dataBuf))) { ota_state_flag = 3; - snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}", command, my_version, GetOtaUrl(stemp1, sizeof(stemp1))); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}"), command, my_version, GetOtaUrl(stemp1, sizeof(stemp1))); } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_ONE_OR_GT "\"}", command, my_version); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"" D_JSON_ONE_OR_GT "\"}"), command, my_version); } } else if (CMND_OTAURL == command_code) { @@ -653,7 +664,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_ONE_TO_RESTART); } } - else if ((CMND_POWERONSTATE == command_code) && (Settings.module != MOTOR)) { + else if ((CMND_POWERONSTATE == command_code) && (my_module_type != MOTOR)) { /* 0 = Keep relays off after power on * 1 = Turn relays on after power on, if PulseTime set wait for PulseTime seconds, and turn relays off * 2 = Toggle relays after power on @@ -664,7 +675,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) if ((payload >= POWER_ALL_OFF) && (payload <= POWER_ALL_OFF_PULSETIME_ON)) { Settings.poweronstate = payload; if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { - for (byte i = 1; i <= devices_present; i++) { + for (uint8_t i = 1; i <= devices_present; i++) { ExecuteCommandPower(i, POWER_ON, SRC_IGNORE); } } @@ -712,14 +723,14 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) XdrvMailbox.topic = command; XdrvMailbox.data = dataBuf; if (CMND_SENSOR == command_code) { - XsnsCall(FUNC_COMMAND); + XsnsCall(FUNC_COMMAND_SENSOR); } else { - XdrvCall(FUNC_COMMAND); + XdrvCall(FUNC_COMMAND_DRIVER); } } else if ((CMND_SETOPTION == command_code) && (index < 82)) { - byte ptype; - byte pindex; + uint8_t ptype; + uint8_t pindex; if (index <= 31) { // SetOption0 .. 31 = Settings.flag ptype = 0; pindex = index; // 0 .. 31 @@ -740,6 +751,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) case 6: // mqtt_button_retain (CMND_BUTTONRETAIN) case 7: // mqtt_switch_retain (CMND_SWITCHRETAIN) case 9: // mqtt_sensor_retain (CMND_SENSORRETAIN) + case 14: // interlock (CMND_INTERLOCK) case 22: // mqtt_serial (SerialSend and SerialLog) case 23: // mqtt_serial_raw (SerialSend) case 25: // knx_enabled (Web config) @@ -758,7 +770,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } #ifdef USE_HOME_ASSISTANT if ((19 == pindex) || (30 == pindex)) { - HAssDiscovery(1); // hass_discovery or hass_light + HAssDiscover(); // Delayed execution to provide enough resources during hass_discovery or hass_light } #endif // USE_HOME_ASSISTANT } @@ -766,13 +778,14 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) else if (1 == ptype) { // SetOption50 .. 81 if (payload <= 1) { bitWrite(Settings.flag3.data, pindex, payload); - if (60 == ptype) { // SetOption60 enable or disable traditional sleep - if (payload == 0) { // Dynamic Sleep - WiFiSetSleepMode(); // Update WiFi sleep mode accordingly - } else { // Traditional Sleep //AT - WiFiSetSleepMode(); // Update WiFi sleep mode accordingly + if (5 == pindex) { // SetOption55 + if (0 == payload) { + restart_flag = 2; // Disable mDNS needs restart } } + if (10 == pindex) { // SetOption60 enable or disable traditional sleep + WiFiSetSleepMode(); // Update WiFi sleep mode accordingly + } } } else { // SetOption32 .. 49 @@ -787,6 +800,11 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } if ((payload >= param_low) && (payload <= param_high)) { Settings.param[pindex] = payload; + switch (pindex) { + case P_RGB_REMAP: + LightUpdateColorMapping(); + break; + } } } } @@ -850,52 +868,54 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.weight_resolution); } else if (CMND_MODULE == command_code) { - if ((payload > 0) && (payload <= MAXMODULE)) { + if ((payload >= 0) && (payload <= MAXMODULE)) { + if (0 == payload) { payload = 256; } payload--; Settings.last_module = Settings.module; Settings.module = payload; + SetModuleType(); if (Settings.last_module != payload) { - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - Settings.my_gp.io[i] = 0; + for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { + Settings.my_gp.io[i] = GPIO_NONE; } } restart_flag = 2; } - snprintf_P(stemp1, sizeof(stemp1), kModules[Settings.module].name); - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, Settings.module +1, stemp1); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, ModuleNr(), ModuleName().c_str()); } else if (CMND_MODULES == command_code) { - for (byte i = 0; i < MAXMODULE; i++) { + for (uint8_t i = 0; i <= MAXMODULE; i++) { if (!jsflg) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_MODULES "%d\":["), lines); } else { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data); } - jsflg = 1; - snprintf_P(stemp1, sizeof(stemp1), kModules[i].name); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i +1, stemp1); - if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == MAXMODULE -1)) { + jsflg = true; + uint8_t j = i; + if (0 == i) { j = USER_MODULE; } else { j--; } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i, AnyModuleName(j).c_str()); + if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == MAXMODULE)) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]}"), mqtt_data); MqttPublishPrefixTopic_P(RESULT_OR_STAT, type); - jsflg = 0; + jsflg = false; lines++; } } mqtt_data[0] = '\0'; } - else if ((CMND_GPIO == command_code) && (index < MAX_GPIO_PIN)) { - mytmplt cmodule; - memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule)); - if ((GPIO_USER == ValidGPIO(index, cmodule.gp.io[index])) && (payload >= 0) && (payload < GPIO_SENSOR_END)) { + else if ((CMND_GPIO == command_code) && (index < sizeof(Settings.my_gp))) { + myio cmodule; + ModuleGpios(&cmodule); + if (ValidGPIO(index, cmodule.io[index]) && (payload >= 0) && (payload < GPIO_SENSOR_END)) { bool present = false; - for (byte i = 0; i < sizeof(kGpioNiceList); i++) { + for (uint8_t i = 0; i < sizeof(kGpioNiceList); i++) { uint8_t midx = pgm_read_byte(kGpioNiceList + i); if (midx == payload) { present = true; } } if (present) { - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if ((GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) && (Settings.my_gp.io[i] == payload)) { - Settings.my_gp.io[i] = 0; + for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { + if (ValidGPIO(i, cmodule.io[i]) && (Settings.my_gp.io[i] == payload)) { + Settings.my_gp.io[i] = GPIO_NONE; } } Settings.my_gp.io[index] = payload; @@ -903,10 +923,10 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{")); - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) { + for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { + if (ValidGPIO(i, cmodule.io[i])) { if (jsflg) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data); - jsflg = 1; + jsflg = true; snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_GPIO "%d\":\"%d (%s)\""), mqtt_data, i, Settings.my_gp.io[i], GetTextIndexed(stemp1, sizeof(stemp1), Settings.my_gp.io[i], kSensorNames)); } @@ -918,31 +938,69 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } } else if (CMND_GPIOS == command_code) { - mytmplt cmodule; - memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule)); + myio cmodule; + ModuleGpios(&cmodule); uint8_t midx; - for (byte i = 0; i < sizeof(kGpioNiceList); i++) { + for (uint8_t i = 0; i < sizeof(kGpioNiceList); i++) { midx = pgm_read_byte(kGpioNiceList + i); - if (!GetUsedInModule(midx, cmodule.gp.io)) { - + if (!GetUsedInModule(midx, cmodule.io)) { if (!jsflg) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_GPIOS "%d\":["), lines); } else { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data); } - jsflg = 1; + jsflg = true; snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, midx, GetTextIndexed(stemp1, sizeof(stemp1), midx, kSensorNames)); if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == sizeof(kGpioNiceList) -1)) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]}"), mqtt_data); MqttPublishPrefixTopic_P(RESULT_OR_STAT, type); - jsflg = 0; + jsflg = false; lines++; } } } - mqtt_data[0] = '\0'; } + else if (CMND_TEMPLATE == command_code) { + // {"NAME":"Generic","GPIO":[17,254,29,254,7,254,254,254,138,254,139,254,254],"FLAG":1,"BASE":255} + bool error = false; + + if (!strstr(dataBuf, "{")) { // If no JSON it must be parameter + if ((payload > 0) && (payload <= MAXMODULE)) { + ModuleDefault(payload -1); // Copy template module + if (USER_MODULE == Settings.module) { restart_flag = 2; } + } + else if (0 == payload) { // Copy current template to user template + if (Settings.module != USER_MODULE) { + ModuleDefault(Settings.module); + } + } + else if (255 == payload) { // Copy current module with user configured GPIO + if (Settings.module != USER_MODULE) { + ModuleDefault(Settings.module); + } + snprintf_P(Settings.user_template.name, sizeof(Settings.user_template.name), PSTR("Merged")); + uint8_t j = 0; + for (uint8_t i = 0; i < sizeof(mycfgio); i++) { + if (6 == i) { j = 9; } + if (8 == i) { j = 12; } + if (my_module.io[j] > GPIO_NONE) { + Settings.user_template.gp.io[i] = my_module.io[j]; + } + j++; + } + } + } + else if (data_len > 9) { // Workaround exception if empty JSON like {} - Needs checks + if (JsonTemplate(dataBuf)) { // Free 336 bytes StaticJsonBuffer stack space by moving code to function + if (USER_MODULE == Settings.module) { restart_flag = 2; } + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON); + error = true; + } + } + if (!error) { TemplateJson(); } + } else if ((CMND_PWM == command_code) && pwm_present && (index > 0) && (index <= MAX_PWMS)) { if ((payload >= 0) && (payload <= Settings.pwm_range) && (pin[GPIO_PWM1 + index -1] < 99)) { Settings.pwm_value[index -1] = payload; @@ -962,7 +1020,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) else if (CMND_PWMRANGE == command_code) { if ((1 == payload) || ((payload > 254) && (payload < 1024))) { Settings.pwm_range = (1 == payload) ? PWM_RANGE : payload; - for (byte i = 0; i < MAX_PWMS; i++) { + for (uint8_t i = 0; i < MAX_PWMS; i++) { if (Settings.pwm_value[i] > Settings.pwm_range) { Settings.pwm_value[i] = Settings.pwm_range; } @@ -1010,7 +1068,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.switch_debounce); } else if (CMND_BAUDRATE == command_code) { - if (payload32 > 0) { + if (payload32 > 1200) { payload32 /= 1200; // Make it a valid baudrate baudrate = (1 == payload) ? APP_BAUDRATE : payload32 * 1200; SetSerialBaudrate(baudrate); @@ -1026,7 +1084,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) Serial.printf("%s\n", dataBuf); // "Hello Tiger\n" } else if (2 == index || 4 == index) { - for (int i = 0; i < data_len; i++) { + for (uint16_t i = 0; i < data_len; i++) { Serial.write(dataBuf[i]); // "Hello Tiger" or "A0" } } @@ -1035,7 +1093,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) Serial.printf("%s", Unescape(dataBuf, &dat_len)); // "Hello\f" } else if (5 == index) { - SerialSendRaw(RemoveSpace(dataBuf)); // "AA004566" + SerialSendRaw(RemoveSpace(dataBuf)); // "AA004566" as hex values } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); } @@ -1087,7 +1145,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) if (Settings.ntp_server[index -1][i] == ',') Settings.ntp_server[index -1][i] = '.'; } // restart_flag = 2; // Issue #3890 - ntp_force_sync = 1; + ntp_force_sync = true; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.ntp_server[index -1]); } @@ -1114,7 +1172,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.sta_ssid[index -1]); } else if ((CMND_PASSWORD == command_code) && (index > 0) && (index <= 2)) { - if ((data_len > 0) && (data_len < sizeof(Settings.sta_pwd[0]))) { + if ((data_len > 4 || SC_CLEAR == Shortcut(dataBuf) || SC_DEFAULT == Shortcut(dataBuf)) && (data_len < sizeof(Settings.sta_pwd[0]))) { strlcpy(Settings.sta_pwd[index -1], (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1 == index) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(Settings.sta_pwd[0])); Settings.sta_active = index -1; restart_flag = 2; @@ -1123,8 +1181,8 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_ASTERIX, command, index); } } - else if ((CMND_HOSTNAME == command_code) && !grpflg) { - if ((data_len > 0) && (data_len < sizeof(Settings.hostname))) { + else if (CMND_HOSTNAME == command_code) { + if (!grpflg && (data_len > 0) && (data_len < sizeof(Settings.hostname))) { strlcpy(Settings.hostname, (SC_DEFAULT == Shortcut(dataBuf)) ? WIFI_HOSTNAME : dataBuf, sizeof(Settings.hostname)); if (strstr(Settings.hostname,"%")) { strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname)); @@ -1162,10 +1220,77 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) else if ((CMND_SWITCHMODE == command_code) && (index > 0) && (index <= MAX_SWITCHES)) { if ((payload >= 0) && (payload < MAX_SWITCH_OPTION)) { Settings.switchmode[index -1] = payload; - GpioSwitchPinMode(index -1); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, index, Settings.switchmode[index-1]); } + else if (CMND_INTERLOCK == command_code) { // Interlock 0 - Off, Interlock 1 - On, Interlock 1,2 3,4 5,6,7 + uint8_t max_relays = devices_present; + if (light_type) { max_relays--; } + if (max_relays > sizeof(Settings.interlock[0]) * 8) { max_relays = sizeof(Settings.interlock[0]) * 8; } + if (max_relays > 1) { // Only interlock with more than 1 relay + if (data_len > 0) { + if (strstr(dataBuf, ",")) { // Interlock entry + for (uint8_t i = 0; i < MAX_INTERLOCKS; i++) { Settings.interlock[i] = 0; } // Reset current interlocks + char *group; + char *q; + uint8_t group_index = 0; + power_t relay_mask = 0; + for (group = strtok_r(dataBuf, " ", &q); group && group_index < MAX_INTERLOCKS; group = strtok_r(NULL, " ", &q)) { + char *str; + for (str = strtok_r(group, ",", &p); str; str = strtok_r(NULL, ",", &p)) { + int pbit = atoi(str); + if ((pbit > 0) && (pbit <= max_relays)) { // Only valid relays + pbit--; + if (!bitRead(relay_mask, pbit)) { // Only relay once + bitSet(relay_mask, pbit); + bitSet(Settings.interlock[group_index], pbit); + } + } + } + group_index++; + } + for (uint8_t i = 0; i < group_index; i++) { + uint8_t minimal_bits = 0; + for (uint8_t j = 0; j < max_relays; j++) { + if (bitRead(Settings.interlock[i], j)) { minimal_bits++; } + } + if (minimal_bits < 2) { Settings.interlock[i] = 0; } // Discard single relay as interlock + } + } else { + Settings.flag.interlock = payload &1; // Enable/disable interlock + if (Settings.flag.interlock) { + SetDevicePower(power, SRC_IGNORE); // Remove multiple relays if set + } + } + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_INTERLOCK "\":\"%s\",\"" D_JSON_GROUPS "\":\""), GetStateText(Settings.flag.interlock)); + uint8_t anygroup = 0; + for (uint8_t i = 0; i < MAX_INTERLOCKS; i++) { + if (Settings.interlock[i]) { + anygroup++; + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s"), mqtt_data, (anygroup > 1) ? " " : ""); + uint8_t anybit = 0; + power_t mask = 1; + for (uint8_t j = 0; j < max_relays; j++) { + if (Settings.interlock[i] & mask) { + anybit++; + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (anybit > 1) ? "," : "", j +1); + } + mask <<= 1; + } + } + } + if (!anygroup) { + for (uint8_t j = 1; j <= max_relays; j++) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (j > 1) ? "," : "", j); + } + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"}"), mqtt_data); + } else { + Settings.flag.interlock = 0; + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag.interlock)); + } + } else if (CMND_TELEPERIOD == command_code) { if ((payload >= 0) && (payload < 3601)) { Settings.tele_period = (1 == payload) ? TELE_PERIOD : payload; @@ -1180,10 +1305,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) restart_flag = 211; snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command , D_JSON_RESET_AND_RESTARTING); break; - case 2: - case 3: - case 4: - case 5: + case 2 ... 6: restart_flag = 210 + payload; snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RESET "\":\"" D_JSON_ERASE ", " D_JSON_RESET_AND_RESTARTING "\"}")); break; @@ -1207,7 +1329,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } else { Settings.timezone = 99; } - ntp_force_sync = 1; + ntp_force_sync = true; } if (99 == Settings.timezone) { snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.timezone); @@ -1242,7 +1364,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) value = strtol(p, &p, 10); tpos++; // Next parameter } - ntp_force_sync = 1; + ntp_force_sync = true; } else { if (0 == payload) { if (0 == ts) { @@ -1251,7 +1373,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) SettingsResetDst(); } } - ntp_force_sync = 1; + ntp_force_sync = true; } } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"Hemisphere\":%d,\"Week\":%d,\"Month\":%d,\"Day\":%d,\"Hour\":%d,\"Offset\":%d}}"), @@ -1283,7 +1405,10 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) else if (CMND_LEDSTATE == command_code) { if ((payload >= 0) && (payload < MAX_LED_OPTION)) { Settings.ledstate = payload; - if (!Settings.ledstate) SetLedPower(0); + if (!Settings.ledstate) { + SetLedPower(0); + SetLedLink(0); + } } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.ledstate); } @@ -1301,12 +1426,12 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) type = (char*)topicBuf; } if (mqtt_data[0] != '\0') MqttPublishPrefixTopic_P(RESULT_OR_STAT, type); - fallback_topic_flag = 0; + fallback_topic_flag = false; } /********************************************************************************************/ -boolean SendKey(byte key, byte device, byte state) +bool SendKey(uint8_t key, uint8_t device, uint8_t state) { // key 0 = button_topic // key 1 = switch_topic @@ -1319,7 +1444,7 @@ boolean SendKey(byte key, byte device, byte state) char stopic[TOPSZ]; char scommand[CMDSZ]; char key_topic[sizeof(Settings.button_topic)]; - boolean result = false; + bool result = false; char *tmp = (key) ? Settings.switch_topic : Settings.button_topic; Format(key_topic, tmp, sizeof(key_topic)); @@ -1337,10 +1462,10 @@ boolean SendKey(byte key, byte device, byte state) } #ifdef USE_DOMOTICZ if (!(DomoticzSendKey(key, device, state, strlen(mqtt_data)))) { - MqttPublishDirect(stopic, (key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain); + MqttPublishDirect(stopic, ((key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain) && (state != 3 || !Settings.flag3.no_hold_retain)); } #else - MqttPublishDirect(stopic, (key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain); + MqttPublishDirect(stopic, ((key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain) && (state != 3 || !Settings.flag3.no_hold_retain)); #endif // USE_DOMOTICZ result = !Settings.flag3.button_switch_force_local; } else { @@ -1353,7 +1478,7 @@ boolean SendKey(byte key, byte device, byte state) return result; } -void ExecuteCommandPower(byte device, byte state, int source) +void ExecuteCommandPower(uint8_t device, uint8_t state, int source) { // device = Relay number 1 and up // state 0 = Relay Off @@ -1367,7 +1492,7 @@ void ExecuteCommandPower(byte device, byte state, int source) // ShowSource(source); - if (SONOFF_IFAN02 == Settings.module) { + if (SONOFF_IFAN02 == my_module_type) { blink_mask &= 1; // No blinking on the fan relays Settings.flag.interlock = 0; // No interlock mode as it is already done by the microcontroller Settings.pulse_timer[1] = 0; // No pulsetimers on the fan relays @@ -1382,20 +1507,30 @@ void ExecuteCommandPower(byte device, byte state, int source) } if ((device < 1) || (device > devices_present)) device = 1; if (device <= MAX_PULSETIMERS) { SetPulseTimer(device -1, 0); } - power_t mask = 1 << (device -1); + power_t mask = 1 << (device -1); // Device to control if (state <= POWER_TOGGLE) { if ((blink_mask & mask)) { blink_mask &= (POWER_MASK ^ mask); // Clear device mask MqttPublishPowerBlinkState(device); } - if (Settings.flag.interlock && !interlock_mutex) { // Clear all but masked relay - interlock_mutex = 1; - for (byte i = 0; i < devices_present; i++) { - power_t imask = 1 << i; - if ((power & imask) && (mask != imask)) ExecuteCommandPower(i +1, POWER_OFF, SRC_IGNORE); + + if (Settings.flag.interlock && !interlock_mutex) { // Clear all but masked relay in interlock group + interlock_mutex = true; + for (uint8_t i = 0; i < MAX_INTERLOCKS; i++) { + if (Settings.interlock[i] & mask) { // Find interlock group + for (uint8_t j = 0; j < devices_present; j++) { + power_t imask = 1 << j; + if ((Settings.interlock[i] & imask) && (power & imask) && (mask != imask)) { + ExecuteCommandPower(j +1, POWER_OFF, SRC_IGNORE); + delay(50); // Add some delay to make sure never have more than one relay on + } + } + break; // An interlocked relay is only present in one group so quit + } } - interlock_mutex = 0; + interlock_mutex = false; } + switch (state) { case POWER_OFF: { power &= (POWER_MASK ^ mask); @@ -1434,7 +1569,7 @@ void ExecuteCommandPower(byte device, byte state, int source) return; } else if (POWER_BLINK_STOP == state) { - byte flag = (blink_mask & mask); + uint8_t flag = (blink_mask & mask); blink_mask &= (POWER_MASK ^ mask); // Clear device mask MqttPublishPowerBlinkState(device); if (flag) ExecuteCommandPower(device, (blink_powersave >> (device -1))&1, SRC_IGNORE); // Restore state @@ -1447,7 +1582,7 @@ void StopAllPowerBlink(void) { power_t mask; - for (byte i = 1; i <= devices_present; i++) { + for (uint8_t i = 1; i <= devices_present; i++) { mask = 1 << (i -1); if (blink_mask & mask) { blink_mask &= (POWER_MASK ^ mask); // Clear device mask @@ -1459,57 +1594,61 @@ void StopAllPowerBlink(void) void ExecuteCommand(char *cmnd, int source) { - char stopic[CMDSZ]; - char svalue[INPUT_BUFFER_SIZE]; char *start; char *token; +#ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("ExecuteCommand")); +#endif ShowSource(source); token = strtok(cmnd, " "); if (token != NULL) { start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble - if (start) token = start +1; + if (start) { token = start +1; } } + uint16_t size = (token != NULL) ? strlen(token) : 0; + char stopic[size +2]; // / + \0 snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), (token == NULL) ? "" : token); + token = strtok(NULL, ""); -// snprintf_P(svalue, sizeof(svalue), (token == NULL) ? "" : token); // Fails with command FullTopic home/%prefix%/%topic% as it processes %p of %prefix% + size = (token != NULL) ? strlen(token) : 0; + char svalue[size +1]; strlcpy(svalue, (token == NULL) ? "" : token, sizeof(svalue)); // Fixed 5.8.0b - MqttDataHandler(stopic, (byte*)svalue, strlen(svalue)); + MqttDataHandler(stopic, (uint8_t*)svalue, strlen(svalue)); } void PublishStatus(uint8_t payload) { uint8_t option = STAT; char stemp[MAX_FRIENDLYNAMES * (sizeof(Settings.friendlyname[0]) +MAX_FRIENDLYNAMES)]; - char stemp2[MAX_SWITCHES * 3]; + char stemp2[64]; // Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX - if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) option++; // TELE + if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) { option++; } // TELE - if ((!Settings.flag.mqtt_enabled) && (6 == payload)) payload = 99; - if (!energy_flg && (9 == payload)) payload = 99; + if ((!Settings.flag.mqtt_enabled) && (6 == payload)) { payload = 99; } + if (!energy_flg && (9 == payload)) { payload = 99; } if ((0 == payload) || (99 == payload)) { uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present; - if (SONOFF_IFAN02 == Settings.module) { maxfn = 1; } + if (SONOFF_IFAN02 == my_module_type) { maxfn = 1; } stemp[0] = '\0'; - for (byte i = 0; i < maxfn; i++) { + for (uint8_t i = 0; i < maxfn; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%s%s\"%s\"" ), stemp, (i > 0 ? "," : ""), Settings.friendlyname[i]); } stemp2[0] = '\0'; - for (byte i = 0; i < MAX_SWITCHES; i++) { + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]); } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\"" D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"), - Settings.module +1, stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.switch_topic, stemp2, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_switch_retain, Settings.flag.mqtt_sensor_retain, Settings.flag.mqtt_power_retain); + ModuleNr(), stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.switch_topic, stemp2, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_switch_retain, Settings.flag.mqtt_sensor_retain, Settings.flag.mqtt_power_retain); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS)); } if ((0 == payload) || (1 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_JSON_BAUDRATE "\":%d,\"" D_CMND_GROUPTOPIC "\":\"%s\",\"" D_CMND_OTAURL "\":\"%s\",\"" D_JSON_RESTARTREASON "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\",\"" D_JSON_STARTUPUTC "\":\"%s\",\"" D_CMND_SLEEP "\":%d,\"" D_JSON_BOOTCOUNT "\":%d,\"" D_JSON_SAVECOUNT "\":%d,\"" D_JSON_SAVEADDRESS "\":\"%X\"}}"), - baudrate, Settings.mqtt_grptopic, Settings.ota_url, GetResetReason().c_str(), GetUptime().c_str(), GetDateAndTime(DT_RESTART).c_str(), Settings.sleep, Settings.bootcount, Settings.save_flag, GetSettingsAddress()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_JSON_BAUDRATE "\":%d,\"" D_CMND_GROUPTOPIC "\":\"%s\",\"" D_CMND_OTAURL "\":\"%s\",\"" D_JSON_RESTARTREASON "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\",\"" D_JSON_STARTUPUTC "\":\"%s\",\"" D_CMND_SLEEP "\":%d,\"" D_JSON_CONFIG_HOLDER "\":%d,\"" D_JSON_BOOTCOUNT "\":%d,\"" D_JSON_SAVECOUNT "\":%d,\"" D_JSON_SAVEADDRESS "\":\"%X\"}}"), + baudrate, Settings.mqtt_grptopic, Settings.ota_url, GetResetReason().c_str(), GetUptime().c_str(), GetDateAndTime(DT_RESTART).c_str(), Settings.sleep, Settings.cfg_holder, Settings.bootcount, Settings.save_flag, GetSettingsAddress()); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "1")); } @@ -1520,8 +1659,12 @@ void PublishStatus(uint8_t payload) } if ((0 == payload) || (3 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\"" D_CMND_LOGHOST "\":\"%s\",\"" D_CMND_LOGPORT "\":%d,\"" D_CMND_SSID "\":[\"%s\",\"%s\"],\"" D_CMND_TELEPERIOD "\":%d,\"" D_CMND_SETOPTION "\":[\"%08X\",\"%08X\",\"%08X\"]}}"), - Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.sta_ssid[0], Settings.sta_ssid[1], Settings.tele_period, Settings.flag.data, Settings.flag2.data, Settings.flag3.data); + stemp2[0] = '\0'; + for (int8_t i = 0; i < PARAM8_SIZE; i++) { + snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%02X"), stemp2, Settings.param[i]); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\"" D_CMND_LOGHOST "\":\"%s\",\"" D_CMND_LOGPORT "\":%d,\"" D_CMND_SSID "\":[\"%s\",\"%s\"],\"" D_CMND_TELEPERIOD "\":%d,\"" D_JSON_RESOLUTION "\":\"%08X\",\"" D_CMND_SETOPTION "\":[\"%08X\",\"%s\",\"%08X\"]}}"), + Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.sta_ssid[0], Settings.sta_ssid[1], Settings.tele_period, Settings.flag2.data, Settings.flag.data, stemp2, Settings.flag3.data); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "3")); } @@ -1539,8 +1682,8 @@ void PublishStatus(uint8_t payload) } if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"MqttType\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"), - Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MqttLibraryType(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"MqttType\":%d,\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"), + Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MqttLibraryType(), MqttConnectCount(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6")); } @@ -1592,7 +1735,7 @@ void MqttShowPWMState(void) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_PWM "\":{"), mqtt_data); bool first = true; - for (byte i = 0; i < MAX_PWMS; i++) { + for (uint8_t i = 0; i < MAX_PWMS; i++) { if (pin[GPIO_PWM1 + i] < 99) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_PWM "%d\":%d"), mqtt_data, first ? "" : ",", i+1, Settings.pwm_value[i]); first = false; @@ -1615,12 +1758,12 @@ void MqttShowState(void) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SleepMode\":\"%s\",\"Sleep\":%u,\"LoadAvg\":%u"), mqtt_data, GetTextIndexed(stemp1, sizeof(stemp1), Settings.flag3.sleep_normal, kSleepMode), sleep, loop_load_avg); - for (byte i = 0; i < devices_present; i++) { + for (uint8_t i = 0; i < devices_present; i++) { if (i == light_device -1) { LightState(1); } else { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":\"%s\""), mqtt_data, GetPowerDevice(stemp1, i +1, sizeof(stemp1), Settings.flag.device_index_enable), GetStateText(bitRead(power, i))); - if (SONOFF_IFAN02 == Settings.module) { + if (SONOFF_IFAN02 == my_module_type) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_FANSPEED "\":%d"), mqtt_data, GetFanspeed()); break; } @@ -1632,26 +1775,26 @@ void MqttShowState(void) MqttShowPWMState(); } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d}}"), - mqtt_data, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WiFi.BSSIDstr().c_str(), WiFi.channel(), WifiGetRssiAsQuality(WiFi.RSSI())); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d,\"" D_JSON_LINK_COUNT "\":%d,\"" D_JSON_DOWNTIME "\":\"%s\"}}"), + mqtt_data, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WiFi.BSSIDstr().c_str(), WiFi.channel(), WifiGetRssiAsQuality(WiFi.RSSI()), WifiLinkCount(), WifiDowntime().c_str()); } -boolean MqttShowSensor(void) +bool MqttShowSensor(void) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{\"" D_JSON_TIME "\":\"%s\""), mqtt_data, GetDateAndTime(DT_LOCAL).c_str()); int json_data_start = strlen(mqtt_data); - for (byte i = 0; i < MAX_SWITCHES; i++) { + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { #ifdef USE_TM1638 if ((pin[GPIO_SWT1 +i] < 99) || ((pin[GPIO_TM16CLK] < 99) && (pin[GPIO_TM16DIO] < 99) && (pin[GPIO_TM16STB] < 99))) { #else if (pin[GPIO_SWT1 +i] < 99) { #endif // USE_TM1638 - boolean swm = ((FOLLOW_INV == Settings.switchmode[i]) || (PUSHBUTTON_INV == Settings.switchmode[i]) || (PUSHBUTTONHOLD_INV == Settings.switchmode[i])); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_SWITCH "%d\":\"%s\""), mqtt_data, i +1, GetStateText(swm ^ lastwallswitch[i])); + bool swm = ((FOLLOW_INV == Settings.switchmode[i]) || (PUSHBUTTON_INV == Settings.switchmode[i]) || (PUSHBUTTONHOLD_INV == Settings.switchmode[i])); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_SWITCH "%d\":\"%s\""), mqtt_data, i +1, GetStateText(swm ^ SwitchLastState(i))); } } XsnsCall(FUNC_JSON_APPEND); - boolean json_data_available = (strlen(mqtt_data) - json_data_start); + bool json_data_available = (strlen(mqtt_data) - json_data_start); if (strstr_P(mqtt_data, PSTR(D_JSON_PRESSURE))) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_PRESSURE_UNIT "\":\"%s\""), mqtt_data, PressureUnit().c_str()); } @@ -1675,11 +1818,10 @@ void PerformEverySecond(void) RtcRebootSave(); Settings.bootcount++; // Moved to here to stop flash writes during start-up - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BOOT_COUNT " %d"), Settings.bootcount); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BOOT_COUNT " %d"), Settings.bootcount); } - if ((4 == uptime) && (SONOFF_IFAN02 == Settings.module)) { // Microcontroller needs 3 seconds before accepting commands + if ((4 == uptime) && (SONOFF_IFAN02 == my_module_type)) { // Microcontroller needs 3 seconds before accepting commands SetDevicePower(1, SRC_RETRY); // Sync with default power on state microcontroller being Light ON and Fan OFF SetDevicePower(power, SRC_RETRY); // Set required power on state } @@ -1739,241 +1881,6 @@ void PerformEverySecond(void) if ((3 == RtcTime.minute) && !latest_uptime_flag) latest_uptime_flag = true; } -/*********************************************************************************************\ - * Button handler with single press only or multi-press and hold on all buttons -\*********************************************************************************************/ - -void ButtonHandler(void) -{ - uint8_t button = NOT_PRESSED; - uint8_t button_present = 0; - uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command - uint16_t loops_per_second = 1000 / Settings.button_debounce; - char scmnd[20]; - - uint8_t maxdev = (devices_present > MAX_KEYS) ? MAX_KEYS : devices_present; - for (byte button_index = 0; button_index < maxdev; button_index++) { - button = NOT_PRESSED; - button_present = 0; - - if (!button_index && ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module))) { - button_present = 1; - if (dual_button_code) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), dual_button_code); - AddLog(LOG_LEVEL_DEBUG); - button = PRESSED; - if (0xF500 == dual_button_code) { // Button hold - holdbutton[button_index] = (loops_per_second * Settings.param[P_HOLD_TIME] / 10) -1; - hold_time_extent = 1; - } - dual_button_code = 0; - } - } else { - if (pin[GPIO_KEY1 +button_index] < 99) { - if (!((uptime < 4) && (0 == pin[GPIO_KEY1 +button_index]))) { // Block GPIO0 for 4 seconds after poweron to workaround Wemos D1 RTS circuit - button_present = 1; - button = digitalRead(pin[GPIO_KEY1 +button_index]); - } - } - } - - if (button_present) { - XdrvMailbox.index = button_index; - XdrvMailbox.payload = button; - if (XdrvCall(FUNC_BUTTON_PRESSED)) { - // Serviced - } - else if (SONOFF_4CHPRO == Settings.module) { - if (holdbutton[button_index]) { holdbutton[button_index]--; } - - boolean button_pressed = false; - if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_10), button_index +1); - AddLog(LOG_LEVEL_DEBUG); - holdbutton[button_index] = loops_per_second; - button_pressed = true; - } - if ((NOT_PRESSED == button) && (PRESSED == lastbutton[button_index])) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1); - AddLog(LOG_LEVEL_DEBUG); - if (!holdbutton[button_index]) { button_pressed = true; } // Do not allow within 1 second - } - if (button_pressed) { - if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - } - } - } - else { - if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) { - if (Settings.flag.button_single) { // Allow only single button press for immediate action - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1); - AddLog(LOG_LEVEL_DEBUG); - if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - } - } else { - multipress[button_index] = (multiwindow[button_index]) ? multipress[button_index] +1 : 1; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, multipress[button_index]); - AddLog(LOG_LEVEL_DEBUG); - multiwindow[button_index] = loops_per_second / 2; // 0.5 second multi press window - } - blinks = 201; - } - - if (NOT_PRESSED == button) { - holdbutton[button_index] = 0; - } else { - holdbutton[button_index]++; - if (Settings.flag.button_single) { // Allow only single button press for immediate action - if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer -// Settings.flag.button_single = 0; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only - ExecuteCommand(scmnd, SRC_BUTTON); - } - } else { - if (Settings.flag.button_restrict) { // Button restriction - if (holdbutton[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { // Button hold - multipress[button_index] = 0; - SendKey(0, button_index +1, 3); // Execute Hold command via MQTT if ButtonTopic is set - } - } else { - if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer - multipress[button_index] = 0; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - } - } - - if (!Settings.flag.button_single) { // Allow multi-press - if (multiwindow[button_index]) { - multiwindow[button_index]--; - } else { - if (!restart_flag && !holdbutton[button_index] && (multipress[button_index] > 0) && (multipress[button_index] < MAX_BUTTON_COMMANDS +3)) { - boolean single_press = false; - if (multipress[button_index] < 3) { // Single or Double press - if ((SONOFF_DUAL_R2 == Settings.module) || (SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) { - single_press = true; - } else { - single_press = (Settings.flag.button_swap +1 == multipress[button_index]); - multipress[button_index] = 1; - } - } - if (single_press && SendKey(0, button_index + multipress[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - // Success - } else { - if (multipress[button_index] < 3) { // Single or Double press - if (WifiState() > WIFI_RESTART) { // WPSconfig, Smartconfig or Wifimanager active - restart_flag = 1; - } else { - ExecuteCommandPower(button_index + multipress[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - } - } else { // 3 - 7 press - if (!Settings.flag.button_restrict) { - snprintf_P(scmnd, sizeof(scmnd), kCommands[multipress[button_index] -3]); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - } - multipress[button_index] = 0; - } - } - } - } - } - lastbutton[button_index] = button; - } -} - -/*********************************************************************************************\ - * Switch handler -\*********************************************************************************************/ - -void SwitchHandler(byte mode) -{ - uint8_t button = NOT_PRESSED; - uint8_t switchflag; - uint16_t loops_per_second = 1000 / Settings.switch_debounce; - - for (byte i = 0; i < MAX_SWITCHES; i++) { - if ((pin[GPIO_SWT1 +i] < 99) || (mode)) { - - if (holdwallswitch[i]) { - holdwallswitch[i]--; - if (0 == holdwallswitch[i]) { - SendKey(1, i +1, 3); // Execute command via MQTT - } - } - - if (mode) { - button = virtualswitch[i]; - } else { - if (!((uptime < 4) && (0 == pin[GPIO_SWT1 +i]))) { // Block GPIO0 for 4 seconds after poweron to workaround Wemos D1 RTS circuit - button = digitalRead(pin[GPIO_SWT1 +i]); - } - } - - if (button != lastwallswitch[i]) { - switchflag = 3; - switch (Settings.switchmode[i]) { - case TOGGLE: - switchflag = 2; // Toggle - break; - case FOLLOW: - switchflag = button &1; // Follow wall switch state - break; - case FOLLOW_INV: - switchflag = ~button &1; // Follow inverted wall switch state - break; - case PUSHBUTTON: - if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) { - switchflag = 2; // Toggle with pushbutton to Gnd - } - break; - case PUSHBUTTON_INV: - if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) { - switchflag = 2; // Toggle with releasing pushbutton from Gnd - } - break; - case PUSHBUTTON_TOGGLE: - if (button != lastwallswitch[i]) { - switchflag = 2; // Toggle with any pushbutton change - } - break; - case PUSHBUTTONHOLD: - if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) { - holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; - } - if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) { - holdwallswitch[i] = 0; - switchflag = 2; // Toggle with pushbutton to Gnd - } - break; - case PUSHBUTTONHOLD_INV: - if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) { - holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; - } - if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) { - holdwallswitch[i] = 0; - switchflag = 2; // Toggle with pushbutton to Gnd - } - break; - } - - if (switchflag < 3) { - if (!SendKey(1, i +1, switchflag)) { // Execute command via MQTT - ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < devices_present) - } - } - - lastwallswitch[i] = button; - } - } - } -} - /*********************************************************************************************\ * State loops \*********************************************************************************************/ @@ -1991,7 +1898,7 @@ void Every100mSeconds(void) if (!latching_relay_pulse) SetLatchingRelay(0, 0); } - for (byte i = 0; i < MAX_PULSETIMERS; i++) { + for (uint8_t i = 0; i < MAX_PULSETIMERS; i++) { if (pulse_timer[i] != 0L) { // Timer active? if (TimeReached(pulse_timer[i])) { // Timer finished? pulse_timer[i] = 0L; // Turn off this timer @@ -2017,9 +1924,9 @@ void Every100mSeconds(void) // Backlog if (TimeReached(backlog_delay)) { if ((backlog_pointer != backlog_index) && !backlog_mutex) { - backlog_mutex = 1; + backlog_mutex = true; ExecuteCommand((char*)backlog[backlog_pointer].c_str(), SRC_BACKLOG); - backlog_mutex = 0; + backlog_mutex = false; backlog_pointer++; if (backlog_pointer >= MAX_BACKLOG) { backlog_pointer = 0; } } @@ -2050,7 +1957,7 @@ void Every250mSeconds(void) } if (blinks || restart_flag || ota_state_flag) { if (restart_flag || ota_state_flag) { // Overrule blinks and keep led lit - blinkstate = 1; // Stay lit + blinkstate = true; // Stay lit } else { blinkspeed--; if (!blinkspeed) { @@ -2060,7 +1967,8 @@ void Every250mSeconds(void) } if ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) { // if ( (!Settings.flag.global_state && global_state.data) || ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) ) { - SetLedPower(blinkstate); // Set led on or off +// SetLedPower(blinkstate); // Set led on or off + SetLedLink(blinkstate); // Set led on or off } if (!blinkstate) { blinks--; @@ -2068,8 +1976,8 @@ void Every250mSeconds(void) } } else if (Settings.ledstate &1) { - boolean tstate = power; - if ((SONOFF_TOUCH == Settings.module) || (SONOFF_T11 == Settings.module) || (SONOFF_T12 == Settings.module) || (SONOFF_T13 == Settings.module)) { + bool tstate = power; + if ((SONOFF_TOUCH == my_module_type) || (SONOFF_T11 == my_module_type) || (SONOFF_T12 == my_module_type) || (SONOFF_T13 == my_module_type)) { tstate = (!power) ? 1 : 0; // As requested invert signal for Touch devices to find them in the dark } SetLedPower(tstate); @@ -2104,21 +2012,20 @@ void Every250mSeconds(void) ota_retry_counter--; if (ota_retry_counter) { strlcpy(mqtt_data, GetOtaUrl(log_data, sizeof(log_data)), sizeof(mqtt_data)); -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL if (RtcSettings.ota_loader) { char *bch = strrchr(mqtt_data, '/'); // Only consider filename after last backslash prevent change of urls having "-" in it char *pch = strrchr((bch != NULL) ? bch : mqtt_data, '-'); // Change from filename-DE.bin into filename-minimal.bin char *ech = strrchr((bch != NULL) ? bch : mqtt_data, '.'); // Change from filename.bin into filename-minimal.bin - if (!pch) pch = ech; + if (!pch) { pch = ech; } if (pch) { mqtt_data[pch - mqtt_data] = '\0'; char *ech = strrchr(Settings.ota_url, '.'); // Change from filename.bin into filename-minimal.bin snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s-" D_JSON_MINIMAL "%s"), mqtt_data, ech); // Minimal filename must be filename-minimal } } -#endif // BE_MINIMAL - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "%s"), mqtt_data); - AddLog(LOG_LEVEL_DEBUG); +#endif // FIRMWARE_MINIMAL + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "%s"), mqtt_data); #if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(mqtt_data)); #else @@ -2127,14 +2034,13 @@ void Every250mSeconds(void) ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(OTAclient, mqtt_data)); #endif if (!ota_result) { -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL int ota_error = ESPhttpUpdate.getLastError(); -// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Ota error %d"), ota_error); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Ota error %d"), ota_error); if ((HTTP_UE_TOO_LESS_SPACE == ota_error) || (HTTP_UE_BIN_FOR_WRONG_FLASH == ota_error)) { RtcSettings.ota_loader = 1; // Try minimal image next } -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL ota_state_flag = 2; // Upgrade failed - retry } } @@ -2159,7 +2065,7 @@ void Every250mSeconds(void) if (save_data_counter <= 0) { if (Settings.flag.save_state) { power_t mask = POWER_MASK; - for (byte i = 0; i < MAX_PULSETIMERS; i++) { + for (uint8_t i = 0; i < MAX_PULSETIMERS; i++) { if ((Settings.pulse_timer[i] > 0) && (Settings.pulse_timer[i] < 30)) { // 3 seconds mask &= ~(1 << i); } @@ -2175,14 +2081,33 @@ void Every250mSeconds(void) } } if (restart_flag && (backlog_pointer == backlog_index)) { - if ((214 == restart_flag) || (215 == restart_flag)) { + if ((214 == restart_flag) || (215 == restart_flag) || (216 == restart_flag)) { char storage[sizeof(Settings.sta_ssid) + sizeof(Settings.sta_pwd)]; + char storage_mqtt_host[sizeof(Settings.mqtt_host)]; + uint16_t storage_mqtt_port; + char storage_mqtt_user[sizeof(Settings.mqtt_user)]; + char storage_mqtt_pwd[sizeof(Settings.mqtt_pwd)]; + char storage_mqtt_topic[sizeof(Settings.mqtt_topic)]; memcpy(storage, Settings.sta_ssid, sizeof(storage)); // Backup current SSIDs and Passwords - if (215 == restart_flag) { + if (216 == restart_flag) { + memcpy(storage_mqtt_host, Settings.mqtt_host, sizeof(Settings.mqtt_host)); + storage_mqtt_port = Settings.mqtt_port; + memcpy(storage_mqtt_user, Settings.mqtt_user, sizeof(Settings.mqtt_user)); + memcpy(storage_mqtt_pwd, Settings.mqtt_pwd, sizeof(Settings.mqtt_pwd)); + memcpy(storage_mqtt_topic, Settings.mqtt_topic, sizeof(Settings.mqtt_topic)); + } + if ((215 == restart_flag) || (216 == restart_flag)) { SettingsErase(0); // Erase all flash from program end to end of physical flash } SettingsDefault(); memcpy(Settings.sta_ssid, storage, sizeof(storage)); // Restore current SSIDs and Passwords + if (216 == restart_flag) { // Restore the mqtt host, port, username and password + memcpy(Settings.mqtt_host, storage_mqtt_host, sizeof(Settings.mqtt_host)); + Settings.mqtt_port = storage_mqtt_port; + memcpy(Settings.mqtt_user, storage_mqtt_user, sizeof(Settings.mqtt_user)); + memcpy(Settings.mqtt_pwd, storage_mqtt_pwd, sizeof(Settings.mqtt_pwd)); + memcpy(Settings.mqtt_topic, storage_mqtt_topic, sizeof(Settings.mqtt_topic)); + } restart_flag = 2; } else if (213 == restart_flag) { @@ -2230,20 +2155,19 @@ void ArduinoOTAInit(void) { ArduinoOTA.setPort(8266); ArduinoOTA.setHostname(my_hostname); - if (Settings.web_password[0] !=0) ArduinoOTA.setPassword(Settings.web_password); + if (Settings.web_password[0] !=0) { ArduinoOTA.setPassword(Settings.web_password); } ArduinoOTA.onStart([]() { SettingsSave(1); // Free flash for OTA update #ifdef USE_WEBSERVER - if (Settings.webserver) StopWebserver(); + if (Settings.webserver) { StopWebserver(); } #endif // USE_WEBSERVER #ifdef USE_ARILUX_RF AriluxRfDisable(); // Prevent restart exception on Arilux Interrupt routine #endif // USE_ARILUX_RF - if (Settings.flag.mqtt_enabled) MqttDisconnect(); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_UPLOAD_STARTED)); - AddLog(LOG_LEVEL_INFO); + if (Settings.flag.mqtt_enabled) { MqttDisconnect(); } + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD "Arduino OTA " D_UPLOAD_STARTED)); arduino_ota_triggered = true; arduino_ota_progress_dot_count = 0; delay(100); // Allow time for message xfer @@ -2254,7 +2178,7 @@ void ArduinoOTAInit(void) if ((LOG_LEVEL_DEBUG <= seriallog_level)) { arduino_ota_progress_dot_count++; Serial.printf("."); - if (!(arduino_ota_progress_dot_count % 80)) Serial.println(); + if (!(arduino_ota_progress_dot_count % 80)) { Serial.println(); } } }); @@ -2266,7 +2190,7 @@ void ArduinoOTAInit(void) */ char error_str[100]; - if ((LOG_LEVEL_DEBUG <= seriallog_level) && arduino_ota_progress_dot_count) Serial.println(); + if ((LOG_LEVEL_DEBUG <= seriallog_level) && arduino_ota_progress_dot_count) { Serial.println(); } switch (error) { case OTA_BEGIN_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_2), sizeof(error_str)); break; case OTA_RECEIVE_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_5), sizeof(error_str)); break; @@ -2274,22 +2198,19 @@ void ArduinoOTAInit(void) default: snprintf_P(error_str, sizeof(error_str), PSTR(D_UPLOAD_ERROR_CODE " %d"), error); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA %s. " D_RESTARTING), error_str); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD "Arduino OTA %s. " D_RESTARTING), error_str); EspRestart(); }); ArduinoOTA.onEnd([]() { - if ((LOG_LEVEL_DEBUG <= seriallog_level)) Serial.println(); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_SUCCESSFUL ". " D_RESTARTING)); - AddLog(LOG_LEVEL_INFO); + if ((LOG_LEVEL_DEBUG <= seriallog_level)) { Serial.println(); } + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD "Arduino OTA " D_SUCCESSFUL ". " D_RESTARTING)); EspRestart(); }); ArduinoOTA.begin(); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_ENABLED " " D_PORT " 8266")); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD "Arduino OTA " D_ENABLED " " D_PORT " 8266")); } #endif // USE_ARDUINO_OTA @@ -2298,29 +2219,15 @@ void ArduinoOTAInit(void) void SerialInput(void) { while (Serial.available()) { - yield(); +// yield(); + delay(0); serial_in_byte = Serial.read(); /*-------------------------------------------------------------------------------------------*\ * Sonoff dual and ch4 19200 baud serial interface \*-------------------------------------------------------------------------------------------*/ - if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) { - if (dual_hex_code) { - dual_hex_code--; - if (dual_hex_code) { - dual_button_code = (dual_button_code << 8) | serial_in_byte; - serial_in_byte = 0; - } else { - if (serial_in_byte != 0xA1) { - dual_button_code = 0; // 0xA1 - End of Sonoff dual button code - } - } - } - if (0xA0 == serial_in_byte) { // 0xA0 - Start of Sonoff dual button code - serial_in_byte = 0; - dual_button_code = 0; - dual_hex_code = 3; - } + if ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { + serial_in_byte = ButtonSerial(serial_in_byte); } /*-------------------------------------------------------------------------------------------*/ @@ -2333,27 +2240,29 @@ void SerialInput(void) /*-------------------------------------------------------------------------------------------*/ - if (serial_in_byte > 127 && !Settings.flag.mqtt_serial_raw) { // binary data... + if (serial_in_byte > 127 && !Settings.flag.mqtt_serial_raw) { // Discard binary data above 127 if no raw reception allowed serial_in_byte_counter = 0; Serial.flush(); return; } - if (!Settings.flag.mqtt_serial) { - if (isprint(serial_in_byte)) { - if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits + if (!Settings.flag.mqtt_serial) { // SerialSend active + if (isprint(serial_in_byte)) { // Any char between 32 and 127 + if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // Add char to string if it still fits serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; } else { serial_in_byte_counter = 0; } } } else { - if (serial_in_byte || Settings.flag.mqtt_serial_raw) { - if ((serial_in_byte_counter < INPUT_BUFFER_SIZE -1) && - ((serial_in_byte != Settings.serial_delimiter) || Settings.flag.mqtt_serial_raw)) { // add char to string if it still fits + if (serial_in_byte || Settings.flag.mqtt_serial_raw) { // Any char between 1 and 127 or any char (0 - 255) + if ((serial_in_byte_counter < INPUT_BUFFER_SIZE -1) && // Add char to string if it still fits and ... + ((isprint(serial_in_byte) && (128 == Settings.serial_delimiter)) || // Any char between 32 and 127 + (serial_in_byte != Settings.serial_delimiter) || // Any char between 1 and 127 and not being delimiter + Settings.flag.mqtt_serial_raw)) { // Any char between 0 and 255 serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; serial_polling_window = millis(); } else { - serial_polling_window = 0; + serial_polling_window = 0; // Reception done - send mqtt break; } } @@ -2362,9 +2271,9 @@ void SerialInput(void) /*-------------------------------------------------------------------------------------------*\ * Sonoff SC 19200 baud serial interface \*-------------------------------------------------------------------------------------------*/ - if (SONOFF_SC == Settings.module) { - if (serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P - serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed + if (SONOFF_SC == my_module_type) { + if (serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P + serial_in_buffer[serial_in_byte_counter] = 0; // Serial data completed SonoffScSerialInput(serial_in_buffer); serial_in_byte_counter = 0; Serial.flush(); @@ -2375,10 +2284,9 @@ void SerialInput(void) /*-------------------------------------------------------------------------------------------*/ else if (!Settings.flag.mqtt_serial && (serial_in_byte == '\n')) { - serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed - seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (byte)LOG_LEVEL_INFO : Settings.seriallog_level; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), serial_in_buffer); - AddLog(LOG_LEVEL_INFO); + serial_in_buffer[serial_in_byte_counter] = 0; // Serial data completed + seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (uint8_t)LOG_LEVEL_INFO : Settings.seriallog_level; + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), serial_in_buffer); ExecuteCommand(serial_in_buffer, SRC_SERIAL); serial_in_byte_counter = 0; serial_polling_window = 0; @@ -2388,7 +2296,7 @@ void SerialInput(void) } if (Settings.flag.mqtt_serial && serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) { - serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed + serial_in_buffer[serial_in_byte_counter] = 0; // Serial data completed if (!Settings.flag.mqtt_serial_raw) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer); } else { @@ -2403,69 +2311,70 @@ void SerialInput(void) serial_in_byte_counter = 0; } } -/********************************************************************************************/ -void GpioSwitchPinMode(uint8_t index) -{ - if (pin[GPIO_SWT1 +index] < 99) { - pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : bitRead(switch_no_pullup, index) ? INPUT : INPUT_PULLUP); -/* - // Re-enable pull-up on Shelly2 as of 20181110 (#4255) - uint8_t no_pullup = bitRead(switch_no_pullup, index); // 0 = INPUT_PULLUP, 1 = INPUT - if (no_pullup) { - if (SHELLY2 == Settings.module) { - // Switchmodes : TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, MAX_SWITCH_OPTION - no_pullup = (Settings.switchmode[index] < PUSHBUTTON); // INPUT on TOGGLE, FOLLOW and FOLLOW_INV. INPUT_PULLUP on anything else - } - } - pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : (no_pullup) ? INPUT : INPUT_PULLUP); -*/ - } -} +/********************************************************************************************/ void GpioInit(void) { uint8_t mpin; - uint8_t key_no_pullup = 0; - mytmplt def_module; - if (Settings.module >= MAXMODULE) { + if ((Settings.module >= MAXMODULE) && (Settings.module < USER_MODULE)) { Settings.module = MODULE; Settings.last_module = MODULE; } + SetModuleType(); + if (Settings.module != Settings.last_module) { baudrate = APP_BAUDRATE; } - memcpy_P(&def_module, &kModules[Settings.module], sizeof(def_module)); - strlcpy(my_module.name, def_module.name, sizeof(my_module.name)); - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if (Settings.my_gp.io[i] > GPIO_NONE) { - my_module.gp.io[i] = Settings.my_gp.io[i]; - } - if ((def_module.gp.io[i] > GPIO_NONE) && (def_module.gp.io[i] < GPIO_USER)) { - my_module.gp.io[i] = def_module.gp.io[i]; + for (uint8_t i = 0; i < sizeof(Settings.user_template.gp); i++) { + if ((Settings.user_template.gp.io[i] >= GPIO_SENSOR_END) && (Settings.user_template.gp.io[i] < GPIO_USER)) { + Settings.user_template.gp.io[i] = GPIO_USER; // Fix not supported sensor ids in template } } - for (byte i = 0; i < GPIO_MAX; i++) { + myio def_gp; + ModuleGpios(&def_gp); + for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { + if ((Settings.my_gp.io[i] >= GPIO_SENSOR_END) && (Settings.my_gp.io[i] < GPIO_USER)) { + Settings.my_gp.io[i] = GPIO_NONE; // Fix not supported sensor ids in module + } + else if (Settings.my_gp.io[i] > GPIO_NONE) { + my_module.io[i] = Settings.my_gp.io[i]; + } + if ((def_gp.io[i] > GPIO_NONE) && (def_gp.io[i] < GPIO_USER)) { + my_module.io[i] = def_gp.io[i]; + } + } + my_module_flag = ModuleFlag(); + + for (uint16_t i = 0; i < GPIO_MAX; i++) { pin[i] = 99; } - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - mpin = ValidGPIO(i, my_module.gp.io[i]); + for (uint8_t i = 0; i < sizeof(my_module.io); i++) { + mpin = ValidPin(i, my_module.io[i]); -// snprintf_P(log_data, sizeof(log_data), PSTR("DBG: gpio pin %d, mpin %d"), i, mpin); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: gpio pin %d, mpin %d"), i, mpin); if (mpin) { if ((mpin >= GPIO_SWT1_NP) && (mpin < (GPIO_SWT1_NP + MAX_SWITCHES))) { - bitSet(switch_no_pullup, mpin - GPIO_SWT1_NP); + SwitchPullupFlag(mpin - GPIO_SWT1_NP); mpin -= (GPIO_SWT1_NP - GPIO_SWT1); } else if ((mpin >= GPIO_KEY1_NP) && (mpin < (GPIO_KEY1_NP + MAX_KEYS))) { - bitSet(key_no_pullup, mpin - GPIO_KEY1_NP); + ButtonPullupFlag(mpin - GPIO_KEY1_NP); // 0 .. 3 mpin -= (GPIO_KEY1_NP - GPIO_KEY1); } + else if ((mpin >= GPIO_KEY1_INV) && (mpin < (GPIO_KEY1_INV + MAX_KEYS))) { + ButtonInvertFlag(mpin - GPIO_KEY1_INV); // 0 .. 3 + mpin -= (GPIO_KEY1_INV - GPIO_KEY1); + } + else if ((mpin >= GPIO_KEY1_INV_NP) && (mpin < (GPIO_KEY1_INV_NP + MAX_KEYS))) { + ButtonPullupFlag(mpin - GPIO_KEY1_INV_NP); // 0 .. 3 + ButtonInvertFlag(mpin - GPIO_KEY1_INV_NP); // 0 .. 3 + mpin -= (GPIO_KEY1_INV_NP - GPIO_KEY1); + } else if ((mpin >= GPIO_REL1_INV) && (mpin < (GPIO_REL1_INV + MAX_RELAYS))) { bitSet(rel_inverted, mpin - GPIO_REL1_INV); mpin -= (GPIO_REL1_INV - GPIO_REL1); @@ -2485,7 +2394,7 @@ void GpioInit(void) #ifdef USE_DHT else if ((mpin >= GPIO_DHT11) && (mpin <= GPIO_SI7021)) { if (DhtSetup(i, mpin)) { - dht_flg = 1; + dht_flg = true; mpin = GPIO_DHT11; } else { mpin = 0; @@ -2496,7 +2405,7 @@ void GpioInit(void) if (mpin) pin[mpin] = i; } - if ((2 == pin[GPIO_TXD]) || (H801 == Settings.module)) { Serial.set_tx(2); } + if ((2 == pin[GPIO_TXD]) || (H801 == my_module_type)) { Serial.set_tx(2); } analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h) analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c) @@ -2504,14 +2413,14 @@ void GpioInit(void) #ifdef USE_SPI spi_flg = ((((pin[GPIO_SPI_CS] < 99) && (pin[GPIO_SPI_CS] > 14)) || (pin[GPIO_SPI_CS] < 12)) || (((pin[GPIO_SPI_DC] < 99) && (pin[GPIO_SPI_DC] > 14)) || (pin[GPIO_SPI_DC] < 12))); if (spi_flg) { - for (byte i = 0; i < GPIO_MAX; i++) { + for (uint16_t i = 0; i < GPIO_MAX; i++) { if ((pin[i] >= 12) && (pin[i] <=14)) pin[i] = 99; } - my_module.gp.io[12] = GPIO_SPI_MISO; + my_module.io[12] = GPIO_SPI_MISO; pin[GPIO_SPI_MISO] = 12; - my_module.gp.io[13] = GPIO_SPI_MOSI; + my_module.io[13] = GPIO_SPI_MOSI; pin[GPIO_SPI_MOSI] = 13; - my_module.gp.io[14] = GPIO_SPI_CLK; + my_module.io[14] = GPIO_SPI_CLK; pin[GPIO_SPI_CLK] = 14; } soft_spi_flg = ((pin[GPIO_SSPI_CS] < 99) && (pin[GPIO_SSPI_SCLK] < 99) && ((pin[GPIO_SSPI_MOSI] < 99) || (pin[GPIO_SSPI_MOSI] < 99))); @@ -2519,19 +2428,19 @@ void GpioInit(void) #ifdef USE_I2C i2c_flg = ((pin[GPIO_I2C_SCL] < 99) && (pin[GPIO_I2C_SDA] < 99)); - if (i2c_flg) Wire.begin(pin[GPIO_I2C_SDA], pin[GPIO_I2C_SCL]); + if (i2c_flg) { Wire.begin(pin[GPIO_I2C_SDA], pin[GPIO_I2C_SCL]); } #endif // USE_I2C devices_present = 1; light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0 if (Settings.flag.pwm_control) { - for (byte i = 0; i < MAX_PWMS; i++) { - if (pin[GPIO_PWM1 +i] < 99) light_type++; // Use Dimmer/Color control for all PWM as SetOption15 = 1 + for (uint8_t i = 0; i < MAX_PWMS; i++) { + if (pin[GPIO_PWM1 +i] < 99) { light_type++; } // Use Dimmer/Color control for all PWM as SetOption15 = 1 } } - if (SONOFF_BRIDGE == Settings.module) { + if (SONOFF_BRIDGE == my_module_type) { Settings.flag.mqtt_serial = 0; baudrate = 19200; } @@ -2539,40 +2448,43 @@ void GpioInit(void) if (XdrvCall(FUNC_MODULE_INIT)) { // Serviced } - else if (SONOFF_DUAL == Settings.module) { + else if (YTF_IR_BRIDGE == my_module_type) { + ClaimSerial(); // Stop serial loopback mode + } + else if (SONOFF_DUAL == my_module_type) { Settings.flag.mqtt_serial = 0; devices_present = 2; baudrate = 19200; } - else if (CH4 == Settings.module) { + else if (CH4 == my_module_type) { Settings.flag.mqtt_serial = 0; devices_present = 4; baudrate = 19200; } - else if (SONOFF_SC == Settings.module) { + else if (SONOFF_SC == my_module_type) { Settings.flag.mqtt_serial = 0; devices_present = 0; baudrate = 19200; } - else if (SONOFF_BN == Settings.module) { // PWM Single color led (White) + else if (SONOFF_BN == my_module_type) { // PWM Single color led (White) light_type = LT_PWM1; } - else if (SONOFF_LED == Settings.module) { // PWM Dual color led (White warm and cold) + else if (SONOFF_LED == my_module_type) { // PWM Dual color led (White warm and cold) light_type = LT_PWM2; } - else if (AILIGHT == Settings.module) { // RGBW led + else if (AILIGHT == my_module_type) { // RGBW led light_type = LT_RGBW; } - else if (SONOFF_B1 == Settings.module) { // RGBWC led + else if (SONOFF_B1 == my_module_type) { // RGBWC led light_type = LT_RGBWC; } else { - if (!light_type) devices_present = 0; - for (byte i = 0; i < MAX_RELAYS; i++) { + if (!light_type) { devices_present = 0; } + for (uint8_t i = 0; i < MAX_RELAYS; i++) { if (pin[GPIO_REL1 +i] < 99) { pinMode(pin[GPIO_REL1 +i], OUTPUT); devices_present++; - if (EXS_RELAY == Settings.module) { + if (EXS_RELAY == my_module_type) { digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0); if (i &1) { devices_present--; } } @@ -2580,25 +2492,16 @@ void GpioInit(void) } } - for (byte i = 0; i < MAX_KEYS; i++) { - if (pin[GPIO_KEY1 +i] < 99) { - pinMode(pin[GPIO_KEY1 +i], (16 == pin[GPIO_KEY1 +i]) ? INPUT_PULLDOWN_16 : bitRead(key_no_pullup, i) ? INPUT : INPUT_PULLUP); - } - } - for (byte i = 0; i < MAX_LEDS; i++) { + for (uint8_t i = 0; i < MAX_LEDS; i++) { if (pin[GPIO_LED1 +i] < 99) { pinMode(pin[GPIO_LED1 +i], OUTPUT); digitalWrite(pin[GPIO_LED1 +i], bitRead(led_inverted, i)); } } - for (byte i = 0; i < MAX_SWITCHES; i++) { - lastwallswitch[i] = 1; // Init global to virtual switch state; - if (pin[GPIO_SWT1 +i] < 99) { - GpioSwitchPinMode(i); - lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // Set global now so doesn't change the saved power state on first switch check - } - virtualswitch[i] = lastwallswitch[i]; - } + + ButtonInit(); + SwitchInit(); + RotaryInit(); #ifdef USE_WS2812 if (!light_type && (pin[GPIO_WS2812] < 99)) { // RGB led @@ -2606,8 +2509,14 @@ void GpioInit(void) light_type = LT_WS2812; } #endif // USE_WS2812 +#ifdef USE_SM16716 + if (SM16716_ModuleSelected()) { + light_type += 3; + light_type |= LT_SM16716; + } +#endif // ifdef USE_SM16716 if (!light_type) { - for (byte i = 0; i < MAX_PWMS; i++) { // Basic PWM control only + for (uint8_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only if (pin[GPIO_PWM1 +i] < 99) { pwm_present = true; pinMode(pin[GPIO_PWM1 +i], OUTPUT); @@ -2617,6 +2526,7 @@ void GpioInit(void) } SetLedPower(Settings.ledstate &8); + SetLedLink(Settings.ledstate &8); XdrvCall(FUNC_PRE_INIT); } @@ -2627,8 +2537,6 @@ extern struct rst_info resetInfo; void setup(void) { - byte idx; - RtcRebootLoad(); if (!RtcRebootValid()) { RtcReboot.fast_reboot_count = 0; } RtcReboot.fast_reboot_count++; @@ -2658,7 +2566,7 @@ void setup(void) } baudrate = Settings.baudrate * 1200; - mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START]; +// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START]; seriallog_level = Settings.seriallog_level; seriallog_timer = SERIALLOG_TIMER; syslog_level = Settings.syslog_level; @@ -2669,28 +2577,31 @@ void setup(void) Settings.flag2.emulation = 0; #endif // USE_EMULATION - // Disable functionality as possible cause of fast restart within BOOT_LOOP_TIME seconds (Exception, WDT or restarts) - if (RtcReboot.fast_reboot_count > 1) { // Restart twice - Settings.flag3.user_esp8285_enable = 0; // Disable ESP8285 Generic GPIOs interfering with flash SPI - if (RtcReboot.fast_reboot_count > 2) { // Restart 3 times - for (byte i = 0; i < MAX_RULE_SETS; i++) { - if (bitRead(Settings.rule_stop, i)) { - bitWrite(Settings.rule_enabled, i, 0); // Disable rules causing boot loop + if (Settings.param[P_BOOT_LOOP_OFFSET]) { + // Disable functionality as possible cause of fast restart within BOOT_LOOP_TIME seconds (Exception, WDT or restarts) + if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET]) { // Restart twice + Settings.flag3.user_esp8285_enable = 0; // Disable ESP8285 Generic GPIOs interfering with flash SPI + if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +1) { // Restart 3 times + for (uint8_t i = 0; i < MAX_RULE_SETS; i++) { + if (bitRead(Settings.rule_stop, i)) { + bitWrite(Settings.rule_enabled, i, 0); // Disable rules causing boot loop + } } } - } - if (RtcReboot.fast_reboot_count > 3) { // Restarted 4 times - Settings.rule_enabled = 0; // Disable all rules - } - if (RtcReboot.fast_reboot_count > 4) { // Restarted 5 times - Settings.module = SONOFF_BASIC; // Reset module to Sonoff Basic -// Settings.last_module = SONOFF_BASIC; - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - Settings.my_gp.io[i] = GPIO_NONE; // Reset user defined GPIO disabling sensors + if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +2) { // Restarted 4 times + Settings.rule_enabled = 0; // Disable all rules } + if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +3) { // Restarted 5 times + for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { + Settings.my_gp.io[i] = GPIO_NONE; // Reset user defined GPIO disabling sensors + } + } + if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +4) { // Restarted 6 times + Settings.module = SONOFF_BASIC; // Reset module to Sonoff Basic + // Settings.last_module = SONOFF_BASIC; + } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_LOG_SOME_SETTINGS_RESET " (%d)"), RtcReboot.fast_reboot_count); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_LOG_SOME_SETTINGS_RESET " (%d)"), RtcReboot.fast_reboot_count); - AddLog(LOG_LEVEL_DEBUG); } Format(mqtt_client, Settings.mqtt_client, sizeof(mqtt_client)); @@ -2708,7 +2619,7 @@ void setup(void) WifiConnect(); - if (MOTOR == Settings.module) Settings.poweronstate = POWER_ALL_ON; // Needs always on else in limbo! + if (MOTOR == my_module_type) { Settings.poweronstate = POWER_ALL_ON; } // Needs always on else in limbo! if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { SetDevicePower(1, SRC_RESTART); } else { @@ -2745,7 +2656,7 @@ void setup(void) } // Issue #526 and #909 - for (byte i = 0; i < devices_present; i++) { + for (uint8_t i = 0; i < devices_present; i++) { if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) { bitWrite(power, i, digitalRead(pin[GPIO_REL1 +i]) ^ bitRead(rel_inverted, i)); } @@ -2755,14 +2666,10 @@ void setup(void) } blink_powersave = power; - char stopic[TOPSZ]; - snprintf_P(log_data, sizeof(log_data), PSTR(D_PROJECT " %s %s " D_VERSION " %s%s-" ARDUINO_ESP8266_RELEASE), - PROJECT, Settings.friendlyname[0], my_version, my_image); - AddLog(LOG_LEVEL_INFO); -#ifdef BE_MINIMAL - snprintf_P(log_data, sizeof(log_data), PSTR(D_WARNING_MINIMAL_VERSION)); - AddLog(LOG_LEVEL_INFO); -#endif // BE_MINIMAL + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_PROJECT " %s %s " D_VERSION " %s%s-" ARDUINO_ESP8266_RELEASE), PROJECT, Settings.friendlyname[0], my_version, my_image); +#ifdef FIRMWARE_MINIMAL + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_WARNING_MINIMAL_VERSION)); +#endif // FIRMWARE_MINIMAL RtcInit(); @@ -2785,14 +2692,10 @@ void loop(void) OsWatchLoop(); - if (TimeReached(button_debounce)) { - SetNextTimeInterval(button_debounce, Settings.button_debounce); - ButtonHandler(); - } - if (TimeReached(switch_debounce)) { - SetNextTimeInterval(switch_debounce, Settings.switch_debounce); - SwitchHandler(0); - } + ButtonLoop(); + SwitchLoop(); + RotaryLoop(); + if (TimeReached(state_50msecond)) { SetNextTimeInterval(state_50msecond, 50); XdrvCall(FUNC_EVERY_50_MSECOND); @@ -2811,7 +2714,7 @@ void loop(void) XsnsCall(FUNC_EVERY_250_MSECOND); } - if (!serial_local) SerialInput(); + if (!serial_local) { SerialInput(); } #ifdef USE_ARDUINO_OTA MDNS.update(); diff --git a/sonoff/sonoff_letsencrypt.h b/sonoff/sonoff_letsencrypt.h index fa00c9f29..24735b2bd 100644 --- a/sonoff/sonoff_letsencrypt.h +++ b/sonoff/sonoff_letsencrypt.h @@ -1,7 +1,7 @@ /* sonoff_letsencrypt.h - TLS Lets Encrypt certificate for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index 12a68fe47..fe5c5c08d 100755 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -1,7 +1,7 @@ /* sonoff_post.h - Post header file for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -55,7 +55,7 @@ void KNX_CB_Action(message_t const &msg, void *arg); * Provide an image with useful supported sensors enabled \*********************************************************************************************/ -#ifdef USE_SENSORS +#ifdef FIRMWARE_SENSORS #undef CODE_IMAGE #define CODE_IMAGE 3 @@ -92,6 +92,8 @@ void KNX_CB_Action(message_t const &msg, void *arg); //#define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code) //#define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code) //#define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) +//#define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) +#define USE_SCD30 // Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) #define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code) #define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code) #ifndef CO2_LOW @@ -112,10 +114,13 @@ void KNX_CB_Action(message_t const &msg, void *arg); #define TUYA_DIMMER_ID 0 // Default dimmer Id #endif #define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer +//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger +#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) #define USE_PZEM_AC // Add support for PZEM014,016 Energy monitor (+1k1 code) #define USE_PZEM_DC // Add support for PZEM003,017 Energy monitor (+1k1 code) #define USE_MCP39F501 // Add support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code) +#define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram) #define USE_IR_HVAC // Support for HVAC system using IR (+2k code) #define USE_IR_RECEIVE // Support for IR receiver (+5k5 code, 264 iram) @@ -135,15 +140,14 @@ 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_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger -#endif // USE_SENSORS +#endif // FIRMWARE_SENSORS /*********************************************************************************************\ * [sonoff-classic.bin] * Provide an image close to version 5.12.0 but still within 499k program space to allow one time OTA \*********************************************************************************************/ -#ifdef USE_CLASSIC +#ifdef FIRMWARE_CLASSIC #undef CODE_IMAGE #define CODE_IMAGE 2 @@ -171,10 +175,6 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_SENSEAIR // Disable support for SenseAir K30, K70 and S8 CO2 sensor #undef USE_PMS5003 // Disable support for PMS5003 and PMS7003 particle concentration sensor #undef USE_NOVA_SDS // Disable support for SDS011 and SDS021 particle concentration sensor -#undef USE_PZEM004T // Disable PZEM004T energy sensor -#undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor -#undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor -#undef USE_MCP39F501 // Disable support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code) #undef USE_SERIAL_BRIDGE // Disable support for software Serial Bridge #undef USE_SDM120 // Disable support for Eastron SDM120-Modbus energy meter #undef USE_SDM630 // Disable support for Eastron SDM630-Modbus energy meter @@ -182,6 +182,13 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer +#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger +#undef USE_PN532_HSU // Disable support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) +#undef USE_PZEM004T // Disable PZEM004T energy sensor +#undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor +#undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor +#undef USE_MCP39F501 // Disable support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code) +#undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI #undef USE_IR_REMOTE // Disable IR remote commands using library IRremoteESP8266 and ArduinoJson #undef USE_IR_RECEIVE // Disable support for IR receiver #undef USE_ARILUX_RF // Disable support for Arilux RF remote controller @@ -194,15 +201,14 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code -#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger -#endif // USE_CLASSIC +#endif // FIRMWARE_CLASSIC /*********************************************************************************************\ * [sonoff-knx.bin] * Provide a dedicated KNX image allowing enough code and memory space \*********************************************************************************************/ -#ifdef USE_KNX_NO_EMULATION +#ifdef FIRMWARE_KNX_NO_EMULATION #undef CODE_IMAGE #define CODE_IMAGE 4 @@ -211,19 +217,23 @@ void KNX_CB_Action(message_t const &msg, void *arg); #define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem) #endif #undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem) -#endif // USE_KNX_NO_EMULATION +#endif // FIRMWARE_KNX_NO_EMULATION /*********************************************************************************************\ * [sonoff-display.bin] * Provide an image with display drivers enabled \*********************************************************************************************/ -#ifdef USE_DISPLAYS +#ifdef FIRMWARE_DISPLAYS #undef CODE_IMAGE #define CODE_IMAGE 6 #undef USE_ENERGY_SENSOR // Disable energy sensors (-14k code) + #undef USE_PZEM004T // Disable PZEM004T energy sensor + #undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor + #undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor + #undef USE_MCP39F501 // Disable MCP39F501 Energy monitor as used in Shelly 2 #undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem) #undef USE_DOMOTICZ // Disable Domoticz #undef USE_HOME_ASSISTANT // Disable Home Assistant @@ -241,7 +251,7 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_ARILUX_RF // Remove support for Arilux RF remote controller (-0k8 code, 252 iram (non 2.3.0)) #undef USE_RF_FLASH // Remove support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (-3k code) -#endif // USE_DISPLAYS +#endif // FIRMWARE_DISPLAYS /*********************************************************************************************\ * Mandatory define for DS18x20 if changed by above image selections @@ -257,13 +267,13 @@ void KNX_CB_Action(message_t const &msg, void *arg); * Provide an image without sensors \*********************************************************************************************/ -#ifdef USE_BASIC +#ifdef FIRMWARE_BASIC #undef CODE_IMAGE #define CODE_IMAGE 5 #undef APP_SLEEP -#define APP_SLEEP 1 // Default to sleep = 1 for USE_BASIC +#define APP_SLEEP 1 // Default to sleep = 1 for FIRMWARE_BASIC //#undef USE_ENERGY_SENSOR // Disable energy sensors #undef USE_ARDUINO_OTA // Disable support for Arduino OTA @@ -299,10 +309,13 @@ void KNX_CB_Action(message_t const &msg, void *arg); //#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer +#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger +#undef USE_PN532_HSU // Disable support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) #undef USE_PZEM004T // Disable PZEM004T energy sensor #undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor #undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor //#undef USE_MCP39F501 // Disable MCP39F501 Energy monitor as used in Shelly 2 +#undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI #undef USE_IR_REMOTE // Disable IR driver #undef USE_WS2812 // Disable WS2812 Led string #undef USE_ARILUX_RF // Disable support for Arilux RF remote controller @@ -315,15 +328,14 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code -#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger -#endif // USE_BASIC +#endif // FIRMWARE_BASIC /*********************************************************************************************\ * [sonoff-minimal.bin] * Provide the smallest image possible while still enabling a webserver for intermediate image load \*********************************************************************************************/ -#ifdef BE_MINIMAL +#ifdef FIRMWARE_MINIMAL #undef CODE_IMAGE #define CODE_IMAGE 1 @@ -362,10 +374,13 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer +#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger +#undef USE_PN532_HSU // Disable support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) #undef USE_PZEM004T // Disable PZEM004T energy sensor #undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor #undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor #undef USE_MCP39F501 // Disable MCP39F501 Energy monitor as used in Shelly 2 +#undef USE_MAX31855 // DIsable MAX31855 K-Type thermocouple sensor using softSPI #undef USE_IR_REMOTE // Disable IR driver #undef USE_WS2812 // Disable WS2812 Led string #undef USE_ARILUX_RF // Disable support for Arilux RF remote controller @@ -378,8 +393,7 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code -#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL /*********************************************************************************************\ * Mandatory defines satisfying possible disabled defines diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 48af9cf4b..c839d2a7e 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -1,7 +1,7 @@ /* sonoff_template.h - template settings for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -143,25 +143,50 @@ enum UserSelectablePins { GPIO_RF_SENSOR, // Rf receiver with sensor decoding GPIO_AZ_TXD, // AZ-Instrument 7798 Serial interface GPIO_AZ_RXD, // AZ-Instrument 7798 Serial interface - GPIO_SENSOR_END }; - -// Programmer selectable GPIO functionality offset by user selectable GPIOs -enum ProgramSelectablePins { - GPIO_RXD = GPIO_SENSOR_END, // Serial interface - GPIO_TXD, // Serial interface - GPIO_SPI_MISO, // SPI MISO library fixed pin GPIO12 - GPIO_SPI_MOSI, // SPI MOSI library fixed pin GPIO13 - GPIO_SPI_CLK, // SPI Clk library fixed pin GPIO14 + GPIO_MAX31855CS, // MAX31855 Serial interface + GPIO_MAX31855CLK, // MAX31855 Serial interface + GPIO_MAX31855DO, // MAX31855 Serial interface + GPIO_KEY1_INV, // Inverted buttons + GPIO_KEY2_INV, + GPIO_KEY3_INV, + GPIO_KEY4_INV, + GPIO_KEY1_INV_NP, // Inverted buttons without pull-up + GPIO_KEY2_INV_NP, + GPIO_KEY3_INV_NP, + GPIO_KEY4_INV_NP, GPIO_NRG_SEL, // HLW8012/HLJ-01 Sel output (1 = Voltage) GPIO_NRG_SEL_INV, // HLW8012/HLJ-01 Sel output (0 = Voltage) GPIO_NRG_CF1, // HLW8012/HLJ-01 CF1 voltage / current GPIO_HLW_CF, // HLW8012 CF power GPIO_HJL_CF, // HJL-01/BL0937 CF power - GPIO_ADC0, // ADC + GPIO_MCP39F5_TX, // MCP39F501 Serial interface (Shelly2) + GPIO_MCP39F5_RX, // MCP39F501 Serial interface (Shelly2) + GPIO_MCP39F5_RST, // MCP39F501 Reset (Shelly2) + GPIO_PN532_TXD, // PN532 NFC Serial Tx + GPIO_PN532_RXD, // PN532 NFC Serial Rx + GPIO_SM16716_CLK, // SM16716 CLOCK + GPIO_SM16716_DAT, // SM16716 DATA + GPIO_SM16716_SEL, // SM16716 SELECT GPIO_DI, // my92x1 PWM input GPIO_DCKI, // my92x1 CLK input + GPIO_CSE7766_TX, // CSE7766 Serial interface (S31 and Pow R2) + GPIO_CSE7766_RX, // CSE7766 Serial interface (S31 and Pow R2) GPIO_ARIRFRCV, // AliLux RF Receive input - GPIO_USER, // User configurable + GPIO_TXD, // Serial interface + GPIO_RXD, // Serial interface + 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_SENSOR_END }; + +// Programmer selectable GPIO functionality +enum ProgramSelectablePins { + GPIO_FIX_START = 251, + GPIO_SPI_MISO, // SPI MISO library fixed pin GPIO12 + GPIO_SPI_MOSI, // SPI MOSI library fixed pin GPIO13 + GPIO_SPI_CLK, // SPI Clk library fixed pin GPIO14 + GPIO_USER, // User configurable needs to be 255 GPIO_MAX }; // Text in webpage Module Parameters and commands GPIOS and GPIO @@ -204,7 +229,19 @@ const char kSensorNames[] PROGMEM = D_SENSOR_MGC3130_XFER "|" D_SENSOR_MGC3130_RESET "|" D_SENSOR_SSPI_MISO "|" D_SENSOR_SSPI_MOSI "|" D_SENSOR_SSPI_SCLK "|" D_SENSOR_SSPI_CS "|" D_SENSOR_SSPI_DC "|" D_SENSOR_RF_SENSOR "|" - D_SENSOR_AZ_TX "|" D_SENSOR_AZ_RX; + D_SENSOR_AZ_TX "|" D_SENSOR_AZ_RX "|" + D_SENSOR_MAX31855_CS "|" D_SENSOR_MAX31855_CLK "|" D_SENSOR_MAX31855_DO "|" + D_SENSOR_BUTTON "1i|" D_SENSOR_BUTTON "2i|" D_SENSOR_BUTTON "3i|" D_SENSOR_BUTTON "4i|" + D_SENSOR_BUTTON "1in|" D_SENSOR_BUTTON "2in|" D_SENSOR_BUTTON "3in|" D_SENSOR_BUTTON "4in|" + D_SENSOR_NRG_SEL "|" D_SENSOR_NRG_SEL "i|" D_SENSOR_NRG_CF1 "|" D_SENSOR_HLW_CF "|" D_SENSOR_HJL_CF "|" + D_SENSOR_MCP39F5_TX "|" D_SENSOR_MCP39F5_RX "|" D_SENSOR_MCP39F5_RST "|" + D_SENSOR_PN532_TX "|" D_SENSOR_PN532_RX "|" + D_SENSOR_SM16716_CLK "|" D_SENSOR_SM16716_DAT "|" D_SENSOR_SM16716_POWER "|" + D_SENSOR_MY92X1_DI "|" D_SENSOR_MY92X1_DCKI "|" + 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|" + ; /********************************************************************************************/ @@ -270,11 +307,23 @@ enum SupportedModules { PS_16_DZ, TECKIN_US, MANZOKU_EU_4, + OBI2, + YTF_IR_BRIDGE, + DIGOO, + KA10, + ZX2820, + MI_DESK_LAMP, + SP10, + WAGA, + SYF05, MAXMODULE }; +#define USER_MODULE 255 + /********************************************************************************************/ -#define MAX_GPIO_PIN 18 // Number of supported GPIO +#define MAX_GPIO_PIN 17 // Number of supported GPIO +#define MIN_FLASH_PINS 4 // Number of flash chip pins unusable for configuration (GPIO6, 7, 8 and 11) const char PINS_WEMOS[] PROGMEM = "D3TXD4RXD2D1flashcFLFLolD6D7D5D8D0A0"; @@ -282,21 +331,59 @@ typedef struct MYIO { uint8_t io[MAX_GPIO_PIN]; } myio; +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_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 + +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 spare02 : 1; + uint8_t spare03 : 1; + uint8_t spare04 : 1; + uint8_t spare05 : 1; + uint8_t spare06 : 1; + uint8_t spare07 : 1; + }; +} gpio_flag; + typedef struct MYTMPLT { char name[15]; - myio gp; + mycfgio gp; + gpio_flag flag; } mytmplt; const uint8_t kGpioNiceList[] PROGMEM = { GPIO_NONE, // Not used GPIO_KEY1, // Buttons GPIO_KEY1_NP, + GPIO_KEY1_INV, + GPIO_KEY1_INV_NP, GPIO_KEY2, GPIO_KEY2_NP, + GPIO_KEY2_INV, + GPIO_KEY2_INV_NP, GPIO_KEY3, GPIO_KEY3_NP, + GPIO_KEY3_INV, + GPIO_KEY3_INV_NP, GPIO_KEY4, GPIO_KEY4_NP, + GPIO_KEY4_INV, + GPIO_KEY4_INV_NP, GPIO_SWT1, // User connected external switches GPIO_SWT1_NP, GPIO_SWT2, @@ -355,6 +442,8 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_CNTR3_NP, GPIO_CNTR4, GPIO_CNTR4_NP, + GPIO_TXD, // Serial interface + GPIO_RXD, // Serial interface #ifdef USE_I2C GPIO_I2C_SCL, // I2C SCL GPIO_I2C_SDA, // I2C SDA @@ -404,21 +493,19 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_HX711_SCK, // HX711 Load Cell clock GPIO_HX711_DAT, // HX711 Load Cell data #endif -#ifdef USE_SERIAL_BRIDGE - GPIO_SBR_TX, // Serial Bridge Serial interface - GPIO_SBR_RX, // Serial Bridge Serial interface +#if defined(USE_ENERGY_SENSOR) && defined(USE_HLW8012) + GPIO_NRG_SEL, // HLW8012/HLJ-01 Sel output (1 = Voltage) + GPIO_NRG_SEL_INV, // HLW8012/HLJ-01 Sel output (0 = Voltage) + GPIO_NRG_CF1, // HLW8012/HLJ-01 CF1 voltage / current + GPIO_HLW_CF, // HLW8012 CF power + GPIO_HJL_CF, // HJL-01/BL0937 CF power #endif -#ifdef USE_MHZ19 - GPIO_MHZ_TXD, // MH-Z19 Serial interface - GPIO_MHZ_RXD, // MH-Z19 Serial interface -#endif -#ifdef USE_SENSEAIR - GPIO_SAIR_TX, // SenseAir Serial interface - GPIO_SAIR_RX, // SenseAir Serial interface -#endif -#ifdef USE_NOVA_SDS - GPIO_SDS0X1_TX, // Nova Fitness SDS011 Serial interface - GPIO_SDS0X1_RX, // Nova Fitness SDS011 Serial interface + GPIO_CSE7766_TX, // CSE7766 Serial interface (S31 and Pow R2) + GPIO_CSE7766_RX, // CSE7766 Serial interface (S31 and Pow R2) +#if defined(USE_ENERGY_SENSOR) && defined(USE_MCP39F501) + GPIO_MCP39F5_TX, // MCP39F501 Serial interface (Shelly2) + GPIO_MCP39F5_RX, // MCP39F501 Serial interface (Shelly2) + GPIO_MCP39F5_RST, // MCP39F501 Reset (Shelly2) #endif #if defined(USE_PZEM004T) || defined(USE_PZEM_AC) || defined(USE_PZEM_DC) GPIO_PZEM0XX_TX, // PZEM0XX Serial interface @@ -440,6 +527,22 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_SDM630_TX, // SDM630 Serial interface GPIO_SDM630_RX, // SDM630 Serial interface #endif +#ifdef USE_SERIAL_BRIDGE + GPIO_SBR_TX, // Serial Bridge Serial interface + GPIO_SBR_RX, // Serial Bridge Serial interface +#endif +#ifdef USE_MHZ19 + GPIO_MHZ_TXD, // MH-Z19 Serial interface + GPIO_MHZ_RXD, // MH-Z19 Serial interface +#endif +#ifdef USE_SENSEAIR + GPIO_SAIR_TX, // SenseAir Serial interface + GPIO_SAIR_RX, // SenseAir Serial interface +#endif +#ifdef USE_NOVA_SDS + GPIO_SDS0X1_TX, // Nova Fitness SDS011 Serial interface + GPIO_SDS0X1_RX, // Nova Fitness SDS011 Serial interface +#endif #ifdef USE_PMS5003 GPIO_PMS5003, // Plantower PMS5003 Serial interface #endif @@ -451,16 +554,37 @@ const uint8_t kGpioNiceList[] PROGMEM = { #endif #ifdef USE_TUYA_DIMMER GPIO_TUYA_TX, // Tuya Serial interface - GPIO_TUYA_RX, // Tuya Serial interface -#endif -#ifdef USE_MGC3130 - GPIO_MGC3130_XFER, - GPIO_MGC3130_RESET + GPIO_TUYA_RX, // Tuya Serial interface #endif #ifdef USE_AZ7798 GPIO_AZ_TXD, // AZ-Instrument 7798 CO2 datalogger Serial interface - GPIO_AZ_RXD // AZ-Instrument 7798 CO2 datalogger Serial interface + GPIO_AZ_RXD, // AZ-Instrument 7798 CO2 datalogger Serial interface #endif +#ifdef USE_PN532_HSU + GPIO_PN532_TXD, // PN532 HSU Tx + GPIO_PN532_RXD, // PN532 HSU Rx +#endif +#ifdef USE_MGC3130 + GPIO_MGC3130_XFER, + GPIO_MGC3130_RESET, +#endif +#ifdef USE_MAX31855 + GPIO_MAX31855CS, // MAX31855 Serial interface + GPIO_MAX31855CLK, // MAX31855 Serial interface + GPIO_MAX31855DO, // MAX31855 Serial interface +#endif + GPIO_DI, // my92x1 PWM input + GPIO_DCKI, // my92x1 CLK input +#ifdef USE_SM16716 + GPIO_SM16716_CLK, // SM16716 CLOCK + GPIO_SM16716_DAT, // SM16716 DATA + GPIO_SM16716_SEL, // SM16716 SELECT +#endif // USE_SM16716 + 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 }; const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { @@ -499,30 +623,39 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { WION, SHELLY1, SHELLY2, - BLITZWOLF_BWSHP, // Socket Relay Devices with Energy Monitoring + BLITZWOLF_BWSHP, // Socket Relay Devices with Energy Monitoring TECKIN, TECKIN_US, APLIC_WDP303075, GOSUND, + ZX2820, SK03_TUYA, - NEO_COOLCAM, // Socket Relay Devices + DIGOO, + KA10, + SP10, + WAGA, + NEO_COOLCAM, // Socket Relay Devices OBI, + OBI2, MANZOKU_EU_4, - ESP_SWITCH, // Switch Devices - TUYA_DIMMER, // Dimmer Devices + ESP_SWITCH, // Switch Devices + TUYA_DIMMER, // Dimmer Devices ARMTRONIX_DIMMERS, PS_16_DZ, - H801, // Light Devices + H801, // Light Devices MAGICHOME, ARILUX_LC01, ARILUX_LC06, ARILUX_LC11, ZENGGE_ZF_WF017, HUAFAN_SS, + MI_DESK_LAMP, KMC_70011, - AILIGHT, // Light Bulbs + AILIGHT, // Light Bulbs PHILIPS, - WITTY, // Development Devices + SYF05, + YTF_IR_BRIDGE, + WITTY, // Development Devices WEMOS }; @@ -535,14 +668,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_USER, // GPIO04 Optional sensor 0, // GPIO05 - 0, // GPIO06 (SD_CLK Flash) - 0, // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) - 0, // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) - 0, // GPIO09 (SD_DATA2 Flash QIO) - 0, // GPIO10 (SD_DATA3 Flash QIO) - 0, // GPIO11 (SD_CMD Flash) + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) - Link and Power status GPIO_USER, // GPIO14 Optional sensor 0, // GPIO15 0, // GPIO16 @@ -551,13 +684,18 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { { "Sonoff RF", // Sonoff RF (ESP8266) GPIO_KEY1, // GPIO00 Button GPIO_USER, // GPIO01 Serial RXD and Optional sensor - 0, + GPIO_USER, // GPIO02 Optional sensor GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_USER, // GPIO04 Optional sensor 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) - Link and Power status GPIO_USER, // GPIO14 Optional sensor 0, 0, 0 }, @@ -568,12 +706,17 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_USER, // GPIO04 Optional sensor GPIO_USER, // GPIO05 Optional sensor - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) - Link and Power status GPIO_USER, // GPIO14 Optional sensor 0, 0, - GPIO_ADC0 // ADC0 Analog input + GPIO_FLAG_ADC0 // ADC0 Analog input }, { "Sonoff TH", // Sonoff TH10/16 (ESP8266) GPIO_KEY1, // GPIO00 Button @@ -582,9 +725,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_USER, // GPIO04 Optional sensor 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) - Link and Power status GPIO_USER, // GPIO14 Optional sensor 0, 0, 0 }, @@ -595,9 +743,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_RXD, // GPIO03 Relay control GPIO_USER, // GPIO04 Optional sensor 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) 0, - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status GPIO_USER, // GPIO14 Optional sensor 0, 0, 0 }, @@ -605,11 +758,16 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_KEY1, // GPIO00 Button 0, 0, 0, 0, GPIO_NRG_SEL, // GPIO05 HLW8012 Sel output (1 = Voltage) - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) GPIO_NRG_CF1, // GPIO13 HLW8012 CF1 voltage / current GPIO_HLW_CF, // GPIO14 HLW8012 CF power - GPIO_LED1, // GPIO15 Blue Led (0 = On, 1 = Off) + GPIO_LED1, // GPIO15 Blue Led (0 = On, 1 = Off) - Link and Power status 0, 0 }, { "Sonoff 4CH", // Sonoff 4CH (ESP8285) @@ -619,11 +777,13 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_REL3, // GPIO04 Sonoff 4CH Red Led and Relay 3 (0 = Off, 1 = On) GPIO_REL2, // GPIO05 Sonoff 4CH Red Led and Relay 2 (0 = Off, 1 = On) - 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) GPIO_KEY2, // GPIO09 Button 2 GPIO_KEY3, // GPIO10 Button 3 - 0, // Flash connection - GPIO_REL1, // GPIO12 Red Led and Relay 1 (0 = Off, 1 = On) + // GPIO11 (SD_CMD Flash) + GPIO_REL1, // GPIO12 Red Led and Relay 1 (0 = Off, 1 = On) - Link and Power status GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) GPIO_KEY4, // GPIO14 Button 4 GPIO_REL4, // GPIO15 Red Led and Relay 4 (0 = Off, 1 = On) @@ -635,8 +795,13 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO02 Optional sensor GPIO_USER, // GPIO03 Serial TXD and Optional sensor 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection - GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - Link and Power status GPIO_LED1_INV, // GPIO13 Green/Blue Led (0 = On, 1 = Off) 0, 0, 0, 0 }, @@ -646,9 +811,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, GPIO_USER, // GPIO03 Serial TXD and Optional sensor 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "Sonoff Touch", // Sonoff Touch (ESP8285) @@ -657,10 +827,13 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, GPIO_USER, // GPIO03 Serial TXD and Optional sensor 0, 0, - 0, 0, 0, // Flash connection - 0, 0, - 0, // Flash connection - GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 + 0, // GPIO10 + // GPIO11 (SD_CMD Flash) + GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - Link and Power status GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) 0, 0, 0, 0 }, @@ -669,9 +842,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0, 0, GPIO_USER, // GPIO04 Optional sensor (PWM3 Green) GPIO_USER, // GPIO05 Optional sensor (PWM2 Red) - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM1, // GPIO12 Cold light (PWM0 Cold) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status GPIO_PWM2, // GPIO14 Warm light (PWM1 Warm) GPIO_USER, // GPIO15 Optional sensor (PWM4 Blue) 0, 0 @@ -679,9 +857,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { { "1 Channel", // 1 Channel Inching/Latching Relay using (PSA-B01 - ESP8266 and PSF-B01 - ESP8285) GPIO_KEY1, // GPIO00 Button 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "4 Channel", // 4 Channel Inching/Latching Relays (ESP8266) @@ -690,17 +873,27 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, GPIO_RXD, // GPIO03 Relay control 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) 0, - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "Motor C/AC", // Motor Clockwise / Anti clockwise (PSA-B01 - ESP8266) GPIO_KEY1, // GPIO00 Button 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "ElectroDragon", // ElectroDragon IoT Relay Board (ESP8266) @@ -710,13 +903,18 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_USER, // GPIO04 Optional sensor GPIO_USER, // GPIO05 Optional sensor - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL2, // GPIO12 Red Led and Relay 2 (0 = Off, 1 = On) GPIO_REL1, // GPIO13 Red Led and Relay 1 (0 = Off, 1 = On) GPIO_USER, // GPIO14 Optional sensor GPIO_USER, // GPIO15 Optional sensor - GPIO_LED1, // GPIO16 Green/Blue Led (1 = On, 0 = Off) - GPIO_ADC0 // ADC0 A0 Analog input + GPIO_LED1, // GPIO16 Green/Blue Led (1 = On, 0 = Off) - Link and Power status + GPIO_FLAG_ADC0 // ADC0 A0 Analog input }, { "EXS Relay(s)", // ES-Store Latching relay(s) (ESP8266) // https://ex-store.de/ESP8266-WiFi-Relay-V31 @@ -728,11 +926,16 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 UART0_RXD V3.1 Module Pin 3 GPIO_USER, // GPIO04 V3.1 Module Pin 10 - V5.0 Module Pin 2 GPIO_USER, // GPIO05 V3.1 Module Pin 9 - V5.0 Module Pin 1 - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Relay1 ( 1 = Off) GPIO_REL2, // GPIO13 Relay1 ( 1 = On) GPIO_USER, // GPIO14 V3.1 Module Pin 5 - V5.0 GPIO_REL3_INV Relay2 ( 1 = Off) - GPIO_LED1, // GPIO15 V5.0 LED1 + GPIO_LED1, // GPIO15 V5.0 LED1 - Link and Power status GPIO_USER, // GPIO16 V3.1 Module Pin 4 - V5.0 GPIO_REL4_INV Relay2 ( 1 = On) 0 }, @@ -740,9 +943,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { // https://www.amazon.com/gp/product/B00ZYLUBJU/ref=s9_acsd_al_bw_c_x_3_w GPIO_USER, // GPIO00 Optional sensor (pm clock) 0, - GPIO_LED1, // GPIO02 Green Led (1 = On, 0 = Off) + GPIO_LED1, // GPIO02 Green Led (1 = On, 0 = Off) - Link and Power status 0, 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_USER, // GPIO12 Optional sensor (pm data) GPIO_KEY1, // GPIO13 Button 0, @@ -756,16 +964,18 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 RX Serial TXD and Optional sensor GPIO_USER, // GPIO04 D2 Wemos I2C SDA GPIO_USER, // GPIO05 D1 Wemos I2C SCL / Wemos Relay Shield (0 = Off, 1 = On) / Wemos WS2812B RGB led Shield - 0, 0, 0, // Flash connection - GPIO_USER, // Flash connection or GPIO09 on ESP8285 only! - GPIO_USER, // Flash connection or GPIO10 on ESP8285 only! - 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + GPIO_USER, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + GPIO_USER, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_USER, // GPIO12 D6 GPIO_USER, // GPIO13 D7 GPIO_USER, // GPIO14 D5 GPIO_USER, // GPIO15 D8 GPIO_USER, // GPIO16 D0 Wemos Wake - GPIO_ADC0 // ADC0 A0 Analog input + GPIO_FLAG_ADC0 // ADC0 A0 Analog input }, { "Sonoff Dev", // Sonoff Dev (ESP8266) GPIO_KEY1, // GPIO00 E-FW Button @@ -774,22 +984,32 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 RX Serial TXD and Optional sensor GPIO_USER, // GPIO04 Optional sensor GPIO_USER, // GPIO05 Optional sensor - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_USER, // GPIO12 GPIO_USER, // GPIO13 BLUE LED GPIO_USER, // GPIO14 Optional sensor 0, // GPIO15 0, // GPIO16 - GPIO_ADC0 // ADC0 A0 Analog input + GPIO_FLAG_ADC0 // ADC0 A0 Analog input }, { "H801", // Lixada H801 Wifi (ESP8266) GPIO_USER, // GPIO00 E-FW Button - GPIO_LED1, // GPIO01 Green LED + GPIO_LED1, // GPIO01 Green LED - Link and Power status GPIO_USER, // GPIO02 TX and Optional sensor - Pin next to TX on the PCB GPIO_USER, // GPIO03 RX and Optional sensor - Pin next to GND on the PCB GPIO_PWM5, // GPIO04 W2 - PWM5 GPIO_LED2_INV, // GPIO05 Red LED - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM3, // GPIO12 Blue GPIO_PWM2, // GPIO13 Green GPIO_PWM4, // GPIO14 W1 - PWM4 @@ -802,20 +1022,27 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO02 Optional sensor GPIO_RXD, // GPIO03 TXD to ATMEGA328P 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) 0, - GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "Sonoff BN-SZ", // Sonoff BN-SZ01 Ceiling led (ESP8285) 0, 0, 0, 0, 0, 0, - 0, 0, 0, // Flash connection - 0, 0, - 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 + 0, // GPIO10 + // GPIO11 (SD_CMD Flash) GPIO_PWM1, // GPIO12 Light - GPIO_LED1_INV, // GPIO13 Red Led (0 = On, 1 = Off) - 0, 0, - 0, 0 + GPIO_LED1_INV, // GPIO13 Red Led (0 = On, 1 = Off) - Link and Power status + 0, 0, 0, 0 }, { "Sonoff 4CH Pro", // Sonoff 4CH Pro (ESP8285) GPIO_KEY1, // GPIO00 Button 1 @@ -824,23 +1051,30 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_REL3, // GPIO04 Sonoff 4CH Red Led and Relay 3 (0 = Off, 1 = On) GPIO_REL2, // GPIO05 Sonoff 4CH Red Led and Relay 2 (0 = Off, 1 = On) - 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) GPIO_KEY2, // GPIO09 Button 2 GPIO_KEY3, // GPIO10 Button 3 - 0, // Flash connection + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay 1 (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status GPIO_KEY4, // GPIO14 Button 4 GPIO_REL4, // GPIO15 Red Led and Relay 4 (0 = Off, 1 = On) 0, 0 }, { "Huafan SS", // Hua Fan Smart Socket (ESP8266) - like Sonoff Pow - GPIO_LED1_INV, // GPIO0 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO00 Blue Led (0 = On, 1 = Off) - Link status 0, 0, - GPIO_LED2_INV, // GPIO3 Red Led (0 = On, 1 = Off) - GPIO_KEY1, // GPIO4 Button - GPIO_REL1_INV, // GPIO5 Relay (0 = On, 1 = Off) - 0, 0, 0, 0, 0, 0, // Flash connection + GPIO_LED2_INV, // GPIO03 Red Led (0 = On, 1 = Off) - Power status + GPIO_KEY1, // GPIO04 Button + GPIO_REL1_INV, // GPIO05 Relay (0 = On, 1 = Off) + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_NRG_CF1, // GPIO12 HLW8012 CF1 voltage / current GPIO_NRG_SEL, // GPIO13 HLW8012 Sel output (1 = Voltage) GPIO_HLW_CF, // GPIO14 HLW8012 CF power @@ -853,12 +1087,16 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_RXD, // GPIO03 RF bridge control GPIO_USER, // GPIO04 Optional sensor GPIO_USER, // GPIO05 Optional sensor - 0, 0, 0, // Flash connection - 0, 0, - 0, // Flash connection - 0, - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - 0, 0, 0, 0 + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 + 0, // GPIO10 + // GPIO11 (SD_CMD Flash) + GPIO_USER, // GPIO12 Optional sensor + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status + GPIO_USER, // GPIO14 Optional sensor + 0, 0, 0 }, { "Sonoff B1", // Sonoff B1 (ESP8285 - my9231) GPIO_KEY1, // GPIO00 Pad @@ -866,9 +1104,12 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO02 Optional sensor SDA pad GPIO_USER, // GPIO03 Serial TXD and Optional sensor pad 0, 0, - 0, 0, 0, // Flash connection - 0, 0, - 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 + 0, // GPIO10 + // GPIO11 (SD_CMD Flash) GPIO_DI, // GPIO12 my9231 DI 0, GPIO_DCKI, // GPIO14 my9231 DCKI @@ -880,9 +1121,12 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO02 Optional sensor SDA pad GPIO_USER, // GPIO03 Serial TXD and Optional sensor pad 0, 0, - 0, 0, 0, // Flash connection - 0, 0, - 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) 0, GPIO_DI, // GPIO13 my9291 DI 0, @@ -895,11 +1139,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO02 Optional Sensor (J3 Pin 5) GPIO_USER, // GPIO03 Serial TXD and Optional sensor 0, 0, - 0, 0, 0, // Flash connection - 0, 0, - 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 + 0, // GPIO10 + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Blue Led and Relay 1 (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "Sonoff T1 2CH", // Sonoff T1 2CH (ESP8285) @@ -909,12 +1156,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor 0, GPIO_REL2, // GPIO05 Blue Led and Relay 2 (0 = Off, 1 = On) - 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) GPIO_KEY2, // GPIO09 Button 2 - 0, - 0, // Flash connection + 0, // GPIO10 + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Blue Led and Relay 1 (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "Sonoff T1 3CH", // Sonoff T1 3CH (ESP8285) @@ -924,12 +1173,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_REL3, // GPIO04 Blue Led and Relay 3 (0 = Off, 1 = On) GPIO_REL2, // GPIO05 Blue Led and Relay 2 (0 = Off, 1 = On) - 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) GPIO_KEY2, // GPIO09 Button 2 GPIO_KEY3, // GPIO10 Button 3 - 0, // Flash connection + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Blue Led and Relay 1 (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "Supla Espablo", // Supla Espablo (ESP8266) @@ -940,55 +1191,75 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_KEY1, // GPIO04 Button 1 GPIO_REL1, // GPIO05 Relay 1 (0 = Off, 1 = On) - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_USER, // GPIO12 Optional sensor GPIO_REL2, // GPIO13 Relay 2 (0 = Off, 1 = On) GPIO_USER, // GPIO14 Optional sensor 0, - GPIO_LED1, // GPIO16 Led (1 = On, 0 = Off) - GPIO_ADC0 // ADC0 A0 Analog input + GPIO_LED1, // GPIO16 Led (1 = On, 0 = Off) - Link and Power status + GPIO_FLAG_ADC0 // ADC0 A0 Analog input }, { "Witty Cloud", // Witty Cloud Dev Board (ESP8266) // https://www.aliexpress.com/item/ESP8266-serial-WIFI-Witty-cloud-Development-Board-ESP-12F-module-MINI-nodemcu/32643464555.html GPIO_USER, // GPIO00 D3 flash push button on interface board GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED1_INV, // GPIO02 D4 Blue Led (0 = On, 1 = Off) on ESP-12F + GPIO_LED1_INV, // GPIO02 D4 Blue Led (0 = On, 1 = Off) on ESP-12F - Link and Power status GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_KEY1, // GPIO04 D2 push button on ESP-12F board GPIO_USER, // GPIO05 D1 optional sensor - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM2, // GPIO12 D6 RGB LED Green GPIO_PWM3, // GPIO13 D7 RGB LED Blue GPIO_USER, // GPIO14 D5 optional sensor GPIO_PWM1, // GPIO15 D8 RGB LED Red GPIO_USER, // GPIO16 D0 optional sensor - GPIO_ADC0 // ADC0 A0 Light sensor / Requires USE_ADC_VCC in user_config.h to be disabled + GPIO_FLAG_ADC0 // ADC0 A0 Light sensor / Requires USE_ADC_VCC in user_config.h to be disabled }, { "Yunshan Relay", // Yunshan Wifi Relay (ESP8266) // https://www.ebay.com/p/Esp8266-220v-10a-Network-Relay-WiFi-Module/1369583381 // Schematics and Info https://ucexperiment.wordpress.com/2016/12/18/yunshan-esp8266-250v-15a-acdc-network-wifi-relay-module/ 0, // GPIO00 Flash jumper - Module Pin 8 GPIO_USER, // GPIO01 Serial RXD and Optional sensor - Module Pin 2 - GPIO_LED1_INV, // GPIO02 Blue Led (0 = On, 1 = Off) on ESP-12F - Module Pin 7 + GPIO_LED1_INV, // GPIO02 Blue Led (0 = On, 1 = Off) on ESP-12F - Module Pin 7 - Link and Power status GPIO_USER, // GPIO03 Serial TXD and Optional sensor - Module Pin 3 GPIO_REL1, // GPIO04 Red Led and Relay (0 = Off, 1 = On) - Module Pin 10 GPIO_KEY1, // GPIO05 Blue Led and OptoCoupler input - Module Pin 9 - 0, 0, 0, 0, 0, 0, // Flash connection - 0, 0, 0, 0, 0 + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + 0, 0, 0, 0, 0, 0 }, { "MagicHome", // Magic Home (aka Flux-light) (ESP8266) and Arilux LC10 (ESP8285) // https://www.aliexpress.com/item/Magic-Home-Mini-RGB-RGBW-Wifi-Controller-For-Led-Strip-Panel-light-Timing-Function-16million-colors/32686853650.html 0, GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED1_INV, // GPIO02 Blue onboard LED + GPIO_LED1_INV, // GPIO02 Blue onboard LED - Link and Power status GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_ARIRFRCV, // GPIO04 IR or RF receiver (optional) (Arilux LC10) GPIO_PWM2, // GPIO05 RGB LED Green - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM3, // GPIO12 RGB LED Blue GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White as used on Arilux LC10) GPIO_PWM1, // GPIO14 RGB LED Red - GPIO_LED2_INV, // GPIO15 RF receiver control (Arilux LC10) + GPIO_LED4_INV, // GPIO15 RF receiver control (Arilux LC10) 0, 0 }, { "Luani HVIO", // ESP8266_HVIO @@ -999,13 +1270,18 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_REL1, // GPIO04 Relay 1 (0 = Off, 1 = On) GPIO_REL2, // GPIO05 Relay 2 (0 = Off, 1 = On) - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_SWT1, // GPIO12 External input 1 (0 = On, 1 = Off) GPIO_SWT2, // GPIO13 External input 2 (0 = On, 1 = Off) GPIO_USER, // GPIO14 Optional sensor / I2C SCL pad - GPIO_LED1, // GPIO15 Led (1 = On, 0 = Off) + GPIO_LED1, // GPIO15 Led (1 = On, 0 = Off) - Link and Power status 0, - GPIO_ADC0 // ADC0 A0 Analog input + GPIO_FLAG_ADC0 // ADC0 A0 Analog input }, { "KMC 70011", // KMC 70011 // https://www.amazon.com/KMC-Timing-Monitoring-Network-125V-240V/dp/B06XRX2GTQ @@ -1013,9 +1289,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0, 0, GPIO_HLW_CF, // GPIO04 HLW8012 CF power GPIO_NRG_CF1, // GPIO05 HLW8012 CF1 voltage / current - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL, // GPIO12 HLW8012 SEL (1 = Voltage) - GPIO_LED1_INV, // GPIO13 Green Led + GPIO_LED1_INV, // GPIO13 Green Led - Link and Power status GPIO_REL1, // GPIO14 Relay 0, 0, 0 }, @@ -1024,11 +1305,16 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { // (PwmFrequency 1111Hz) GPIO_KEY1, // GPIO00 Optional Button GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED2_INV, // GPIO02 RF receiver control + GPIO_LED4_INV, // GPIO02 RF receiver control GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_ARIRFRCV, // GPIO04 IR or RF receiver (optional) GPIO_PWM1, // GPIO05 RGB LED Red - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM2, // GPIO12 RGB LED Green GPIO_PWM3, // GPIO13 RGB LED Blue GPIO_USER, // GPIO14 RGBW LED White (optional - set to PWM4 for Cold White or Warm White) @@ -1039,11 +1325,16 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { // (PwmFrequency 540Hz) GPIO_KEY1, // GPIO00 Optional Button GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED2_INV, // GPIO02 RF receiver control + GPIO_LED4_INV, // GPIO02 RF receiver control GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_PWM2, // GPIO04 RGB LED Green GPIO_PWM1, // GPIO05 RGB LED Red - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM5, // GPIO12 RGBCW LED Warm GPIO_PWM4, // GPIO13 RGBW LED Cold GPIO_PWM3, // GPIO14 RGB LED Blue @@ -1057,12 +1348,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor 0, GPIO_REL2, // GPIO05 Relay 2 (0 = Off, 1 = On) - 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) GPIO_USER, // GPIO09 Button 1 on header (0 = On, 1 = Off) GPIO_KEY1, // GPIO10 Button on casing - 0, // Flash connection + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Relay 1 (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "Arilux LC06", // Arilux AL-LC06 (ESP8285) @@ -1073,7 +1366,12 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_USER, // GPIO04 W2 - PWM5 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM2, // GPIO12 RGB LED Green GPIO_PWM3, // GPIO13 RGB LED Blue GPIO_PWM1, // GPIO14 RGB LED Red @@ -1082,13 +1380,18 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { }, { "Sonoff S31", // Sonoff S31 (ESP8266 - CSE7766) GPIO_KEY1, // GPIO00 Button - 0, // GPIO01 Serial RXD 4800 baud 8E1 CSE7766 energy sensor + GPIO_CSE7766_TX, // GPIO01 Serial RXD 4800 baud 8E1 CSE7766 energy sensor 0, - 0, // GPIO03 Serial TXD + GPIO_CSE7766_RX, // GPIO03 Serial TXD 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "Zengge WF017", // Zenggee ZJ-WF017-A (ESP12S)) @@ -1099,7 +1402,12 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, GPIO_USER, // GPIO04 W2 - PWM5 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM2, // GPIO12 RGB LED Green GPIO_PWM1, // GPIO13 RGB LED Red GPIO_PWM3, // GPIO14 RGB LED Blue @@ -1107,13 +1415,18 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { }, { "Sonoff Pow R2", // Sonoff Pow R2 (ESP8285 - CSE7766) GPIO_KEY1, // GPIO00 Button - 0, // GPIO01 Serial RXD 4800 baud 8E1 CSE7766 energy sensor + GPIO_CSE7766_TX, // GPIO01 Serial RXD 4800 baud 8E1 CSE7766 energy sensor 0, - 0, // GPIO03 Serial TXD + GPIO_CSE7766_RX, // GPIO03 Serial TXD 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 }, { "Sonoff iFan02", // Sonoff iFan02 (ESP8285) @@ -1123,12 +1436,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 ESP_RXD Serial TXD and Optional sensor GPIO_REL3, // GPIO04 WIFI_O2 Relay 3 (0 = Off, 1 = On) controlling the fan GPIO_REL2, // GPIO05 WIFI_O1 Relay 2 (0 = Off, 1 = On) controlling the fan - 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) GPIO_KEY2, // GPIO09 WIFI_KEY1 Virtual button 2 as feedback from RC GPIO_KEY3, // GPIO10 WIFI_KEY2 Virtual button 3 as feedback from RC - 0, // Flash connection + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 WIFI_O0 Relay 1 (0 = Off, 1 = On) controlling the light - GPIO_LED1_INV, // GPIO13 WIFI_CHK Blue Led on PCA (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 WIFI_CHK Blue Led on PCA (0 = On, 1 = Off) - Link and Power status GPIO_KEY4, // GPIO14 WIFI_KEY3 Virtual button 4 as feedback from RC GPIO_REL4, // GPIO15 WIFI_O3 Relay 4 (0 = Off, 1 = On) controlling the fan 0, 0 @@ -1138,43 +1453,67 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { // https://www.amazon.de/Steckdose-Homecube-intelligente-Verbrauchsanzeige-funktioniert/dp/B076Q2LKHG/ref=sr_1_fkmr0_1 // https://www.amazon.de/Intelligente-Stromverbrauch-Fernsteurung-Schaltbare-Energieklasse/dp/B076WZQS4S/ref=sr_1_1 // https://www.aliexpress.com/store/product/BlitzWolf-BW-SHP6-EU-Plug-Metering-Version-WIFI-Smart-Socket-220V-240V-10A-Work-with-Amazon/1965360_32945504669.html - GPIO_LED2_INV, // GPIO00 Red Led (1 = On, 0 = Off) + GPIO_LED2_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off) + GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status GPIO_USER, // GPIO03 Serial TXD and Optional sensor 0, GPIO_HJL_CF, // GPIO05 BL0937 or HJL-01 CF power - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) GPIO_KEY1, // GPIO13 Button GPIO_NRG_CF1, // GPIO14 BL0937 or HJL-01 CF1 current / voltage GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On) 0, 0 }, - { "Shelly 1", // Shelly1 Open Source (ESP8266 - 2MB) - https://shelly.cloud/shelly1-open-source/ - 0, 0, 0, 0, - GPIO_REL1, // GPIO04 Relay (0 = Off, 1 = On) - GPIO_SWT1_NP, // GPIO05 SW pin - 0, 0, 0, 0, 0, 0, // Flash connection + { "Shelly 1", // Shelly1 Open Source (ESP8266 - 2MB) - https://shelly.cloud/shelly1-open-source/ + GPIO_USER, // GPIO00 - Only to be used when Shelly is connected to 12V DC + GPIO_USER, // GPIO01 Serial RXD - Only to be used when Shelly is connected to 12V DC + 0, + GPIO_USER, // GPIO03 Serial TXD - Only to be used when Shelly is connected to 12V DC + GPIO_REL1, // GPIO04 Relay (0 = Off, 1 = On) + GPIO_SWT1_NP, // GPIO05 SW pin + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) 0, 0, 0, 0, 0, 0 }, - { "Shelly 2", // Shelly2 (ESP8266 - 2MB) - https://shelly.cloud/shelly2/ + { "Shelly 2", // Shelly2 (ESP8266 - 2MB) - https://shelly.cloud/shelly2/ 0, - GPIO_TXD, // GPIO01 MCP39F501 Serial input + GPIO_MCP39F5_TX, // GPIO01 MCP39F501 Serial input 0, - GPIO_RXD, // GPIO03 MCP39F501 Serial output - GPIO_REL1, // GPIO04 - GPIO_REL2, // GPIO05 - 0, 0, 0, 0, 0, 0, // Flash connection - GPIO_SWT1, // GPIO12 + GPIO_MCP39F5_RX, // GPIO03 MCP39F501 Serial output + GPIO_REL1, // GPIO04 + GPIO_REL2, // GPIO05 + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_SWT1, // GPIO12 0, - GPIO_SWT2, // GPIO14 - 0, // GPIO15 MCP39F501 Reset - 0, 0 + GPIO_SWT2, // GPIO14 + GPIO_MCP39F5_RST, // GPIO15 MCP39F501 Reset + 0, + 0 }, { "Xiaomi Philips", // Xiaomi Philips bulb (ESP8266) 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM2, // GPIO12 cold/warm light 0, 0, GPIO_PWM1, // GPIO15 light intensity @@ -1183,9 +1522,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { { "Neo Coolcam", // Neo Coolcam (ESP8266) // https://www.banggood.com/NEO-COOLCAM-WiFi-Mini-Smart-Plug-APP-Remote-Control-Timing-Smart-Socket-EU-Plug-p-1288562.html?cur_warehouse=CN 0, 0, 0, 0, - GPIO_LED1_INV, // GPIO04 Red Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO04 Red Led (0 = On, 1 = Off) - Link and Power status 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) GPIO_KEY1, // GPIO13 Button 0, 0, 0, 0 @@ -1198,38 +1542,54 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_KEY1, // GPIO04 Button 1 GPIO_REL2_INV, // GPIO05 Red Led 2 (0 = On, 1 = Off) - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL4_INV, // GPIO12 Blue Led 4 (0 = On, 1 = Off) GPIO_KEY4, // GPIO13 Button 4 GPIO_KEY3, // GPIO14 Button 3 GPIO_LED1, // GPIO15 Optional sensor GPIO_REL1_INV, // GPIO16 Green Led 1 (0 = On, 1 = Off) + 0 }, { "OBI Socket", // OBI socket (ESP8266) - https://www.obi.de/hausfunksteuerung/wifi-stecker-schuko/p/2291706 GPIO_USER, // GPIO00 GPIO_USER, // GPIO01 Serial RXD 0, GPIO_USER, // GPIO03 Serial TXD - GPIO_LED1, // GPIO04 Blue LED + GPIO_LED1, // GPIO04 Blue LED - Link and Power status GPIO_REL1, // GPIO05 (Relay OFF, but used as Relay Switch) - 0, 0, 0, 0, 0, 0, // Flash connection - GPIO_LED2, // GPIO12 (Relay ON, but set to LOW, so we can switch with GPIO05) + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_LED3, // GPIO12 (Relay ON, but set to LOW, so we can switch with GPIO05) GPIO_USER, // GPIO13 GPIO_KEY1, // GPIO14 Button 0, GPIO_USER, // GPIO16 - GPIO_ADC0 // ADC0 A0 Analog input + GPIO_FLAG_ADC0 // ADC0 A0 Analog input }, { "Teckin", // https://www.amazon.de/gp/product/B07D5V139R 0, GPIO_KEY1, // GPIO01 Serial TXD and Button 0, - GPIO_LED2_INV, // GPIO03 Serial RXD and Red Led (0 = On, 1 = Off) + GPIO_LED2_INV, // GPIO03 Serial RXD and Red Led (0 = On, 1 = Off) - Power status GPIO_HJL_CF, // GPIO04 BL0937 or HJL-01 CF power GPIO_NRG_CF1, // GPIO05 BL0937 or HJL-01 CF1 current / voltage - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link status GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On) 0, 0, 0 }, @@ -1239,9 +1599,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_KEY1, // GPIO03 Button GPIO_HLW_CF, // GPIO04 HLW8012 CF power GPIO_NRG_CF1, // GPIO05 HLW8012 CF1 current / voltage - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 HLW8012 CF Sel output (0 = Voltage) - GPIO_LED1_INV, // GPIO13 LED (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 LED (0 = On, 1 = Off) - Link and Power status GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0 = Off, 1 = On ) 0, 0, 0 }, @@ -1253,7 +1618,12 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 MCU serial control GPIO_USER, GPIO_USER, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_USER, GPIO_USER, GPIO_USER, // GPIO14 Green Led @@ -1263,27 +1633,37 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { }, { "Gosund SP1 v23", // https://www.amazon.de/gp/product/B0777BWS1P 0, - GPIO_LED1_INV, // GPIO01 Serial RXD and LED1 (blue) inv + GPIO_LED1_INV, // GPIO01 Serial RXD and LED1 (blue) inv - Link status 0, GPIO_KEY1, // GPIO03 Serial TXD and Button GPIO_HJL_CF, // GPIO04 BL0937 or HJL-01 CF power GPIO_NRG_CF1, // GPIO05 BL0937 or HJL-01 CF1 current / voltage - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) - GPIO_LED2_INV, // GPIO13 LED2 (red) inv + GPIO_LED2_INV, // GPIO13 LED2 (red) inv - Power status GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On) 0, 0, 0 }, - { "ARMTR Dimmer", // ARMTRONIX Dimmer, one or two channel (ESP8266 w/ separate MCU dimmer) - // https://www.tindie.com/products/Armtronix/wifi-ac-dimmer-two-triac-board/ - // https://www.tindie.com/products/Armtronix/wifi-ac-dimmer-esp8266-one-triac-board-alexaecho/ + { "ARMTR Dimmer", // ARMTRONIX Dimmer, one or two channel (ESP8266 w/ separate MCU dimmer) + // https://www.tindie.com/products/Armtronix/wifi-ac-dimmer-two-triac-board/ + // https://www.tindie.com/products/Armtronix/wifi-ac-dimmer-esp8266-one-triac-board-alexaecho/ GPIO_USER, - GPIO_TXD, // GPIO01 MCU serial control + GPIO_TXD, // GPIO01 MCU serial control GPIO_USER, - GPIO_RXD, // GPIO03 MCU serial control + GPIO_RXD, // GPIO03 MCU serial control GPIO_USER, GPIO_USER, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_USER, GPIO_USER, GPIO_USER, @@ -1296,10 +1676,15 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0, 0, GPIO_HLW_CF, // GPIO04 HLW8012 CF power GPIO_NRG_CF1, // GPIO05 HLW8012 CF1 current / voltage - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 HLW8012 CF Sel output (0 = Voltage) - GPIO_LED2_INV, // GPIO13 Red Led (0 = On, 1 = Off) - GPIO_LED1_INV, // GPIO14 Blue Led (0 = On, 1 = Off) + GPIO_LED2_INV, // GPIO13 Red Led (0 = On, 1 = Off) - Power status + GPIO_LED1_INV, // GPIO14 Blue Led (0 = On, 1 = Off) - Link status GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On) 0, 0 }, @@ -1311,9 +1696,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_RXD, // GPIO03 MCU serial control GPIO_USER, GPIO_USER, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_USER, - GPIO_LED1, // GPIO13 WiFi LED + GPIO_LED1, // GPIO13 WiFi LED - Link and Power status GPIO_USER, GPIO_USER, GPIO_USER, @@ -1322,13 +1712,18 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { { "Teckin US", // Teckin SP20 US with Energy Monitoring // https://www.amazon.com/Outlet-Compatible-Monitoring-Function-Required/dp/B079Q5W22B // https://www.amazon.com/Outlet-ZOOZEE-Monitoring-Function-Compatible/dp/B07J2LR5KN - GPIO_LED2_INV, // GPIO00 Red Led (1 = On, 0 = Off) + GPIO_LED2_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status 0, - GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off) + GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status 0, GPIO_REL1, // GPIO04 Relay (0 = Off, 1 = On) GPIO_HJL_CF, // GPIO05 BL0937 or HJL-01 CF power - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) GPIO_KEY1, // GPIO13 Button GPIO_NRG_CF1, // GPIO14 BL0937 or HJL-01 CF1 current / voltage @@ -1343,33 +1738,274 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_KEY1, // GPIO03 Serial TXD + Button GPIO_REL2, // GPIO04 Relay 2 GPIO_REL1, // GPIO05 Relay 1 - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL3, // GPIO12 Relay 3 GPIO_REL4, // GPIO13 Relay 4 GPIO_USER, // GPIO14 0, GPIO_USER, // GPIO16 0 + }, + { "OBI Socket 2", // OBI socket (ESP8266) - https://www.obi.de/hausfunksteuerung/wifi-stecker-schuko-2-stueck-weiss/p/4077673 + 0, // GPIO00 + 0, // GPIO01 Serial RXD + 0, + 0, // GPIO03 Serial TXD + GPIO_REL1, // GPIO04 Relay 1 + GPIO_KEY1, // GPIO05 Button + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_LED1_INV, // GPIO12 Green LED - Link status + GPIO_LED2, // GPIO13 Red LED - Power status + 0, 0, 0, 0 + }, + { "YTF IR Bridge", // https://www.aliexpress.com/item/Tuya-universal-Smart-IR-Hub-remote-control-Voice-Control-AC-TV-Work-With-Alexa-Google-Home/32951202513.html + GPIO_USER, // GPIO00 + GPIO_USER, // GPIO01 Serial RXD + GPIO_USER, // GPIO02 + GPIO_USER, // GPIO03 Serial TXD + GPIO_LED1_INV, // GPIO04 Blue Led - Link status + GPIO_IRRECV, // GPIO05 IR Receiver + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + 0, // GPIO12 + GPIO_KEY1, // GPIO13 Button + GPIO_IRSEND, // GPIO14 IR Transmitter + 0, 0, 0 + }, + { "Digoo DG-SP202", // Digoo DG-SP202 + // https://www.banggood.com/DIGOO-DG-SP202-Dual-EU-Plug-Smart-WIFI-Socket-Individual-Controllable-Energy-Monitor-Remote-Control-Timing-Smart-Home-Outlet-let-p-1375323.html + GPIO_KEY1, // GPIO00 Button1 + 0, // GPIO01 Serial RXD + 0, // GPIO02 + 0, // GPIO03 Serial TXD + GPIO_HJL_CF, // GPIO04 BL0937 or HJL-01 CF power + GPIO_NRG_CF1, // GPIO05 BL0937 or HJL-01 CF1 current / voltage + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) + GPIO_LED1, // GPIO13 Blue Leds - Link Status + GPIO_REL2, // GPIO14 Relay2 (0 = Off, 1 = On) and Red Led + GPIO_REL1, // GPIO15 Relay1 (0 = Off, 1 = On) and Red Led + GPIO_KEY2_NP, // GPIO16 Button2, externally pulled up + 0 + }, + { "KA10", // SMANERGY KA10 (ESP8285 - BL0937 Energy Monitoring) - https://www.amazon.es/dp/B07MBTCH2Y + 0, // GPIO00 + GPIO_LED1_INV, // GPIO01 Blue LED - Link status + 0, // GPIO02 + GPIO_KEY1, // GPIO03 Button + GPIO_HJL_CF, // GPIO04 BL0937 CF power + GPIO_NRG_CF1, // GPIO05 BL0937 CF1 voltage / current + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_NRG_SEL_INV, // GPIO12 BL0937 Sel output (1 = Voltage) + GPIO_LED2, // GPIO13 Red LED - Power status + GPIO_REL1, // GPIO14 Relay 1 + 0, 0, 0 + }, + { "Luminea ZX2820", + GPIO_KEY1, // GPIO00 Button + 0, 0, 0, + GPIO_HLW_CF, // GPIO04 HLW8012 CF power + GPIO_NRG_CF1, // GPIO05 HLW8012 CF1 voltage / current + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_NRG_SEL_INV, // GPIO12 HLW8012 SEL (0 = Voltage) + GPIO_LED1_INV, // GPIO13 Green Led - Link and Power status + GPIO_REL1, // GPIO14 Relay + 0, 0, 0 + }, + { "Mi Desk Lamp", // Mi LED Desk Lamp - https://www.mi.com/global/smartlamp/ + 0, 0, + GPIO_KEY1, // GPIO02 Button + 0, + GPIO_PWM1, // GPIO04 Cold White + GPIO_PWM2, // GPIO05 Warm White + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_ROT1A, // GPIO12 Rotary switch A pin + GPIO_ROT1B, // GPIO13 Rotary switch B pin + 0, 0, 0, 0 + }, + { "SP10", // Tuya SP10 (BL0937 Energy Monitoring) + // https://www.aliexpress.com/item/Smart-Mini-WiFi-Plug-Outlet-Switch-Work-With-ForEcho-Alexa-Google-Home-Remote-EU-Smart-Socket/32963670423.html + 0, // GPIO00 + GPIO_PWM1, // GPIO01 Nightlight + 0, // GPIO02 + GPIO_KEY1, // GPIO03 Button + GPIO_HJL_CF, // GPIO04 BL0937 CF power + GPIO_NRG_CF1, // GPIO05 BL0937 CF1 voltage / current + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_NRG_SEL_INV, // GPIO12 BL0937 Sel output (1 = Voltage) + GPIO_LED1, // GPIO13 Blue LED - Link status + GPIO_REL1, // GPIO14 Relay and red LED + 0, 0, 0 + }, + { "WAGA CHCZ02MB", // WAGA life CHCZ02MB (HJL-01 Energy Monitoring) + // https://www.ebay.com/itm/332595697006 + GPIO_LED2_INV, // GPIO00 Red LED + 0, // GPIO01 Serial RXD + 0, // GPIO02 + GPIO_NRG_SEL_INV, // GPIO03 HJL-01 Sel output (1 = Voltage) + 0, // GPIO04 + GPIO_HJL_CF, // GPIO05 HJL-01 CF power + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_REL1, // GPIO12 Relay + GPIO_KEY1, // GPIO13 Button + GPIO_NRG_CF1, // GPIO14 HJL-01 CF1 voltage / current + GPIO_LED1_INV, // GPIO15 Blue LED - Link status + 0, 0 + }, + { "SYF05", // Sunyesmart SYF05 (a.k.a. Fcmila) = TYWE3S + SM16726 + // Also works with Merkury 904 RGBW Bulbs with 13 set to GPIO_SM16716_SEL + // https://www.flipkart.com/fc-mila-bxav-xs-ad-smart-bulb/p/itmf85zgs45fzr7n + // https://docs.tuya.com/en/hardware/WiFi-module/wifi-e3s-module.html + // http://www.datasheet-pdf.com/PDF/SM16716-Datasheet-Sunmoon-932771 + GPIO_USER, // GPIO00 N.C. + 0, // GPIO01 Serial RXD + GPIO_USER, // GPIO02 N.C. + 0, // GPIO03 Serial TXD + GPIO_SM16716_CLK, // GPIO04 SM16716 Clock + GPIO_PWM1, // GPIO05 White + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_USER, // GPIO12 Alt. White on some devices + GPIO_USER, // GPIO13 SM16716 Enable on some devices + GPIO_SM16716_DAT, // GPIO14 SM16716 Data + 0, // GPIO15 wired to GND + GPIO_USER, // GPIO16 N.C. + GPIO_FLAG_ADC0 // ADC0 A0 Analog input } }; /* Optionals + { "RGB Smart Plug", // Tuya based smart plug with power monitoring and RGB light + // https://www.aliexpress.com/item/ET-Smart-Plug-Wifi-Socket-With-Switch-Phone-APP-Voice-Remote-Control-Monitor-Smart-Timing-Switch/32964036349.html?spm=a2g0s.9042311.0.0.439c4c4d4N8N2Q + // https://xiangshangcn.en.alibaba.com/product/60844251239-807590977/RGB_wifi_smart_plug_smart_socket_smart_outlet_EU_works_with_Amazon_alexa_google_home_mobile_app_tuya_solution_smart_life.html?spm=a2700.icbuShop.41413.24.4e996767oFAAmO + GPIO_PWM1, // GPIO00 Red + GPIO_USER, // GPIO01 Serial RXD and Optional sensor + GPIO_PWM3, // GPIO02 Blue + GPIO_USER, // GPIO03 Serial TXD and Optional sensor + GPIO_PWM2, // GPIO04 Green + GPIO_HJL_CF, // GPIO05 BL0937 or HJL-01 CF power + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) + GPIO_KEY1, // GPIO13 Button + GPIO_NRG_CF1, // GPIO14 BL0937 or HJL-01 CF1 current / voltage + GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On) + 0, 0 + } + + { "ESP RGBWWC", // esp rgbww controller https://github.com/pljakobs/esp_rgbww_controller/tree/v2.3 + GPIO_KEY1, // GPIO00 Button + GPIO_USER, // GPIO01 Serial RXD and Optional sensor + 0, // GPIO02 + GPIO_USER, // GPIO03 Serial TXD and Optional sensor + GPIO_PWM5, // GPIO04 LED Warm White + GPIO_PWM4, // GPIO05 LED Cold White + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_PWM2, // GPIO12 LED Green + GPIO_PWM1, // GPIO13 LED Red + GPIO_PWM3, // GPIO14 LED Blue + 0, // GPIO15 + GPIO_KEY2, // GPIO16 Button + 0 + } + + { "N0DY Relay", // N0DY Wifi Dual Relay (ESP-07) + // https://www.n0dy.com/product/web-controlled-dual-relay/ + // https://www.amazon.com/dp/B072MKV8ZM + GPIO_KEY1, // GPIO00 PROG Button + GPIO_USER, // GPIO01 Serial RXD or Optional sensor on J2 RXD (if not using serial io) + 0, // GPIO02 + GPIO_USER, // GPIO03 Serial TXD or Optional sensor on J2 TXD (if not using serial io) + GPIO_REL2_INV, // GPIO04 Relay 2 (active low) + GPIO_REL1_INV, // GPIO05 Relay 1 (active low) + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + 0, 0, 0, 0, 0, 0 + } + { "MagicHome", // Magic Home (aka Flux-light) (ESP8266) // https://www.aliexpress.com/item/Magic-Home-Mini-RGB-RGBW-Wifi-Controller-For-Led-Strip-Panel-light-Timing-Function-16million-colors/32686853650.html 0, GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED1_INV, // GPIO02 Blue onboard LED + GPIO_LED1_INV, // GPIO02 Blue onboard LED - Link and Power status GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_USER, // GPIO04 IR receiver (optional) GPIO_PWM2, // GPIO05 RGB LED Green - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM3, // GPIO12 RGB LED Blue GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White) GPIO_PWM1, // GPIO14 RGB LED Red 0, 0, 0 - }, + } + { "Arilux LC10", // Arilux LC10 (ESP8285), RGBW + RF // https://github.com/arendst/Sonoff-Tasmota/wiki/MagicHome-with-ESP8285 // https://www.aliexpress.com/item/DC5-24V-Wireless-WIFI-LED-RGB-Controller-RGBW-Controller-IR-RF-Remote-Control-IOS-Android-for/32827253255.html @@ -1380,11 +2016,16 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 Serial TXD and Optional sensor0 GPIO_ARIRFRCV, // GPIO04 RF receiver input GPIO_PWM2, // GPIO05 RGB LED Green - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM3, // GPIO12 RGB LED Blue GPIO_PWM4, // GPIO13 RGBW LED White GPIO_PWM1, // GPIO14 RGB LED Red - GPIO_LED2_INV, // GPIO15 RF receiver control + GPIO_LED4_INV, // GPIO15 RF receiver control 0, 0 } @@ -1393,7 +2034,12 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_KEY2, // GPIO03 Serial TXD and Optional sensor GPIO_REL2, // GPIO04 Relay 2 GPIO_KEY3, // GPIO05 Input 2 - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_KEY1, // GPIO12 Key input GPIO_REL1, // GPIO13 Relay 1 0, @@ -1405,18 +2051,28 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0, 0, 0, GPIO_REL1, // GPIO04 Relay (0 = Off, 1 = On) 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_KEY1, // GPIO12 Button 0, 0, - GPIO_LED1, // GPIO15 Led (1 = On, 0 = Off) + GPIO_LED1, // GPIO15 Led (1 = On, 0 = Off) - Link and Power status 0, 0 } { "SMPW701E", // SM-PW701E WLAN Socket (#1190) 0, 0, 0, 0, - GPIO_LED1_INV, // GPIO04 Blue Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO04 Blue Led (0 = On, 1 = Off) - Link and Power status 0, // GPIO05 IR or RF receiver (optional) - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Relay and Red Led (0 = Off, 1 = On) GPIO_KEY1, // GPIO13 Button 0, 0, 0, 0 @@ -1427,9 +2083,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO01 0, GPIO_USER, // GPIO03 - GPIO_LED1_INV, // GPIO04 Blue LED + GPIO_LED1_INV, // GPIO04 Blue LED - Link and Power status GPIO_REL1, // GPIO05 Red LED and relay - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) 0, GPIO_KEY1, // GPIO13 Button (normally GPIO00) GPIO_USER, // GPIO14 @@ -1438,11 +2099,16 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { { "MagicHome v2.3", // Magic Home (aka Flux-light) (ESP8266) (#1353) 0, 0, - GPIO_LED1_INV, // GPIO02 Blue onboard LED + GPIO_LED1_INV, // GPIO02 Blue onboard LED - Link and Power status 0, GPIO_USER, // GPIO04 IR receiver (optional) GPIO_PWM2, // GPIO05 RGB LED Green - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_PWM1, // GPIO12 RGB LED Red GPIO_PWM3, // GPIO13 RGB LED Blue 0, @@ -1457,7 +2123,12 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO03 (D8) Serial TXD GPIO_USER, // GPIO04 (D4) 4 x WS2812 Leds, (DOUT) Extents WS2812 string GPIO_USER, // GPIO05 (D5) Blue Led - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_USER, // GPIO12 (D12) GPIO_USER, // GPIO13 (D13) GPIO_USER, // GPIO14 (D14) @@ -1469,9 +2140,14 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { { "Delock 11826", // Delock 11826 (ESP8285) = Sonoff Basic GPIO_KEY1, // GPIO00 Button 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, // Flash connection + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) - Link and Power status 0, 0, 0, 0 } diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 6e635a341..0e9c322ac 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -1,7 +1,7 @@ /* sonoff_version.h - Version header file for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x06040100 +#define VERSION 0x06050000 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/support.ino b/sonoff/support.ino index 5c80651e9..fc2a3d853 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -1,7 +1,7 @@ /* support.ino - support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ Ticker tickerOSWatch; #define OSWATCH_RESET_TIME 120 static unsigned long oswatch_last_loop_time; -byte oswatch_blocked_loop = 0; +uint8_t oswatch_blocked_loop = 0; #ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception //void OsWatchTicker() ICACHE_RAM_ATTR; @@ -47,8 +47,7 @@ void OsWatchTicker(void) unsigned long last_run = abs(t - oswatch_last_loop_time); #ifdef DEBUG_THEO - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_OSWATCH " FreeRam %d, rssi %d, last_run %d"), ESP.getFreeHeap(), WifiGetRssiAsQuality(WiFi.RSSI()), last_run); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_OSWATCH " FreeRam %d, rssi %d, last_run %d"), ESP.getFreeHeap(), WifiGetRssiAsQuality(WiFi.RSSI()), last_run); #endif // DEBUG_THEO if (last_run >= (OSWATCH_RESET_TIME * 1000)) { // AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_OSWATCH " " D_BLOCKED_LOOP ". " D_RESTARTING)); // Save iram space @@ -84,7 +83,7 @@ String GetResetReason(void) } } -boolean OsWatchBlockedLoop(void) +bool OsWatchBlockedLoop(void) { return oswatch_blocked_loop; } @@ -140,7 +139,7 @@ size_t strchrspn(const char *str1, int character) char* subStr(char* dest, char* str, const char *delim, int index) { char *act; - char *sub; + char *sub = NULL; char *ptr; int i; @@ -154,34 +153,39 @@ char* subStr(char* dest, char* str, const char *delim, int index) return sub; } -double CharToDouble(char *str) +double CharToDouble(const char *str) { // simple ascii to double, because atof or strtod are too large char strbuf[24]; strlcpy(strbuf, str, sizeof(strbuf)); - char *pt; - double left = atoi(strbuf); + char *pt = strbuf; + while ((*pt != '\0') && isblank(*pt)) { pt++; } // Trim leading spaces + + signed char sign = 1; + if (*pt == '-') { sign = -1; } + if (*pt == '-' || *pt=='+') { pt++; } // Skip any sign + + double left = 0; + if (*pt != '.') { + left = atoi(pt); // Get left part + while (isdigit(*pt)) { pt++; } // Skip number + } + double right = 0; - short len = 0; - pt = strtok (strbuf, "."); - if (pt) { - pt = strtok (NULL, "."); - if (pt) { - right = atoi(pt); - len = strlen(pt); - double fac = 1; - while (len) { - fac /= 10.0; - len--; - } - // pow is also very large - //double fac=pow(10,-len); - right *= fac; + if (*pt == '.') { + pt++; + right = atoi(pt); // Decimal part + while (isdigit(*pt)) { + pt++; + right /= 10.0; } } + double result = left + right; - if (left < 0) { result = left - right; } + if (sign < 0) { + return -result; // Add negative sign + } return result; } @@ -210,10 +214,12 @@ char* Unescape(char* buffer, uint16_t* size) { uint8_t* read = (uint8_t*)buffer; uint8_t* write = (uint8_t*)buffer; - uint16_t start_size = *size; - uint16_t end_size = *size; + int16_t start_size = *size; + int16_t end_size = *size; uint8_t che = 0; +// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)buffer, *size); + while (start_size > 0) { uint8_t ch = *read++; start_size--; @@ -235,6 +241,14 @@ char* Unescape(char* buffer, uint16_t* size) case 's': che = ' '; break; // 20 Space case 't': che = '\t'; break; // 09 Horizontal tab case 'v': che = '\v'; break; // 0B Vertical tab + case 'x': { + uint8_t* start = read; + che = (uint8_t)strtol((const char*)read, (char**)&read, 16); + start_size -= (uint16_t)(read - start); + end_size -= (uint16_t)(read - start); + break; + } + case '"': che = '\"'; break; // 22 Quotation mark // case '?': che = '\?'; break; // 3F Question mark default : { che = chi; @@ -247,6 +261,9 @@ char* Unescape(char* buffer, uint16_t* size) } } *size = end_size; + +// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)buffer, *size); + return buffer; } @@ -262,7 +279,7 @@ char* RemoveSpace(char* p) *write++ = ch; } } - *write = '\0'; +// *write = '\0'; // Removed 20190223 as it buffer overflows on no isspace found - no need either return p; } @@ -292,27 +309,6 @@ char* UpperCase_P(char* dest, const char* source) return dest; } -/* -char* LTrim(char* p) -{ - while ((*p != '\0') && (isblank(*p))) { - p++; // Trim leading spaces - } - return p; -} - -char* RTrim(char* p) -{ - char* q = p + strlen(p) -1; - while ((q >= p) && (isblank(*q))) { - q--; // Trim trailing spaces - } - q++; - *q = '\0'; - return p; -} -*/ - char* Trim(char* p) { while ((*p != '\0') && isblank(*p)) { p++; } // Trim leading spaces @@ -361,10 +357,10 @@ uint8_t Shortcut(const char* str) return result; } -boolean ParseIp(uint32_t* addr, const char* str) +bool ParseIp(uint32_t* addr, const char* str) { uint8_t *part = (uint8_t*)addr; - byte i; + uint8_t i; *addr = 0; for (i = 0; i < 4; i++) { @@ -378,7 +374,7 @@ boolean ParseIp(uint32_t* addr, const char* str) return (3 == i); } -void MakeValidMqtt(byte option, char* str) +void MakeValidMqtt(uint8_t option, char* str) { // option 0 = replace by underscore // option 1 = delete character @@ -643,7 +639,160 @@ int GetStateNumber(char *state_text) return state_number; } -boolean GetUsedInModule(byte val, uint8_t *arr) +void SetSerialBaudrate(int baudrate) +{ + Settings.baudrate = baudrate / 1200; + if (Serial.baudRate() != baudrate) { + if (seriallog_level) { + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_SET_BAUDRATE_TO " %d"), baudrate); + } + delay(100); + Serial.flush(); + Serial.begin(baudrate, serial_config); + delay(10); + Serial.println(); + } +} + +void ClaimSerial(void) +{ + serial_local = true; + AddLog_P(LOG_LEVEL_INFO, PSTR("SNS: Hardware Serial")); + SetSeriallog(LOG_LEVEL_NONE); + baudrate = Serial.baudRate(); + Settings.baudrate = baudrate / 1200; +} + +void SerialSendRaw(char *codes) +{ + char *p; + char stemp[3]; + uint8_t code; + + int size = strlen(codes); + + while (size > 0) { + strlcpy(stemp, codes, sizeof(stemp)); + code = strtol(stemp, &p, 16); + Serial.write(code); + size -= 2; + codes += 2; + } +} + +uint32_t GetHash(const char *buffer, size_t size) +{ + uint32_t hash = 0; + for (uint16_t i = 0; i <= size; i++) { + hash += (uint8_t)*buffer++ * (i +1); + } + return hash; +} + +void ShowSource(int source) +{ + if ((source > 0) && (source < SRC_MAX)) { + char stemp1[20]; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SRC: %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource)); + } +} + +/*********************************************************************************************\ + * GPIO Module and Template management +\*********************************************************************************************/ + +uint8_t ModuleNr() +{ + // 0 = User module (255) + // 1 up = Template module 0 up + return (USER_MODULE == Settings.module) ? 0 : Settings.module +1; +} + +String AnyModuleName(uint8_t index) +{ + if (USER_MODULE == index) { + return String(Settings.user_template.name); + } else { + return FPSTR(kModules[index].name); + } +} + +String ModuleName() +{ + return AnyModuleName(Settings.module); +} + +void ModuleGpios(myio *gp) +{ + uint8_t *dest = (uint8_t *)gp; + memset(dest, GPIO_NONE, sizeof(myio)); + + uint8_t src[sizeof(mycfgio)]; + if (USER_MODULE == Settings.module) { + memcpy(&src, &Settings.user_template.gp, sizeof(mycfgio)); + } else { + memcpy_P(&src, &kModules[Settings.module].gp, sizeof(mycfgio)); + } + // 11 85 00 85 85 00 00 00 15 38 85 00 00 81 + +// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)&src, sizeof(mycfgio)); + + uint8_t j = 0; + for (uint8_t i = 0; i < sizeof(mycfgio); i++) { + if (6 == i) { j = 9; } + if (8 == i) { j = 12; } + dest[j] = src[i]; + j++; + } + // 11 85 00 85 85 00 00 00 00 00 00 00 15 38 85 00 00 81 + +// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)gp, sizeof(myio)); +} + +gpio_flag ModuleFlag() +{ + gpio_flag flag; + + if (USER_MODULE == Settings.module) { + flag = Settings.user_template.flag; + } else { + memcpy_P(&flag, &kModules[Settings.module].flag, sizeof(gpio_flag)); + } + + return flag; +} + +void ModuleDefault(uint8_t module) +{ + if (USER_MODULE == module) { module = WEMOS; } // Generic + Settings.user_template_base = module; + memcpy_P(&Settings.user_template, &kModules[module], sizeof(mytmplt)); +} + +void SetModuleType() +{ + my_module_type = (USER_MODULE == Settings.module) ? Settings.user_template_base : Settings.module; +} + +uint8_t ValidPin(uint8_t pin, uint8_t gpio) +{ + uint8_t result = gpio; + + if (((pin > 5) && (pin < 9)) || (11 == pin)) { + result = GPIO_NONE; // Disable flash pins GPIO6, GPIO7, GPIO8 and GPIO11 + } + if ((WEMOS == Settings.module) && (!Settings.flag3.user_esp8285_enable)) { + if ((pin == 9) || (pin == 10)) { result = GPIO_NONE; } // Disable possible flash GPIO9 and GPIO10 + } + return result; +} + +bool ValidGPIO(uint8_t pin, uint8_t gpio) +{ + return (GPIO_USER == ValidPin(pin, gpio)); // Only allow GPIO_USER pins +} + +bool GetUsedInModule(uint8_t val, uint8_t *arr) { int offset = 0; @@ -655,6 +804,12 @@ boolean GetUsedInModule(byte val, uint8_t *arr) if ((val >= GPIO_KEY1_NP) && (val < GPIO_KEY1_NP + MAX_KEYS)) { offset = -(GPIO_KEY1_NP - GPIO_KEY1); } + if ((val >= GPIO_KEY1_INV) && (val < GPIO_KEY1_INV + MAX_KEYS)) { + offset = -(GPIO_KEY1_INV - GPIO_KEY1); + } + if ((val >= GPIO_KEY1_INV_NP) && (val < GPIO_KEY1_INV_NP + MAX_KEYS)) { + offset = -(GPIO_KEY1_INV_NP - GPIO_KEY1); + } if ((val >= GPIO_SWT1) && (val < GPIO_SWT1 + MAX_SWITCHES)) { offset = (GPIO_SWT1_NP - GPIO_SWT1); @@ -691,80 +846,49 @@ boolean GetUsedInModule(byte val, uint8_t *arr) offset = -(GPIO_CNTR1_NP - GPIO_CNTR1); } - for (byte i = 0; i < MAX_GPIO_PIN; i++) { + for (uint8_t i = 0; i < MAX_GPIO_PIN; i++) { if (arr[i] == val) { return true; } if (arr[i] == val + offset) { return true; } } return false; } -void SetSerialBaudrate(int baudrate) +bool JsonTemplate(const char* dataBuf) { - Settings.baudrate = baudrate / 1200; - if (Serial.baudRate() != baudrate) { - if (seriallog_level) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_SET_BAUDRATE_TO " %d"), baudrate); - AddLog(LOG_LEVEL_INFO); + StaticJsonBuffer<350> jb; // 331 from https://arduinojson.org/v5/assistant/ + JsonObject& obj = jb.parseObject(dataBuf); + if (!obj.success()) { return false; } + + // All parameters are optional allowing for partial changes + const char* name = obj[D_JSON_NAME]; + if (name != nullptr) { + strlcpy(Settings.user_template.name, name, sizeof(Settings.user_template.name)); + } + if (obj[D_JSON_GPIO].success()) { + for (uint8_t i = 0; i < sizeof(mycfgio); i++) { + Settings.user_template.gp.io[i] = obj[D_JSON_GPIO][i] | 0; } - delay(100); - Serial.flush(); - Serial.begin(baudrate, serial_config); - delay(10); - Serial.println(); } + if (obj[D_JSON_FLAG].success()) { + uint8_t flag = obj[D_JSON_FLAG] | 0; + memcpy(&Settings.user_template.flag, &flag, sizeof(gpio_flag)); + } + 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 + } + return true; } -void ClaimSerial(void) +void TemplateJson() { - serial_local = 1; - AddLog_P(LOG_LEVEL_INFO, PSTR("SNS: Hardware Serial")); - SetSeriallog(LOG_LEVEL_NONE); - baudrate = Serial.baudRate(); - Settings.baudrate = baudrate / 1200; -} - -void SerialSendRaw(char *codes) -{ - char *p; - char stemp[3]; - uint8_t code; - - int size = strlen(codes); - - while (size > 0) { - snprintf(stemp, sizeof(stemp), codes); - code = strtol(stemp, &p, 16); - Serial.write(code); - size -= 2; - codes += 2; + snprintf_P(mqtt_data, sizeof(mqtt_data), 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]); } -} - -uint32_t GetHash(const char *buffer, size_t size) -{ - uint32_t hash = 0; - for (uint16_t i = 0; i <= size; i++) { - hash += (uint8_t)*buffer++ * (i +1); - } - return hash; -} - -void ShowSource(int source) -{ - if ((source > 0) && (source < SRC_MAX)) { - char stemp1[20]; - snprintf_P(log_data, sizeof(log_data), PSTR("SRC: %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource)); - AddLog(LOG_LEVEL_DEBUG); - } -} - -uint8_t ValidGPIO(uint8_t pin, uint8_t gpio) -{ - uint8_t result = gpio; - if ((WEMOS == Settings.module) && (!Settings.flag3.user_esp8285_enable)) { - if ((pin == 9) || (pin == 10)) { result = GPIO_NONE; } // Disable possible flash GPIO9 and GPIO10 - } - return result; + 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); } /*********************************************************************************************\ @@ -841,7 +965,7 @@ uint32_t i2c_buffer = 0; bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size) { - byte x = I2C_RETRY_COUNTER; + uint8_t x = I2C_RETRY_COUNTER; i2c_buffer = 0; do { @@ -850,7 +974,7 @@ bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size) if (0 == Wire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request... Wire.requestFrom((int)addr, (int)size); // send data n-bytes read if (Wire.available() == size) { - for (byte i = 0; i < size; i++) { + for (uint8_t i = 0; i < size; i++) { i2c_buffer = i2c_buffer << 8 | Wire.read(); // receive DATA } } @@ -942,7 +1066,7 @@ int32_t I2cRead24(uint8_t addr, uint8_t reg) bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size) { - byte x = I2C_RETRY_COUNTER; + uint8_t x = I2C_RETRY_COUNTER; do { Wire.beginTransmission((uint8_t)addr); // start transmission to device @@ -971,7 +1095,7 @@ int8_t I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len) Wire.beginTransmission((uint8_t)addr); Wire.write((uint8_t)reg); Wire.endTransmission(); - if (len != Wire.requestFrom((uint8_t)addr, (byte)len)) { + if (len != Wire.requestFrom((uint8_t)addr, (uint8_t)len)) { return 1; } while (len--) { @@ -1002,9 +1126,9 @@ void I2cScan(char *devs, unsigned int devs_len) // I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by slave/another_master after n bits // I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master? - byte error = 0; - byte address = 0; - byte any = 0; + uint8_t error = 0; + uint8_t address = 0; + uint8_t any = 0; snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_DEVICES_FOUND_AT)); for (address = 1; address <= 127; address++) { @@ -1028,9 +1152,9 @@ void I2cScan(char *devs, unsigned int devs_len) } } -boolean I2cDevice(byte addr) +bool I2cDevice(uint8_t addr) { - for (byte address = 1; address <= 127; address++) { + for (uint8_t address = 1; address <= 127; address++) { Wire.beginTransmission(address); if (!Wire.endTransmission() && (address == addr)) { return true; @@ -1044,12 +1168,11 @@ boolean I2cDevice(byte addr) * Syslog * * Example: - * snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG "Any value %d"), value); - * AddLog(LOG_LEVEL_DEBUG); + * AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_LOG "Any value %d"), value); * \*********************************************************************************************/ -void SetSeriallog(byte loglevel) +void SetSeriallog(uint8_t loglevel) { Settings.seriallog_level = loglevel; seriallog_level = loglevel; @@ -1057,7 +1180,7 @@ void SetSeriallog(byte loglevel) } #ifdef USE_WEBSERVER -void GetLog(byte idx, char** entry_pp, size_t* len_p) +void GetLog(uint8_t idx, char** entry_pp, size_t* len_p) { char* entry_p = NULL; size_t len = 0; @@ -1065,7 +1188,7 @@ void GetLog(byte idx, char** entry_pp, size_t* len_p) if (idx) { char* it = web_log; do { - byte cur_idx = *it; + uint8_t cur_idx = *it; it++; size_t tmp = strchrspn(it, '\1'); tmp++; // Skip terminating '\1' @@ -1101,12 +1224,11 @@ void Syslog(void) } else { syslog_level = 0; syslog_timer = SYSLOG_TIMER; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_SYSLOG_HOST_NOT_FOUND ". " D_RETRY_IN " %d " D_UNIT_SECOND), SYSLOG_TIMER); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_SYSLOG_HOST_NOT_FOUND ". " D_RETRY_IN " %d " D_UNIT_SECOND), SYSLOG_TIMER); } } -void AddLog(byte loglevel) +void AddLog(uint8_t loglevel) { char mxtime[10]; // "13:45:21 " @@ -1136,13 +1258,13 @@ void AddLog(byte loglevel) if (!global_state.wifi_down && (loglevel <= syslog_level)) { Syslog(); } } -void AddLog_P(byte loglevel, const char *formatP) +void AddLog_P(uint8_t loglevel, const char *formatP) { snprintf_P(log_data, sizeof(log_data), formatP); AddLog(loglevel); } -void AddLog_P(byte loglevel, const char *formatP, const char *formatP2) +void AddLog_P(uint8_t loglevel, const char *formatP, const char *formatP2) { char message[100]; @@ -1152,22 +1274,31 @@ void AddLog_P(byte loglevel, const char *formatP, const char *formatP2) AddLog(loglevel); } -void AddLogSerial(byte loglevel, uint8_t *buffer, int count) +void AddLog_P2(uint8_t loglevel, PGM_P formatP, ...) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_SERIAL D_RECEIVED)); + va_list arg; + va_start(arg, formatP); + int len = vsnprintf_P(log_data, sizeof(log_data), formatP, arg); + va_end(arg); + + AddLog(loglevel); +} + +void AddLogBuffer(uint8_t loglevel, uint8_t *buffer, int count) +{ + snprintf_P(log_data, sizeof(log_data), PSTR("DMP:")); for (int i = 0; i < count; i++) { snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, *(buffer++)); } AddLog(loglevel); } -void AddLogSerial(byte loglevel) +void AddLogSerial(uint8_t loglevel) { - AddLogSerial(loglevel, (uint8_t*)serial_in_buffer, serial_in_byte_counter); + AddLogBuffer(loglevel, (uint8_t*)serial_in_buffer, serial_in_byte_counter); } void AddLogMissed(char *sensor, uint8_t misses) { - snprintf_P(log_data, sizeof(log_data), PSTR("SNS: %s missed %d"), sensor, SENSOR_MAX_MISS - misses); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SNS: %s missed %d"), sensor, SENSOR_MAX_MISS - misses); } diff --git a/sonoff/support_button.ino b/sonoff/support_button.ino new file mode 100644 index 000000000..c0fe14bd2 --- /dev/null +++ b/sonoff/support_button.ino @@ -0,0 +1,242 @@ +/* + support_button.ino - button support for Sonoff-Tasmota + + Copyright (C) 2019 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define BUTTON_V1 +#ifdef BUTTON_V1 +/*********************************************************************************************\ + * Button support +\*********************************************************************************************/ + +unsigned long button_debounce = 0; // Button debounce timer +uint16_t holdbutton[MAX_KEYS] = { 0 }; // Timer for button hold +uint16_t dual_button_code = 0; // Sonoff dual received code + +uint8_t lastbutton[MAX_KEYS] = { NOT_PRESSED, NOT_PRESSED, NOT_PRESSED, NOT_PRESSED }; // Last button states +uint8_t multiwindow[MAX_KEYS] = { 0 }; // Max time between button presses to record press count +uint8_t multipress[MAX_KEYS] = { 0 }; // Number of button presses within multiwindow + +uint8_t dual_hex_code = 0; // Sonoff dual input flag +uint8_t key_no_pullup = 0; // key no pullup flag (1 = no pullup) +uint8_t key_inverted = 0; // Key inverted flag (1 = inverted) +uint8_t buttons_found = 0; // Number of buttons found flag + +/********************************************************************************************/ + +void ButtonPullupFlag(uint8 button_bit) +{ + bitSet(key_no_pullup, button_bit); +} + +void ButtonInvertFlag(uint8 button_bit) +{ + bitSet(key_inverted, button_bit); +} + +void ButtonInit(void) +{ + buttons_found = 0; + for (uint8_t i = 0; i < MAX_KEYS; i++) { + if (pin[GPIO_KEY1 +i] < 99) { + buttons_found++; + pinMode(pin[GPIO_KEY1 +i], bitRead(key_no_pullup, i) ? INPUT : ((16 == pin[GPIO_KEY1 +i]) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); + } + } +} + +uint8_t ButtonSerial(uint8_t serial_in_byte) +{ + if (dual_hex_code) { + dual_hex_code--; + if (dual_hex_code) { + dual_button_code = (dual_button_code << 8) | serial_in_byte; + serial_in_byte = 0; + } else { + if (serial_in_byte != 0xA1) { + dual_button_code = 0; // 0xA1 - End of Sonoff dual button code + } + } + } + if (0xA0 == serial_in_byte) { // 0xA0 - Start of Sonoff dual button code + serial_in_byte = 0; + dual_button_code = 0; + dual_hex_code = 3; + } + + return serial_in_byte; +} + +/*********************************************************************************************\ + * Button handler with single press only or multi-press and hold on all buttons +\*********************************************************************************************/ + +void ButtonHandler(void) +{ + if (uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit + + uint8_t button = NOT_PRESSED; + uint8_t button_present = 0; + uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command + uint16_t loops_per_second = 1000 / Settings.button_debounce; + char scmnd[20]; + +// uint8_t maxdev = (devices_present > MAX_KEYS) ? MAX_KEYS : devices_present; +// for (uint8_t button_index = 0; button_index < maxdev; button_index++) { + for (uint8_t button_index = 0; button_index < MAX_KEYS; button_index++) { + button = NOT_PRESSED; + button_present = 0; + + if (!button_index && ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type))) { + button_present = 1; + if (dual_button_code) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), dual_button_code); + button = PRESSED; + if (0xF500 == dual_button_code) { // Button hold + holdbutton[button_index] = (loops_per_second * Settings.param[P_HOLD_TIME] / 10) -1; + hold_time_extent = 1; + } + dual_button_code = 0; + } + } else { + if (pin[GPIO_KEY1 +button_index] < 99) { + button_present = 1; + button = (digitalRead(pin[GPIO_KEY1 +button_index]) != bitRead(key_inverted, button_index)); + } + } + + if (button_present) { + XdrvMailbox.index = button_index; + XdrvMailbox.payload = button; + if (XdrvCall(FUNC_BUTTON_PRESSED)) { + // Serviced + } + else if (SONOFF_4CHPRO == my_module_type) { + if (holdbutton[button_index]) { holdbutton[button_index]--; } + + bool button_pressed = false; + if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_10), button_index +1); + holdbutton[button_index] = loops_per_second; + button_pressed = true; + } + if ((NOT_PRESSED == button) && (PRESSED == lastbutton[button_index])) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1); + if (!holdbutton[button_index]) { button_pressed = true; } // Do not allow within 1 second + } + if (button_pressed) { + if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally + } + } + } + else { + if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) { + if (Settings.flag.button_single) { // Allow only single button press for immediate action + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1); + if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally + } + } else { + multipress[button_index] = (multiwindow[button_index]) ? multipress[button_index] +1 : 1; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, multipress[button_index]); + multiwindow[button_index] = loops_per_second / 2; // 0.5 second multi press window + } + blinks = 201; + } + + if (NOT_PRESSED == button) { + holdbutton[button_index] = 0; + } else { + holdbutton[button_index]++; + if (Settings.flag.button_single) { // Allow only single button press for immediate action + if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer +// Settings.flag.button_single = 0; + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only + ExecuteCommand(scmnd, SRC_BUTTON); + } + } else { + if (Settings.flag.button_restrict) { // Button restriction + if (holdbutton[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { // Button hold + multipress[button_index] = 0; + SendKey(0, button_index +1, 3); // Execute Hold command via MQTT if ButtonTopic is set + } + } else { + if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer + multipress[button_index] = 0; + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); + ExecuteCommand(scmnd, SRC_BUTTON); + } + } + } + } + + if (!Settings.flag.button_single) { // Allow multi-press + if (multiwindow[button_index]) { + multiwindow[button_index]--; + } else { + if (!restart_flag && !holdbutton[button_index] && (multipress[button_index] > 0) && (multipress[button_index] < MAX_BUTTON_COMMANDS +3)) { + bool single_press = false; + if (multipress[button_index] < 3) { // Single or Double press + if ((SONOFF_DUAL_R2 == my_module_type) || (SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { + single_press = true; + } else { + single_press = (Settings.flag.button_swap +1 == multipress[button_index]); + multipress[button_index] = 1; + } + } + if ((MI_DESK_LAMP == my_module_type) && (button_index == 0) && (rotary_changed) && (light_power)) { + rotary_changed = 0; // Color temp changed, no need to turn of the light + } else { + if (single_press && SendKey(0, button_index + multipress[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + // Success + } else { + if (multipress[button_index] < 3) { // Single or Double press + if (WifiState() > WIFI_RESTART) { // WPSconfig, Smartconfig or Wifimanager active + restart_flag = 1; + } else { + ExecuteCommandPower(button_index + multipress[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally + } + } else { // 3 - 7 press + if (!Settings.flag.button_restrict) { + snprintf_P(scmnd, sizeof(scmnd), kCommands[multipress[button_index] -3]); + ExecuteCommand(scmnd, SRC_BUTTON); + } + } + } + } + multipress[button_index] = 0; + } + } + } + } + } + lastbutton[button_index] = button; + } +} + +void ButtonLoop(void) +{ + if (buttons_found) { + if (TimeReached(button_debounce)) { + SetNextTimeInterval(button_debounce, Settings.button_debounce); + ButtonHandler(); + } + } +} + +#endif // BUTTON_V1 diff --git a/sonoff/support_features.ino b/sonoff/support_features.ino index 75ddaf327..c69b8e671 100644 --- a/sonoff/support_features.ino +++ b/sonoff/support_features.ino @@ -1,7 +1,7 @@ /* support_features.ino - feature support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -126,16 +126,16 @@ void GetFeatures(void) #ifdef USE_CONFIG_OVERRIDE feature_drv2 |= 0x00000001; // user_config(_override).h #endif -#ifdef BE_MINIMAL +#ifdef FIRMWARE_MINIMAL feature_drv2 |= 0x00000002; // user_config(_override).h #endif -#ifdef USE_SENSORS +#ifdef FIRMWARE_SENSORS feature_drv2 |= 0x00000004; // user_config(_override).h #endif -#ifdef USE_CLASSIC +#ifdef FIRMWARE_CLASSIC feature_drv2 |= 0x00000008; // user_config(_override).h #endif -#ifdef USE_KNX_NO_EMULATION +#ifdef FIRMWARE_KNX_NO_EMULATION feature_drv2 |= 0x00000010; // user_config(_override).h #endif #ifdef USE_DISPLAY_MODES1TO5 @@ -177,8 +177,10 @@ void GetFeatures(void) #ifdef USE_ARMTRONIX_DIMMERS feature_drv2 |= 0x00020000; // xdrv_18_armtronixdimmer.ino #endif +#ifdef USE_SM16716 + feature_drv2 |= 0x00040000; // xdrv_04_light.ino +#endif -// feature_drv2 |= 0x00040000; // feature_drv2 |= 0x00080000; // feature_drv2 |= 0x00100000; // feature_drv2 |= 0x00200000; @@ -365,18 +367,26 @@ void GetFeatures(void) feature_sns2 |= 0x00008000; // xsns_37_rfsensor.ino #endif #ifdef USE_THEO_V2 - feature_sns2 |= 0x00010000; + feature_sns2 |= 0x00010000; // xsns_37_rfsensor.ino #endif #ifdef USE_ALECTO_V2 - feature_sns2 |= 0x00020000; + feature_sns2 |= 0x00020000; // xsns_37_rfsensor.ino #endif #ifdef USE_AZ7798 - feature_sns2 |= 0x00040000; + feature_sns2 |= 0x00040000; // xsns_38_az7798.ino +#endif +#ifdef USE_MAX31855 + feature_sns2 |= 0x00080000; // xsns_39_max31855.ino +#endif +#ifdef USE_PN532_HSU + feature_sns2 |= 0x00100000; // xsns_40_pn532.ino +#endif +#ifdef USE_MAX44009 + feature_sns2 |= 0x00200000; +#endif +#ifdef USE_SCD30 + feature_sns2 |= 0x00400000; #endif -// feature_sns2 |= 0x00080000; -// feature_sns2 |= 0x00100000; -// feature_sns2 |= 0x00200000; -// feature_sns2 |= 0x00400000; // feature_sns2 |= 0x00800000; // feature_sns2 |= 0x01000000; // feature_sns2 |= 0x02000000; diff --git a/sonoff/support_rotary.ino b/sonoff/support_rotary.ino new file mode 100644 index 000000000..db88d8378 --- /dev/null +++ b/sonoff/support_rotary.ino @@ -0,0 +1,151 @@ +/* + support_rotary.ino - rotary switch support for Sonoff-Tasmota + + Copyright (C) 2019 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define ROTARY_V1 +#ifdef ROTARY_V1 +/*********************************************************************************************\ + * Rotary support +\*********************************************************************************************/ + +unsigned long rotary_debounce = 0; // Rotary debounce timer +uint8_t rotaries_found = 0; +uint8_t rotary_state = 0; +uint8_t rotary_position = 128; +uint8_t rotary_last_position = 128; +uint8_t interrupts_in_use = 0; +uint8_t rotary_changed = 0; + +/********************************************************************************************/ + +void update_position(void) +{ + uint8_t s; + + /* + * https://github.com/PaulStoffregen/Encoder/blob/master/Encoder.h + */ + + s = rotary_state & 3; + if (digitalRead(pin[GPIO_ROT1A])) s |= 4; + if (digitalRead(pin[GPIO_ROT1B])) s |= 8; + switch (s) { + case 0: case 5: case 10: case 15: + break; + case 1: case 7: case 8: case 14: + rotary_position++; break; + case 2: case 4: case 11: case 13: + rotary_position--; break; + case 3: case 12: + rotary_position = rotary_position + 2; break; + default: + rotary_position = rotary_position - 2; break; + } + rotary_state = (s >> 2); +} + +void update_rotary(void) +{ + if (MI_DESK_LAMP == my_module_type){ + if (light_power) { + update_position(); + } + } +} + +void RotaryInit(void) +{ + rotaries_found = 0; + if ((pin[GPIO_ROT1A] < 99) && (pin[GPIO_ROT1B] < 99)) { + rotaries_found++; + pinMode(pin[GPIO_ROT1A], INPUT_PULLUP); + pinMode(pin[GPIO_ROT1B], INPUT_PULLUP); + + // GPIO6-GPIO11 are typically used to interface with the flash memory IC on + // most esp8266 modules, so we should avoid adding interrupts to these pins. + + if ((pin[GPIO_ROT1A] < 6) || (pin[GPIO_ROT1A] > 11)) { + attachInterrupt(digitalPinToInterrupt(pin[GPIO_ROT1A]), update_rotary, CHANGE); + interrupts_in_use++; + } + if ((pin[GPIO_ROT1B] < 6) || (pin[GPIO_ROT1B] > 11)) { + attachInterrupt(digitalPinToInterrupt(pin[GPIO_ROT1B]), update_rotary, CHANGE); + interrupts_in_use++; + } + } +} + +/*********************************************************************************************\ + * Rotary handler +\*********************************************************************************************/ + +void RotaryHandler(void) +{ + if (interrupts_in_use < 2) { + noInterrupts(); + update_rotary(); + } else { + noInterrupts(); + } + if (rotary_last_position != rotary_position) { + if (MI_DESK_LAMP == my_module_type) { // Mi Desk lamp + if (holdbutton[0]) { + rotary_changed = 1; + // button1 is pressed: set color temperature + int16_t t = LightGetColorTemp(); + t = t + (rotary_position - rotary_last_position); + if (t < 153) { + t = 153; + } + if (t > 500) { + t = 500; + } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_CMND_COLORTEMPERATURE " %d"), rotary_position - rotary_last_position); + LightSetColorTemp((uint16_t)t); + } else { + int8_t d = Settings.light_dimmer; + d = d + (rotary_position - rotary_last_position); + if (d < 1) { + d = 1; + } + if (d > 100) { + d = 100; + } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_CMND_DIMMER " %d"), rotary_position - rotary_last_position); + + LightSetDimmer((uint8_t)d); + Settings.light_dimmer = d; + } + } + rotary_last_position = 128; + rotary_position = 128; + } + interrupts(); +} + +void RotaryLoop(void) +{ + if (rotaries_found) { + if (TimeReached(rotary_debounce)) { + SetNextTimeInterval(rotary_debounce, Settings.button_debounce); // Using button_debounce setting for this as well + RotaryHandler(); + } + } +} + +#endif // ROTARY_V1 diff --git a/sonoff/support_rtc.ino b/sonoff/support_rtc.ino index b09c593e2..9a36951f0 100644 --- a/sonoff/support_rtc.ino +++ b/sonoff/support_rtc.ino @@ -1,7 +1,7 @@ /* support_rtc.ino - Real Time Clock support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -43,7 +43,7 @@ uint32_t local_time = 0; uint32_t daylight_saving_time = 0; uint32_t standard_time = 0; uint32_t ntp_time = 0; -uint32_t midnight = 1451602800; +uint32_t midnight = 0; uint32_t restart_time = 0; int32_t time_timezone = 0; uint8_t midnight_now = 0; @@ -60,7 +60,7 @@ String GetBuildDateAndTime(void) int year = 0; // sscanf(mdate, "%s %d %d", bdt, &day, &year); // Not implemented in 2.3.0 and probably too much code - byte i = 0; + uint8_t i = 0; for (char *str = strtok_r(mdate, " ", &p); str && i < 3; str = strtok_r(NULL, " ", &p)) { switch (i++) { case 0: // Month @@ -87,6 +87,23 @@ String GetTimeZone(void) return String(tz); // -03:45 } +String GetDuration(uint32_t time) +{ + char dt[16]; + + TIME_T ut; + BreakTime(time, ut); + + // "P128DT14H35M44S" - ISO8601:2004 - https://en.wikipedia.org/wiki/ISO_8601 Durations +// snprintf_P(dt, sizeof(dt), PSTR("P%dDT%02dH%02dM%02dS"), ut.days, ut.hour, ut.minute, ut.second); + + // "128 14:35:44" - OpenVMS + // "128T14:35:44" - Tasmota + snprintf_P(dt, sizeof(dt), PSTR("%dT%02d:%02d:%02d"), ut.days, ut.hour, ut.minute, ut.second); + + return String(dt); // 128T14:35:44 +} + String GetDT(uint32_t time) { // "2017-03-07T11:08:02" - ISO8601:2004 @@ -112,7 +129,7 @@ String GetDT(uint32_t time) * "2017-03-07T11:08:02-07:00" - if DT_LOCAL and SetOption52 = 1 * "2017-03-07T11:08:02" - otherwise */ -String GetDateAndTime(byte time_type) +String GetDateAndTime(uint8_t time_type) { // "2017-03-07T11:08:02-07:00" - ISO8601:2004 uint32_t time = local_time; @@ -155,42 +172,26 @@ String GetTime(int type) return String(stime); // Thu Nov 01 11:41:02 2018 } +uint32_t UpTime(void) +{ + if (restart_time) { + return utc_time - restart_time; + } else { + return uptime; + } +} + +uint32_t MinutesUptime(void) +{ + return (UpTime() / 60); +} + String GetUptime(void) { - char dt[16]; - - TIME_T ut; - - if (restart_time) { - BreakTime(utc_time - restart_time, ut); - } else { - BreakTime(uptime, ut); - } - - // "P128DT14H35M44S" - ISO8601:2004 - https://en.wikipedia.org/wiki/ISO_8601 Durations -// snprintf_P(dt, sizeof(dt), PSTR("P%dDT%02dH%02dM%02dS"), ut.days, ut.hour, ut.minute, ut.second); - - // "128 14:35:44" - OpenVMS - // "128T14:35:44" - Tasmota - snprintf_P(dt, sizeof(dt), PSTR("%dT%02d:%02d:%02d"), ut.days, ut.hour, ut.minute, ut.second); - - return String(dt); // 128T14:35:44 + return GetDuration(UpTime()); } -uint32_t GetMinutesUptime(void) -{ - TIME_T ut; - - if (restart_time) { - BreakTime(utc_time - restart_time, ut); - } else { - BreakTime(uptime, ut); - } - - return (ut.days *1440) + (ut.hour *60) + ut.minute; -} - -uint32_t GetMinutesPastMidnight(void) +uint32_t MinutesPastMidnight(void) { uint32_t minutes = 0; @@ -322,6 +323,11 @@ uint32_t RuleToTime(TimeRule r, int yr) return t; } +uint32_t UtcTime(void) +{ + return utc_time; +} + uint32_t LocalTime(void) { return local_time; @@ -332,9 +338,9 @@ uint32_t Midnight(void) return midnight; } -boolean MidnightNow(void) +bool MidnightNow(void) { - boolean mnflg = midnight_now; + bool mnflg = midnight_now; if (mnflg) midnight_now = 0; return mnflg; } @@ -348,7 +354,7 @@ void RtcSecond(void) if (!global_state.wifi_down && (offset == RtcTime.second) && ((RtcTime.year < 2016) || (ntp_sync_minute == RtcTime.minute) || ntp_force_sync)) { ntp_time = sntp_get_current_timestamp(); if (ntp_time > 1451602800) { // Fix NTP bug in core 2.4.1/SDK 2.2.1 (returns Thu Jan 01 08:00:10 1970 after power on) - ntp_force_sync = 0; + ntp_force_sync = false; utc_time = ntp_time; ntp_sync_minute = 60; // Sync so block further requests if (restart_time == 0) { @@ -358,9 +364,7 @@ void RtcSecond(void) RtcTime.year = tmpTime.year + 1970; daylight_saving_time = RuleToTime(Settings.tflag[1], RtcTime.year); standard_time = RuleToTime(Settings.tflag[0], RtcTime.year); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "(" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), - GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str()); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "(" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str()); if (local_time < 1451602800) { // 2016-01-01 rules_flag.time_init = 1; } else { @@ -400,10 +404,17 @@ void RtcSecond(void) if (!Settings.energy_kWhtotal_time) { Settings.energy_kWhtotal_time = local_time; } } BreakTime(local_time, RtcTime); - if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second && RtcTime.valid) { - midnight = local_time; - midnight_now = 1; + + if (RtcTime.valid) { + if (!midnight) { + midnight = local_time - (RtcTime.hour * 3600) - (RtcTime.minute * 60) - RtcTime.second; + } + if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second) { + midnight = local_time; + midnight_now = 1; + } } + RtcTime.year += 1970; } diff --git a/sonoff/support_switch.ino b/sonoff/support_switch.ino new file mode 100644 index 000000000..7e84149ba --- /dev/null +++ b/sonoff/support_switch.ino @@ -0,0 +1,221 @@ +/* + support_switch.ino - switch support for Sonoff-Tasmota + + Copyright (C) 2019 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define SWITCH_V2 +#ifdef SWITCH_V2 +/*********************************************************************************************\ + * Switch support with input filter + * + * 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 + +#include + +Ticker TickerSwitch; + +unsigned long switch_debounce = 0; // Switch debounce timer +uint16_t switch_no_pullup = 0; // Switch pull-up bitmask flags +uint8_t switch_state_buf[MAX_SWITCHES] = { 0 }; +uint8_t lastwallswitch[MAX_SWITCHES]; // Last wall switch states +uint8_t holdwallswitch[MAX_SWITCHES] = { 0 }; // Timer for wallswitch push button hold +uint8_t switch_virtual[MAX_SWITCHES]; // Virtual switch states +uint8_t switches_found = 0; + +/********************************************************************************************/ + +void SwitchPullupFlag(uint16 switch_bit) +{ + bitSet(switch_no_pullup, switch_bit); +} + +uint8_t SwitchLastState(uint8_t index) +{ + return lastwallswitch[index]; +} + +void SwitchSetVirtual(uint8_t index, uint8_t state) +{ + switch_virtual[index] = state; +} + +uint8_t SwitchGetVirtual(uint8_t index) +{ + return switch_virtual[index]; +} + +/*********************************************************************************************/ + +void SwitchProbe(void) +{ + if (uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit + + uint8_t state_filter = Settings.switch_debounce / SWITCH_PROBE_INTERVAL; // 5, 10, 15 + uint8_t force_high = (Settings.switch_debounce % 50) &1; // 51, 101, 151 etc + uint8_t force_low = (Settings.switch_debounce % 50) &2; // 52, 102, 152 etc + + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { + if (pin[GPIO_SWT1 +i] < 99) { + // Olimex user_switch2.c code to fix 50Hz induced pulses + if (1 == digitalRead(pin[GPIO_SWT1 +i])) { + + if (force_high) { // Enabled with SwitchDebounce x1 + if (1 == switch_virtual[i]) { + switch_state_buf[i] = state_filter; // With noisy input keep current state 1 unless constant 0 + } + } + + if (switch_state_buf[i] < state_filter) { + switch_state_buf[i]++; + if (state_filter == switch_state_buf[i]) { + switch_virtual[i] = 1; + } + } + } else { + + if (force_low) { // Enabled with SwitchDebounce x2 + if (0 == switch_virtual[i]) { + switch_state_buf[i] = 0; // With noisy input keep current state 0 unless constant 1 + } + } + + if (switch_state_buf[i] > 0) { + switch_state_buf[i]--; + if (0 == switch_state_buf[i]) { + switch_virtual[i] = 0; + } + } + } + } + } + TickerSwitch.attach_ms(SWITCH_PROBE_INTERVAL, SwitchProbe); // Re-arm as core 2.3.0 does only support ONCE mode +} + +void SwitchInit(void) +{ + switches_found = 0; + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { + lastwallswitch[i] = 1; // Init global to virtual switch state; + if (pin[GPIO_SWT1 +i] < 99) { + switches_found++; + pinMode(pin[GPIO_SWT1 +i], bitRead(switch_no_pullup, i) ? INPUT : ((16 == pin[GPIO_SWT1 +i]) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); + lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // Set global now so doesn't change the saved power state on first switch check + } + switch_virtual[i] = lastwallswitch[i]; + } + if (switches_found) { TickerSwitch.attach_ms(SWITCH_PROBE_INTERVAL, SwitchProbe); } +} + +/*********************************************************************************************\ + * Switch handler +\*********************************************************************************************/ + +void SwitchHandler(uint8_t mode) +{ + if (uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit + + uint8_t button = NOT_PRESSED; + uint8_t switchflag; + uint16_t loops_per_second = 1000 / Settings.switch_debounce; + + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { + if ((pin[GPIO_SWT1 +i] < 99) || (mode)) { + + if (holdwallswitch[i]) { + holdwallswitch[i]--; + if (0 == holdwallswitch[i]) { + SendKey(1, i +1, 3); // Execute command via MQTT + } + } + + button = switch_virtual[i]; + +// enum SwitchModeOptions {TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, MAX_SWITCH_OPTION}; + + if (button != lastwallswitch[i]) { + switchflag = 3; + switch (Settings.switchmode[i]) { + case TOGGLE: + switchflag = 2; // Toggle + break; + case FOLLOW: + switchflag = button &1; // Follow wall switch state + break; + case FOLLOW_INV: + switchflag = ~button &1; // Follow inverted wall switch state + break; + case PUSHBUTTON: + if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) { + switchflag = 2; // Toggle with pushbutton to Gnd + } + break; + case PUSHBUTTON_INV: + if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) { + switchflag = 2; // Toggle with releasing pushbutton from Gnd + } + break; + case PUSHBUTTON_TOGGLE: + if (button != lastwallswitch[i]) { + switchflag = 2; // Toggle with any pushbutton change + } + break; + case PUSHBUTTONHOLD: + if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) { + holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; + } + if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) { + holdwallswitch[i] = 0; + switchflag = 2; // Toggle with pushbutton to Gnd + } + break; + case PUSHBUTTONHOLD_INV: + if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) { + holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; + } + if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) { + holdwallswitch[i] = 0; + switchflag = 2; // Toggle with pushbutton to Gnd + } + break; + } + + if (switchflag < 3) { + if (!SendKey(1, i +1, switchflag)) { // Execute command via MQTT + ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < devices_present) + } + } + + lastwallswitch[i] = button; + } + } + } +} + +void SwitchLoop(void) +{ + if (switches_found) { + if (TimeReached(switch_debounce)) { + SetNextTimeInterval(switch_debounce, Settings.switch_debounce); + SwitchHandler(0); + } + } +} + +#endif // SWITCH_V2 diff --git a/sonoff/support_wifi.ino b/sonoff/support_wifi.ino index 8e45f58ea..2c7299991 100644 --- a/sonoff/support_wifi.ino +++ b/sonoff/support_wifi.ino @@ -1,7 +1,7 @@ /* support_wifi.ino - wifi support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,8 +32,26 @@ #define WIFI_CHECK_SEC 20 // seconds #define 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) +#ifdef USE_MQTT_TLS +#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) +#else +#define USING_AXTLS +#include +// force use of AxTLS (BearSSL is now default) which uses less memory (#4952) +#include +using namespace axTLS; +#endif // ARDUINO_ESP8266_RELEASE prior to 2_5_0 +#else +#include // Wifi, MQTT, Ota, WifiManager +#endif // USE_MQTT_TLS +*/ #include // Wifi, MQTT, Ota, WifiManager +uint32_t wifi_last_event = 0; // Last wifi connection event +uint32_t wifi_downtime = 0; // Wifi down duration +uint16_t wifi_link_count = 0; // Number of wifi re-connect uint8_t wifi_counter; uint8_t wifi_retry_init; uint8_t wifi_retry; @@ -41,6 +59,7 @@ uint8_t wifi_status; uint8_t wps_result; uint8_t wifi_config_type = 0; uint8_t wifi_config_counter = 0; +uint8_t mdns_begun = 0; // mDNS active uint8_t wifi_scan_state; uint8_t wifi_bssid[6]; @@ -59,7 +78,7 @@ int WifiGetRssiAsQuality(int rssi) return quality; } -boolean WifiConfigCounter(void) +bool WifiConfigCounter(void) { if (wifi_config_counter) { wifi_config_counter = WIFI_CONFIG_SEC; @@ -88,18 +107,17 @@ void WifiWpsStatusCallback(wps_cb_status status) if (WPS_CB_ST_SUCCESS == wps_result) { wifi_wps_disable(); } else { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_WPS_FAILED_WITH_STATUS " %d"), wps_result); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_WPS_FAILED_WITH_STATUS " %d"), wps_result); wifi_config_counter = 2; } } -boolean WifiWpsConfigDone(void) +bool WifiWpsConfigDone(void) { return (!wps_result); } -boolean WifiWpsConfigBegin(void) +bool WifiWpsConfigBegin(void) { wps_result = 99; if (!wifi_wps_disable()) { return false; } @@ -155,9 +173,9 @@ void WifiConfig(uint8_t type) } #endif // USE_WPS #ifdef USE_WEBSERVER - else if (WIFI_MANAGER == wifi_config_type) { + else if (WIFI_MANAGER == wifi_config_type || WIFI_MANAGER_RESET_ONLY == wifi_config_type) { AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES)); - WifiManagerBegin(); + WifiManagerBegin(WIFI_MANAGER_RESET_ONLY == wifi_config_type); } #endif // USE_WEBSERVER } @@ -206,7 +224,8 @@ void WifiBegin(uint8_t flag, uint8_t channel) delay(200); WiFi.mode(WIFI_STA); // Disable AP mode WiFiSetSleepMode(); -// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); } +// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); } // B/G/N +// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11G) { WiFi.setPhyMode(WIFI_PHY_MODE_11G); } // B/G if (!WiFi.getAutoConnect()) { WiFi.setAutoConnect(true); } // WiFi.setAutoReconnect(true); switch (flag) { @@ -227,9 +246,8 @@ void WifiBegin(uint8_t flag, uint8_t channel) } else { WiFi.begin(Settings.sta_ssid[Settings.sta_active], Settings.sta_pwd[Settings.sta_active]); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CONNECTING_TO_AP "%d %s " D_IN_MODE " 11%c " D_AS " %s..."), + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CONNECTING_TO_AP "%d %s " D_IN_MODE " 11%c " D_AS " %s..."), Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], kWifiPhyMode[WiFi.getPhyMode() & 0x3], my_hostname); - AddLog(LOG_LEVEL_INFO); } void WifiBeginAfterScan() @@ -304,9 +322,8 @@ void WifiBeginAfterScan() break; } } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI "Network %d, AP%c, SSId %s, Channel %d, BSSId %02X:%02X:%02X:%02X:%02X:%02X, RSSI %d, Encryption %d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI "Network %d, AP%c, SSId %s, Channel %d, BSSId %02X:%02X:%02X:%02X:%02X:%02X, RSSI %d, Encryption %d"), i, (known) ? (j) ? '2' : '1' : '-', ssid_scan.c_str(), chan_scan, bssid_scan[0], bssid_scan[1], bssid_scan[2], bssid_scan[3], bssid_scan[4], bssid_scan[5], rssi_scan, (sec_scan == ENC_TYPE_NONE) ? 0 : 1); - AddLog(LOG_LEVEL_DEBUG); delay(0); } WiFi.scanDelete(); // Clean up Ram @@ -323,13 +340,26 @@ void WifiBeginAfterScan() } } +uint16_t WifiLinkCount() +{ + return wifi_link_count; +} + +String WifiDowntime() +{ + return GetDuration(wifi_downtime); +} + void WifiSetState(uint8_t state) { if (state == global_state.wifi_down) { if (state) { rules_flag.wifi_connected = 1; + wifi_link_count++; + wifi_downtime += UpTime() - wifi_last_event; } else { rules_flag.wifi_disconnected = 1; + wifi_last_event = UpTime(); } } global_state.wifi_down = state ^1; @@ -349,6 +379,14 @@ void WifiCheckIp(void) Settings.ip_address[3] = (uint32_t)WiFi.dnsIP(); } wifi_status = WL_CONNECTED; +#ifdef USE_DISCOVERY +#ifdef WEBSERVER_ADVERTISE + if (2 == mdns_begun) { + MDNS.update(); + AddLog_P(LOG_LEVEL_DEBUG_MORE, D_LOG_MDNS, "MDNS.update"); + } +#endif // USE_DISCOVERY +#endif // WEBSERVER_ADVERTISE } else { WifiSetState(0); uint8_t wifi_config_tool = Settings.sta_config; @@ -449,8 +487,7 @@ void WifiCheck(uint8_t param) strlcpy(Settings.sta_pwd[0], WiFi.psk().c_str(), sizeof(Settings.sta_pwd[0])); } Settings.sta_active = 0; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_WCFG_1_SMARTCONFIG D_CMND_SSID "1 %s"), Settings.sta_ssid[0]); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_WCFG_1_SMARTCONFIG D_CMND_SSID "1 %s"), Settings.sta_ssid[0]); } } if (!wifi_config_counter) { @@ -477,23 +514,24 @@ void WifiCheck(uint8_t param) } } -#ifdef BE_MINIMAL +#ifdef FIRMWARE_MINIMAL if (1 == RtcSettings.ota_loader) { RtcSettings.ota_loader = 0; ota_state_flag = 3; } -#endif // BE_MINIMAL +#endif // FIRMWARE_MINIMAL #ifdef USE_DISCOVERY - if (!mdns_begun) { - if (mdns_delayed_start) { - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION)); - mdns_delayed_start--; - } else { - mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START]; - mdns_begun = MDNS.begin(my_hostname); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS "%s"), (mdns_begun) ? D_INITIALIZED : D_FAILED); - AddLog(LOG_LEVEL_INFO); + if (Settings.flag3.mdns_enabled) { + if (!mdns_begun) { +// if (mdns_delayed_start) { +// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION)); +// mdns_delayed_start--; +// } else { +// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START]; + mdns_begun = (uint8_t)MDNS.begin(my_hostname); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (mdns_begun) ? D_INITIALIZED : D_FAILED); +// } } } #endif // USE_DISCOVERY @@ -503,7 +541,8 @@ void WifiCheck(uint8_t param) StartWebserver(Settings.webserver, WiFi.localIP()); #ifdef USE_DISCOVERY #ifdef WEBSERVER_ADVERTISE - if (mdns_begun) { + if (1 == mdns_begun) { + mdns_begun = 2; MDNS.addService("http", "tcp", WEB_PORT); } #endif // WEBSERVER_ADVERTISE @@ -528,7 +567,7 @@ void WifiCheck(uint8_t param) #if defined(USE_WEBSERVER) && defined(USE_EMULATION) UdpDisconnect(); #endif // USE_EMULATION - mdns_begun = false; + mdns_begun = 0; #ifdef USE_KNX knx_started = false; #endif // USE_KNX diff --git a/sonoff/user_config_override_sample.h b/sonoff/user_config_override_sample.h index 8d0abb22f..9a48d2d50 100644 --- a/sonoff/user_config_override_sample.h +++ b/sonoff/user_config_override_sample.h @@ -1,7 +1,7 @@ /* user_config_override.h - user configuration overrides my_user_config.h for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ #ifndef _USER_CONFIG_OVERRIDE_H_ #define _USER_CONFIG_OVERRIDE_H_ -// force the compiler to show a warning to confirm that this file is inlcuded +// force the compiler to show a warning to confirm that this file is included #warning **** user_config_override.h: Using Settings from this File **** /*****************************************************************************************************\ @@ -74,7 +74,7 @@ Examples : #ifdef MY_IP #undef WIFI_IP_ADDRESS -#define WIFI_IP_ADDRESS MY_IP // Set to 0.0.0.0 for using DHCP or IP address +#define WIFI_IP_ADDRESS MY_IP // Set to 0.0.0.0 for using DHCP or enter a static IP address #endif #ifdef MY_GW @@ -93,4 +93,4 @@ Examples : -#endif // _USER_CONFIG_OVERRIDE_H_ \ No newline at end of file +#endif // _USER_CONFIG_OVERRIDE_H_ diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index 046181283..9d96c480c 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -1,7 +1,7 @@ /* xdrv_01_webserver.ino - webserver for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,6 +27,8 @@ #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 #endif @@ -49,16 +51,16 @@ const char HTTP_HEAD[] PROGMEM = "" "" "" - "{h} - {v}" + "%s - %s" ""; + "window.onload=u;"; const char HTTP_SCRIPT_ROOT[] PROGMEM = "function la(p){" @@ -75,24 +77,25 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM = "a=p;" "clearTimeout(lt);" "}" - "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) + "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) "x=new XMLHttpRequest();" "x.onreadystatechange=function(){" "if(x.readyState==4&&x.status==200){" - "var s=x.responseText.replace(/{t}/g,\"\").replace(/{s}/g,\"\").replace(/{c}/g,\"%'>
\").replace(/{s}/g,\"
\").replace(/{c}/g,\"%%'>
hasArg("m") "x.send();" - "lt=setTimeout(la,{a});" // Settings.web_refresh + "lt=setTimeout(la,%d);" // Settings.web_refresh "}" "function lb(p){" - "la('?d='+p);" // ?d related to WebGetArg("d", tmp, sizeof(tmp)); + "la('&d='+p);" // &d related to WebGetArg("d", tmp, sizeof(tmp)); "}" "function lc(p){" - "la('?t='+p);" // ?t related to WebGetArg("t", tmp, sizeof(tmp)); - "}"; + "la('&t='+p);" // &t related to WebGetArg("t", tmp, sizeof(tmp)); + "}" + "window.onload=la();"; const char HTTP_SCRIPT_WIFI[] PROGMEM = "function c(l){" @@ -101,18 +104,16 @@ const char HTTP_SCRIPT_WIFI[] PROGMEM = "}"; const char HTTP_SCRIPT_RELOAD[] PROGMEM = - "setTimeout(function(){location.href='.';}," STR(HTTP_RESTART_RECONNECT_TIME) ");" - ""; + "setTimeout(function(){location.href='.';}," STR(HTTP_RESTART_RECONNECT_TIME) ");"; // Local OTA upgrade requires more time to complete cp: before web ui should be reloaded const char HTTP_SCRIPT_RELOAD_OTA[] PROGMEM = - "setTimeout(function(){location.href='.';}," STR(HTTP_OTA_RESTART_RECONNECT_TIME) ");" - ""; + "setTimeout(function(){location.href='.';}," STR(HTTP_OTA_RESTART_RECONNECT_TIME) ");"; const char HTTP_SCRIPT_CONSOL[] PROGMEM = - "var sn=0;" // Scroll position - "var id=0;" // Get most of weblog initially - "function l(p){" // Console log and command service + "var sn=0;" // Scroll position + "var id=0;" // Get most of weblog initially + "function l(p){" // Console log and command service "var c,o,t;" "clearTimeout(lt);" "o='';" @@ -123,75 +124,131 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM = "c.value='';" "t.scrollTop=sn;" "}" - "if(t.scrollTop>=sn){" // User scrolled back so no updates - "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) + "if(t.scrollTop>=sn){" // User scrolled back so no updates + "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) "x=new XMLHttpRequest();" "x.onreadystatechange=function(){" "if(x.readyState==4&&x.status==200){" "var z,d;" - "d=x.responseXML;" - "id=d.getElementsByTagName('i')[0].childNodes[0].nodeValue;" - "if(d.getElementsByTagName('j')[0].childNodes[0].nodeValue==0){t.value='';}" - "z=d.getElementsByTagName('l')[0].childNodes;" - "if(z.length>0){t.value+=decodeURIComponent(z[0].nodeValue);}" + "d=x.responseText.split(/}1/);" // Field separator + "id=d.shift();" + "if(d.shift()==0){t.value='';}" + "z=d.shift();" + "if(z.length>0){t.value+=z;}" "t.scrollTop=99999;" "sn=t.scrollTop;" "}" "};" - "x.open('GET','ax?c2='+id+o,true);" + "x.open('GET','cs?c2='+id+o,true);" // Related to WebServer->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp)) "x.send();" "}" - "lt=setTimeout(l,{a});" + "lt=setTimeout(l,%d);" "return false;" "}" - ""; + "window.onload=l;"; -const char HTTP_SCRIPT_MODULE1[] PROGMEM = +const char HTTP_MODULE_TEMPLATE_REPLACE[] PROGMEM = + "}2%d'>%s (%d}3"; // }2 and }3 are used in below os.replace + +const char HTTP_SCRIPT_MODULE_TEMPLATE[] PROGMEM = "var os;" - "function sk(s,g){" // s = value, g = id and name - "var o=os.replace(\"value='\"+s+\"'\",\"selected value='\"+s+\"'\");" + "function sk(s,g){" // s = value, g = id and name + "var o=os.replace(/}2/g,\"
"); - byte idx = 0; - for (byte i = 0; i < 4; i++) { - if (idx > 0) { page += F(""); } - for (byte j = 0; j < 4; j++) { - idx++; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(""), idx, idx); // ?k is related to WebGetArg("k", tmp, sizeof(tmp)); - page += mqtt_data; - } - } - page += F("
\").replace(/{m}/g,\"\").replace(/{e}/g,\"
\").replace(/{m}/g,\"\").replace(/{e}/g,\"
\").replace(/}2/g,\"\");" "eb('i').innerHTML=s;" "}" - ""; + "window.onload=i;"; -const char HTTP_HEAD_STYLE[] PROGMEM = +const char HTTP_HEAD_STYLE1[] PROGMEM = "" "" "" "" "
" -#ifdef BE_MINIMAL +#ifdef FIRMWARE_MINIMAL "

" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "

" #endif "
" #ifdef LANGUAGE_MODULE_NAME - "

" D_MODULE " {ha

" + "

" D_MODULE " %s

" #else - "

{ha " D_MODULE "

" + "

%s " D_MODULE "

" #endif - "

{h}

{j}
"; + "

%s

%s
"; + const char HTTP_MSG_SLIDER1[] PROGMEM = "
" D_COLDLIGHT "" D_WARMLIGHT "
" "
"; @@ -223,78 +282,69 @@ const char HTTP_MSG_SLIDER2[] PROGMEM = "
"; const char HTTP_MSG_RSTRT[] PROGMEM = "
" D_DEVICE_WILL_RESTART "

"; -const char HTTP_BTN_MENU1[] PROGMEM = -#ifndef BE_MINIMAL - "
" - "
" -#endif - "
" - "
"; -const char HTTP_BTN_RSTRT[] PROGMEM = - "
"; -const char HTTP_BTN_MENU_MODULE[] PROGMEM = - "
" - "
"; -const char HTTP_BTN_MENU4[] PROGMEM = - "
" - "
" - "
" - "
" - "
" - "
"; -const char HTTP_BTN_MAIN[] PROGMEM = - "

"; + const char HTTP_FORM_LOGIN[] PROGMEM = + "
" "
" - "
" D_USER "

" - "
" D_PASSWORD "

" + "

" D_USER "

" + "

" D_PASSWORD "

" "
" - "
"; -const char HTTP_BTN_CONF[] PROGMEM = - "

"; + "" + "
"; + +const char HTTP_FORM_TEMPLATE[] PROGMEM = + "
 " D_TEMPLATE_PARAMETERS " " + "
" + "

" D_TEMPLATE_NAME "

" + "

" D_BASE_TYPE "

"; +const char HTTP_FORM_TEMPLATE_FLAG[] PROGMEM = + "

" // Keep close so do not use
+ "
 " D_TEMPLATE_FLAGS " 

" + "" D_ALLOW_ADC0 "
" + "

"; + const char HTTP_FORM_MODULE[] PROGMEM = - "
 " D_MODULE_PARAMETERS " " - "
" D_MODULE_TYPE " ({mt)

"; -const char HTTP_LNK_ITEM[] PROGMEM = - "
{v} ({w}) {i} {r}%
"; -const char HTTP_LNK_SCAN[] PROGMEM = - "
"; + "
 " D_MODULE_PARAMETERS " " + "" + "

" D_MODULE_TYPE " (%s)

" + "
"; + const char HTTP_FORM_WIFI[] PROGMEM = - "
 " D_WIFI_PARAMETERS " " - "
" D_AP1_SSID " (" STA_SSID1 ")

" - "
" D_AP1_PASSWORD "

" - "
" D_AP2_SSID " (" STA_SSID2 ")

" - "
" D_AP2_PASSWORD "

" - "
" D_HOSTNAME " (" WIFI_HOSTNAME ")

"; + "
 " D_WIFI_PARAMETERS " " + "" + "

" D_AP1_SSID " (" STA_SSID1 ")

" + "

" D_AP1_PASSWORD "

" + "

" D_AP2_SSID " (" STA_SSID2 ")

" + "

" D_AP2_PASSWORD "

" + "

" D_HOSTNAME " (%s)

"; + const char HTTP_FORM_LOG1[] PROGMEM = - "
 " D_LOGGING_PARAMETERS " "; + "
 " D_LOGGING_PARAMETERS " " + ""; const char HTTP_FORM_LOG2[] PROGMEM = - "
{b0 ({b1)

"; -const char HTTP_FORM_LOG3[] PROGMEM = - "
" D_SYSLOG_HOST " (" SYS_LOG_HOST ")

" - "
" D_SYSLOG_PORT " (" STR(SYS_LOG_PORT) ")

" - "
" D_TELEMETRY_PERIOD " (" STR(TELE_PERIOD) ")

"; + "

" D_SYSLOG_HOST " (" SYS_LOG_HOST ")

" + "

" D_SYSLOG_PORT " (" STR(SYS_LOG_PORT) ")

" + "

" D_TELEMETRY_PERIOD " (" STR(TELE_PERIOD) ")

"; + const char HTTP_FORM_OTHER[] PROGMEM = - "
 " D_OTHER_PARAMETERS " " -// "" - "
" D_WEB_ADMIN_PASSWORD "

" - "
" D_MQTT_ENABLE "
"; - const char HTTP_FORM_OTHER2[] PROGMEM = - "
" D_FRIENDLY_NAME " {1 ({2)

"; -#ifdef USE_EMULATION -const char HTTP_FORM_OTHER3a[] PROGMEM = - "
 " D_EMULATION " "; -const char HTTP_FORM_OTHER3b[] PROGMEM = - "
{3{4"; // Different id only used for labels -#endif // USE_EMULATION + "
 " D_OTHER_PARAMETERS " " + "" + "

" + "
 " D_TEMPLATE " " + "

" + "

" D_ACTIVATE "

" + "
" + "
" + "" D_WEB_ADMIN_PASSWORD "

" + "
" + "" D_MQTT_ENABLE "
" + "
"; + const char HTTP_FORM_END[] PROGMEM = - "
"; + "
" + "" + "
"; + const char HTTP_FORM_RST[] PROGMEM = "
" "
 " D_RESTORE_CONFIGURATION " "; @@ -302,51 +352,79 @@ const char HTTP_FORM_UPG[] PROGMEM = "
" "
 " D_UPGRADE_BY_WEBSERVER " " "
" - "
" D_OTA_URL "

" + "
" D_OTA_URL "

" "
" "


" "
 " D_UPGRADE_BY_FILE_UPLOAD " "; const char HTTP_FORM_RST_UPG[] PROGMEM = "
" "

" - "
" + "
" "
" "
" ""; + const char HTTP_FORM_CMND[] PROGMEM = "


" "
" "
" // "
" ""; + const char HTTP_TABLE100[] PROGMEM = - "
"; + "
"; + const char HTTP_COUNTER[] PROGMEM = "
"; + const char HTTP_END[] PROGMEM = "
" - "" + "" "" "" ""; -const char HTTP_DEVICE_CONTROL[] PROGMEM = ""; // ?o is related to WebGetArg("o", tmp, sizeof(tmp)); +const char HTTP_DEVICE_CONTROL[] PROGMEM = ""; // ?o is related to WebGetArg("o", tmp, sizeof(tmp)); const char HTTP_DEVICE_STATE[] PROGMEM = "%s"; // {c} = %'>
0) && (source < SRC_MAX)) { char stemp1[20]; - snprintf_P(log_data, sizeof(log_data), PSTR("SRC: %s from %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource), WebServer->client().remoteIP().toString().c_str()); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SRC: %s from %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource), WebServer->client().remoteIP().toString().c_str()); } } @@ -383,22 +464,21 @@ void StartWebserver(int type, IPAddress ipweb) if (!Settings.web_refresh) { Settings.web_refresh = HTTP_REFRESH_TIME; } if (!webserver_state) { if (!WebServer) { - WebServer = new ESP8266WebServer((HTTP_MANAGER==type) ? 80 : WEB_PORT); + WebServer = new ESP8266WebServer((HTTP_MANAGER == type || HTTP_MANAGER_RESET_ONLY == type) ? 80 : WEB_PORT); WebServer->on("/", HandleRoot); + WebServer->onNotFound(HandleNotFound); WebServer->on("/up", HandleUpgradeFirmware); WebServer->on("/u1", HandleUpgradeFirmwareStart); // OTA WebServer->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop); WebServer->on("/u2", HTTP_OPTIONS, HandlePreflightRequest); WebServer->on("/cs", HandleConsole); - WebServer->on("/ax", HandleAjaxConsoleRefresh); - WebServer->on("/ay", HandleAjaxStatusRefresh); WebServer->on("/cm", HandleHttpCommand); - WebServer->onNotFound(HandleNotFound); -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL WebServer->on("/cn", HandleConfiguration); WebServer->on("/md", HandleModuleConfiguration); WebServer->on("/wi", HandleWifiConfiguration); WebServer->on("/lg", HandleLoggingConfiguration); + WebServer->on("/tp", HandleTemplateConfiguration); WebServer->on("/co", HandleOtherConfiguration); WebServer->on("/dl", HandleBackupConfiguration); WebServer->on("/rs", HandleRestoreConfiguration); @@ -409,15 +489,13 @@ void StartWebserver(int type, IPAddress ipweb) #endif // USE_EMULATION XdrvCall(FUNC_WEB_ADD_HANDLER); XsnsCall(FUNC_WEB_ADD_HANDLER); -#endif // Not BE_MINIMAL +#endif // Not FIRMWARE_MINIMAL } - reset_web_log_flag = 0; + reset_web_log_flag = false; WebServer->begin(); // Web server start } if (webserver_state != type) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), - my_hostname, (mdns_begun) ? ".local" : "", ipweb.toString().c_str()); - AddLog(LOG_LEVEL_INFO); + 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()); } if (type) { webserver_state = type; } } @@ -431,7 +509,7 @@ void StopWebserver(void) } } -void WifiManagerBegin(void) +void WifiManagerBegin(bool reset_only) { // setup AP if (!global_state.wifi_down) { @@ -455,7 +533,7 @@ void WifiManagerBegin(void) DnsServer->setErrorReplyCode(DNSReplyCode::NoError); DnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); - StartWebserver(HTTP_MANAGER, WiFi.softAPIP()); + StartWebserver((reset_only ? HTTP_MANAGER_RESET_ONLY : HTTP_MANAGER), WiFi.softAPIP()); } void PollDnsWebserver(void) @@ -466,35 +544,30 @@ void PollDnsWebserver(void) /*********************************************************************************************/ -void SetHeader(void) -{ - WebServer->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); - WebServer->sendHeader(F("Pragma"), F("no-cache")); - WebServer->sendHeader(F("Expires"), F("-1")); -#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 - WebServer->sendHeader(F("Access-Control-Allow-Origin"), F("*")); -#endif -} - bool WebAuthenticate(void) { - if (Settings.web_password[0] != 0) { + if (Settings.web_password[0] != 0 && HTTP_MANAGER_RESET_ONLY != webserver_state) { return WebServer->authenticate(WEB_USERNAME, Settings.web_password); } else { return true; } } -void ShowPage(String &page, bool auth) +bool HttpCheckPriviledgedAccess(bool autorequestauth = true) { - if (auth && (Settings.web_password[0] != 0) && !WebServer->authenticate(WEB_USERNAME, Settings.web_password)) { - return WebServer->requestAuthentication(); + if (HTTP_USER == webserver_state) { + HandleRoot(); + return false; } + if (autorequestauth && !WebAuthenticate()) { + WebServer->requestAuthentication(); + return false; + } + return true; +} - page.replace(F("{a}"), String(Settings.web_refresh)); - page.replace(F("{ha"), my_module.name); - page.replace(F("{h}"), Settings.friendlyname[0]); - +String WSNetworkInfo(void) +{ String info = ""; if (Settings.flag3.gui_hostname_ip) { uint8_t more_ips = 0; @@ -511,30 +584,170 @@ void ShowPage(String &page, bool auth) } info += F(")"); } - page.replace(F("{j}"), info); + return info; +} - if (HTTP_MANAGER == webserver_state) { +void WSHeaderSend(void) +{ + WebServer->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); + WebServer->sendHeader(F("Pragma"), F("no-cache")); + WebServer->sendHeader(F("Expires"), F("-1")); +#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 + WebServer->sendHeader(F("Access-Control-Allow-Origin"), F("*")); +#endif +} + +/********************************************************************************************** +* HTTP Content Page handler +**********************************************************************************************/ + +void WSSend(int code, int ctype, const String& content) +{ + char ct[25]; // strlen("application/octet-stream") +1 = Longest Content type string + WebServer->send(code, GetTextIndexed(ct, sizeof(ct), ctype, kContentTypes), content); +} + +/********************************************************************************************** +* HTTP Content Chunk handler +**********************************************************************************************/ + +void _WSContentSend(const String& content) // Low level sendContent for all core versions +{ + size_t len = content.length(); + +#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 + const char * footer = "\r\n"; + char chunk_size[11]; + sprintf(chunk_size, "%x\r\n", len); + WebServer->sendContent(String() + chunk_size + content + footer); +#else + WebServer->sendContent(content); +#endif + +#ifdef USE_DEBUG_DRIVER + ShowFreeMem(PSTR("WSContentSend")); +#endif +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HTP: Chunk size %d"), len); +} + +void WSContentFlush() +{ + if (chunk_buffer.length() > 0) { + _WSContentSend(chunk_buffer); // Flush chunk buffer + chunk_buffer = ""; + } +} + +void WSContentSend_P(const char* formatP, ...) // Content send snprintf_P char data +{ + // This uses char strings. Be aware of sending %% if % is needed + va_list arg; + va_start(arg, formatP); + int len = vsnprintf_P(mqtt_data, sizeof(mqtt_data), formatP, arg); + va_end(arg); + + if (0 == len) { // No content + return; + } + else if (len == sizeof(mqtt_data)) { + AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: Content too large")); + } + else if (len < CHUNKED_BUFFER_SIZE) { // Append chunk buffer with small content + chunk_buffer += mqtt_data; + len = chunk_buffer.length(); + } + + if (len >= CHUNKED_BUFFER_SIZE) { // Either content or chunk buffer is oversize + WSContentFlush(); // Send chunk buffer before possible content oversize + } + if (strlen(mqtt_data) >= CHUNKED_BUFFER_SIZE) { // Content is oversize + _WSContentSend(mqtt_data); // Send content + } +} + +void WSContentStart_P(const char* title, bool auth) +{ + if (auth && (Settings.web_password[0] != 0) && !WebServer->authenticate(WEB_USERNAME, Settings.web_password)) { + return WebServer->requestAuthentication(); + } + + WebServer->client().flush(); + WebServer->setContentLength(CONTENT_LENGTH_UNKNOWN); + WSHeaderSend(); +#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 + WebServer->sendHeader(F("Accept-Ranges"),F("none")); + WebServer->sendHeader(F("Transfer-Encoding"),F("chunked")); +#endif + WSSend(200, CT_HTML, ""); // Signal start of chunked content + chunk_buffer = ""; + + char ctitle[strlen_P(title) +1]; + strcpy_P(ctitle, title); // Get title from flash to RAM + WSContentSend_P(HTTP_HEAD, Settings.friendlyname[0], ctitle); +} + +void WSContentStart_P(const char* title) +{ + WSContentStart_P(title, true); +} + +void WSContentSendStyle_P(const char* style) +{ + if (WifiIsInManagerMode()) { if (WifiConfigCounter()) { - page.replace(F(""), FPSTR(HTTP_SCRIPT_COUNTER)); - page.replace(F(""), F("")); - page += FPSTR(HTTP_COUNTER); + WSContentSend_P(HTTP_SCRIPT_COUNTER); } } - page += FPSTR(HTTP_END); - page.replace(F("{mv"), my_version); - SetHeader(); - - ShowFreeMem(PSTR("ShowPage")); - - WebServer->send(200, FPSTR(HDR_CTYPE_HTML), page); + WSContentSend_P(HTTP_HEAD_STYLE1); + WSContentSend_P(HTTP_HEAD_STYLE2); + WSContentSend_P(style); + WSContentSend_P(HTTP_HEAD_STYLE3, ModuleName().c_str(), Settings.friendlyname[0], WSNetworkInfo().c_str()); } -void ShowPage(String &page) +void WSContentSendStyle(void) { - ShowPage(page, true); + WSContentSendStyle_P(PSTR("")); } -/*-------------------------------------------------------------------------------------------*/ +void WSContentButton(uint8_t title_index) +{ + char action[4]; + char title[32]; + + if (title_index <= BUTTON_RESET_CONFIGURATION) { + char confirm[64]; + WSContentSend_P(PSTR("

"), + GetTextIndexed(action, sizeof(action), title_index, kButtonAction), + GetTextIndexed(confirm, sizeof(confirm), title_index, kButtonConfirm), + (!title_index) ? "rst" : "non", + GetTextIndexed(title, sizeof(title), title_index, kButtonTitle)); + } else { + WSContentSend_P(PSTR("

"), + GetTextIndexed(action, sizeof(action), title_index, kButtonAction), + GetTextIndexed(title, sizeof(title), title_index, kButtonTitle)); + } +} + +void WSContentSpaceButton(uint8_t title_index) +{ + WSContentSend_P(PSTR("
")); // 5px padding + WSContentButton(title_index); +} + +void WSContentEnd(void) +{ + if (WifiIsInManagerMode()) { + if (WifiConfigCounter()) { + WSContentSend_P(HTTP_COUNTER); + } + } + WSContentSend_P(HTTP_END, my_version); + WSContentFlush(); // Flush chunk buffer + _WSContentSend(""); // Signal end of chunked content + WebServer->client().stop(); +} + +/*********************************************************************************************/ void WebRestart(uint8_t type) { @@ -543,29 +756,25 @@ void WebRestart(uint8_t type) // type 2 = restart after config change with possible ip address change too AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESTART); - String page = FPSTR(HTTP_HEAD); - page += FPSTR(HTTP_HEAD_STYLE); + bool reset_only = (HTTP_MANAGER_RESET_ONLY == webserver_state); + WSContentStart_P((type) ? S_SAVE_CONFIGURATION : S_RESTART, !reset_only); + WSContentSend_P(HTTP_SCRIPT_RELOAD); + WSContentSendStyle(); if (type) { - page.replace(F("{v}"), FPSTR(S_SAVE_CONFIGURATION)); - page += F("
" D_CONFIGURATION_SAVED "
"); + WSContentSend_P(PSTR("
" D_CONFIGURATION_SAVED "
")); if (2 == type) { - page += F("
" D_TRYING_TO_CONNECT "
"); + WSContentSend_P(PSTR("
" D_TRYING_TO_CONNECT "
")); } - page += F("
"); + WSContentSend_P(PSTR("
")); } - else { - page.replace(F("{v}"), FPSTR(S_RESTART)); - } - - page += FPSTR(HTTP_MSG_RSTRT); - if (HTTP_MANAGER == webserver_state) { + WSContentSend_P(HTTP_MSG_RSTRT); + if (HTTP_MANAGER == webserver_state || reset_only) { webserver_state = HTTP_ADMIN; } else { - page += FPSTR(HTTP_BTN_MAIN); + WSContentSpaceButton(BUTTON_MAIN); } - page.replace(F(""), FPSTR(HTTP_SCRIPT_RELOAD)); - ShowPage(page); + WSContentEnd(); ShowWebSource(SRC_WEBGUI); restart_flag = 2; @@ -575,124 +784,133 @@ void WebRestart(uint8_t type) void HandleWifiLogin(void) { - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR( D_CONFIGURE_WIFI )); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_LOGIN); - ShowPage(page, false); // false means show page no matter if the client has or has not credentials + WSContentStart_P(S_CONFIGURE_WIFI, false); // false means show page no matter if the client has or has not credentials + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_LOGIN); + + if (HTTP_MANAGER_RESET_ONLY == webserver_state) { + WSContentSpaceButton(BUTTON_RESTART); +#ifndef FIRMWARE_MINIMAL + WSContentSpaceButton(BUTTON_RESET_CONFIGURATION); +#endif // FIRMWARE_MINIMAL + } + + WSContentEnd(); } void HandleRoot(void) { - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_MAIN_MENU); - if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the page. - if ( WebServer->hasArg("rstrt") ) { + if (WebServer->hasArg("rst")) { WebRestart(0); return; } - if (HTTP_MANAGER == webserver_state) { -#ifndef BE_MINIMAL - if ((Settings.web_password[0] != 0) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1"))) { + if (WifiIsInManagerMode()) { +#ifndef FIRMWARE_MINIMAL + if ((Settings.web_password[0] != 0) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1")) && HTTP_MANAGER_RESET_ONLY != webserver_state) { HandleWifiLogin(); } else { -/* - char tmp1[100]; - WebGetArg("USER1", tmp1, sizeof(tmp1)); - char tmp2[100]; - WebGetArg("PASS1", tmp2, sizeof(tmp2)); - if (!(Settings.web_password[0] != 0) || (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, Settings.web_password)))) { -*/ - if (!(Settings.web_password[0] != 0) || ((WebServer->arg("USER1") == WEB_USERNAME ) && (WebServer->arg("PASS1") == Settings.web_password ))) { + if (!(Settings.web_password[0] != 0) || ((WebServer->arg("USER1") == WEB_USERNAME ) && (WebServer->arg("PASS1") == Settings.web_password ) || HTTP_MANAGER_RESET_ONLY == webserver_state)) { HandleWifiConfiguration(); } else { // wrong user and pass HandleWifiLogin(); } } -#endif // Not BE_MINIMAL - } else { - char stemp[10]; - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_MAIN_MENU)); - page += FPSTR(HTTP_SCRIPT_ROOT); - page += FPSTR(HTTP_HEAD_STYLE); - page.replace(F(""), F("")); - - page += F("
"); - if (devices_present) { - if (light_type) { - if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER1, LightGetColorTemp()); - page += mqtt_data; - } - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER2, Settings.light_dimmer); - page += mqtt_data; - } - page += FPSTR(HTTP_TABLE100); - page += F("
"); - if (SONOFF_IFAN02 == Settings.module) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 36, 1, D_BUTTON_TOGGLE, ""); - page += mqtt_data; - for (byte i = 0; i < MAX_FAN_SPEED; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i); - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 16, i +2, stemp, ""); - page += mqtt_data; - } - } else { - for (byte idx = 1; idx <= devices_present; idx++) { - snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx); - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, - 100 / devices_present, idx, (devices_present < 5) ? D_BUTTON_TOGGLE : "", (devices_present > 1) ? stemp : ""); - page += mqtt_data; - } - } - page += F("
%s
"); - } - if (SONOFF_BRIDGE == Settings.module) { - page += FPSTR(HTTP_TABLE100); - page += F("
"); - } - -#ifndef BE_MINIMAL - mqtt_data[0] = '\0'; - XdrvCall(FUNC_WEB_ADD_MAIN_BUTTON); - XsnsCall(FUNC_WEB_ADD_MAIN_BUTTON); - page += String(mqtt_data); -#endif // Not BE_MINIMAL - - if (HTTP_ADMIN == webserver_state) { - page += FPSTR(HTTP_BTN_MENU1); - page += FPSTR(HTTP_BTN_RSTRT); - } - ShowPage(page); +#endif // Not FIRMWARE_MINIMAL + return; } + + if (HandleRootStatusRefresh()) { + return; + } + + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_MAIN_MENU); + + char stemp[5]; + + WSContentStart_P(S_MAIN_MENU); + WSContentSend_P(HTTP_SCRIPT_ROOT, Settings.web_refresh); + WSContentSendStyle(); + + WSContentSend_P(PSTR("
")); + if (devices_present) { + if (light_type) { + if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) { + WSContentSend_P(HTTP_MSG_SLIDER1, LightGetColorTemp()); + } + WSContentSend_P(HTTP_MSG_SLIDER2, Settings.light_dimmer); + } + WSContentSend_P(HTTP_TABLE100); + WSContentSend_P(PSTR("")); + if (SONOFF_IFAN02 == my_module_type) { + WSContentSend_P(HTTP_DEVICE_CONTROL, 36, 1, D_BUTTON_TOGGLE, ""); + for (uint8_t i = 0; i < MAX_FAN_SPEED; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i); + WSContentSend_P(HTTP_DEVICE_CONTROL, 16, i +2, stemp, ""); + } + } else { + for (uint8_t idx = 1; idx <= devices_present; idx++) { + snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx); + WSContentSend_P(HTTP_DEVICE_CONTROL, 100 / devices_present, idx, (devices_present < 5) ? D_BUTTON_TOGGLE : "", (devices_present > 1) ? stemp : ""); + } + } + WSContentSend_P(PSTR("")); + } + if (SONOFF_BRIDGE == my_module_type) { + WSContentSend_P(HTTP_TABLE100); + WSContentSend_P(PSTR("")); + uint8_t idx = 0; + for (uint8_t i = 0; i < 4; i++) { + if (idx > 0) { WSContentSend_P(PSTR("")); } + for (uint8_t j = 0; j < 4; j++) { + idx++; + WSContentSend_P(PSTR(""), idx, idx); // &k is related to WebGetArg("k", tmp, sizeof(tmp)); + } + } + WSContentSend_P(PSTR("")); + } + +#ifndef FIRMWARE_MINIMAL + XdrvCall(FUNC_WEB_ADD_MAIN_BUTTON); + XsnsCall(FUNC_WEB_ADD_MAIN_BUTTON); +#endif // Not FIRMWARE_MINIMAL + + if (HTTP_ADMIN == webserver_state) { +#ifdef FIRMWARE_MINIMAL + WSContentSpaceButton(BUTTON_FIRMWARE_UPGRADE); +#else + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentButton(BUTTON_INFORMATION); + WSContentButton(BUTTON_FIRMWARE_UPGRADE); +#endif // Not FIRMWARE_MINIMAL + WSContentButton(BUTTON_CONSOLE); + WSContentButton(BUTTON_RESTART); + } + WSContentEnd(); } -void HandleAjaxStatusRefresh(void) +bool HandleRootStatusRefresh(void) { - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!WebAuthenticate()) { + WebServer->requestAuthentication(); + return true; + } - char svalue[80]; - char tmp[100]; + if (!WebServer->hasArg("m")) { // Status refresh requested + return false; + } - WebGetArg("o", tmp, sizeof(tmp)); + char tmp[8]; // WebGetArg numbers only + char svalue[32]; // Command and number parameter + + WebGetArg("o", tmp, sizeof(tmp)); // 1 - 16 Device number for button Toggle or Fanspeed if (strlen(tmp)) { ShowWebSource(SRC_WEBGUI); uint8_t device = atoi(tmp); - if (SONOFF_IFAN02 == Settings.module) { + if (SONOFF_IFAN02 == my_module_type) { if (device < 2) { ExecuteCommandPower(1, POWER_TOGGLE, SRC_IGNORE); } else { @@ -703,17 +921,17 @@ void HandleAjaxStatusRefresh(void) ExecuteCommandPower(device, POWER_TOGGLE, SRC_IGNORE); } } - WebGetArg("d", tmp, sizeof(tmp)); + WebGetArg("d", tmp, sizeof(tmp)); // 0 - 100 Dimmer value if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_DIMMER " %s"), tmp); ExecuteWebCommand(svalue, SRC_WEBGUI); } - WebGetArg("t", tmp, sizeof(tmp)); + WebGetArg("t", tmp, sizeof(tmp)); // 153 - 500 Color temperature if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_COLORTEMPERATURE " %s"), tmp); ExecuteWebCommand(svalue, SRC_WEBGUI); } - WebGetArg("k", tmp, sizeof(tmp)); + WebGetArg("k", tmp, sizeof(tmp)); // 1 - 16 Pre defined RF keys if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_RFKEY "%s"), tmp); ExecuteWebCommand(svalue, SRC_WEBGUI); @@ -732,7 +950,7 @@ void HandleAjaxStatusRefresh(void) if (devices_present) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{t}"), mqtt_data); uint8_t fsize = (devices_present < 5) ? 70 - (devices_present * 8) : 32; - if (SONOFF_IFAN02 == Settings.module) { + if (SONOFF_IFAN02 == my_module_type) { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_STATE, mqtt_data, 36, (bitRead(power, 0)) ? "bold" : "normal", 54, GetStateText(bitRead(power, 0))); uint8_t fanspeed = GetFanspeed(); @@ -740,7 +958,7 @@ void HandleAjaxStatusRefresh(void) snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_STATE, mqtt_data, 64, (fanspeed) ? "bold" : "normal", 54, (fanspeed) ? svalue : GetStateText(0)); } else { - for (byte idx = 1; idx <= devices_present; idx++) { + for (uint8_t idx = 1; idx <= devices_present; idx++) { snprintf_P(svalue, sizeof(svalue), PSTR("%d"), bitRead(power, idx -1)); snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_STATE, mqtt_data, 100 / devices_present, (bitRead(power, idx -1)) ? "bold" : "normal", fsize, (devices_present < 5) ? GetStateText(bitRead(power, idx -1)) : svalue); @@ -748,47 +966,167 @@ void HandleAjaxStatusRefresh(void) } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s"), mqtt_data); } - WebServer->send(200, FPSTR(HDR_CTYPE_HTML), mqtt_data); -} - -boolean HttpUser(void) -{ - boolean status = (HTTP_USER == webserver_state); - if (status) { HandleRoot(); } - return status; + WSHeaderSend(); + WSSend(200, CT_HTML, mqtt_data); + return true; } /*-------------------------------------------------------------------------------------------*/ -#ifndef BE_MINIMAL +#ifndef FIRMWARE_MINIMAL void HandleConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURATION); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_BTN_MENU_MODULE); + WSContentStart_P(S_CONFIGURATION); + WSContentSendStyle(); + + WSContentButton(BUTTON_MODULE); + WSContentButton(BUTTON_WIFI); - mqtt_data[0] = '\0'; XdrvCall(FUNC_WEB_ADD_BUTTON); XsnsCall(FUNC_WEB_ADD_BUTTON); - page += String(mqtt_data); - page += FPSTR(HTTP_BTN_MENU4); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentButton(BUTTON_LOGGING); + WSContentButton(BUTTON_OTHER); + WSContentButton(BUTTON_TEMPLATE); + + WSContentSpaceButton(BUTTON_RESET_CONFIGURATION); + WSContentButton(BUTTON_BACKUP); + WSContentButton(BUTTON_RESTORE); + + WSContentSpaceButton(BUTTON_MAIN); + WSContentEnd(); +} + +/*-------------------------------------------------------------------------------------------*/ + +void HandleTemplateConfiguration(void) +{ + if (!HttpCheckPriviledgedAccess()) { return; } + + if (WebServer->hasArg("save")) { + TemplateSaveSettings(); + WebRestart(1); + return; + } + + char stemp[20]; // Template number and Sensor name + + if (WebServer->hasArg("m")) { + String page = ""; + for (uint8_t i = 0; i < MAXMODULE; i++) { // "}2'%d'>%s (%d)}3" - "}2'0'>Sonoff Basic (1)}3" + uint8_t midx = pgm_read_byte(kModuleNiceList + i); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MODULE_TEMPLATE_REPLACE, midx, AnyModuleName(midx).c_str(), midx +1); + page += mqtt_data; + } + WSSend(200, CT_PLAIN, page); + return; + } + + WebGetArg("t", stemp, sizeof(stemp)); // 0 - 69 Template number + if (strlen(stemp)) { + uint8_t module = atoi(stemp); + uint8_t module_save = Settings.module; + Settings.module = module; + myio cmodule; + ModuleGpios(&cmodule); + gpio_flag flag = ModuleFlag(); + Settings.module = module_save; + + String page = AnyModuleName(module); // NAME: Generic + page += F("}1"); // Field separator + + for (uint8_t i = 0; i < sizeof(kGpioNiceList); i++) { // GPIO: }2'0'>None (0)}3}2'17'>Button1 (17)}3... + + if (1 == i) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MODULE_TEMPLATE_REPLACE, 255, D_SENSOR_USER, 255); // }2'255'>User (255)}3 + page += mqtt_data; + } + + uint8_t midx = pgm_read_byte(kGpioNiceList + i); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MODULE_TEMPLATE_REPLACE, midx, GetTextIndexed(stemp, sizeof(stemp), midx, kSensorNames), midx); + page += mqtt_data; + } + + page += F("}1"); // Field separator + mqtt_data[0] = '\0'; + for (uint8_t i = 0; i < sizeof(cmodule); i++) { // 17,148,29,149,7,255,255,255,138,255,139,255,255 + if ((i < 6) || ((i > 8) && (i != 11))) { // Ignore flash pins GPIO06, 7, 8 and 11 + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (i>0)?",":"", cmodule.io[i]); + } + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}1%d}1%d"), mqtt_data, flag, Settings.user_template_base); // FLAG: 1 BASE: 17 + page += mqtt_data; + + WSSend(200, CT_PLAIN, page); + return; + } + + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TEMPLATE); + + WSContentStart_P(S_CONFIGURE_TEMPLATE); + WSContentSend_P(HTTP_SCRIPT_MODULE_TEMPLATE); + WSContentSend_P(HTTP_SCRIPT_TEMPLATE); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_TEMPLATE); + + WSContentSend_P(PSTR("
")); + for (uint8_t i = 0; i < 17; i++) { + if ((i < 6) || ((i > 8) && (i != 11))) { // Ignore flash pins GPIO06, 7, 8 and 11 + WSContentSend_P(PSTR("" D_GPIO "%d"), + (0==i)?" style='width:74px'":"", i, ((9==i)||(10==i))? "ESP8285" :"", (0==i)?" style='width:176px'":"", i, i); + } + } + WSContentSend_P(PSTR("
%s
")); + + WSContentSend_P(HTTP_FORM_TEMPLATE_FLAG); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); +} + +void TemplateSaveSettings(void) +{ + char tmp[sizeof(Settings.user_template.name)]; // WebGetArg NAME and GPIO/BASE/FLAG byte value + char webindex[5]; // WebGetArg name + char svalue[128]; // Template command string + + WebGetArg("s1", tmp, sizeof(tmp)); // NAME + snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_TEMPLATE " {\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), tmp); + + uint8_t j = 0; + for (uint8_t i = 0; i < sizeof(Settings.user_template.gp); i++) { + if (6 == i) { j = 9; } + if (8 == i) { j = 12; } + snprintf_P(webindex, sizeof(webindex), PSTR("g%d"), j); + WebGetArg(webindex, tmp, sizeof(tmp)); // GPIO + uint8_t gpio = atoi(tmp); + snprintf_P(svalue, sizeof(svalue), PSTR("%s%s%d"), svalue, (i>0)?",":"", gpio); + j++; + } + + uint8_t flag = 0; + for (uint8_t i = 0; i < GPIO_FLAG_USED; i++) { + snprintf_P(webindex, sizeof(webindex), PSTR("c%d"), i); + uint8_t state = WebServer->hasArg(webindex) << i; // FLAG + flag += state; + } + WebGetArg("g99", tmp, sizeof(tmp)); // BASE + uint8_t base = atoi(tmp) +1; + + snprintf_P(svalue, sizeof(svalue), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), svalue, flag, base); + ExecuteWebCommand(svalue, SRC_WEBGUI); } /*-------------------------------------------------------------------------------------------*/ void HandleModuleConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } if (WebServer->hasArg("save")) { ModuleSaveSettings(); @@ -796,213 +1134,213 @@ void HandleModuleConfiguration(void) return; } - char stemp[20]; + char stemp[20]; // Sensor name uint8_t midx; - mytmplt cmodule; - memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule)); + myio cmodule; + ModuleGpios(&cmodule); if (WebServer->hasArg("m")) { String page = ""; - for (byte i = 0; i < MAXMODULE; i++) { - midx = pgm_read_byte(kModuleNiceList + i); - snprintf_P(stemp, sizeof(stemp), kModules[midx].name); - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SCRIPT_MODULE3, midx, stemp, midx +1); + 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" + if (0 == i) { + midx = USER_MODULE; + vidx = 0; + } else { + midx = pgm_read_byte(kModuleNiceList + i -1); + vidx = midx +1; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MODULE_TEMPLATE_REPLACE, midx, AnyModuleName(midx).c_str(), vidx); page += mqtt_data; } - page += "}3"; // String separator means do not use "}3" in Module name and Sensor name - for (byte j = 0; j < sizeof(kGpioNiceList); j++) { + WSSend(200, CT_PLAIN, page); + return; + } + + if (WebServer->hasArg("g")) { + String page = ""; + for (uint8_t j = 0; j < sizeof(kGpioNiceList); j++) { midx = pgm_read_byte(kGpioNiceList + j); - if (!GetUsedInModule(midx, cmodule.gp.io)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SCRIPT_MODULE3, midx, GetTextIndexed(stemp, sizeof(stemp), midx, kSensorNames), midx); + if (!GetUsedInModule(midx, cmodule.io)) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MODULE_TEMPLATE_REPLACE, midx, GetTextIndexed(stemp, sizeof(stemp), midx, kSensorNames), midx); page += mqtt_data; } } - WebServer->send(200, FPSTR(HDR_CTYPE_PLAIN), page); + WSSend(200, CT_PLAIN, page); return; } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MODULE); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_MODULE)); - page += FPSTR(HTTP_SCRIPT_MODULE1); - page.replace(F("}4"), String(Settings.module)); - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("sk(%d,%d);"), my_module.gp.io[i], i); // g0 - g16 - page += mqtt_data; + WSContentStart_P(S_CONFIGURE_MODULE); + WSContentSend_P(HTTP_SCRIPT_MODULE_TEMPLATE); + WSContentSend_P(HTTP_SCRIPT_MODULE1, Settings.module); + for (uint8_t i = 0; i < sizeof(cmodule); i++) { + if (ValidGPIO(i, cmodule.io[i])) { + WSContentSend_P(PSTR("sk(%d,%d);"), my_module.io[i], i); // g0 - g16 } } - page += FPSTR(HTTP_SCRIPT_MODULE2); - page += FPSTR(HTTP_HEAD_STYLE); - page.replace(F(""), F("")); - page += FPSTR(HTTP_FORM_MODULE); - snprintf_P(stemp, sizeof(stemp), kModules[MODULE].name); - page.replace(F("{mt"), stemp); - page += F("
"); - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) { + WSContentSend_P(HTTP_SCRIPT_MODULE2); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_MODULE, AnyModuleName(MODULE).c_str()); + for (uint8_t i = 0; i < sizeof(cmodule); i++) { + if (ValidGPIO(i, cmodule.io[i])) { snprintf_P(stemp, 3, PINS_WEMOS +i*2); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(""), - (WEMOS==Settings.module)?stemp:"", i, (0==i)? D_SENSOR_BUTTON "1":(1==i)? D_SERIAL_OUT :(3==i)? D_SERIAL_IN :(9==i)? "ESP8285" :(10==i)? "ESP8285" :(12==i)? D_SENSOR_RELAY "1":(13==i)? D_SENSOR_LED "1i":(14==i)? D_SENSOR :"", i, i); - page += mqtt_data; + WSContentSend_P(PSTR(""), + (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))? "ESP8285" :(12==i)? D_SENSOR_RELAY "1":(13==i)? D_SENSOR_LED "1i":(14==i)? D_SENSOR :"", i, i); } } - page += F("
%s " D_GPIO "%d %s
%s " D_GPIO "%d %s
"); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentSend_P(PSTR("")); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); } void ModuleSaveSettings(void) { - char tmp[100]; - char stemp[TOPSZ]; + char tmp[8]; // WebGetArg numbers only + char webindex[5]; // WebGetArg name WebGetArg("g99", tmp, sizeof(tmp)); - byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp); + uint8_t new_module = (!strlen(tmp)) ? MODULE : atoi(tmp); Settings.last_module = Settings.module; Settings.module = new_module; - mytmplt cmodule; - memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule)); + SetModuleType(); + myio cmodule; + ModuleGpios(&cmodule); String gpios = ""; - for (byte i = 0; i < MAX_GPIO_PIN; i++) { + for (uint8_t i = 0; i < sizeof(cmodule); i++) { if (Settings.last_module != new_module) { - Settings.my_gp.io[i] = 0; + Settings.my_gp.io[i] = GPIO_NONE; } else { - if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) { - snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); + if (ValidGPIO(i, cmodule.io[i])) { + snprintf_P(webindex, sizeof(webindex), PSTR("g%d"), i); + WebGetArg(webindex, tmp, sizeof(tmp)); Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp); gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]); } } } - snprintf_P(stemp, sizeof(stemp), kModules[Settings.module].name); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), stemp, gpios.c_str()); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), ModuleName().c_str(), gpios.c_str()); } /*-------------------------------------------------------------------------------------------*/ String htmlEscape(String s) { - s.replace("&", "&"); - s.replace("<", "<"); - s.replace(">", ">"); - s.replace("\"", """); - s.replace("'", "'"); - s.replace("/", "/"); - return s; + s.replace("&", "&"); + s.replace("<", "<"); + s.replace(">", ">"); + s.replace("\"", """); + s.replace("'", "'"); + s.replace("/", "/"); + return s; } void HandleWifiConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess(!WifiIsInManagerMode())) { return; } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI); - if (WebServer->hasArg("save")) { + if (WebServer->hasArg("save") && HTTP_MANAGER_RESET_ONLY != webserver_state) { WifiSaveSettings(); WebRestart(2); return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_WIFI)); - page += FPSTR(HTTP_SCRIPT_WIFI); - page += FPSTR(HTTP_HEAD_STYLE); + WSContentStart_P(S_CONFIGURE_WIFI, !WifiIsInManagerMode()); + WSContentSend_P(HTTP_SCRIPT_WIFI); + WSContentSendStyle(); - if (WebServer->hasArg("scan")) { + if (HTTP_MANAGER_RESET_ONLY != webserver_state) { + if (WebServer->hasArg("scan")) { #ifdef USE_EMULATION - UdpDisconnect(); + UdpDisconnect(); #endif // USE_EMULATION - int n = WiFi.scanNetworks(); - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_SCAN_DONE)); + int n = WiFi.scanNetworks(); + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_SCAN_DONE)); - if (0 == n) { - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, S_NO_NETWORKS_FOUND); - page += FPSTR(S_NO_NETWORKS_FOUND); - page += F(". " D_REFRESH_TO_SCAN_AGAIN "."); - } else { - //sort networks - int indices[n]; - for (int i = 0; i < n; i++) { - indices[i] = i; - } - - // RSSI SORT - for (int i = 0; i < n; i++) { - for (int j = i + 1; j < n; j++) { - if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) { - std::swap(indices[i], indices[j]); - } - } - } - - // remove duplicates ( must be RSSI sorted ) - if (remove_duplicate_access_points) { - String cssid; + if (0 == n) { + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, S_NO_NETWORKS_FOUND); + WSContentSend_P(S_NO_NETWORKS_FOUND); + WSContentSend_P(PSTR(". " D_REFRESH_TO_SCAN_AGAIN ".")); + } else { + //sort networks + int indices[n]; + for (int i = 0; i < n; i++) { + indices[i] = i; + } + + // RSSI SORT for (int i = 0; i < n; i++) { - if (-1 == indices[i]) { continue; } - cssid = WiFi.SSID(indices[i]); for (int j = i + 1; j < n; j++) { - if (cssid == WiFi.SSID(indices[j])) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_DUPLICATE_ACCESSPOINT " %s"), WiFi.SSID(indices[j]).c_str()); - AddLog(LOG_LEVEL_DEBUG); - indices[j] = -1; // set dup aps to index -1 + if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) { + std::swap(indices[i], indices[j]); } } } - } - //display networks in page - for (int i = 0; i < n; i++) { - if (-1 == indices[i]) { continue; } // skip dups - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_SSID " %s, " D_BSSID " %s, " D_CHANNEL " %d, " D_RSSI " %d"), WiFi.SSID(indices[i]).c_str(), WiFi.BSSIDstr(indices[i]).c_str(), WiFi.channel(indices[i]), WiFi.RSSI(indices[i])); - AddLog(LOG_LEVEL_DEBUG); - int quality = WifiGetRssiAsQuality(WiFi.RSSI(indices[i])); - - if (minimum_signal_quality == -1 || minimum_signal_quality < quality) { - String item = FPSTR(HTTP_LNK_ITEM); - String rssiQ; - rssiQ += quality; - item.replace(F("{v}"), htmlEscape(WiFi.SSID(indices[i]))); - item.replace(F("{w}"), String(WiFi.channel(indices[i]))); - item.replace(F("{r}"), rssiQ); - uint8_t auth = WiFi.encryptionType(indices[i]); - item.replace(F("{i}"), (ENC_TYPE_WEP == auth) ? F(D_WEP) : (ENC_TYPE_TKIP == auth) ? F(D_WPA_PSK) : (ENC_TYPE_CCMP == auth) ? F(D_WPA2_PSK) : (ENC_TYPE_AUTO == auth) ? F(D_AUTO) : F("")); - page += item; - delay(0); - } else { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_SKIPPING_LOW_QUALITY)); + // remove duplicates ( must be RSSI sorted ) + if (remove_duplicate_access_points) { + String cssid; + for (int i = 0; i < n; i++) { + if (-1 == indices[i]) { continue; } + cssid = WiFi.SSID(indices[i]); + for (int j = i + 1; j < n; j++) { + if (cssid == WiFi.SSID(indices[j])) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_DUPLICATE_ACCESSPOINT " %s"), WiFi.SSID(indices[j]).c_str()); + indices[j] = -1; // set dup aps to index -1 + } + } + } } + //display networks in page + for (int i = 0; i < n; i++) { + if (-1 == indices[i]) { continue; } // skip dups + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_SSID " %s, " D_BSSID " %s, " D_CHANNEL " %d, " D_RSSI " %d"), WiFi.SSID(indices[i]).c_str(), WiFi.BSSIDstr(indices[i]).c_str(), WiFi.channel(indices[i]), WiFi.RSSI(indices[i])); + int quality = WifiGetRssiAsQuality(WiFi.RSSI(indices[i])); + + if (minimum_signal_quality == -1 || minimum_signal_quality < quality) { + uint8_t auth = WiFi.encryptionType(indices[i]); + WSContentSend_P(PSTR("
%s (%d) %s %d%%
"), + htmlEscape(WiFi.SSID(indices[i])).c_str(), + WiFi.channel(indices[i]), + (ENC_TYPE_WEP == auth) ? D_WEP : (ENC_TYPE_TKIP == auth) ? D_WPA_PSK : (ENC_TYPE_CCMP == auth) ? D_WPA2_PSK : (ENC_TYPE_AUTO == auth) ? D_AUTO : "", + quality + ); + delay(0); + } else { + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_SKIPPING_LOW_QUALITY)); + } + + } + WSContentSend_P(PSTR("
")); } - page += "
"; + } else { + WSContentSend_P(PSTR("
")); } - } else { - page += FPSTR(HTTP_LNK_SCAN); + + // As WIFI_HOSTNAME may contain %s-%04d it cannot be part of HTTP_FORM_WIFI where it will exception + WSContentSend_P(HTTP_FORM_WIFI, Settings.sta_ssid[0], Settings.sta_ssid[1], WIFI_HOSTNAME, WIFI_HOSTNAME, Settings.hostname); + WSContentSend_P(HTTP_FORM_END); } - page += FPSTR(HTTP_FORM_WIFI); - page.replace(F("{h1"), Settings.hostname); - page.replace(F("{s1"), Settings.sta_ssid[0]); - page.replace(F("{s2"), Settings.sta_ssid[1]); - page += FPSTR(HTTP_FORM_END); - if (HTTP_MANAGER == webserver_state) { - page += FPSTR(HTTP_BTN_RSTRT); + if (WifiIsInManagerMode()) { + WSContentSpaceButton(BUTTON_RESTART); +#ifndef FIRMWARE_MINIMAL + WSContentSpaceButton(BUTTON_RESET_CONFIGURATION); +#endif // FIRMWARE_MINIMAL } else { - page += FPSTR(HTTP_BTN_CONF); + WSContentSpaceButton(BUTTON_CONFIGURATION); } -// ShowPage(page); - ShowPage(page, !(HTTP_MANAGER == webserver_state)); + WSContentEnd(); } void WifiSaveSettings(void) { - char tmp[100]; + char tmp[sizeof(Settings.sta_pwd[0])]; // Max length is currently 65 WebGetArg("h", tmp, sizeof(tmp)); strlcpy(Settings.hostname, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp, sizeof(Settings.hostname)); @@ -1014,20 +1352,18 @@ void WifiSaveSettings(void) WebGetArg("s2", tmp, sizeof(tmp)); strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1])); WebGetArg("p1", tmp, sizeof(tmp)); - strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0])); + strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strlen(tmp) < 5) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0])); WebGetArg("p2", tmp, sizeof(tmp)); - strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1])); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"), - Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]); - AddLog(LOG_LEVEL_INFO); + strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strlen(tmp) < 5) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1])); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"), Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]); } /*-------------------------------------------------------------------------------------------*/ void HandleLoggingConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_LOGGING); if (WebServer->hasArg("save")) { @@ -1036,58 +1372,40 @@ void HandleLoggingConfiguration(void) return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_LOGGING)); - page += FPSTR(HTTP_HEAD_STYLE); - - page += FPSTR(HTTP_FORM_LOG1); - for (byte idx = 0; idx < 3; idx++) { - page += FPSTR(HTTP_FORM_LOG2); - switch (idx) { - case 0: - page.replace(F("{b0"), F(D_SERIAL_LOG_LEVEL)); - page.replace(F("{b1"), STR(SERIAL_LOG_LEVEL)); - page.replace(F("{b2"), F("ls")); - for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { - page.replace("{a" + String(i), (i == Settings.seriallog_level) ? F(" selected ") : F(" ")); - } - break; - case 1: - page.replace(F("{b0"), F(D_WEB_LOG_LEVEL)); - page.replace(F("{b1"), STR(WEB_LOG_LEVEL)); - page.replace(F("{b2"), F("lw")); - for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { - page.replace("{a" + String(i), (i == Settings.weblog_level) ? F(" selected ") : F(" ")); - } - break; - case 2: - page.replace(F("{b0"), F(D_SYS_LOG_LEVEL)); - page.replace(F("{b1"), STR(SYS_LOG_LEVEL)); - page.replace(F("{b2"), F("ll")); - for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { - page.replace("{a" + String(i), (i == Settings.syslog_level) ? F(" selected ") : F(" ")); - } - break; + WSContentStart_P(S_CONFIGURE_LOGGING); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_LOG1); + char stemp1[32]; + char stemp2[32]; + uint8_t dlevel[3] = { LOG_LEVEL_INFO, LOG_LEVEL_INFO, LOG_LEVEL_NONE }; + for (uint8_t idx = 0; idx < 3; idx++) { + uint8_t llevel = (0==idx)?Settings.seriallog_level:(1==idx)?Settings.weblog_level:Settings.syslog_level; + WSContentSend_P(PSTR("

%s (%s)

")); } - page += FPSTR(HTTP_FORM_LOG3); - page.replace(F("{l2"), Settings.syslog_host); - page.replace(F("{l3"), String(Settings.syslog_port)); - page.replace(F("{l4"), String(Settings.tele_period)); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentSend_P(HTTP_FORM_LOG2, Settings.syslog_host, Settings.syslog_port, Settings.tele_period); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); } void LoggingSaveSettings(void) { - char tmp[100]; + char tmp[sizeof(Settings.syslog_host)]; // Max length is currently 33 - WebGetArg("ls", tmp, sizeof(tmp)); + WebGetArg("l0", tmp, sizeof(tmp)); Settings.seriallog_level = (!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp); - WebGetArg("lw", tmp, sizeof(tmp)); + WebGetArg("l1", tmp, sizeof(tmp)); Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp); - WebGetArg("ll", tmp, sizeof(tmp)); + WebGetArg("l2", tmp, sizeof(tmp)); Settings.syslog_level = (!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp); syslog_level = Settings.syslog_level; syslog_timer = 0; @@ -1100,17 +1418,16 @@ void LoggingSaveSettings(void) if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) { Settings.tele_period = 10; // Do not allow periods < 10 seconds } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"), + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"), Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period); - AddLog(LOG_LEVEL_INFO); } /*-------------------------------------------------------------------------------------------*/ void HandleOtherConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_OTHER); if (WebServer->hasArg("save")) { @@ -1119,44 +1436,48 @@ void HandleOtherConfiguration(void) return; } - char stemp[40]; + WSContentStart_P(S_CONFIGURE_OTHER); + WSContentSendStyle(); + + TemplateJson(); + char stemp[strlen(mqtt_data) +1]; + strlcpy(stemp, mqtt_data, sizeof(stemp)); // Get JSON template + WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? " checked disabled" : "", (Settings.flag.mqtt_enabled) ? " checked" : ""); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_OTHER)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_OTHER); - page.replace(F("{r1"), (Settings.flag.mqtt_enabled) ? F(" checked") : F("")); uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present; - if (SONOFF_IFAN02 == Settings.module) { maxfn = 1; } - for (byte i = 0; i < maxfn; i++) { - page += FPSTR(HTTP_FORM_OTHER2); - page.replace(F("{1"), String(i +1)); - snprintf_P(stemp, sizeof(stemp), PSTR(FRIENDLY_NAME"%d"), i +1); - page.replace(F("{2"), (i) ? stemp : FRIENDLY_NAME); - page.replace(F("{3"), Settings.friendlyname[i]); + if (SONOFF_IFAN02 == my_module_type) { maxfn = 1; } + for (uint8_t i = 0; i < maxfn; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i +1); + WSContentSend_P(PSTR("" D_FRIENDLY_NAME " %d (" FRIENDLY_NAME "%s)

"), + i +1, + (i) ? stemp : "", + i, i, + (i) ? stemp : "", + Settings.friendlyname[i]); } + #ifdef USE_EMULATION - page += FPSTR(HTTP_FORM_OTHER3a); - for (byte i = 0; i < EMUL_MAX; i++) { - page += FPSTR(HTTP_FORM_OTHER3b); - page.replace(F("{1"), String(i)); - page.replace(F("{2"), (i == Settings.flag2.emulation) ? F(" checked") : F("")); - page.replace(F("{3"), (i == EMUL_NONE) ? F(D_NONE) : (i == EMUL_WEMO) ? F(D_BELKIN_WEMO) : F(D_HUE_BRIDGE)); - page.replace(F("{4"), (i == EMUL_NONE) ? F("") : (i == EMUL_WEMO) ? F(" " D_SINGLE_DEVICE) : F(" " D_MULTI_DEVICE)); + WSContentSend_P(PSTR("

 " D_EMULATION " 

")); // Keep close to Friendlynames so do not use
+ for (uint8_t i = 0; i < EMUL_MAX; i++) { + WSContentSend_P(PSTR("%s %s
"), // Different id only used for labels + i, i, + (i == Settings.flag2.emulation) ? " checked" : "", + GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions), + (i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? D_SINGLE_DEVICE : D_MULTI_DEVICE); } - page += F("
"); - page += F("

"); + WSContentSend_P(PSTR("

")); #endif // USE_EMULATION - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); } void OtherSaveSettings(void) { - char tmp[100]; - char stemp[TOPSZ]; - char stemp2[TOPSZ]; + char tmp[128]; + char webindex[5]; + char friendlyname[sizeof(Settings.friendlyname[0])]; WebGetArg("p1", tmp, sizeof(tmp)); strlcpy(Settings.web_password, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.web_password : tmp, sizeof(Settings.web_password)); @@ -1166,22 +1487,34 @@ void OtherSaveSettings(void) Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp); #endif // USE_EMULATION snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation); - for (byte i = 0; i < MAX_FRIENDLYNAMES; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("a%d"), i +1); - WebGetArg(stemp, tmp, sizeof(tmp)); - snprintf_P(stemp2, sizeof(stemp2), PSTR(FRIENDLY_NAME"%d"), i +1); - strlcpy(Settings.friendlyname[i], (!strlen(tmp)) ? (i) ? stemp2 : FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[i])); + for (uint8_t i = 0; i < MAX_FRIENDLYNAMES; i++) { + snprintf_P(webindex, sizeof(webindex), PSTR("a%d"), i); + WebGetArg(webindex, tmp, sizeof(tmp)); + snprintf_P(friendlyname, sizeof(friendlyname), PSTR(FRIENDLY_NAME"%d"), i +1); + strlcpy(Settings.friendlyname[i], (!strlen(tmp)) ? (i) ? friendlyname : FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[i])); snprintf_P(log_data, sizeof(log_data), PSTR("%s%s %s"), log_data, (i) ? "," : "", Settings.friendlyname[i]); } AddLog(LOG_LEVEL_INFO); + WebGetArg("t1", tmp, sizeof(tmp)); + if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255} + char svalue[128]; + snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_TEMPLATE " %s"), tmp); + ExecuteWebCommand(svalue, SRC_WEBGUI); + + if (WebServer->hasArg("t2")) { + snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_MODULE " 0")); + ExecuteWebCommand(svalue, SRC_WEBGUI); + } + + } } /*-------------------------------------------------------------------------------------------*/ void HandleBackupConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_BACKUP_CONFIGURATION)); if (!SettingsBufferAlloc()) { return; } @@ -1194,7 +1527,7 @@ void HandleBackupConfiguration(void) snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"), NoAlNumToUnderscore(friendlyname, Settings.friendlyname[0]), my_version); WebServer->sendHeader(F("Content-Disposition"), attachment); - WebServer->send(200, FPSTR(HDR_CTYPE_STREAM), ""); + WSSend(200, CT_STREAM, ""); uint16_t cfg_crc = Settings.cfg_crc; Settings.cfg_crc = GetSettingsCrc(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918) @@ -1224,39 +1557,34 @@ void HandleBackupConfiguration(void) void HandleResetConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - - char svalue[33]; + if (!HttpCheckPriviledgedAccess(!WifiIsInManagerMode())) { return; } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESET_CONFIGURATION); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_RESET_CONFIGURATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += F("
" D_CONFIGURATION_RESET "
"); - page += FPSTR(HTTP_MSG_RSTRT); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentStart_P(S_RESET_CONFIGURATION, !WifiIsInManagerMode()); + WSContentSendStyle(); + WSContentSend_P(PSTR("
" D_CONFIGURATION_RESET "
")); + WSContentSend_P(HTTP_MSG_RSTRT); + WSContentSpaceButton(BUTTON_MAIN); + WSContentEnd(); - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_RESET " 1")); - ExecuteWebCommand(svalue, SRC_WEBGUI); + char command[CMDSZ]; + snprintf_P(command, sizeof(command), PSTR(D_CMND_RESET " 1")); + ExecuteWebCommand(command, SRC_WEBGUI); } void HandleRestoreConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESTORE_CONFIGURATION); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_RESTORE_CONFIGURATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_RST); - page += FPSTR(HTTP_FORM_RST_UPG); - page.replace(F("{r1"), F(D_RESTORE)); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentStart_P(S_RESTORE_CONFIGURATION); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_RST); + WSContentSend_P(HTTP_FORM_RST_UPG, D_RESTORE); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); upload_error = 0; upload_file_type = UPL_SETTINGS; @@ -1266,139 +1594,116 @@ void HandleRestoreConfiguration(void) void HandleInformation(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_INFORMATION); char stopic[TOPSZ]; int freeMem = ESP.getFreeHeap(); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_INFORMATION)); - page += FPSTR(HTTP_HEAD_STYLE); - // page += F("
 Information "); - - page += F(""); - page += F("
"); - + WSContentStart_P(S_INFORMATION); // Save 1k of code space replacing table html with javascript replace codes // }1 = // }2 = - String func = FPSTR(HTTP_SCRIPT_INFO_BEGIN); - func += F("
"); - func += F(D_PROGRAM_VERSION "}2"); func += my_version; func += my_image; - func += F("}1" D_BUILD_DATE_AND_TIME "}2"); func += GetBuildDateAndTime(); - func += F("}1" D_CORE_AND_SDK_VERSION "}2" ARDUINO_ESP8266_RELEASE "/"); func += String(ESP.getSdkVersion()); - func += F("}1" D_UPTIME "}2"); func += GetUptime(); - snprintf_P(stopic, sizeof(stopic), PSTR(" at 0x%X"), GetSettingsAddress()); - func += F("}1" D_FLASH_WRITE_COUNT "}2"); func += String(Settings.save_flag); func += stopic; - func += F("}1" D_BOOT_COUNT "}2"); func += String(Settings.bootcount); - func += F("}1" D_RESTART_REASON "}2"); func += GetResetReason(); + WSContentSend_P(HTTP_SCRIPT_INFO_BEGIN); + WSContentSend_P(PSTR("
")); + WSContentSend_P(PSTR(D_PROGRAM_VERSION "}2%s%s"), my_version, my_image); + WSContentSend_P(PSTR("}1" D_BUILD_DATE_AND_TIME "}2%s"), GetBuildDateAndTime().c_str()); + WSContentSend_P(PSTR("}1" D_CORE_AND_SDK_VERSION "}2" ARDUINO_ESP8266_RELEASE "/%s"), ESP.getSdkVersion()); + WSContentSend_P(PSTR("}1" D_UPTIME "}2%s"), GetUptime().c_str()); + WSContentSend_P(PSTR("}1" D_FLASH_WRITE_COUNT "}2%d at 0x%X"), Settings.save_flag, GetSettingsAddress()); + WSContentSend_P(PSTR("}1" D_BOOT_COUNT "}2%d"), Settings.bootcount); + WSContentSend_P(PSTR("}1" D_RESTART_REASON "}2%s"), GetResetReason().c_str()); uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present; - if (SONOFF_IFAN02 == Settings.module) { maxfn = 1; } - for (byte i = 0; i < maxfn; i++) { - func += F("}1" D_FRIENDLY_NAME " "); func += i +1; func += F("}2"); func += Settings.friendlyname[i]; + if (SONOFF_IFAN02 == my_module_type) { maxfn = 1; } + for (uint8_t i = 0; i < maxfn; i++) { + WSContentSend_P(PSTR("}1" D_FRIENDLY_NAME " %d}2%s"), i +1, Settings.friendlyname[i]); } - - func += F("}1}2 "); // Empty line - func += F("}1" D_AP); func += String(Settings.sta_active +1); - func += F(" " D_SSID " (" D_RSSI ")}2"); func += Settings.sta_ssid[Settings.sta_active]; func += F(" ("); func += WifiGetRssiAsQuality(WiFi.RSSI()); func += F("%)"); - func += F("}1" D_HOSTNAME "}2"); func += my_hostname; - if (mdns_begun) { func += F(".local"); } + WSContentSend_P(PSTR("}1}2 ")); // Empty line + WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%)"), Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WifiGetRssiAsQuality(WiFi.RSSI())); + WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), my_hostname, (mdns_begun) ? ".local" : ""); if (static_cast(WiFi.localIP()) != 0) { - func += F("}1" D_IP_ADDRESS "}2"); func += WiFi.localIP().toString(); - func += F("}1" D_GATEWAY "}2"); func += IPAddress(Settings.ip_address[1]).toString(); - func += F("}1" D_SUBNET_MASK "}2"); func += IPAddress(Settings.ip_address[2]).toString(); - func += F("}1" D_DNS_SERVER "}2"); func += IPAddress(Settings.ip_address[3]).toString(); - func += F("}1" D_MAC_ADDRESS "}2"); func += WiFi.macAddress(); + WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.localIP().toString().c_str()); + WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), IPAddress(Settings.ip_address[1]).toString().c_str()); + WSContentSend_P(PSTR("}1" D_SUBNET_MASK "}2%s"), IPAddress(Settings.ip_address[2]).toString().c_str()); + WSContentSend_P(PSTR("}1" D_DNS_SERVER "}2%s"), IPAddress(Settings.ip_address[3]).toString().c_str()); + WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str()); } if (static_cast(WiFi.softAPIP()) != 0) { - func += F("}1" D_AP " " D_IP_ADDRESS "}2"); func += WiFi.softAPIP().toString(); - func += F("}1" D_AP " " D_GATEWAY "}2"); func += WiFi.softAPIP().toString(); - func += F("}1" D_AP " " D_MAC_ADDRESS "}2"); func += WiFi.softAPmacAddress(); + WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.softAPIP().toString().c_str()); + WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), WiFi.softAPIP().toString().c_str()); + WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.softAPmacAddress().c_str()); } - - func += F("}1}2 "); // Empty line + WSContentSend_P(PSTR("}1}2 ")); // Empty line if (Settings.flag.mqtt_enabled) { - func += F("}1" D_MQTT_HOST "}2"); func += Settings.mqtt_host; - func += F("}1" D_MQTT_PORT "}2"); func += String(Settings.mqtt_port); - func += F("}1" D_MQTT_USER "}2"); func += Settings.mqtt_user; - func += F("}1" D_MQTT_CLIENT "}2"); func += mqtt_client; - func += F("}1" D_MQTT_TOPIC "}2"); func += Settings.mqtt_topic; - func += F("}1" D_MQTT_GROUP_TOPIC "}2"); func += Settings.mqtt_grptopic; - func += F("}1" D_MQTT_FULL_TOPIC "}2"); func += GetTopic_P(stopic, CMND, mqtt_topic, ""); - func += F("}1" D_MQTT " " D_FALLBACK_TOPIC "}2"); func += GetFallbackTopic_P(stopic, CMND, ""); + WSContentSend_P(PSTR("}1" D_MQTT_HOST "}2%s"), Settings.mqtt_host); + WSContentSend_P(PSTR("}1" D_MQTT_PORT "}2%d"), Settings.mqtt_port); + WSContentSend_P(PSTR("}1" D_MQTT_USER "}2%s"), Settings.mqtt_user); + WSContentSend_P(PSTR("}1" D_MQTT_CLIENT "}2%s"), mqtt_client); + WSContentSend_P(PSTR("}1" D_MQTT_TOPIC "}2%s"), Settings.mqtt_topic); + WSContentSend_P(PSTR("}1" D_MQTT_GROUP_TOPIC "}2%s"), Settings.mqtt_grptopic); + WSContentSend_P(PSTR("}1" D_MQTT_FULL_TOPIC "}2%s"), GetTopic_P(stopic, CMND, mqtt_topic, "")); + WSContentSend_P(PSTR("}1" D_MQTT " " D_FALLBACK_TOPIC "}2%s"), GetFallbackTopic_P(stopic, CMND, "")); } else { - func += F("}1" D_MQTT "}2" D_DISABLED); + WSContentSend_P(PSTR("}1" D_MQTT "}2" D_DISABLED)); } + WSContentSend_P(PSTR("}1}2 ")); // Empty line - func += F("}1}2 "); // Empty line - func += F("}1" D_EMULATION "}2"); #ifdef USE_EMULATION - if (EMUL_WEMO == Settings.flag2.emulation) { - func += F(D_BELKIN_WEMO); - } - else if (EMUL_HUE == Settings.flag2.emulation) { - func += F(D_HUE_BRIDGE); - } - else { - func += F(D_NONE); - } + WSContentSend_P(PSTR("}1" D_EMULATION "}2%s"), GetTextIndexed(stopic, sizeof(stopic), Settings.flag2.emulation, kEmulationOptions)); #else - func += F(D_DISABLED); + WSContentSend_P(PSTR("}1" D_EMULATION "}2" D_DISABLED)); #endif // USE_EMULATION - func += F("}1" D_MDNS_DISCOVERY "}2"); #ifdef USE_DISCOVERY - func += F(D_ENABLED); - func += F("}1" D_MDNS_ADVERTISE "}2"); + WSContentSend_P(PSTR("}1" D_MDNS_DISCOVERY "}2%s"), (Settings.flag3.mdns_enabled) ? D_ENABLED : D_DISABLED); + if (Settings.flag3.mdns_enabled) { #ifdef WEBSERVER_ADVERTISE - func += F(D_WEB_SERVER); + WSContentSend_P(PSTR("}1" D_MDNS_ADVERTISE "}2" D_WEB_SERVER)); #else - func += F(D_DISABLED); + WSContentSend_P(PSTR("}1" D_MDNS_ADVERTISE "}2" D_DISABLED)); #endif // WEBSERVER_ADVERTISE + } #else - func += F(D_DISABLED); + WSContentSend_P(PSTR("}1" D_MDNS_DISCOVERY "}2" D_DISABLED)); #endif // USE_DISCOVERY - func += F("}1}2 "); // Empty line - func += F("}1" D_ESP_CHIP_ID "}2"); func += String(ESP.getChipId()); - snprintf_P(stopic, sizeof(stopic), PSTR("0x%06X"), ESP.getFlashChipId()); - func += F("}1" D_FLASH_CHIP_ID "}2"); func += stopic; - func += F("}1" D_FLASH_CHIP_SIZE "}2"); func += String(ESP.getFlashChipRealSize() / 1024); func += F("kB"); - func += F("}1" D_PROGRAM_FLASH_SIZE "}2"); func += String(ESP.getFlashChipSize() / 1024); func += F("kB"); - func += F("}1" D_PROGRAM_SIZE "}2"); func += String(ESP.getSketchSize() / 1024); func += F("kB"); - func += F("}1" D_FREE_PROGRAM_SPACE "}2"); func += String(ESP.getFreeSketchSpace() / 1024); func += F("kB"); - func += F("}1" D_FREE_MEMORY "}2"); func += String(freeMem / 1024); func += F("kB"); - func += F("
"); - func += FPSTR(HTTP_SCRIPT_INFO_END); - page.replace(F(""), func); - page.replace(F(""), F("")); + WSContentSend_P(PSTR("}1}2 ")); // Empty line + WSContentSend_P(PSTR("}1" D_ESP_CHIP_ID "}2%d"), ESP.getChipId()); + WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP.getFlashChipId()); + WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP.getFlashChipRealSize() / 1024); + WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%dkB"), ESP.getFlashChipSize() / 1024); + WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%dkB"), ESP.getSketchSize() / 1024); + WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%dkB"), ESP.getFreeSketchSpace() / 1024); + WSContentSend_P(PSTR("}1" D_FREE_MEMORY "}2%dkB"), freeMem / 1024); + WSContentSend_P(PSTR("
")); - // page += F("
"); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentSend_P(HTTP_SCRIPT_INFO_END); + WSContentSendStyle(); + // WSContentSend_P(PSTR("
 Information ")); + WSContentSend_P(PSTR("" + "
")); + // WSContentSend_P(PSTR("
")); + WSContentSpaceButton(BUTTON_MAIN); + WSContentEnd(); } -#endif // Not BE_MINIMAL +#endif // Not FIRMWARE_MINIMAL /*-------------------------------------------------------------------------------------------*/ void HandleUpgradeFirmware(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_FIRMWARE_UPGRADE); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_FIRMWARE_UPGRADE)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_UPG); - page.replace(F("{o1"), Settings.ota_url); - page += FPSTR(HTTP_FORM_RST_UPG); - page.replace(F("{r1"), F(D_UPGRADE)); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentStart_P(S_FIRMWARE_UPGRADE); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_UPG, Settings.ota_url); + WSContentSend_P(HTTP_FORM_RST_UPG, D_UPGRADE); + WSContentSpaceButton(BUTTON_MAIN); + WSContentEnd(); upload_error = 0; upload_file_type = UPL_TASMOTA; @@ -1406,37 +1711,36 @@ void HandleUpgradeFirmware(void) void HandleUpgradeFirmwareStart(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - char svalue[100]; + if (!HttpCheckPriviledgedAccess()) { return; } + + char command[sizeof(Settings.ota_url) + 10]; // OtaUrl AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_UPGRADE_STARTED)); WifiConfigCounter(); - char tmp[100]; - WebGetArg("o", tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_OTAURL " %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); + char otaurl[sizeof(Settings.ota_url)]; + WebGetArg("o", otaurl, sizeof(otaurl)); + if (strlen(otaurl)) { + snprintf_P(command, sizeof(command), PSTR(D_CMND_OTAURL " %s"), otaurl); + ExecuteWebCommand(command, SRC_WEBGUI); } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_INFORMATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += F("
" D_UPGRADE_STARTED " ...
"); - page += FPSTR(HTTP_MSG_RSTRT); - page += FPSTR(HTTP_BTN_MAIN); - page.replace(F(""), FPSTR(HTTP_SCRIPT_RELOAD_OTA)); - ShowPage(page); + WSContentStart_P(S_INFORMATION); + WSContentSend_P(HTTP_SCRIPT_RELOAD_OTA); + WSContentSendStyle(); + WSContentSend_P(PSTR("
" D_UPGRADE_STARTED " ...
")); + WSContentSend_P(HTTP_MSG_RSTRT); + WSContentSpaceButton(BUTTON_MAIN); + WSContentEnd(); - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_UPGRADE " 1")); - ExecuteWebCommand(svalue, SRC_WEBGUI); + snprintf_P(command, sizeof(command), PSTR(D_CMND_UPGRADE " 1")); + ExecuteWebCommand(command, SRC_WEBGUI); } void HandleUploadDone(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_UPLOAD_DONE)); char error[100]; @@ -1445,52 +1749,42 @@ void HandleUploadDone(void) restart_flag = 0; MqttRetryCounter(0); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_INFORMATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += F("
" D_UPLOAD " " D_UPLOAD " " D_FAILED "

"); - switch (upload_error) { - case 1: strncpy_P(error, PSTR(D_UPLOAD_ERR_1), sizeof(error)); break; - case 2: strncpy_P(error, PSTR(D_UPLOAD_ERR_2), sizeof(error)); break; - case 3: strncpy_P(error, PSTR(D_UPLOAD_ERR_3), sizeof(error)); break; - case 4: strncpy_P(error, PSTR(D_UPLOAD_ERR_4), sizeof(error)); break; - case 5: strncpy_P(error, PSTR(D_UPLOAD_ERR_5), sizeof(error)); break; - case 6: strncpy_P(error, PSTR(D_UPLOAD_ERR_6), sizeof(error)); break; - case 7: strncpy_P(error, PSTR(D_UPLOAD_ERR_7), sizeof(error)); break; - case 8: strncpy_P(error, PSTR(D_UPLOAD_ERR_8), sizeof(error)); break; - case 9: strncpy_P(error, PSTR(D_UPLOAD_ERR_9), sizeof(error)); break; + WSContentSend_P(PSTR("red'>" D_FAILED "


")); #ifdef USE_RF_FLASH - case 10: strncpy_P(error, PSTR(D_UPLOAD_ERR_10), sizeof(error)); break; - case 11: strncpy_P(error, PSTR(D_UPLOAD_ERR_11), sizeof(error)); break; - case 12: strncpy_P(error, PSTR(D_UPLOAD_ERR_12), sizeof(error)); break; - case 13: strncpy_P(error, PSTR(D_UPLOAD_ERR_13), sizeof(error)); break; + if (upload_error < 14) { +#else + if (upload_error < 10) { #endif - default: - snprintf_P(error, sizeof(error), PSTR(D_UPLOAD_ERROR_CODE " %d"), upload_error); + GetTextIndexed(error, sizeof(error), upload_error -1, kUploadErrors); + } else { + snprintf_P(error, sizeof(error), PSTR(D_UPLOAD_ERROR_CODE " %d"), upload_error); } - page += error; - snprintf_P(log_data, sizeof(log_data), PSTR(D_UPLOAD ": %s"), error); - AddLog(LOG_LEVEL_DEBUG); + WSContentSend_P(error); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_UPLOAD ": %s"), error); stop_flash_rotate = Settings.flag.stop_flash_rotate; } else { - page += F("green'>" D_SUCCESSFUL "
"); - page += FPSTR(HTTP_MSG_RSTRT); - page.replace(F(""), FPSTR(HTTP_SCRIPT_RELOAD_OTA)); // Refesh main web ui after OTA upgrade + WSContentSend_P(PSTR("green'>" D_SUCCESSFUL "
")); + WSContentSend_P(HTTP_MSG_RSTRT); ShowWebSource(SRC_WEBGUI); restart_flag = 2; // Always restart to re-enable disabled features during update } SettingsBufferFree(); - page += F("

"); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentSend_P(PSTR("
")); + WSContentSpaceButton(BUTTON_MAIN); + WSContentEnd(); } void HandleUploadLoop(void) { // Based on ESP8266HTTPUpdateServer.cpp uses ESP8266WebServer Parsing.cpp and Cores Updater.cpp (Update) - boolean _serialoutput = (LOG_LEVEL_DEBUG <= seriallog_level); + bool _serialoutput = (LOG_LEVEL_DEBUG <= seriallog_level); if (HTTP_USER == webserver_state) { return; } if (upload_error) { @@ -1507,8 +1801,7 @@ void HandleUploadLoop(void) return; } SettingsSave(1); // Free flash for upload - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD D_FILE " %s ..."), upload.filename.c_str()); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD D_FILE " %s ..."), upload.filename.c_str()); if (UPL_SETTINGS == upload_file_type) { if (!SettingsBufferAlloc()) { upload_error = 2; // Not enough space @@ -1543,7 +1836,7 @@ void HandleUploadLoop(void) } else { #ifdef USE_RF_FLASH - if ((SONOFF_BRIDGE == Settings.module) && (upload.buf[0] == ':')) { // Check if this is a RF bridge FW file + if ((SONOFF_BRIDGE == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a RF bridge FW file Update.end(); // End esp8266 update session upload_file_type = UPL_EFM8BB1; @@ -1591,7 +1884,7 @@ void HandleUploadLoop(void) upload_error = abs(result); return; } else if (result > 0) { - if (result > upload.currentSize) { + if ((size_t)result > upload.currentSize) { // Offset is larger than the buffer supplied, this should not happen upload_error = 9; // File too large - Failed to decode RF firmware return; @@ -1667,8 +1960,7 @@ void HandleUploadLoop(void) } } if (!upload_error) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD D_SUCCESSFUL " %u bytes. " D_RESTARTING), upload.totalSize); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD D_SUCCESSFUL " %u bytes. " D_RESTARTING), upload.totalSize); } } else if (UPLOAD_FILE_ABORTED == upload.status) { restart_flag = 0; @@ -1686,37 +1978,34 @@ void HandlePreflightRequest(void) WebServer->sendHeader(F("Access-Control-Allow-Origin"), F("*")); WebServer->sendHeader(F("Access-Control-Allow-Methods"), F("GET, POST")); WebServer->sendHeader(F("Access-Control-Allow-Headers"), F("authorization")); - WebServer->send(200, FPSTR(HDR_CTYPE_HTML), ""); + WSSend(200, CT_HTML, ""); } /*-------------------------------------------------------------------------------------------*/ void HandleHttpCommand(void) { - if (HttpUser()) { return; } -// if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - char svalue[INPUT_BUFFER_SIZE]; // Large to serve Backlog + if (!HttpCheckPriviledgedAccess(false)) { return; } AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_COMMAND)); uint8_t valid = 1; if (Settings.web_password[0] != 0) { - char tmp1[100]; + char tmp1[sizeof(Settings.web_password)]; WebGetArg("user", tmp1, sizeof(tmp1)); - char tmp2[100]; + char tmp2[sizeof(Settings.web_password)]; WebGetArg("password", tmp2, sizeof(tmp2)); if (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, Settings.web_password))) { valid = 0; } } String message = F("{\"" D_RSLT_WARNING "\":\""); if (valid) { - byte curridx = web_log_index; - WebGetArg("cmnd", svalue, sizeof(svalue)); - if (strlen(svalue)) { - ExecuteWebCommand(svalue, SRC_WEBCOMMAND); - + uint8_t curridx = web_log_index; + String svalue = WebServer->arg("cmnd"); + if (svalue.length() && (svalue.length() < INPUT_BUFFER_SIZE)) { + ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCOMMAND); if (web_log_index != curridx) { - byte counter = curridx; + uint8_t counter = curridx; message = F("{"); do { char* tmp; @@ -1728,6 +2017,7 @@ void HandleHttpCommand(void) if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O]) if (message.length() > 1) { message += F(","); } size_t JSONlen = len - (JSON - tmp); + if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); } strlcpy(mqtt_data, JSON +1, JSONlen -2); message += mqtt_data; } @@ -1745,56 +2035,58 @@ void HandleHttpCommand(void) } else { message += F(D_NEED_USER_AND_PASSWORD "\"}"); } - SetHeader(); - WebServer->send(200, FPSTR(HDR_CTYPE_JSON), message); + WSHeaderSend(); + WSSend(200, CT_JSON, message); } /*-------------------------------------------------------------------------------------------*/ void HandleConsole(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONSOLE); + if (!HttpCheckPriviledgedAccess()) { return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONSOLE)); - page += FPSTR(HTTP_HEAD_STYLE); - page.replace(F(""), FPSTR(HTTP_SCRIPT_CONSOL)); - page.replace(F(""), F("")); - page += FPSTR(HTTP_FORM_CMND); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); -} - -void HandleAjaxConsoleRefresh(void) -{ - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - char svalue[INPUT_BUFFER_SIZE]; // Large to serve Backlog - byte cflg = 1; - byte counter = 0; // Initial start, should never be 0 again - - WebGetArg("c1", svalue, sizeof(svalue)); - if (strlen(svalue)) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), svalue); - AddLog(LOG_LEVEL_INFO); - ExecuteWebCommand(svalue, SRC_WEBCONSOLE); + if (WebServer->hasArg("c2")) { // Console refresh requested + HandleConsoleRefresh(); + return; } - WebGetArg("c2", svalue, sizeof(svalue)); - if (strlen(svalue)) { counter = atoi(svalue); } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONSOLE); - byte last_reset_web_log_flag = reset_web_log_flag; - String message = F("}9"); // Cannot load mqtt_data here as <> will be encoded by replacements below + WSContentStart_P(S_CONSOLE); + WSContentSend_P(HTTP_SCRIPT_CONSOL, Settings.web_refresh); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_CMND); + WSContentSpaceButton(BUTTON_MAIN); + WSContentEnd(); +} + +void HandleConsoleRefresh(void) +{ + bool cflg = true; + uint8_t counter = 0; // Initial start, should never be 0 again + + String svalue = WebServer->arg("c1"); + if (svalue.length() && (svalue.length() < INPUT_BUFFER_SIZE)) { + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), svalue.c_str()); + ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCONSOLE); + } + + char stmp[8]; + WebGetArg("c2", stmp, sizeof(stmp)); + if (strlen(stmp)) { counter = atoi(stmp); } + + bool last_reset_web_log_flag = reset_web_log_flag; + // mqtt_data used as scratch space + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%d}1%d}1"), web_log_index, last_reset_web_log_flag); + String message = mqtt_data; if (!reset_web_log_flag) { counter = 0; - reset_web_log_flag = 1; + reset_web_log_flag = true; } if (counter != web_log_index) { if (!counter) { counter = web_log_index; - cflg = 0; + cflg = false; } do { char* tmp; @@ -1804,32 +2096,25 @@ void HandleAjaxConsoleRefresh(void) if (cflg) { message += F("\n"); } else { - cflg = 1; + cflg = true; } + if (len > sizeof(mqtt_data) -2) { len = sizeof(mqtt_data); } strlcpy(mqtt_data, tmp, len); - message += mqtt_data; + message += mqtt_data; // mqtt_data used as scratch space } counter++; - if (!counter) { counter++; } // Skip 0 as it is not allowed + if (!counter) { counter++; } // Skip log index 0 as it is not allowed } while (counter != web_log_index); - // XML encoding to fix blank console log in concert with javascript decodeURIComponent - message.replace(F("%"), F("%25")); // Needs to be done first as otherwise the % in %26 will also be converted - message.replace(F("&"), F("%26")); - message.replace(F("<"), F("%3C")); - message.replace(F(">"), F("%3E")); } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%d%d"), web_log_index, last_reset_web_log_flag); - message.replace(F("}9"), mqtt_data); // Save to load here - message += F(""); - WebServer->send(200, FPSTR(HDR_CTYPE_XML), message); + message += F("}1"); + WSSend(200, CT_PLAIN, message); } /********************************************************************************************/ void HandleNotFound(void) { -// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_HTTP "Not fount (%s)"), WebServer->uri().c_str()); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Not fount (%s)"), WebServer->uri().c_str()); if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the error page. @@ -1845,19 +2130,19 @@ void HandleNotFound(void) 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()); } - SetHeader(); - WebServer->send(404, FPSTR(HDR_CTYPE_PLAIN), mqtt_data); + WSHeaderSend(); + WSSend(404, CT_PLAIN, mqtt_data); } } /* 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. */ -boolean CaptivePortal(void) +bool CaptivePortal(void) { - if ((HTTP_MANAGER == webserver_state) && !ValidIpAddress(WebServer->hostHeader())) { + if ((WifiIsInManagerMode()) && !ValidIpAddress(WebServer->hostHeader())) { AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED)); WebServer->sendHeader(F("Location"), String("http://") + WebServer->client().localIP().toString(), true); - WebServer->send(302, FPSTR(HDR_CTYPE_PLAIN), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. + WSSend(302, CT_PLAIN, ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. WebServer->client().stop(); // Stop is needed because we sent no content length return true; } @@ -1865,7 +2150,7 @@ boolean CaptivePortal(void) } /** Is this an IP? */ -boolean ValidIpAddress(String str) +bool ValidIpAddress(String str) { for (uint16_t i = 0; i < str.length(); i++) { int c = str.charAt(i); @@ -1912,90 +2197,76 @@ String UrlEncode(const String& text) int WebSend(char *buffer) { - /* [sonoff] POWER1 ON --> Sends http://sonoff/cm?cmnd=POWER1 ON - * [192.168.178.86:80,admin:joker] POWER1 ON --> Sends http://hostname:80/cm?user=admin&password=joker&cmnd=POWER1 ON - * [sonoff] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123 - * [sonoff,admin:joker] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123 - */ + // [sonoff] POWER1 ON --> Sends http://sonoff/cm?cmnd=POWER1 ON + // [192.168.178.86:80,admin:joker] POWER1 ON --> Sends http://hostname:80/cm?user=admin&password=joker&cmnd=POWER1 ON + // [sonoff] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123 + // [sonoff,admin:joker] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123 char *host; - char *port; char *user; char *password; char *command; - uint16_t nport = 80; int status = 1; // Wrong parameters // buffer = | [ 192.168.178.86 : 80 , admin : joker ] POWER1 ON | host = strtok_r(buffer, "]", &command); // host = | [ 192.168.178.86 : 80 , admin : joker |, command = | POWER1 ON | if (host && command) { - host = Trim(host); // host = |[ 192.168.178.86 : 80 , admin : joker| - host++; // host = | 192.168.178.86 : 80 , admin : joker| - Skip [ - host = strtok_r(host, ",", &user); // host = | 192.168.178.86 : 80 |, user = | admin : joker| - host = strtok_r(host, ":", &port); // host = | 192.168.178.86 |, port = | 80 | - host = Trim(host); // host = |192.168.178.86| - if (port) { - port = Trim(port); // port = |80| - nport = atoi(port); - } - if (user) { - user = strtok_r(user, ":", &password); // user = | admin |, password = | joker| - user = Trim(user); // user = |admin| - if (password) { password = Trim(password); } // password = |joker| - } + RemoveSpace(host); // host = |[192.168.178.86:80,admin:joker| + host++; // host = |192.168.178.86:80,admin:joker| - Skip [ + host = strtok_r(host, ",", &user); // host = |192.168.178.86:80|, user = |admin:joker| + String url = F("http://"); // url = |http://| + url += host; // url = |http://192.168.178.86:80| + command = Trim(command); // command = |POWER1 ON| or |/any/link/starting/with/a/slash.php?log=123| - - String nuri = ""; if (command[0] != '/') { - nuri = "/cm?"; - if (user && password) { - nuri += F("user="); - nuri += user; - nuri += F("&password="); - nuri += password; - nuri += F("&"); - } - nuri += F("cmnd="); - } - nuri += command; - String uri = UrlEncode(nuri); - - IPAddress host_ip; - if (WiFi.hostByName(host, host_ip)) { - WiFiClient client; - - bool connected = false; - byte retry = 2; - while ((retry > 0) && !connected) { - --retry; - connected = client.connect(host_ip, nport); - if (connected) break; - } - - if (connected) { - String url = F("GET "); - url += uri; - url += F(" HTTP/1.1\r\nHost: "); -// url += IPAddress(host_ip).toString(); - url += host; // https://tools.ietf.org/html/rfc7230#section-5.4 (#4331) - if (port) { - url += F(":"); - url += port; + url += F("/cm?"); // url = |http://192.168.178.86/cm?| + if (user) { + user = strtok_r(user, ":", &password); // user = |admin|, password = |joker| + if (user && password) { + char userpass[128]; + snprintf_P(userpass, sizeof(userpass), PSTR("user=%s&password=%s&"), user, password); + url += userpass; // url = |http://192.168.178.86/cm?user=admin&password=joker&| } - url += F("\r\nConnection: close\r\n\r\n"); + } + url += F("cmnd="); // url = |http://192.168.178.86/cm?cmnd=| or |http://192.168.178.86/cm?user=admin&password=joker&cmnd=| + } + url += command; // url = |http://192.168.178.86/cm?cmnd=POWER1 ON| -//snprintf_P(log_data, sizeof(log_data), PSTR("DBG: Url |%s|"), url.c_str()); -//AddLog(LOG_LEVEL_DEBUG); +//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: Uri |%s|"), url.c_str()); - client.print(url.c_str()); - client.flush(); - client.stop(); +#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) + HTTPClient http; + if (http.begin(UrlEncode(url))) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON| +#else + WiFiClient http_client; + HTTPClient http; + if (http.begin(http_client, UrlEncode(url))) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON| +#endif + int http_code = http.GET(); // Start connection and send HTTP header + if (http_code > 0) { // http_code will be negative on error + if (http_code == HTTP_CODE_OK || http_code == HTTP_CODE_MOVED_PERMANENTLY) { +/* + // Return received data to the user - Adds 900+ bytes to the code + String result = http.getString(); // File found at server - may need lot of ram or trigger out of memory! + uint16_t j = 0; + for (uint16_t i = 0; i < result.length(); i++) { + char text = result.charAt(i); + if (text > 31) { // Remove control characters like linefeed + mqtt_data[j++] = text; + if (j == sizeof(mqtt_data) -2) { break; } + } + } + mqtt_data[j] = '\0'; + MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_WEBSEND)); +*/ + } status = 0; // No error - Done } else { status = 2; // Connection failed } + http.end(); // Clean up connection data } else { - status = 3; // Host not found + status = 3; // Host not found or connection error } } return status; @@ -2066,9 +2337,9 @@ bool WebCommand(void) * Interface \*********************************************************************************************/ -boolean Xdrv01(byte function) +bool Xdrv01(uint8_t function) { - boolean result = false; + bool result = false; switch (function) { case FUNC_LOOP: diff --git a/sonoff/xdrv_02_mqtt.ino b/sonoff/xdrv_02_mqtt.ino index 7ba5cf47a..ba3dabc09 100644 --- a/sonoff/xdrv_02_mqtt.ino +++ b/sonoff/xdrv_02_mqtt.ino @@ -1,7 +1,7 @@ /* xdrv_02_mqtt.ino - mqtt support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -73,9 +73,11 @@ 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 ; +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 bool mqtt_connected = false; // MQTT virtual connection status +bool mqtt_allowed = false; // MQTT enabled and parameters valid /*********************************************************************************************\ * MQTT driver specific code need to provide the following functions: @@ -83,7 +85,7 @@ bool mqtt_connected = false; // MQTT virtual connection status * bool MqttIsConnected() * void MqttDisconnect() * void MqttSubscribeLib(char *topic) - * bool MqttPublishLib(const char* topic, boolean retained) + * bool MqttPublishLib(const char* topic, bool retained) * void MqttLoop() \*********************************************************************************************/ @@ -108,13 +110,19 @@ void MqttDisconnect(void) MqttClient.disconnect(); } -void MqttSubscribeLib(char *topic) +void MqttSubscribeLib(const char *topic) { MqttClient.subscribe(topic); MqttClient.loop(); // Solve LmacRxBlk:1 messages } -bool MqttPublishLib(const char* topic, boolean retained) +void MqttUnsubscribeLib(const char *topic) +{ + MqttClient.unsubscribe(topic); + MqttClient.loop(); // Solve LmacRxBlk:1 messages +} + +bool MqttPublishLib(const char* topic, bool retained) { bool result = MqttClient.publish(topic, mqtt_data, retained); yield(); // #3313 @@ -146,12 +154,17 @@ void MqttDisconnectedCb(void) MqttDisconnected(MqttClient.State()); // status codes are documented in file mqtt.h as tConnState } -void MqttSubscribeLib(char *topic) +void MqttSubscribeLib(const char *topic) { MqttClient.Subscribe(topic, 0); } -bool MqttPublishLib(const char* topic, boolean retained) +void MqttUnsubscribeLib(const char *topic) +{ + MqttClient.Unsubscribe(topic, 0); +} + +bool MqttPublishLib(const char* topic, bool retained) { return MqttClient.Publish(topic, mqtt_data, strlen(mqtt_data), 0, retained); } @@ -179,21 +192,26 @@ void MqttDisconnect(void) void MqttMyDataCb(MQTTClient* client, char* topic, char* data, int data_len) //void MqttMyDataCb(MQTTClient *client, char topic[], char data[], int data_len) { -// MqttDataHandler((char*)topic, (byte*)data, data_len); +// MqttDataHandler((char*)topic, (uint8_t*)data, data_len); } */ void MqttMyDataCb(String &topic, String &data) { - MqttDataHandler((char*)topic.c_str(), (byte*)data.c_str(), data.length()); + MqttDataHandler((char*)topic.c_str(), (uint8_t*)data.c_str(), data.length()); } -void MqttSubscribeLib(char *topic) +void MqttSubscribeLib(const char *topic) { MqttClient.subscribe(topic, 0); } -bool MqttPublishLib(const char* topic, boolean retained) +void MqttUnsubscribeLib(const char *topic) +{ + MqttClient.unsubscribe(topic, 0); +} + +bool MqttPublishLib(const char* topic, bool retained) { return MqttClient.publish(topic, mqtt_data, strlen(mqtt_data), retained, 0); } @@ -210,26 +228,28 @@ void MqttLoop(void) #ifdef USE_DISCOVERY #ifdef MQTT_HOST_DISCOVERY -boolean MqttDiscoverServer(void) +void MqttDiscoverServer(void) { - if (!mdns_begun) { return false; } + if (!mdns_begun) { return; } int n = MDNS.queryService("mqtt", "tcp"); // Search for mqtt service - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n); if (n > 0) { - // Note: current strategy is to get the first MQTT service (even when many are found) - snprintf_P(Settings.mqtt_host, sizeof(Settings.mqtt_host), MDNS.IP(0).toString().c_str()); - Settings.mqtt_port = MDNS.port(0); + uint8_t i = 0; // If the hostname isn't set, use the first record found. +#ifdef MDNS_HOSTNAME + for (i = n; i > 0; i--) { // Search from last to first and use first if not found + if (!strcmp(MDNS.hostname(i).c_str(), MDNS_HOSTNAME)) { + break; // Stop at matching record + } + } +#endif // MDNS_HOSTNAME + snprintf_P(Settings.mqtt_host, sizeof(Settings.mqtt_host), MDNS.IP(i).toString().c_str()); + Settings.mqtt_port = MDNS.port(i); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"), - MDNS.hostname(0).c_str(), Settings.mqtt_host, Settings.mqtt_port); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"), MDNS.hostname(i).c_str(), Settings.mqtt_host, Settings.mqtt_port); } - - return n > 0; } #endif // MQTT_HOST_DISCOVERY #endif // USE_DISCOVERY @@ -244,19 +264,26 @@ void MqttRetryCounter(uint8_t value) mqtt_retry_counter = value; } -void MqttSubscribe(char *topic) +void MqttSubscribe(const char *topic) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_SUBSCRIBE_TO " %s"), topic); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT D_SUBSCRIBE_TO " %s"), topic); MqttSubscribeLib(topic); } -void MqttPublishDirect(const char* topic, boolean retained) +void MqttUnsubscribe(const char *topic) +{ + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT D_UNSUBSCRIBE_FROM " %s"), topic); + MqttUnsubscribeLib(topic); +} + +void MqttPublishDirect(const char* topic, bool retained) { char sretained[CMDSZ]; char slog_type[10]; +#ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("MqttPublishDirect")); +#endif sretained[0] = '\0'; snprintf_P(slog_type, sizeof(slog_type), PSTR(D_LOG_RESULT)); @@ -278,14 +305,14 @@ void MqttPublishDirect(const char* topic, boolean retained) snprintf_P(log_data, sizeof(log_data), PSTR("%s ..."), log_data); } snprintf_P(log_data, sizeof(log_data), PSTR("%s%s"), log_data, sretained); - AddLog(LOG_LEVEL_INFO); + if (Settings.ledstate &0x04) { blinks++; } } -void MqttPublish(const char* topic, boolean retained) +void MqttPublish(const char* topic, bool retained) { char *me; @@ -303,7 +330,7 @@ void MqttPublish(const char* topic) MqttPublish(topic, false); } -void MqttPublishPrefixTopic_P(uint8_t prefix, const char* subtopic, boolean retained) +void MqttPublishPrefixTopic_P(uint8_t prefix, const char* subtopic, bool retained) { /* prefix 0 = cmnd using subtopic * prefix 1 = stat using subtopic @@ -316,7 +343,7 @@ void MqttPublishPrefixTopic_P(uint8_t prefix, const char* subtopic, boolean reta char stopic[TOPSZ]; snprintf_P(romram, sizeof(romram), ((prefix > 3) && !Settings.flag.mqtt_response) ? S_RSLT_RESULT : subtopic); - for (byte i = 0; i < strlen(romram); i++) { + for (uint8_t i = 0; i < strlen(romram); i++) { romram[i] = toupper(romram[i]); } prefix &= 3; @@ -329,14 +356,14 @@ void MqttPublishPrefixTopic_P(uint8_t prefix, const char* subtopic) MqttPublishPrefixTopic_P(prefix, subtopic, false); } -void MqttPublishPowerState(byte device) +void MqttPublishPowerState(uint8_t device) { char stopic[TOPSZ]; char scommand[33]; if ((device < 1) || (device > devices_present)) { device = 1; } - if ((SONOFF_IFAN02 == Settings.module) && (device > 1)) { + if ((SONOFF_IFAN02 == my_module_type) && (device > 1)) { if (GetFanspeed() < MAX_FAN_SPEED) { // 4 occurs when fanspeed is 3 and RC button 2 is pressed #ifdef USE_DOMOTICZ DomoticzUpdateFanState(); // RC Button feedback @@ -358,7 +385,7 @@ void MqttPublishPowerState(byte device) } } -void MqttPublishPowerBlinkState(byte device) +void MqttPublishPowerBlinkState(uint8_t device) { char scommand[33]; @@ -373,14 +400,17 @@ void MqttPublishPowerBlinkState(byte device) /*********************************************************************************************/ +uint16_t MqttConnectCount() +{ + return mqtt_connect_count; +} + void MqttDisconnected(int state) { mqtt_connected = false; mqtt_retry_counter = Settings.mqtt_retry; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d, rc %d. " D_RETRY_IN " %d " D_UNIT_SECOND), - Settings.mqtt_host, Settings.mqtt_port, state, mqtt_retry_counter); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d, rc %d. " D_RETRY_IN " %d " D_UNIT_SECOND), Settings.mqtt_host, Settings.mqtt_port, state, mqtt_retry_counter); rules_flag.mqtt_disconnected = 1; } @@ -388,10 +418,11 @@ void MqttConnected(void) { char stopic[TOPSZ]; - if (Settings.flag.mqtt_enabled) { + if (mqtt_allowed) { AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_CONNECTED)); mqtt_connected = true; mqtt_retry_counter = 0; + mqtt_connect_count++; GetTopic_P(stopic, TELE, mqtt_topic, S_LWT); snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_ONLINE)); @@ -415,8 +446,7 @@ 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\"}"), - my_module.name, my_version, my_image, GetFallbackTopic_P(stopic, CMND, ""), Settings.mqtt_grptopic); -// my_module.name, my_version, my_image, mqtt_client, Settings.mqtt_grptopic); + 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) { @@ -428,9 +458,9 @@ void MqttConnected(void) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_RESTARTREASON "\":\"%s\"}"), (GetResetReason() == "Exception") ? ESP.getResetInfo().c_str() : GetResetReason().c_str()); MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "3")); - for (byte i = 1; i <= devices_present; i++) { + for (uint8_t i = 1; i <= devices_present; i++) { MqttPublishPowerState(i); - if (SONOFF_IFAN02 == Settings.module) { break; } // Report status of light relay only + if (SONOFF_IFAN02 == my_module_type) { break; } // Report status of light relay only } if (Settings.tele_period) { tele_period = Settings.tele_period -9; } // Enable TelePeriod in 9 seconds rules_flag.system_boot = 1; @@ -445,15 +475,15 @@ void MqttConnected(void) } #ifdef USE_MQTT_TLS -boolean MqttCheckTls(void) +bool MqttCheckTls(void) { char fingerprint1[60]; char fingerprint2[60]; - boolean result = false; + bool result = false; fingerprint1[0] = '\0'; fingerprint2[0] = '\0'; - for (byte i = 0; i < sizeof(Settings.mqtt_fingerprint[0]); i++) { + for (uint8_t i = 0; i < sizeof(Settings.mqtt_fingerprint[0]); i++) { snprintf_P(fingerprint1, sizeof(fingerprint1), PSTR("%s%s%02X"), fingerprint1, (i) ? " " : "", Settings.mqtt_fingerprint[0][i]); snprintf_P(fingerprint2, sizeof(fingerprint2), PSTR("%s%s%02X"), fingerprint2, (i) ? " " : "", Settings.mqtt_fingerprint[1][i]); } @@ -465,9 +495,7 @@ boolean MqttCheckTls(void) //#endif if (!EspClient.connect(Settings.mqtt_host, Settings.mqtt_port)) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_TLS_CONNECT_FAILED_TO " %s:%d. " D_RETRY_IN " %d " D_UNIT_SECOND), - Settings.mqtt_host, Settings.mqtt_port, mqtt_retry_counter); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT D_TLS_CONNECT_FAILED_TO " %s:%d. " D_RETRY_IN " %d " D_UNIT_SECOND), Settings.mqtt_host, Settings.mqtt_port, mqtt_retry_counter); } else { #ifdef USE_MQTT_TLS_CA_CERT unsigned char tls_ca_cert[] = MQTT_TLS_CA_CERT; @@ -486,7 +514,19 @@ boolean MqttCheckTls(void) AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED "2")); result = true; } -#endif +#ifdef MDNS_HOSTNAME + // If the hostname is set, check that as well. + // This lets certs with the hostname for the CN be used. + else if (EspClient.verify(fingerprint1, MDNS_HOSTNAME)) { + AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED "1")); + result = true; + } + else if (EspClient.verify(fingerprint2, MDNS_HOSTNAME)) { + AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED "2")); + result = true; + } +#endif // MDNS_HOSTNAME +#endif // USE_MQTT_TLS_CA_CERT } if (!result) AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_FAILED)); EspClient.stop(); @@ -499,7 +539,18 @@ void MqttReconnect(void) { char stopic[TOPSZ]; - if (!Settings.flag.mqtt_enabled) { + mqtt_allowed = Settings.flag.mqtt_enabled; + if (mqtt_allowed) { +#ifdef USE_DISCOVERY +#ifdef MQTT_HOST_DISCOVERY + MqttDiscoverServer(); +#endif // MQTT_HOST_DISCOVERY +#endif // USE_DISCOVERY + if (!strlen(Settings.mqtt_host) || !Settings.mqtt_port) { + mqtt_allowed = false; + } + } + if (!mqtt_allowed) { MqttConnected(); return; } @@ -514,14 +565,6 @@ void MqttReconnect(void) mqtt_retry_counter = Settings.mqtt_retry; global_state.mqtt_down = 1; -#ifndef USE_MQTT_TLS -#ifdef USE_DISCOVERY -#ifdef MQTT_HOST_DISCOVERY - if (!strlen(Settings.mqtt_host) && !MqttDiscoverServer()) { return; } -#endif // MQTT_HOST_DISCOVERY -#endif // USE_DISCOVERY -#endif // USE_MQTT_TLS - char *mqtt_user = NULL; char *mqtt_pwd = NULL; if (strlen(Settings.mqtt_user) > 0) mqtt_user = Settings.mqtt_user; @@ -586,13 +629,11 @@ void MqttCheck(void) if (!MqttIsConnected()) { global_state.mqtt_down = 1; if (!mqtt_retry_counter) { -#ifndef USE_MQTT_TLS #ifdef USE_DISCOVERY #ifdef MQTT_HOST_DISCOVERY if (!strlen(Settings.mqtt_host) && !mdns_begun) { return; } #endif // MQTT_HOST_DISCOVERY #endif // USE_DISCOVERY -#endif // USE_MQTT_TLS MqttReconnect(); } else { mqtt_retry_counter--; @@ -620,7 +661,7 @@ bool MqttCommand(void) uint16_t data_len = XdrvMailbox.data_len; uint16_t payload16 = XdrvMailbox.payload16; int16_t payload = XdrvMailbox.payload; - uint8_t grpflg = XdrvMailbox.grpflg; + bool grpflg = XdrvMailbox.grpflg; char *type = XdrvMailbox.topic; char *dataBuf = XdrvMailbox.data; @@ -664,20 +705,20 @@ bool MqttCommand(void) if ((data_len > 0) && (data_len < sizeof(fingerprint))) { strlcpy(fingerprint, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1 == index) ? MQTT_FINGERPRINT1 : MQTT_FINGERPRINT2 : dataBuf, sizeof(fingerprint)); char *p = fingerprint; - for (byte i = 0; i < 20; i++) { + for (uint8_t i = 0; i < 20; i++) { Settings.mqtt_fingerprint[index -1][i] = strtol(p, &p, 16); } restart_flag = 2; } fingerprint[0] = '\0'; - for (byte i = 0; i < sizeof(Settings.mqtt_fingerprint[index -1]); i++) { + 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); } #endif - else if ((CMND_MQTTCLIENT == command_code) && !grpflg) { - if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_client))) { + else if (CMND_MQTTCLIENT == command_code) { + if (!grpflg && (data_len > 0) && (data_len < sizeof(Settings.mqtt_client))) { strlcpy(Settings.mqtt_client, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_CLIENT_ID : dataBuf, sizeof(Settings.mqtt_client)); restart_flag = 2; } @@ -726,10 +767,10 @@ bool MqttCommand(void) if (data_len > 0) { char *mqtt_part = strtok(dataBuf, " "); if (mqtt_part) { - snprintf(stemp1, sizeof(stemp1), mqtt_part); + strlcpy(stemp1, mqtt_part, sizeof(stemp1)); mqtt_part = strtok(NULL, " "); if (mqtt_part) { - snprintf(mqtt_data, sizeof(mqtt_data), mqtt_part); + strlcpy(mqtt_data, mqtt_part, sizeof(mqtt_data)); } else { mqtt_data[0] = '\0'; } @@ -748,8 +789,8 @@ bool MqttCommand(void) } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_grptopic); } - else if ((CMND_TOPIC == command_code) && !grpflg) { - if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_topic))) { + else if (CMND_TOPIC == command_code) { + if (!grpflg && (data_len > 0) && (data_len < sizeof(Settings.mqtt_topic))) { MakeValidMqtt(0, dataBuf); if (!strcmp(dataBuf, mqtt_client)) SetShortcut(dataBuf, SC_DEFAULT); strlcpy(stemp1, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_TOPIC : dataBuf, sizeof(stemp1)); @@ -762,8 +803,8 @@ bool MqttCommand(void) } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_topic); } - else if ((CMND_BUTTONTOPIC == command_code) && !grpflg) { - if ((data_len > 0) && (data_len < sizeof(Settings.button_topic))) { + else if (CMND_BUTTONTOPIC == command_code) { + if (!grpflg && (data_len > 0) && (data_len < sizeof(Settings.button_topic))) { MakeValidMqtt(0, dataBuf); if (!strcmp(dataBuf, mqtt_client)) SetShortcut(dataBuf, SC_DEFAULT); switch (Shortcut(dataBuf)) { @@ -850,22 +891,24 @@ bool MqttCommand(void) const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT; const char HTTP_BTN_MENU_MQTT[] PROGMEM = - "
"; + "

"; -const char HTTP_FORM_MQTT[] PROGMEM = - "
 " D_MQTT_PARAMETERS " 
" - "
" D_HOST " (" MQTT_HOST ")

" - "
" D_PORT " (" STR(MQTT_PORT) ")

" - "
" D_CLIENT " ({m0)

" - "
" D_USER " (" MQTT_USER ")

" - "
" D_PASSWORD "

" - "
" D_TOPIC " = %topic% (" MQTT_TOPIC ")

" - "
" D_FULL_TOPIC " (" MQTT_FULLTOPIC ")

"; +const char HTTP_FORM_MQTT1[] PROGMEM = + "
 " D_MQTT_PARAMETERS " " + "" + "

" D_HOST " (" MQTT_HOST ")

" + "

" D_PORT " (" STR(MQTT_PORT) ")

" + "

" D_CLIENT " (%s)

"; +const char HTTP_FORM_MQTT2[] PROGMEM = + "

" D_USER " (" MQTT_USER ")

" + "

" D_PASSWORD "

" + "

" D_TOPIC " = %%topic%% (" MQTT_TOPIC ")

" + "

" D_FULL_TOPIC " (%s)

"; void HandleMqttConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT); if (WebServer->hasArg("save")) { @@ -874,23 +917,24 @@ void HandleMqttConfiguration(void) return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_MQTT)); - page += FPSTR(HTTP_HEAD_STYLE); - - page += FPSTR(HTTP_FORM_MQTT); char str[sizeof(Settings.mqtt_client)]; - page.replace(F("{m0"), Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client))); - page.replace(F("{m1"), Settings.mqtt_host); - page.replace(F("{m2"), String(Settings.mqtt_port)); - page.replace(F("{m3"), Settings.mqtt_client); - page.replace(F("{m4"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user); - page.replace(F("{m6"), Settings.mqtt_topic); - page.replace(F("{m7"), Settings.mqtt_fulltopic); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentStart_P(S_CONFIGURE_MQTT); + WSContentSendStyle(); + 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); + WSContentSend_P(HTTP_FORM_MQTT2, + (Settings.mqtt_user[0] == '\0') ? "0" : Settings.mqtt_user, + Settings.mqtt_topic, + MQTT_FULLTOPIC, MQTT_FULLTOPIC, + Settings.mqtt_fulltopic); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); } void MqttSaveSettings(void) @@ -920,10 +964,9 @@ void MqttSaveSettings(void) WebGetArg("mu", tmp, sizeof(tmp)); strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user)); WebGetArg("mp", tmp, sizeof(tmp)); - strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.mqtt_pwd : tmp, sizeof(Settings.mqtt_pwd)); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"), + strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? "" : (!strcmp(tmp, D_ASTERISK_PWD)) ? Settings.mqtt_pwd : tmp, sizeof(Settings.mqtt_pwd)); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"), Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_topic, Settings.mqtt_fulltopic); - AddLog(LOG_LEVEL_INFO); } #endif // USE_WEBSERVER @@ -931,15 +974,15 @@ void MqttSaveSettings(void) * Interface \*********************************************************************************************/ -boolean Xdrv02(byte function) +bool Xdrv02(uint8_t function) { - boolean result = false; + bool result = false; if (Settings.flag.mqtt_enabled) { switch (function) { #ifdef USE_WEBSERVER case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_MQTT, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend_P(HTTP_BTN_MENU_MQTT); break; case FUNC_WEB_ADD_HANDLER: WebServer->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration); diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index b97c53fc2..10814bd65 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -1,7 +1,7 @@ /* xdrv_03_energy.ino - Energy sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,9 +31,14 @@ #include +#define D_CMND_POWERCAL "PowerCal" +#define D_CMND_VOLTAGECAL "VoltageCal" +#define D_CMND_CURRENTCAL "CurrentCal" + enum EnergyCommands { CMND_POWERDELTA, CMND_POWERLOW, CMND_POWERHIGH, CMND_VOLTAGELOW, CMND_VOLTAGEHIGH, CMND_CURRENTLOW, CMND_CURRENTHIGH, + CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL, CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_ENERGYRESET, CMND_MAXENERGY, CMND_MAXENERGYSTART, CMND_MAXPOWER, CMND_MAXPOWERHOLD, CMND_MAXPOWERWINDOW, @@ -41,6 +46,7 @@ enum EnergyCommands { const char kEnergyCommands[] PROGMEM = D_CMND_POWERDELTA "|" D_CMND_POWERLOW "|" D_CMND_POWERHIGH "|" D_CMND_VOLTAGELOW "|" D_CMND_VOLTAGEHIGH "|" D_CMND_CURRENTLOW "|" D_CMND_CURRENTHIGH "|" + D_CMND_POWERCAL "|" D_CMND_VOLTAGECAL "|" D_CMND_CURRENTCAL "|" D_CMND_POWERSET "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" D_CMND_ENERGYRESET "|" D_CMND_MAXENERGY "|" D_CMND_MAXENERGYSTART "|" D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|" @@ -66,24 +72,23 @@ uint8_t energy_power_delta = 0; bool energy_type_dc = false; bool energy_power_on = true; +bool energy_min_power_flag = false; +bool energy_max_power_flag = false; +bool energy_min_voltage_flag = false; +bool energy_max_voltage_flag = false; +bool energy_min_current_flag = false; +bool energy_max_current_flag = false; -byte energy_min_power_flag = 0; -byte energy_max_power_flag = 0; -byte energy_min_voltage_flag = 0; -byte energy_max_voltage_flag = 0; -byte energy_min_current_flag = 0; -byte energy_max_current_flag = 0; - -byte energy_power_steady_cntr = 8; // Allow for power on stabilization -byte energy_max_energy_state = 0; +uint8_t energy_power_steady_cntr = 8; // Allow for power on stabilization +uint8_t energy_max_energy_state = 0; #if FEATURE_POWER_LIMIT -byte energy_mplr_counter = 0; +uint8_t energy_mplr_counter = 0; uint16_t energy_mplh_counter = 0; uint16_t energy_mplw_counter = 0; #endif // FEATURE_POWER_LIMIT -byte energy_fifth_second = 0; +uint8_t energy_fifth_second = 0; Ticker ticker_energy; int energy_command_code = 0; @@ -141,9 +146,9 @@ void EnergySaveState(void) Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; } -boolean EnergyMargin(byte type, uint16_t margin, uint16_t value, byte &flag, byte &save_flag) +bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool &save_flag) { - byte change; + bool change; if (!margin) return false; change = save_flag; @@ -167,8 +172,8 @@ void EnergyMarginCheck(void) uint16_t energy_power_u = 0; uint16_t energy_voltage_u = 0; uint16_t energy_current_u = 0; - boolean flag; - boolean jsonflg; + bool flag; + bool jsonflg; if (energy_power_steady_cntr) { energy_power_steady_cntr--; @@ -194,34 +199,33 @@ void EnergyMarginCheck(void) energy_voltage_u = (uint16_t)(energy_voltage); energy_current_u = (uint16_t)(energy_current * 1000); -// snprintf_P(log_data, sizeof(log_data), PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u); -// AddLog(LOG_LEVEL_DEBUG); +// 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("{")); - jsonflg = 0; - if (EnergyMargin(0, Settings.energy_min_power, energy_power_u, flag, energy_min_power_flag)) { + 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)); - jsonflg = 1; + jsonflg = true; } - if (EnergyMargin(1, Settings.energy_max_power, energy_power_u, flag, energy_max_power_flag)) { + 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)); - jsonflg = 1; + jsonflg = true; } - if (EnergyMargin(0, Settings.energy_min_voltage, energy_voltage_u, flag, energy_min_voltage_flag)) { + 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)); - jsonflg = 1; + jsonflg = true; } - if (EnergyMargin(1, Settings.energy_max_voltage, energy_voltage_u, flag, energy_max_voltage_flag)) { + 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)); - jsonflg = 1; + jsonflg = true; } - if (EnergyMargin(0, Settings.energy_min_current, energy_current_u, flag, energy_min_current_flag)) { + 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)); - jsonflg = 1; + jsonflg = true; } - if (EnergyMargin(1, Settings.energy_max_current, energy_current_u, flag, energy_max_current_flag)) { + 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)); - jsonflg = 1; + jsonflg = true; } if (jsonflg) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); @@ -304,7 +308,7 @@ void EnergyMqttShow(void) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); int tele_period_save = tele_period; tele_period = 2; - EnergyShow(1); + EnergyShow(true); tele_period = tele_period_save; snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); @@ -315,12 +319,12 @@ void EnergyMqttShow(void) * Commands \*********************************************************************************************/ -boolean EnergyCommand(void) +bool EnergyCommand(void) { char command [CMDSZ]; char sunit[CMDSZ]; - boolean serviced = true; - uint8_t status_flag = 0; + bool serviced = true; + bool status_flag = false; uint8_t unit = 0; unsigned long nvalue = 0; @@ -390,6 +394,7 @@ boolean EnergyCommand(void) Settings.energy_kWhtoday = energy_kWhtoday; RtcSettings.energy_kWhtoday = energy_kWhtoday; energy_daily = (float)energy_kWhtoday / 100000; + if (!RtcSettings.energy_kWhtotal && !energy_kWhtoday) { Settings.energy_kWhtotal_time = LocalTime(); } break; case 2: Settings.energy_kWhyesterday = lnum *100; @@ -398,7 +403,7 @@ boolean EnergyCommand(void) RtcSettings.energy_kWhtotal = lnum *100; Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; energy_total = (float)(RtcSettings.energy_kWhtotal + energy_kWhtoday) / 100000; - if (!energy_total) { Settings.energy_kWhtotal_time = LocalTime(); } + Settings.energy_kWhtotal_time = (!energy_kWhtoday) ? LocalTime() : Midnight(); break; } } @@ -411,23 +416,38 @@ boolean EnergyCommand(void) snprintf_P(mqtt_data, sizeof(mqtt_data), 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 = 1; + status_flag = true; } - else if ((CMND_POWERSET == command_code) && XnrgCall(FUNC_COMMAND)) { // Watt + else if ((CMND_POWERCAL == command_code) && XnrgCall(FUNC_COMMAND)) { // microseconds + if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { Settings.energy_power_calibration = XdrvMailbox.payload; } nvalue = Settings.energy_power_calibration; unit = UNIT_MICROSECOND; } - else if ((CMND_VOLTAGESET == command_code) && XnrgCall(FUNC_COMMAND)) { // Volt + else if ((CMND_VOLTAGECAL == command_code) && XnrgCall(FUNC_COMMAND)) { // microseconds + if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { Settings.energy_voltage_calibration = XdrvMailbox.payload; } nvalue = Settings.energy_voltage_calibration; unit = UNIT_MICROSECOND; } - else if ((CMND_CURRENTSET == command_code) && XnrgCall(FUNC_COMMAND)) { // milliAmpere + else if ((CMND_CURRENTCAL == command_code) && XnrgCall(FUNC_COMMAND)) { // microseconds + if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { Settings.energy_current_calibration = XdrvMailbox.payload; } nvalue = Settings.energy_current_calibration; unit = UNIT_MICROSECOND; } + else if ((CMND_POWERSET == command_code) && XnrgCall(FUNC_COMMAND)) { // Watt + nvalue = Settings.energy_power_calibration; + unit = UNIT_MILLISECOND; + } + else if ((CMND_VOLTAGESET == command_code) && XnrgCall(FUNC_COMMAND)) { // Volt + nvalue = Settings.energy_voltage_calibration; + unit = UNIT_MILLISECOND; + } + else if ((CMND_CURRENTSET == command_code) && XnrgCall(FUNC_COMMAND)) { // milliAmpere + nvalue = Settings.energy_current_calibration; + unit = UNIT_MILLISECOND; + } else if ((CMND_FREQUENCYSET == command_code) && XnrgCall(FUNC_COMMAND)) { // Hz nvalue = Settings.energy_frequency_calibration; - unit = UNIT_MICROSECOND; + unit = UNIT_MILLISECOND; } #if FEATURE_POWER_LIMIT @@ -493,8 +513,9 @@ boolean EnergyCommand(void) if (serviced && !status_flag) { - if (UNIT_MICROSECOND == unit) { + if (UNIT_MILLISECOND == unit) { snprintf_P(command, sizeof(command), PSTR("%sCal"), command); + unit = UNIT_MICROSECOND; } if (Settings.flag.value_units) { @@ -546,7 +567,7 @@ const char HTTP_ENERGY_SNS4[] PROGMEM = "%s" "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER -void EnergyShow(boolean json) +void EnergyShow(bool json) { char speriod[20]; char sfrequency[20]; @@ -659,9 +680,9 @@ void EnergyShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xdrv03(byte function) +bool Xdrv03(uint8_t function) { - boolean result = false; + bool result = false; if (FUNC_PRE_INIT == function) { EnergyDrvInit(); @@ -674,6 +695,9 @@ boolean Xdrv03(byte function) case FUNC_SET_POWER: EnergySetPowerSteadyCounter(); break; + case FUNC_LOOP: + XnrgCall(FUNC_LOOP); + break; case FUNC_SERIAL: result = XnrgCall(FUNC_SERIAL); break; @@ -682,9 +706,9 @@ boolean Xdrv03(byte function) return result; } -boolean Xsns03(byte function) +bool Xsns03(uint8_t function) { - boolean result = false; + bool result = false; if (energy_flg) { switch (function) { @@ -695,11 +719,11 @@ boolean Xsns03(byte function) EnergyMarginCheck(); break; case FUNC_JSON_APPEND: - EnergyShow(1); + EnergyShow(true); break; #ifdef USE_WEBSERVER case FUNC_WEB_APPEND: - EnergyShow(0); + EnergyShow(false); break; #endif // USE_WEBSERVER case FUNC_SAVE_BEFORE_RESTART: diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino index ae6644dda..1dc6e8630 100644 --- a/sonoff/xdrv_04_light.ino +++ b/sonoff/xdrv_04_light.ino @@ -1,7 +1,7 @@ /* xdrv_04_light.ino - PWM, WS2812 and sonoff led support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,6 +32,9 @@ * 11 +WS2812 RGB(W) no (One WS2812 RGB or RGBW ledstrip) * 12 AiLight RGBW no * 13 Sonoff B1 RGBCW yes + * 19 SM16716 RGB no + * 20 SM16716+W RGBW no + * 21 SM16716+CW RGBCW yes * * light_scheme WS2812 3+ Colors 1+2 Colors Effect * ------------ ------ --------- ---------- ----------------- @@ -106,11 +109,15 @@ uint8_t light_current_color[5]; uint8_t light_new_color[5]; uint8_t light_last_color[5]; uint8_t light_signal_color[5]; +uint8_t light_color_remap[5]; + +bool light_ct_rgb_linked; uint8_t light_wheel = 0; uint8_t light_subtype = 0; uint8_t light_device = 0; uint8_t light_power = 0; +uint8_t light_old_power = 1; uint8_t light_update = 1; uint8_t light_wakeup_active = 0; uint8_t light_wakeup_dimmer = 0; @@ -198,8 +205,7 @@ void AriluxRfHandler(void) } uint16_t stored_hostcode = Settings.rf_code[1][6] << 8 | Settings.rf_code[1][7]; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_RFR D_HOST D_CODE " 0x%04X, " D_RECEIVED " 0x%06X"), stored_hostcode, arilux_rf_received_value); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_RFR D_HOST D_CODE " 0x%04X, " D_RECEIVED " 0x%06X"), stored_hostcode, arilux_rf_received_value); if (hostcode == stored_hostcode) { char command[33]; @@ -247,23 +253,23 @@ void AriluxRfHandler(void) void AriluxRfInit(void) { - if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_LED2] < 99)) { + if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_LED4] < 99)) { if (Settings.last_module != Settings.module) { Settings.rf_code[1][6] = 0; Settings.rf_code[1][7] = 0; Settings.last_module = Settings.module; } arilux_rf_received_value = 0; - digitalWrite(pin[GPIO_LED2], !bitRead(led_inverted, 1)); // Turn on RF + digitalWrite(pin[GPIO_LED4], !bitRead(led_inverted, 3)); // Turn on RF attachInterrupt(pin[GPIO_ARIRFRCV], AriluxRfInterrupt, CHANGE); } } void AriluxRfDisable(void) { - if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_LED2] < 99)) { + if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_LED4] < 99)) { detachInterrupt(pin[GPIO_ARIRFRCV]); - digitalWrite(pin[GPIO_LED2], bitRead(led_inverted, 1)); // Turn off RF + digitalWrite(pin[GPIO_LED4], bitRead(led_inverted, 3)); // Turn off RF } } #endif // USE_ARILUX_RF @@ -353,6 +359,109 @@ void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t dut os_delay_us(12); // TStop > 12us. } +#ifdef USE_SM16716 +/*********************************************************************************************\ + * SM16716 - Controlling RGB over a synchronous serial line + * Copyright (C) 2019 Gabor Simon + * + * Source: https://community.home-assistant.io/t/cheap-uk-wifi-bulbs-with-tasmota-teardown-help-tywe3s/40508/27 + * +\*********************************************************************************************/ + +// Enable this for debug logging +//#define D_LOG_SM16716 "SM16716: " + +uint8_t sm16716_pin_clk = 100; +uint8_t sm16716_pin_dat = 100; +uint8_t sm16716_pin_sel = 100; +uint8_t sm16716_enabled = 0; + +void SM16716_SendBit(uint8_t v) +{ + /* NOTE: + * According to the spec sheet, max freq is 30 MHz, that is 16.6 ns per high/low half of the + * clk square wave. That is less than the overhead of 'digitalWrite' at this clock rate, + * so no additional delays are needed yet. */ + + digitalWrite(sm16716_pin_dat, (v != 0) ? HIGH : LOW); + //delayMicroseconds(1); + digitalWrite(sm16716_pin_clk, HIGH); + //delayMicroseconds(1); + digitalWrite(sm16716_pin_clk, LOW); +} + +void SM16716_SendByte(uint8_t v) +{ + uint8_t mask; + + for (mask = 0x80; mask; mask >>= 1) { + SM16716_SendBit(v & mask); + } +} + +void SM16716_Update(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b) +{ + if (sm16716_pin_sel < 99) { + uint8_t sm16716_should_enable = (duty_r | duty_g | duty_b); + if (!sm16716_enabled && sm16716_should_enable) { +#ifdef D_LOG_SM16716 + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_SM16716 "turning color on")); +#endif // D_LOG_SM16716 + sm16716_enabled = 1; + digitalWrite(sm16716_pin_sel, HIGH); + // in testing I found it takes a minimum of ~380us to wake up the chip + // tested on a Merkury RGBW with an SM726EB + delayMicroseconds(1000); + SM16716_Init(); + } + else if (sm16716_enabled && !sm16716_should_enable) { +#ifdef D_LOG_SM16716 + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_SM16716 "turning color off")); +#endif // D_LOG_SM16716 + sm16716_enabled = 0; + digitalWrite(sm16716_pin_sel, LOW); + } + } +#ifdef D_LOG_SM16716 + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_SM16716 "Update; rgb=%02x%02x%02x"), duty_r, duty_g, duty_b); +#endif // D_LOG_SM16716 + + // send start bit + SM16716_SendBit(1); + SM16716_SendByte(duty_r); + SM16716_SendByte(duty_g); + SM16716_SendByte(duty_b); + + // send a 'do it' pulse + // (if multiple chips are chained, each one processes the 1st '1rgb' 25-bit block and + // passes on the rest, right until the one starting with 0) + //SM16716_Init(); + SM16716_SendBit(0); + SM16716_SendByte(0); + SM16716_SendByte(0); + SM16716_SendByte(0); +} + +bool SM16716_ModuleSelected(void) +{ + sm16716_pin_clk = pin[GPIO_SM16716_CLK]; + sm16716_pin_dat = pin[GPIO_SM16716_DAT]; + sm16716_pin_sel = pin[GPIO_SM16716_SEL]; +#ifdef D_LOG_SM16716 + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_SM16716 "ModuleSelected; clk_pin=%d, dat_pin=%d)"), sm16716_pin_clk, sm16716_pin_dat); +#endif // D_LOG_SM16716 + return (sm16716_pin_clk < 99) && (sm16716_pin_dat < 99); +} + +void SM16716_Init(void) +{ + for (uint8_t t_init = 0; t_init < 50; ++t_init) { + SM16716_SendBit(0); + } +} + +#endif // ifdef USE_SM16716 + /********************************************************************************************/ void LightInit(void) @@ -366,29 +475,29 @@ void LightInit(void) Settings.light_color[0] = 255; // One channel only supports Dimmer but needs max color } if (light_type < LT_PWM6) { // PWM - for (byte i = 0; i < light_type; i++) { + for (uint8_t i = 0; i < light_type; i++) { Settings.pwm_value[i] = 0; // Disable direct PWM control if (pin[GPIO_PWM1 +i] < 99) { pinMode(pin[GPIO_PWM1 +i], OUTPUT); } } - if (SONOFF_LED == Settings.module) { // Fix Sonoff Led instabilities - if (!my_module.gp.io[4]) { + if (SONOFF_LED == my_module_type) { // Fix Sonoff Led instabilities + if (!my_module.io[4]) { pinMode(4, OUTPUT); // Stop floating outputs digitalWrite(4, LOW); } - if (!my_module.gp.io[5]) { + if (!my_module.io[5]) { pinMode(5, OUTPUT); // Stop floating outputs digitalWrite(5, LOW); } - if (!my_module.gp.io[14]) { + if (!my_module.io[14]) { pinMode(14, OUTPUT); // Stop floating outputs digitalWrite(14, LOW); } } if (pin[GPIO_ARIRFRCV] < 99) { - if (pin[GPIO_LED2] < 99) { - digitalWrite(pin[GPIO_LED2], bitRead(led_inverted, 1)); // Turn off RF + if (pin[GPIO_LED4] < 99) { + digitalWrite(pin[GPIO_LED4], bitRead(led_inverted, 3)); // Turn off RF } } } @@ -401,6 +510,32 @@ void LightInit(void) max_scheme = LS_MAX + WS2812_SCHEMES; } #endif // USE_WS2812 ************************************************************************ +#ifdef USE_SM16716 + else if (LT_SM16716 == light_type - light_subtype) { + // init PWM + for (uint8_t i = 0; i < light_subtype; i++) { + Settings.pwm_value[i] = 0; // Disable direct PWM control + if (pin[GPIO_PWM1 +i] < 99) { + pinMode(pin[GPIO_PWM1 +i], OUTPUT); + } + } + // init sm16716 + pinMode(sm16716_pin_clk, OUTPUT); + digitalWrite(sm16716_pin_clk, LOW); + + pinMode(sm16716_pin_dat, OUTPUT); + digitalWrite(sm16716_pin_dat, LOW); + + if (sm16716_pin_sel < 99) { + pinMode(sm16716_pin_sel, OUTPUT); + digitalWrite(sm16716_pin_sel, LOW); + // no need to call SM16716_Init here, it will be called after sel goes HIGH + } else { + // no sel pin means you have an 'always on' chip, so init right away + SM16716_Init(); + } + } +#endif // ifdef USE_SM16716 else { light_pdi_pin = pin[GPIO_DI]; light_pdcki_pin = pin[GPIO_DCKI]; @@ -422,6 +557,39 @@ void LightInit(void) light_power = 0; light_update = 1; light_wakeup_active = 0; + + LightUpdateColorMapping(); +} + +void LightUpdateColorMapping(void) +{ + uint8_t param = Settings.param[P_RGB_REMAP] & 127; + if(param > 119){ + param = 0; + } + uint8_t tmp[] = {0,1,2,3,4}; + light_color_remap[0] = tmp[param / 24]; + for (uint8_t i = param / 24; i<4; ++i){ + tmp[i] = tmp[i+1]; + } + param = param % 24; + light_color_remap[1] = tmp[(param / 6)]; + for (uint8_t i = param / 6; i<3; ++i){ + tmp[i] = tmp[i+1]; + } + param = param % 6; + light_color_remap[2] = tmp[(param / 2)]; + for (uint8_t i = param / 2; i<2; ++i){ + tmp[i] = tmp[i+1]; + } + param = param % 2; + light_color_remap[3] = tmp[param]; + light_color_remap[4] = tmp[1-param]; + + light_ct_rgb_linked = !(Settings.param[P_RGB_REMAP] & 128); + + light_update = 1; + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%d colors: %d %d %d %d %d") ,Settings.param[P_RGB_REMAP], light_color_remap[0],light_color_remap[1],light_color_remap[2],light_color_remap[3],light_color_remap[4]); } void LightSetColorTemp(uint16_t ct) @@ -437,15 +605,17 @@ void LightSetColorTemp(uint16_t ct) } uint16_t icold = (100 * (347 - my_ct)) / 136; uint16_t iwarm = (100 * my_ct) / 136; - if (PHILIPS == Settings.module) { + if (PHILIPS == my_module_type) { // Xiaomi Philips bulbs follow a different scheme: // channel 0=intensity, channel2=temperature Settings.light_color[1] = (uint8_t)icold; } else if (LST_RGBWC == light_subtype) { - Settings.light_color[0] = 0; - Settings.light_color[1] = 0; - Settings.light_color[2] = 0; + if(light_ct_rgb_linked){ + Settings.light_color[0] = 0; + Settings.light_color[1] = 0; + Settings.light_color[2] = 0; + } Settings.light_color[3] = (uint8_t)icold; Settings.light_color[4] = (uint8_t)iwarm; } else { @@ -473,7 +643,7 @@ void LightSetDimmer(uint8_t myDimmer) { float temp; - if (PHILIPS == Settings.module) { + if (PHILIPS == my_module_type) { // Xiaomi Philips bulbs use two PWM channels with a different scheme: float dimmer = 100 / (float)myDimmer; temp = (float)Settings.light_color[0] / dimmer; // channel 1 is intensity @@ -486,7 +656,7 @@ void LightSetDimmer(uint8_t myDimmer) Settings.light_color[0] = 255; // One PWM channel only supports Dimmer but needs max color } float dimmer = 100 / (float)myDimmer; - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { if (Settings.flag.light_signal) { temp = (float)light_signal_color[i] / dimmer; } else { @@ -500,7 +670,7 @@ void LightSetColor(void) { uint8_t highest = 0; - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { if (highest < light_current_color[i]) { highest = light_current_color[i]; } @@ -508,7 +678,7 @@ void LightSetColor(void) float mDim = (float)highest / 2.55; Settings.light_dimmer = (uint8_t)mDim; float dimmer = 100 / mDim; - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { float temp = (float)light_current_color[i] * dimmer; Settings.light_color[i] = (uint8_t)temp; } @@ -527,8 +697,7 @@ void LightSetSignal(uint16_t lo, uint16_t hi, uint16_t value) signal = 255; } } -// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "Light signal %d"), signal); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Light signal %d"), signal); light_signal_color[0] = signal; light_signal_color[1] = 255 - signal; light_signal_color[2] = 0; @@ -546,7 +715,7 @@ char* LightGetColor(uint8_t type, char* scolor) { LightSetDimmer(Settings.light_dimmer); scolor[0] = '\0'; - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { if (!type && Settings.flag.decimal_text) { snprintf_P(scolor, 25, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", light_current_color[i]); } else { @@ -589,7 +758,7 @@ void LightState(uint8_t append) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_HSBCOLOR "\":\"%d,%d,%d\""), mqtt_data, h,s,b); // Add status for each channel snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_CHANNEL "\":[" ), mqtt_data); - for (byte i = 0; i < light_subtype; i++) { + 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); } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]" ), mqtt_data); @@ -636,7 +805,7 @@ void LightPreparePower(void) void LightFade(void) { if (0 == Settings.light_fade) { - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { light_new_color[i] = light_current_color[i]; } } else { @@ -645,7 +814,7 @@ void LightFade(void) shift = (strip_timer_counter % (Settings.light_speed -6)) ? 0 : 8; } if (shift) { - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { if (light_new_color[i] != light_current_color[i]) { if (light_new_color[i] < light_current_color[i]) { light_new_color[i] += ((light_current_color[i] - light_new_color[i]) >> shift) +1; @@ -680,7 +849,7 @@ void LightWheel(uint8_t wheel_pos) light_entry_color[3] = 0; light_entry_color[4] = 0; float dimmer = 100 / (float)Settings.light_dimmer; - for (byte i = 0; i < LST_RGB; i++) { + for (uint8_t i = 0; i < LST_RGB; i++) { float temp = (float)light_entry_color[i] / dimmer; light_entry_color[i] = (uint8_t)temp; } @@ -699,7 +868,7 @@ void LightCycleColor(int8_t direction) void LightRandomColor(void) { uint8_t light_update = 0; - for (byte i = 0; i < LST_RGB; i++) { + for (uint8_t i = 0; i < LST_RGB; i++) { if (light_new_color[i] != light_current_color[i]) { light_update = 1; } @@ -715,11 +884,12 @@ void LightRandomColor(void) void LightSetPower(void) { // light_power = XdrvMailbox.index; + light_old_power = light_power; light_power = bitRead(XdrvMailbox.index, light_device -1); if (light_wakeup_active) { light_wakeup_active--; } - if (light_power) { + if (light_power && !light_old_power) { light_update = 1; } LightAnimate(); @@ -734,7 +904,7 @@ void LightAnimate(void) if (!light_power) { // Power Off sleep = Settings.sleep; strip_timer_counter = 0; - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { light_still_on += light_new_color[i]; } if (light_still_on && Settings.light_fade && (Settings.light_scheme < LS_MAX)) { @@ -742,19 +912,23 @@ void LightAnimate(void) if (speed > 6) { speed = 6; } - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { if (light_new_color[i] > 0) { light_new_color[i] -= (light_new_color[i] >> speed) +1; } } } else { - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { light_new_color[i] = 0; } } } else { +#ifdef PWM_LIGHTSCHEME0_IGNORE_SLEEP + sleep = (LS_POWER == Settings.light_scheme) ? Settings.sleep : 0; // If no animation then use sleep as is +#else sleep = 0; +#endif // PWM_LIGHTSCHEME0_IGNORE_SLEEP switch (Settings.light_scheme) { case LS_POWER: LightSetDimmer(Settings.light_dimmer); @@ -763,7 +937,7 @@ void LightAnimate(void) case LS_WAKEUP: if (2 == light_wakeup_active) { light_wakeup_active = 1; - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { light_new_color[i] = 0; } light_wakeup_counter = 0; @@ -775,7 +949,7 @@ void LightAnimate(void) light_wakeup_dimmer++; if (light_wakeup_dimmer <= Settings.light_dimmer) { LightSetDimmer(light_wakeup_dimmer); - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { light_new_color[i] = light_current_color[i]; } } else { @@ -805,30 +979,40 @@ void LightAnimate(void) } if ((Settings.light_scheme < LS_MAX) || !light_power) { - for (byte i = 0; i < light_subtype; i++) { - if (light_last_color[i] != light_new_color[i]) { + if (memcmp(light_last_color, light_new_color, light_subtype)) { light_update = 1; - } } if (light_update) { light_update = 0; - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { light_last_color[i] = light_new_color[i]; cur_col[i] = light_last_color[i]*Settings.rgbwwTable[i]/255; cur_col[i] = (Settings.light_correction) ? ledTable[cur_col[i]] : cur_col[i]; + } + + // color remapping + uint8_t orig_col[5]; + memcpy(orig_col, cur_col, sizeof(orig_col)); + for (uint8_t i = 0; i < 5; i++) { + cur_col[i] = orig_col[light_color_remap[i]]; + } + + for (uint8_t i = 0; i < light_subtype; i++) { if (light_type < LT_PWM6) { if (pin[GPIO_PWM1 +i] < 99) { if (cur_col[i] > 0xFC) { cur_col[i] = 0xFC; // Fix unwanted blinking and PWM watchdog errors for values close to pwm_range (H801, Arilux and BN-SZ01) } uint16_t curcol = cur_col[i] * (Settings.pwm_range / 255); -// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "Cur_Col%d %d, CurCol %d"), i, cur_col[i], curcol); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d %d, CurCol %d"), i, cur_col[i], curcol); analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - curcol : curcol); } } } - XdrvMailbox.index = light_device; + + char *tmp_data = XdrvMailbox.data; + uint16_t tmp_data_len = XdrvMailbox.data_len; + XdrvMailbox.data = (char*)cur_col; XdrvMailbox.data_len = sizeof(cur_col); if (XdrvCall(FUNC_SET_CHANNELS)) { @@ -839,9 +1023,28 @@ void LightAnimate(void) Ws2812SetColor(0, cur_col[0], cur_col[1], cur_col[2], cur_col[3]); } #endif // USE_ES2812 ************************************************************************ +#ifdef USE_SM16716 + else if (LT_SM16716 == light_type - light_subtype) { + // handle any PWM pins, skipping the first 3 values for sm16716 + for (uint8_t i = 3; i < light_subtype; i++) { + if (pin[GPIO_PWM1 +i-3] < 99) { + if (cur_col[i] > 0xFC) { + cur_col[i] = 0xFC; // Fix unwanted blinking and PWM watchdog errors for values close to pwm_range (H801, Arilux and BN-SZ01) + } + uint16_t curcol = cur_col[i] * (Settings.pwm_range / 255); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d %d, CurCol %d"), i, cur_col[i], curcol); + analogWrite(pin[GPIO_PWM1 +i-3], bitRead(pwm_inverted, i-3) ? Settings.pwm_range - curcol : curcol); + } + } + // handle sm16716 update + SM16716_Update(cur_col[0], cur_col[1], cur_col[2]); + } +#endif // ifdef USE_SM16716 else if (light_type > LT_WS2812) { LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]); } + XdrvMailbox.data = tmp_data; + XdrvMailbox.data_len = tmp_data_len; } } } @@ -947,8 +1150,10 @@ void LightHsbToRgb(void) light_current_color[0] = (uint8_t)(r * 255.0f); light_current_color[1] = (uint8_t)(g * 255.0f); light_current_color[2] = (uint8_t)(b * 255.0f); - light_current_color[3] = 0; - light_current_color[4] = 0; + if(light_ct_rgb_linked){ + light_current_color[3] = 0; + light_current_color[4] = 0; + } } /********************************************************************************************/ @@ -1005,7 +1210,7 @@ void LightSetHsb(float hue, float sat, float bri, uint16_t ct, bool gotct) * Commands \*********************************************************************************************/ -boolean LightColorEntry(char *buffer, uint8_t buffer_length) +bool LightColorEntry(char *buffer, uint8_t buffer_length) { char scolor[10]; char *p; @@ -1041,7 +1246,7 @@ boolean LightColorEntry(char *buffer, uint8_t buffer_length) entry_type = 2; // Decimal } else if (((2 * light_subtype) == buffer_length) || (buffer_length > 3)) { // Hexadecimal entry - for (byte i = 0; i < buffer_length / 2; i++) { + for (uint8_t i = 0; i < tmin((uint)(buffer_length / 2), sizeof(light_entry_color)); i++) { strlcpy(scolor, buffer + (i *2), 3); light_entry_color[i] = (uint8_t)strtol(scolor, &p, 16); } @@ -1074,12 +1279,12 @@ boolean LightColorEntry(char *buffer, uint8_t buffer_length) /********************************************************************************************/ -boolean LightCommand(void) +bool LightCommand(void) { char command [CMDSZ]; - boolean serviced = true; - boolean coldim = false; - boolean valid_entry = false; + bool serviced = true; + bool coldim = false; + bool valid_entry = false; char scolor[25]; char option = (1 == XdrvMailbox.data_len) ? XdrvMailbox.data[0] : '\0'; @@ -1111,7 +1316,7 @@ boolean LightCommand(void) Settings.light_scheme = 0; coldim = true; } else { // Color3, 4, 5 and 6 - for (byte i = 0; i < LST_RGB; i++) { + for (uint8_t i = 0; i < LST_RGB; i++) { Settings.ws_color[XdrvMailbox.index -3][i] = light_entry_color[i]; } } @@ -1122,7 +1327,7 @@ boolean LightCommand(void) } if (XdrvMailbox.index >= 3) { scolor[0] = '\0'; - for (byte i = 0; i < LST_RGB; i++) { + for (uint8_t i = 0; i < LST_RGB; i++) { if (Settings.flag.decimal_text) { snprintf_P(scolor, 25, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", Settings.ws_color[XdrvMailbox.index -3][i]); } else { @@ -1196,7 +1401,7 @@ boolean LightCommand(void) if (LightColorEntry(color, strlen(color))) { Ws2812SetColor(idx, light_entry_color[0], light_entry_color[1], light_entry_color[2], light_entry_color[3]); idx++; - if (idx >= Settings.light_pixels) break; + if (idx > Settings.light_pixels) break; } else { break; } @@ -1319,7 +1524,6 @@ boolean LightCommand(void) bool validtable = (XdrvMailbox.data_len > 0); char scolor[25]; if (validtable) { - uint16_t HSB[3]; if (strstr(XdrvMailbox.data, ",")) { // Command with up to 5 comma separated parameters for (int i = 0; i < LST_RGBWC; i++) { char *substr; @@ -1337,7 +1541,7 @@ boolean LightCommand(void) light_update = 1; } scolor[0] = '\0'; - for (byte i = 0; i < LST_RGBWC; i++) { + 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); @@ -1396,9 +1600,9 @@ boolean LightCommand(void) * Interface \*********************************************************************************************/ -boolean Xdrv04(byte function) +bool Xdrv04(uint8_t function) { - boolean result = false; + bool result = false; if (light_type) { switch (function) { diff --git a/sonoff/xdrv_05_irremote.ino b/sonoff/xdrv_05_irremote.ino index ef02e61ba..a72bc2764 100644 --- a/sonoff/xdrv_05_irremote.ino +++ b/sonoff/xdrv_05_irremote.ino @@ -1,7 +1,7 @@ /* xdrv_05_irremote.ino - infra red support for Sonoff-Tasmota - Copyright (C) 2018 Heiko Krupp, Lazar Obradovic and Theo Arends + Copyright (C) 2019 Heiko Krupp, Lazar Obradovic and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -58,7 +58,7 @@ IRMitsubishiAC *mitsubir = NULL; const char kFanSpeedOptions[] = "A12345S"; const char kHvacModeOptions[] = "HDCA"; -#endif +#endif // USE_IR_HVAC /*********************************************************************************************\ * IR Send @@ -67,6 +67,7 @@ const char kHvacModeOptions[] = "HDCA"; #include IRsend *irsend = NULL; +bool irsend_active = false; void IrSendInit(void) { @@ -113,13 +114,12 @@ void IrReceiveCheck(void) if (irrecv->decode(&results)) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_IRR "RawLen %d, Overflow %d, Bits %d, Value %08X, Decode %d"), - results.rawlen, results.overflow, results.bits, results.value, results.decode_type); - AddLog(LOG_LEVEL_DEBUG); + 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); unsigned long now = millis(); // if ((now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) && (UNKNOWN != results.decode_type) && (results.bits > 0)) { - if (now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) { + if (!irsend_active && (now - ir_lasttime > IR_TIME_AVOID_DUPLICATE)) { ir_lasttime = now; iridx = results.decode_type; @@ -129,7 +129,7 @@ void IrReceiveCheck(void) if (Settings.flag.ir_receive_decimal) { snprintf_P(stemp, sizeof(stemp), PSTR("%u"), (uint32_t)results.value); } else { - snprintf_P(stemp, sizeof(stemp), PSTR("\"%lX\""), (uint32_t)results.value); + snprintf_P(stemp, sizeof(stemp), PSTR("\"0x%lX\""), (uint32_t)results.value); } 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); @@ -181,10 +181,10 @@ void IrReceiveCheck(void) TOSHIBA ********************/ -boolean IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp) +bool 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]; - byte data[HVAC_TOSHIBA_DATALEN] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}; + uint8_t data[HVAC_TOSHIBA_DATALEN] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}; char *p; uint8_t mode; @@ -201,7 +201,7 @@ boolean IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H data[6] = (p - kHvacModeOptions) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00 if (!HVAC_Power) { - data[6] = (byte)0x07; // Turn OFF HVAC + data[6] = (uint8_t)0x07; // Turn OFF HVAC } if (HVAC_FanMode == NULL) { @@ -220,7 +220,7 @@ boolean IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H mode = mode << 5; // AUTO = 0x00, SPEED = 0x40, 0x60, 0x80, 0xA0, 0xC0, SILENT = 0x00 data[6] = data[6] | mode; - byte Temp; + uint8_t Temp; if (HVAC_Temp > 30) { Temp = 30; } @@ -230,15 +230,15 @@ boolean IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H else { Temp = HVAC_Temp; } - data[5] = (byte)(Temp - 17) << 4; + data[5] = (uint8_t)(Temp - 17) << 4; data[HVAC_TOSHIBA_DATALEN - 1] = 0; for (int x = 0; x < HVAC_TOSHIBA_DATALEN - 1; x++) { - data[HVAC_TOSHIBA_DATALEN - 1] = (byte)data[x] ^ data[HVAC_TOSHIBA_DATALEN - 1]; // CRC is a simple bits addition + data[HVAC_TOSHIBA_DATALEN - 1] = (uint8_t)data[x] ^ data[HVAC_TOSHIBA_DATALEN - 1]; // CRC is a simple bits addition } int i = 0; - byte mask = 1; + uint8_t mask = 1; //header rawdata[i++] = HVAC_TOSHIBA_HDR_MARK; @@ -262,10 +262,11 @@ boolean IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H rawdata[i++] = HVAC_TOSHIBA_RPT_MARK; rawdata[i++] = HVAC_TOSHIBA_RPT_SPACE; - noInterrupts(); +// noInterrupts(); + irsend_active = true; irsend->sendRaw(rawdata, i, 38); irsend->sendRaw(rawdata, i, 38); - interrupts(); +// interrupts(); return false; } @@ -275,7 +276,7 @@ boolean IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H MITSUBISHI ********************/ -boolean IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp) +bool IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) { char *p; uint8_t mode; @@ -312,9 +313,8 @@ boolean IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, boolea mitsubir->setVane(MITSUBISHI_AC_VANE_AUTO); mitsubir->send(); -// snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"), +// 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()); -// AddLog(LOG_LEVEL_DEBUG); return false; } @@ -324,14 +324,14 @@ boolean IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, boolea LG ********************/ -boolean IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp) +bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) { uint32_t LG_Code; - byte data[HVAC_LG_DATALEN]; - static boolean hvacOn = false; + uint8_t data[HVAC_LG_DATALEN]; + static bool hvacOn = false; char *p; uint8_t mode; - byte Temp; + uint8_t Temp; // Constant data data[0] = 0x08; @@ -339,11 +339,11 @@ boolean IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_P data[2] = 0x00; if (!HVAC_Power) { - data[2] = (byte)0x0C; // Turn OFF HVAC, code 0x88C0051 - data[3] = (byte)0x00; - data[4] = (byte)0x00; - data[5] = (byte)0x05; - data[6] = (byte)0x01; + data[2] = (uint8_t)0x0C; // Turn OFF HVAC, code 0x88C0051 + data[3] = (uint8_t)0x00; + data[4] = (uint8_t)0x00; + data[5] = (uint8_t)0x05; + data[6] = (uint8_t)0x01; hvacOn = false; } @@ -379,8 +379,7 @@ boolean IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_P hvacOn = true; } -// snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: HvacMode %s, ModeVal %d, Code %d"), p, mode, data[3]); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: HvacMode %s, ModeVal %d, Code %d"), p, mode, data[3]); // Set code for HVAC temperature - data[4] if (HVAC_Temp > 30) { @@ -392,7 +391,7 @@ boolean IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_P else { Temp = HVAC_Temp; } - data[4] = (byte)(Temp - 15); + data[4] = (uint8_t)(Temp - 15); // Set code for HVAC fan mode - data[5] if (HVAC_FanMode == NULL) { @@ -412,8 +411,7 @@ boolean IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_P data[5] = (mode * 2) - 2; // Low = 0x00, Mid = 0x02, High = 0x04 } -// snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: FanMode %s, ModeVal %d, Code %d"), p, mode, data[5]); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: FanMode %s, ModeVal %d, Code %d"), p, mode, data[5]); // Set CRC code - data[6] data[6] = (data[3] + data[4] + data[5]) & 0x0f; // CRC @@ -426,13 +424,13 @@ boolean IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_P } LG_Code = LG_Code + data[6]; -// snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: LG_Code %d"), LG_Code); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: LG_Code %d"), LG_Code); // Send LG IR Code - noInterrupts(); +// noInterrupts(); + irsend_active = true; irsend->sendLG(LG_Code, 28); - interrupts(); +// interrupts(); return false; } @@ -442,23 +440,24 @@ boolean IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_P Fujitsu ********************/ -boolean IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp) +bool IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) { const char kFujitsuHvacModeOptions[] = "HDCAF"; -// snprintf_P(log_data, sizeof(log_data), PSTR("FUJITSU: mode:%s, fan:%s, power:%u, temp:%u"), HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("FUJITSU: mode:%s, fan:%s, power:%u, temp:%u"), HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); IRFujitsuAC ac(pin[GPIO_IRSEND]); + irsend_active = true; + if (0 == HVAC_Power) { ac.off(); ac.send(); return false; } - byte modes[5] = {FUJITSU_AC_MODE_HEAT, FUJITSU_AC_MODE_DRY, FUJITSU_AC_MODE_COOL, FUJITSU_AC_MODE_AUTO, FUJITSU_AC_MODE_FAN}; - byte fanModes[7] = {FUJITSU_AC_FAN_AUTO, FUJITSU_AC_FAN_LOW, FUJITSU_AC_FAN_MED, FUJITSU_AC_FAN_HIGH, FUJITSU_AC_FAN_HIGH, FUJITSU_AC_FAN_HIGH, FUJITSU_AC_FAN_QUIET}; + uint8_t modes[5] = {FUJITSU_AC_MODE_HEAT, FUJITSU_AC_MODE_DRY, FUJITSU_AC_MODE_COOL, FUJITSU_AC_MODE_AUTO, FUJITSU_AC_MODE_FAN}; + uint8_t fanModes[7] = {FUJITSU_AC_FAN_AUTO, FUJITSU_AC_FAN_LOW, FUJITSU_AC_FAN_MED, FUJITSU_AC_FAN_HIGH, FUJITSU_AC_FAN_HIGH, FUJITSU_AC_FAN_HIGH, FUJITSU_AC_FAN_QUIET}; ac.setCmd(FUJITSU_AC_CMD_TURN_ON); ac.setSwing(FUJITSU_AC_SWING_VERT); @@ -505,11 +504,11 @@ boolean IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H { "Vendor": "", "Power": <0|1>, "Mode": "", "FanSpeed": "<1|2|3|4|5|Auto|Silence>", "Temp": <17..30> } */ -boolean IrSendCommand(void) +bool IrSendCommand(void) { char command [CMDSZ]; - boolean serviced = true; - boolean error = false; + bool serviced = true; + bool error = false; int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kIrRemoteCommands); if (-1 == command_code) { @@ -531,15 +530,14 @@ boolean IrSendCommand(void) 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) - byte i = 0; + 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 } -// snprintf_P(log_data, sizeof(log_data), PSTR("IRS: Count %d, Freq %d, Arr[0] %d, Arr[count -1] %d"), -// count, freq, raw_array[0], raw_array[count -1]); -// AddLog(LOG_LEVEL_DEBUG); +// 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); @@ -567,10 +565,10 @@ boolean IrSendCommand(void) char protocol_text[20]; int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols); - snprintf_P(log_data, sizeof(log_data), PSTR("IRS: protocol_text %s, protocol %s, bits %d, data %u (0x%lX), protocol_code %d"), + 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); - AddLog(LOG_LEVEL_DEBUG); + irsend_active = true; switch (protocol_code) { case NEC: irsend->sendNEC(data, (bits > NEC_BITS) ? NEC_BITS : bits); break; @@ -589,6 +587,7 @@ boolean IrSendCommand(void) 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); } } @@ -611,7 +610,7 @@ boolean IrSendCommand(void) const char *HVAC_FanMode; const char *HVAC_Vendor; int HVAC_Temp = 21; - boolean HVAC_Power = true; + bool HVAC_Power = true; if (XdrvMailbox.data_len) { char dataBufUc[XdrvMailbox.data_len]; @@ -629,9 +628,7 @@ boolean IrSendCommand(void) HVAC_FanMode = root[D_JSON_IRHVAC_FANSPEED]; HVAC_Temp = root[D_JSON_IRHVAC_TEMP]; -// snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"), -// HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp); -// AddLog(LOG_LEVEL_DEBUG); +// 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); @@ -666,9 +663,9 @@ boolean IrSendCommand(void) * Interface \*********************************************************************************************/ -boolean Xdrv05(byte function) +bool Xdrv05(uint8_t function) { - boolean result = false; + bool result = false; if ((pin[GPIO_IRSEND] < 99) || (pin[GPIO_IRRECV] < 99)) { switch (function) { @@ -688,6 +685,7 @@ boolean Xdrv05(byte function) IrReceiveCheck(); // check if there's anything on IR side } #endif // USE_IR_RECEIVE + irsend_active = false; // re-enable IR reception break; case FUNC_COMMAND: if (pin[GPIO_IRSEND] < 99) { diff --git a/sonoff/xdrv_06_snfbridge.ino b/sonoff/xdrv_06_snfbridge.ino index 30bd6e4f0..c4b4d209b 100644 --- a/sonoff/xdrv_06_snfbridge.ino +++ b/sonoff/xdrv_06_snfbridge.ino @@ -1,7 +1,7 @@ /* xdrv_06_snfbridge.ino - sonoff RF bridge 433 support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends and Erik Andrén Zachrisson (fw update) + Copyright (C) 2019 Theo Arends and Erik Andrén Zachrisson (fw update) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -56,7 +56,7 @@ unsigned long sonoff_bridge_last_learn_time = 0; ssize_t rf_find_hex_record_start(uint8_t *buf, size_t size) { - for (int i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { if (buf[i] == ':') { return i; } @@ -66,7 +66,7 @@ ssize_t rf_find_hex_record_start(uint8_t *buf, size_t size) ssize_t rf_find_hex_record_end(uint8_t *buf, size_t size) { - for (ssize_t i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { if (buf[i] == '\n') { return i; } @@ -251,7 +251,7 @@ void SonoffBridgeReceived(void) low_time = serial_in_buffer[3] << 8 | serial_in_buffer[4]; // Low time in uSec high_time = serial_in_buffer[5] << 8 | serial_in_buffer[6]; // High time in uSec if (low_time && high_time) { - for (byte i = 0; i < 9; i++) { + 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); @@ -274,7 +274,7 @@ void SonoffBridgeReceived(void) sonoff_bridge_last_received_id = received_id; sonoff_bridge_last_time = now; strncpy_P(rfkey, PSTR("\"" D_JSON_NONE "\""), sizeof(rfkey)); - for (byte i = 1; i <= 16; i++) { + for (uint8_t i = 1; i <= 16; i++) { if (Settings.rf_code[i][0]) { uint32_t send_id = Settings.rf_code[i][6] << 16 | Settings.rf_code[i][7] << 8 | Settings.rf_code[i][8]; if (send_id == received_id) { @@ -300,7 +300,7 @@ void SonoffBridgeReceived(void) } } -boolean SonoffBridgeSerialInput(void) +bool SonoffBridgeSerialInput(void) { // iTead Rf Universal Transceiver Module Serial Protocol Version 1.0 (20170420) static int8_t receive_len = 0; @@ -352,7 +352,7 @@ boolean SonoffBridgeSerialInput(void) return 0; } -void SonoffBridgeSendCommand(byte code) +void SonoffBridgeSendCommand(uint8_t code) { Serial.write(0xAA); // Start of Text Serial.write(code); // Command or Acknowledge @@ -370,7 +370,7 @@ void SonoffBridgeSendCode(uint32_t code) { Serial.write(0xAA); // Start of Text Serial.write(0xA5); // Send following code - for (byte i = 0; i < 6; i++) { + for (uint8_t i = 0; i < 6; i++) { Serial.write(Settings.rf_code[0][i]); } Serial.write((code >> 16) & 0xff); @@ -387,7 +387,7 @@ void SonoffBridgeSend(uint8_t idx, uint8_t key) key--; // Support 1 to 16 Serial.write(0xAA); // Start of Text Serial.write(0xA5); // Send following code - for (byte i = 0; i < 8; i++) { + for (uint8_t i = 0; i < 8; i++) { Serial.write(Settings.rf_code[idx][i]); } if (0 == idx) { @@ -418,10 +418,10 @@ void SonoffBridgeLearn(uint8_t key) * Commands \*********************************************************************************************/ -boolean SonoffBridgeCommand(void) +bool SonoffBridgeCommand(void) { char command [CMDSZ]; - boolean serviced = true; + bool serviced = true; int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kSonoffBridgeCommands); if (-1 == command_code) { @@ -485,7 +485,7 @@ boolean SonoffBridgeCommand(void) snprintf_P(mqtt_data, sizeof(mqtt_data), 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 (byte i = 0; i < 6; i++) { + for (uint8_t i = 0; i < 6; i++) { Settings.rf_code[XdrvMailbox.index][i] = Settings.rf_code[0][i]; } Settings.rf_code[XdrvMailbox.index][6] = (sonoff_bridge_last_send_code >> 16) & 0xff; @@ -566,11 +566,11 @@ void SonoffBridgeInit(void) * Interface \*********************************************************************************************/ -boolean Xdrv06(byte function) +bool Xdrv06(uint8_t function) { - boolean result = false; + bool result = false; - if (SONOFF_BRIDGE == Settings.module) { + if (SONOFF_BRIDGE == my_module_type) { switch (function) { case FUNC_INIT: SonoffBridgeInit(); diff --git a/sonoff/xdrv_07_domoticz.ino b/sonoff/xdrv_07_domoticz.ino index 3eb3fa275..0bd275d7c 100644 --- a/sonoff/xdrv_07_domoticz.ino +++ b/sonoff/xdrv_07_domoticz.ino @@ -1,7 +1,7 @@ /* xdrv_07_domoticz.ino - domoticz support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,8 +41,8 @@ const char S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE[] PROGMEM = "{\"" D_CMND_DOMOTIC char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC; char domoticz_out_topic[] = DOMOTICZ_OUT_TOPIC; -boolean domoticz_subscribe = false; -byte domoticz_update_flag = 1; +bool domoticz_subscribe = false; +uint8_t domoticz_update_flag = 1; int domoticz_update_timer = 0; unsigned long fan_debounce = 0; // iFan02 state debounce timer @@ -80,7 +80,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, - Settings.domoticz_relay_idx[1], (0 == fan_speed) ? 0 : 2, svalue, DomoticzBatteryQuality(), DomoticzRssiQuality()); + (int)Settings.domoticz_relay_idx[1], (0 == fan_speed) ? 0 : 2, svalue, DomoticzBatteryQuality(), DomoticzRssiQuality()); MqttPublish(domoticz_in_topic); fan_debounce = millis(); @@ -95,26 +95,26 @@ void DomoticzUpdateFanState() domoticz_update_flag = 1; } -void MqttPublishDomoticzPowerState(byte device) +void MqttPublishDomoticzPowerState(uint8_t device) { if (Settings.flag.mqtt_enabled) { if ((device < 1) || (device > devices_present)) { device = 1; } if (Settings.domoticz_relay_idx[device -1]) { - if ((SONOFF_IFAN02 == Settings.module) && (device > 1)) { + if ((SONOFF_IFAN02 == my_module_type) && (device > 1)) { // Fan handled by MqttPublishDomoticzFanState } else { char svalue[8]; // Dimmer value snprintf_P(svalue, sizeof(svalue), PSTR("%d"), Settings.light_dimmer); snprintf_P(mqtt_data, sizeof(mqtt_data), DOMOTICZ_MESSAGE, - Settings.domoticz_relay_idx[device -1], (power & (1 << (device -1))) ? 1 : 0, (light_type) ? svalue : "", DomoticzBatteryQuality(), DomoticzRssiQuality()); + (int)Settings.domoticz_relay_idx[device -1], (power & (1 << (device -1))) ? 1 : 0, (light_type) ? svalue : "", DomoticzBatteryQuality(), DomoticzRssiQuality()); MqttPublish(domoticz_in_topic); } } } } -void DomoticzUpdatePowerState(byte device) +void DomoticzUpdatePowerState(uint8_t device) { if (domoticz_update_flag) { MqttPublishDomoticzPowerState(device); @@ -128,8 +128,8 @@ void DomoticzMqttUpdate(void) domoticz_update_timer--; if (domoticz_update_timer <= 0) { domoticz_update_timer = Settings.domoticz_update_timer; - for (byte i = 1; i <= devices_present; i++) { - if ((SONOFF_IFAN02 == Settings.module) && (i > 1)) { + for (uint8_t i = 1; i <= devices_present; i++) { + if ((SONOFF_IFAN02 == my_module_type) && (i > 1)) { MqttPublishDomoticzFanState(); break; } else { @@ -143,7 +143,7 @@ void DomoticzMqttUpdate(void) void DomoticzMqttSubscribe(void) { uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present; - for (byte i = 0; i < maxdev; i++) { + for (uint8_t i = 0; i < maxdev; i++) { if (Settings.domoticz_relay_idx[i]) { domoticz_subscribe = true; } @@ -181,7 +181,7 @@ void DomoticzMqttSubscribe(void) } */ -boolean DomoticzMqttData(void) +bool DomoticzMqttData(void) { char stemp1[10]; unsigned long idx = 0; @@ -206,16 +206,15 @@ boolean DomoticzMqttData(void) nvalue = domoticz["nvalue"]; } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue); - AddLog(LOG_LEVEL_DEBUG_MORE); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue); if ((idx > 0) && (nvalue >= 0) && (nvalue <= 15)) { uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present; - for (byte i = 0; i < maxdev; i++) { + for (uint8_t i = 0; i < maxdev; i++) { if (idx == Settings.domoticz_relay_idx[i]) { bool iscolordimmer = strcmp_P(domoticz["dtype"],PSTR("Color Switch")) == 0; snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1); - if ((SONOFF_IFAN02 == Settings.module) && (1 == i)) { // Idx 2 is fanspeed + if ((SONOFF_IFAN02 == my_module_type) && (1 == i)) { // Idx 2 is fanspeed uint8_t svalue = 0; if (domoticz.containsKey("svalue1")) { svalue = domoticz["svalue1"]; @@ -275,8 +274,7 @@ boolean DomoticzMqttData(void) return 1; } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DOMOTICZ D_RECEIVED_TOPIC " %s, " D_DATA " %s"), XdrvMailbox.topic, XdrvMailbox.data); - AddLog(LOG_LEVEL_DEBUG_MORE); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ D_RECEIVED_TOPIC " %s, " D_DATA " %s"), XdrvMailbox.topic, XdrvMailbox.data); domoticz_update_flag = 0; } @@ -287,10 +285,10 @@ boolean DomoticzMqttData(void) * Commands \*********************************************************************************************/ -boolean DomoticzCommand(void) +bool DomoticzCommand(void) { char command [CMDSZ]; - boolean serviced = true; + bool serviced = true; uint8_t dmtcz_len = strlen(D_CMND_DOMOTICZ); // Prep for string length change if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_DOMOTICZ), dmtcz_len)) { // Prefix @@ -336,9 +334,9 @@ boolean DomoticzCommand(void) return serviced; } -boolean DomoticzSendKey(byte key, byte device, byte state, byte svalflg) +bool DomoticzSendKey(uint8_t key, uint8_t device, uint8_t state, uint8_t svalflg) { - boolean result = 0; + bool result = 0; if (device <= MAX_DOMOTICZ_IDX) { if ((Settings.domoticz_key_idx[device -1] || Settings.domoticz_switch_idx[device -1]) && (svalflg)) { @@ -374,7 +372,7 @@ uint8_t DomoticzHumidityState(char *hum) return (!h) ? 0 : (h < 40) ? 2 : (h > 70) ? 3 : 1; } -void DomoticzSensor(byte idx, char *data) +void DomoticzSensor(uint8_t idx, char *data) { if (Settings.domoticz_sensor_idx[idx]) { char dmess[90]; @@ -392,7 +390,7 @@ void DomoticzSensor(byte idx, char *data) } } -void DomoticzSensor(byte idx, uint32_t value) +void DomoticzSensor(uint8_t idx, uint32_t value) { char data[16]; snprintf_P(data, sizeof(data), PSTR("%d"), value); @@ -431,25 +429,27 @@ void DomoticzSensorPowerEnergy(int power, char *energy) const char S_CONFIGURE_DOMOTICZ[] PROGMEM = D_CONFIGURE_DOMOTICZ; const char HTTP_BTN_MENU_DOMOTICZ[] PROGMEM = - "
"; + "

"; const char HTTP_FORM_DOMOTICZ[] PROGMEM = - "
 " D_DOMOTICZ_PARAMETERS " 
" - "
"; + "
 " D_DOMOTICZ_PARAMETERS " " + "" + "
" + "
"; const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = - "" - ""; + "" + ""; const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM = - ""; + ""; const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM = - ""; + ""; const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = - ""; + ""; void HandleDomoticzConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ); if (WebServer->hasArg("save")) { @@ -460,35 +460,30 @@ void HandleDomoticzConfiguration(void) char stemp[32]; - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_DOMOTICZ)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_DOMOTICZ); + WSContentStart_P(S_CONFIGURE_DOMOTICZ); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_DOMOTICZ); for (int i = 0; i < MAX_DOMOTICZ_IDX; i++) { if (i < devices_present) { - page += FPSTR(HTTP_FORM_DOMOTICZ_RELAY); - page.replace("{2", String((int)Settings.domoticz_relay_idx[i])); - page.replace("{3", String((int)Settings.domoticz_key_idx[i])); + WSContentSend_P(HTTP_FORM_DOMOTICZ_RELAY, + i +1, i, i, Settings.domoticz_relay_idx[i], + i +1, i, i, Settings.domoticz_key_idx[i]); } if (pin[GPIO_SWT1 +i] < 99) { - page += FPSTR(HTTP_FORM_DOMOTICZ_SWITCH); - page.replace("{4", String((int)Settings.domoticz_switch_idx[i])); + WSContentSend_P(HTTP_FORM_DOMOTICZ_SWITCH, + i +1, i, i, Settings.domoticz_switch_idx[i]); } - page.replace("{1", String(i +1)); - if ((SONOFF_IFAN02 == Settings.module) && (1 == i)) { break; } + if ((SONOFF_IFAN02 == my_module_type) && (1 == i)) { break; } } for (int i = 0; i < DZ_MAX_SENSORS; i++) { - page += FPSTR(HTTP_FORM_DOMOTICZ_SENSOR); - page.replace("{1", String(i +1)); - page.replace("{2", GetTextIndexed(stemp, sizeof(stemp), i, kDomoticzSensors)); - page.replace("{5", String((int)Settings.domoticz_sensor_idx[i])); + WSContentSend_P(HTTP_FORM_DOMOTICZ_SENSOR, + i +1, GetTextIndexed(stemp, sizeof(stemp), i, kDomoticzSensors), i, i, Settings.domoticz_sensor_idx[i]); } - page += FPSTR(HTTP_FORM_DOMOTICZ_TIMER); - page.replace("{6", String((int)Settings.domoticz_update_timer)); - page += F("
" D_DOMOTICZ_IDX " {1
" D_DOMOTICZ_KEY_IDX " {1
" D_DOMOTICZ_IDX " %d
" D_DOMOTICZ_KEY_IDX " %d
" D_DOMOTICZ_SWITCH_IDX " {1
" D_DOMOTICZ_SWITCH_IDX " %d
" D_DOMOTICZ_SENSOR_IDX " {1 {2
" D_DOMOTICZ_SENSOR_IDX " %d %s
" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")
" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")
"); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentSend_P(HTTP_FORM_DOMOTICZ_TIMER, Settings.domoticz_update_timer); + WSContentSend_P(PSTR("")); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); } void DomoticzSaveSettings(void) @@ -497,20 +492,20 @@ void DomoticzSaveSettings(void) char ssensor_indices[6 * MAX_DOMOTICZ_SNS_IDX]; char tmp[100]; - for (byte i = 0; i < MAX_DOMOTICZ_IDX; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i +1); + for (uint8_t i = 0; i < MAX_DOMOTICZ_IDX; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i); WebGetArg(stemp, tmp, sizeof(tmp)); Settings.domoticz_relay_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i +1); + snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i); WebGetArg(stemp, tmp, sizeof(tmp)); Settings.domoticz_key_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i +1); + snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i); WebGetArg(stemp, tmp, sizeof(tmp)); Settings.domoticz_switch_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); } ssensor_indices[0] = '\0'; - for (byte i = 0; i < DZ_MAX_SENSORS; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i +1); + for (uint8_t i = 0; i < DZ_MAX_SENSORS; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i); WebGetArg(stemp, tmp, sizeof(tmp)); Settings.domoticz_sensor_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); snprintf_P(ssensor_indices, sizeof(ssensor_indices), PSTR("%s%s%d"), ssensor_indices, (strlen(ssensor_indices)) ? "," : "", Settings.domoticz_sensor_idx[i]); @@ -518,12 +513,11 @@ void DomoticzSaveSettings(void) WebGetArg("ut", tmp, sizeof(tmp)); Settings.domoticz_update_timer = (!strlen(tmp)) ? DOMOTICZ_UPDATE_TIMER : atoi(tmp); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DOMOTICZ D_CMND_IDX " %d,%d,%d,%d, " D_CMND_KEYIDX " %d,%d,%d,%d, " D_CMND_SWITCHIDX " %d,%d,%d,%d, " D_CMND_SENSORIDX " %s, " D_CMND_UPDATETIMER " %d"), + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_DOMOTICZ D_CMND_IDX " %d,%d,%d,%d, " D_CMND_KEYIDX " %d,%d,%d,%d, " D_CMND_SWITCHIDX " %d,%d,%d,%d, " D_CMND_SENSORIDX " %s, " D_CMND_UPDATETIMER " %d"), Settings.domoticz_relay_idx[0], Settings.domoticz_relay_idx[1], Settings.domoticz_relay_idx[2], Settings.domoticz_relay_idx[3], Settings.domoticz_key_idx[0], Settings.domoticz_key_idx[1], Settings.domoticz_key_idx[2], Settings.domoticz_key_idx[3], Settings.domoticz_switch_idx[0], Settings.domoticz_switch_idx[1], Settings.domoticz_switch_idx[2], Settings.domoticz_switch_idx[3], ssensor_indices, Settings.domoticz_update_timer); - AddLog(LOG_LEVEL_INFO); } #endif // USE_WEBSERVER @@ -531,15 +525,15 @@ void DomoticzSaveSettings(void) * Interface \*********************************************************************************************/ -boolean Xdrv07(byte function) +bool Xdrv07(uint8_t function) { - boolean result = false; + bool result = false; if (Settings.flag.mqtt_enabled) { switch (function) { #ifdef USE_WEBSERVER case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_DOMOTICZ, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend_P(HTTP_BTN_MENU_DOMOTICZ); break; case FUNC_WEB_ADD_HANDLER: WebServer->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration); diff --git a/sonoff/xdrv_08_serial_bridge.ino b/sonoff/xdrv_08_serial_bridge.ino index e901e9958..d39e7a6eb 100644 --- a/sonoff/xdrv_08_serial_bridge.ino +++ b/sonoff/xdrv_08_serial_bridge.ino @@ -1,7 +1,7 @@ /* xdrv_08_serial_bridge.ino - serial bridge support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends and Dániel Zoltán Tolnai + Copyright (C) 2019 Theo Arends and Dániel Zoltán Tolnai This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,12 +31,13 @@ enum SerialBridgeCommands { CMND_SSERIALSEND, CMND_SBAUDRATE }; const char kSerialBridgeCommands[] PROGMEM = D_CMND_SSERIALSEND "|" D_CMND_SBAUDRATE; -TasmotaSerial *SerialBridgeSerial; +TasmotaSerial *SerialBridgeSerial = NULL; -uint8_t serial_bridge_active = 1; -uint8_t serial_bridge_in_byte_counter = 0; unsigned long serial_bridge_polling_window = 0; char *serial_bridge_buffer = NULL; +int serial_bridge_in_byte_counter = 0; +bool serial_bridge_active = true; +bool serial_bridge_raw = false; void SerialBridgeInput(void) { @@ -44,25 +45,37 @@ void SerialBridgeInput(void) yield(); uint8_t serial_in_byte = SerialBridgeSerial->read(); - if (serial_in_byte > 127) { // binary data... + if ((serial_in_byte > 127) && !serial_bridge_raw) { // Discard binary data above 127 if no raw reception allowed serial_bridge_in_byte_counter = 0; SerialBridgeSerial->flush(); return; } - if (serial_in_byte) { - if ((serial_in_byte_counter < SERIAL_BRIDGE_BUFFER_SIZE -1) && (serial_in_byte != Settings.serial_delimiter)) { // add char to string if it still fits + if (serial_in_byte || serial_bridge_raw) { // Any char between 1 and 127 or any char (0 - 255) + + if ((serial_bridge_in_byte_counter < SERIAL_BRIDGE_BUFFER_SIZE -1) && // Add char to string if it still fits and ... + ((isprint(serial_in_byte) && (128 == Settings.serial_delimiter)) || // Any char between 32 and 127 + (serial_in_byte != Settings.serial_delimiter) || // Any char between 1 and 127 and not being delimiter + serial_bridge_raw)) { // Any char between 0 and 255 serial_bridge_buffer[serial_bridge_in_byte_counter++] = serial_in_byte; - serial_bridge_polling_window = millis(); // Wait for more data + serial_bridge_polling_window = millis(); // Wait for more data } else { - serial_bridge_polling_window = 0; // Publish now + serial_bridge_polling_window = 0; // Publish now break; } } } 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 - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SSERIALRECEIVED "\":\"%s\"}"), serial_bridge_buffer); + 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); + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), 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]); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"}"), mqtt_data); + } MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED)); // XdrvRulesProcess(); serial_bridge_in_byte_counter = 0; @@ -73,15 +86,18 @@ void SerialBridgeInput(void) void SerialBridgeInit(void) { - serial_bridge_active = 0; + serial_bridge_active = false; if ((pin[GPIO_SBR_RX] < 99) && (pin[GPIO_SBR_TX] < 99)) { - serial_bridge_buffer = (char*)(malloc(SERIAL_BRIDGE_BUFFER_SIZE)); - if (serial_bridge_buffer != NULL) { - SerialBridgeSerial = new TasmotaSerial(pin[GPIO_SBR_RX], pin[GPIO_SBR_TX]); - if (SerialBridgeSerial->begin(Settings.sbaudrate * 1200)) { // Baud rate is stored div 1200 so it fits into one byte - serial_bridge_active = 1; - SerialBridgeSerial->flush(); + SerialBridgeSerial = new TasmotaSerial(pin[GPIO_SBR_RX], pin[GPIO_SBR_TX]); + if (SerialBridgeSerial->begin(Settings.sbaudrate * 1200)) { // Baud rate is stored div 1200 so it fits into one byte + if (SerialBridgeSerial->hardwareSerial()) { + ClaimSerial(); + serial_bridge_buffer = serial_in_buffer; // Use idle serial buffer to save RAM + } else { + serial_bridge_buffer = (char*)(malloc(SERIAL_BRIDGE_BUFFER_SIZE)); } + serial_bridge_active = true; + SerialBridgeSerial->flush(); } } } @@ -90,39 +106,56 @@ void SerialBridgeInit(void) * Commands \*********************************************************************************************/ -boolean SerialBridgeCommand(void) +bool SerialBridgeCommand(void) { char command [CMDSZ]; - boolean serviced = true; + bool serviced = true; int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kSerialBridgeCommands); if (-1 == command_code) { serviced = false; // Unknown command } - else if ((CMND_SSERIALSEND == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 3)) { + else if ((CMND_SSERIALSEND == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) { + serial_bridge_raw = (XdrvMailbox.index > 3); if (XdrvMailbox.data_len > 0) { if (1 == XdrvMailbox.index) { - SerialBridgeSerial->write(XdrvMailbox.data, XdrvMailbox.data_len); - SerialBridgeSerial->write("\n"); + SerialBridgeSerial->write(XdrvMailbox.data, XdrvMailbox.data_len); // "Hello Tiger" + SerialBridgeSerial->write("\n"); // "\n" } - else if (2 == XdrvMailbox.index) { - SerialBridgeSerial->write(XdrvMailbox.data, XdrvMailbox.data_len); + else if ((2 == XdrvMailbox.index) || (4 == XdrvMailbox.index)) { + SerialBridgeSerial->write(XdrvMailbox.data, XdrvMailbox.data_len); // "Hello Tiger" or "A0" } - else if (3 == XdrvMailbox.index) { + else if (3 == XdrvMailbox.index) { // "Hello\f" SerialBridgeSerial->write(Unescape(XdrvMailbox.data, &XdrvMailbox.data_len), XdrvMailbox.data_len); } + else if (5 == XdrvMailbox.index) { + char *p; + char stemp[3]; + uint8_t code; + + char *codes = RemoveSpace(XdrvMailbox.data); + int size = strlen(XdrvMailbox.data); + + while (size > 0) { + strlcpy(stemp, codes, sizeof(stemp)); + code = strtol(stemp, &p, 16); + SerialBridgeSerial->write(code); // "AA004566" as hex values + size -= 2; + codes += 2; + } + } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); } } else if (CMND_SBAUDRATE == command_code) { char *p; int baud = strtol(XdrvMailbox.data, &p, 10); - if (baud > 0) { + if (baud >= 1200) { baud /= 1200; // Make it a valid baudrate 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_LVALUE, command, Settings.sbaudrate * 1200); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.sbaudrate * 1200); } else serviced = false; // Unknown command @@ -133,9 +166,9 @@ boolean SerialBridgeCommand(void) * Interface \*********************************************************************************************/ -boolean Xdrv08(byte function) +bool Xdrv08(uint8_t function) { - boolean result = false; + bool result = false; if (serial_bridge_active) { switch (function) { @@ -143,7 +176,7 @@ boolean Xdrv08(byte function) SerialBridgeInit(); break; case FUNC_LOOP: - SerialBridgeInput(); + if (SerialBridgeSerial) { SerialBridgeInput(); } break; case FUNC_COMMAND: result = SerialBridgeCommand(); diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index 8273201d5..9a85ad3c4 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -1,7 +1,7 @@ /* xdrv_09_timers.ino - timer support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -135,7 +135,6 @@ void DuskTillDawn(uint8_t *hour_up,uint8_t *minute_up, uint8_t *hour_down, uint8 // double Zeitzone = 2.0; //Sommerzeit double Zeitzone = ((double)time_timezone) / 60; double Zeitgleichung = BerechneZeitgleichung(&DK, T); - double Minuten = Zeitgleichung * 60.0; double Zeitdifferenz = 12.0*acos((sin(h) - sin(B)*sin(DK)) / (cos(B)*cos(DK)))/pi; double AufgangOrtszeit = 12.0 - Zeitdifferenz - Zeitgleichung; double UntergangOrtszeit = 12.0 + Zeitdifferenz - Zeitgleichung; @@ -220,7 +219,7 @@ void ApplyTimerOffsets(Timer *duskdawn) duskdawn->time = timeBuffer; } -String GetSun(byte dawn) +String GetSun(uint8_t dawn) { char stime[6]; @@ -233,7 +232,7 @@ String GetSun(byte dawn) return String(stime); } -uint16_t GetSunMinutes(byte dawn) +uint16_t SunMinutes(uint8_t dawn) { uint8_t hour[2]; uint8_t minute[2]; @@ -247,7 +246,7 @@ uint16_t GetSunMinutes(byte dawn) /*******************************************************************************************/ -void TimerSetRandomWindow(byte index) +void TimerSetRandomWindow(uint8_t index) { timer_window[index] = 0; if (Settings.timer[index].window) { @@ -257,7 +256,7 @@ void TimerSetRandomWindow(byte index) void TimerSetRandomWindows(void) { - for (byte i = 0; i < MAX_TIMERS; i++) { TimerSetRandomWindow(i); } + for (uint8_t i = 0; i < MAX_TIMERS; i++) { TimerSetRandomWindow(i); } } void TimerEverySecond(void) @@ -269,7 +268,7 @@ void TimerEverySecond(void) int16_t time = (RtcTime.hour *60) + RtcTime.minute; uint8_t days = 1 << (RtcTime.day_of_week -1); - for (byte i = 0; i < MAX_TIMERS; i++) { + for (uint8_t i = 0; i < MAX_TIMERS; i++) { // if (Settings.timer[i].device >= devices_present) Settings.timer[i].data = 0; // Reset timer due to change in devices present Timer xtimer = Settings.timer[i]; uint16_t set_time = xtimer.time; @@ -309,7 +308,7 @@ void PrepShowTimer(uint8_t index) Timer xtimer = Settings.timer[index -1]; - for (byte i = 0; i < 7; i++) { + for (uint8_t i = 0; i < 7; i++) { uint8_t mask = 1 << i; snprintf(days, sizeof(days), "%s%d", days, ((xtimer.days & mask) > 0)); } @@ -338,11 +337,11 @@ void PrepShowTimer(uint8_t index) * Commands \*********************************************************************************************/ -boolean TimerCommand(void) +bool TimerCommand(void) { char command[CMDSZ]; char dataBufUc[XdrvMailbox.data_len]; - boolean serviced = true; + bool serviced = true; uint8_t index = XdrvMailbox.index; UpperCase(dataBufUc, XdrvMailbox.data); @@ -386,7 +385,7 @@ boolean TimerCommand(void) uint8_t sign = 0; char time_str[10]; - snprintf(time_str, sizeof(time_str), root[parm_uc]); + strlcpy(time_str, root[parm_uc], sizeof(time_str)); const char *substr = strtok(time_str, ":"); if (substr != NULL) { if (strchr(substr, '-')) { @@ -465,9 +464,9 @@ boolean TimerCommand(void) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.flag3.timers_enable)); MqttPublishPrefixTopic_P(RESULT_OR_STAT, command); - byte jsflg = 0; - byte lines = 1; - for (byte i = 0; i < MAX_TIMERS; i++) { + 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++); } else { @@ -518,9 +517,9 @@ boolean TimerCommand(void) const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER; const char HTTP_BTN_MENU_TIMER[] PROGMEM = - "
"; + "

"; -const char HTTP_TIMER_SCRIPT[] PROGMEM = +const char HTTP_TIMER_SCRIPT1[] PROGMEM = "var pt=[],ct=99;" "function qs(s){" // Alias to save code space "return document.querySelector(s);" @@ -529,8 +528,9 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "var o=document.createElement('option');" "o.textContent=i;" "q.appendChild(o);" - "}" + "}"; #ifdef USE_SUNRISE +const char HTTP_TIMER_SCRIPT2[] PROGMEM = "function gt(){" // Set hours and minutes according to mode "var m,p,q;" "m=qs('input[name=\"rd\"]:checked').value;" // Get mode @@ -538,7 +538,7 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "if(m==0){" // Time is set "so(0);" // Hide offset span and allow Hour 00..23 "q=Math.floor(p/60);if(q<10){q='0'+q;}qs('#ho').value=q;" // Set hours - "q=p%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set minutes + "q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set minutes "}" "if((m==1)||(m==2)){" // Sunrise or sunset is set "so(1);" // Show offset span and allow Hour 00..11 @@ -546,7 +546,7 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "if(q>=12){q-=12;qs('#dr').selectedIndex=1;}" // Negative offset "else{qs('#dr').selectedIndex=0;}" "if(q<10){q='0'+q;}qs('#ho').value=q;" // Set offset hours - "q=p%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set offset minutes + "q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set offset minutes "}" "}" "function so(b){" // Hide or show offset items @@ -559,8 +559,9 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "qs('#dr').disabled='disabled';" "if(e<23){for(i=12;i<=23;i++){ce(i,o);}}" // Create hours select options "}" - "}" + "}"; #endif +const char HTTP_TIMER_SCRIPT3[] PROGMEM = "function st(){" // Save parameters to hidden area "var i,l,m,n,p,s;" "m=0;s=0;" @@ -571,7 +572,7 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "m=qs('input[name=\"rd\"]:checked').value;" // Check mode "s|=(qs('input[name=\"rd\"]:checked').value<<29);" // Get mode #endif - "if(}1>0){" + "if(%d>0){" "i=qs('#d1').selectedIndex;if(i>=0){s|=(i<<23);}" // Get output "s|=(qs('#p1').selectedIndex<<27);" // Get action "}else{" @@ -588,14 +589,15 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "s|=((qs('#mw').selectedIndex)&0x0F)<<11;" // Get window minutes "pt[ct]=s;" "eb('t0').value=pt.join();" // Save parameters from array to hidden area - "}" + "}"; +const char HTTP_TIMER_SCRIPT4[] PROGMEM = "function ot(t,e){" // Select tab and update elements "var i,n,o,p,q,s;" "if(ct<99){st();}" // Save changes "ct=t;" "o=document.getElementsByClassName('tl');" // Restore style to all tabs/buttons - "for(i=0;i>29)&3;eb('b'+p).checked=1;" // Set mode @@ -603,23 +605,24 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = #else "p=s&0x7FF;" // Get time "q=Math.floor(p/60);if(q<10){q='0'+q;}qs('#ho').value=q;" // Set hours - "q=p%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set minutes + "q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set minutes #endif "q=(s>>11)&0xF;if(q<10){q='0'+q;}qs('#mw').value=q;" // Set window minutes "for(i=0;i<7;i++){p=(s>>(16+i))&1;eb('w'+i).checked=p;}" // Set weekdays - "if(}1>0){" + "if(%d>0){" "p=(s>>23)&0xF;qs('#d1').value=p+1;" // Set output "p=(s>>27)&3;qs('#p1').selectedIndex=p;" // Set action "}" "p=(s>>15)&1;eb('r0').checked=p;" // Set repeat "p=(s>>31)&1;eb('a0').checked=p;" // Set arm - "}" + "}"; +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+=\"\"}" "eb('bt').innerHTML=s;" // Create tabs - "if(}1>0){" // Create Output and Action drop down boxes + "if(%d>0){" // Create Output and Action drop down boxes "eb('oa').innerHTML=\"" D_TIMER_OUTPUT " " D_TIMER_ACTION " \";" "o=qs('#p1');ce('" D_OFF "',o);ce('" D_ON "',o);ce('" D_TOGGLE "',o);" // Create offset direction select options #ifdef USE_RULES @@ -629,50 +632,52 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = #endif "}else{" "eb('oa').innerHTML=\"" D_TIMER_ACTION " " D_RULE "\";" // No outputs but rule is allowed - "}" + "}"; +const char HTTP_TIMER_SCRIPT6[] PROGMEM = #ifdef USE_SUNRISE "o=qs('#dr');ce('+',o);ce('-',o);" // Create offset direction select options #endif "o=qs('#ho');for(i=0;i<=23;i++){ce((i<10)?('0'+i):i,o);}" // Create hours select options "o=qs('#mi');for(i=0;i<=59;i++){ce((i<10)?('0'+i):i,o);}" // Create minutes select options "o=qs('#mw');for(i=0;i<=15;i++){ce((i<10)?('0'+i):i,o);}" // Create window minutes select options - "o=qs('#d1');for(i=0;i<}1;i++){ce(i+1,o);}" // Create outputs + "o=qs('#d1');for(i=0;i<%d;i++){ce(i+1,o);}" // Create outputs "var a='" D_DAY3LIST "';" - "s='';for(i=0;i<7;i++){s+=\"\"+a.substring(i*3,(i*3)+3)+\"\"}" + "s='';for(i=0;i<7;i++){s+=\"\"+a.substring(i*3,(i*3)+3)+\" \"}" "eb('ds').innerHTML=s;" // Create weekdays "eb('dP').click();" // Get the element with id='dP' and click on it - "}"; + "}" + "window.onload=it;"; const char HTTP_TIMER_STYLE[] PROGMEM = - ".tl{float:left;border-radius:0;border:1px solid #fff;padding:1px;width:6.25%;}" -#ifdef USE_SUNRISE - "input[type='radio']{width:13px;height:24px;margin-top:-1px;margin-right:8px;vertical-align:middle;}" -#endif - ""; -const char HTTP_FORM_TIMER[] 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) +const char HTTP_FORM_TIMER1[] PROGMEM = "
" " " D_TIMER_PARAMETERS " " "
" - "
" D_TIMER_ENABLE "


" + "
" D_TIMER_ENABLE "


" "



" "

" "
" - "" D_TIMER_ARM " " - "" D_TIMER_REPEAT "" + "" D_TIMER_ARM " " + "" D_TIMER_REPEAT "" "

" - "
" + "
"; #ifdef USE_SUNRISE - "
" +const char HTTP_FORM_TIMER3[] PROGMEM = + "
" "" D_TIMER_TIME "
" - "" D_SUNRISE " (}8)
" - "" D_SUNSET " (}9)
" + "" D_SUNRISE " (%s)
" + "" D_SUNSET " (%s)
" "
" + "

" "" - " " + " "; #else - "" D_TIMER_TIME " " +const char HTTP_FORM_TIMER3[] PROGMEM = + "" D_TIMER_TIME " "; #endif // USE_SUNRISE +const char HTTP_FORM_TIMER4[] PROGMEM = "" " " D_HOUR_MINUTE_SEPARATOR " " "" @@ -683,8 +688,8 @@ const char HTTP_FORM_TIMER1[] PROGMEM = void HandleTimerConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TIMER); if (WebServer->hasArg("save")) { @@ -693,28 +698,30 @@ void HandleTimerConfiguration(void) return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_TIMER)); - page += FPSTR(HTTP_TIMER_SCRIPT); - page += FPSTR(HTTP_HEAD_STYLE); - page.replace(F(""), FPSTR(HTTP_TIMER_STYLE)); - page += FPSTR(HTTP_FORM_TIMER); - page.replace(F("{e0"), (Settings.flag3.timers_enable) ? F(" checked") : F("")); - for (byte i = 0; i < MAX_TIMERS; i++) { - if (i > 0) { page += F(","); } - page += String(Settings.timer[i].data); - } - page += FPSTR(HTTP_FORM_TIMER1); - page.replace(F("}1"), String(devices_present)); + WSContentStart_P(S_CONFIGURE_TIMER); + WSContentSend_P(HTTP_TIMER_SCRIPT1); #ifdef USE_SUNRISE - page.replace(F("}8"), GetSun(0)); // Add Sunrise - page.replace(F("}9"), GetSun(1)); // Add Sunset - page.replace(F("299"), String(100 + (strlen(D_SUNSET) *12))); // Fix string length to keep radios centered + WSContentSend_P(HTTP_TIMER_SCRIPT2); #endif // USE_SUNRISE - page += FPSTR(HTTP_FORM_END); - page += F(""); // Init elements and select first tab/button - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + 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_SCRIPT6, devices_present); + WSContentSendStyle_P(HTTP_TIMER_STYLE); + 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); + } + WSContentSend_P(HTTP_FORM_TIMER2); +#ifdef USE_SUNRISE + WSContentSend_P(HTTP_FORM_TIMER3, 100 + (strlen(D_SUNSET) *12), GetSun(0).c_str(), GetSun(1).c_str()); +#else + WSContentSend_P(HTTP_FORM_TIMER3); +#endif // USE_SUNRISE + WSContentSend_P(HTTP_FORM_TIMER4); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); } void TimerSaveSettings(void) @@ -726,7 +733,7 @@ void TimerSaveSettings(void) WebGetArg("t0", tmp, sizeof(tmp)); char *p = tmp; snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_TIMERS " %d"), Settings.flag3.timers_enable); - for (byte i = 0; i < MAX_TIMERS; i++) { + for (uint8_t i = 0; i < MAX_TIMERS; i++) { timer.data = strtol(p, &p, 10); p++; // Skip comma if (timer.time < 1440) { @@ -745,9 +752,9 @@ void TimerSaveSettings(void) * Interface \*********************************************************************************************/ -boolean Xdrv09(byte function) +bool Xdrv09(uint8_t function) { - boolean result = false; + bool result = false; switch (function) { case FUNC_PRE_INIT: @@ -757,9 +764,9 @@ boolean Xdrv09(byte function) #ifdef USE_TIMERS_WEB case FUNC_WEB_ADD_BUTTON: #ifdef USE_RULES - strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend_P(HTTP_BTN_MENU_TIMER); #else - if (devices_present) { strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data) - strlen(mqtt_data) -1); } + if (devices_present) { WSContentSend_P(HTTP_BTN_MENU_TIMER); } #endif // USE_RULES break; case FUNC_WEB_ADD_HANDLER: diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index c9d880128..4d13bf6b9 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -1,7 +1,7 @@ /* xdrv_10_rules.ino - rule support for Sonoff-Tasmota - Copyright (C) 2018 ESP Easy Group and Theo Arends + Copyright (C) 2019 ESP Easy Group and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -75,11 +75,50 @@ #define D_CMND_MULT "Mult" #define D_CMND_SCALE "Scale" #define D_CMND_CALC_RESOLUTION "CalcRes" +#define D_CMND_SUBSCRIBE "Subscribe" +#define D_CMND_UNSUBSCRIBE "Unsubscribe" #define D_JSON_INITIATED "Initiated" -enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM, CMND_ADD, CMND_SUB, CMND_MULT, CMND_SCALE, CMND_CALC_RESOLUTION }; -const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE "|" D_CMND_CALC_RESOLUTION ; +#define COMPARE_OPERATOR_NONE -1 +#define COMPARE_OPERATOR_EQUAL 0 +#define COMPARE_OPERATOR_BIGGER 1 +#define COMPARE_OPERATOR_SMALLER 2 +#define COMPARE_OPERATOR_EXACT_DIVISION 3 +#define COMPARE_OPERATOR_NUMBER_EQUAL 4 +#define COMPARE_OPERATOR_NOT_EQUAL 5 +#define COMPARE_OPERATOR_BIGGER_EQUAL 6 +#define COMPARE_OPERATOR_SMALLER_EQUAL 7 +#define MAXIMUM_COMPARE_OPERATOR COMPARE_OPERATOR_SMALLER_EQUAL +const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<="; + +#ifdef USE_EXPRESSION + #include // Import LinkedList library + + const char kExpressionOperators[] PROGMEM = "+-*/%^"; + #define EXPRESSION_OPERATOR_ADD 0 + #define EXPRESSION_OPERATOR_SUBTRACT 1 + #define EXPRESSION_OPERATOR_MULTIPLY 2 + #define EXPRESSION_OPERATOR_DIVIDEDBY 3 + #define EXPRESSION_OPERATOR_MODULO 4 + #define EXPRESSION_OPERATOR_POWER 5 + + const uint8_t kExpressionOperatorsPriorities[] PROGMEM = {1, 1, 2, 2, 3, 4}; + #define MAX_EXPRESSION_OPERATOR_PRIORITY 4 +#endif // USE_EXPRESSION + +enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM, CMND_ADD, CMND_SUB, CMND_MULT, CMND_SCALE, CMND_CALC_RESOLUTION, CMND_SUBSCRIBE, CMND_UNSUBSCRIBE }; +const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE "|" D_CMND_CALC_RESOLUTION "|" D_CMND_SUBSCRIBE "|" D_CMND_UNSUBSCRIBE ; + +#ifdef SUPPORT_MQTT_EVENT + #include // Import LinkedList library + typedef struct { + String Event; + String Topic; + String Key; + } MQTT_Subscription; + LinkedList subscriptions; +#endif //SUPPORT_MQTT_EVENT String rules_event_value; unsigned long rules_timer[MAX_RULE_TIMERS] = { 0 }; @@ -95,10 +134,18 @@ uint8_t rules_teleperiod = 0; char event_data[100]; char vars[MAX_RULE_VARS][33] = { 0 }; +#if (MAX_RULE_VARS>16) +#error MAX_RULE_VARS is bigger than 16 +#endif +#if (MAX_RULE_MEMS>5) +#error MAX_RULE_MEMS is bigger than 5 +#endif +uint16_t vars_event = 0; +uint8_t mems_event = 0; /*******************************************************************************************/ -bool RulesRuleMatch(byte rule_set, String &event, String &rule) +bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule) { // event = {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}} // event = {"System":{"Boot":1}} @@ -120,39 +167,28 @@ bool RulesRuleMatch(byte rule_set, String &event, String &rule) String rule_name = rule.substring(pos +1); // "CURRENT>0.100" or "BOOT" or "%var1%" or "MINUTE|5" - char compare = ' '; - pos = rule_name.indexOf(">"); - if (pos > 0) { - compare = '>'; - } else { - pos = rule_name.indexOf("<"); - if (pos > 0) { - compare = '<'; - } else { - pos = rule_name.indexOf("="); - if (pos > 0) { - compare = '='; - } else { - pos = rule_name.indexOf("|"); // Modulo, cannot use % easily as it is used for variable detection - if (pos > 0) { - compare = '%'; - } - } + char compare_operator[3]; + int8_t compare = COMPARE_OPERATOR_NONE; + for (int8_t i = MAXIMUM_COMPARE_OPERATOR; i >= 0; i--) { + snprintf_P(compare_operator, sizeof(compare_operator), kCompareOperators + (i *2)); + if ((pos = rule_name.indexOf(compare_operator)) > 0) { + compare = i; + break; } } char rule_svalue[CMDSZ] = { 0 }; double rule_value = 0; - if (pos > 0) { - String rule_param = rule_name.substring(pos + 1); - for (byte i = 0; i < MAX_RULE_VARS; i++) { + if (compare != COMPARE_OPERATOR_NONE) { + String rule_param = rule_name.substring(pos + strlen(compare_operator)); + for (uint8_t i = 0; i < MAX_RULE_VARS; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%%VAR%d%%"), i +1); if (rule_param.startsWith(stemp)) { rule_param = vars[i]; break; } } - for (byte i = 0; i < MAX_RULE_MEMS; i++) { + for (uint8_t i = 0; i < MAX_RULE_MEMS; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%%MEM%d%%"), i +1); if (rule_param.startsWith(stemp)) { rule_param = Settings.mems[i]; @@ -161,24 +197,28 @@ bool RulesRuleMatch(byte rule_set, String &event, String &rule) } snprintf_P(stemp, sizeof(stemp), PSTR("%%TIME%%")); if (rule_param.startsWith(stemp)) { - rule_param = String(GetMinutesPastMidnight()); + rule_param = String(MinutesPastMidnight()); } snprintf_P(stemp, sizeof(stemp), PSTR("%%UPTIME%%")); if (rule_param.startsWith(stemp)) { - rule_param = String(GetMinutesUptime()); + rule_param = String(MinutesUptime()); + } + snprintf_P(stemp, sizeof(stemp), PSTR("%%TIMESTAMP%%")); + if (rule_param.startsWith(stemp)) { + rule_param = GetDateAndTime(DT_LOCAL).c_str(); } #if defined(USE_TIMERS) && defined(USE_SUNRISE) snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNRISE%%")); if (rule_param.startsWith(stemp)) { - rule_param = String(GetSunMinutes(0)); + rule_param = String(SunMinutes(0)); } snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNSET%%")); if (rule_param.startsWith(stemp)) { - rule_param = String(GetSunMinutes(1)); + rule_param = String(SunMinutes(1)); } #endif // USE_TIMERS and USE_SUNRISE rule_param.toUpperCase(); - snprintf(rule_svalue, sizeof(rule_svalue), rule_param.c_str()); + strlcpy(rule_svalue, rule_param.c_str(), sizeof(rule_svalue)); int temp_value = GetStateNumber(rule_svalue); if (temp_value > -1) { @@ -197,9 +237,8 @@ bool RulesRuleMatch(byte rule_set, String &event, String &rule) double value = 0; const char* str_value = root[rule_task][rule_name]; -//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Task %s, Name %s, Value |%s|, TrigCnt %d, TrigSt %d, Source %s, Json %s"), +//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Task %s, Name %s, Value |%s|, TrigCnt %d, TrigSt %d, Source %s, Json %s"), // rule_task.c_str(), rule_name.c_str(), rule_svalue, rules_trigger_count[rule_set], bitRead(rules_triggers[rule_set], rules_trigger_count[rule_set]), event.c_str(), (str_value) ? str_value : "none"); -//AddLog(LOG_LEVEL_DEBUG); if (!root[rule_task][rule_name].success()) { return false; } // No value but rule_name is ok @@ -212,24 +251,32 @@ bool RulesRuleMatch(byte rule_set, String &event, String &rule) int int_value = int(value); int int_rule_value = int(rule_value); switch (compare) { - case '%': - if ((int_value > 0) && (int_rule_value > 0)) { - if ((int_value % int_rule_value) == 0) { match = true; } - } + case COMPARE_OPERATOR_EXACT_DIVISION: + match = (int_rule_value && (int_value % int_rule_value) == 0); break; - case '>': - if (value > rule_value) { match = true; } + case COMPARE_OPERATOR_EQUAL: + match = (!strcasecmp(str_value, rule_svalue)); // Compare strings - this also works for hexadecimals break; - case '<': - if (value < rule_value) { match = true; } + case COMPARE_OPERATOR_BIGGER: + match = (value > rule_value); break; - case '=': -// if (value == rule_value) { match = true; } // Compare values - only decimals or partly hexadecimals - if (!strcasecmp(str_value, rule_svalue)) { match = true; } // Compare strings - this also works for hexadecimals + case COMPARE_OPERATOR_SMALLER: + match = (value < rule_value); break; - case ' ': - match = true; // Json value but not needed + case COMPARE_OPERATOR_NUMBER_EQUAL: + match = (value == rule_value); break; + case COMPARE_OPERATOR_NOT_EQUAL: + match = (value != rule_value); + break; + case COMPARE_OPERATOR_BIGGER_EQUAL: + match = (value >= rule_value); + break; + case COMPARE_OPERATOR_SMALLER_EQUAL: + match = (value <= rule_value); + break; + default: + match = true; } } else match = true; @@ -250,15 +297,14 @@ bool RulesRuleMatch(byte rule_set, String &event, String &rule) /*******************************************************************************************/ -bool RuleSetProcess(byte rule_set, String &event_saved) +bool RuleSetProcess(uint8_t rule_set, String &event_saved) { bool serviced = false; char stemp[10]; delay(0); // Prohibit possible loop software watchdog -//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Event = %s, Rule = %s"), event_saved.c_str(), Settings.rules[rule_set]); -//AddLog(LOG_LEVEL_DEBUG); +//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Event = %s, Rule = %s"), event_saved.c_str(), Settings.rules[rule_set]); String rules = Settings.rules[rule_set]; @@ -293,8 +339,7 @@ bool RuleSetProcess(byte rule_set, String &event_saved) rules_event_value = ""; String event = event_saved; -//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Event |%s|, Rule |%s|, Command(s) |%s|"), event.c_str(), event_trigger.c_str(), commands.c_str()); -//AddLog(LOG_LEVEL_DEBUG); +//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Event |%s|, Rule |%s|, Command(s) |%s|"), event.c_str(), event_trigger.c_str(), commands.c_str()); if (RulesRuleMatch(rule_set, event, event_trigger)) { commands.trim(); @@ -303,26 +348,26 @@ bool RuleSetProcess(byte rule_set, String &event_saved) // if (!ucommand.startsWith("BACKLOG")) { commands = "backlog " + commands; } // Always use Backlog to prevent power race exception if (ucommand.indexOf("EVENT ") != -1) { commands = "backlog " + commands; } // Always use Backlog with event to prevent rule event loop exception commands.replace(F("%value%"), rules_event_value); - for (byte i = 0; i < MAX_RULE_VARS; i++) { + for (uint8_t i = 0; i < MAX_RULE_VARS; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%%var%d%%"), i +1); commands.replace(stemp, vars[i]); } - for (byte i = 0; i < MAX_RULE_MEMS; i++) { + for (uint8_t i = 0; i < MAX_RULE_MEMS; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%%mem%d%%"), i +1); commands.replace(stemp, Settings.mems[i]); } - commands.replace(F("%time%"), String(GetMinutesPastMidnight())); - commands.replace(F("%uptime%"), String(GetMinutesUptime())); + commands.replace(F("%time%"), String(MinutesPastMidnight())); + commands.replace(F("%uptime%"), String(MinutesUptime())); + commands.replace(F("%timestamp%"), GetDateAndTime(DT_LOCAL).c_str()); #if defined(USE_TIMERS) && defined(USE_SUNRISE) - commands.replace(F("%sunrise%"), String(GetSunMinutes(0))); - commands.replace(F("%sunset%"), String(GetSunMinutes(1))); + commands.replace(F("%sunrise%"), String(SunMinutes(0))); + commands.replace(F("%sunset%"), String(SunMinutes(1))); #endif // USE_TIMERS and USE_SUNRISE char command[commands.length() +1]; - snprintf(command, sizeof(command), commands.c_str()); + strlcpy(command, commands.c_str(), sizeof(command)); - snprintf_P(log_data, sizeof(log_data), PSTR("RUL: %s performs \"%s\""), event_trigger.c_str(), command); - AddLog(LOG_LEVEL_INFO); + 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); // MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_RULE)); @@ -342,15 +387,16 @@ bool RulesProcessEvent(char *json_event) { bool serviced = false; +#ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("RulesProcessEvent")); +#endif String event_saved = json_event; event_saved.toUpperCase(); -//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Event %s"), event_saved.c_str()); -//AddLog(LOG_LEVEL_DEBUG); +//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Event %s"), event_saved.c_str()); - for (byte i = 0; i < MAX_RULE_SETS; i++) { + for (uint8_t i = 0; i < MAX_RULE_SETS; i++) { if (strlen(Settings.rules[i]) && bitRead(Settings.rule_enabled, i)) { if (RuleSetProcess(i, event_saved)) { serviced = true; } } @@ -366,7 +412,7 @@ bool RulesProcess(void) void RulesInit(void) { rules_flag.data = 0; - for (byte i = 0; i < MAX_RULE_SETS; i++) { + for (uint8_t i = 0; i < MAX_RULE_SETS; i++) { if (Settings.rules[i][0] == '\0') { bitWrite(Settings.rule_enabled, i, 0); bitWrite(Settings.rule_once, i, 0); @@ -383,7 +429,7 @@ void RulesEvery50ms(void) if (-1 == rules_new_power) { rules_new_power = power; } if (rules_new_power != rules_old_power) { if (rules_old_power != -1) { - for (byte i = 0; i < devices_present; i++) { + for (uint8_t i = 0; i < devices_present; i++) { uint8_t new_state = (rules_new_power >> i) &1; if (new_state != ((rules_old_power >> i) &1)) { snprintf_P(json_event, sizeof(json_event), PSTR("{\"Power%d\":{\"State\":%d}}"), i +1, new_state); @@ -392,20 +438,20 @@ void RulesEvery50ms(void) } } else { // Boot time POWER OUTPUTS (Relays) Status - for (byte i = 0; i < devices_present; i++) { + for (uint8_t i = 0; i < devices_present; i++) { uint8_t new_state = (rules_new_power >> i) &1; snprintf_P(json_event, sizeof(json_event), PSTR("{\"Power%d\":{\"Boot\":%d}}"), i +1, new_state); RulesProcessEvent(json_event); } // Boot time SWITCHES Status - for (byte i = 0; i < MAX_SWITCHES; i++) { + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { #ifdef USE_TM1638 if ((pin[GPIO_SWT1 +i] < 99) || ((pin[GPIO_TM16CLK] < 99) && (pin[GPIO_TM16DIO] < 99) && (pin[GPIO_TM16STB] < 99))) { #else if (pin[GPIO_SWT1 +i] < 99) { #endif // USE_TM1638 - boolean swm = ((FOLLOW_INV == Settings.switchmode[i]) || (PUSHBUTTON_INV == Settings.switchmode[i]) || (PUSHBUTTONHOLD_INV == Settings.switchmode[i])); - snprintf_P(json_event, sizeof(json_event), PSTR("{\"" D_JSON_SWITCH "%d\":{\"Boot\":%d}}"), i +1, (swm ^ lastwallswitch[i])); + bool swm = ((FOLLOW_INV == Settings.switchmode[i]) || (PUSHBUTTON_INV == Settings.switchmode[i]) || (PUSHBUTTONHOLD_INV == Settings.switchmode[i])); + snprintf_P(json_event, sizeof(json_event), PSTR("{\"" D_JSON_SWITCH "%d\":{\"Boot\":%d}}"), i +1, (swm ^ SwitchLastState(i))); RulesProcessEvent(json_event); } } @@ -440,16 +486,36 @@ 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 (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; + } + } + } else if (rules_flag.data) { uint16_t mask = 1; - for (byte i = 0; i < MAX_RULES_FLAG; i++) { + for (uint8_t i = 0; i < MAX_RULES_FLAG; i++) { if (rules_flag.data & mask) { rules_flag.data ^= mask; json_event[0] = '\0'; switch (i) { case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break; - case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), GetMinutesPastMidnight()); break; - case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), GetMinutesPastMidnight()); break; + case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), MinutesPastMidnight()); break; + case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), MinutesPastMidnight()); break; case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break; 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; @@ -492,11 +558,11 @@ void RulesEverySecond(void) if (RtcTime.valid) { if ((uptime > 60) && (RtcTime.minute != rules_last_minute)) { // Execute from one minute after restart every minute only once rules_last_minute = RtcTime.minute; - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Minute\":%d}}"), GetMinutesPastMidnight()); + snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Minute\":%d}}"), MinutesPastMidnight()); RulesProcessEvent(json_event); } } - for (byte i = 0; i < MAX_RULE_TIMERS; i++) { + for (uint8_t i = 0; i < MAX_RULE_TIMERS; i++) { if (rules_timer[i] != 0L) { // Timer active? if (TimeReached(rules_timer[i])) { // Timer finished? rules_timer[i] = 0L; // Turn off this timer @@ -520,10 +586,496 @@ void RulesTeleperiod(void) rules_teleperiod = 0; } -boolean RulesCommand(void) +#ifdef SUPPORT_MQTT_EVENT +/********************************************************************************************/ +/* + * Rules: Process received MQTT message. + * If the message is in our subscription list, trigger an event with the value parsed from MQTT data + * Input: + * void - We are going to access XdrvMailbox data directly. + * Return: + * true - The message is consumed. + * false - The message is not in our list. + */ +bool RulesMqttData(void) +{ + bool serviced = false; + if (XdrvMailbox.data_len < 1 || XdrvMailbox.data_len > 128) { + return false; + } + String sTopic = XdrvMailbox.topic; + String sData = XdrvMailbox.data; + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: MQTT Topic %s, Event %s"), XdrvMailbox.topic, XdrvMailbox.data); + MQTT_Subscription event_item; + //Looking for matched topic + for (int index = 0; index < subscriptions.size(); index++) { + event_item = subscriptions.get(index); + + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Match MQTT message Topic %s with subscription topic %s"), sTopic.c_str(), event_item.Topic.c_str()); + if (sTopic.startsWith(event_item.Topic)) { + //This topic is subscribed by us, so serve it + serviced = true; + String value; + if (event_item.Key.length() == 0) { //If did not specify Key + value = sData; + } else { //If specified Key, need to parse Key/Value from JSON data + StaticJsonBuffer<400> jsonBuf; + JsonObject& jsonData = jsonBuf.parseObject(sData); + String key1 = event_item.Key; + String key2; + if (!jsonData.success()) break; //Failed to parse JSON data, ignore this message. + int dot; + if ((dot = key1.indexOf('.')) > 0) { + key2 = key1.substring(dot+1); + key1 = key1.substring(0, dot); + if (!jsonData[key1][key2].success()) break; //Failed to get the key/value, ignore this message. + value = (const char *)jsonData[key1][key2]; + } else { + if (!jsonData[key1].success()) break; + value = (const char *)jsonData[key1]; + } + } + value.trim(); + //Create an new event. Cannot directly call RulesProcessEvent(). + snprintf_P(event_data, sizeof(event_data), PSTR("%s=%s"), event_item.Event.c_str(), value.c_str()); + } + } + return serviced; +} + +/********************************************************************************************/ +/* + * Subscribe a MQTT topic (with or without key) and assign an event name to it + * Command Subscribe format: + * Subscribe , [, ] + * This command will subscribe a and give it an event name . + * The optional parameter is for parse the specified key/value from MQTT message + * payload with JSON format. + * Subscribe + * Subscribe command without any parameter will list all topics currently subscribed. + * Input: + * data - A char buffer with all the parameters + * data_len - Length of the parameters + * Return: + * A string include subscribed event, topic and key. + */ +String RulesSubscribe(const char *data, int data_len) +{ + MQTT_Subscription subscription_item; + String events; + if (data_len > 0) { + char parameters[data_len+1]; + memcpy(parameters, data, data_len); + parameters[data_len] = '\0'; + String event_name, topic, key; + + char * pos = strtok(parameters, ","); + if (pos) { + event_name = Trim(pos); + pos = strtok(NULL, ","); + if (pos) { + topic = Trim(pos); + pos = strtok(NULL, ","); + if (pos) { + key = Trim(pos); + } + } + } + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Subscribe command with parameters: %s, %s, %s."), event_name.c_str(), topic.c_str(), key.c_str()); + event_name.toUpperCase(); + if (event_name.length() > 0 && topic.length() > 0) { + //Search all subscriptions + for (int index=0; index < subscriptions.size(); index++) { + if (subscriptions.get(index).Event.equals(event_name)) { + //If find exists one, remove it. + String stopic = subscriptions.get(index).Topic + "/#"; + MqttUnsubscribe(stopic.c_str()); + subscriptions.remove(index); + break; + } + } + //Add "/#" to the topic + if (!topic.endsWith("#")) { + if (topic.endsWith("/")) { + topic.concat("#"); + } else { + topic.concat("/#"); + } + } + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: New topic: %s."), topic.c_str()); + //MQTT Subscribe + subscription_item.Event = event_name; + subscription_item.Topic = topic.substring(0, topic.length() - 2); //Remove "/#" so easy to match + subscription_item.Key = key; + subscriptions.add(subscription_item); + + MqttSubscribe(topic.c_str()); + events.concat(event_name + "," + topic + + (key.length()>0 ? "," : "") + + key); + } else { + events = D_JSON_WRONG_PARAMETERS; + } + } else { + //If did not specify the event name, list all subscribed event + for (int index=0; index < subscriptions.size(); index++) { + subscription_item = subscriptions.get(index); + events.concat(subscription_item.Event + "," + subscription_item.Topic + + (subscription_item.Key.length()>0 ? "," : "") + + subscription_item.Key + "; "); + } + } + return events; +} + +/********************************************************************************************/ +/* + * Unsubscribe specified MQTT event. If no event specified, Unsubscribe all. + * Command Unsubscribe format: + * Unsubscribe [] + * Input: + * data - Event name + * data_len - Length of the parameters + * Return: + * list all the events unsubscribed. + */ +String RulesUnsubscribe(const char * data, int data_len) +{ + MQTT_Subscription subscription_item; + String events; + if (data_len > 0) { + for (int index = 0; index < subscriptions.size(); index++) { + subscription_item = subscriptions.get(index); + if (subscription_item.Event.equalsIgnoreCase(data)) { + String stopic = subscription_item.Topic + "/#"; + MqttUnsubscribe(stopic.c_str()); + events = subscription_item.Event; + subscriptions.remove(index); + break; + } + } + } else { + //If did not specify the event name, unsubscribe all event + String stopic; + while (subscriptions.size() > 0) { + events.concat(subscriptions.get(0).Event + "; "); + stopic = subscriptions.get(0).Topic + "/#"; + MqttUnsubscribe(stopic.c_str()); + subscriptions.remove(0); + } + } + return events; +} +#endif // SUPPORT_MQTT_EVENT + +#ifdef USE_EXPRESSION +/********************************************************************************************/ +/* + * Parse a number value + * Input: + * pNumber - A char pointer point to a digit started string (guaranteed) + * value - Reference a double variable used to accept the result + * Output: + * pNumber - Pointer forward to next character after the number + * value - double type, the result value + * Return: + * true - succeed + * false - failed + */ +bool findNextNumber(char * &pNumber, double &value) +{ + bool bSucceed = false; + String sNumber = ""; + while (*pNumber) { + if (isdigit(*pNumber) || (*pNumber == '.')) { + sNumber += *pNumber; + pNumber++; + } else { + break; + } + } + if (sNumber.length() > 0) { + value = CharToDouble(sNumber.c_str()); + bSucceed = true; + } + return bSucceed; +} + +/********************************************************************************************/ +/* + * Parse a variable (like VAR1, MEM3) and get its value (double type) + * Input: + * pVarname - A char pointer point to a variable name string + * value - Reference a double variable used to accept the result + * Output: + * pVarname - Pointer forward to next character after the variable + * value - double type, the result value + * Return: + * true - succeed + * false - failed + */ +bool findNextVariableValue(char * &pVarname, double &value) +{ + bool succeed = true; + value = 0; + String sVarName = ""; + while (*pVarname) { + if (isalpha(*pVarname) || isdigit(*pVarname)) { + sVarName.concat(*pVarname); + pVarname++; + } else { + break; + } + } + sVarName.toUpperCase(); + if (sVarName.startsWith(F("VAR"))) { + int index = sVarName.substring(3).toInt(); + if (index > 0 && index <= MAX_RULE_VARS) { + value = CharToDouble(vars[index -1]); + } + } else if (sVarName.startsWith(F("MEM"))) { + int index = sVarName.substring(3).toInt(); + if (index > 0 && index <= MAX_RULE_MEMS) { + value = CharToDouble(Settings.mems[index -1]); + } + } else if (sVarName.equals(F("TIME"))) { + value = MinutesPastMidnight(); + } else if (sVarName.equals(F("UPTIME"))) { + value = MinutesUptime(); + } else if (sVarName.equals(F("UTCTIME"))) { + value = UtcTime(); + } else if (sVarName.equals(F("LOCALTIME"))) { + value = LocalTime(); +#if defined(USE_TIMERS) && defined(USE_SUNRISE) + } else if (sVarName.equals(F("SUNRISE"))) { + value = SunMinutes(0); + } else if (sVarName.equals(F("SUNSET"))) { + value = SunMinutes(1); +#endif + } else { + succeed = false; + } + + return succeed; +} + +/********************************************************************************************/ +/* + * Find next object in expression and evaluate it + * An object could be: + * - A float number start with a digit, like 0.787 + * - A variable name, like VAR1, MEM3 + * - An expression enclosed with a pair of round brackets, (.....) + * Input: + * pointer - A char pointer point to a place of the expression string + * value - Reference a double variable used to accept the result + * Output: + * pointer - Pointer forward to next character after next object + * value - double type, the result value + * Return: + * true - succeed + * false - failed + */ +bool findNextObjectValue(char * &pointer, double &value) +{ + bool bSucceed = false; + while (*pointer) + { + if (isspace(*pointer)) { //Skip leading spaces + pointer++; + continue; + } + if (isdigit(*pointer)) { //This object is a number + bSucceed = findNextNumber(pointer, value); + break; + } else if (isalpha(*pointer)) { //Should be a variable like VAR12, MEM1 + bSucceed = findNextVariableValue(pointer, value); + break; + } else if (*pointer == '(') { //It is a sub expression bracketed with () + pointer++; + char * sub_exp_start = pointer; //Find out the sub expression between a pair of parenthesis. "()" + unsigned int sub_exp_len = 0; + //Look for the matched closure parenthesis.")" + bool bFindClosures = false; + uint8_t matchClosures = 1; + while (*pointer) + { + if (*pointer == ')') { + matchClosures--; + if (matchClosures == 0) { + sub_exp_len = pointer - sub_exp_start; + bFindClosures = true; + break; + } + } else if (*pointer == '(') { + matchClosures++; + } + pointer++; + } + if (bFindClosures) { + value = evaluateExpression(sub_exp_start, sub_exp_len); + bSucceed = true; + } + break; + } else { //No number, no variable, no expression, then invalid object. + break; + } + } + return bSucceed; +} + +/********************************************************************************************/ +/* + * Find next operator in expression + * An operator could be: +, - , * , / , %, ^ + * Input: + * pointer - A char pointer point to a place of the expression string + * op - Reference to a variable used to accept the result + * Output: + * pointer - Pointer forward to next character after next operator + * op - The operator. 0, 1, 2, 3, 4, 5 + * Return: + * true - succeed + * false - failed + */ +bool findNextOperator(char * &pointer, int8_t &op) +{ + bool bSucceed = false; + while (*pointer) + { + if (isspace(*pointer)) { //Skip leading spaces + pointer++; + continue; + } + if (char *pch = strchr(kExpressionOperators, *pointer)) { //If it is an operator + op = (int8_t)(pch - kExpressionOperators); + pointer++; + bSucceed = true; + } + break; + } + return bSucceed; +} +/********************************************************************************************/ +/* + * Calculate a simple expression composed by 2 value and 1 operator, like 2 * 3 + * Input: + * pointer - A char pointer point to a place of the expression string + * value - Reference a double variable used to accept the result + * Output: + * pointer - Pointer forward to next character after next object + * value - double type, the result value + * Return: + * true - succeed + * false - failed + */ +double calculateTwoValues(double v1, double v2, uint8_t op) +{ + switch (op) + { + case EXPRESSION_OPERATOR_ADD: + return v1 + v2; + case EXPRESSION_OPERATOR_SUBTRACT: + return v1 - v2; + case EXPRESSION_OPERATOR_MULTIPLY: + return v1 * v2; + case EXPRESSION_OPERATOR_DIVIDEDBY: + return (0 == v2) ? 0 : (v1 / v2); + case EXPRESSION_OPERATOR_MODULO: + return (0 == v2) ? 0 : (int(v1) % int(v2)); + case EXPRESSION_OPERATOR_POWER: + return FastPrecisePow(v1, v2); + } + return 0; +} + +/********************************************************************************************/ +/* + * Parse and evaluate an expression. + * For example: "10 * ( MEM2 + 1) / 2" + * Right now, only support operators listed here: (order by priority) + * Priority 4: ^ (power) + * Priority 3: % (modulo, always get integer result) + * Priority 2: *, / + * Priority 1: +, - + * Input: + * expression - The expression to be evaluated + * len - Length of the expression + * Return: + * double - result. + * 0 - if the expression is invalid + * An example: + * MEM1 = 3, MEM2 = 6, VAR2 = 15, VAR10 = 80 + * At beginning, the expression might be complicated like: 3.14 * (MEM1 * (10 + VAR2 ^2) - 100) % 10 + VAR10 / (2 + MEM2) + * We are going to scan the whole expression, evaluate each object. + * Finally we will have a value list:. + * Order Object Value + * 0 3.14 3.14 + * 1 (MEM1 * (10 + VAR2 ^2) - 100) 605 + * 2 10 10 + * 3 VAR10 80 + * 4 (2 + MEM2) 8 + * And an operator list: + * Order Operator Priority + * 0 * 2 + * 1 % 3 + * 2 + 1 + * 3 / 2 + */ +double evaluateExpression(const char * expression, unsigned int len) +{ + char expbuf[len + 1]; + memcpy(expbuf, expression, len); + expbuf[len] = '\0'; + char * scan_pointer = expbuf; + + LinkedList object_values; + LinkedList operators; + int8_t op; + double va; + //Find and add the value of first object + if (findNextObjectValue(scan_pointer, va)) { + object_values.add(va); + } else { + return 0; + } + while (*scan_pointer) + { + if (findNextOperator(scan_pointer, op) + && *scan_pointer + && findNextObjectValue(scan_pointer, va)) + { + operators.add(op); + object_values.add(va); + } else { + //No operator followed or no more object after this operator, we done. + break; + } + } + + //Going to evaluate the whole expression + //Calculate by order of operator priorities. Looking for all operators with specified priority (from High to Low) + for (int8_t priority = MAX_EXPRESSION_OPERATOR_PRIORITY; priority>0; priority--) { + int index = 0; + while (index < operators.size()) { + if (priority == kExpressionOperatorsPriorities[(operators.get(index))]) { //need to calculate the operator first + //get current object value and remove the next object with current operator + va = calculateTwoValues(object_values.get(index), object_values.remove(index + 1), operators.remove(index)); + //Replace the current value with the result + object_values.set(index, va); + } else { + index++; + } + } + } + return object_values.get(0); +} +#endif //USE_EXPRESSION + +bool RulesCommand(void) { char command[CMDSZ]; - boolean serviced = true; + bool serviced = true; uint8_t index = XdrvMailbox.index; int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kRulesCommands); @@ -578,10 +1130,15 @@ boolean RulesCommand(void) } else if ((CMND_RULETIMER == command_code) && (index > 0) && (index <= MAX_RULE_TIMERS)) { if (XdrvMailbox.data_len > 0) { +#ifdef USE_EXPRESSION + double timer_set = evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len); + rules_timer[index -1] = (timer_set > 0) ? millis() + (1000 * timer_set) : 0; +#else rules_timer[index -1] = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0; +#endif //USE_EXPRESSION } mqtt_data[0] = '\0'; - for (byte i = 0; i < MAX_RULE_TIMERS; i++) { + 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); } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); @@ -594,13 +1151,23 @@ boolean RulesCommand(void) } else if ((CMND_VAR == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) { if (XdrvMailbox.data_len > 0) { +#ifdef USE_EXPRESSION + dtostrfd(evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len), Settings.flag2.calc_resolution, vars[index -1]); +#else strlcpy(vars[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(vars[index -1])); +#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]); } else if ((CMND_MEM == command_code) && (index > 0) && (index <= MAX_RULE_MEMS)) { if (XdrvMailbox.data_len > 0) { +#ifdef USE_EXPRESSION + dtostrfd(evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len), Settings.flag2.calc_resolution, Settings.mems[index -1]); +#else strlcpy(Settings.mems[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(Settings.mems[index -1])); +#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]); } @@ -614,6 +1181,7 @@ boolean RulesCommand(void) if (XdrvMailbox.data_len > 0) { double tempvar = CharToDouble(vars[index -1]) + CharToDouble(XdrvMailbox.data); 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]); } @@ -621,6 +1189,7 @@ boolean RulesCommand(void) if (XdrvMailbox.data_len > 0) { double tempvar = CharToDouble(vars[index -1]) - CharToDouble(XdrvMailbox.data); 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]); } @@ -628,6 +1197,7 @@ boolean RulesCommand(void) if (XdrvMailbox.data_len > 0) { double tempvar = CharToDouble(vars[index -1]) * CharToDouble(XdrvMailbox.data); 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]); } @@ -643,9 +1213,18 @@ boolean RulesCommand(void) double toHigh = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 5)); double value = map_double(valueIN, fromLow, fromHigh, toLow, toHigh); dtostrfd(value, 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]); +#ifdef SUPPORT_MQTT_EVENT + } else if (CMND_SUBSCRIBE == command_code) { //MQTT Subscribe command. Subscribe , [, ] + String result = RulesSubscribe(XdrvMailbox.data, XdrvMailbox.data_len); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, result.c_str()); + } else if (CMND_UNSUBSCRIBE == command_code) { //MQTT Un-subscribe command. UnSubscribe + String result = RulesUnsubscribe(XdrvMailbox.data, XdrvMailbox.data_len); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, result.c_str()); +#endif //SUPPORT_MQTT_EVENT } else serviced = false; // Unknown command @@ -661,9 +1240,9 @@ double map_double(double x, double in_min, double in_max, double out_min, double * Interface \*********************************************************************************************/ -boolean Xdrv10(byte function) +bool Xdrv10(uint8_t function) { - boolean result = false; + bool result = false; switch (function) { case FUNC_PRE_INIT: @@ -687,6 +1266,11 @@ boolean Xdrv10(byte function) case FUNC_RULES_PROCESS: result = RulesProcess(); break; +#ifdef SUPPORT_MQTT_EVENT + case FUNC_MQTT_DATA: + result = RulesMqttData(); + break; +#endif //SUPPORT_MQTT_EVENT } return result; } diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 9095b4efc..5ab0c7c88 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -1,7 +1,7 @@ /* xdrv_11_knx.ino - KNX IP Protocol support for Sonoff-Tasmota - Copyright (C) 2018 Adrian Scillato (https://github.com/ascillato) + Copyright (C) 2019 Adrian Scillato (https://github.com/ascillato) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -39,12 +39,12 @@ Variables in settings.h bool Settings.flag.knx_enabled Enable/Disable KNX Protocol uint16_t Settings.knx_physsical_addr Physical KNX address of this device -byte Settings.knx_GA_registered Number of group address to read -byte Settings.knx_CB_registered Number of group address to write +uint8_t Settings.knx_GA_registered Number of group address to read +uint8_t Settings.knx_CB_registered Number of group address to write uint16_t Settings.knx_GA_addr[MAX_KNX_GA] Group address to read uint16_t Settings.knx_CB_addr[MAX_KNX_CB] Group address to write -byte Settings.knx_GA_param[MAX_KNX_GA] Type of Input (relay changed, button pressed, sensor read) -byte Settings.knx_CB_param[MAX_KNX_CB] Type of Output (set relay, toggle relay, reply sensor value) +uint8_t Settings.knx_GA_param[MAX_KNX_GA] Type of Input (relay changed, button pressed, sensor read) +uint8_t Settings.knx_CB_param[MAX_KNX_CB] Type of Output (set relay, toggle relay, reply sensor value) \*********************************************************************************************/ @@ -61,11 +61,11 @@ address_t KNX_addr; // KNX Address converter variable float last_temp; float last_hum; -byte toggle_inhibit; +uint8_t toggle_inhibit; typedef struct __device_parameters { - byte type; // PARAMETER_ID. Used as type of GA = relay, button, sensor, etc, (INPUTS) + uint8_t type; // PARAMETER_ID. Used as type of GA = relay, button, sensor, etc, (INPUTS) // used when an action on device triggers a MSG to send on KNX // Needed because this is the value that the ESP_KNX_IP library will pass as parameter // to identify the action to perform when a MSG is received @@ -200,9 +200,9 @@ enum KnxCommands { CMND_KNXTXCMND, CMND_KNXTXVAL, CMND_KNX_ENABLED, CMND_KNX_ENH const char kKnxCommands[] PROGMEM = D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" D_CMND_KNX_ENHANCED "|" D_CMND_KNX_PA "|" D_CMND_KNX_GA "|" D_CMND_KNX_CB ; -byte KNX_GA_Search( byte param, byte start = 0 ) +uint8_t KNX_GA_Search( uint8_t param, uint8_t start = 0 ) { - for (byte i = start; i < Settings.knx_GA_registered; ++i) + for (uint8_t i = start; i < Settings.knx_GA_registered; ++i) { if ( Settings.knx_GA_param[i] == param ) { @@ -216,9 +216,9 @@ byte KNX_GA_Search( byte param, byte start = 0 ) } -byte KNX_CB_Search( byte param, byte start = 0 ) +uint8_t KNX_CB_Search( uint8_t param, uint8_t start = 0 ) { - for (byte i = start; i < Settings.knx_CB_registered; ++i) + for (uint8_t i = start; i < Settings.knx_CB_registered; ++i) { if ( Settings.knx_CB_param[i] == param ) { @@ -232,7 +232,7 @@ byte KNX_CB_Search( byte param, byte start = 0 ) } -void KNX_ADD_GA( byte GAop, byte GA_FNUM, byte GA_AREA, byte GA_FDEF ) +void KNX_ADD_GA( uint8_t GAop, uint8_t GA_FNUM, uint8_t GA_AREA, uint8_t GA_FDEF ) { // Check if all GA were assigned. If yes-> return if ( Settings.knx_GA_registered >= MAX_KNX_GA ) { return; } @@ -247,20 +247,19 @@ void KNX_ADD_GA( byte GAop, byte GA_FNUM, byte GA_AREA, byte GA_FDEF ) Settings.knx_GA_registered++; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_ADD " GA #%d: %s " D_TO " %d/%d/%d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_ADD " GA #%d: %s " D_TO " %d/%d/%d"), Settings.knx_GA_registered, device_param_ga[GAop-1], GA_FNUM, GA_AREA, GA_FDEF ); - AddLog(LOG_LEVEL_DEBUG); } -void KNX_DEL_GA( byte GAnum ) +void KNX_DEL_GA( uint8_t GAnum ) { - byte dest_offset = 0; - byte src_offset = 0; - byte len = 0; + uint8_t dest_offset = 0; + uint8_t src_offset = 0; + uint8_t len = 0; // Delete GA Settings.knx_GA_param[GAnum-1] = 0; @@ -291,19 +290,18 @@ void KNX_DEL_GA( byte GAnum ) if (len > 0) { - memmove(Settings.knx_GA_param + dest_offset, Settings.knx_GA_param + src_offset, len * sizeof(byte)); + memmove(Settings.knx_GA_param + dest_offset, Settings.knx_GA_param + src_offset, len * sizeof(uint8_t)); memmove(Settings.knx_GA_addr + dest_offset, Settings.knx_GA_addr + src_offset, len * sizeof(uint16_t)); } Settings.knx_GA_registered--; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_DELETE " GA #%d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_DELETE " GA #%d"), GAnum ); - AddLog(LOG_LEVEL_DEBUG); } -void KNX_ADD_CB( byte CBop, byte CB_FNUM, byte CB_AREA, byte CB_FDEF ) +void KNX_ADD_CB( uint8_t CBop, uint8_t CB_FNUM, uint8_t CB_AREA, uint8_t CB_FDEF ) { // Check if all callbacks were assigned. If yes-> return if ( Settings.knx_CB_registered >= MAX_KNX_CB ) { return; } @@ -330,20 +328,19 @@ void KNX_ADD_CB( byte CBop, byte CB_FNUM, byte CB_AREA, byte CB_FDEF ) Settings.knx_CB_registered++; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_ADD " CB #%d: %d/%d/%d " D_TO " %s"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_ADD " CB #%d: %d/%d/%d " D_TO " %s"), Settings.knx_CB_registered, CB_FNUM, CB_AREA, CB_FDEF, device_param_cb[CBop-1] ); - AddLog(LOG_LEVEL_DEBUG); } -void KNX_DEL_CB( byte CBnum ) +void KNX_DEL_CB( uint8_t CBnum ) { - byte oldparam = Settings.knx_CB_param[CBnum-1]; - byte dest_offset = 0; - byte src_offset = 0; - byte len = 0; + uint8_t oldparam = Settings.knx_CB_param[CBnum-1]; + uint8_t dest_offset = 0; + uint8_t src_offset = 0; + uint8_t len = 0; // Delete assigment knx.callback_unassign(CBnum-1); @@ -375,7 +372,7 @@ void KNX_DEL_CB( byte CBnum ) if (len > 0) { - memmove(Settings.knx_CB_param + dest_offset, Settings.knx_CB_param + src_offset, len * sizeof(byte)); + memmove(Settings.knx_CB_param + dest_offset, Settings.knx_CB_param + src_offset, len * sizeof(uint8_t)); memmove(Settings.knx_CB_addr + dest_offset, Settings.knx_CB_addr + src_offset, len * sizeof(uint16_t)); } @@ -387,15 +384,14 @@ void KNX_DEL_CB( byte CBnum ) device_param[oldparam-1].CB_id = KNX_Empty; } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_DELETE " CB #%d"), CBnum ); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_DELETE " CB #%d"), CBnum ); } bool KNX_CONFIG_NOT_MATCH(void) { // Check for configured parameters that the device does not have (module changed) - for (byte i = 0; i < KNX_MAX_device_param; ++i) + for (uint8_t i = 0; i < KNX_MAX_device_param; ++i) { if ( !device_param[i].show ) { // device has this parameter ? // if not, search for all registered group address to this parameter for deletion @@ -417,7 +413,7 @@ bool KNX_CONFIG_NOT_MATCH(void) } // Check for invalid or erroneous configuration (tasmota flashed without clearing the memory) - for (byte i = 0; i < Settings.knx_GA_registered; ++i) + for (uint8_t i = 0; i < Settings.knx_GA_registered; ++i) { if ( Settings.knx_GA_param[i] != 0 ) // the GA[i] have a parameter defined? { @@ -427,7 +423,7 @@ bool KNX_CONFIG_NOT_MATCH(void) } } } - for (byte i = 0; i < Settings.knx_CB_registered; ++i) + for (uint8_t i = 0; i < Settings.knx_CB_registered; ++i) { if ( Settings.knx_CB_param[i] != 0 ) // the CB[i] have a parameter defined? { @@ -445,8 +441,7 @@ bool KNX_CONFIG_NOT_MATCH(void) void KNXStart(void) { knx.start(nullptr); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_START)); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_START)); } @@ -465,11 +460,11 @@ void KNX_INIT(void) // and activate options according to the hardware /*for (int i = GPIO_REL1; i < GPIO_REL8 + 1; ++i) { - if (GetUsedInModule(i, my_module.gp.io)) { device_param[i - GPIO_REL1].show = true; } + if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_REL1].show = true; } } for (int i = GPIO_REL1_INV; i < GPIO_REL8_INV + 1; ++i) { - if (GetUsedInModule(i, my_module.gp.io)) { device_param[i - GPIO_REL1_INV].show = true; } + if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_REL1_INV].show = true; } }*/ for (int i = 0; i < devices_present; ++i) { @@ -477,30 +472,30 @@ void KNX_INIT(void) } for (int i = GPIO_SWT1; i < GPIO_SWT4 + 1; ++i) { - if (GetUsedInModule(i, my_module.gp.io)) { device_param[i - GPIO_SWT1 + 8].show = true; } + if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_SWT1 + 8].show = true; } } for (int i = GPIO_KEY1; i < GPIO_KEY4 + 1; ++i) { - if (GetUsedInModule(i, my_module.gp.io)) { device_param[i - GPIO_KEY1 + 8].show = true; } + if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_KEY1 + 8].show = true; } } for (int i = GPIO_SWT1_NP; i < GPIO_SWT4_NP + 1; ++i) { - if (GetUsedInModule(i, my_module.gp.io)) { device_param[i - GPIO_SWT1_NP + 8].show = true; } + if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_SWT1_NP + 8].show = true; } } for (int i = GPIO_KEY1_NP; i < GPIO_KEY4_NP + 1; ++i) { - if (GetUsedInModule(i, my_module.gp.io)) { device_param[i - GPIO_KEY1_NP + 8].show = true; } + if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_KEY1_NP + 8].show = true; } } - if (GetUsedInModule(GPIO_DHT11, my_module.gp.io)) { device_param[KNX_TEMPERATURE-1].show = true; } - if (GetUsedInModule(GPIO_DHT22, my_module.gp.io)) { device_param[KNX_TEMPERATURE-1].show = true; } - if (GetUsedInModule(GPIO_SI7021, my_module.gp.io)) { device_param[KNX_TEMPERATURE-1].show = true; } - if (GetUsedInModule(GPIO_DSB, my_module.gp.io)) { device_param[KNX_TEMPERATURE-1].show = true; } - if (GetUsedInModule(GPIO_DHT11, my_module.gp.io)) { device_param[KNX_HUMIDITY-1].show = true; } - if (GetUsedInModule(GPIO_DHT22, my_module.gp.io)) { device_param[KNX_HUMIDITY-1].show = true; } - if (GetUsedInModule(GPIO_SI7021, my_module.gp.io)) { device_param[KNX_HUMIDITY-1].show = true; } + if (GetUsedInModule(GPIO_DHT11, my_module.io)) { device_param[KNX_TEMPERATURE-1].show = true; } + if (GetUsedInModule(GPIO_DHT22, my_module.io)) { device_param[KNX_TEMPERATURE-1].show = true; } + if (GetUsedInModule(GPIO_SI7021, my_module.io)) { device_param[KNX_TEMPERATURE-1].show = true; } + if (GetUsedInModule(GPIO_DSB, my_module.io)) { device_param[KNX_TEMPERATURE-1].show = true; } + if (GetUsedInModule(GPIO_DHT11, my_module.io)) { device_param[KNX_HUMIDITY-1].show = true; } + if (GetUsedInModule(GPIO_DHT22, my_module.io)) { device_param[KNX_HUMIDITY-1].show = true; } + if (GetUsedInModule(GPIO_SI7021, my_module.io)) { device_param[KNX_HUMIDITY-1].show = true; } - // Sonoff 31 or Sonoff Pow or any HLW8012 based device or Sonoff POW R2 or Any device with a Pzem004T - if ( ( SONOFF_S31 == Settings.module ) || ( SONOFF_POW_R2 == Settings.module ) || ( energy_flg != ENERGY_NONE ) ) { + // Any device with a Power Monitoring + if ( energy_flg != ENERGY_NONE ) { device_param[KNX_ENERGY_POWER-1].show = true; device_param[KNX_ENERGY_DAILY-1].show = true; device_param[KNX_ENERGY_START-1].show = true; @@ -522,15 +517,14 @@ void KNX_INIT(void) if (KNX_CONFIG_NOT_MATCH()) { Settings.knx_GA_registered = 0; Settings.knx_CB_registered = 0; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_DELETE " " D_KNX_PARAMETERS )); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_DELETE " " D_KNX_PARAMETERS)); } // Register Group Addresses to listen to // Search on the settings if there is a group address set for receive KNX messages for the type: device_param[j].type // If there is, register the group address on the KNX_IP Library to Receive data for Executing Callbacks - byte j; - for (byte i = 0; i < Settings.knx_CB_registered; ++i) + uint8_t j; + for (uint8_t i = 0; i < Settings.knx_CB_registered; ++i) { j = Settings.knx_CB_param[i]; if ( j > 0 ) @@ -555,22 +549,18 @@ void KNX_CB_Action(message_t const &msg, void *arg) if (msg.data_len == 1) { // COMMAND - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_RECEIVED_FROM " %d.%d.%d " D_COMMAND " %s: %d " D_TO " %s"), - msg.received_on.ga.area, msg.received_on.ga.line, msg.received_on.ga.member, - (msg.ct == KNX_CT_WRITE) ? D_KNX_COMMAND_WRITE : (msg.ct == KNX_CT_READ) ? D_KNX_COMMAND_READ : D_KNX_COMMAND_OTHER, - msg.data[0], - device_param_cb[(chan->type)-1]); + tempchar[0] = msg.data[0]; + tempchar[1] = '\0'; } else { // VALUE float tempvar = knx.data_to_2byte_float(msg.data); dtostrfd(tempvar,2,tempchar); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_RECEIVED_FROM " %d.%d.%d " D_COMMAND " %s: %s " D_TO " %s"), - msg.received_on.ga.area, msg.received_on.ga.line, msg.received_on.ga.member, - (msg.ct == KNX_CT_WRITE) ? D_KNX_COMMAND_WRITE : (msg.ct == KNX_CT_READ) ? D_KNX_COMMAND_READ : D_KNX_COMMAND_OTHER, - tempchar, - device_param_cb[(chan->type)-1]); } - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX D_RECEIVED_FROM " %d.%d.%d " D_COMMAND " %s: %s " D_TO " %s"), + msg.received_on.ga.area, msg.received_on.ga.line, msg.received_on.ga.member, + (msg.ct == KNX_CT_WRITE) ? D_KNX_COMMAND_WRITE : (msg.ct == KNX_CT_READ) ? D_KNX_COMMAND_READ : D_KNX_COMMAND_OTHER, + tempchar, + device_param_cb[(chan->type)-1]); switch (msg.ct) { @@ -652,14 +642,14 @@ void KNX_CB_Action(message_t const &msg, void *arg) } -void KnxUpdatePowerState(byte device, power_t state) +void KnxUpdatePowerState(uint8_t device, power_t state) { if (!(Settings.flag.knx_enabled)) { return; } device_param[device -1].last_state = bitRead(state, device -1); // power state (on/off) // Search all the registered GA that has that output (variable: device) as parameter - byte i = KNX_GA_Search(device); + uint8_t i = KNX_GA_Search(device); while ( i != KNX_Empty ) { KNX_addr.value = Settings.knx_GA_addr[i]; knx.write_1bit(KNX_addr, device_param[device -1].last_state); @@ -668,17 +658,16 @@ void KnxUpdatePowerState(byte device, power_t state) knx.write_1bit(KNX_addr, device_param[device -1].last_state); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "%s = %d " D_SENT_TO " %d.%d.%d"), + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %d " D_SENT_TO " %d.%d.%d"), device_param_ga[device -1], device_param[device -1].last_state, KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - AddLog(LOG_LEVEL_INFO); i = KNX_GA_Search(device, i + 1); } } -void KnxSendButtonPower(byte key, byte device, byte state) +void KnxSendButtonPower(uint8_t key, uint8_t device, uint8_t state) { // key 0 = button_topic // key 1 = switch_topic @@ -692,7 +681,7 @@ void KnxSendButtonPower(byte key, byte device, byte state) // { // Search all the registered GA that has that output (variable: device) as parameter - byte i = KNX_GA_Search(device + 8); + uint8_t i = KNX_GA_Search(device + 8); while ( i != KNX_Empty ) { KNX_addr.value = Settings.knx_GA_addr[i]; knx.write_1bit(KNX_addr, !(state == 0)); @@ -701,10 +690,9 @@ void KnxSendButtonPower(byte key, byte device, byte state) knx.write_1bit(KNX_addr, !(state == 0)); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "%s = %d " D_SENT_TO " %d.%d.%d"), + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %d " D_SENT_TO " %d.%d.%d"), device_param_ga[device + 7], !(state == 0), KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - AddLog(LOG_LEVEL_INFO); i = KNX_GA_Search(device + 8, i + 1); } @@ -712,7 +700,7 @@ void KnxSendButtonPower(byte key, byte device, byte state) } -void KnxSensor(byte sensor_type, float value) +void KnxSensor(uint8_t sensor_type, float value) { if (sensor_type == KNX_TEMPERATURE) { @@ -724,7 +712,7 @@ void KnxSensor(byte sensor_type, float value) if (!(Settings.flag.knx_enabled)) { return; } - byte i = KNX_GA_Search(sensor_type); + uint8_t i = KNX_GA_Search(sensor_type); while ( i != KNX_Empty ) { KNX_addr.value = Settings.knx_GA_addr[i]; knx.write_2byte_float(KNX_addr, value); @@ -733,10 +721,9 @@ void KnxSensor(byte sensor_type, float value) knx.write_2byte_float(KNX_addr, value); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "%s " D_SENT_TO " %d.%d.%d "), + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s " D_SENT_TO " %d.%d.%d "), device_param_ga[sensor_type -1], KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - AddLog(LOG_LEVEL_INFO); i = KNX_GA_Search(sensor_type, i+1); } @@ -752,20 +739,22 @@ void KnxSensor(byte sensor_type, float value) const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX; const char HTTP_BTN_MENU_KNX[] PROGMEM = - "
"; + "

"; const char HTTP_FORM_KNX[] PROGMEM = - "
 " D_KNX_PARAMETERS " 
" + "
" + " " D_KNX_PARAMETERS " " + "" "
" "" D_KNX_PHYSICAL_ADDRESS " " - " . " - " . " - "" + " . " + " . " + "" "

" D_KNX_PHYSICAL_ADDRESS_NOTE "

" - "" D_KNX_ENABLE " " D_KNX_ENABLE "

" @@ -773,23 +762,23 @@ const char HTTP_FORM_KNX2[] PROGMEM = "
" "" D_KNX_GROUP_ADDRESS_TO_WRITE "
" - ""; const char HTTP_FORM_KNX_OPT[] PROGMEM = - ""; + ""; const char HTTP_FORM_KNX_GA[] PROGMEM = - " / " - " / " - " "; + " / " + " / " + " "; const char HTTP_FORM_KNX_ADD_BTN[] PROGMEM = - "

" - ""; + "

" + "
"; const char HTTP_FORM_KNX_ADD_TABLE_ROW[] PROGMEM = - "" - ""; + "" + ""; const char HTTP_FORM_KNX3[] PROGMEM = "
{optex} -> GAfnum / GAarea / GAfdef
%s -> %d / %d / %d

" @@ -797,16 +786,16 @@ const char HTTP_FORM_KNX3[] PROGMEM = "" D_KNX_GROUP_ADDRESS_TO_READ "
"; const char HTTP_FORM_KNX4[] PROGMEM = - "-> "; const char HTTP_FORM_KNX_ADD_TABLE_ROW2[] PROGMEM = - "GAfnum / GAarea / GAfdef -> {optex}" - ""; + "%d / %d / %d -> %s" + ""; void HandleKNXConfiguration(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_KNX); char tmp[100]; @@ -822,13 +811,13 @@ void HandleKNXConfiguration(void) if ( WebServer->arg("btn_add") == "1" ) { stmp = WebServer->arg("GAop"); //option selected - byte GAop = stmp.toInt(); + uint8_t GAop = stmp.toInt(); stmp = WebServer->arg("GA_FNUM"); - byte GA_FNUM = stmp.toInt(); + uint8_t GA_FNUM = stmp.toInt(); stmp = WebServer->arg("GA_AREA"); - byte GA_AREA = stmp.toInt(); + uint8_t GA_AREA = stmp.toInt(); stmp = WebServer->arg("GA_FDEF"); - byte GA_FDEF = stmp.toInt(); + uint8_t GA_FDEF = stmp.toInt(); if (GAop) { KNX_ADD_GA( GAop, GA_FNUM, GA_AREA, GA_FDEF ); @@ -838,13 +827,13 @@ void HandleKNXConfiguration(void) { stmp = WebServer->arg("CBop"); //option selected - byte CBop = stmp.toInt(); + uint8_t CBop = stmp.toInt(); stmp = WebServer->arg("CB_FNUM"); - byte CB_FNUM = stmp.toInt(); + uint8_t CB_FNUM = stmp.toInt(); stmp = WebServer->arg("CB_AREA"); - byte CB_AREA = stmp.toInt(); + uint8_t CB_AREA = stmp.toInt(); stmp = WebServer->arg("CB_FDEF"); - byte CB_FDEF = stmp.toInt(); + uint8_t CB_FDEF = stmp.toInt(); if (CBop) { KNX_ADD_CB( CBop, CB_FNUM, CB_AREA, CB_FDEF ); @@ -855,7 +844,7 @@ void HandleKNXConfiguration(void) { stmp = WebServer->arg("btn_del_ga"); - byte GA_NUM = stmp.toInt(); + uint8_t GA_NUM = stmp.toInt(); KNX_DEL_GA(GA_NUM); @@ -864,139 +853,88 @@ void HandleKNXConfiguration(void) { stmp = WebServer->arg("btn_del_cb"); - byte CB_NUM = stmp.toInt(); + uint8_t CB_NUM = stmp.toInt(); KNX_DEL_CB(CB_NUM); } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_KNX)); - page += FPSTR(HTTP_HEAD_STYLE); - page.replace(F("340px"), F("530px")); - page += FPSTR(HTTP_FORM_KNX); - KNX_physs_addr.value = Settings.knx_physsical_addr; - page.replace(F("{kna"), String(KNX_physs_addr.pa.area)); - page.replace(F("{knl"), String(KNX_physs_addr.pa.line)); - page.replace(F("{knm"), String(KNX_physs_addr.pa.member)); - if ( Settings.flag.knx_enabled ) { page += F(" checked"); } - page += FPSTR(HTTP_FORM_KNX1); - if ( Settings.flag.knx_enable_enhancement ) { page += F(" checked"); } + WSContentStart_P(S_CONFIGURE_KNX); + WSContentSend_P( + PSTR("function GAwarning()" + "{" + "var GA_FNUM=eb('GA_FNUM');" + "var GA_AREA=eb('GA_AREA');" + "var GA_FDEF=eb('GA_FDEF');" + "if(GA_FNUM!=null&&GA_FNUM.value=='0'&&GA_AREA.value=='0'&&GA_FDEF.value=='0'){" + "alert('" D_KNX_WARNING "');" + "}" + "}" + "function CBwarning()" + "{" + "var CB_FNUM=eb('CB_FNUM');" + "var CB_AREA=eb('CB_AREA');" + "var CB_FDEF=eb('CB_FDEF');" + "if(CB_FNUM!=null&&CB_FNUM.value=='0'&&CB_AREA.value=='0'&&CB_FDEF.value=='0'){" + "alert('" D_KNX_WARNING "');" + "}" + "}")); + WSContentSendStyle(); + 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); + if ( Settings.flag.knx_enable_enhancement ) { WSContentSend_P(PSTR(" checked")); } - page += FPSTR(HTTP_FORM_KNX2); - for (byte i = 0; i < KNX_MAX_device_param ; i++) + WSContentSend_P(HTTP_FORM_KNX2); + for (uint8_t i = 0; i < KNX_MAX_device_param ; i++) { if ( device_param[i].show ) { - page += FPSTR(HTTP_FORM_KNX_OPT); - page.replace(F("{vop}"), String(device_param[i].type)); - page.replace(F("{nop}"), String(device_param_ga[i])); + WSContentSend_P(HTTP_FORM_KNX_OPT, device_param[i].type, device_param_ga[i]); } } - page += F(" -> "); - page += FPSTR(HTTP_FORM_KNX_GA); - page.replace(F("GAfnum"), F("GA_FNUM")); - page.replace(F("GAarea"), F("GA_AREA")); - page.replace(F("GAfdef"), F("GA_FDEF")); - page.replace(F("GAfnum"), F("GA_FNUM")); - page.replace(F("GAarea"), F("GA_AREA")); - page.replace(F("GAfdef"), F("GA_FDEF")); - page += FPSTR(HTTP_FORM_KNX_ADD_BTN); - page.replace(F("{btnval}"), String(1)); - if (Settings.knx_GA_registered < MAX_KNX_GA) { - page.replace(F("btndis"), F(" ")); - } - else - { - page.replace(F("btndis"), F("disabled")); - } - page.replace(F("fncbtnadd"), F("GAwarning")); - for (byte i = 0; i < Settings.knx_GA_registered ; ++i) + WSContentSend_P(PSTR(" -> ")); + WSContentSend_P(HTTP_FORM_KNX_GA, "GA_FNUM", "GA_FNUM", "GA_AREA", "GA_AREA", "GA_FDEF", "GA_FDEF"); + WSContentSend_P(HTTP_FORM_KNX_ADD_BTN, "GAwarning", (Settings.knx_GA_registered < MAX_KNX_GA) ? "" : "disabled", 1); + for (uint8_t i = 0; i < Settings.knx_GA_registered ; ++i) { if ( Settings.knx_GA_param[i] ) { - page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW); - page.replace(F("{opval}"), String(i+1)); - page.replace(F("{optex}"), String(device_param_ga[Settings.knx_GA_param[i]-1])); KNX_addr.value = Settings.knx_GA_addr[i]; - page.replace(F("GAfnum"), String(KNX_addr.ga.area)); - page.replace(F("GAarea"), String(KNX_addr.ga.line)); - page.replace(F("GAfdef"), String(KNX_addr.ga.member)); + WSContentSend_P(HTTP_FORM_KNX_ADD_TABLE_ROW, device_param_ga[Settings.knx_GA_param[i]-1], KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member, i +1); } } - page += FPSTR(HTTP_FORM_KNX3); - page += FPSTR(HTTP_FORM_KNX_GA); - page.replace(F("GAfnum"), F("CB_FNUM")); - page.replace(F("GAarea"), F("CB_AREA")); - page.replace(F("GAfdef"), F("CB_FDEF")); - page.replace(F("GAfnum"), F("CB_FNUM")); - page.replace(F("GAarea"), F("CB_AREA")); - page.replace(F("GAfdef"), F("CB_FDEF")); - page += FPSTR(HTTP_FORM_KNX4); - byte j; - for (byte i = 0; i < KNX_MAX_device_param ; i++) + WSContentSend_P(HTTP_FORM_KNX3); + WSContentSend_P(HTTP_FORM_KNX_GA, "CB_FNUM", "CB_FNUM", "CB_AREA", "CB_AREA", "CB_FDEF", "CB_FDEF"); + WSContentSend_P(HTTP_FORM_KNX4); + + uint8_t j; + for (uint8_t i = 0; i < KNX_MAX_device_param ; i++) { // Check How many Relays are available and add: RelayX and TogleRelayX if ( (i > 8) && (i < 16) ) { j=i-8; } else { j=i; } if ( i == 8 ) { j = 0; } if ( device_param[j].show ) { - page += FPSTR(HTTP_FORM_KNX_OPT); - page.replace(F("{vop}"), String(device_param[i].type)); - page.replace(F("{nop}"), String(device_param_cb[i])); + WSContentSend_P(HTTP_FORM_KNX_OPT, device_param[i].type, device_param_cb[i]); } } - page += F(" "); - page += FPSTR(HTTP_FORM_KNX_ADD_BTN); - page.replace(F("{btnval}"), String(2)); - if (Settings.knx_CB_registered < MAX_KNX_CB) { - page.replace(F("btndis"), F(" ")); - } - else - { - page.replace(F("btndis"), F("disabled")); - } - page.replace(F("fncbtnadd"), F("CBwarning")); + WSContentSend_P(PSTR(" ")); + WSContentSend_P(HTTP_FORM_KNX_ADD_BTN, "CBwarning", (Settings.knx_CB_registered < MAX_KNX_CB) ? "" : "disabled", 2); - for (byte i = 0; i < Settings.knx_CB_registered ; ++i) + for (uint8_t i = 0; i < Settings.knx_CB_registered ; ++i) { if ( Settings.knx_CB_param[i] ) { - page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW2); - page.replace(F("{opval}"), String(i+1)); - page.replace(F("{optex}"), String(device_param_cb[Settings.knx_CB_param[i]-1])); KNX_addr.value = Settings.knx_CB_addr[i]; - page.replace(F("GAfnum"), String(KNX_addr.ga.area)); - page.replace(F("GAarea"), String(KNX_addr.ga.line)); - page.replace(F("GAfdef"), String(KNX_addr.ga.member)); + WSContentSend_P(HTTP_FORM_KNX_ADD_TABLE_ROW2, KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member, device_param_cb[Settings.knx_CB_param[i]-1], i +1); } } - page += F("
"); - page += F("
"); - page += FPSTR(HTTP_BTN_CONF); - - page.replace( F(""), - F("function GAwarning()" - "{" - "var GA_FNUM = document.getElementById('GA_FNUM');" - "var GA_AREA = document.getElementById('GA_AREA');" - "var GA_FDEF = document.getElementById('GA_FDEF');" - "if ( GA_FNUM != null && GA_FNUM.value == '0' && GA_AREA.value == '0' && GA_FDEF.value == '0' ) {" - "alert('" D_KNX_WARNING "');" - "}" - "}" - "function CBwarning()" - "{" - "var CB_FNUM = document.getElementById('CB_FNUM');" - "var CB_AREA = document.getElementById('CB_AREA');" - "var CB_FDEF = document.getElementById('CB_FDEF');" - "if ( CB_FNUM != null && CB_FNUM.value == '0' && CB_AREA.value == '0' && CB_FDEF.value == '0' ) {" - "alert('" D_KNX_WARNING "');" - "}" - "}" - "") ); - ShowPage(page); + WSContentSend_P(PSTR("
")); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); } } @@ -1009,9 +947,8 @@ void KNX_Save_Settings(void) Settings.flag.knx_enabled = WebServer->hasArg("b1"); Settings.flag.knx_enable_enhancement = WebServer->hasArg("b2"); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_ENABLED ": %d, " D_KNX_ENHANCEMENT ": %d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_ENABLED ": %d, " D_KNX_ENHANCEMENT ": %d"), Settings.flag.knx_enabled, Settings.flag.knx_enable_enhancement ); - AddLog(LOG_LEVEL_DEBUG); stmp = WebServer->arg("area"); KNX_addr.pa.area = stmp.toInt(); @@ -1021,33 +958,29 @@ void KNX_Save_Settings(void) KNX_addr.pa.member = stmp.toInt(); Settings.knx_physsical_addr = KNX_addr.value; knx.physical_address_set( KNX_addr ); // Set Physical KNX Address of the device - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_KNX_PHYSICAL_ADDRESS ": %d.%d.%d "), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_KNX_PHYSICAL_ADDRESS ": %d.%d.%d "), KNX_addr.pa.area, KNX_addr.pa.line, KNX_addr.pa.member ); - AddLog(LOG_LEVEL_DEBUG); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "GA: %d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX "GA: %d"), Settings.knx_GA_registered ); - AddLog(LOG_LEVEL_DEBUG); - for (byte i = 0; i < Settings.knx_GA_registered ; ++i) + for (uint8_t i = 0; i < Settings.knx_GA_registered ; ++i) { KNX_addr.value = Settings.knx_GA_addr[i]; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "GA #%d: %s " D_TO " %d/%d/%d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX "GA #%d: %s " D_TO " %d/%d/%d"), i+1, device_param_ga[Settings.knx_GA_param[i]-1], KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member ); - AddLog(LOG_LEVEL_DEBUG); + } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "CB: %d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX "CB: %d"), Settings.knx_CB_registered ); - AddLog(LOG_LEVEL_DEBUG); - for (byte i = 0; i < Settings.knx_CB_registered ; ++i) + for (uint8_t i = 0; i < Settings.knx_CB_registered ; ++i) { KNX_addr.value = Settings.knx_CB_addr[i]; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "CB #%d: %d/%d/%d " D_TO " %s"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX "CB #%d: %d/%d/%d " D_TO " %s"), i+1, KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member, device_param_cb[Settings.knx_CB_param[i]-1] ); - AddLog(LOG_LEVEL_DEBUG); } } @@ -1055,7 +988,7 @@ void KNX_Save_Settings(void) #endif // USE_WEBSERVER -boolean KnxCommand(void) +bool KnxCommand(void) { char command[CMDSZ]; uint8_t index = XdrvMailbox.index; @@ -1068,7 +1001,7 @@ boolean KnxCommand(void) // XdrvMailbox.payload <- data to send if (!(Settings.flag.knx_enabled)) { return false; } // Search all the registered GA that has that output (variable: KNX SLOTx) as parameter - byte i = KNX_GA_Search(index + KNX_SLOT1 -1); + uint8_t i = KNX_GA_Search(index + KNX_SLOT1 -1); while ( i != KNX_Empty ) { KNX_addr.value = Settings.knx_GA_addr[i]; knx.write_1bit(KNX_addr, !(XdrvMailbox.payload == 0)); @@ -1077,10 +1010,9 @@ boolean KnxCommand(void) knx.write_1bit(KNX_addr, !(XdrvMailbox.payload == 0)); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "%s = %d " D_SENT_TO " %d.%d.%d"), + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %d " D_SENT_TO " %d.%d.%d"), device_param_ga[index + KNX_SLOT1 -2], !(XdrvMailbox.payload == 0), KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - AddLog(LOG_LEVEL_INFO); i = KNX_GA_Search(index + KNX_SLOT1 -1, i + 1); } @@ -1093,7 +1025,7 @@ boolean KnxCommand(void) // XdrvMailbox.payload <- data to send if (!(Settings.flag.knx_enabled)) { return false; } // Search all the registered GA that has that output (variable: KNX SLOTx) as parameter - byte i = KNX_GA_Search(index + KNX_SLOT1 -1); + uint8_t i = KNX_GA_Search(index + KNX_SLOT1 -1); while ( i != KNX_Empty ) { KNX_addr.value = Settings.knx_GA_addr[i]; @@ -1106,10 +1038,9 @@ boolean KnxCommand(void) knx.write_2byte_float(KNX_addr, tempvar); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "%s = %s " D_SENT_TO " %d.%d.%d"), + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %s " D_SENT_TO " %d.%d.%d"), device_param_ga[index + KNX_SLOT1 -2], XdrvMailbox.data, KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - AddLog(LOG_LEVEL_INFO); i = KNX_GA_Search(index + KNX_SLOT1 -1, i + 1); } @@ -1288,9 +1219,9 @@ boolean KnxCommand(void) * Interface \*********************************************************************************************/ -boolean Xdrv11(byte function) +bool Xdrv11(uint8_t function) { - boolean result = false; + bool result = false; switch (function) { case FUNC_PRE_INIT: KNX_INIT(); @@ -1298,7 +1229,7 @@ boolean Xdrv11(byte function) #ifdef USE_WEBSERVER #ifdef USE_KNX_WEB_MENU case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_KNX, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend_P(HTTP_BTN_MENU_KNX); break; case FUNC_WEB_ADD_HANDLER: WebServer->on("/kn", HandleKNXConfiguration); diff --git a/sonoff/xdrv_12_home_assistant.ino b/sonoff/xdrv_12_home_assistant.ino index 350fe1ca6..5998b3585 100644 --- a/sonoff/xdrv_12_home_assistant.ino +++ b/sonoff/xdrv_12_home_assistant.ino @@ -1,7 +1,7 @@ /* xdrv_12_home_assistant.ino - home assistant support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -67,7 +67,7 @@ const char HASS_DISCOVER_LIGHT_WHITE[] PROGMEM = "%s,\"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] }}\""; + "\"whit_val_tpl\":\"{{value_json.Channel[3]}}\""; const char HASS_DISCOVER_LIGHT_CT[] PROGMEM = "%s,\"clr_temp_cmd_t\":\"%s\"," // cmnd/led2/CT @@ -122,17 +122,30 @@ const char HASS_DISCOVER_SENSOR_ANY[] PROGMEM = "%s,\"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\"," + "\"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\"," "\"device\":{\"identifiers\":[\"%06X\"]," "\"name\":\"%s\"," "\"model\":\"%s\"," "\"sw_version\":\"%s%s\"," - "\"manufacturer\":\"%s\"}"; + "\"manufacturer\":\"Tasmota\"}"; + +const char HASS_DISCOVER_DEVICE_INFO_SHORT[] PROGMEM = + "%s,\"uniq_id\":\"%s\"," + "\"device\":{\"identifiers\":[\"%06X\"]}"; const char HASS_DISCOVER_TOPIC_PREFIX[] PROGMEM = "%s, \"~\":\"%s\""; +uint8_t hass_init_step = 0; +uint8_t hass_mode = 0; +int hass_tele_period = 0; + static void FindPrefix(char* s1, char* s2, char* out) { int prefixlen = 0; @@ -147,12 +160,31 @@ static void Shorten(char** s, char *prefix) { size_t len = strlen(*s); size_t prefixlen = strlen(prefix); - if (len > prefixlen && !strncmp(*s, prefix, prefixlen)) { + if (len > prefixlen && prefixlen != 0 && !strncmp(*s, prefix, prefixlen)) { *s += prefixlen-1; *s[0] = '~'; } } +int try_snprintf_P(char *s, size_t n, 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); + 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); + } + va_end(args); +} + void HAssAnnounceRelayLight(void) { char stopic[TOPSZ]; @@ -169,16 +201,18 @@ void HAssAnnounceRelayLight(void) mqtt_data[0] = '\0'; // Clear retained message - // Clear "other" topic first in case the device has been reconfigured from ligth to switch or vice versa + // Clear "other" topic first in case the device has been reconfigured from light to switch or vice versa snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%d"), ESP.getChipId(), (is_topic_light) ? "RL" : "LI", i); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), (is_topic_light) ? "switch" : "light", unique_id); + snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), + (is_topic_light) ? "switch" : "light", unique_id); MqttPublish(stopic, true); // Clear or Set topic snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%d"), ESP.getChipId(), (is_topic_light) ? "LI" : "RL", i); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), (is_topic_light) ? "light" : "switch", unique_id); + snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), + (is_topic_light) ? "light" : "switch", unique_id); if (Settings.flag.hass_discovery && (i <= devices_present)) { - char name[33]; + char name[33+2]; // friendlyname(33) + " " + index char value_template[33]; char prefix[TOPSZ]; char *command_topic = stemp1; @@ -199,27 +233,31 @@ void HAssAnnounceRelayLight(void) Shorten(&command_topic, prefix); Shorten(&state_topic, prefix); Shorten(&availability_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_RELAY, + + 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); if (is_light) { char *brightness_command_topic = stemp1; GetTopic_P(brightness_command_topic, CMND, mqtt_topic, D_CMND_DIMMER); Shorten(&brightness_command_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_DIMMER, mqtt_data, brightness_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_DIMMER, mqtt_data, 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); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_COLOR, mqtt_data, rgb_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_COLOR, mqtt_data, 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); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_SCHEME, mqtt_data, effect_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_SCHEME, mqtt_data, effect_command_topic, state_topic); } if (LST_RGBW == light_subtype) { @@ -227,28 +265,23 @@ void HAssAnnounceRelayLight(void) GetTopic_P(white_temp_command_topic, CMND, mqtt_topic, D_CMND_WHITE); Shorten(&white_temp_command_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_WHITE, mqtt_data, white_temp_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_WHITE, mqtt_data, 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); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_LIGHT_CT, mqtt_data, color_temp_command_topic, state_topic); + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_LIGHT_CT, mqtt_data, color_temp_command_topic, state_topic); } } - snprintf_P(stemp1, sizeof(stemp1), kModules[Settings.module].name); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_DEVICE_INFO, mqtt_data, - unique_id, ESP.getChipId(), - Settings.friendlyname[0], stemp1, my_version, my_image, "Tasmota"); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); } MqttPublish(stopic, true); } } -void HAssAnnounceButtonSwitch(byte device, char* topic, byte present, byte key, byte toggle) +void HAssAnnounceButtonSwitch(uint8_t device, char* topic, uint8_t present, uint8_t key, uint8_t toggle) { // key 0 = button // key 1 = switch @@ -264,7 +297,7 @@ void HAssAnnounceButtonSwitch(byte device, char* topic, byte present, byte key, snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/binary_sensor/%s/config"), unique_id); if (Settings.flag.hass_discovery && present) { - char name[33]; + char name[33+6]; // friendlyname(33) + " " + "BTN" + " " + index char value_template[33]; char prefix[TOPSZ]; char *state_topic = stemp1; @@ -282,17 +315,15 @@ void HAssAnnounceButtonSwitch(byte device, char* topic, byte present, byte key, FindPrefix(state_topic, availability_topic, prefix); Shorten(&state_topic, prefix); Shorten(&availability_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_BUTTON_SWITCH, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_BUTTON_SWITCH, name, state_topic, Settings.state_text[toggle?2:1], availability_topic); - if (toggle) snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_BUTTON_SWITCH_TOGGLE, mqtt_data); - else snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_BUTTON_SWITCH_ONOFF, mqtt_data, Settings.state_text[0]); + 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]); - snprintf_P(stemp1, sizeof(stemp1), kModules[Settings.module].name); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_DEVICE_INFO, mqtt_data, - unique_id, ESP.getChipId(), - Settings.friendlyname[0], stemp1, my_version, my_image, "Tasmota"); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); } MqttPublish(stopic, true); } @@ -305,11 +336,11 @@ void HAssAnnounceSwitches(void) char *tmp = Settings.switch_topic; Format(sw_topic, tmp, sizeof(sw_topic)); if ((strlen(sw_topic) != 0) && strcmp(sw_topic, "0")) { - for (byte switch_index = 0; switch_index < MAX_SWITCHES; switch_index++) { - byte switch_present = 0; - byte toggle = 1; + for (uint8_t switch_index = 0; switch_index < MAX_SWITCHES; switch_index++) { + uint8_t switch_present = 0; + uint8_t toggle = 1; - if ((pin[GPIO_SWT1 + switch_index] < 99) || (pin[GPIO_SWT1_NP + switch_index] < 99)) { + if (pin[GPIO_SWT1 + switch_index] < 99) { switch_present = 1; } @@ -334,14 +365,14 @@ void HAssAnnounceButtons(void) char *tmp = Settings.button_topic; Format(key_topic, tmp, sizeof(key_topic)); if ((strlen(key_topic) != 0) && strcmp(key_topic, "0")) { - for (byte button_index = 0; button_index < MAX_KEYS; button_index++) { - byte button_present = 0; - byte toggle = 1; + for (uint8_t button_index = 0; button_index < MAX_KEYS; button_index++) { + uint8_t button_present = 0; + uint8_t toggle = 1; - if (!button_index && ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module))) { + if (!button_index && ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type))) { button_present = 1; } else { - if ((pin[GPIO_KEY1 + button_index] < 99) || (pin[GPIO_KEY1_NP + button_index] < 99)) { + if (pin[GPIO_KEY1 + button_index] < 99) { button_present = 1; } } @@ -373,7 +404,7 @@ void HAssAnnounceSensor(const char* sensorname, const char* subsensortype) snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s/config"), unique_id); if (Settings.flag.hass_discovery) { - char name[33]; + char name[33+42]; // friendlyname(33) + " " + sensorname(20?) + " " + sensortype(20?) char prefix[TOPSZ]; char *state_topic = stemp1; char *availability_topic = stemp2; @@ -385,40 +416,40 @@ void HAssAnnounceSensor(const char* sensorname, const char* subsensortype) Shorten(&state_topic, prefix); Shorten(&availability_topic, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR, + 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); if (!strcmp_P(subsensortype, PSTR(D_JSON_TEMPERATURE))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_TEMP, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_TEMP, mqtt_data, TempUnit(), sensorname); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_HUMIDITY))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_HUM, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_HUM, mqtt_data, sensorname); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_PRESSURE))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_PRESS, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_PRESS, mqtt_data, 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))){ - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_KWH, + } 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); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_POWERUSAGE))){ - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_WATT, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_WATT, mqtt_data, sensorname, subsensortype); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_VOLTAGE))){ - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_VOLTAGE, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_VOLTAGE, mqtt_data, sensorname, subsensortype); } else if (!strcmp_P(subsensortype, PSTR(D_JSON_CURRENT))){ - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_AMPERE, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_AMPERE, mqtt_data, sensorname, subsensortype); } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SENSOR_ANY, + try_snprintf_P(mqtt_data, sizeof(mqtt_data)-1, HASS_DISCOVER_SENSOR_ANY, mqtt_data, sensorname, subsensortype); } - snprintf_P(stemp1, sizeof(stemp1), kModules[Settings.module].name); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_DEVICE_INFO, mqtt_data, - unique_id, ESP.getChipId(), - Settings.friendlyname[0], stemp1, my_version, my_image, "Tasmota"); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_TOPIC_PREFIX, mqtt_data, prefix); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + try_snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); } MqttPublish(stopic, true); } @@ -426,6 +457,7 @@ void HAssAnnounceSensor(const char* sensorname, const char* subsensortype) void HAssAnnounceSensors(void) { uint8_t hass_xsns_index = 0; + do { mqtt_data[0] = '\0'; int tele_period_save = tele_period; @@ -433,26 +465,28 @@ void HAssAnnounceSensors(void) XsnsNextCall(FUNC_JSON_APPEND, hass_xsns_index); // ,"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089} tele_period = tele_period_save; - char sensordata[256]; // Copy because we need to write to mqtt_data + char sensordata[256]; // Copy because we need to write to mqtt_data strlcpy(sensordata, mqtt_data, sizeof(sensordata)); if (strlen(sensordata)) { sensordata[0] = '{'; // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089} - snprintf_P(sensordata, sizeof(sensordata), PSTR("%s}"), sensordata); + snprintf_P(sensordata, sizeof(sensordata), PSTR("%s}"), sensordata); // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}} - StaticJsonBuffer<256> jsonBuffer; + // JsonBuffer size calculation (https://arduinojson.org/v5/assistant/) + // 383 = {"MCP230XX":{"D0":0,"D1":0,"D2":0,"D3":0,"D4":0,"D5":0,"D6":0,"D7":0,"D8":0,"D9":0,"D10":0,"D11":0,"D12":0,"D13":0,"D14":0,"D15":0}} + // 381 = {"MPR121A":{"Button0":0,"Button1":0,"Button2":0,"Button3":0,"Button4":0,"Button5":0,"Button6":0,"Button7":0,"Button8":0,"Button9":0,"Button10":0,"Button11":0,"Button12":0}} + // 420 = {"ENERGY":{"TotalStartTime":"2018-10-30T17:09:47","Total":2.684,"Yesterday":0.020,"Today":0.006,"Period":0.04,"Power":0.49,"ApparentPower":4.71,"ReactivePower":4.70,"Factor":0.10,"Frequency":50.04,"Voltage":226.3,"Current":0.021}} + StaticJsonBuffer<500> jsonBuffer; JsonObject& root = jsonBuffer.parseObject(sensordata); if (!root.success()) { - snprintf_P(log_data, sizeof(log_data), PSTR("HASS: failed to parse '%s'"), sensordata); - AddLog(LOG_LEVEL_ERROR); + AddLog_P2(LOG_LEVEL_ERROR, PSTR("HASS: failed to parse '%s'"), sensordata); continue; } for (auto sensor : root) { const char* sensorname = sensor.key; JsonObject& sensors = sensor.value.as(); if (!sensors.success()) { - snprintf_P(log_data, sizeof(log_data), PSTR("HASS: failed to parse '%s'"), sensordata); - AddLog(LOG_LEVEL_ERROR); + AddLog_P2(LOG_LEVEL_ERROR, PSTR("HASS: failed to parse '%s'"), sensordata); continue; } for (auto subsensor : sensors) { @@ -460,32 +494,82 @@ void HAssAnnounceSensors(void) } } } + yield(); } while (hass_xsns_index != 0); } -static int string_ends_with(const char * str, const char * suffix) +void HAssAnnounceStatusSensor(void) { - int str_len = strlen(str); - int suffix_len = strlen(suffix); + char stopic[TOPSZ]; + char stemp1[TOPSZ]; + char stemp2[TOPSZ]; + char unique_id[30]; - return (str_len >= suffix_len) && (0 == strcmp(str + (str_len-suffix_len), suffix)); + // Announce sensor + 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(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s/config"), unique_id); + + if (Settings.flag.hass_discovery) { + char name[33+7]; // friendlyname(33) + " " + "status" + char prefix[TOPSZ]; + char *state_topic = stemp1; + char *availability_topic = stemp2; + + snprintf_P(name, sizeof(name), PSTR("%s %s"), Settings.friendlyname[0], "status"); + 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(), + 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); + } + MqttPublish(stopic, true); } -void HAssDiscovery(uint8_t mode) +void HAssPublishStatus(void) +{ + snprintf_P(mqtt_data, sizeof(mqtt_data), + 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," + "\"" D_JSON_BOOTCOUNT "\":%d,\"" D_JSON_SAVECOUNT "\":%d,\"" D_CMND_IPADDRESS "\":\"%s\"," + "\"" D_JSON_RSSI "\":\"%d\",\"LoadAvg\":%lu}"), + my_version, my_image, GetBuildDateAndTime().c_str(), ESP.getSdkVersion(), ModuleName().c_str(), + GetResetReason().c_str(), GetUptime().c_str(), WifiLinkCount(), WifiDowntime().c_str(), MqttConnectCount(), + Settings.bootcount, Settings.save_flag, WiFi.localIP().toString().c_str(), + WifiGetRssiAsQuality(WiFi.RSSI()), loop_load_avg); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_HASS_STATE)); +} + +void HAssDiscovery(void) { // Configure Tasmota for default Home Assistant parameters to keep discovery message as short as possible if (Settings.flag.hass_discovery) { - Settings.flag.mqtt_response = 0; // Response always as RESULT and not as uppercase command - Settings.flag.decimal_text = 1; // Respond with decimal color values - Settings.flag3.hass_tele_on_power = 1; // send tele/STATE message as stat/RESULT -// Settings.light_scheme = 0; // To just control color it needs to be Scheme 0 - if (!string_ends_with(Settings.mqtt_fulltopic, "%prefix%/")) { + Settings.flag.mqtt_response = 0; // Response always as RESULT and not as uppercase command + Settings.flag.decimal_text = 1; // Respond with decimal color values + Settings.flag3.hass_tele_on_power = 1; // send tele/STATE message as stat/RESULT +// Settings.light_scheme = 0; // To just control color it needs to be Scheme 0 + if (strcmp_P(Settings.mqtt_fulltopic, PSTR("%topic%/%prefix%/"))) { strncpy_P(Settings.mqtt_fulltopic, PSTR("%topic%/%prefix%/"), sizeof(Settings.mqtt_fulltopic)); restart_flag = 2; + return; // As full topic has changed do restart first before sending discovery data } } - if (Settings.flag.hass_discovery || (1 == mode)) { + if (Settings.flag.hass_discovery || (1 == hass_mode)) { // Send info about relays and lights HAssAnnounceRelayLight(); @@ -497,71 +581,48 @@ void HAssDiscovery(uint8_t mode) // Send info about sensors HAssAnnounceSensors(); + + // Send info about status sensor + HAssAnnounceStatusSensor(); } } -/* -#define D_CMND_HASSDISCOVER "HassDiscover" - -enum HassCommands { CMND_HASSDISCOVER }; -const char kHassCommands[] PROGMEM = D_CMND_HASSDISCOVER ; - -boolean HassCommand(void) +void HAssDiscover(void) { - char command[CMDSZ]; - boolean serviced = true; - - int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kHassCommands); - if (-1 == command_code) { - serviced = false; // Unknown command - } - else if (CMND_HASSDISCOVER == command_code) { - if (XdrvMailbox.data_len > 0) { - switch (XdrvMailbox.payload) { - case 0: // Off - case 1: // On - Settings.flag.hass_discovery = XdrvMailbox.payload; - break; - case 2: // Toggle - Settings.flag.hass_discovery ^= 1; - break; - case 4: // Off - case 5: // On - Settings.flag.hass_light = XdrvMailbox.payload &1; - break; - case 6: // Toggle - Settings.flag.hass_light ^= 1; - break; - } - HAssDiscovery(1); - } - snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"Force light\":\"%s\"}"), - command, GetStateText(Settings.flag.hass_discovery), GetStateText(Settings.flag.hass_light)); - } - else serviced = false; // Unknown command - - return serviced; + hass_mode = 1; // Force discovery + hass_init_step = 1; // Delayed discovery } -*/ /*********************************************************************************************\ * Interface \*********************************************************************************************/ -boolean Xdrv12(byte function) +bool Xdrv12(uint8_t function) { - boolean result = false; + bool result = false; if (Settings.flag.mqtt_enabled) { switch (function) { case FUNC_MQTT_INIT: - HAssDiscovery(0); + hass_mode = 0; // Discovery only if Settings.flag.hass_discovery is set + hass_init_step = 2; // Delayed discovery break; -/* - case FUNC_COMMAND: - result = HassCommand(); + case FUNC_EVERY_SECOND: + if (hass_init_step) { + hass_init_step--; + if (!hass_init_step) { + HAssDiscovery(); // Scheduled discovery using available resources + } + } else if (Settings.flag.hass_discovery && Settings.tele_period) { + hass_tele_period++; + if (hass_tele_period >= Settings.tele_period) { + hass_tele_period = 0; + + mqtt_data[0] = '\0'; + HAssPublishStatus(); + } + } break; -*/ } } return result; diff --git a/sonoff/xdrv_13_display.ino b/sonoff/xdrv_13_display.ino index f585f842c..f14680939 100644 --- a/sonoff/xdrv_13_display.ino +++ b/sonoff/xdrv_13_display.ino @@ -1,7 +1,7 @@ /* xdrv_13_display.ino - Display support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -427,13 +427,18 @@ void DisplayText(void) cp += var; DisplayDrawFilledRectangle(disp_xpos, disp_ypos, temp, temp1, color); break; - case 't': { + case 't': if (dp < (linebuf + DISPLAY_BUFFER_COLS) -5) { - snprintf_P(dp, 5, PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute); + snprintf_P(dp, 6, PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute); dp += 5; } break; - } + case 'T': + if (dp < (linebuf + DISPLAY_BUFFER_COLS) -8) { + snprintf_P(dp, 9, PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year%2000); + dp += 8; + } + break; case 'd': // force draw grafics buffer DisplayDrawFrame(); @@ -490,7 +495,7 @@ void DisplayText(void) void DisplayClearScreenBuffer(void) { if (disp_screen_buffer_cols) { - for (byte i = 0; i < disp_screen_buffer_rows; i++) { + for (uint8_t i = 0; i < disp_screen_buffer_rows; i++) { memset(disp_screen_buffer[i], 0, disp_screen_buffer_cols); } } @@ -499,7 +504,7 @@ void DisplayClearScreenBuffer(void) void DisplayFreeScreenBuffer(void) { if (disp_screen_buffer != NULL) { - for (byte i = 0; i < disp_screen_buffer_rows; i++) { + for (uint8_t i = 0; i < disp_screen_buffer_rows; i++) { if (disp_screen_buffer[i] != NULL) { free(disp_screen_buffer[i]); } } free(disp_screen_buffer); @@ -514,7 +519,7 @@ void DisplayAllocScreenBuffer(void) 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) { - for (byte i = 0; i < disp_screen_buffer_rows; i++) { + 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) { DisplayFreeScreenBuffer(); @@ -537,7 +542,7 @@ void DisplayReAllocScreenBuffer(void) void DisplayFillScreen(uint8_t line) { - byte len = disp_screen_buffer_cols - strlen(disp_screen_buffer[line]); + uint8_t len = disp_screen_buffer_cols - strlen(disp_screen_buffer[line]); if (len) { memset(disp_screen_buffer[line] + strlen(disp_screen_buffer[line]), 0x20, len); disp_screen_buffer[line][disp_screen_buffer_cols -1] = 0; @@ -549,7 +554,7 @@ void DisplayFillScreen(uint8_t line) void DisplayClearLogBuffer(void) { if (disp_log_buffer_cols) { - for (byte i = 0; i < DISPLAY_LOG_ROWS; i++) { + for (uint8_t i = 0; i < DISPLAY_LOG_ROWS; i++) { memset(disp_log_buffer[i], 0, disp_log_buffer_cols); } } @@ -558,7 +563,7 @@ void DisplayClearLogBuffer(void) void DisplayFreeLogBuffer(void) { if (disp_log_buffer != NULL) { - for (byte i = 0; i < DISPLAY_LOG_ROWS; i++) { + for (uint8_t i = 0; i < DISPLAY_LOG_ROWS; i++) { if (disp_log_buffer[i] != NULL) { free(disp_log_buffer[i]); } } free(disp_log_buffer); @@ -571,7 +576,7 @@ 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) { - for (byte i = 0; i < DISPLAY_LOG_ROWS; i++) { + 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) { DisplayFreeLogBuffer(); @@ -682,7 +687,7 @@ const char kSensorQuantity[] PROGMEM = D_JSON_CO2 "|" // ppm D_JSON_FREQUENCY ; // Hz -void DisplayJsonValue(const char *topic, const char* device, const char* mkey, const char* value) +void DisplayJsonValue(const char* topic, const char* device, const char* mkey, const char* value) { char quantity[TOPSZ]; char buffer[Settings.display_cols[0] +1]; @@ -690,11 +695,13 @@ void DisplayJsonValue(const char *topic, const char* device, const char* mkey, c char source[Settings.display_cols[0] - Settings.display_cols[1]]; char svalue[Settings.display_cols[1] +1]; +#ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("DisplayJsonValue")); +#endif memset(spaces, 0x20, sizeof(spaces)); spaces[sizeof(spaces) -1] = '\0'; - snprintf_P(source, sizeof(source), PSTR("%s/%s%s"), topic, mkey, spaces); // pow1/Voltage + snprintf_P(source, sizeof(source), PSTR("%s%s%s%s"), topic, (strlen(topic))?"/":"", mkey, spaces); // pow1/Voltage or Voltage if topic is empty (local sensor) int quantity_code = GetCommandCode(quantity, sizeof(quantity), mkey, kSensorQuantity); if ((-1 == quantity_code) || !strcmp_P(mkey, S_RSLT_POWER)) { // Ok: Power, Not ok: POWER @@ -741,8 +748,7 @@ void DisplayJsonValue(const char *topic, const char* device, const char* mkey, c } snprintf_P(buffer, sizeof(buffer), PSTR("%s %s"), source, svalue); -// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "mkey [%s], source [%s], value [%s], quantity_code %d, log_buffer [%s]"), mkey, source, value, quantity_code, buffer); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "mkey [%s], source [%s], value [%s], quantity_code %d, log_buffer [%s]"), mkey, source, value, quantity_code, buffer); DisplayLogBufferAdd(buffer); } @@ -772,8 +778,7 @@ void DisplayAnalyzeJson(char *topic, char *json) tempunit = root[D_JSON_TEMPERATURE_UNIT]; if (tempunit) { snprintf_P(disp_temp, sizeof(disp_temp), PSTR("%s"), tempunit); -// snprintf_P(log_data, sizeof(log_data), disp_temp); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, disp_temp); } for (JsonObject::iterator it = root.begin(); it != root.end(); ++it) { @@ -785,14 +790,23 @@ void DisplayAnalyzeJson(char *topic, char *json) if (value2.is()) { JsonObject& Object3 = value2; for (JsonObject::iterator it3 = Object3.begin(); it3 != Object3.end(); ++it3) { - DisplayJsonValue(topic, it->key, it3->key, it3->value.as()); // Sensor 56% + const char* value = it3->value; + if (value != nullptr) { // "DHT11":{"Temperature":null,"Humidity":null} - ignore null as it will raise exception 28 + DisplayJsonValue(topic, it->key, it3->key, value); // Sensor 56% + } } } else { - DisplayJsonValue(topic, it->key, it2->key, it2->value.as()); // Sensor 56% + const char* value = it2->value; + if (value != nullptr) { + DisplayJsonValue(topic, it->key, it2->key, value); // Sensor 56% + } } } } else { - DisplayJsonValue(topic, it->key, it->key, it->value.as()); // Topic 56% + const char* value = it->value; + if (value != nullptr) { + DisplayJsonValue(topic, it->key, it->key, value); // Topic 56% + } } } } @@ -831,7 +845,7 @@ void DisplayMqttSubscribe(void) } } -boolean DisplayMqttData(void) +bool DisplayMqttData(void) { if (disp_subscribed) { char stopic[TOPSZ]; @@ -853,7 +867,9 @@ boolean DisplayMqttData(void) void DisplayLocalSensor(void) { if ((Settings.display_mode &0x02) && (0 == tele_period)) { - DisplayAnalyzeJson(mqtt_topic, mqtt_data); + char no_topic[1] = { 0 }; +// DisplayAnalyzeJson(mqtt_topic, mqtt_data); // Add local topic + DisplayAnalyzeJson(no_topic, mqtt_data); // Discard any topic } } @@ -867,8 +883,7 @@ void DisplayInitDriver(void) { XdspCall(FUNC_DISPLAY_INIT_DRIVER); -// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "Display model %d"), Settings.display_model); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings.display_model); if (Settings.display_model) { devices_present++; @@ -894,10 +909,10 @@ void DisplaySetPower(void) * Commands \*********************************************************************************************/ -boolean DisplayCommand(void) +bool DisplayCommand(void) { char command [CMDSZ]; - boolean serviced = true; + bool serviced = true; uint8_t disp_len = strlen(D_CMND_DISPLAY); // Prep for string length change if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_DISPLAY), disp_len)) { // Prefix @@ -1062,9 +1077,9 @@ boolean DisplayCommand(void) * Interface \*********************************************************************************************/ -boolean Xdrv13(byte function) +bool Xdrv13(uint8_t function) { - boolean result = false; + bool result = false; if ((i2c_flg || spi_flg || soft_spi_flg) && XdspPresent()) { switch (function) { diff --git a/sonoff/xdrv_14_mp3.ino b/sonoff/xdrv_14_mp3.ino index 973c3fe5e..4e55cddc5 100644 --- a/sonoff/xdrv_14_mp3.ino +++ b/sonoff/xdrv_14_mp3.ino @@ -1,7 +1,7 @@ /* xdrv_14_mp3.ino - MP3 support for Sonoff-Tasmota - Copyright (C) 2018 gemu2015, mike2nl and Theo Arends + Copyright (C) 2019 gemu2015, mike2nl and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -178,9 +178,9 @@ void MP3_CMD(uint8_t mp3cmd,uint16_t val) { * check the MP3 commands \*********************************************************************************************/ -boolean MP3PlayerCmd(void) { +bool MP3PlayerCmd(void) { char command[CMDSZ]; - boolean serviced = true; + bool serviced = true; uint8_t disp_len = strlen(D_CMND_MP3); if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_MP3), disp_len)) { // prefix @@ -226,9 +226,9 @@ boolean MP3PlayerCmd(void) { * Interface \*********************************************************************************************/ -boolean Xdrv14(byte function) +bool Xdrv14(uint8_t function) { - boolean result = false; + bool result = false; if (pin[GPIO_MP3_DFR562] < 99) { switch (function) { diff --git a/sonoff/xdrv_15_pca9685.ino b/sonoff/xdrv_15_pca9685.ino index b29e85a5b..de91a02b4 100644 --- a/sonoff/xdrv_15_pca9685.ino +++ b/sonoff/xdrv_15_pca9685.ino @@ -1,7 +1,7 @@ /* xdrv_15_pca9685.ino - Support for I2C PCA9685 12bit 16 pin hardware PWM driver - Copyright (C) 2018 Andre Thomas and Theo Arends + Copyright (C) 2019 Andre Thomas and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -45,8 +45,7 @@ void PCA9685_Detect(void) if (I2cValidRead8(&buffer, USE_PCA9685_ADDR, PCA9685_REG_MODE1)) { if (0x20 == buffer) { pca9685_detected = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "PCA9685", USE_PCA9685_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "PCA9685", USE_PCA9685_ADDR); PCA9685_Reset(); // Reset the controller } } @@ -101,10 +100,10 @@ void PCA9685_SetPWM(uint8_t pin, uint16_t pwm, bool inverted) { pca9685_pin_pwm_value[pin] = pwm; } -bool PCA9685_Command(void) +bool PCA9685_Command(void) { - boolean serviced = true; - boolean validpin = false; + bool serviced = true; + bool validpin = false; uint8_t paramcount = 0; if (XdrvMailbox.data_len > 0) { paramcount=1; @@ -178,9 +177,9 @@ void PCA9685_OutputTelemetry(bool telemetry) { } } -boolean Xdrv15(byte function) +bool Xdrv15(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xdrv_16_tuyadimmer.ino b/sonoff/xdrv_16_tuyadimmer.ino index eb564a8e8..53c4984cc 100644 --- a/sonoff/xdrv_16_tuyadimmer.ino +++ b/sonoff/xdrv_16_tuyadimmer.ino @@ -1,7 +1,7 @@ /* xdrv_16_tuyadimmer.ino - Tuya dimmer support for Sonoff-Tasmota - Copyright (C) 2018 digiblur, Joel Stein and Theo Arends + Copyright (C) 2019 digiblur, Joel Stein and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -47,7 +47,7 @@ TasmotaSerial *TuyaSerial = nullptr; uint8_t tuya_new_dim = 0; // Tuya dimmer value temp -boolean tuya_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction +bool tuya_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction uint8_t tuya_cmd_status = 0; // Current status of serial-read uint8_t tuya_cmd_checksum = 0; // Checksum of tuya command uint8_t tuya_data_len = 0; // Data lenght of command @@ -106,25 +106,24 @@ void TuyaSendState(uint8_t id, uint8_t type, uint8_t* value){ TuyaSendCmd(TUYA_CMD_SET_DP, payload_buffer, payload_len); } -void TuyaSendBool(uint8_t id, boolean value){ - TuyaSendState(id, TUYA_TYPE_BOOL, &value); +void TuyaSendBool(uint8_t id, bool value){ + TuyaSendState(id, TUYA_TYPE_BOOL, (uint8_t*)&value); } void TuyaSendValue(uint8_t id, uint32_t value){ TuyaSendState(id, TUYA_TYPE_VALUE, (uint8_t*)(&value)); } -boolean TuyaSetPower(void) +bool TuyaSetPower(void) { - boolean status = false; + bool status = false; uint8_t rpower = XdrvMailbox.index; int16_t source = XdrvMailbox.payload; if (source != SRC_SWITCH && TuyaSerial) { // ignore to prevent loop from pushing state from faceplate interaction - snprintf_P(log_data, sizeof(log_data), PSTR("TYA: SetDevicePower.rpower=%d"), rpower); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: SetDevicePower.rpower=%d"), rpower); TuyaSendBool(TUYA_POWER_ID, rpower); @@ -133,7 +132,7 @@ boolean TuyaSetPower(void) return status; } -boolean TuyaSetChannels(void) +bool TuyaSetChannels(void) { LightSerialDuty(((uint8_t*)XdrvMailbox.data)[0]); return true; @@ -146,16 +145,14 @@ void LightSerialDuty(uint8_t duty) duty = 25; // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself } - snprintf_P(log_data, sizeof(log_data), PSTR( "TYA: Send Serial Packet Dim Value=%d (id=%d)"), duty, Settings.param[P_TUYA_DIMMER_ID]); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR( "TYA: Send Serial Packet Dim Value=%d (id=%d)"), duty, Settings.param[P_TUYA_DIMMER_ID]); TuyaSendValue(Settings.param[P_TUYA_DIMMER_ID], duty); } else { tuya_ignore_dim = false; // reset flag - snprintf_P(log_data, sizeof(log_data), PSTR( "TYA: Send Dim Level skipped due to 0 or already set. Value=%d"), duty); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR( "TYA: Send Dim Level skipped due to 0 or already set. Value=%d"), duty); } } @@ -164,8 +161,7 @@ void TuyaRequestState(void){ if(TuyaSerial) { // Get current status of MCU - snprintf_P(log_data, sizeof(log_data), "TYA: Request MCU state"); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Request MCU state")); TuyaSendCmd(TUYA_CMD_QUERY_STATE); } @@ -197,8 +193,7 @@ void TuyaPacketProcess(void) case TUYA_CMD_STATE: if (tuya_buffer[5] == 5) { // on/off packet - snprintf_P(log_data, sizeof(log_data),PSTR("TYA: RX - %s State"),tuya_buffer[10]?"On":"Off"); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX - %s State"),tuya_buffer[10]?"On":"Off"); if((power || Settings.light_dimmer > 0) && (power != tuya_buffer[10])) { ExecuteCommandPower(1, tuya_buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction @@ -206,12 +201,10 @@ void TuyaPacketProcess(void) } else if (tuya_buffer[5] == 8) { // dim packet - snprintf_P(log_data, sizeof(log_data), PSTR("TYA: RX Dim State=%d"), tuya_buffer[13]); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Dim State=%d"), tuya_buffer[13]); if (!Settings.param[P_TUYA_DIMMER_ID]) { - snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Autoconfiguring Dimmer ID %d"), tuya_buffer[6]); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Autoconfiguring Dimmer ID %d"), tuya_buffer[6]); Settings.param[P_TUYA_DIMMER_ID] = tuya_buffer[6]; } @@ -220,8 +213,7 @@ void TuyaPacketProcess(void) snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), tuya_new_dim ); - snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Send CMND_DIMMER_STR=%s"), scmnd ); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send CMND_DIMMER_STR=%s"), scmnd ); tuya_ignore_dim = true; ExecuteCommand(scmnd, SRC_SWITCH); @@ -246,9 +238,9 @@ void TuyaPacketProcess(void) if (tuya_buffer[5] == 2) { uint8_t led1_gpio = tuya_buffer[6]; uint8_t key1_gpio = tuya_buffer[7]; - boolean key1_set = false; - boolean led1_set = false; - for (byte i = 0; i < MAX_GPIO_PIN; i++) { + bool key1_set = false; + bool led1_set = false; + for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { if (Settings.my_gp.io[i] == GPIO_LED1) led1_set = true; else if (Settings.my_gp.io[i] == GPIO_KEY1) key1_set = true; } @@ -273,7 +265,7 @@ void TuyaPacketProcess(void) * API Functions \*********************************************************************************************/ -boolean TuyaModuleSelected(void) +bool TuyaModuleSelected(void) { if (!(pin[GPIO_TUYA_RX] < 99) || !(pin[GPIO_TUYA_TX] < 99)) { // fallback to hardware-serial if not explicitly selected pin[GPIO_TUYA_TX] = 1; @@ -297,8 +289,7 @@ void TuyaInit(void) if (TuyaSerial->begin(9600)) { if (TuyaSerial->hardwareSerial()) { ClaimSerial(); } // Get MCU Configuration - snprintf_P(log_data, sizeof(log_data), "TYA: Request MCU configuration"); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Request MCU configuration")); TuyaSendCmd(TUYA_CMD_MCU_CONF); } @@ -309,7 +300,7 @@ void TuyaSerialInput(void) { while (TuyaSerial->available()) { yield(); - byte serial_in_byte = TuyaSerial->read(); + uint8_t serial_in_byte = TuyaSerial->read(); if (serial_in_byte == 0x55) { // Start TUYA Packet tuya_cmd_status = 1; @@ -361,11 +352,10 @@ void TuyaSerialInput(void) } -boolean TuyaButtonPressed(void) +bool TuyaButtonPressed(void) { if (!XdrvMailbox.index && ((PRESSED == XdrvMailbox.payload) && (NOT_PRESSED == lastbutton[XdrvMailbox.index]))) { - snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Reset GPIO triggered")); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Reset GPIO triggered")); TuyaResetWifi(); return true; // Reset GPIO served here } @@ -387,8 +377,7 @@ void TuyaSetWifiLed(void){ break; } - snprintf_P(log_data, sizeof(log_data), "TYA: Set WiFi LED to state %d (%d)", wifi_state, WifiState()); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Set WiFi LED to state %d (%d)"), wifi_state, WifiState()); TuyaSendCmd(TUYA_CMD_WIFI_STATE, &wifi_state, 1); } @@ -398,11 +387,11 @@ void TuyaSetWifiLed(void){ * Interface \*********************************************************************************************/ -boolean Xdrv16(byte function) +bool Xdrv16(uint8_t function) { - boolean result = false; + bool result = false; - if (TUYA_DIMMER == Settings.module) { + if (TUYA_DIMMER == my_module_type) { switch (function) { case FUNC_MODULE_INIT: result = TuyaModuleSelected(); diff --git a/sonoff/xdrv_17_rcswitch.ino b/sonoff/xdrv_17_rcswitch.ino index cb972e87d..300a156f5 100644 --- a/sonoff/xdrv_17_rcswitch.ino +++ b/sonoff/xdrv_17_rcswitch.ino @@ -1,7 +1,7 @@ /* xdrv_17_rcswitch.ino - RF transceiver using RcSwitch library for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -49,8 +49,7 @@ void RfReceiveCheck(void) int protocol = mySwitch.getReceivedProtocol(); int delay = mySwitch.getReceivedDelay(); - snprintf_P(log_data, sizeof(log_data), PSTR("RFR: Data %lX (%u), Bits %d, Protocol %d, Delay %d"), data, data, bits, protocol, delay); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RFR: Data 0x%lX (%u), Bits %d, Protocol %d, Delay %d"), data, data, bits, protocol, delay); uint32_t now = millis(); if ((now - rf_lasttime > RF_TIME_AVOID_DUPLICATE) && (data > 0)) { @@ -60,7 +59,7 @@ void RfReceiveCheck(void) if (Settings.flag.rf_receive_decimal) { // SetOption28 (0 = hexadecimal, 1 = decimal) snprintf_P(stemp, sizeof(stemp), PSTR("%u"), (uint32_t)data); } else { - snprintf_P(stemp, sizeof(stemp), PSTR("\"%lX\""), (uint32_t)data); + 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}}"), stemp, bits, protocol, delay); @@ -88,10 +87,10 @@ void RfInit(void) * Commands \*********************************************************************************************/ -boolean RfSendCommand(void) +bool RfSendCommand(void) { - boolean serviced = true; - boolean error = false; + bool serviced = true; + bool error = false; if (!strcasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_RFSEND))) { if (XdrvMailbox.data_len) { @@ -116,7 +115,7 @@ boolean RfSendCommand(void) } else { // RFsend data, bits, protocol, repeat, pulse char *p; - byte i = 0; + uint8_t i = 0; for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 5; str = strtok_r(NULL, ", ", &p)) { switch (i++) { case 0: @@ -166,9 +165,9 @@ boolean RfSendCommand(void) * Interface \*********************************************************************************************/ -boolean Xdrv17(byte function) +bool Xdrv17(uint8_t function) { - boolean result = false; + bool result = false; if ((pin[GPIO_RFSEND] < 99) || (pin[GPIO_RFRECV] < 99)) { switch (function) { diff --git a/sonoff/xdrv_18_armtronix_dimmers.ino b/sonoff/xdrv_18_armtronix_dimmers.ino index 795149bff..30af12ce7 100644 --- a/sonoff/xdrv_18_armtronix_dimmers.ino +++ b/sonoff/xdrv_18_armtronix_dimmers.ino @@ -1,7 +1,7 @@ /* xdrv_18_armtronix_dimmers.ino - Armtronix dimmers support for Sonoff-Tasmota - Copyright (C) 2018 wvdv2002 and Theo Arends + Copyright (C) 2019 wvdv2002 and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ TasmotaSerial *ArmtronixSerial = nullptr; -boolean armtronix_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction +bool armtronix_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction int8_t armtronix_wifi_state = -2; // Keep MCU wifi-status in sync with WifiState() int8_t armtronix_dimState[2]; // Dimmer state values. int8_t armtronix_knobState[2]; // Dimmer state values. @@ -40,7 +40,7 @@ int8_t armtronix_knobState[2]; // Dimmer state values. * Internal Functions \*********************************************************************************************/ -boolean ArmtronixSetChannels(void) +bool ArmtronixSetChannels(void) { LightSerial2Duty(((uint8_t*)XdrvMailbox.data)[0], ((uint8_t*)XdrvMailbox.data)[1]); return true; @@ -58,13 +58,11 @@ void LightSerial2Duty(uint8_t duty1, uint8_t duty2) ArmtronixSerial->print("\nDimmer2:"); ArmtronixSerial->println(duty2); - snprintf_P(log_data, sizeof(log_data), PSTR( "ARM: Send Serial Packet Dim Values=%d,%d"), armtronix_dimState[0],armtronix_dimState[1]); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ARM: Send Serial Packet Dim Values=%d,%d"), armtronix_dimState[0],armtronix_dimState[1]); } else { armtronix_ignore_dim = false; - snprintf_P(log_data, sizeof(log_data), PSTR( "ARM: Send Dim Level skipped due to already set. Value=%d,%d"), armtronix_dimState[0],armtronix_dimState[1]); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ARM: Send Dim Level skipped due to already set. Value=%d,%d"), armtronix_dimState[0],armtronix_dimState[1]); } } @@ -73,8 +71,7 @@ void ArmtronixRequestState(void) { if (ArmtronixSerial) { // Get current status of MCU - snprintf_P(log_data, sizeof(log_data), "TYA: Request MCU state"); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("ARM: Request MCU state")); ArmtronixSerial->println("Status"); } @@ -84,7 +81,7 @@ void ArmtronixRequestState(void) * API Functions \*********************************************************************************************/ -boolean ArmtronixModuleSelected(void) +bool ArmtronixModuleSelected(void) { light_type = LT_SERIAL2; return true; @@ -123,8 +120,7 @@ void ArmtronixSerialInput(void) armtronix_ignore_dim = true; snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_CHANNEL "%d %d"),i+1, temp); ExecuteCommand(scmnd,SRC_SWITCH); - snprintf_P(log_data, sizeof(log_data), PSTR("ARM: Send CMND_CHANNEL=%s"), scmnd ); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ARM: Send CMND_CHANNEL=%s"), scmnd ); } commaIndex = answer.indexOf(',',commaIndex+1); } @@ -152,14 +148,13 @@ void ArmtronixSetWifiLed(void) break; } - snprintf_P(log_data, sizeof(log_data), "ARM: Set WiFi LED to state %d (%d)", wifi_state, WifiState()); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ARM: Set WiFi LED to state %d (%d)"), wifi_state, WifiState()); - char state = '0' + (wifi_state & 1 > 0); + char state = '0' + ((wifi_state & 1) > 0); ArmtronixSerial->print("Setled:"); ArmtronixSerial->write(state); ArmtronixSerial->write(','); - state = '0' + (wifi_state & 2 > 0); + state = '0' + ((wifi_state & 2) > 0); ArmtronixSerial->write(state); ArmtronixSerial->write(10); armtronix_wifi_state = WifiState(); @@ -169,11 +164,11 @@ void ArmtronixSetWifiLed(void) * Interface \*********************************************************************************************/ -boolean Xdrv18(byte function) +bool Xdrv18(uint8_t function) { - boolean result = false; + bool result = false; - if (ARMTRONIX_DIMMERS == Settings.module) { + if (ARMTRONIX_DIMMERS == my_module_type) { switch (function) { case FUNC_MODULE_INIT: result = ArmtronixModuleSelected(); diff --git a/sonoff/xdrv_19_ps16dz_dimmer.ino b/sonoff/xdrv_19_ps16dz_dimmer.ino index 7671249eb..e4b71bb18 100644 --- a/sonoff/xdrv_19_ps16dz_dimmer.ino +++ b/sonoff/xdrv_19_ps16dz_dimmer.ino @@ -1,7 +1,7 @@ /* xdrv_19_ps16dz_dimmer.ino - PS_16_DZ dimmer support for Sonoff-Tasmota - Copyright (C) 2018 Joel Stein and Theo Arends + Copyright (C) 2019 Joel Stein and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ TasmotaSerial *PS16DZSerial = nullptr; -boolean ps16dz_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction +bool ps16dz_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction //uint64_t ps16dz_seq = 0; @@ -67,17 +67,16 @@ void PS16DZSendCommand(char type = 0, uint8_t value = 0) break; } - snprintf_P(log_data, sizeof(log_data), PSTR( "PSZ: Send serial command: %s"), ps16dz_tx_buffer ); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PSZ: Send serial command: %s"), ps16dz_tx_buffer ); PS16DZSerial->print(ps16dz_tx_buffer); PS16DZSerial->write(0x1B); PS16DZSerial->flush(); } -boolean PS16DZSetPower(void) +bool PS16DZSetPower(void) { - boolean status = false; + bool status = false; uint8_t rpower = XdrvMailbox.index; int16_t source = XdrvMailbox.payload; @@ -91,7 +90,7 @@ boolean PS16DZSetPower(void) return status; } -boolean PS16DZSetChannels(void) +bool PS16DZSetChannels(void) { PS16DZSerialDuty(((uint8_t*)XdrvMailbox.data)[0]); return true; @@ -109,8 +108,7 @@ void PS16DZSerialDuty(uint8_t duty) } else { ps16dz_ignore_dim = false; // reset flag - snprintf_P(log_data, sizeof(log_data), PSTR( "PSZ: Send Dim Level skipped due to 0 or already set. Value=%d"), duty); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PSZ: Send Dim Level skipped due to 0 or already set. Value=%d"), duty); } } @@ -128,7 +126,7 @@ void PS16DZResetWifi(void) * API Functions \*********************************************************************************************/ -boolean PS16DZModuleSelected(void) +bool PS16DZModuleSelected(void) { light_type = LT_SERIAL1; return true; @@ -153,7 +151,7 @@ void PS16DZSerialInput(void) char scmnd[20]; while (PS16DZSerial->available()) { yield(); - byte serial_in_byte = PS16DZSerial->read(); + uint8_t serial_in_byte = PS16DZSerial->read(); if (serial_in_byte != 0x1B){ if (ps16dz_byte_counter >= PS16DZ_BUFFER_SIZE - 1) { memset(ps16dz_rx_buffer, 0, PS16DZ_BUFFER_SIZE); @@ -165,8 +163,7 @@ void PS16DZSerialInput(void) } else { ps16dz_rx_buffer[ps16dz_byte_counter++] = 0x00; - snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: command received: %s"), ps16dz_rx_buffer); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PSZ: command received: %s"), ps16dz_rx_buffer); if(!strncmp(ps16dz_rx_buffer+3, "UPDATE", 6) || !strncmp(ps16dz_rx_buffer+3, "RESULT", 6)) { char *end_str; char *string = ps16dz_rx_buffer+10; @@ -176,23 +173,20 @@ void PS16DZSerialInput(void) char* token2 = strtok_r(token, ":", &end_token); char* token3 = strtok_r(NULL, ":", &end_token); if(!strncmp(token2, "\"switch\"", 8)){ - boolean ps16dz_power = !strncmp(token3, "\"on\"", 4)?true:false; - snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: power received: %s"), token3); - AddLog(LOG_LEVEL_DEBUG); + bool ps16dz_power = !strncmp(token3, "\"on\"", 4)?true:false; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PSZ: power received: %s"), token3); if((power || Settings.light_dimmer > 0) && (power !=ps16dz_power)) { ExecuteCommandPower(1, ps16dz_power, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction } } else if(!strncmp(token2, "\"bright\"", 8)){ uint8_t ps16dz_bright = atoi(token3); - snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: brightness received: %d"), ps16dz_bright); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PSZ: brightness received: %d"), ps16dz_bright); if(power && ps16dz_bright > 0 && ps16dz_bright != Settings.light_dimmer) { snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), ps16dz_bright ); - snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: Send CMND_DIMMER_STR=%s"), scmnd ); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PSZ: Send CMND_DIMMER_STR=%s"), scmnd ); ps16dz_ignore_dim = true; ExecuteCommand(scmnd, SRC_SWITCH); @@ -200,15 +194,13 @@ void PS16DZSerialInput(void) } else if(!strncmp(token2, "\"sequence\"", 10)){ //ps16dz_seq = strtoull(token3+1, NULL, 10); - snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: sequence received: %s"), token3); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PSZ: sequence received: %s"), token3); } token = strtok_r(NULL, ",", &end_str); } } else if(!strncmp(ps16dz_rx_buffer+3, "SETTING", 7)) { - snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: Reset")); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("PSZ: Reset")); PS16DZResetWifi(); } memset(ps16dz_rx_buffer, 0, PS16DZ_BUFFER_SIZE); @@ -225,11 +217,11 @@ void PS16DZSerialInput(void) * Interface \*********************************************************************************************/ -boolean Xdrv19(byte function) +bool Xdrv19(uint8_t function) { - boolean result = false; + bool result = false; - if (PS_16_DZ == Settings.module) { + if (PS_16_DZ == my_module_type) { switch (function) { case FUNC_MODULE_INIT: result = PS16DZModuleSelected(); diff --git a/sonoff/xdrv_99_debug.ino b/sonoff/xdrv_99_debug.ino new file mode 100644 index 000000000..e9da144b8 --- /dev/null +++ b/sonoff/xdrv_99_debug.ino @@ -0,0 +1,516 @@ +/* + xdrv_99_debug.ino - debug support for Sonoff-Tasmota + + Copyright (C) 2019 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +//#define USE_DEBUG_DRIVER + +#ifdef DEBUG_THEO +#ifndef USE_DEBUG_DRIVER +#define USE_DEBUG_DRIVER +#endif // USE_DEBUG_DRIVER +#endif // DEBUG_THEO + +//#define USE_DEBUG_SETTING_NAMES + +#ifdef USE_DEBUG_DRIVER +/*********************************************************************************************\ + * Virtual debugging support - Part1 + * + * Needs file zzzz_debug.ino due to DEFINE processing +\*********************************************************************************************/ + +#define XDRV_99 99 + +#ifndef CPU_LOAD_CHECK +#define CPU_LOAD_CHECK 1 // Seconds between each CPU_LOAD log +#endif + +/*********************************************************************************************\ + * Debug commands +\*********************************************************************************************/ + +#define D_CMND_CFGDUMP "CfgDump" +#define D_CMND_CFGPOKE "CfgPoke" +#define D_CMND_CFGPEEK "CfgPeek" +#define D_CMND_CFGSHOW "CfgShow" +#define D_CMND_CFGXOR "CfgXor" +#define D_CMND_CPUCHECK "CpuChk" +#define D_CMND_EXCEPTION "Exception" +#define D_CMND_FREEMEM "FreeMem" +#define D_CMND_RTCDUMP "RtcDump" +#define D_CMND_HELP "Help" +#define D_CMND_SETSENSOR "SetSensor" +#define D_CMND_FLASHMODE "FlashMode" + +enum DebugCommands { + CMND_CFGDUMP, CMND_CFGPEEK, CMND_CFGPOKE, CMND_CFGSHOW, CMND_CFGXOR, + CMND_CPUCHECK, CMND_EXCEPTION, CMND_FREEMEM, CMND_RTCDUMP, CMND_SETSENSOR, CMND_FLASHMODE, CMND_HELP }; +const char kDebugCommands[] PROGMEM = + D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" D_CMND_CFGSHOW "|" D_CMND_CFGXOR "|" + D_CMND_CPUCHECK "|" D_CMND_EXCEPTION "|" D_CMND_FREEMEM "|" D_CMND_RTCDUMP "|" D_CMND_SETSENSOR "|" D_CMND_FLASHMODE "|" D_CMND_HELP; + +uint32_t CPU_loops = 0; +uint32_t CPU_last_millis = 0; +uint32_t CPU_last_loop_time = 0; +uint8_t CPU_load_check = 0; +uint8_t CPU_show_freemem = 0; + +/*******************************************************************************************/ + +#ifdef DEBUG_THEO +void ExceptionTest(uint8_t type) +{ +/* +Exception (28): +epc1=0x4000bf64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000007 depc=0x00000000 + +ctx: cont +sp: 3fff1f30 end: 3fff2840 offset: 01a0 + +>>>stack>>> +3fff20d0: 202c3573 756f7247 2c302070 646e4920 +3fff20e0: 40236a6e 7954202c 45206570 00454358 +3fff20f0: 00000010 00000007 00000000 3fff2180 +3fff2100: 3fff2190 40107bfc 3fff3e4c 3fff22c0 +3fff2110: 40261934 000000f0 3fff22c0 401004d8 +3fff2120: 40238fcf 00000050 3fff2100 4021fc10 +3fff2130: 3fff32bc 4021680c 3ffeade1 4021ff7d +3fff2140: 3fff2190 3fff2180 0000000c 7fffffff +3fff2150: 00000019 00000000 00000000 3fff21c0 +3fff2160: 3fff23f3 3ffe8e08 00000000 4021ffb4 +3fff2170: 3fff2190 3fff2180 0000000c 40201118 +3fff2180: 3fff21c0 0000003c 3ffef840 00000007 +3fff2190: 00000000 00000000 00000000 40201128 +3fff21a0: 3fff23f3 000000f1 3fff23ec 4020fafb +3fff21b0: 3fff23f3 3fff21c0 3fff21d0 3fff23f6 +3fff21c0: 00000000 3fff23fb 4022321b 00000000 + +Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads +Decoding 14 results +0x40236a6e: ets_vsnprintf at ?? line ? +0x40107bfc: vsnprintf at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/libc_replacements.c line 387 +0x40261934: bignum_exptmod at ?? line ? +0x401004d8: malloc at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1664 +0x40238fcf: wifi_station_get_connect_status at ?? line ? +0x4021fc10: operator new[](unsigned int) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/abi.cpp line 57 +0x4021680c: ESP8266WiFiSTAClass::status() at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WiFi\src/ESP8266WiFiSTA.cpp line 569 +0x4021ff7d: vsnprintf_P(char*, unsigned int, char const*, __va_list_tag) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146 +0x4021ffb4: snprintf_P(char*, unsigned int, char const*, ...) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146 +0x40201118: atol at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45 +0x40201128: atoi at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45 +0x4020fafb: MqttDataHandler(char*, unsigned char*, unsigned int) at R:\Arduino\Work-ESP8266\Theo\sonoff\sonoff-4\sonoff/sonoff.ino line 679 (discriminator 1) +0x4022321b: pp_attach at ?? line ? + +00:00:08 MQTT: tele/sonoff/INFO3 = {"Started":"Fatal exception:28 flag:2 (EXCEPTION) epc1:0x4000bf64 epc2:0x00000000 epc3:0x00000000 excvaddr:0x00000007 depc:0x00000000"} +*/ + if (1 == type) { + char svalue[10]; + snprintf_P(svalue, sizeof(svalue), PSTR("%s"), 7); // Exception 28 as number in string (7 in excvaddr) + } +/* +14:50:52 osWatch: FreeRam 25896, rssi 68, last_run 0 +14:51:02 osWatch: FreeRam 25896, rssi 58, last_run 0 +14:51:03 CMND: exception 2 +14:51:12 osWatch: FreeRam 25360, rssi 60, last_run 8771 +14:51:22 osWatch: FreeRam 25360, rssi 62, last_run 18771 +14:51:32 osWatch: FreeRam 25360, rssi 62, last_run 28771 +14:51:42 osWatch: FreeRam 25360, rssi 62, last_run 38771 +14:51:42 osWatch: Warning, loop blocked. Restart now +*/ + if (2 == type) { + while(1) delay(1000); // this will trigger the os watch + } +} + +#endif // DEBUG_THEO + +/*******************************************************************************************/ + +void CpuLoadLoop(void) +{ + CPU_last_loop_time = millis(); + if (CPU_load_check && CPU_last_millis) { + CPU_loops ++; + if ((CPU_last_millis + (CPU_load_check *1000)) <= CPU_last_loop_time) { +#if defined(F_CPU) && (F_CPU == 160000000L) + int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *800) ); + CPU_loops = CPU_loops / CPU_load_check; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(160MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops); +#else + int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *400) ); + CPU_loops = CPU_loops / CPU_load_check; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(80MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops); +#endif + CPU_last_millis = CPU_last_loop_time; + CPU_loops = 0; + } + } +} + +/*******************************************************************************************/ + +#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) +// All version before core 2.4.2 +// https://github.com/esp8266/Arduino/issues/2557 + +extern "C" { +#include + extern cont_t g_cont; +} + +void DebugFreeMem(void) +{ + register uint32_t *sp asm("a1"); + +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d, UnmodifiedStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_cont.stack), cont_get_free_stack(&g_cont), XdrvMailbox.data); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_cont.stack), XdrvMailbox.data); +} + +#else +// All version from core 2.4.2 +// https://github.com/esp8266/Arduino/pull/5018 +// https://github.com/esp8266/Arduino/pull/4553 + +extern "C" { +#include + extern cont_t* g_pcont; +} + +void DebugFreeMem(void) +{ + register uint32_t *sp asm("a1"); + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_pcont->stack), XdrvMailbox.data); +} + +#endif // ARDUINO_ESP8266_RELEASE_2_x_x + +/*******************************************************************************************/ + +void DebugRtcDump(char* parms) +{ + #define CFG_COLS 16 + + uint16_t idx; + uint16_t maxrow; + uint16_t row; + uint16_t col; + char *p; + + // |<--SDK data (256 bytes)-->|<--User data (512 bytes)-->| + // 000 - 0FF: SDK + // 000 - 01B: SDK rst_info + // 100 - 2FF: User + // 280 - 283: Tasmota RtcReboot (Offset 100 (x 4bytes) - sizeof(RTCRBT) (x 4bytes)) + // 290 - 2EB: Tasmota RtcSettings (Offset 100 (x 4bytes)) + + uint8_t buffer[768]; +// ESP.rtcUserMemoryRead(0, (uint32_t*)&buffer, sizeof(buffer)); + system_rtc_mem_read(0, (uint32_t*)&buffer, sizeof(buffer)); + + maxrow = ((sizeof(buffer)+CFG_COLS)/CFG_COLS); + + uint16_t srow = strtol(parms, &p, 16) / CFG_COLS; + uint16_t mrow = strtol(p, &p, 10); + +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Cnfg: Parms %s, Start row %d, rows %d"), parms, srow, mrow); + + if (0 == mrow) { // Default only 8 lines + mrow = 8; + } + if (srow > maxrow) { + srow = maxrow - mrow; + } + if (mrow < (maxrow - srow)) { + maxrow = srow + mrow; + } + + for (row = srow; row < maxrow; row++) { + idx = row * CFG_COLS; + snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx); + for (col = 0; col < CFG_COLS; col++) { + if (!(col%4)) { + snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data); + for (col = 0; col < CFG_COLS; col++) { +// if (!(col%4)) { +// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); +// } + snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data); + AddLog(LOG_LEVEL_INFO); + } +} + +/*******************************************************************************************/ + +void DebugCfgDump(char* parms) +{ + #define CFG_COLS 16 + + uint16_t idx; + uint16_t maxrow; + uint16_t row; + uint16_t col; + char *p; + + uint8_t *buffer = (uint8_t *) &Settings; + maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS); + + uint16_t srow = strtol(parms, &p, 16) / CFG_COLS; + uint16_t mrow = strtol(p, &p, 10); + +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Cnfg: Parms %s, Start row %d, rows %d"), parms, srow, mrow); + + if (0 == mrow) { // Default only 8 lines + mrow = 8; + } + if (srow > maxrow) { + srow = maxrow - mrow; + } + if (mrow < (maxrow - srow)) { + maxrow = srow + mrow; + } + + for (row = srow; row < maxrow; row++) { + idx = row * CFG_COLS; + snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx); + for (col = 0; col < CFG_COLS; col++) { + if (!(col%4)) { + snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data); + for (col = 0; col < CFG_COLS; col++) { +// if (!(col%4)) { +// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); +// } + snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data); + AddLog(LOG_LEVEL_INFO); + delay(1); + } +} + +void DebugCfgPeek(char* parms) +{ + char *p; + + uint16_t address = strtol(parms, &p, 16); + if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4; + address = (address >> 2) << 2; + + uint8_t *buffer = (uint8_t *) &Settings; + uint8_t data8 = buffer[address]; + uint16_t data16 = (buffer[address +1] << 8) + buffer[address]; + uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + data16; + + snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), address); + for (uint8_t i = 0; i < 4; i++) { + snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[address +i]); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data); + for (uint8_t i = 0; i < 4; i++) { + snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[address +i] > 0x20) && (buffer[address +i] < 0x7F)) ? (char)buffer[address +i] : ' '); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s| 0x%02X (%d), 0x%04X (%d), 0x%0LX (%lu)"), log_data, data8, data8, data16, data16, data32, data32); + AddLog(LOG_LEVEL_INFO); +} + +void DebugCfgPoke(char* parms) +{ + char *p; + + uint16_t address = strtol(parms, &p, 16); + if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4; + address = (address >> 2) << 2; + + uint32_t data = strtol(p, &p, 16); + + uint8_t *buffer = (uint8_t *) &Settings; + uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address]; + + uint8_t *nbuffer = (uint8_t *) &data; + for (uint8_t i = 0; i < 4; i++) { buffer[address +i] = nbuffer[+i]; } + + uint32_t ndata32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address]; + + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: 0x%0LX (%lu) poked to 0x%0LX (%lu)"), address, data32, data32, ndata32, ndata32); +} + +#ifdef USE_DEBUG_SETTING_NAMES +void DebugCfgShow(uint8_t more) +{ + uint8_t *SetAddr; + SetAddr = (uint8_t *)&Settings; + + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: Hostname (%d) [%s]"), (uint8_t *)&Settings.hostname - SetAddr, sizeof(Settings.hostname)-1, Settings.hostname); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: SSids (%d) [%s], [%s]"), (uint8_t *)&Settings.sta_ssid - SetAddr, sizeof(Settings.sta_ssid[0])-1, Settings.sta_ssid[0], Settings.sta_ssid[1]); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: Friendlynames (%d) [%s], [%s], [%s], [%s]"), (uint8_t *)&Settings.friendlyname - SetAddr, sizeof(Settings.friendlyname[0])-1, Settings.friendlyname[0], Settings.friendlyname[1], Settings.friendlyname[2], Settings.friendlyname[3]); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: OTA Url (%d) [%s]"), (uint8_t *)&Settings.ota_url - SetAddr, sizeof(Settings.ota_url)-1, Settings.ota_url); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: StateText (%d) [%s], [%s], [%s], [%s]"), (uint8_t *)&Settings.state_text - SetAddr, sizeof(Settings.state_text[0])-1, Settings.state_text[0], Settings.state_text[1], Settings.state_text[2], Settings.state_text[3]); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: Syslog Host (%d) [%s]"), (uint8_t *)&Settings.syslog_host - SetAddr, sizeof(Settings.syslog_host)-1, Settings.syslog_host); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: NTP Servers (%d) [%s], [%s], [%s]"), (uint8_t *)&Settings.ntp_server - SetAddr, sizeof(Settings.ntp_server[0])-1, Settings.ntp_server[0], Settings.ntp_server[1], Settings.ntp_server[2]); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT Host (%d) [%s]"), (uint8_t *)&Settings.mqtt_host - SetAddr, sizeof(Settings.mqtt_host)-1, Settings.mqtt_host); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT Client (%d) [%s]"), (uint8_t *)&Settings.mqtt_client - SetAddr, sizeof(Settings.mqtt_client)-1, Settings.mqtt_client); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT User (%d) [%s]"), (uint8_t *)&Settings.mqtt_user - SetAddr, sizeof(Settings.mqtt_user)-1, Settings.mqtt_user); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT FullTopic (%d) [%s]"), (uint8_t *)&Settings.mqtt_fulltopic - SetAddr, sizeof(Settings.mqtt_fulltopic)-1, Settings.mqtt_fulltopic); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT Topic (%d) [%s]"), (uint8_t *)&Settings.mqtt_topic - SetAddr, sizeof(Settings.mqtt_topic)-1, Settings.mqtt_topic); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT GroupTopic (%d) [%s]"), (uint8_t *)&Settings.mqtt_grptopic - SetAddr, sizeof(Settings.mqtt_grptopic)-1, Settings.mqtt_grptopic); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT ButtonTopic (%d) [%s]"), (uint8_t *)&Settings.button_topic - SetAddr, sizeof(Settings.button_topic)-1, Settings.button_topic); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT SwitchTopic (%d) [%s]"), (uint8_t *)&Settings.switch_topic - SetAddr, sizeof(Settings.switch_topic)-1, Settings.switch_topic); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT Prefixes (%d) [%s], [%s], [%s]"), (uint8_t *)&Settings.mqtt_prefix - SetAddr, sizeof(Settings.mqtt_prefix[0])-1, Settings.mqtt_prefix[0], Settings.mqtt_prefix[1], Settings.mqtt_prefix[2]); + if (17 == more) { + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: AP Passwords (%d) [%s], [%s]"), (uint8_t *)&Settings.sta_pwd - SetAddr, sizeof(Settings.sta_pwd[0])-1, Settings.sta_pwd[0], Settings.sta_pwd[1]); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: MQTT Password (%d) [%s]"), (uint8_t *)&Settings.mqtt_pwd - SetAddr, sizeof(Settings.mqtt_pwd)-1, Settings.mqtt_pwd); + AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: Web Password (%d) [%s]"), (uint8_t *)&Settings.web_password - SetAddr, sizeof(Settings.web_password)-1, Settings.web_password); + } +} +#endif // USE_DEBUG_SETTING_NAMES + +void SetFlashMode(uint8_t mode) +{ + uint8_t *_buffer; + uint32_t address; + + address = 0; + _buffer = new uint8_t[FLASH_SECTOR_SIZE]; + + if (ESP.flashRead(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE)) { + if (_buffer[2] != mode) { // DOUT + _buffer[2] = mode; + if (ESP.flashEraseSector(address / FLASH_SECTOR_SIZE)) ESP.flashWrite(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE); + } + } + delete[] _buffer; +} + +/*******************************************************************************************/ + +bool DebugCommand(void) +{ + char command[CMDSZ]; + bool serviced = true; + + int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kDebugCommands); + if (-1 == command_code) { + serviced = false; // Unknown command + } + 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); + } + else if (CMND_RTCDUMP == command_code) { + DebugRtcDump(XdrvMailbox.data); + snprintf_P(mqtt_data, sizeof(mqtt_data), 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); + } + else if (CMND_CFGPEEK == command_code) { + DebugCfgPeek(XdrvMailbox.data); + snprintf_P(mqtt_data, sizeof(mqtt_data), 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); + } +#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); + } +#endif // USE_DEBUG_SETTING_NAMES +#ifdef USE_WEBSERVER + else if (CMND_CFGXOR == command_code) { + 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); + } +#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); + } +#endif // DEBUG_THEO + else if (CMND_CPUCHECK == command_code) { + if (XdrvMailbox.data_len > 0) { + 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); + } + 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); + } + 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()); + } + 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()); + } + else serviced = false; // Unknown command + + return serviced; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +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_COMMAND: + result = DebugCommand(); + break; + case FUNC_FREE_MEM: + if (CPU_show_freemem) { DebugFreeMem(); } + break; + } + return result; +} + +#endif // USE_DEBUG_DRIVER \ No newline at end of file diff --git a/sonoff/xdrv_interface.ino b/sonoff/xdrv_interface.ino index 0ec3696d9..7de5e1bb5 100644 --- a/sonoff/xdrv_interface.ino +++ b/sonoff/xdrv_interface.ino @@ -1,7 +1,7 @@ /* xdrv_interface.ino - Driver interface support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends inspired by ESPEasy + Copyright (C) 2019 Theo Arends inspired by ESPEasy This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,9 +18,9 @@ */ #ifdef XFUNC_PTR_IN_ROM -boolean (* const xdrv_func_ptr[])(byte) PROGMEM = { // Driver Function Pointers +bool (* const xdrv_func_ptr[])(uint8_t) PROGMEM = { // Driver Function Pointers #else -boolean (* const xdrv_func_ptr[])(byte) = { // Driver Function Pointers +bool (* const xdrv_func_ptr[])(uint8_t) = { // Driver Function Pointers #endif #ifdef XDRV_01 @@ -192,21 +192,7 @@ boolean (* const xdrv_func_ptr[])(byte) = { // Driver Function Pointers const uint8_t xdrv_present = sizeof(xdrv_func_ptr) / sizeof(xdrv_func_ptr[0]); // Number of drivers found -boolean XdrvCommand(uint8_t grpflg, char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, uint16_t payload16) -{ -// XdrvMailbox.valid = 1; - XdrvMailbox.index = index; - XdrvMailbox.data_len = data_len; - XdrvMailbox.payload16 = payload16; - XdrvMailbox.payload = payload; - XdrvMailbox.grpflg = grpflg; - XdrvMailbox.topic = type; - XdrvMailbox.data = dataBuf; - - return XdrvCall(FUNC_COMMAND); -} - -boolean XdrvMqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t sdataBuf) +bool XdrvMqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t sdataBuf) { XdrvMailbox.index = stopicBuf; XdrvMailbox.data_len = sdataBuf; @@ -216,11 +202,12 @@ boolean XdrvMqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t return XdrvCall(FUNC_MQTT_DATA); } -boolean XdrvRulesProcess(void) +bool XdrvRulesProcess(void) { return XdrvCall(FUNC_RULES_PROCESS); } +#ifdef USE_DEBUG_DRIVER void ShowFreeMem(const char *where) { char stemp[20]; @@ -228,19 +215,32 @@ void ShowFreeMem(const char *where) XdrvMailbox.data = stemp; XdrvCall(FUNC_FREE_MEM); } +#endif /*********************************************************************************************\ * Function call to all xdrv \*********************************************************************************************/ -boolean XdrvCall(byte Function) +bool XdrvCall(uint8_t Function) { - boolean result = false; + bool result = false; - for (byte x = 0; x < xdrv_present; x++) { + for (uint8_t x = 0; x < xdrv_present; x++) { // WifiAddDelayWhenDisconnected(); result = xdrv_func_ptr[x](Function); - if (result) break; + + if (result && ((FUNC_COMMAND == Function) || + (FUNC_COMMAND_DRIVER == Function) || + (FUNC_MQTT_DATA == Function) || + (FUNC_RULES_PROCESS == Function) || + (FUNC_BUTTON_PRESSED == Function) || + (FUNC_SERIAL == Function) || + (FUNC_MODULE_INIT == Function) || + (FUNC_SET_CHANNELS == Function) || + (FUNC_SET_DEVICE_POWER == Function) + )) { + break; + } } return result; diff --git a/sonoff/xdsp_01_lcd.ino b/sonoff/xdsp_01_lcd.ino index 60fe0bab6..28d045858 100644 --- a/sonoff/xdsp_01_lcd.ino +++ b/sonoff/xdsp_01_lcd.ino @@ -1,7 +1,7 @@ /* xdsp_01_lcd.ino - Display LCD support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends and Adafruit + Copyright (C) 2019 Theo Arends and Adafruit This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -97,24 +97,29 @@ void LcdDisplayOnOff(uint8_t on) #ifdef USE_DISPLAY_MODES1TO5 -void LcdCenter(byte row, char* txt) +void LcdCenter(uint8_t row, char* txt) { - int offset; - int len; char line[Settings.display_cols[0] +2]; + int len = strlen(txt); + int offset = 0; + if (len >= Settings.display_cols[0]) { + len = Settings.display_cols[0]; + } else { + offset = (Settings.display_cols[0] - len) / 2; + } memset(line, 0x20, Settings.display_cols[0]); line[Settings.display_cols[0]] = 0; - len = strlen(txt); - offset = (len < Settings.display_cols[0]) ? offset = (Settings.display_cols[0] - len) / 2 : 0; - strlcpy(line +offset, txt, len); + for (uint8_t i = 0; i < len; i++) { + line[offset +i] = txt[i]; + } lcd->setCursor(0, row); lcd->print(line); } -boolean LcdPrintLog(void) +bool LcdPrintLog(void) { - boolean result = false; + bool result = false; disp_refresh--; if (!disp_refresh) { @@ -125,7 +130,7 @@ boolean LcdPrintLog(void) if (txt != NULL) { uint8_t last_row = Settings.display_rows -1; - for (byte i = 0; i < last_row; i++) { + for (uint8_t i = 0; i < last_row; i++) { strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); lcd->setCursor(0, i); // Col 0, Row i lcd->print(disp_screen_buffer[i +1]); @@ -133,8 +138,7 @@ boolean LcdPrintLog(void) strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); DisplayFillScreen(last_row); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); lcd->setCursor(0, last_row); lcd->print(disp_screen_buffer[last_row]); @@ -181,9 +185,9 @@ void LcdRefresh(void) // Every second * Interface \*********************************************************************************************/ -boolean Xdsp01(byte function) +bool Xdsp01(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { if (FUNC_DISPLAY_INIT_DRIVER == function) { diff --git a/sonoff/xdsp_02_ssd1306.ino b/sonoff/xdsp_02_ssd1306.ino index 4ccdcd9c9..9697e4db0 100644 --- a/sonoff/xdsp_02_ssd1306.ino +++ b/sonoff/xdsp_02_ssd1306.ino @@ -1,7 +1,7 @@ /* xdsp_02_ssd1306.ino - Display Oled ssd1306 support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends and Adafruit + Copyright (C) 2019 Theo Arends and Adafruit This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -147,15 +147,14 @@ void Ssd1306PrintLog(void) oled->clearDisplay(); oled->setTextSize(Settings.display_size); oled->setCursor(0,0); - for (byte i = 0; i < last_row; i++) { + for (uint8_t i = 0; i < last_row; i++) { strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); oled->println(disp_screen_buffer[i]); } strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); DisplayFillScreen(last_row); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); oled->println(disp_screen_buffer[last_row]); oled->display(); @@ -200,9 +199,9 @@ void Ssd1306Refresh(void) // Every second * Interface \*********************************************************************************************/ -boolean Xdsp02(byte function) +bool Xdsp02(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { if (FUNC_DISPLAY_INIT_DRIVER == function) { diff --git a/sonoff/xdsp_03_matrix.ino b/sonoff/xdsp_03_matrix.ino index da458cb15..2535c92d9 100644 --- a/sonoff/xdsp_03_matrix.ino +++ b/sonoff/xdsp_03_matrix.ino @@ -1,7 +1,7 @@ /* xdsp_03_matrix.ino - Display 8x8 matrix support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends and Adafruit + Copyright (C) 2019 Theo Arends and Adafruit This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -47,14 +47,14 @@ uint8_t mtx_done = 0; void MatrixWrite(void) { - for (byte i = 0; i < mtx_matrices; i++) { + for (uint8_t i = 0; i < mtx_matrices; i++) { matrix[i]->writeDisplay(); } } void MatrixClear(void) { - for (byte i = 0; i < mtx_matrices; i++) { + for (uint8_t i = 0; i < mtx_matrices; i++) { matrix[i]->clear(); } MatrixWrite(); @@ -62,7 +62,7 @@ void MatrixClear(void) void MatrixFixed(char* txt) { - for (byte i = 0; i < mtx_matrices; i++) { + for (uint8_t i = 0; i < mtx_matrices; i++) { matrix[i]->clear(); matrix[i]->setCursor(-i *8, 0); matrix[i]->print(txt); @@ -77,7 +77,7 @@ void MatrixCenter(char* txt) int len = strlen(txt); offset = (len < 8) ? offset = ((mtx_matrices *8) - (len *6)) / 2 : 0; - for (byte i = 0; i < mtx_matrices; i++) { + for (uint8_t i = 0; i < mtx_matrices; i++) { matrix[i]->clear(); matrix[i]->setCursor(-(i *8)+offset, 0); matrix[i]->print(txt); @@ -94,15 +94,14 @@ void MatrixScrollLeft(char* txt, int loop) // Horiz. position of text -- starts off right edge mtx_x = 8 * mtx_matrices; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), txt); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), txt); disp_refresh = Settings.display_refresh; case 2: disp_refresh--; if (!disp_refresh) { disp_refresh = Settings.display_refresh; - for (byte i = 0; i < mtx_matrices; i++) { + for (uint8_t i = 0; i < mtx_matrices; i++) { matrix[i]->clear(); matrix[i]->setCursor(mtx_x - i *8, 0); matrix[i]->print(txt); @@ -145,9 +144,9 @@ void MatrixScrollUp(char* txt, int loop) words[wordcounter++] = p; p = strtok(NULL, separators); } - for (byte i = 0; i < mtx_matrices; i++) { + for (uint8_t i = 0; i < mtx_matrices; i++) { matrix[i]->clear(); - for (byte j = 0; j < wordcounter; j++) { + for (uint8_t j = 0; j < wordcounter; j++) { matrix[i]->setCursor(-i *8, mtx_y + (j *8)); matrix[i]->println(words[j]); } @@ -170,7 +169,7 @@ void MatrixScrollUp(char* txt, int loop) void MatrixInitMode(void) { - for (byte i = 0; i < mtx_matrices; i++) { + for (uint8_t i = 0; i < mtx_matrices; i++) { matrix[i]->setRotation(Settings.display_rotate); // 1 matrix[i]->setBrightness(Settings.display_dimmer); matrix[i]->blinkRate(0); // 0 - 3 @@ -227,7 +226,7 @@ void MatrixOnOff(void) void MatrixDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag) { - snprintf(mtx_buffer, MTX_MAX_SCREEN_BUFFER, str); + strlcpy(mtx_buffer, str, MTX_MAX_SCREEN_BUFFER); mtx_mode = x &1; // Use x for selecting scroll up (0) or scroll left (1) mtx_loop = y &1; // Use y for selecting no loop (0) or loop (1) if (!mtx_state) { mtx_state = 1; } @@ -261,8 +260,7 @@ void MatrixPrintLog(uint8_t direction) i++; } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "[%s]"), mtx_buffer); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "[%s]"), mtx_buffer); mtx_done = 1; } @@ -327,9 +325,9 @@ void MatrixRefresh(void) // Every second * Interface \*********************************************************************************************/ -boolean Xdsp03(byte function) +bool Xdsp03(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { if (FUNC_DISPLAY_INIT_DRIVER == function) { diff --git a/sonoff/xdsp_04_ili9341.ino b/sonoff/xdsp_04_ili9341.ino index b4149035e..f50164e59 100644 --- a/sonoff/xdsp_04_ili9341.ino +++ b/sonoff/xdsp_04_ili9341.ino @@ -1,7 +1,7 @@ /* xdsp_04_ili9341.ino - Display Tft Ili9341 support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends and Adafruit + Copyright (C) 2019 Theo Arends and Adafruit This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -148,7 +148,7 @@ void Ili9341PrintLog(void) char* txt = DisplayLogBuffer('\370'); if (txt != NULL) { - byte size = Settings.display_size; + uint8_t size = Settings.display_size; uint16_t theight = size * TFT_FONT_HEIGTH; tft->setTextSize(size); @@ -167,7 +167,7 @@ void Ili9341PrintLog(void) tft_scroll = theight; // Start below header tft->setCursor(0, tft_scroll); - for (byte i = 0; i < last_row; i++) { + for (uint8_t i = 0; i < last_row; i++) { strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); // tft->fillRect(0, tft_scroll, tft->width(), theight, ILI9341_BLACK); // Erase line tft->print(disp_screen_buffer[i]); @@ -178,8 +178,7 @@ void Ili9341PrintLog(void) DisplayFillScreen(last_row); tft->print(disp_screen_buffer[last_row]); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "[%s]"), txt); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "[%s]"), txt); } } } @@ -222,9 +221,9 @@ void Ili9341Refresh(void) // Every second * Interface \*********************************************************************************************/ -boolean Xdsp04(byte function) +bool Xdsp04(uint8_t function) { - boolean result = false; + bool result = false; if (spi_flg) { if (FUNC_DISPLAY_INIT_DRIVER == function) { diff --git a/sonoff/xdsp_05_epaper_29.ino b/sonoff/xdsp_05_epaper_29.ino index 24bb19655..6f4034ece 100644 --- a/sonoff/xdsp_05_epaper_29.ino +++ b/sonoff/xdsp_05_epaper_29.ino @@ -1,7 +1,7 @@ /* xdsp_05_epaper_29.ino - 2.9 Inch display e-paper support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends, Gerhard Mutz and Waveshare + Copyright (C) 2019 Theo Arends, Gerhard Mutz and Waveshare This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ #ifdef USE_SPI #ifdef USE_DISPLAY -#ifdef USE_DISPLAY_EPAPER +#ifdef USE_DISPLAY_EPAPER_29 #define XDSP_05 5 @@ -123,12 +123,14 @@ void EpdInitDriver(void) epd.sclk_pin = pin[GPIO_SPI_CLK]; // 14 epd.mosi_pin = pin[GPIO_SPI_MOSI]; // 13 EpdInitMode(); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EPD: HardSPI CS %d, CLK %d, MOSI %d"), epd.cs_pin, epd.sclk_pin, epd.mosi_pin); } else if ((pin[GPIO_SSPI_CS] < 99) && (pin[GPIO_SSPI_SCLK] < 99) && (pin[GPIO_SSPI_MOSI] < 99)) { epd.cs_pin = pin[GPIO_SSPI_CS]; epd.sclk_pin = pin[GPIO_SSPI_SCLK]; epd.mosi_pin = pin[GPIO_SSPI_MOSI]; EpdInitMode(); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EPD: SoftSPI CS %d, CLK %d, MOSI %d"), epd.cs_pin, epd.sclk_pin, epd.mosi_pin); } } } @@ -161,6 +163,7 @@ void EpdDisplayFrame(void) { epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight()); epd.DisplayFrame(); + epd.Sleep(); } void EpdDrawStringAt(uint16_t x, uint16_t y, char *str, uint8_t color, uint8_t flag) @@ -198,7 +201,7 @@ void EpdPrintLog(void) char* txt = DisplayLogBuffer('\040'); if (txt != NULL) { - byte size = Settings.display_size; + uint8_t size = Settings.display_size; uint16_t theight = size * EPD_FONT_HEIGTH; EpdSetFont(size); @@ -206,7 +209,7 @@ void EpdPrintLog(void) // epd_scroll = theight; // Start below header epd_scroll = 0; // Start at top with no header - for (byte i = 0; i < last_row; i++) { + for (uint8_t i = 0; i < last_row; i++) { strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); EpdDrawStringAt(0, epd_scroll, disp_screen_buffer[i], COLORED, 0); epd_scroll += theight; @@ -216,8 +219,7 @@ void EpdPrintLog(void) EpdDrawStringAt(0, epd_scroll, disp_screen_buffer[last_row], COLORED, 0); // EpdDisplayFrame(); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "[%s]"), txt); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "[%s]"), txt); } } } @@ -262,9 +264,9 @@ void EpdRefresh(void) // Every second * Interface \*********************************************************************************************/ -boolean Xdsp05(byte function) +bool Xdsp05(uint8_t function) { - boolean result = false; + bool result = false; if (spi_flg || soft_spi_flg) { if (FUNC_DISPLAY_INIT_DRIVER == function) { @@ -337,6 +339,6 @@ boolean Xdsp05(byte function) return result; } -#endif // USE_DISPLAY_EPAPER +#endif // USE_DISPLAY_EPAPER_29 #endif // USE_DISPLAY #endif // USE_SPI diff --git a/sonoff/xdsp_interface.ino b/sonoff/xdsp_interface.ino index e2847d85e..1f7becf88 100644 --- a/sonoff/xdsp_interface.ino +++ b/sonoff/xdsp_interface.ino @@ -1,7 +1,7 @@ /* xdsp_interface.ino - Display interface support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,10 +17,12 @@ along with this program. If not, see . */ +#ifdef USE_DISPLAY + #ifdef XFUNC_PTR_IN_ROM -boolean (* const xdsp_func_ptr[])(byte) PROGMEM = { // Display Function Pointers +bool (* const xdsp_func_ptr[])(uint8_t) PROGMEM = { // Display Function Pointers #else -boolean (* const xdsp_func_ptr[])(byte) = { // Display Function Pointers +bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers #endif #ifdef XDSP_01 @@ -117,14 +119,19 @@ uint8_t XdspPresent(void) return xdsp_present; } -boolean XdspCall(byte Function) +bool XdspCall(uint8_t Function) { - boolean result = false; + bool result = false; - for (byte x = 0; x < xdsp_present; x++) { + for (uint8_t x = 0; x < xdsp_present; x++) { result = xdsp_func_ptr[x](Function); - if (result) break; + + if (result && (FUNC_DISPLAY_MODEL == Function)) { + break; + } } return result; } + +#endif // USE_DISPLAY diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino index 0a4419498..14c00d911 100644 --- a/sonoff/xnrg_01_hlw8012.ino +++ b/sonoff/xnrg_01_hlw8012.ino @@ -1,7 +1,7 @@ /* xnrg_01_hlw8012.ino - HLW8012 (Sonoff Pow) energy sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,29 +37,36 @@ #define HJL_UREF 822 #define HJL_IREF 3300 -#define HLW_POWER_PROBE_TIME 10 // Number of seconds to probe for power before deciding none used +#define HLW_POWER_PROBE_TIME 10 // Number of seconds to probe for power before deciding none used (low power pulse can take up to 10 seconds) +#define HLW_SAMPLE_COUNT 10 // Max number of samples per cycle -byte hlw_select_ui_flag; -byte hlw_ui_flag = 1; -byte hlw_model_type = 0; -byte hlw_load_off; -byte hlw_cf1_timer; -unsigned long hlw_cf_pulse_length; -unsigned long hlw_cf_pulse_last_time; -unsigned long hlw_cf1_pulse_length; -unsigned long hlw_cf1_pulse_last_time; -unsigned long hlw_cf1_summed_pulse_length; -unsigned long hlw_cf1_pulse_counter; -unsigned long hlw_cf1_voltage_pulse_length; -unsigned long hlw_cf1_current_pulse_length; -unsigned long hlw_energy_period_counter; +//#define HLW_DEBUG +#ifdef HLW_DEBUG +unsigned long hlw_debug[HLW_SAMPLE_COUNT]; +#endif + +unsigned long hlw_cf_pulse_length = 0; +unsigned long hlw_cf_pulse_last_time = 0; +unsigned long hlw_cf_power_pulse_length = 0; + +unsigned long hlw_cf1_pulse_length = 0; +unsigned long hlw_cf1_pulse_last_time = 0; +unsigned long hlw_cf1_summed_pulse_length = 0; +unsigned long hlw_cf1_pulse_counter = 0; +unsigned long hlw_cf1_voltage_pulse_length = 0; +unsigned long hlw_cf1_current_pulse_length = 0; + +unsigned long hlw_energy_period_counter = 0; unsigned long hlw_power_ratio = 0; unsigned long hlw_voltage_ratio = 0; unsigned long hlw_current_ratio = 0; -unsigned long hlw_cf1_voltage_max_pulse_counter; -unsigned long hlw_cf1_current_max_pulse_counter; +uint8_t hlw_select_ui_flag = 0; +uint8_t hlw_ui_flag = 1; +uint8_t hlw_model_type = 0; +uint8_t hlw_load_off = 1; +uint8_t hlw_cf1_timer = 0; #ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception void HlwCfInterrupt(void) ICACHE_RAM_ATTR; @@ -88,9 +95,12 @@ void HlwCf1Interrupt(void) // Service Voltage and Current hlw_cf1_pulse_last_time = us; if ((hlw_cf1_timer > 2) && (hlw_cf1_timer < 8)) { // Allow for 300 mSec set-up time and measure for up to 1 second hlw_cf1_summed_pulse_length += hlw_cf1_pulse_length; +#ifdef HLW_DEBUG + hlw_debug[hlw_cf1_pulse_counter] = hlw_cf1_pulse_length; +#endif hlw_cf1_pulse_counter++; - if (10 == hlw_cf1_pulse_counter) { - hlw_cf1_timer = 8; // We need up to ten samples within 1 second (low current could take up to 0.3 second) + if (HLW_SAMPLE_COUNT == hlw_cf1_pulse_counter) { + hlw_cf1_timer = 8; // We need up to HLW_SAMPLE_COUNT samples within 1 second (low current could take up to 0.3 second) } } } @@ -99,6 +109,7 @@ void HlwCf1Interrupt(void) // Service Voltage and Current void HlwEvery200ms(void) { + unsigned long cf1_pulse_length = 0; unsigned long hlw_w = 0; unsigned long hlw_u = 0; unsigned long hlw_i = 0; @@ -107,9 +118,10 @@ void HlwEvery200ms(void) hlw_cf_pulse_length = 0; // No load for some time hlw_load_off = 1; } + hlw_cf_power_pulse_length = hlw_cf_pulse_length; - if (hlw_cf_pulse_length && energy_power_on && !hlw_load_off) { - hlw_w = (hlw_power_ratio * Settings.energy_power_calibration) / hlw_cf_pulse_length; + if (hlw_cf_power_pulse_length && energy_power_on && !hlw_load_off) { + hlw_w = (hlw_power_ratio * Settings.energy_power_calibration) / hlw_cf_power_pulse_length; // W *10 energy_active_power = (float)hlw_w / 10; } else { energy_active_power = 0; @@ -122,27 +134,43 @@ void HlwEvery200ms(void) digitalWrite(pin[GPIO_NRG_SEL], hlw_select_ui_flag); if (hlw_cf1_pulse_counter) { - hlw_cf1_pulse_length = hlw_cf1_summed_pulse_length / hlw_cf1_pulse_counter; - } else { - hlw_cf1_pulse_length = 0; + cf1_pulse_length = hlw_cf1_summed_pulse_length / hlw_cf1_pulse_counter; } + +#ifdef HLW_DEBUG + // Debugging for calculating mean and median + char stemp[100]; + stemp[0] = '\0'; + for (uint8_t i = 0; i < hlw_cf1_pulse_counter; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("%s %d"), stemp, hlw_debug[i]); + } + for (uint8_t i = 0; i < hlw_cf1_pulse_counter; i++) { + for (uint8_t j = i + 1; j < hlw_cf1_pulse_counter; j++) { + if (hlw_debug[i] > hlw_debug[j]) { // Sort ascending + std::swap(hlw_debug[i], hlw_debug[j]); + } + } + } + unsigned long median = hlw_debug[(hlw_cf1_pulse_counter +1) / 2]; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NRG: power %d, ui %d, cnt %d, smpl%s, sum %d, mean %d, median %d"), + hlw_cf_power_pulse_length, hlw_select_ui_flag, hlw_cf1_pulse_counter, stemp, hlw_cf1_summed_pulse_length, cf1_pulse_length, median); +#endif + if (hlw_select_ui_flag == hlw_ui_flag) { - hlw_cf1_voltage_pulse_length = hlw_cf1_pulse_length; - hlw_cf1_voltage_max_pulse_counter = hlw_cf1_pulse_counter; + hlw_cf1_voltage_pulse_length = cf1_pulse_length; if (hlw_cf1_voltage_pulse_length && energy_power_on) { // If powered on always provide voltage - hlw_u = (hlw_voltage_ratio * Settings.energy_voltage_calibration) / hlw_cf1_voltage_pulse_length; + hlw_u = (hlw_voltage_ratio * Settings.energy_voltage_calibration) / hlw_cf1_voltage_pulse_length; // V *10 energy_voltage = (float)hlw_u / 10; } else { energy_voltage = 0; } } else { - hlw_cf1_current_pulse_length = hlw_cf1_pulse_length; - hlw_cf1_current_max_pulse_counter = hlw_cf1_pulse_counter; + hlw_cf1_current_pulse_length = cf1_pulse_length; if (hlw_cf1_current_pulse_length && energy_active_power) { // No current if no power being consumed - hlw_i = (hlw_current_ratio * Settings.energy_current_calibration) / hlw_cf1_current_pulse_length; + hlw_i = (hlw_current_ratio * Settings.energy_current_calibration) / hlw_cf1_current_pulse_length; // mA energy_current = (float)hlw_i / 1000; } else { energy_current = 0; @@ -186,45 +214,29 @@ void HlwSnsInit(void) hlw_current_ratio = HLW_IREF; } - hlw_cf_pulse_length = 0; - hlw_cf_pulse_last_time = 0; - hlw_cf1_pulse_length = 0; - hlw_cf1_pulse_last_time = 0; - hlw_cf1_voltage_pulse_length = 0; - hlw_cf1_current_pulse_length = 0; - hlw_cf1_voltage_max_pulse_counter = 0; - hlw_cf1_current_max_pulse_counter = 0; - - hlw_load_off = 1; - hlw_energy_period_counter = 0; - - hlw_select_ui_flag = 0; // Voltage; - pinMode(pin[GPIO_NRG_SEL], OUTPUT); digitalWrite(pin[GPIO_NRG_SEL], hlw_select_ui_flag); pinMode(pin[GPIO_NRG_CF1], INPUT_PULLUP); attachInterrupt(pin[GPIO_NRG_CF1], HlwCf1Interrupt, FALLING); pinMode(pin[GPIO_HLW_CF], INPUT_PULLUP); attachInterrupt(pin[GPIO_HLW_CF], HlwCfInterrupt, FALLING); - - hlw_cf1_timer = 0; } void HlwDrvInit(void) { if (!energy_flg) { - hlw_model_type = 0; + hlw_model_type = 0; // HLW8012 if (pin[GPIO_HJL_CF] < 99) { pin[GPIO_HLW_CF] = pin[GPIO_HJL_CF]; pin[GPIO_HJL_CF] = 99; - hlw_model_type = 1; + hlw_model_type = 1; // HJL-01/BL0937 } - hlw_ui_flag = 1; + hlw_ui_flag = 1; // Voltage on high if (pin[GPIO_NRG_SEL_INV] < 99) { pin[GPIO_NRG_SEL] = pin[GPIO_NRG_SEL_INV]; pin[GPIO_NRG_SEL_INV] = 99; - hlw_ui_flag = 0; + hlw_ui_flag = 0; // Voltage on low } if ((pin[GPIO_NRG_SEL] < 99) && (pin[GPIO_NRG_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)) { // HLW8012 or HJL-01 based device @@ -233,13 +245,16 @@ void HlwDrvInit(void) } } -boolean HlwCommand(void) +bool HlwCommand(void) { - boolean serviced = true; + bool serviced = true; - if (CMND_POWERSET == energy_command_code) { - if (XdrvMailbox.data_len && hlw_cf_pulse_length) { - Settings.energy_power_calibration = ((unsigned long)(CharToDouble(XdrvMailbox.data) * 10) * hlw_cf_pulse_length) / hlw_power_ratio; + if ((CMND_POWERCAL == energy_command_code) || (CMND_VOLTAGECAL == energy_command_code) || (CMND_CURRENTCAL == energy_command_code)) { + // Service in xdrv_03_energy.ino + } + else if (CMND_POWERSET == energy_command_code) { + if (XdrvMailbox.data_len && hlw_cf_power_pulse_length) { + Settings.energy_power_calibration = ((unsigned long)(CharToDouble(XdrvMailbox.data) * 10) * hlw_cf_power_pulse_length) / hlw_power_ratio; } } else if (CMND_VOLTAGESET == energy_command_code) { @@ -261,7 +276,7 @@ boolean HlwCommand(void) * Interface \*********************************************************************************************/ -int Xnrg01(byte function) +int Xnrg01(uint8_t function) { int result = 0; diff --git a/sonoff/xnrg_02_cse7766.ino b/sonoff/xnrg_02_cse7766.ino index 318fb02a7..17fda1f44 100644 --- a/sonoff/xnrg_02_cse7766.ino +++ b/sonoff/xnrg_02_cse7766.ino @@ -1,7 +1,7 @@ /* xnrg_02_cse7766.ino - CSE7766 energy sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ uint8_t cse_receive_flag = 0; long voltage_cycle = 0; long current_cycle = 0; long power_cycle = 0; -unsigned long power_cycle_first = 0; +long power_cycle_first = 0; long cf_pulses = 0; long cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; uint8_t cse_power_invalid = CSE_MAX_INVALID_POWER; @@ -137,7 +137,7 @@ bool CseSerialInput(void) AddLogSerial(LOG_LEVEL_DEBUG_MORE); uint8_t checksum = 0; - for (byte i = 2; i < 23; i++) { checksum += serial_in_buffer[i]; } + for (uint8_t i = 2; i < 23; i++) { checksum += serial_in_buffer[i]; } if (checksum == serial_in_buffer[23]) { CseReceived(); cse_receive_flag = 0; @@ -191,7 +191,7 @@ void CseEverySecond(void) void CseDrvInit(void) { if (!energy_flg) { - if ((SONOFF_S31 == Settings.module) || (SONOFF_POW_R2 == Settings.module)) { // Sonoff S31 or Sonoff Pow R2 + if ((3 == pin[GPIO_CSE7766_RX]) && (1 == pin[GPIO_CSE7766_TX])) { // As it uses 8E1 currently only hardware serial is supported baudrate = 4800; serial_config = SERIAL_8E1; energy_flg = XNRG_02; @@ -199,23 +199,23 @@ void CseDrvInit(void) } } -boolean CseCommand(void) +bool CseCommand(void) { - boolean serviced = true; + bool serviced = true; if (CMND_POWERSET == energy_command_code) { if (XdrvMailbox.data_len && power_cycle) { - Settings.energy_power_calibration = ((unsigned long)CharToDouble(XdrvMailbox.data) * power_cycle) / CSE_PREF; + Settings.energy_power_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * power_cycle) / CSE_PREF; } } else if (CMND_VOLTAGESET == energy_command_code) { if (XdrvMailbox.data_len && voltage_cycle) { - Settings.energy_voltage_calibration = ((unsigned long)CharToDouble(XdrvMailbox.data) * voltage_cycle) / CSE_UREF; + Settings.energy_voltage_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * voltage_cycle) / CSE_UREF; } } else if (CMND_CURRENTSET == energy_command_code) { if (XdrvMailbox.data_len && current_cycle) { - Settings.energy_current_calibration = ((unsigned long)CharToDouble(XdrvMailbox.data) * current_cycle) / 1000; + Settings.energy_current_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * current_cycle) / 1000; } } else serviced = false; // Unknown command @@ -227,7 +227,7 @@ boolean CseCommand(void) * Interface \*********************************************************************************************/ -int Xnrg02(byte function) +int Xnrg02(uint8_t function) { int result = 0; diff --git a/sonoff/xnrg_03_pzem004t.ino b/sonoff/xnrg_03_pzem004t.ino index 850131762..a15d61ba1 100644 --- a/sonoff/xnrg_03_pzem004t.ino +++ b/sonoff/xnrg_03_pzem004t.ino @@ -1,7 +1,7 @@ /* xnrg_03_pzem004t.ino - PZEM004T energy sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,7 +32,7 @@ #include -TasmotaSerial *PzemSerial; +TasmotaSerial *PzemSerial = NULL; #define PZEM_VOLTAGE (uint8_t)0xB0 #define RESP_VOLTAGE (uint8_t)0xA0 @@ -122,7 +122,7 @@ bool PzemRecieve(uint8_t resp, float *data) } } - AddLogSerial(LOG_LEVEL_DEBUG_MORE, buffer, len); + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, len); if (len != sizeof(PZEMCommand)) { // AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Pzem comms timeout")); @@ -226,7 +226,7 @@ void PzemDrvInit(void) * Interface \*********************************************************************************************/ -int Xnrg03(byte function) +int Xnrg03(uint8_t function) { int result = 0; @@ -239,7 +239,7 @@ int Xnrg03(byte function) PzemSnsInit(); break; case FUNC_EVERY_200_MSECOND: - PzemEvery200ms(); + if (PzemSerial) { PzemEvery200ms(); } break; } } diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index d962ef204..d878d9e8b 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -1,7 +1,7 @@ /* xnrg_04_mcp39f501.ino - MCP39F501 energy sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,6 +28,7 @@ #define XNRG_04 4 +#define MCP_BAUDRATE 4800 #define MCP_TIMEOUT 4 #define MCP_CALIBRATION_TIMEOUT 2 @@ -63,6 +64,11 @@ #define MCP_FREQUENCY_GAIN_BASE 0x00AE #define MCP_FREQUENCY_LEN 4 +#define MCP_BUFFER_SIZE 60 + +#include +TasmotaSerial *McpSerial = NULL; + typedef struct mcp_cal_registers_type { uint16_t gain_current_rms; uint16_t gain_voltage_rms; @@ -86,6 +92,8 @@ typedef struct mcp_cal_registers_type { uint16_t accumulation_interval; } mcp_cal_registers_type; +char *mcp_buffer = NULL; +unsigned long mcp_window = 0; unsigned long mcp_kWhcounter = 0; uint32_t mcp_system_configuration = 0x03000000; uint32_t mcp_active_power; @@ -100,6 +108,7 @@ uint8_t mcp_calibration_active = 0; uint8_t mcp_init = 0; uint8_t mcp_timeout = 0; uint8_t mcp_calibrate = 0; +uint8_t mcp_byte_counter = 0; /*********************************************************************************************\ * Olimex tools @@ -112,7 +121,7 @@ uint8_t McpChecksum(uint8_t *data) uint8_t offset = 0; uint8_t len = data[1] -1; - for (byte i = offset; i < len; i++) { checksum += data[i]; } + for (uint8_t i = offset; i < len; i++) { checksum += data[i]; } return checksum; } @@ -121,7 +130,7 @@ unsigned long McpExtractInt(char *data, uint8_t offset, uint8_t size) unsigned long result = 0; unsigned long pow = 1; - for (byte i = 0; i < size; i++) { + for (uint8_t i = 0; i < size; i++) { result = result + (uint8_t)data[offset + i] * pow; pow = pow * 256; } @@ -130,7 +139,7 @@ unsigned long McpExtractInt(char *data, uint8_t offset, uint8_t size) void McpSetInt(unsigned long value, uint8_t *data, uint8_t offset, size_t size) { - for (byte i = 0; i < size; i++) { + for (uint8_t i = 0; i < size; i++) { data[offset + i] = ((value >> (i * 8)) & 0xFF); } } @@ -143,10 +152,10 @@ void McpSend(uint8_t *data) data[0] = MCP_START_FRAME; data[data[1] -1] = McpChecksum(data); -// AddLogSerial(LOG_LEVEL_DEBUG_MORE, data, data[1]); +// AddLogBuffer(LOG_LEVEL_DEBUG_MORE, data, data[1]); - for (byte i = 0; i < data[1]; i++) { - Serial.write(data[i]); + for (uint8_t i = 0; i < data[1]; i++) { + McpSerial->write(data[i]); } } @@ -162,7 +171,7 @@ void McpGetAddress(void) void McpAddressReceive(void) { // 06 05 004D 58 - mcp_address = serial_in_buffer[3]; + mcp_address = mcp_buffer[3]; } /********************************************************************************************/ @@ -183,26 +192,26 @@ void McpParseCalibration(void) mcp_cal_registers_type cal_registers; // 06 37 C882 B6AD 0781 9273 06000000 00000000 00000000 0000 D3FF 0300 00000003 9204 120C1300 204E0000 9808 E0AB0000 D9940000 0200 24 - cal_registers.gain_current_rms = McpExtractInt(serial_in_buffer, 2, 2); - cal_registers.gain_voltage_rms = McpExtractInt(serial_in_buffer, 4, 2); - cal_registers.gain_active_power = McpExtractInt(serial_in_buffer, 6, 2); - cal_registers.gain_reactive_power = McpExtractInt(serial_in_buffer, 8, 2); - cal_registers.offset_current_rms = McpExtractInt(serial_in_buffer, 10, 4); - cal_registers.offset_active_power = McpExtractInt(serial_in_buffer, 14, 4); - cal_registers.offset_reactive_power = McpExtractInt(serial_in_buffer, 18, 4); - cal_registers.dc_offset_current = McpExtractInt(serial_in_buffer, 22, 2); - cal_registers.phase_compensation = McpExtractInt(serial_in_buffer, 24, 2); - cal_registers.apparent_power_divisor = McpExtractInt(serial_in_buffer, 26, 2); + cal_registers.gain_current_rms = McpExtractInt(mcp_buffer, 2, 2); + cal_registers.gain_voltage_rms = McpExtractInt(mcp_buffer, 4, 2); + cal_registers.gain_active_power = McpExtractInt(mcp_buffer, 6, 2); + cal_registers.gain_reactive_power = McpExtractInt(mcp_buffer, 8, 2); + cal_registers.offset_current_rms = McpExtractInt(mcp_buffer, 10, 4); + cal_registers.offset_active_power = McpExtractInt(mcp_buffer, 14, 4); + cal_registers.offset_reactive_power = McpExtractInt(mcp_buffer, 18, 4); + cal_registers.dc_offset_current = McpExtractInt(mcp_buffer, 22, 2); + cal_registers.phase_compensation = McpExtractInt(mcp_buffer, 24, 2); + cal_registers.apparent_power_divisor = McpExtractInt(mcp_buffer, 26, 2); - cal_registers.system_configuration = McpExtractInt(serial_in_buffer, 28, 4); - cal_registers.dio_configuration = McpExtractInt(serial_in_buffer, 32, 2); - cal_registers.range = McpExtractInt(serial_in_buffer, 34, 4); + cal_registers.system_configuration = McpExtractInt(mcp_buffer, 28, 4); + cal_registers.dio_configuration = McpExtractInt(mcp_buffer, 32, 2); + cal_registers.range = McpExtractInt(mcp_buffer, 34, 4); - cal_registers.calibration_current = McpExtractInt(serial_in_buffer, 38, 4); - cal_registers.calibration_voltage = McpExtractInt(serial_in_buffer, 42, 2); - cal_registers.calibration_active_power = McpExtractInt(serial_in_buffer, 44, 4); - cal_registers.calibration_reactive_power = McpExtractInt(serial_in_buffer, 48, 4); - cal_registers.accumulation_interval = McpExtractInt(serial_in_buffer, 52, 2); + cal_registers.calibration_current = McpExtractInt(mcp_buffer, 38, 4); + cal_registers.calibration_voltage = McpExtractInt(mcp_buffer, 42, 2); + cal_registers.calibration_active_power = McpExtractInt(mcp_buffer, 44, 4); + cal_registers.calibration_reactive_power = McpExtractInt(mcp_buffer, 48, 4); + cal_registers.accumulation_interval = McpExtractInt(mcp_buffer, 52, 2); if (mcp_calibrate & MCP_CALIBRATE_POWER) { cal_registers.calibration_active_power = Settings.energy_power_calibration; @@ -373,8 +382,8 @@ void McpGetFrequency(void) void McpParseFrequency(void) { // 06 07 C350 8000 A0 - uint16_t line_frequency_ref = serial_in_buffer[2] * 256 + serial_in_buffer[3]; - uint16_t gain_line_frequency = serial_in_buffer[4] * 256 + serial_in_buffer[5]; + uint16_t line_frequency_ref = mcp_buffer[2] * 256 + mcp_buffer[3]; + uint16_t gain_line_frequency = mcp_buffer[4] * 256 + mcp_buffer[5]; if (mcp_calibrate & MCP_CALIBRATE_FREQUENCY) { line_frequency_ref = Settings.energy_frequency_calibration; @@ -438,12 +447,12 @@ void McpParseData(void) // 06 19 CE 18 00 00 F2 08 3A 38 00 00 66 00 00 00 93 38 00 00 36 7F 9A C6 B7 // Ak Ln Current---- Volt- ActivePower ReActivePow ApparentPow Factr Frequ Ck - mcp_current_rms = McpExtractInt(serial_in_buffer, 2, 4); - mcp_voltage_rms = McpExtractInt(serial_in_buffer, 6, 2); - mcp_active_power = McpExtractInt(serial_in_buffer, 8, 4); -// mcp_reactive_power = McpExtractInt(serial_in_buffer, 12, 4); -// mcp_power_factor = McpExtractInt(serial_in_buffer, 20, 2); - mcp_line_frequency = McpExtractInt(serial_in_buffer, 22, 2); + mcp_current_rms = McpExtractInt(mcp_buffer, 2, 4); + mcp_voltage_rms = McpExtractInt(mcp_buffer, 6, 2); + mcp_active_power = McpExtractInt(mcp_buffer, 8, 4); +// mcp_reactive_power = McpExtractInt(mcp_buffer, 12, 4); +// mcp_power_factor = McpExtractInt(mcp_buffer, 20, 2); + mcp_line_frequency = McpExtractInt(mcp_buffer, 22, 2); if (energy_power_on) { // Powered on energy_frequency = (float)mcp_line_frequency / 1000; @@ -464,49 +473,53 @@ void McpParseData(void) /********************************************************************************************/ -bool McpSerialInput(void) +void McpSerialInput(void) { - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - unsigned long start = millis(); - while (millis() - start < 20) { + while ((McpSerial->available()) && (mcp_byte_counter < MCP_BUFFER_SIZE)) { yield(); - if (Serial.available()) { - serial_in_buffer[serial_in_byte_counter++] = Serial.read(); - start = millis(); - } + mcp_buffer[mcp_byte_counter++] = McpSerial->read(); + mcp_window = millis(); } - AddLogSerial(LOG_LEVEL_DEBUG_MORE); + // Ignore until non received after 2 chars (= 12 bits/char) time + if ((mcp_byte_counter) && (millis() - mcp_window > (24000 / MCP_BAUDRATE) +1)) { + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)mcp_buffer, mcp_byte_counter); - if (1 == serial_in_byte_counter) { - if (MCP_ERROR_CRC == serial_in_buffer[0]) { -// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: Send " D_CHECKSUM_FAILURE)); - mcp_timeout = 0; + if (MCP_BUFFER_SIZE == mcp_byte_counter) { +// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: Overflow")); } - else if (MCP_ERROR_NAK == serial_in_buffer[0]) { -// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: NAck")); - mcp_timeout = 0; - } - } - else if (MCP_ACK_FRAME == serial_in_buffer[0]) { - if (serial_in_byte_counter == serial_in_buffer[1]) { - - if (McpChecksum((uint8_t *)serial_in_buffer) != serial_in_buffer[serial_in_byte_counter -1]) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); - } else { - if (5 == serial_in_buffer[1]) { McpAddressReceive(); } - if (25 == serial_in_buffer[1]) { McpParseData(); } - if (MCP_CALIBRATION_LEN + 3 == serial_in_buffer[1]) { McpParseCalibration(); } - if (MCP_FREQUENCY_LEN + 3 == serial_in_buffer[1]) { McpParseFrequency(); } + else if (1 == mcp_byte_counter) { + if (MCP_ERROR_CRC == mcp_buffer[0]) { +// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: Send " D_CHECKSUM_FAILURE)); + mcp_timeout = 0; + } + else if (MCP_ERROR_NAK == mcp_buffer[0]) { +// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: NAck")); + mcp_timeout = 0; } - } - mcp_timeout = 0; + else if (MCP_ACK_FRAME == mcp_buffer[0]) { + if (mcp_byte_counter == mcp_buffer[1]) { + + if (McpChecksum((uint8_t *)mcp_buffer) != mcp_buffer[mcp_byte_counter -1]) { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); + } else { + if (5 == mcp_buffer[1]) { McpAddressReceive(); } + if (25 == mcp_buffer[1]) { McpParseData(); } + if (MCP_CALIBRATION_LEN + 3 == mcp_buffer[1]) { McpParseCalibration(); } + if (MCP_FREQUENCY_LEN + 3 == mcp_buffer[1]) { McpParseFrequency(); } + } + + } + mcp_timeout = 0; + } + else if (MCP_SINGLE_WIRE == mcp_buffer[0]) { + mcp_timeout = 0; + } + + mcp_byte_counter = 0; + McpSerial->flush(); } - else if (MCP_SINGLE_WIRE == serial_in_buffer[0]) { - mcp_timeout = 0; - } - return 1; } /********************************************************************************************/ @@ -543,17 +556,31 @@ void McpEverySecond(void) void McpSnsInit(void) { - SetSeriallog(LOG_LEVEL_NONE); // Free serial interface from logging interference - digitalWrite(15, 1); // GPIO15 - MCP enable + // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions + McpSerial = new TasmotaSerial(pin[GPIO_MCP39F5_RX], pin[GPIO_MCP39F5_TX], 1); + if (McpSerial->begin(MCP_BAUDRATE)) { + if (McpSerial->hardwareSerial()) { + ClaimSerial(); + mcp_buffer = serial_in_buffer; // Use idle serial buffer to save RAM + } else { + mcp_buffer = (char*)(malloc(MCP_BUFFER_SIZE)); + } + if (pin[GPIO_MCP39F5_RST] < 99) { + digitalWrite(pin[GPIO_MCP39F5_RST], 1); // MCP enable + } + } else { + energy_flg = ENERGY_NONE; + } } void McpDrvInit(void) { if (!energy_flg) { - if (SHELLY2 == Settings.module) { - pinMode(15, OUTPUT); - digitalWrite(15, 0); // GPIO15 - MCP disable - Reset Delta Sigma ADC's - baudrate = 4800; + if ((pin[GPIO_MCP39F5_RX] < 99) && (pin[GPIO_MCP39F5_TX] < 99)) { + if (pin[GPIO_MCP39F5_RST] < 99) { + pinMode(pin[GPIO_MCP39F5_RST], OUTPUT); + digitalWrite(pin[GPIO_MCP39F5_RST], 0); // MCP disable - Reset Delta Sigma ADC's + } mcp_calibrate = 0; mcp_timeout = 2; // Initial wait mcp_init = 2; // Initial setup steps @@ -562,9 +589,9 @@ void McpDrvInit(void) } } -boolean McpCommand(void) +bool McpCommand(void) { - boolean serviced = true; + bool serviced = true; unsigned long value = 0; if (CMND_POWERSET == energy_command_code) { @@ -616,7 +643,7 @@ boolean McpCommand(void) * Interface \*********************************************************************************************/ -int Xnrg04(byte function) +int Xnrg04(uint8_t function) { int result = 0; @@ -628,15 +655,15 @@ int Xnrg04(byte function) case FUNC_INIT: McpSnsInit(); break; + case FUNC_LOOP: + if (McpSerial) { McpSerialInput(); } + break; case FUNC_EVERY_SECOND: - McpEverySecond(); + if (McpSerial) { McpEverySecond(); } break; case FUNC_COMMAND: result = McpCommand(); break; - case FUNC_SERIAL: - result = McpSerialInput(); - break; } } return result; diff --git a/sonoff/xnrg_05_pzem_ac.ino b/sonoff/xnrg_05_pzem_ac.ino index 7c145384a..b4ecea288 100644 --- a/sonoff/xnrg_05_pzem_ac.ino +++ b/sonoff/xnrg_05_pzem_ac.ino @@ -1,7 +1,7 @@ /* xnrg_05_pzem_ac.ino - PZEM-014,016 Modbus AC energy sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -46,11 +46,10 @@ void PzemAcEverySecond(void) uint8_t buffer[26]; uint8_t error = PzemAcModbus->ReceiveBuffer(buffer, 10); - AddLogSerial(LOG_LEVEL_DEBUG_MORE, buffer, (buffer[2]) ? buffer[2] +5 : sizeof(buffer)); + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, (buffer[2]) ? buffer[2] +5 : sizeof(buffer)); if (error) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "PzemAc response error %d"), error); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemAc response error %d"), error); } else { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // 01 04 14 08 D1 00 6C 00 00 00 F4 00 00 00 26 00 00 01 F4 00 64 00 00 51 34 @@ -104,7 +103,7 @@ void PzemAcDrvInit(void) * Interface \*********************************************************************************************/ -int Xnrg05(byte function) +int Xnrg05(uint8_t function) { int result = 0; diff --git a/sonoff/xnrg_06_pzem_dc.ino b/sonoff/xnrg_06_pzem_dc.ino index c12f401d4..2bb2bc4a2 100644 --- a/sonoff/xnrg_06_pzem_dc.ino +++ b/sonoff/xnrg_06_pzem_dc.ino @@ -1,7 +1,7 @@ /* xnrg_06_pzem_dc.ino - PZEM-003,017 Modbus DC energy sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -46,11 +46,10 @@ void PzemDcEverySecond(void) uint8_t buffer[22]; uint8_t error = PzemDcModbus->ReceiveBuffer(buffer, 8); - AddLogSerial(LOG_LEVEL_DEBUG_MORE, buffer, (buffer[2]) ? buffer[2] +5 : sizeof(buffer)); + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, (buffer[2]) ? buffer[2] +5 : sizeof(buffer)); if (error) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "PzemDc response error %d"), error); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemDc response error %d"), error); } else { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // 01 04 10 05 40 00 0A 00 0D 00 00 00 02 00 00 00 00 00 00 D6 29 @@ -103,7 +102,7 @@ void PzemDcDrvInit(void) * Interface \*********************************************************************************************/ -int Xnrg06(byte function) +int Xnrg06(uint8_t function) { int result = 0; diff --git a/sonoff/xnrg_interface.ino b/sonoff/xnrg_interface.ino index cea14e47c..61ff34e24 100644 --- a/sonoff/xnrg_interface.ino +++ b/sonoff/xnrg_interface.ino @@ -1,7 +1,7 @@ /* xnrg_interface.ino - Energy driver interface support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends inspired by ESPEasy + Copyright (C) 2019 Theo Arends inspired by ESPEasy This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,10 +17,12 @@ along with this program. If not, see . */ +#ifdef USE_ENERGY_SENSOR + #ifdef XFUNC_PTR_IN_ROM -int (* const xnrg_func_ptr[])(byte) PROGMEM = { // Energy driver Function Pointers +int (* const xnrg_func_ptr[])(uint8_t) PROGMEM = { // Energy driver Function Pointers #else -int (* const xnrg_func_ptr[])(byte) = { // Energy driver Function Pointers +int (* const xnrg_func_ptr[])(uint8_t) = { // Energy driver Function Pointers #endif #ifdef XNRG_01 @@ -90,13 +92,20 @@ int (* const xnrg_func_ptr[])(byte) = { // Energy driver Function Pointers const uint8_t xnrg_present = sizeof(xnrg_func_ptr) / sizeof(xnrg_func_ptr[0]); // Number of drivers found -int XnrgCall(byte Function) +int XnrgCall(uint8_t Function) { int result = 0; - for (byte x = 0; x < xnrg_present; x++) { + for (uint8_t x = 0; x < xnrg_present; x++) { result = xnrg_func_ptr[x](Function); - if (result) break; + + if (result && ((FUNC_SERIAL == Function) || + (FUNC_COMMAND == Function) + )) { + break; + } } return result; } + +#endif // USE_ENERGY_SENSOR diff --git a/sonoff/xplg_wemohue.ino b/sonoff/xplg_wemohue.ino index 143d0e6ba..2a7b60b80 100644 --- a/sonoff/xplg_wemohue.ino +++ b/sonoff/xplg_wemohue.ino @@ -1,7 +1,7 @@ /* xplg_wemohue.ino - wemo and hue support for Sonoff-Tasmota - Copyright (C) 2018 Heiko Krupp and Theo Arends + Copyright (C) 2019 Heiko Krupp and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ #include Ticker TickerMSearch; -boolean udp_connected = false; +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) @@ -95,9 +95,8 @@ void WemoRespondToMSearch(int echo_type) } else { snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE)); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"), echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port); - AddLog(LOG_LEVEL_DEBUG); udp_response_mutex = false; } @@ -186,9 +185,8 @@ void HueRespondToMSearch(void) } else { snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE)); } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"), message, udp_remote_ip.toString().c_str(), udp_remote_port); - AddLog(LOG_LEVEL_DEBUG); udp_response_mutex = false; } @@ -197,7 +195,7 @@ void HueRespondToMSearch(void) * Belkin WeMo and Philips Hue bridge UDP multicast support \*********************************************************************************************/ -boolean UdpDisconnect(void) +bool UdpDisconnect(void) { if (udp_connected) { WiFiUDP::stopAll(); @@ -207,7 +205,7 @@ boolean UdpDisconnect(void) return udp_connected; } -boolean UdpConnect(void) +bool UdpConnect(void) { if (!udp_connected) { if (PortUdp.beginMulticast(WiFi.localIP(), ipMulticast, port_multicast)) { @@ -302,7 +300,7 @@ const char WEMO_EVENTSERVICE_XML[] PROGMEM = "" "" "BinaryState" - "Boolean" + "bool" "0" "" "" @@ -405,21 +403,21 @@ void HandleUpnpEvent(void) state_xml.replace(F("Set"), F("Get")); } state_xml.replace("{x1", String(bitRead(power, devices_present -1))); - WebServer->send(200, FPSTR(HDR_CTYPE_XML), state_xml); + WSSend(200, CT_XML, state_xml); } void HandleUpnpService(void) { AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_EVENT_SERVICE)); - WebServer->send(200, FPSTR(HDR_CTYPE_PLAIN), FPSTR(WEMO_EVENTSERVICE_XML)); + WSSend(200, CT_PLAIN, FPSTR(WEMO_EVENTSERVICE_XML)); } void HandleUpnpMetaService(void) { AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_META_SERVICE)); - WebServer->send(200, FPSTR(HDR_CTYPE_PLAIN), FPSTR(WEMO_METASERVICE_XML)); + WSSend(200, CT_PLAIN, FPSTR(WEMO_METASERVICE_XML)); } void HandleUpnpSetupWemo(void) @@ -430,7 +428,7 @@ void HandleUpnpSetupWemo(void) setup_xml.replace("{x1", Settings.friendlyname[0]); setup_xml.replace("{x2", WemoUuid()); setup_xml.replace("{x3", WemoSerialnumber()); - WebServer->send(200, FPSTR(HDR_CTYPE_XML), setup_xml); + WSSend(200, CT_XML, setup_xml); } /*********************************************************************************************\ @@ -532,15 +530,14 @@ void HandleUpnpSetupHue(void) description_xml.replace("{x1", WiFi.localIP().toString()); description_xml.replace("{x2", HueUuid()); description_xml.replace("{x3", HueSerialnumber()); - WebServer->send(200, FPSTR(HDR_CTYPE_XML), description_xml); + WSSend(200, CT_XML, description_xml); } void HueNotImplemented(String *path) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_HTTP D_HUE_API_NOT_IMPLEMENTED " (%s)"), path->c_str()); - AddLog(LOG_LEVEL_DEBUG_MORE); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_API_NOT_IMPLEMENTED " (%s)"), path->c_str()); - WebServer->send(200, FPSTR(HDR_CTYPE_JSON), "{}"); + WSSend(200, CT_JSON, "{}"); } void HueConfigResponse(String *response) @@ -559,12 +556,12 @@ void HueConfig(String *path) { String response = ""; HueConfigResponse(&response); - WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response); + WSSend(200, CT_JSON, response); } bool g_gotct = false; -void HueLightStatus1(byte device, String *response) +void HueLightStatus1(uint8_t device, String *response) { float hue = 0; float sat = 0; @@ -584,7 +581,7 @@ void HueLightStatus1(byte device, String *response) response->replace("{m}", g_gotct?"ct":"hs"); } -void HueLightStatus2(byte device, String *response) +void HueLightStatus2(uint8_t device, String *response) { *response += FPSTR(HUE_LIGHTS_STATUS_JSON2); response->replace("{j1", Settings.friendlyname[device-1]); @@ -610,7 +607,7 @@ void HueGlobalConfig(String *path) response += F("},\"groups\":{},\"schedules\":{},\"config\":"); HueConfigResponse(&response); response += "}"; - WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response); + WSSend(200, CT_JSON, response); } void HueAuthentication(String *path) @@ -618,7 +615,7 @@ void HueAuthentication(String *path) char response[38]; snprintf_P(response, sizeof(response), PSTR("[{\"success\":{\"username\":\"%s\"}}]"), GetHueUserId().c_str()); - WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response); + WSSend(200, CT_JSON, response); } void HueLights(String *path) @@ -627,15 +624,16 @@ void HueLights(String *path) * http://sonoff/api/username/lights/1/state?1={"on":true,"hue":56100,"sat":254,"bri":254,"alert":"none","transitiontime":40} */ String response; - uint8_t device = 1; - uint16_t tmp = 0; + int code = 200; float bri = 0; float hue = 0; float sat = 0; + uint16_t tmp = 0; uint16_t ct = 0; bool resp = false; bool on = false; bool change = false; + uint8_t device = 1; uint8_t maxhue = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present; path->remove(0,path->indexOf("/lights")); // Remove until /lights @@ -651,7 +649,6 @@ void HueLights(String *path) } } response += "}"; - WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response); } else if (path->endsWith("/state")) { // Got ID/state path->remove(0,8); // Remove /lights/ @@ -761,8 +758,6 @@ void HueLights(String *path) else { response = FPSTR(HUE_ERROR_JSON); } - - WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response); } else if(path->indexOf("/lights/") >= 0) { // Got /lights/ID path->remove(0,8); // Remove /lights/ @@ -773,11 +768,12 @@ void HueLights(String *path) response += F("{\"state\":"); HueLightStatus1(device, &response); HueLightStatus2(device, &response); - WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response); } else { - WebServer->send(406, FPSTR(HDR_CTYPE_JSON), "{}"); + response = "{}"; + code = 406; } + WSSend(code, CT_JSON, response); } void HueGroups(String *path) @@ -799,7 +795,7 @@ void HueGroups(String *path) response += F("}"); } - WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response); + WSSend(200, CT_JSON, response); } void HandleHueApi(String *path) @@ -820,12 +816,10 @@ void HandleHueApi(String *path) path->remove(0, 4); // remove /api uint16_t apilen = path->length(); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_HTTP D_HUE_API " (%s)"), path->c_str()); - AddLog(LOG_LEVEL_DEBUG_MORE); // HTP: Hue API (//lights/1/state) + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_API " (%s)"), path->c_str()); // HTP: Hue API (//lights/1/state for (args = 0; args < WebServer->args(); args++) { String json = WebServer->arg(args); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_HTTP D_HUE_POST_ARGS " (%s)"), json.c_str()); - AddLog(LOG_LEVEL_DEBUG_MORE); // HTP: Hue POST args ({"on":false}) + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_POST_ARGS " (%s)"), json.c_str()); // HTP: Hue POST args ({"on":false}) } if (path->endsWith("/invalid/")) {} // Just ignore diff --git a/sonoff/xplg_ws2812.ino b/sonoff/xplg_ws2812.ino index 423c834ff..d230b5a94 100644 --- a/sonoff/xplg_ws2812.ino +++ b/sonoff/xplg_ws2812.ino @@ -1,7 +1,7 @@ /* xplg_ws2812.ino - ws2812 led string support for Sonoff-Tasmota - Copyright (C) 2018 Heiko Krupp and Theo Arends + Copyright (C) 2019 Heiko Krupp and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,35 +24,27 @@ #include +#if (USE_WS2812_CTYPE == NEO_GRB) + typedef NeoGrbFeature selectedNeoFeatureType; +#elif (USE_WS2812_CTYPE == NEO_BRG) + typedef NeoBrgFeature selectedNeoFeatureType; +#elif (USE_WS2812_CTYPE == NEO_RBG) + typedef NeoRbgFeature selectedNeoFeatureType; +#elif (USE_WS2812_CTYPE == NEO_RGBW) + typedef NeoRgbwFeature selectedNeoFeatureType; +#elif (USE_WS2812_CTYPE == NEO_GRBW) + typedef NeoGrbwFeature selectedNeoFeatureType; +#else // USE_WS2812_CTYPE + typedef NeoRgbFeature selectedNeoFeatureType; +#endif // USE_WS2812_CTYPE + + #ifdef USE_WS2812_DMA -#if (USE_WS2812_CTYPE == NEO_GRB) - NeoPixelBus *strip = NULL; -#elif (USE_WS2812_CTYPE == NEO_BRG) - NeoPixelBus *strip = NULL; -#elif (USE_WS2812_CTYPE == NEO_RBG) - NeoPixelBus *strip = NULL; -#elif (USE_WS2812_CTYPE == NEO_RGBW) - NeoPixelBus *strip = NULL; -#elif (USE_WS2812_CTYPE == NEO_GRBW) - NeoPixelBus *strip = NULL; -#else // USE_WS2812_CTYPE - NeoPixelBus *strip = NULL; -#endif // USE_WS2812_CTYPE + typedef Neo800KbpsMethod selectedNeoSpeedType; #else // USE_WS2812_DMA -#if (USE_WS2812_CTYPE == NEO_GRB) - NeoPixelBus *strip = NULL; -#elif (USE_WS2812_CTYPE == NEO_BRG) - NeoPixelBus *strip = NULL; -#elif (USE_WS2812_CTYPE == NEO_RBG) - NeoPixelBus *strip = NULL; -#elif (USE_WS2812_CTYPE == NEO_RGBW) - NeoPixelBus *strip = NULL; -#elif (USE_WS2812_CTYPE == NEO_GRBW) - NeoPixelBus *strip = NULL; -#else // USE_WS2812_CTYPE - NeoPixelBus *strip = NULL; -#endif // USE_WS2812_CTYPE + typedef NeoEsp8266BitBang800KbpsMethod selectedNeoSpeedType; #endif // USE_WS2812_DMA + NeoPixelBus *strip = NULL; struct WsColor { uint8_t red, green, blue; @@ -170,9 +162,9 @@ void Ws2812Clock(void) Ws2812UpdateHand((RtcTime.second * 1000) / clksize, WS_SECOND); Ws2812UpdateHand((RtcTime.minute * 1000) / clksize, WS_MINUTE); - Ws2812UpdateHand(((RtcTime.hour % 12) * (5000 / clksize)) + ((RtcTime.minute * 1000) / (12 * clksize)), WS_HOUR); + Ws2812UpdateHand((((RtcTime.hour % 12) * 5000) + ((RtcTime.minute * 1000) / 12 )) / clksize, WS_HOUR); if (Settings.ws_color[WS_MARKER][WS_RED] + Settings.ws_color[WS_MARKER][WS_GREEN] + Settings.ws_color[WS_MARKER][WS_BLUE]) { - for (byte i = 0; i < 12; i++) { + for (uint8_t i = 0; i < 12; i++) { Ws2812UpdateHand((i * 5000) / clksize, WS_MARKER); } } @@ -305,33 +297,9 @@ void Ws2812Bars(uint8_t schemenr) void Ws2812Init(void) { #ifdef USE_WS2812_DMA -#if (USE_WS2812_CTYPE == NEO_GRB) - strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. -#elif (USE_WS2812_CTYPE == NEO_BRG) - strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. -#elif (USE_WS2812_CTYPE == NEO_RBG) - strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. -#elif (USE_WS2812_CTYPE == NEO_RGBW) - strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. -#elif (USE_WS2812_CTYPE == NEO_GRBW) - strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. -#else // USE_WS2812_CTYPE - strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. -#endif // USE_WS2812_CTYPE + strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. #else // USE_WS2812_DMA -#if (USE_WS2812_CTYPE == NEO_GRB) - strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); -#elif (USE_WS2812_CTYPE == NEO_BRG) - strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); -#elif (USE_WS2812_CTYPE == NEO_RBG) - strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); -#elif (USE_WS2812_CTYPE == NEO_RGBW) - strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); -#elif (USE_WS2812_CTYPE == NEO_GRBW) - strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); -#else // USE_WS2812_CTYPE - strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); -#endif // USE_WS2812_CTYPE + strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); #endif // USE_WS2812_DMA strip->Begin(); Ws2812Clear(); @@ -395,7 +363,7 @@ char* Ws2812GetColor(uint16_t led, char* scolor) sl_ledcolor[1] = lcolor.G; sl_ledcolor[2] = lcolor.B; scolor[0] = '\0'; - for (byte i = 0; i < light_subtype; i++) { + for (uint8_t i = 0; i < light_subtype; i++) { if (Settings.flag.decimal_text) { snprintf_P(scolor, 25, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", sl_ledcolor[i]); } else { diff --git a/sonoff/xsns_01_counter.ino b/sonoff/xsns_01_counter.ino index 6b501d49f..cfa797030 100644 --- a/sonoff/xsns_01_counter.ino +++ b/sonoff/xsns_01_counter.ino @@ -1,7 +1,7 @@ /* xsns_01_counter.ino - Counter sensors (water meters, electricity meters etc.) sensor support for Sonoff-Tasmota - Copyright (C) 2018 Maarten Damen and Theo Arends + Copyright (C) 2019 Maarten Damen and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ unsigned long last_counter_timer[MAX_COUNTERS]; // Last counter time in micro seconds -void CounterUpdate(byte index) +void CounterUpdate(uint8_t index) { unsigned long counter_debounce_time = micros() - last_counter_timer[index -1]; if (counter_debounce_time > Settings.pulse_counter_debounce * 1000) { @@ -36,8 +36,7 @@ void CounterUpdate(byte index) RtcSettings.pulse_counter[index -1]++; } -// snprintf_P(log_data, sizeof(log_data), PSTR("CNTR: Interrupt %d"), index); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CNTR: Interrupt %d"), index); } } @@ -65,7 +64,7 @@ void CounterUpdate4(void) void CounterSaveState(void) { - for (byte i = 0; i < MAX_COUNTERS; i++) { + for (uint8_t i = 0; i < MAX_COUNTERS; i++) { if (pin[GPIO_CNTR1 +i] < 99) { Settings.pulse_counter[i] = RtcSettings.pulse_counter[i]; } @@ -77,7 +76,7 @@ void CounterInit(void) typedef void (*function) () ; function counter_callbacks[] = { CounterUpdate1, CounterUpdate2, CounterUpdate3, CounterUpdate4 }; - for (byte i = 0; i < MAX_COUNTERS; i++) { + for (uint8_t i = 0; i < MAX_COUNTERS; i++) { if (pin[GPIO_CNTR1 +i] < 99) { pinMode(pin[GPIO_CNTR1 +i], bitRead(counter_no_pullup, i) ? INPUT : INPUT_PULLUP); attachInterrupt(pin[GPIO_CNTR1 +i], counter_callbacks[i], FALLING); @@ -90,20 +89,20 @@ const char HTTP_SNS_COUNTER[] PROGMEM = "%s{s}" D_COUNTER "%d{m}%s%s{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER -void CounterShow(boolean json) +void CounterShow(bool json) { char stemp[10]; - byte dsxflg = 0; - byte header = 0; - for (byte i = 0; i < MAX_COUNTERS; i++) { + uint8_t dsxflg = 0; + uint8_t header = 0; + for (uint8_t i = 0; i < MAX_COUNTERS; i++) { if (pin[GPIO_CNTR1 +i] < 99) { char counter[33]; if (bitRead(Settings.pulse_counter_type, i)) { dtostrfd((double)RtcSettings.pulse_counter[i] / 1000000, 6, counter); } else { dsxflg++; - dtostrfd(RtcSettings.pulse_counter[i], 0, counter); + snprintf_P(counter, sizeof(counter), PSTR("%lu"), RtcSettings.pulse_counter[i]); } if (json) { @@ -141,9 +140,9 @@ void CounterShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns01(byte function) +bool Xsns01(uint8_t function) { - boolean result = false; + bool result = false; switch (function) { case FUNC_INIT: diff --git a/sonoff/xsns_02_analog.ino b/sonoff/xsns_02_analog.ino index cb4e794f1..e75160697 100644 --- a/sonoff/xsns_02_analog.ino +++ b/sonoff/xsns_02_analog.ino @@ -1,7 +1,7 @@ /* xsns_02_analog.ino - ESP8266 ADC support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,7 +29,7 @@ uint16_t adc_last_value = 0; uint16_t AdcRead(void) { uint16_t analog = 0; - for (byte i = 0; i < 32; i++) { + for (uint8_t i = 0; i < 32; i++) { analog += analogRead(A0); delay(1); } @@ -50,7 +50,7 @@ void AdcEvery250ms(void) } #endif // USE_RULES -void AdcShow(boolean json) +void AdcShow(bool json) { uint16_t analog = AdcRead(); @@ -67,11 +67,11 @@ void AdcShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns02(byte function) +bool Xsns02(uint8_t function) { - boolean result = false; + bool result = false; - if (pin[GPIO_ADC0] < 99) { + if (my_module_flag.adc0) { switch (function) { #ifdef USE_RULES case FUNC_EVERY_250_MSECOND: diff --git a/sonoff/xsns_04_snfsc.ino b/sonoff/xsns_04_snfsc.ino index d3329e3e5..f4880a308 100644 --- a/sonoff/xsns_04_snfsc.ino +++ b/sonoff/xsns_04_snfsc.ino @@ -1,7 +1,7 @@ /* xsns_04_snfsc.ino - sonoff SC support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -61,8 +61,7 @@ void SonoffScSend(const char *data) { Serial.write(data); Serial.write('\x1B'); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_SERIAL D_TRANSMIT " %s"), data); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_SERIAL D_TRANSMIT " %s"), data); } void SonoffScInit(void) @@ -78,8 +77,7 @@ void SonoffScSerialInput(char *rcvstat) char *str; uint16_t value[5] = { 0 }; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_SERIAL D_RECEIVED " %s"), rcvstat); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_SERIAL D_RECEIVED " %s"), rcvstat); if (!strncasecmp_P(rcvstat, PSTR("AT+UPDATE="), 10)) { int8_t i = -1; @@ -87,7 +85,7 @@ void SonoffScSerialInput(char *rcvstat) value[i++] = atoi(str); } if (value[0] > 0) { - for (byte i = 0; i < 5; i++) { + for (uint8_t i = 0; i < 5; i++) { sc_value[i] = value[i]; } sc_value[2] = (11 - sc_value[2]) * 10; // Invert light level @@ -110,7 +108,7 @@ const char HTTP_SNS_SCPLUS[] PROGMEM = "%s{s}" D_LIGHT "{m}%d%%{e}{s}" D_NOISE "{m}%d%%{e}{s}" D_AIR_QUALITY "{m}%d%%{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER -void SonoffScShow(boolean json) +void SonoffScShow(bool json) { if (sc_value[0] > 0) { float t = ConvertTemp(sc_value[1]); @@ -154,11 +152,11 @@ void SonoffScShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns04(byte function) +bool Xsns04(uint8_t function) { - boolean result = false; + bool result = false; - if (SONOFF_SC == Settings.module) { + if (SONOFF_SC == my_module_type) { switch (function) { case FUNC_INIT: SonoffScInit(); diff --git a/sonoff/xsns_05_ds18b20.ino b/sonoff/xsns_05_ds18b20.ino index dfd4394dd..f5d4bd03d 100644 --- a/sonoff/xsns_05_ds18b20.ino +++ b/sonoff/xsns_05_ds18b20.ino @@ -1,7 +1,7 @@ /* xsns_05_ds18b20.ino - DS18B20 temperature sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,7 +42,11 @@ uint8_t OneWireReset(void) uint8_t retries = 125; //noInterrupts(); +#ifdef DS18B20_INTERNAL_PULLUP + pinMode(ds18x20_pin, INPUT_PULLUP); +#else pinMode(ds18x20_pin, INPUT); +#endif do { if (--retries == 0) { return 0; @@ -52,7 +56,11 @@ uint8_t OneWireReset(void) pinMode(ds18x20_pin, OUTPUT); digitalWrite(ds18x20_pin, LOW); delayMicroseconds(480); +#ifdef DS18B20_INTERNAL_PULLUP + pinMode(ds18x20_pin, INPUT_PULLUP); +#else pinMode(ds18x20_pin, INPUT); +#endif delayMicroseconds(70); uint8_t r = !digitalRead(ds18x20_pin); //interrupts(); @@ -81,7 +89,11 @@ uint8_t OneWireReadBit(void) pinMode(ds18x20_pin, OUTPUT); digitalWrite(ds18x20_pin, LOW); delayMicroseconds(3); +#ifdef DS18B20_INTERNAL_PULLUP + pinMode(ds18x20_pin, INPUT_PULLUP); +#else pinMode(ds18x20_pin, INPUT); +#endif delayMicroseconds(10); uint8_t r = digitalRead(ds18x20_pin); //interrupts(); @@ -108,7 +120,7 @@ uint8_t OneWireRead(void) return r; } -boolean OneWireCrc8(uint8_t *addr) +bool OneWireCrc8(uint8_t *addr) { uint8_t crc = 0; uint8_t len = 8; @@ -137,7 +149,7 @@ void Ds18b20Convert(void) // delay(750); // 750ms should be enough for 12bit conv } -boolean Ds18b20Read(void) +bool Ds18b20Read(void) { uint8_t data[9]; int8_t sign = 1; @@ -187,7 +199,7 @@ void Ds18b20EverySecond(void) } } -void Ds18b20Show(boolean json) +void Ds18b20Show(bool json) { if (ds18b20_valid) { // Check for valid temperature char temperature[33]; @@ -216,9 +228,9 @@ void Ds18b20Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns05(byte function) +bool Xsns05(uint8_t function) { - boolean result = false; + bool result = false; if (pin[GPIO_DSB] < 99) { switch (function) { diff --git a/sonoff/xsns_05_ds18x20.ino b/sonoff/xsns_05_ds18x20.ino index 1061df86d..521fdeaa8 100644 --- a/sonoff/xsns_05_ds18x20.ino +++ b/sonoff/xsns_05_ds18x20.ino @@ -1,7 +1,7 @@ /* xsns_05_ds18x20.ino - DS18x20 temperature sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -233,7 +233,7 @@ uint8_t OneWireSearch(uint8_t *newAddr) return search_result; } -boolean OneWireCrc8(uint8_t *addr) +bool OneWireCrc8(uint8_t *addr) { uint8_t crc = 0; uint8_t len = 8; @@ -261,7 +261,9 @@ void Ds18x20Init(void) ds18x20_pin = pin[GPIO_DSB]; OneWireResetSearch(); - for (ds18x20_sensors = 0; ds18x20_sensors < DS18X20_MAX_SENSORS; ds18x20_sensors) { + + ds18x20_sensors = 0; + while (ds18x20_sensors < DS18X20_MAX_SENSORS) { if (!OneWireSearch(ds18x20_sensor[ds18x20_sensors].address)) { break; } @@ -285,8 +287,7 @@ void Ds18x20Init(void) } } } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DSB D_SENSORS_FOUND " %d"), ds18x20_sensors); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSORS_FOUND " %d"), ds18x20_sensors); } void Ds18x20Convert(void) @@ -308,9 +309,6 @@ bool Ds18x20Read(uint8_t sensor) { uint8_t data[9]; int8_t sign = 1; - uint16_t temp12 = 0; - int16_t temp14 = 0; - float temp9 = 0.0; uint8_t index = ds18x20_sensor[sensor].index; if (ds18x20_sensor[index].valid) { ds18x20_sensor[index].valid--; } @@ -323,48 +321,47 @@ bool Ds18x20Read(uint8_t sensor) } if (OneWireCrc8(data)) { switch(ds18x20_sensor[index].address[0]) { - case DS18S20_CHIPID: - if (data[1] > 0x80) { - data[0] = (~data[0]) +1; - sign = -1; // App-Note fix possible sign error + case DS18S20_CHIPID: { + if (data[1] > 0x80) { + data[0] = (~data[0]) +1; + sign = -1; // App-Note fix possible sign error + } + float temp9 = (float)(data[0] >> 1) * sign; + ds18x20_sensor[index].temperature = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0)); + ds18x20_sensor[index].valid = SENSOR_MAX_MISS; + return true; } - if (data[0] & 1) { - temp9 = ((data[0] >> 1) + 0.5) * sign; - } else { - temp9 = (data[0] >> 1) * sign; - } - ds18x20_sensor[index].temperature = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0)); - ds18x20_sensor[index].valid = SENSOR_MAX_MISS; - return true; - case DS1822_CHIPID: - case DS18B20_CHIPID: - if (data[4] != 0x7F) { - data[4] = 0x7F; // Set resolution to 12-bit - OneWireReset(); - OneWireSelect(ds18x20_sensor[index].address); - OneWireWrite(W1_WRITE_SCRATCHPAD); - OneWireWrite(data[2]); // Th Register - OneWireWrite(data[3]); // Tl Register - OneWireWrite(data[4]); // Configuration Register - OneWireSelect(ds18x20_sensor[index].address); - OneWireWrite(W1_WRITE_EEPROM); // Save scratchpad to EEPROM + case DS1822_CHIPID: + case DS18B20_CHIPID: { + if (data[4] != 0x7F) { + data[4] = 0x7F; // Set resolution to 12-bit + OneWireReset(); + OneWireSelect(ds18x20_sensor[index].address); + OneWireWrite(W1_WRITE_SCRATCHPAD); + OneWireWrite(data[2]); // Th Register + OneWireWrite(data[3]); // Tl Register + OneWireWrite(data[4]); // Configuration Register + OneWireSelect(ds18x20_sensor[index].address); + OneWireWrite(W1_WRITE_EEPROM); // Save scratchpad to EEPROM #ifdef W1_PARASITE_POWER - w1_power_until = millis() + 10; // 10ms specified duration for EEPROM write + w1_power_until = millis() + 10; // 10ms specified duration for EEPROM write #endif + } + uint16_t temp12 = (data[1] << 8) + data[0]; + if (temp12 > 2047) { + temp12 = (~temp12) +1; + sign = -1; + } + ds18x20_sensor[index].temperature = ConvertTemp(sign * temp12 * 0.0625); // Divide by 16 + ds18x20_sensor[index].valid = SENSOR_MAX_MISS; + return true; } - temp12 = (data[1] << 8) + data[0]; - if (temp12 > 2047) { - temp12 = (~temp12) +1; - sign = -1; + case MAX31850_CHIPID: { + int16_t temp14 = (data[1] << 8) + (data[0] & 0xFC); + ds18x20_sensor[index].temperature = ConvertTemp(temp14 * 0.0625); // Divide by 16 + ds18x20_sensor[index].valid = SENSOR_MAX_MISS; + return true; } - ds18x20_sensor[index].temperature = ConvertTemp(sign * temp12 * 0.0625); // Divide by 16 - ds18x20_sensor[index].valid = SENSOR_MAX_MISS; - return true; - case MAX31850_CHIPID: - temp14 = (data[1] << 8) + (data[0] & 0xFC); - ds18x20_sensor[index].temperature = ConvertTemp(temp14 * 0.0625); // Divide by 16 - ds18x20_sensor[index].valid = SENSOR_MAX_MISS; - return true; } } } @@ -422,7 +419,7 @@ void Ds18x20EverySecond(void) } } -void Ds18x20Show(boolean json) +void Ds18x20Show(bool json) { for (uint8_t i = 0; i < ds18x20_sensors; i++) { uint8_t index = ds18x20_sensor[i].index; @@ -438,7 +435,7 @@ void Ds18x20Show(boolean json) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, ds18x20_types, temperature); } else { char address[17]; - for (byte j = 0; j < 6; j++) { + 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); @@ -466,9 +463,9 @@ void Ds18x20Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns05(byte function) +bool Xsns05(uint8_t function) { - boolean result = false; + bool result = false; if (pin[GPIO_DSB] < 99) { switch (function) { diff --git a/sonoff/xsns_05_ds18x20_legacy.ino b/sonoff/xsns_05_ds18x20_legacy.ino index 5a89a0abe..cb07bf63c 100644 --- a/sonoff/xsns_05_ds18x20_legacy.ino +++ b/sonoff/xsns_05_ds18x20_legacy.ino @@ -1,7 +1,7 @@ /* xsns_05_ds18x20_legacy.ino - DS18x20 temperature sensor support for Sonoff-Tasmota - Copyright (C) 2018 Heiko Krupp and Theo Arends + Copyright (C) 2019 Heiko Krupp and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -65,11 +65,11 @@ void Ds18x20Search(void) num_sensors++; } } - for (byte i = 0; i < num_sensors; i++) { + for (uint8_t i = 0; i < num_sensors; i++) { ds18x20_index[i] = i; } - for (byte i = 0; i < num_sensors; i++) { - for (byte j = i + 1; j < num_sensors; j++) { + for (uint8_t i = 0; i < num_sensors; i++) { + for (uint8_t j = i + 1; j < num_sensors; j++) { if (uint32_t(ds18x20_address[ds18x20_index[i]]) > uint32_t(ds18x20_address[ds18x20_index[j]])) { std::swap(ds18x20_index[i], ds18x20_index[j]); } @@ -87,7 +87,7 @@ String Ds18x20Addresses(uint8_t sensor) { char address[20]; - for (byte i = 0; i < 8; i++) { + for (uint8_t i = 0; i < 8; i++) { sprintf(address+2*i, "%02X", ds18x20_address[ds18x20_index[sensor]][i]); } return String(address); @@ -101,9 +101,9 @@ void Ds18x20Convert(void) // delay(750); // 750ms should be enough for 12bit conv } -boolean Ds18x20Read(uint8_t sensor, float &t) +bool Ds18x20Read(uint8_t sensor, float &t) { - byte data[12]; + uint8_t data[12]; int8_t sign = 1; uint16_t temp12 = 0; int16_t temp14 = 0; @@ -116,7 +116,7 @@ boolean Ds18x20Read(uint8_t sensor, float &t) ds->select(ds18x20_address[ds18x20_index[sensor]]); ds->write(W1_READ_SCRATCHPAD); // Read Scratchpad - for (byte i = 0; i < 9; i++) { + for (uint8_t i = 0; i < 9; i++) { data[i] = ds->read(); } if (OneWire::crc8(data, 8) == data[8]) { @@ -126,11 +126,7 @@ boolean Ds18x20Read(uint8_t sensor, float &t) data[0] = (~data[0]) +1; sign = -1; // App-Note fix possible sign error } - if (data[0] & 1) { - temp9 = ((data[0] >> 1) + 0.5) * sign; - } else { - temp9 = (data[0] >> 1) * sign; - } + temp9 = (float)(data[0] >> 1) * sign; t = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0)); break; case DS18B20_CHIPID: @@ -168,13 +164,13 @@ void Ds18x20Type(uint8_t sensor) } } -void Ds18x20Show(boolean json) +void Ds18x20Show(bool json) { char stemp[10]; float t; - byte dsxflg = 0; - for (byte i = 0; i < Ds18x20Sensors(); i++) { + uint8_t dsxflg = 0; + for (uint8_t i = 0; i < Ds18x20Sensors(); i++) { if (Ds18x20Read(i, t)) { // Check if read failed Ds18x20Type(i); char temperature[33]; @@ -220,9 +216,9 @@ void Ds18x20Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns05(byte function) +bool Xsns05(uint8_t function) { - boolean result = false; + bool result = false; if (pin[GPIO_DSB] < 99) { switch (function) { diff --git a/sonoff/xsns_06_dht.ino b/sonoff/xsns_06_dht.ino index 72f94edd7..e6d8d7328 100644 --- a/sonoff/xsns_06_dht.ino +++ b/sonoff/xsns_06_dht.ino @@ -1,7 +1,7 @@ /* xsns_06_dht.ino - DHTxx, AM23xx and SI7021 temperature and humidity sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,11 +33,11 @@ uint32_t dht_max_cycles; uint8_t dht_data[5]; -byte dht_sensors = 0; +uint8_t dht_sensors = 0; struct DHTSTRUCT { - byte pin; - byte type; + uint8_t pin; + uint8_t type; char stype[12]; uint32_t lastreadtime; uint8_t lastresult; @@ -47,12 +47,12 @@ struct DHTSTRUCT { void DhtReadPrep(void) { - for (byte i = 0; i < dht_sensors; i++) { + for (uint8_t i = 0; i < dht_sensors; i++) { digitalWrite(Dht[i].pin, HIGH); } } -int32_t DhtExpectPulse(byte sensor, bool level) +int32_t DhtExpectPulse(uint8_t sensor, bool level) { int32_t count = 0; @@ -64,7 +64,7 @@ int32_t DhtExpectPulse(byte sensor, bool level) return count; } -boolean DhtRead(byte sensor) +bool DhtRead(uint8_t sensor) { int32_t cycles[80]; uint8_t error = 0; @@ -125,16 +125,15 @@ boolean DhtRead(byte sensor) uint8_t checksum = (dht_data[0] + dht_data[1] + dht_data[2] + dht_data[3]) & 0xFF; if (dht_data[4] != checksum) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DHT D_CHECKSUM_FAILURE " %02X, %02X, %02X, %02X, %02X =? %02X"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_CHECKSUM_FAILURE " %02X, %02X, %02X, %02X, %02X =? %02X"), dht_data[0], dht_data[1], dht_data[2], dht_data[3], dht_data[4], checksum); - AddLog(LOG_LEVEL_DEBUG); return false; } return true; } -void DhtReadTempHum(byte sensor) +void DhtReadTempHum(uint8_t sensor) { if ((NAN == Dht[sensor].h) || (Dht[sensor].lastresult > DHT_MAX_RETRY)) { // Reset after 8 misses Dht[sensor].t = NAN; @@ -162,9 +161,9 @@ void DhtReadTempHum(byte sensor) } } -boolean DhtSetup(byte pin, byte type) +bool DhtSetup(uint8_t pin, uint8_t type) { - boolean success = false; + bool success = false; if (dht_sensors < DHT_MAX_SENSORS) { Dht[dht_sensors].pin = pin; @@ -181,7 +180,7 @@ void DhtInit(void) { dht_max_cycles = microsecondsToClockCycles(1000); // 1 millisecond timeout for reading pulses from DHT sensor. - for (byte i = 0; i < dht_sensors; i++) { + for (uint8_t i = 0; i < dht_sensors; i++) { pinMode(Dht[i].pin, INPUT_PULLUP); Dht[i].lastreadtime = 0; Dht[i].lastresult = 0; @@ -198,16 +197,16 @@ void DhtEverySecond(void) // <1mS DhtReadPrep(); } else { - for (byte i = 0; i < dht_sensors; i++) { + for (uint8_t i = 0; i < dht_sensors; i++) { // DHT11 and AM2301 25mS per sensor, SI7021 5mS per sensor DhtReadTempHum(i); } } } -void DhtShow(boolean json) +void DhtShow(bool json) { - for (byte i = 0; i < dht_sensors; i++) { + for (uint8_t i = 0; i < dht_sensors; i++) { char temperature[33]; dtostrfd(Dht[i].t, Settings.flag2.temperature_resolution, temperature); char humidity[33]; @@ -239,9 +238,9 @@ void DhtShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns06(byte function) +bool Xsns06(uint8_t function) { - boolean result = false; + bool result = false; if (dht_flg) { switch (function) { diff --git a/sonoff/xsns_07_sht1x.ino b/sonoff/xsns_07_sht1x.ino index 0bf2d774c..51351bdf5 100644 --- a/sonoff/xsns_07_sht1x.ino +++ b/sonoff/xsns_07_sht1x.ino @@ -1,7 +1,7 @@ /* xsns_07_sht1x.ino - SHT1x temperature and sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,21 +44,21 @@ uint8_t sht_valid = 0; float sht_temperature = 0; float sht_humidity = 0; -boolean ShtReset(void) +bool ShtReset(void) { pinMode(sht_sda_pin, INPUT_PULLUP); pinMode(sht_scl_pin, OUTPUT); delay(11); - for (byte i = 0; i < 9; i++) { + for (uint8_t i = 0; i < 9; i++) { digitalWrite(sht_scl_pin, HIGH); digitalWrite(sht_scl_pin, LOW); } - boolean success = ShtSendCommand(SHT1X_CMD_SOFT_RESET); + bool success = ShtSendCommand(SHT1X_CMD_SOFT_RESET); delay(11); return success; } -boolean ShtSendCommand(const byte cmd) +bool ShtSendCommand(const uint8_t cmd) { pinMode(sht_sda_pin, OUTPUT); // Transmission Start sequence @@ -72,7 +72,7 @@ boolean ShtSendCommand(const byte cmd) // Send the command (address must be 000b) shiftOut(sht_sda_pin, sht_scl_pin, MSBFIRST, cmd); // Wait for ACK - boolean ackerror = false; + bool ackerror = false; digitalWrite(sht_scl_pin, HIGH); pinMode(sht_sda_pin, INPUT_PULLUP); if (digitalRead(sht_sda_pin) != LOW) { @@ -90,10 +90,10 @@ boolean ShtSendCommand(const byte cmd) return (!ackerror); } -boolean ShtAwaitResult(void) +bool ShtAwaitResult(void) { // Maximum 320ms for 14 bit measurement - for (byte i = 0; i < 16; i++) { + for (uint8_t i = 0; i < 16; i++) { if (LOW == digitalRead(sht_sda_pin)) { return true; } @@ -125,7 +125,7 @@ int ShtReadData(void) return val; } -boolean ShtRead(void) +bool ShtRead(void) { if (sht_valid) { sht_valid--; } if (!ShtReset()) { return false; } @@ -185,7 +185,7 @@ void ShtEverySecond(void) } } -void ShtShow(boolean json) +void ShtShow(bool json) { if (sht_valid) { char temperature[33]; @@ -219,9 +219,9 @@ void ShtShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns07(byte function) +bool Xsns07(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_08_htu21.ino b/sonoff/xsns_08_htu21.ino index 3e22c17f3..8ce9657ea 100644 --- a/sonoff/xsns_08_htu21.ino +++ b/sonoff/xsns_08_htu21.ino @@ -1,7 +1,7 @@ /* xsns_08_htu21.ino - HTU21 temperature and humidity sensor support for Sonoff-Tasmota - Copyright (C) 2018 Heiko Krupp and Theo Arends + Copyright (C) 2019 Heiko Krupp and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -140,7 +140,7 @@ void HtuInit(void) HtuSetResolution(HTU21_RES_RH12_T14); } -boolean HtuRead(void) +bool HtuRead(void) { uint8_t checksum = 0; uint16_t sensorval = 0; @@ -224,8 +224,7 @@ void HtuDetect(void) htu_delay_humidity = 23; } GetTextIndexed(htu_types, sizeof(htu_types), index, kHtuTypes); - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, htu_types, htu_address); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, htu_types, htu_address); } } @@ -246,7 +245,7 @@ void HtuEverySecond(void) } } -void HtuShow(boolean json) +void HtuShow(bool json) { if (htu_valid) { char temperature[33]; @@ -280,9 +279,9 @@ void HtuShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns08(byte function) +bool Xsns08(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_09_bmp.ino b/sonoff/xsns_09_bmp.ino index 6023ba5cc..488efd7ee 100755 --- a/sonoff/xsns_09_bmp.ino +++ b/sonoff/xsns_09_bmp.ino @@ -1,7 +1,7 @@ /* xsns_09_bmp.ino - BMP pressure, temperature, humidity and gas sensor support for Sonoff-Tasmota - Copyright (C) 2018 Heiko Krupp and Theo Arends + Copyright (C) 2019 Heiko Krupp and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -101,7 +101,7 @@ typedef struct { bmp180_cal_data_t *bmp180_cal_data = NULL; -boolean Bmp180Calibration(uint8_t bmp_idx) +bool Bmp180Calibration(uint8_t bmp_idx) { if (!bmp180_cal_data) { bmp180_cal_data = (bmp180_cal_data_t*)malloc(BMP_MAX_SENSORS * sizeof(bmp180_cal_data_t)); @@ -246,7 +246,7 @@ typedef struct { Bme280CalibrationData_t *Bme280CalibrationData = NULL; -boolean Bmx280Calibrate(uint8_t bmp_idx) +bool Bmx280Calibrate(uint8_t bmp_idx) { // if (I2cRead8(bmp_address, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false; @@ -351,7 +351,7 @@ static void BmeDelayMs(uint32_t ms) delay(ms); } -boolean Bme680Init(uint8_t bmp_idx) +bool Bme680Init(uint8_t bmp_idx) { if (!gas_sensor) { gas_sensor = (bme680_dev*)malloc(BMP_MAX_SENSORS * sizeof(bme680_dev)); @@ -455,14 +455,14 @@ void BmpDetect(void) if (!bmp_sensors) { return; } memset(bmp_sensors, 0, bmp_sensor_size); // Init defaults to 0 - for (byte i = 0; i < BMP_MAX_SENSORS; i++) { + for (uint8_t i = 0; i < BMP_MAX_SENSORS; i++) { uint8_t bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID); if (bmp_type) { bmp_sensors[bmp_count].bmp_address = bmp_addresses[i]; bmp_sensors[bmp_count].bmp_type = bmp_type; bmp_sensors[bmp_count].bmp_model = 0; - boolean success = false; + bool success = false; switch (bmp_type) { case BMP180_CHIPID: success = Bmp180Calibration(bmp_count); @@ -482,8 +482,7 @@ void BmpDetect(void) } if (success) { GetTextIndexed(bmp_sensors[bmp_count].bmp_name, sizeof(bmp_sensors[bmp_count].bmp_name), bmp_sensors[bmp_count].bmp_model, kBmpTypes); - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bmp_sensors[bmp_count].bmp_name, bmp_sensors[bmp_count].bmp_address); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, bmp_sensors[bmp_count].bmp_name, bmp_sensors[bmp_count].bmp_address); bmp_count++; } } @@ -494,7 +493,7 @@ void BmpRead(void) { if (!bmp_sensors) { return; } - for (byte bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { + for (uint8_t bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { switch (bmp_sensors[bmp_idx].bmp_type) { case BMP180_CHIPID: Bmp180Read(bmp_idx); @@ -525,11 +524,11 @@ void BmpEverySecond(void) } } -void BmpShow(boolean json) +void BmpShow(bool json) { if (!bmp_sensors) { return; } - for (byte bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { + for (uint8_t bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { if (bmp_sensors[bmp_idx].bmp_type) { float bmp_sealevel = 0.0; if (bmp_sensors[bmp_idx].bmp_pressure != 0.0) { @@ -540,7 +539,7 @@ void BmpShow(boolean json) float bmp_pressure = ConvertPressure(bmp_sensors[bmp_idx].bmp_pressure); char name[10]; - snprintf(name, sizeof(name), bmp_sensors[bmp_idx].bmp_name); + strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(name)); if (bmp_count > 1) { snprintf_P(name, sizeof(name), PSTR("%s-%02X"), name, bmp_sensors[bmp_idx].bmp_address); // BMXXXX-XX } @@ -621,9 +620,9 @@ void BmpShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns09(byte function) +bool Xsns09(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_10_bh1750.ino b/sonoff/xsns_10_bh1750.ino index af0d1aebb..95abc41c5 100644 --- a/sonoff/xsns_10_bh1750.ino +++ b/sonoff/xsns_10_bh1750.ino @@ -1,7 +1,7 @@ /* xsns_10_bh1750.ino - BH1750 ambient light sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,8 +44,8 @@ bool Bh1750Read(void) if (bh1750_valid) { bh1750_valid--; } if (2 != Wire.requestFrom(bh1750_address, (uint8_t)2)) { return false; } - byte msb = Wire.read(); - byte lsb = Wire.read(); + uint8_t msb = Wire.read(); + uint8_t lsb = Wire.read(); bh1750_illuminance = ((msb << 8) | lsb) / 1.2; bh1750_valid = SENSOR_MAX_MISS; return true; @@ -59,14 +59,13 @@ void Bh1750Detect(void) return; } - for (byte i = 0; i < sizeof(bh1750_addresses); i++) { + for (uint8_t i = 0; i < sizeof(bh1750_addresses); i++) { bh1750_address = bh1750_addresses[i]; Wire.beginTransmission(bh1750_address); Wire.write(BH1750_CONTINUOUS_HIGH_RES_MODE); if (!Wire.endTransmission()) { bh1750_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bh1750_types, bh1750_address); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, bh1750_types, bh1750_address); break; } } @@ -89,7 +88,7 @@ void Bh1750EverySecond(void) } } -void Bh1750Show(boolean json) +void Bh1750Show(bool json) { if (bh1750_valid) { if (json) { @@ -111,9 +110,9 @@ void Bh1750Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns10(byte function) +bool Xsns10(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_11_veml6070.ino b/sonoff/xsns_11_veml6070.ino index 0177fcc63..c32fc090f 100644 --- a/sonoff/xsns_11_veml6070.ino +++ b/sonoff/xsns_11_veml6070.ino @@ -1,7 +1,7 @@ /* xsns_11_veml6070.ino - VEML6070 ultra violet light sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ Version Date Action Description -------------------------------------------------------------------------------------------- - 1.0.0.3 20181006 fixed - missing "" around the UV Index text + 1.0.0.3 20181006 fixed - missing "" around the UV Index text - thanks to Lisa she had tested it on here mqtt system. -- 1.0.0.2 20180928 tests - same as in version 1.0.0.1 @@ -140,8 +140,7 @@ void Veml6070Detect(void) veml6070_type = 1; uint8_t veml_model = 0; GetTextIndexed(veml6070_name, sizeof(veml6070_name), veml_model, kVemlTypes); - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070", VEML6070_ADDR_L); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "VEML6070", VEML6070_ADDR_L); } } @@ -156,13 +155,11 @@ void Veml6070UvTableInit(void) uv_risk_map[i] = ( (USE_VEML6070_RSET / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT ) * (i+1); } else { uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT ) * (i+1); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "VEML6070 resistor error %d"), USE_VEML6070_RSET); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "VEML6070 resistor error %d"), USE_VEML6070_RSET); } #else uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT ) * (i+1); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "VEML6070 resistor default used %d"), VEML6070_RSET_DEFAULT); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "VEML6070 resistor default used %d"), VEML6070_RSET_DEFAULT); #endif } } @@ -187,7 +184,7 @@ void Veml6070EverySecond(void) /********************************************************************************************/ -void Veml6070ModeCmd(boolean mode_cmd) +void Veml6070ModeCmd(bool mode_cmd) { // mode_cmd 1 = on = 1[ms] // mode_cmd 0 = off = 2[ms] @@ -196,8 +193,7 @@ void Veml6070ModeCmd(boolean mode_cmd) uint8_t status = Wire.endTransmission(); // action on status if (!status) { - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070 mode_cmd", VEML6070_ADDR_L); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "VEML6070 mode_cmd", VEML6070_ADDR_L); } } @@ -241,8 +237,7 @@ double Veml6070UvRiskLevel(uint16_t uv_level) // out of range and much to high - it must be outerspace or sensor damaged snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_7); return ( risk = 99 ); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "VEML6070 out of range %d"), risk); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "VEML6070 out of range %d"), risk); } } @@ -270,7 +265,7 @@ double Veml6070UvPower(double uvrisk) /********************************************************************************************/ -void Veml6070Show(boolean json) +void Veml6070Show(bool json) { if (veml6070_type) { // convert double values to string @@ -307,9 +302,9 @@ void Veml6070Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns11(byte function) +bool Xsns11(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_12_ads1115.ino b/sonoff/xsns_12_ads1115.ino index d07831725..a8f0d8531 100644 --- a/sonoff/xsns_12_ads1115.ino +++ b/sonoff/xsns_12_ads1115.ino @@ -1,7 +1,7 @@ /* xsns_12_ads1115_ada.ino - ADS1115 A/D Converter support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -119,7 +119,8 @@ CONFIG REGISTER uint8_t ads1115_type = 0; uint8_t ads1115_address; uint8_t ads1115_addresses[] = { ADS1115_ADDRESS_ADDR_GND, ADS1115_ADDRESS_ADDR_VDD, ADS1115_ADDRESS_ADDR_SDA, ADS1115_ADDRESS_ADDR_SCL }; - +uint8_t ads1115_found[] = {false,false,false,false}; +int16_t ads1115_values[4]; //Ads1115StartComparator(channel, ADS1115_REG_CONFIG_MODE_SINGLE); //Ads1115StartComparator(channel, ADS1115_REG_CONFIG_MODE_CONTIN); void Ads1115StartComparator(uint8_t channel, uint16_t mode) @@ -160,61 +161,90 @@ int16_t Ads1115GetConversion(uint8_t channel) void Ads1115Detect(void) { uint16_t buffer; - - if (ads1115_type) { - return; - } - - for (byte i = 0; i < sizeof(ads1115_addresses); i++) { - ads1115_address = ads1115_addresses[i]; - if (I2cValidRead16(&buffer, ads1115_address, ADS1115_REG_POINTER_CONVERT)) { - Ads1115StartComparator(i, ADS1115_REG_CONFIG_MODE_CONTIN); - ads1115_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "ADS1115", ads1115_address); - AddLog(LOG_LEVEL_DEBUG); - break; + for (uint8_t i = 0; i < sizeof(ads1115_addresses); i++) { + if (!ads1115_found[i]) { + ads1115_address = ads1115_addresses[i]; + if (I2cValidRead16(&buffer, ads1115_address, ADS1115_REG_POINTER_CONVERT) && + I2cValidRead16(&buffer, ads1115_address, ADS1115_REG_POINTER_CONFIG)) { + Ads1115StartComparator(i, ADS1115_REG_CONFIG_MODE_CONTIN); + ads1115_type = 1; + ads1115_found[i] = 1; + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "ADS1115", ads1115_address); + } } } } -void Ads1115Show(boolean json) +void Ads1115GetValues(uint8_t address) { - if (ads1115_type) { - char stemp[10]; + uint8_t old_address = ads1115_address; + ads1115_address = address; + for (uint8_t i = 0; i < 4; i++) { + ads1115_values[i] = Ads1115GetConversion(i); + //AddLog_P2(LOG_LEVEL_INFO, "Logging ADS1115 %02x (%i) = %i", address, i, ads1115_values[i] ); + } + ads1115_address = old_address; +} - byte dsxflg = 0; - for (byte i = 0; i < 4; i++) { - int16_t adc_value = Ads1115GetConversion(i); +void Ads1115toJSON(char *comma_j) +{ + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s{"), mqtt_data,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]); + comma = (char*)","; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); +} +void Ads1115toString(uint8_t address) +{ + char label[15]; + snprintf_P(label, sizeof(label), "ADS1115(%02x)", address); + + for (uint8_t i = 0; i < 4; i++) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ANALOG, mqtt_data, label, i, ads1115_values[i]); + } +} + +void Ads1115Show(bool json) +{ + if (!ads1115_type) { return; } + + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"ADS1115\":["), mqtt_data); + } + + char *comma = (char*)""; + + for (uint8_t t = 0; t < sizeof(ads1115_addresses); t++) { + //AddLog_P2(LOG_LEVEL_INFO, "Logging ADS1115 %02x", ads1115_addresses[t]); + if (ads1115_found[t]) { + Ads1115GetValues(ads1115_addresses[t]); if (json) { - if (!dsxflg ) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"ADS1115\":{"), mqtt_data); - stemp[0] = '\0'; - } - dsxflg++; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"A%d\":%d"), mqtt_data, stemp, i, adc_value); - strlcpy(stemp, ",", sizeof(stemp)); + Ads1115toJSON(comma); + comma = (char*)","; + } #ifdef USE_WEBSERVER - } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ANALOG, mqtt_data, "ADS1115", i, adc_value); + else { + Ads1115toString(ads1115_addresses[t]); + } #endif // USE_WEBSERVER - } - } - if (json) { - if (dsxflg) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); - } } } + + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]"), mqtt_data); + } } /*********************************************************************************************\ * Interface \*********************************************************************************************/ -boolean Xsns12(byte function) +bool Xsns12(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_12_ads1115_i2cdev.ino b/sonoff/xsns_12_ads1115_i2cdev.ino index 96c2f7006..f73581ec0 100644 --- a/sonoff/xsns_12_ads1115_i2cdev.ino +++ b/sonoff/xsns_12_ads1115_i2cdev.ino @@ -1,7 +1,7 @@ /* xsns_12_ads1115.ino - ADS1x15 A/D Converter support for Sonoff-Tasmota - Copyright (C) 2018 Stefan Bode and Theo Arends + Copyright (C) 2019 Stefan Bode and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -55,7 +55,7 @@ uint8_t ads1115_addresses[] = { ADS1115_ADDRESS_ADDR_SCL // address pin tied to SCL pin }; -int16_t Ads1115GetConversion(byte channel) +int16_t Ads1115GetConversion(uint8_t channel) { switch (channel) { case 0: @@ -81,7 +81,7 @@ void Ads1115Detect(void) return; } - for (byte i = 0; i < sizeof(ads1115_addresses); i++) { + for (uint8_t i = 0; i < sizeof(ads1115_addresses); i++) { ads1115_address = ads1115_addresses[i]; ADS1115 adc0(ads1115_address); if (adc0.testConnection()) { @@ -90,20 +90,19 @@ void Ads1115Detect(void) adc0.setRate(ADS1115_RATE_860); adc0.setMode(ADS1115_MODE_CONTINUOUS); ads1115_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "ADS1115", ads1115_address); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "ADS1115", ads1115_address); break; } } } -void Ads1115Show(boolean json) +void Ads1115Show(bool json) { if (ads1115_type) { char stemp[10]; - byte dsxflg = 0; - for (byte i = 0; i < 4; i++) { + uint8_t dsxflg = 0; + for (uint8_t i = 0; i < 4; i++) { int16_t adc_value = Ads1115GetConversion(i); if (json) { @@ -132,9 +131,9 @@ void Ads1115Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns12(byte function) +bool Xsns12(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_13_ina219.ino b/sonoff/xsns_13_ina219.ino index ae5999a7e..88f6ce240 100644 --- a/sonoff/xsns_13_ina219.ino +++ b/sonoff/xsns_13_ina219.ino @@ -1,7 +1,7 @@ /* xsns_13_ina219.ino - INA219 Current Sensor support for Sonoff-Tasmota - Copyright (C) 2018 Stefan Bode and Theo Arends + Copyright (C) 2019 Stefan Bode and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -177,7 +177,7 @@ bool Ina219Read(void) bool Ina219CommandSensor(void) { - boolean serviced = true; + bool serviced = true; if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { Settings.ina219_mode = XdrvMailbox.payload; @@ -194,12 +194,11 @@ void Ina219Detect(void) { if (ina219_type) { return; } - for (byte i = 0; i < sizeof(ina219_addresses); i++) { + for (uint8_t i = 0; i < sizeof(ina219_addresses); i++) { ina219_address = ina219_addresses[i]; if (Ina219SetCalibration(Settings.ina219_mode)) { ina219_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, ina219_types, ina219_address); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, ina219_types, ina219_address); break; } } @@ -229,7 +228,7 @@ const char HTTP_SNS_INA219_DATA[] PROGMEM = "%s" "{s}INA219 " D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"; #endif // USE_WEBSERVER -void Ina219Show(boolean json) +void Ina219Show(bool json) { if (ina219_valid) { float fpower = ina219_voltage * ina219_current; @@ -261,13 +260,13 @@ void Ina219Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns13(byte function) +bool Xsns13(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { - case FUNC_COMMAND: + case FUNC_COMMAND_SENSOR: if ((XSNS_13 == XdrvMailbox.index) && (ina219_type)) { result = Ina219CommandSensor(); } diff --git a/sonoff/xsns_14_sht3x.ino b/sonoff/xsns_14_sht3x.ino index 6738b866a..fcb7f4a22 100755 --- a/sonoff/xsns_14_sht3x.ino +++ b/sonoff/xsns_14_sht3x.ino @@ -1,7 +1,7 @@ /* xsns_14_sht3x.ino - SHT3X temperature and humidity sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -82,24 +82,23 @@ void Sht3xDetect(void) float t; float h; - for (byte i = 0; i < SHT3X_MAX_SENSORS; i++) { + for (uint8_t i = 0; i < SHT3X_MAX_SENSORS; i++) { if (Sht3xRead(t, h, sht3x_addresses[i])) { sht3x_sensors[sht3x_count].address = sht3x_addresses[i]; GetTextIndexed(sht3x_sensors[sht3x_count].types, sizeof(sht3x_sensors[sht3x_count].types), i, kShtTypes); - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, sht3x_sensors[sht3x_count].types, sht3x_sensors[sht3x_count].address); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, sht3x_sensors[sht3x_count].types, sht3x_sensors[sht3x_count].address); sht3x_count++; } } } -void Sht3xShow(boolean json) +void Sht3xShow(bool json) { if (sht3x_count) { float t; float h; char types[11]; - for (byte i = 0; i < sht3x_count; i++) { + for (uint8_t i = 0; i < sht3x_count; i++) { if (Sht3xRead(t, h, sht3x_sensors[i].address)) { if (0 == i) { SetGlobalValues(t, h); } @@ -140,9 +139,9 @@ void Sht3xShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns14(byte function) +bool Xsns14(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_15_mhz19.ino b/sonoff/xsns_15_mhz19.ino index 968c0d021..1e21aa6fb 100644 --- a/sonoff/xsns_15_mhz19.ino +++ b/sonoff/xsns_15_mhz19.ino @@ -1,7 +1,7 @@ /* xsns_15_mhz19.ino - MH-Z19(B) CO2 sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -39,7 +39,10 @@ enum MhzFilterOptions {MHZ19_FILTER_OFF, MHZ19_FILTER_OFF_ALLSAMPLES, MHZ19_FILT /*********************************************************************************************\ * Source: http://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf * - * Automatic Baseline Correction (ABC logic function) + * Automatic Baseline Correction (ABC logic function) is enabled by default but may be disabled with command + * Sensor15 0 + * and enabled again with command + * Sensor15 1 * * ABC logic function refers to that sensor itself do zero point judgment and automatic calibration procedure * intelligently after a continuous operation period. The automatic calibration cycle is every 24 hours after powered on. @@ -52,10 +55,6 @@ enum MhzFilterOptions {MHZ19_FILTER_OFF, MHZ19_FILTER_OFF_ALLSAMPLES, MHZ19_FILT * Please do zero calibration timely, such as manual or commend calibration. \*********************************************************************************************/ -#define MHZ19_ABC_ENABLE 1 // Automatic Baseline Correction (0 = off, 1 = on (default)) - -/*********************************************************************************************/ - #include #ifndef CO2_LOW @@ -70,7 +69,10 @@ enum MhzFilterOptions {MHZ19_FILTER_OFF, MHZ19_FILTER_OFF_ALLSAMPLES, MHZ19_FILT TasmotaSerial *MhzSerial; -const char kMhzTypes[] PROGMEM = "MHZ19|MHZ19B"; +const char kMhzModels[] PROGMEM = "|B"; + +const char ABC_ENABLED[] PROGMEM = "ABC is Enabled"; +const char ABC_DISABLED[] PROGMEM = "ABC is Enabled"; 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 = { @@ -88,9 +90,7 @@ const uint8_t kMhzCommands[][4] PROGMEM = { uint8_t mhz_type = 1; uint16_t mhz_last_ppm = 0; uint8_t mhz_filter = MHZ19_FILTER_OPTION; -bool mhz_abc_enable = MHZ19_ABC_ENABLE; bool mhz_abc_must_apply = false; -char mhz_types[7]; float mhz_temperature = 0; uint8_t mhz_retry = MHZ19_RETRY_COUNT; @@ -99,17 +99,17 @@ uint8_t mhz_state = 0; /*********************************************************************************************/ -byte MhzCalculateChecksum(byte *array) +uint8_t MhzCalculateChecksum(uint8_t *array) { - byte checksum = 0; - for (byte i = 1; i < 8; i++) { + uint8_t checksum = 0; + for (uint8_t i = 1; i < 8; i++) { checksum += array[i]; } checksum = 255 - checksum; return (checksum +1); } -size_t MhzSendCmd(byte command_id) +size_t MhzSendCmd(uint8_t command_id) { uint8_t mhz_send[9] = { 0 }; @@ -123,8 +123,7 @@ size_t MhzSendCmd(byte command_id) memcpy_P(&mhz_send[6], kMhzCommands[command_id] + sizeof(uint16_t), sizeof(uint16_t)); mhz_send[8] = MhzCalculateChecksum(mhz_send); - snprintf_P(log_data, sizeof(log_data), PSTR("Final MhzCommand: %x %x %x %x %x %x %x %x %x"),mhz_send[0],mhz_send[1],mhz_send[2],mhz_send[3],mhz_send[4],mhz_send[5],mhz_send[6],mhz_send[7],mhz_send[8]); - AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Final MhzCommand: %x %x %x %x %x %x %x %x %x"),mhz_send[0],mhz_send[1],mhz_send[2],mhz_send[3],mhz_send[4],mhz_send[5],mhz_send[6],mhz_send[7],mhz_send[8]); return MhzSerial->write(mhz_send, sizeof(mhz_send)); } @@ -198,14 +197,14 @@ void MhzEverySecond(void) } } - AddLogSerial(LOG_LEVEL_DEBUG_MORE, mhz_response, counter); + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, mhz_response, counter); if (counter < 9) { // AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "MH-Z19 comms timeout")); return; } - byte crc = MhzCalculateChecksum(mhz_response); + uint8_t crc = MhzCalculateChecksum(mhz_response); if (mhz_response[8] != crc) { // AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "MH-Z19 crc error")); return; @@ -219,7 +218,7 @@ void MhzEverySecond(void) uint16_t u = (mhz_response[6] << 8) | mhz_response[7]; if (15000 == u) { // During (and only ever at) sensor boot, 'u' is reported as 15000 - if (!mhz_abc_enable) { + if (Settings.SensorBits1.mhz19b_abc_disable) { // After bootup of the sensor the ABC will be enabled. // Thus only actively disable after bootup. mhz_abc_must_apply = true; @@ -236,7 +235,7 @@ void MhzEverySecond(void) if (0 == s || 64 == s) { // Reading is stable. if (mhz_abc_must_apply) { mhz_abc_must_apply = false; - if (mhz_abc_enable) { + if (!Settings.SensorBits1.mhz19b_abc_disable) { MhzSendCmd(MHZ_CMND_ABCENABLE); } else { MhzSendCmd(MHZ_CMND_ABCDISABLE); @@ -253,8 +252,8 @@ void MhzEverySecond(void) /*********************************************************************************************\ * Command Sensor15 * - * 0 - (Not implemented) ABC Off - * 1 - (Not implemented) ABC On + * 0 - ABC Off + * 1 - ABC On (Default) * 2 - Manual start = ABC Off * 3 - (Not implemented) Optional filter settings * 9 - Reset @@ -271,9 +270,19 @@ void MhzEverySecond(void) bool MhzCommandSensor(void) { - boolean serviced = true; + bool serviced = true; switch (XdrvMailbox.payload) { + 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); + 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); + 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); @@ -299,7 +308,11 @@ bool MhzCommandSensor(void) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_5000); break; default: - serviced = false; + if (!Settings.SensorBits1.mhz19b_abc_disable) { + snprintf_P(mqtt_data, sizeof(mqtt_data), 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); + } } return serviced; @@ -320,21 +333,26 @@ void MhzInit(void) } } -void MhzShow(boolean json) +void MhzShow(bool json) { + char types[7] = "MHZ19B"; // MHZ19B for legacy reasons. Prefered is MHZ19 char temperature[33]; dtostrfd(mhz_temperature, Settings.flag2.temperature_resolution, temperature); - GetTextIndexed(mhz_types, sizeof(mhz_types), mhz_type -1, kMhzTypes); + char model[3]; + GetTextIndexed(model, sizeof(model), mhz_type -1, kMhzModels); if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_CO2 "\":%d,\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, mhz_types, mhz_last_ppm, temperature); + 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); #ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, mhz_last_ppm); + if (0 == tele_period) { + DomoticzSensor(DZ_AIRQUALITY, mhz_last_ppm); + DomoticzSensor(DZ_TEMP, temperature); + } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CO2, mqtt_data, mhz_types, mhz_last_ppm); - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, mhz_types, temperature, TempUnit()); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CO2, mqtt_data, types, mhz_last_ppm); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, types, temperature, TempUnit()); #endif // USE_WEBSERVER } } @@ -343,9 +361,9 @@ void MhzShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns15(byte function) +bool Xsns15(uint8_t function) { - boolean result = false; + bool result = false; if (mhz_type) { switch (function) { @@ -355,7 +373,7 @@ boolean Xsns15(byte function) case FUNC_EVERY_SECOND: MhzEverySecond(); break; - case FUNC_COMMAND: + case FUNC_COMMAND_SENSOR: if (XSNS_15 == XdrvMailbox.index) { result = MhzCommandSensor(); } diff --git a/sonoff/xsns_16_tsl2561.ino b/sonoff/xsns_16_tsl2561.ino index 0285c55e0..688cdf419 100644 --- a/sonoff/xsns_16_tsl2561.ino +++ b/sonoff/xsns_16_tsl2561.ino @@ -1,7 +1,7 @@ /* xsns_16_tsl2561.ino - TSL2561 light sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends and Joachim Banzhaf + Copyright (C) 2019 Theo Arends and Joachim Banzhaf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -48,7 +48,6 @@ bool Tsl2561Read(void) uint16_t scaledFull, scaledIr; uint32_t full, ir; - if (Tsl.available()) { if (Tsl.on()) { if (Tsl.id(id) && Tsl2561Util::autoGain(Tsl, gain, exposure, scaledFull, scaledIr) @@ -58,7 +57,6 @@ bool Tsl2561Read(void) tsl2561_milliLux = 0; } } - } tsl2561_valid = SENSOR_MAX_MISS; return true; } @@ -66,13 +64,14 @@ bool Tsl2561Read(void) void Tsl2561Detect(void) { if (tsl2561_type) { return; } + uint8_t id; - if (!Tsl.available()) { + if (I2cDevice(0x29) || I2cDevice(0x39) || I2cDevice(0x49)) { Tsl.begin(); - if (Tsl.available()) { + if (!Tsl.id(id)) return; + if (Tsl.on()) { tsl2561_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, tsl2561_types, Tsl.address()); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, tsl2561_types, Tsl.address(), id); } } } @@ -88,7 +87,7 @@ void Tsl2561EverySecond(void) if (tsl2561_type) { if (!Tsl2561Read()) { AddLogMissed(tsl2561_types, tsl2561_valid); -// if (!tsl2561_valid) { tsl2561_type = 0; } + if (!tsl2561_valid) { tsl2561_type = 0; } } } } @@ -99,7 +98,7 @@ const char HTTP_SNS_TSL2561[] PROGMEM = "%s{s}TSL2561 " D_ILLUMINANCE "{m}%u.%03u " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER -void Tsl2561Show(boolean json) +void Tsl2561Show(bool json) { if (tsl2561_valid) { if (json) { @@ -120,9 +119,9 @@ void Tsl2561Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns16(byte function) +bool Xsns16(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_17_senseair.ino b/sonoff/xsns_17_senseair.ino index 967563972..461b41145 100644 --- a/sonoff/xsns_17_senseair.ino +++ b/sonoff/xsns_17_senseair.ino @@ -1,7 +1,7 @@ /* xsns_17_senseair.ino - SenseAir CO2 sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -70,19 +70,16 @@ void Senseair250ms(void) // Every 250 mSec if (data_ready) { uint8_t error = SenseairModbus->Receive16BitRegister(&value); if (error) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "SenseAir response error %d"), error); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir response error %d"), error); } else { switch(senseair_read_state) { case 0: // 0x1A (26) READ_TYPE_LOW - S8: fe 04 02 01 77 ec 92 senseair_type = 2; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "SenseAir type id low %04X"), value); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir type id low %04X"), value); break; case 1: // 0x00 (0) READ_ERRORLOG - fe 04 02 00 00 ad 24 if (value) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "SenseAir error %04X"), value); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir error %04X"), value); } break; case 2: // 0x03 (3) READ_CO2 - fe 04 02 06 2c af 59 @@ -98,13 +95,11 @@ void Senseair250ms(void) // Every 250 mSec case 5: // 0x1C (28) READ_RELAY_STATE - S8: fe 04 02 01 54 ad 4b - firmware version { bool relay_state = value >> 8 & 1; - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "SenseAir relay state %d"), relay_state); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir relay state %d"), relay_state); break; } case 6: // 0x0A (10) READ_TEMP_ADJUSTMENT - S8: fe 84 02 f2 f1 - Illegal Data Address - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "SenseAir temp adjustment %d"), value); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir temp adjustment %d"), value); break; } } @@ -145,7 +140,7 @@ void SenseairInit(void) } } -void SenseairShow(boolean json) +void SenseairShow(bool json) { char temperature[33]; dtostrfd(senseair_temperature, Settings.flag2.temperature_resolution, temperature); @@ -177,9 +172,9 @@ void SenseairShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns17(byte function) +bool Xsns17(uint8_t function) { - boolean result = false; + bool result = false; if (senseair_type) { switch (function) { diff --git a/sonoff/xsns_18_pms5003.ino b/sonoff/xsns_18_pms5003.ino index 271b94301..82959ff88 100644 --- a/sonoff/xsns_18_pms5003.ino +++ b/sonoff/xsns_18_pms5003.ino @@ -1,7 +1,7 @@ /* xsns_18_pms5003.ino - PMS5003-7003 particle concentration sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -45,7 +45,7 @@ struct pms5003data { /*********************************************************************************************/ -boolean PmsReadData(void) +bool PmsReadData(void) { if (! PmsSerial->available()) { return false; @@ -62,7 +62,7 @@ boolean PmsReadData(void) PmsSerial->readBytes(buffer, 32); PmsSerial->flush(); // Make room for another burst - AddLogSerial(LOG_LEVEL_DEBUG_MORE, buffer, 32); + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, 32); // get checksum ready for (uint8_t i = 0; i < 30; i++) { @@ -128,7 +128,7 @@ const char HTTP_PMS5003_SNS[] PROGMEM = "%s" "{s}PMS5003 " D_PARTICALS_BEYOND " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER -void PmsShow(boolean json) +void PmsShow(bool json) { if (pms_valid) { if (json) { @@ -158,9 +158,9 @@ void PmsShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns18(byte function) +bool Xsns18(uint8_t function) { - boolean result = false; + bool result = false; if (pms_type) { switch (function) { diff --git a/sonoff/xsns_19_mgs.ino b/sonoff/xsns_19_mgs.ino index 36ce969f7..dacd1430e 100644 --- a/sonoff/xsns_19_mgs.ino +++ b/sonoff/xsns_19_mgs.ino @@ -1,7 +1,7 @@ /* xsns_19_mgs.ino - Xadow and Grove Mutichannel Gas sensor support for Sonoff-Tasmota - Copyright (C) 2018 Palich2000 and Theo Arends + Copyright (C) 2019 Palich2000 and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -38,12 +38,11 @@ void MGSInit(void) { gas.begin(MGS_SENSOR_ADDR); } -boolean MGSPrepare(void) +bool MGSPrepare(void) { gas.begin(MGS_SENSOR_ADDR); if (!gas.isError()) { - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MultiGasSensor", MGS_SENSOR_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "MultiGasSensor", MGS_SENSOR_ADDR); return true; } else { return false; @@ -61,7 +60,7 @@ char* measure_gas(int gas_type, char* buffer) const char HTTP_MGS_GAS[] PROGMEM = "%s{s}MGS %s{m}%s " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER -void MGSShow(boolean json) +void MGSShow(bool json) { char buffer[33]; if (json) { @@ -91,9 +90,9 @@ void MGSShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns19(byte function) +bool Xsns19(uint8_t function) { - boolean result = false; + bool result = false; static int detected = false; if (i2c_flg) { diff --git a/sonoff/xsns_20_novasds.ino b/sonoff/xsns_20_novasds.ino index dfb08ac5a..d40301508 100644 --- a/sonoff/xsns_20_novasds.ino +++ b/sonoff/xsns_20_novasds.ino @@ -1,7 +1,7 @@ /* xsns_20_novasds.ino - Nova SDS011/SDS021 particle concentration sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ /*********************************************************************************************\ * Nova Fitness SDS011 (and possibly SDS021) particle concentration sensor * For background information see http://aqicn.org/sensor/sds011/ - * For protocol specification see + * For protocol specification see * https://cdn.sparkfun.com/assets/parts/1/2/2/7/5/Laser_Dust_Sensor_Control_Protocol_V1.3.pdf * * Hardware Serial will be selected if GPIO3 = [SDS0X01] @@ -74,18 +74,17 @@ struct sds011data { #define NOVA_SDS_SLEEP 1 // Subcmnd "sleep mode" -bool NovaSdsCommand(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint16_t sensorid, byte *buffer) +bool NovaSdsCommand(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint16_t sensorid, uint8_t *buffer) { uint8_t novasds_cmnd[19] = {0xAA, 0xB4, byte1, byte2, byte3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (uint8_t)(sensorid & 0xFF), (uint8_t)((sensorid>>8) & 0xFF), 0x00, 0xAB}; // calc crc - for (byte i = 2; i < 17; i++) { + for (uint8_t i = 2; i < 17; i++) { novasds_cmnd[17] += novasds_cmnd[i]; } - //~ snprintf_P(log_data, sizeof(log_data), PSTR("SDS: Send %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X"), + //~ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SDS: Send %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X"), //~ novasds_cmnd[0],novasds_cmnd[1],novasds_cmnd[2],novasds_cmnd[3],novasds_cmnd[4],novasds_cmnd[5],novasds_cmnd[6],novasds_cmnd[7],novasds_cmnd[8],novasds_cmnd[9], //~ novasds_cmnd[10],novasds_cmnd[11],novasds_cmnd[12],novasds_cmnd[13],novasds_cmnd[14],novasds_cmnd[15],novasds_cmnd[16],novasds_cmnd[17],novasds_cmnd[18]); - //~ AddLog(LOG_LEVEL_DEBUG); // send cmnd NovaSdsSerial->write(novasds_cmnd, sizeof(novasds_cmnd)); NovaSdsSerial->flush(); @@ -97,7 +96,7 @@ bool NovaSdsCommand(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint16_t sensor // timeout return false; } - byte recbuf[10]; + uint8_t recbuf[10]; memset(recbuf, 0, sizeof(recbuf)); // sync to 0xAA header while ( (TimePassedSince(cmndtime) < NOVA_SDS_RECDATA_TIMEOUT) && ( NovaSdsSerial->available() > 0) && (0xAA != (recbuf[0] = NovaSdsSerial->read())) ); @@ -108,7 +107,7 @@ bool NovaSdsCommand(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint16_t sensor // read rest (9 of 10 bytes) of message NovaSdsSerial->readBytes(&recbuf[1], 9); - AddLogSerial(LOG_LEVEL_DEBUG_MORE, recbuf, sizeof(recbuf)); + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, recbuf, sizeof(recbuf)); if ( NULL != buffer ) { // return data to buffer @@ -134,7 +133,7 @@ void NovaSdsSetWorkPeriod(void) bool NovaSdsReadData(void) { - byte d[10]; + uint8_t d[10]; if ( ! NovaSdsCommand(NOVA_SDS_QUERY_DATA, 0, 0, NOVA_SDS_DEVICE_ID, d) ) { return false; } @@ -186,7 +185,7 @@ const char HTTP_SDS0X1_SNS[] PROGMEM = "%s" "{s}SDS0X1 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER -void NovaSdsShow(boolean json) +void NovaSdsShow(bool json) { if (novasds_valid) { float pm10f = (float)(novasds_data.pm100) / 10.0f; @@ -215,9 +214,9 @@ void NovaSdsShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns20(byte function) +bool Xsns20(uint8_t function) { - boolean result = false; + bool result = false; if (novasds_type) { switch (function) { diff --git a/sonoff/xsns_21_sgp30.ino b/sonoff/xsns_21_sgp30.ino index 7c22da514..48fde6793 100644 --- a/sonoff/xsns_21_sgp30.ino +++ b/sonoff/xsns_21_sgp30.ino @@ -1,7 +1,7 @@ /* xsns_21_sgp30.ino - SGP30 gas and air quality sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,10 +44,8 @@ void Sgp30Update(void) // Perform every second to ensure proper operation of th if (!sgp30_type) { if (sgp.begin()) { sgp30_type = 1; -// snprintf_P(log_data, sizeof(log_data), PSTR("SGP: Serialnumber 0x%04X-0x%04X-0x%04X"), sgp.serialnumber[0], sgp.serialnumber[1], sgp.serialnumber[2]); -// AddLog(LOG_LEVEL_DEBUG); - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "SGP30", 0x58); - AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SGP: Serialnumber 0x%04X-0x%04X-0x%04X"), sgp.serialnumber[0], sgp.serialnumber[1], sgp.serialnumber[2]); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "SGP30", 0x58); } } else { if (!sgp.IAQmeasure()) return; // Measurement failed @@ -59,8 +57,7 @@ void Sgp30Update(void) // Perform every second to ensure proper operation of th uint16_t eCO2_base; if (!sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) return; // Failed to get baseline readings -// snprintf_P(log_data, sizeof(log_data), PSTR("SGP: Baseline values eCO2 0x%04X, TVOC 0x%04X"), eCO2_base, TVOC_base); -// AddLog(LOG_LEVEL_DEBUG); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SGP: Baseline values eCO2 0x%04X, TVOC 0x%04X"), eCO2_base, TVOC_base); } sgp30_ready = 1; } @@ -70,7 +67,7 @@ const char HTTP_SNS_SGP30[] PROGMEM = "%s" "{s}SGP30 " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}" // {s} = , {m} = , {e} = "{s}SGP30 " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}"; -void Sgp30Show(boolean json) +void Sgp30Show(bool json) { if (sgp30_ready) { if (json) { @@ -90,9 +87,9 @@ void Sgp30Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns21(byte function) +bool Xsns21(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_22_sr04.ino b/sonoff/xsns_22_sr04.ino index 0278011e1..a52898728 100644 --- a/sonoff/xsns_22_sr04.ino +++ b/sonoff/xsns_22_sr04.ino @@ -1,7 +1,7 @@ /* xsns_22_sr04.ino - SR04 ultrasonic sensor support for Sonoff-Tasmota - Copyright (C) 2018 Nuno Ferreira and Theo Arends + Copyright (C) 2019 Nuno Ferreira and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,6 +28,8 @@ * - https://www.dfrobot.com/wiki/index.php/Weather-proof_Ultrasonic_Sensor_SKU_:_SEN0207 \*********************************************************************************************/ +#define XSNS_22 22 + uint8_t sr04_echo_pin = 0; uint8_t sr04_trig_pin = 0; real64_t distance; @@ -46,7 +48,7 @@ const char HTTP_SNS_DISTANCE[] PROGMEM = "%s{s}SR04 " D_DISTANCE "{m}%s" D_UNIT_CENTIMETER "{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER -void Sr04Show(boolean json) +void Sr04Show(bool json) { distance = (real64_t)(sonar->ping_median(5))/ US_ROUNDTRIP_CM; @@ -73,11 +75,9 @@ void Sr04Show(boolean json) * Interface \*********************************************************************************************/ -#define XSNS_22 - -boolean Xsns22(byte function) +bool Xsns22(uint8_t function) { - boolean result = false; + bool result = false; if ((pin[GPIO_SR04_ECHO] < 99) && (pin[GPIO_SR04_TRIG] < 99)) { switch (function) { diff --git a/sonoff/xsns_23_sdm120.ino b/sonoff/xsns_23_sdm120.ino index 9f27927e8..67971845a 100644 --- a/sonoff/xsns_23_sdm120.ino +++ b/sonoff/xsns_23_sdm120.ino @@ -1,7 +1,7 @@ /* xsns_23_sdm120.ino - Eastron SDM120-Modbus energy meter support for Sonoff-Tasmota - Copyright (C) 2018 Gennaro Tortone + Copyright (C) 2019 Gennaro Tortone This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -165,8 +165,7 @@ void SDM120250ms(void) // Every 250 mSec if (data_ready) { uint8_t error = SDM120_ModbusReceive(&value); if (error) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "SDM120 response error %d"), error); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SDM120 response error %d"), error); } else { switch(sdm120_read_state) { case 0: @@ -281,7 +280,7 @@ const char HTTP_SNS_SDM120_DATA[] PROGMEM = "%s" ; #endif // USE_WEBSERVER -void SDM120Show(boolean json) +void SDM120Show(bool json) { char voltage[33]; dtostrfd(sdm120_voltage, Settings.flag2.voltage_resolution, voltage); @@ -343,9 +342,9 @@ void SDM120Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns23(byte function) +bool Xsns23(uint8_t function) { - boolean result = false; + bool result = false; if (sdm120_type) { switch (function) { diff --git a/sonoff/xsns_24_si1145.ino b/sonoff/xsns_24_si1145.ino index 7b051ebe0..19855bf42 100644 --- a/sonoff/xsns_24_si1145.ino +++ b/sonoff/xsns_24_si1145.ino @@ -1,7 +1,7 @@ /* xsns_24_si1145.ino - SI1145/46/47 UV Index / IR / Visible light sensor support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -276,7 +276,7 @@ void Si1145DeInit(void) Si1145WriteByte(SI114X_COMMAND, SI114X_PSALS_AUTO); } -boolean Si1145Begin(void) +bool Si1145Begin(void) { if (!Si1145Present()) { return false; } @@ -310,8 +310,7 @@ void Si1145Update(void) if (!si1145_type) { if (Si1145Begin()) { si1145_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "SI1145", SI114X_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "SI1145", SI114X_ADDR); } } } @@ -323,14 +322,14 @@ const char HTTP_SNS_SI1145[] PROGMEM = "%s" "{s}SI1145 " D_UV_INDEX "{m}%d.%d{e}"; #endif // USE_WEBSERVER -void Si1145Show(boolean json) +void Si1145Show(bool json) { if (si1145_type && Si1145Present()) { uint16_t visible = Si1145ReadVisible(); uint16_t infrared = Si1145ReadIR(); uint16_t uvindex = Si1145ReadUV(); if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SI1145\":{\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_INFRARED "\":%d,\"" D_JSON_UVINDEX "\":%d.%d}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SI1145\":{\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_INFRARED "\":%d,\"" D_JSON_UV_INDEX "\":%d.%d}"), mqtt_data, visible, infrared, uvindex /100, uvindex %100); #ifdef USE_DOMOTICZ if (0 == tele_period) DomoticzSensor(DZ_ILLUMINANCE, visible); @@ -349,9 +348,9 @@ void Si1145Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns24(byte function) +bool Xsns24(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_25_sdm630.ino b/sonoff/xsns_25_sdm630.ino index 9060444b3..2f8e0acd8 100644 --- a/sonoff/xsns_25_sdm630.ino +++ b/sonoff/xsns_25_sdm630.ino @@ -1,7 +1,7 @@ /* xsns_25_sdm630.ino - Eastron SDM630-Modbus energy meter support for Sonoff-Tasmota - Copyright (C) 2018 Gennaro Tortone + Copyright (C) 2019 Gennaro Tortone This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -155,8 +155,7 @@ void SDM630250ms(void) // Every 250 mSec if (data_ready) { uint8_t error = SDM630_ModbusReceive(&value); if (error) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "SDM630 response error %d"), error); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SDM630 response error %d"), error); } else { switch(sdm630_read_state) { case 0: @@ -267,7 +266,7 @@ const char HTTP_SNS_SDM630_DATA[] PROGMEM = "%s" "{s}SDM630 " D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; #endif // USE_WEBSERVER -void SDM630Show(boolean json) +void SDM630Show(bool json) { char voltage_l1[33]; dtostrfd(sdm630_voltage[0], Settings.flag2.voltage_resolution, voltage_l1); @@ -326,9 +325,9 @@ void SDM630Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns25(byte function) +bool Xsns25(uint8_t function) { - boolean result = false; + bool result = false; if (sdm630_type) { switch (function) { diff --git a/sonoff/xsns_26_lm75ad.ino b/sonoff/xsns_26_lm75ad.ino index 3b548fa8f..8a48327bf 100644 --- a/sonoff/xsns_26_lm75ad.ino +++ b/sonoff/xsns_26_lm75ad.ino @@ -1,7 +1,7 @@ /* xsns_26_lm75ad.ino - Support for I2C LM75AD Temperature Sensor - Copyright (C) 2018 Andre Thomas and Theo Arends + Copyright (C) 2019 Andre Thomas and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -53,13 +53,12 @@ void LM75ADDetect(void) if (lm75ad_type) { return; } uint16_t buffer; - for (byte i = 0; i < sizeof(lm75ad_addresses); i++) { + for (uint8_t i = 0; i < sizeof(lm75ad_addresses); i++) { lm75ad_address = lm75ad_addresses[i]; if (I2cValidRead16(&buffer, lm75ad_address, LM75_THYST_REGISTER)) { if (buffer == 0x4B00) { lm75ad_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "LM75AD", lm75ad_address); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "LM75AD", lm75ad_address); break; } } @@ -78,7 +77,7 @@ float LM75ADGetTemp(void) { return ConvertTemp(sign * t * 0.125); } -void LM75ADShow(boolean json) +void LM75ADShow(bool json) { if (lm75ad_type) { float t = LM75ADGetTemp(); @@ -102,9 +101,9 @@ void LM75ADShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns26(byte function) +bool Xsns26(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_27_apds9960.ino b/sonoff/xsns_27_apds9960.ino index 33b98a5d2..765c89263 100644 --- a/sonoff/xsns_27_apds9960.ino +++ b/sonoff/xsns_27_apds9960.ino @@ -1,7 +1,7 @@ /* xsns_27_apds9960.ino - Support for I2C APDS9960 Proximity Sensor for Sonoff-Tasmota - Copyright (C) 2018 Shawn Hymel/Sparkfun and Theo Arends + Copyright (C) 2019 Shawn Hymel/Sparkfun and Theo Arends Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -1518,8 +1518,7 @@ int16_t readGesture(void) if (gesture_loop_counter == APDS9960_MAX_GESTURE_CYCLES){ // We will escape after a few loops disableGestureSensor(); // stop the sensor to prevent problems with power consumption/blocking and return to the main loop APDS9960_overload = true; // we report this as "long"-gesture - snprintf_P(log_data, sizeof(log_data), PSTR("Sensor overload")); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("Sensor overload")); } gesture_loop_counter += 1; /* Wait some time to collect next batch of FIFO data */ @@ -1794,33 +1793,32 @@ void handleGesture(void) { if (isGestureAvailable() ) { switch (readGesture()) { case DIR_UP: - snprintf_P(log_data, sizeof(log_data), PSTR("UP")); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("UP")); snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Up")); break; case DIR_DOWN: - snprintf_P(log_data, sizeof(log_data), PSTR("DOWN")); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("DOWN")); snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Down")); break; case DIR_LEFT: - snprintf_P(log_data, sizeof(log_data), PSTR("LEFT")); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("LEFT")); snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Left")); break; case DIR_RIGHT: - snprintf_P(log_data, sizeof(log_data), PSTR("RIGHT")); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("RIGHT")); snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Right")); break; default: if(APDS9960_overload) { - snprintf_P(log_data, sizeof(log_data), PSTR("LONG")); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("LONG")); snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Long")); } else{ - snprintf_P(log_data, sizeof(log_data), PSTR("NONE")); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("NONE")); snprintf_P(currentGesture, sizeof(currentGesture), PSTR("None")); } } - AddLog(LOG_LEVEL_DEBUG); mqtt_data[0] = '\0'; if (MqttShowSensor()) { @@ -1903,13 +1901,12 @@ bool APDS9960_detect(void) return true; } - boolean success = false; + bool success = false; APDS9960type = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ID); if (APDS9960type == APDS9960_CHIPID_1 || APDS9960type == APDS9960_CHIPID_2) { strcpy_P(APDS9960stype, PSTR("APDS9960")); - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, APDS9960stype, APDS9960_I2C_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, APDS9960stype, APDS9960_I2C_ADDR); if (APDS9960_init()) { success = true; AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "APDS9960 initialized")); @@ -1919,12 +1916,10 @@ bool APDS9960_detect(void) } else { if (APDS9960type == APDS9930_CHIPID_1 || APDS9960type == APDS9930_CHIPID_2) { - snprintf_P(log_data, sizeof(log_data), PSTR("APDS9930 found at address 0x%x, unsupported chip"), APDS9960_I2C_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("APDS9930 found at address 0x%x, unsupported chip"), APDS9960_I2C_ADDR); } else{ - snprintf_P(log_data, sizeof(log_data), PSTR("APDS9960 not found at address 0x%x"), APDS9960_I2C_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("APDS9960 not found at address 0x%x"), APDS9960_I2C_ADDR); } } currentGesture[0] = '\0'; @@ -1935,7 +1930,7 @@ bool APDS9960_detect(void) * Presentation \*********************************************************************************************/ -void APDS9960_show(boolean json) +void APDS9960_show(bool json) { if (!APDS9960type) { return; @@ -1993,7 +1988,7 @@ void APDS9960_show(boolean json) bool APDS9960CommandSensor(void) { - boolean serviced = true; + bool serviced = true; switch (XdrvMailbox.payload) { case 0: // Off @@ -2039,9 +2034,9 @@ bool APDS9960CommandSensor(void) * Interface \*********************************************************************************************/ -boolean Xsns27(byte function) +bool Xsns27(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { if (FUNC_INIT == function) { @@ -2051,7 +2046,7 @@ boolean Xsns27(byte function) case FUNC_EVERY_50_MSECOND: APDS9960_loop(); break; - case FUNC_COMMAND: + case FUNC_COMMAND_SENSOR: if (XSNS_27 == XdrvMailbox.index) { result = APDS9960CommandSensor(); } diff --git a/sonoff/xsns_28_tm1638.ino b/sonoff/xsns_28_tm1638.ino index 61852b40d..590432dfd 100644 --- a/sonoff/xsns_28_tm1638.ino +++ b/sonoff/xsns_28_tm1638.ino @@ -1,7 +1,7 @@ /* xsns_28_tm1638.ino - TM1638 8 switch, led and 7 segment unit support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -46,7 +46,7 @@ uint8_t tm1638_state = 0; * and from library https://github.com/MartyMacGyver/TM1638-demos-and-examples \*********************************************************************************************/ -void Tm16XXSend(byte data) +void Tm16XXSend(uint8_t data) { for (uint8_t i = 0; i < 8; i++) { digitalWrite(tm1638_data_pin, !!(data & (1 << i))); @@ -56,14 +56,14 @@ void Tm16XXSend(byte data) } } -void Tm16XXSendCommand(byte cmd) +void Tm16XXSendCommand(uint8_t cmd) { digitalWrite(tm1638_strobe_pin, LOW); Tm16XXSend(cmd); digitalWrite(tm1638_strobe_pin, HIGH); } -void TM16XXSendData(byte address, byte data) +void TM16XXSendData(uint8_t address, uint8_t data) { Tm16XXSendCommand(0x44); digitalWrite(tm1638_strobe_pin, LOW); @@ -72,9 +72,9 @@ void TM16XXSendData(byte address, byte data) digitalWrite(tm1638_strobe_pin, HIGH); } -byte Tm16XXReceive(void) +uint8_t Tm16XXReceive(void) { - byte temp = 0; + uint8_t temp = 0; // Pull-up on pinMode(tm1638_data_pin, INPUT); @@ -103,7 +103,7 @@ void Tm16XXClearDisplay(void) } } -void Tm1638SetLED(byte color, byte pos) +void Tm1638SetLED(uint8_t color, uint8_t pos) { TM16XXSendData((pos << 1) + 1, color); } @@ -111,7 +111,7 @@ void Tm1638SetLED(byte color, byte pos) void Tm1638SetLEDs(word leds) { for (int i = 0; i < tm1638_displays; i++) { - byte color = 0; + uint8_t color = 0; if ((leds & (1 << i)) != 0) { color |= TM1638_COLOR_RED; @@ -125,9 +125,9 @@ void Tm1638SetLEDs(word leds) } } -byte Tm1638GetButtons(void) +uint8_t Tm1638GetButtons(void) { - byte keys = 0; + uint8_t keys = 0; digitalWrite(tm1638_strobe_pin, LOW); Tm16XXSend(0x42); @@ -174,10 +174,10 @@ void TmInit(void) void TmLoop(void) { if (tm1638_state) { - byte buttons = Tm1638GetButtons(); - for (byte i = 0; i < MAX_SWITCHES; i++) { - virtualswitch[i] = (buttons &1) ^1; - byte color = (virtualswitch[i]) ? TM1638_COLOR_NONE : TM1638_COLOR_RED; + uint8_t buttons = Tm1638GetButtons(); + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { + SwitchSetVirtual(i, (buttons &1) ^1); + uint8_t color = (SwitchGetVirtual(i)) ? TM1638_COLOR_NONE : TM1638_COLOR_RED; Tm1638SetLED(color, i); buttons >>= 1; } @@ -186,7 +186,7 @@ void TmLoop(void) } /* -void TmShow(boolean json) +void TmShow(bool json) { if (tm1638_type) { @@ -198,9 +198,9 @@ void TmShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns28(byte function) +bool Xsns28(uint8_t function) { - boolean result = false; + bool result = false; if (tm1638_type) { switch (function) { diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 64f3351a5..d7aaaf2ef 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -1,7 +1,7 @@ /* xsns_29_mcp230xx.ino - Support for I2C MCP23008/MCP23017 GPIO Expander - Copyright (C) 2018 Andre Thomas and Theo Arends + Copyright (C) 2019 Andre Thomas and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -81,7 +81,7 @@ void MCP230xx_CheckForIntCounter(void) { } } } - + void MCP230xx_CheckForIntRetainer(void) { uint8_t en = 0; for (uint8_t ca=0;ca<16;ca++) { @@ -210,15 +210,13 @@ void MCP230xx_Detect(void) if (I2cValidRead8(&buffer, USE_MCP230xx_ADDR, MCP230xx_IOCON)) { if (0x00 == buffer) { mcp230xx_type = 1; // We have a MCP23008 - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23008", USE_MCP230xx_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "MCP23008", USE_MCP230xx_ADDR); mcp230xx_pincount = 8; MCP230xx_ApplySettings(); } else { if (0x80 == buffer) { mcp230xx_type = 2; // We have a MCP23017 - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23017", USE_MCP230xx_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "MCP23017", USE_MCP230xx_ADDR); mcp230xx_pincount = 16; // Reset bank mode to 0 I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_IOCON, 0x00); @@ -325,7 +323,7 @@ void MCP230xx_CheckForInterrupt(void) { } } -void MCP230xx_Show(boolean json) +void MCP230xx_Show(bool json) { if (mcp230xx_type) { if (json) { @@ -426,8 +424,8 @@ void MCP230xx_Reset(uint8_t pinmode) { } bool MCP230xx_Command(void) { - boolean serviced = true; - boolean validpin = false; + bool serviced = true; + bool validpin = false; uint8_t paramcount = 0; if (XdrvMailbox.data_len > 0) { paramcount=1; @@ -498,8 +496,7 @@ bool MCP230xx_Command(void) { if (Settings.mcp230xx_config[pin].int_count_en) { Settings.mcp230xx_config[pin].int_count_en=0; MCP230xx_CheckForIntCounter(); - snprintf_P(log_data, sizeof(log_data), PSTR("*** WARNING *** - Disabled INTCNT for pin D%i"),pin); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR("*** WARNING *** - Disabled INTCNT for pin D%i"),pin); } snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_INTCFG_RESPONSE,"DEF",pin,Settings.mcp230xx_config[pin].int_report_defer); // "{\"MCP230xx_INT%s\":{\"D_%i\":%i}}"; return serviced; @@ -537,17 +534,14 @@ bool MCP230xx_Command(void) { Settings.mcp230xx_config[pin].int_count_en=intcnt; if (Settings.mcp230xx_config[pin].int_report_defer) { Settings.mcp230xx_config[pin].int_report_defer=0; - snprintf_P(log_data, sizeof(log_data), PSTR("*** WARNING *** - Disabled INTDEF for pin D%i"),pin); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR("*** WARNING *** - Disabled INTDEF for pin D%i"),pin); } if (Settings.mcp230xx_config[pin].int_report_mode < 3) { Settings.mcp230xx_config[pin].int_report_mode=3; - snprintf_P(log_data, sizeof(log_data), PSTR("*** WARNING *** - Disabled immediate interrupt/telemetry reporting for pin D%i"),pin); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR("*** WARNING *** - Disabled immediate interrupt/telemetry reporting for pin D%i"),pin); } if ((Settings.mcp230xx_config[pin].int_count_en) && (!Settings.mcp230xx_int_timer)) { - snprintf_P(log_data, sizeof(log_data), PSTR("*** WARNING *** - INTCNT enabled for pin D%i but global INTTIMER is disabled!"),pin); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR("*** WARNING *** - INTCNT enabled for pin D%i but global INTTIMER is disabled!"),pin); } MCP230xx_CheckForIntCounter(); // update register on whether or not we should be counting interrupts snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_INTCFG_RESPONSE,"CNT",pin,Settings.mcp230xx_config[pin].int_count_en); // "{\"MCP230xx_INT%s\":{\"D_%i\":%i}}"; @@ -605,7 +599,7 @@ bool MCP230xx_Command(void) { } uint8_t pin = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1)); - + if (pin < mcp230xx_pincount) { if (0 == pin) { if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1), "0")) validpin=true; @@ -767,7 +761,7 @@ void MCP230xx_Interrupt_Retain_Report(void) { uint16_t retainresult = 0; snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"MCP_INTRETAIN\": {"), GetDateAndTime(DT_LOCAL).c_str()); for (uint8_t pinx = 0;pinx < mcp230xx_pincount;pinx++) { - if (Settings.mcp230xx_config[pinx].int_retain_flag) { + if (Settings.mcp230xx_config[pinx].int_retain_flag) { snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"D%i\":%i,"),mqtt_data,pinx,mcp230xx_int_retainer[pinx]); retainresult |= (((mcp230xx_int_retainer[pinx])&1) << pinx); mcp230xx_int_retainer[pinx]=0; @@ -781,9 +775,9 @@ void MCP230xx_Interrupt_Retain_Report(void) { Interface \*********************************************************************************************/ -boolean Xsns29(byte function) +bool Xsns29(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { @@ -820,7 +814,7 @@ boolean Xsns29(byte function) case FUNC_JSON_APPEND: MCP230xx_Show(1); break; - case FUNC_COMMAND: + case FUNC_COMMAND_SENSOR: if (XSNS_29 == XdrvMailbox.index) { result = MCP230xx_Command(); } diff --git a/sonoff/xsns_30_mpr121.ino b/sonoff/xsns_30_mpr121.ino index 4021247a6..01431faa6 100644 --- a/sonoff/xsns_30_mpr121.ino +++ b/sonoff/xsns_30_mpr121.ino @@ -220,8 +220,7 @@ void Mpr121Init(struct mpr121 *pS) if (pS->connected[i]) { // Log sensor found - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121(%c) " D_FOUND_AT " 0x%X"), pS->id[i], pS->i2c_addr[i]); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_I2C "MPR121(%c) " D_FOUND_AT " 0x%X"), pS->id[i], pS->i2c_addr[i]); // Set thresholds for registers 0x41 - 0x5A (ExTTH and ExRTH) for (uint8_t j = 0; j < 13; j++) { @@ -283,12 +282,9 @@ void Mpr121Init(struct mpr121 *pS) // Check if sensor is running pS->running[i] = (0x00 != I2cRead8(pS->i2c_addr[i], MPR121_ECR_REG)); - if (pS->running[i]) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121%c: Running"), pS->id[i]); - } else { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121%c: NOT Running"), pS->id[i]); - } - AddLog(LOG_LEVEL_INFO); + + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_I2C "MPR121%c: %sRunning"), pS->id[i], (pS->running[i]) ? "" : "NOT"); + } else { // Make sure running is false @@ -299,8 +295,7 @@ void Mpr121Init(struct mpr121 *pS) // Display no sensor found message if (!(pS->connected[0] || pS->connected[1] || pS->connected[2] || pS->connected[3])) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121: No sensors found")); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C "MPR121: No sensors found")); } } // void Mpr121Init(struct mpr121 *s) @@ -318,7 +313,7 @@ void Mpr121Init(struct mpr121 *pS) * @post None. * */ -void Mpr121Show(struct mpr121 *pS, byte function) +void Mpr121Show(struct mpr121 *pS, uint8_t function) { // Loop through sensors @@ -329,8 +324,7 @@ void Mpr121Show(struct mpr121 *pS, byte function) // Read data if (!I2cValidRead16LE(&pS->current[i], pS->i2c_addr[i], MPR121_ELEX_REG)) { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "MPR121%c: ERROR: Cannot read data!"), pS->id[i]); - AddLog(LOG_LEVEL_ERROR); + AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_I2C "MPR121%c: ERROR: Cannot read data!"), pS->id[i]); Mpr121Init(pS); return; } @@ -339,9 +333,7 @@ void Mpr121Show(struct mpr121 *pS, byte function) // Clear OVCF bit I2cWrite8(pS->i2c_addr[i], MPR121_ELEX_REG, 0x00); - snprintf_P(log_data, sizeof(log_data), - PSTR(D_LOG_I2C "MPR121%c: ERROR: Excess current detected! Fix circuits if it happens repeatedly! Soft-resetting MPR121 ..."), pS->id[i]); - AddLog(LOG_LEVEL_ERROR); + AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_I2C "MPR121%c: ERROR: Excess current detected! Fix circuits if it happens repeatedly! Soft-resetting MPR121 ..."), pS->id[i]); Mpr121Init(pS); return; } @@ -384,7 +376,7 @@ void Mpr121Show(struct mpr121 *pS, byte function) } } // if->running } // for-loop i -} // void Mpr121Show(byte function) +} // void Mpr121Show(uint8_t function) /*********************************************************************************************\ * Interface @@ -400,15 +392,15 @@ void Mpr121Show(struct mpr121 *pS, byte function) * FUNC_WEB_APPEND for displaying data in the Tasmota web-interface * * @param byte function Tasmota function ID. - * @return boolean ??? + * @return bool ??? * @pre None. * @post None. * */ -boolean Xsns30(byte function) +bool Xsns30(uint8_t function) { // ??? - boolean result = false; + bool result = false; // Sensor state/data struct static struct mpr121 mpr121; @@ -440,7 +432,7 @@ boolean Xsns30(byte function) #endif // USE_WEBSERVER } } - // Return boolean result + // Return bool result return result; } diff --git a/sonoff/xsns_31_ccs811.ino b/sonoff/xsns_31_ccs811.ino index 624dac34e..173cbe388 100644 --- a/sonoff/xsns_31_ccs811.ino +++ b/sonoff/xsns_31_ccs811.ino @@ -1,7 +1,7 @@ /* xsns_31_ccs811.ino - CCS811 gas and air quality sensor support for Sonoff-Tasmota - Copyright (C) 2018 Gerhard Mutz and Theo Arends + Copyright (C) 2019 Gerhard Mutz and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -52,11 +52,9 @@ void CCS811Update(void) // Perform every n second sint8_t res = ccs.begin(CCS811_ADDRESS); if (!res) { CCS811_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "CCS811", 0x5A); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "CCS811", 0x5A); } else { - //snprintf_P(log_data, sizeof(log_data), "CCS811 init failed: %d",res); - //AddLog(LOG_LEVEL_DEBUG); + //AddLog_P2(LOG_LEVEL_DEBUG, "CCS811 init failed: %d",res); } } else { if (ccs.available()) { @@ -83,7 +81,7 @@ const char HTTP_SNS_CCS811[] PROGMEM = "%s" "{s}CCS811 " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}" // {s} = , {m} = , {e} = "{s}CCS811 " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}"; -void CCS811Show(boolean json) +void CCS811Show(bool json) { if (CCS811_ready) { if (json) { @@ -103,9 +101,9 @@ void CCS811Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns31(byte function) +bool Xsns31(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_32_mpu6050.ino b/sonoff/xsns_32_mpu6050.ino index 8fbdfc6f3..61156f9c1 100644 --- a/sonoff/xsns_32_mpu6050.ino +++ b/sonoff/xsns_32_mpu6050.ino @@ -1,7 +1,7 @@ /* xsns_32_mpu6050.ino - MPU6050 gyroscope and temperature sensor support for Sonoff-Tasmota - Copyright (C) 2018 Oliver Welter + Copyright (C) 2019 Oliver Welter This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -120,7 +120,7 @@ void MPU_6050Detect(void) return; } - for (byte i = 0; i < sizeof(MPU_6050_addresses); i++) + for (uint8_t i = 0; i < sizeof(MPU_6050_addresses); i++) { if(!I2cDevice(MPU_6050_addresses[i])) { @@ -134,12 +134,12 @@ void MPU_6050Detect(void) mpu6050.setXGyroOffset(220); mpu6050.setYGyroOffset(76); mpu6050.setZGyroOffset(-85); - mpu6050.setZAccelOffset(1788); + mpu6050.setZAccelOffset(1788); if (MPU6050_dmp.devStatus == 0) { mpu6050.setDMPEnabled(true); MPU6050_dmp.packetSize = mpu6050.dmpGetFIFOPacketSize(); MPU_6050_found = true; - } + } #else mpu6050.initialize(); MPU_6050_found = mpu6050.testConnection(); @@ -150,8 +150,7 @@ void MPU_6050Detect(void) if (MPU_6050_found) { - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, D_SENSOR_MPU6050, MPU_6050_address); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, D_SENSOR_MPU6050, MPU_6050_address); } } @@ -171,7 +170,7 @@ const char HTTP_SNS_GZ_AXIS[] PROGMEM = "%s{s}%s " D_GZ_AXIS "{m}%s{e}"; #define D_JSON_AXIS_GY "GyroYAxis" #define D_JSON_AXIS_GZ "GyroZAxis" -void MPU_6050Show(boolean json) +void MPU_6050Show(bool json) { if (MPU_6050_found) { MPU_6050PerformReading(); @@ -228,9 +227,9 @@ void MPU_6050Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns32(byte function) +bool Xsns32(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { diff --git a/sonoff/xsns_33_ds3231.ino b/sonoff/xsns_33_ds3231.ino index 48cb12553..98afa0ab0 100644 --- a/sonoff/xsns_33_ds3231.ino +++ b/sonoff/xsns_33_ds3231.ino @@ -1,7 +1,7 @@ /* xsns_33_ds3231.ino - ds3231 RTC chip, act like sensor support for Sonoff-Tasmota - Copyright (C) 2018 Guy Elgabsi (guy.elg AT gmail.com) + Copyright (C) 2019 Guy Elgabsi (guy.elg AT gmail.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -62,26 +62,21 @@ #define HR1224 6 //Hours register 12 or 24 hour mode (24 hour mode==0) #define CENTURY 7 //Century bit in Month register #define DYDT 6 //Day/Date flag bit in alarm Day/Date registers -boolean ds3231ReadStatus = false , ds3231WriteStatus = false; //flag, we want to wriet/write to DS3231 onlu once -boolean DS3231chipDetected; - +bool ds3231ReadStatus = false; +bool ds3231WriteStatus = false; //flag, we want to wriet/write to DS3231 onlu once +bool DS3231chipDetected = false; /*----------------------------------------------------------------------* Detect the DS3231 Chip ----------------------------------------------------------------------*/ -boolean DS3231Detect(void) +void DS3231Detect(void) { - if (I2cValidRead(USE_RTC_ADDR, RTC_STATUS, 1)) - { - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "DS3231", USE_RTC_ADDR); - AddLog(LOG_LEVEL_INFO); - return true; - } - else - { - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "%s *NOT* " D_FOUND_AT " 0x%x"), "DS3231", USE_RTC_ADDR); - AddLog(LOG_LEVEL_INFO); - return false; + DS3231chipDetected = false; + if (I2cValidRead(USE_RTC_ADDR, RTC_STATUS, 1)) { + AddLog_P2(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, "DS3231", USE_RTC_ADDR); + DS3231chipDetected = true; + } else { + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_I2C "DS3231 NOT " D_FOUND_AT " 0x%x"), USE_RTC_ADDR); } } @@ -136,21 +131,19 @@ void SetDS3231Time (uint32_t epoch_time) { Interface \*********************************************************************************************/ -boolean Xsns33(byte function) +bool Xsns33(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { switch (function) { case FUNC_INIT: - DS3231chipDetected = DS3231Detect(); - result = DS3231chipDetected; + DS3231Detect(); break; - case FUNC_EVERY_SECOND: TIME_T tmpTime; if (!ds3231ReadStatus && DS3231chipDetected && utc_time < 1451602800 ) { // We still did not sync with NTP (time not valid) , so, read time from DS3231 - ntp_force_sync = 1; //force to sync with ntp + ntp_force_sync = true; //force to sync with ntp utc_time = ReadFromDS3231(); //we read UTC TIME from DS3231 // from this line, we just copy the function from "void RtcSecond()" at the support.ino ,line 2143 and above // We need it to set rules etc. @@ -161,26 +154,20 @@ boolean Xsns33(byte function) RtcTime.year = tmpTime.year + 1970; daylight_saving_time = RuleToTime(Settings.tflag[1], RtcTime.year); standard_time = RuleToTime(Settings.tflag[0], RtcTime.year); - snprintf_P(log_data, sizeof(log_data), PSTR("Set time from DS3231 to RTC (" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), + AddLog_P2(LOG_LEVEL_INFO, PSTR("Set time from DS3231 to RTC (" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str()); - AddLog(LOG_LEVEL_INFO); if (local_time < 1451602800) { // 2016-01-01 rules_flag.time_init = 1; } else { rules_flag.time_set = 1; } - result = true; } else if (!ds3231WriteStatus && DS3231chipDetected && utc_time > 1451602800 && abs(utc_time - ReadFromDS3231()) > 60) {//if time is valid and is drift from RTC in more that 60 second - snprintf_P(log_data, sizeof(log_data), PSTR("Write Time TO DS3231 from NTP (" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), + AddLog_P2(LOG_LEVEL_INFO, PSTR("Write Time TO DS3231 from NTP (" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str()); - AddLog(LOG_LEVEL_INFO); SetDS3231Time (utc_time); //update the DS3231 time ds3231WriteStatus = true; } - else { - result = false; - } break; } } diff --git a/sonoff/xsns_34_hx711.ino b/sonoff/xsns_34_hx711.ino index c3f10ded9..2072dc496 100644 --- a/sonoff/xsns_34_hx711.ino +++ b/sonoff/xsns_34_hx711.ino @@ -1,7 +1,7 @@ /* xsns_34_hx711.ino - HX711 load cell support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -67,12 +67,12 @@ long hx_offset = 0; long hx_scale = 1; uint8_t hx_type = 1; uint8_t hx_sample_count = 0; -uint8_t hx_tare_flg = 0; uint8_t hx_calibrate_step = HX_CAL_END; uint8_t hx_calibrate_timer = 0; uint8_t hx_calibrate_msg = 0; uint8_t hx_pin_sck; uint8_t hx_pin_dout; +bool hx_tare_flg = false; /*********************************************************************************************/ @@ -118,7 +118,7 @@ long HxRead() void HxReset(void) { - hx_tare_flg = 1; + hx_tare_flg = true; hx_sum_weight = 0; hx_sample_count = 0; } @@ -155,7 +155,7 @@ bool HxCommand(void) bool show_parms = false; char sub_string[XdrvMailbox.data_len +1]; - for (byte ca = 0; ca < XdrvMailbox.data_len; ca++) { + for (uint8_t ca = 0; ca < XdrvMailbox.data_len; ca++) { if ((' ' == XdrvMailbox.data[ca]) || ('=' == XdrvMailbox.data[ca])) { XdrvMailbox.data[ca] = ','; } } @@ -257,7 +257,7 @@ void HxEvery100mSecond(void) if (hx_weight < 0) { hx_weight = 0; } if (hx_tare_flg) { - hx_tare_flg = 0; + hx_tare_flg = false; hx_offset = average; // grams } @@ -270,7 +270,7 @@ void HxEvery100mSecond(void) } else if (HX_CAL_RESET == hx_calibrate_step) { // Wait for stable reset if (hx_calibrate_timer) { - if (hx_weight < Settings.weight_reference) { + if (hx_weight < (long)Settings.weight_reference) { hx_calibrate_step--; hx_calibrate_timer = HX_CAL_TIMEOUT * (10 / HX_SAMPLES); HxCalibrationStateTextJson(2); @@ -281,7 +281,7 @@ void HxEvery100mSecond(void) } else if (HX_CAL_FIRST == hx_calibrate_step) { // Wait for first reference weight if (hx_calibrate_timer) { - if (hx_weight > Settings.weight_reference) { + if (hx_weight > (long)Settings.weight_reference) { hx_calibrate_step--; } } else { @@ -289,7 +289,7 @@ void HxEvery100mSecond(void) } } else if (HX_CAL_DONE == hx_calibrate_step) { // Second stable reference weight - if (hx_weight > Settings.weight_reference) { + if (hx_weight > (long)Settings.weight_reference) { hx_calibrate_step = HX_CAL_FINISH; // Calibration done Settings.weight_calibration = hx_weight / Settings.weight_reference; hx_weight = 0; // Reset calibration value @@ -301,7 +301,7 @@ void HxEvery100mSecond(void) if (HX_CAL_FAIL == hx_calibrate_step) { // Calibration failed hx_calibrate_step--; - hx_tare_flg = 1; // Perform a reset using old scale + hx_tare_flg = true; // Perform a reset using old scale HxCalibrationStateTextJson(0); } if (HX_CAL_FINISH == hx_calibrate_step) { // Calibration finished @@ -329,7 +329,7 @@ const char HTTP_HX711_CAL[] PROGMEM = "%s" "{s}HX711 %s{m}{e}"; #endif // USE_WEBSERVER -void HxShow(boolean json) +void HxShow(bool json) { char scount[30] = { 0 }; @@ -377,24 +377,24 @@ const char HTTP_BTN_MENU_MAIN_HX711[] PROGMEM = "
"; const char HTTP_BTN_MENU_HX711[] PROGMEM = - "
"; + "

"; const char HTTP_FORM_HX711[] PROGMEM = "
 " D_CALIBRATION " " "
" - "
" D_REFERENCE_WEIGHT " (" D_UNIT_KILOGRAM ")

" - "

" + "

" D_REFERENCE_WEIGHT " (" D_UNIT_KILOGRAM ")

" + "
" "
" "


" "
 " D_HX711_PARAMETERS " " "
" - "
" D_ITEM_WEIGHT " (" D_UNIT_KILOGRAM ")

"; + "

" D_ITEM_WEIGHT " (" D_UNIT_KILOGRAM ")

"; void HandleHxAction(void) { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!HttpCheckPriviledgedAccess()) { return; } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_HX711); if (WebServer->hasArg("save")) { @@ -403,41 +403,38 @@ void HandleHxAction(void) return; } - char tmp[100]; + char stemp1[20]; if (WebServer->hasArg("reset")) { - snprintf_P(tmp, sizeof(tmp), PSTR("Sensor34 1")); // Reset - ExecuteWebCommand(tmp, SRC_WEBGUI); + snprintf_P(stemp1, sizeof(stemp1), PSTR("Sensor34 1")); // Reset + ExecuteWebCommand(stemp1, SRC_WEBGUI); HandleRoot(); // Return to main screen return; } if (WebServer->hasArg("calibrate")) { - WebGetArg("p1", tmp, sizeof(tmp)); - Settings.weight_reference = (!strlen(tmp)) ? 0 : (unsigned long)(CharToDouble(tmp) * 1000); + WebGetArg("p1", stemp1, sizeof(stemp1)); + Settings.weight_reference = (!strlen(stemp1)) ? 0 : (unsigned long)(CharToDouble(stemp1) * 1000); HxLogUpdates(); - snprintf_P(tmp, sizeof(tmp), PSTR("Sensor34 2")); // Start calibration - ExecuteWebCommand(tmp, SRC_WEBGUI); + snprintf_P(stemp1, sizeof(stemp1), PSTR("Sensor34 2")); // Start calibration + ExecuteWebCommand(stemp1, SRC_WEBGUI); HandleRoot(); // Return to main screen return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(D_CONFIGURE_HX711)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_HX711); - dtostrfd((float)Settings.weight_reference / 1000, 3, tmp); - page.replace("{1", String(tmp)); - dtostrfd((float)Settings.weight_item / 10000, 4, tmp); - page.replace("{2", String(tmp)); - - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentStart_P(S_CONFIGURE_HX711); + WSContentSendStyle(); + dtostrfd((float)Settings.weight_reference / 1000, 3, stemp1); + char stemp2[20]; + dtostrfd((float)Settings.weight_item / 10000, 4, stemp2); + WSContentSend_P(HTTP_FORM_HX711, stemp1, stemp2); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentEnd(); } void HxSaveSettings(void) @@ -457,9 +454,7 @@ void HxLogUpdates(void) char weigth_item_chr[33]; dtostrfd((float)Settings.weight_item / 10000, 4, weigth_item_chr); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_JSON_WEIGHT_REF " %s, " D_JSON_WEIGHT_ITEM " %s"), - weigth_ref_chr, weigth_item_chr); - AddLog(LOG_LEVEL_INFO); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_JSON_WEIGHT_REF " %s, " D_JSON_WEIGHT_ITEM " %s"), weigth_ref_chr, weigth_item_chr); } #endif // USE_HX711_GUI @@ -469,9 +464,9 @@ void HxLogUpdates(void) * Interface \*********************************************************************************************/ -boolean Xsns34(byte function) +bool Xsns34(uint8_t function) { - boolean result = false; + bool result = false; if (hx_type) { switch (function) { @@ -481,7 +476,7 @@ boolean Xsns34(byte function) case FUNC_EVERY_100_MSECOND: HxEvery100mSecond(); break; - case FUNC_COMMAND: + case FUNC_COMMAND_SENSOR: if (XSNS_34 == XdrvMailbox.index) { result = HxCommand(); } @@ -495,10 +490,10 @@ boolean Xsns34(byte function) break; #ifdef USE_HX711_GUI case FUNC_WEB_ADD_MAIN_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_MAIN_HX711, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend_P(HTTP_BTN_MENU_MAIN_HX711); break; case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_HX711, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend_P(HTTP_BTN_MENU_HX711); break; case FUNC_WEB_ADD_HANDLER: WebServer->on("/" WEB_HANDLE_HX711, HandleHxAction); diff --git a/sonoff/xsns_35_tx20.ino b/sonoff/xsns_35_tx20.ino index a198c766f..bae2e9532 100644 --- a/sonoff/xsns_35_tx20.ino +++ b/sonoff/xsns_35_tx20.ino @@ -1,7 +1,7 @@ /* xsns_35_Tx20.ino - La Crosse Tx20 wind sensor support for Sonoff-Tasmota - Copyright (C) 2018 Thomas Eckerstorfer and Theo Arends + Copyright (C) 2019 Thomas Eckerstorfer and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -78,7 +78,7 @@ float tx20_wind_sum = 0; int tx20_count = 0; uint8_t tx20_wind_direction = 0; -boolean tx20_available = false; +bool tx20_available = false; void Tx20StartRead(void) { @@ -170,7 +170,7 @@ void Tx20Init(void) { attachInterrupt(pin[GPIO_TX20_TXD_BLACK], Tx20StartRead, RISING); } -void Tx20Show(boolean json) +void Tx20Show(bool json) { char wind_speed_string[33]; dtostrfd(tx20_wind_speed_kmh, 2, wind_speed_string); @@ -195,9 +195,9 @@ void Tx20Show(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns35(byte function) +bool Xsns35(uint8_t function) { - boolean result = false; + bool result = false; if (pin[GPIO_TX20_TXD_BLACK] < 99) { switch (function) { diff --git a/sonoff/xsns_36_mgc3130.ino b/sonoff/xsns_36_mgc3130.ino index 81f4a72c6..5c1d2df48 100644 --- a/sonoff/xsns_36_mgc3130.ino +++ b/sonoff/xsns_36_mgc3130.ino @@ -1,7 +1,7 @@ /* xsns_36_MGC3130.ino - Support for I2C MGC3130 Electric Field Sensor for Sonoff-Tasmota - Copyright (C) 2018 Christian Baars & Theo Arends + Copyright (C) 2019 Christian Baars & Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -497,17 +497,15 @@ bool MGC3130_detect(void) digitalWrite(MGC3130_reset, HIGH); delay(50); - boolean success = false; + bool success = false; success = MGC3130_receiveMessage(); // This should read the firmware info if (success) { strcpy_P(MGC3130stype, PSTR("MGC3130")); - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, MGC3130stype, MGC3130_I2C_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, MGC3130stype, MGC3130_I2C_ADDR); MGC3130_currentGesture[0] = '\0'; MGC3130_type = true; } else { - snprintf_P(log_data, sizeof(log_data), PSTR("MGC3130 did not respond at address 0x%x"), MGC3130_I2C_ADDR); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MGC3130 did not respond at address 0x%x"), MGC3130_I2C_ADDR); } return success; } @@ -516,7 +514,7 @@ bool MGC3130_detect(void) * Presentation \*********************************************************************************************/ -void MGC3130_show(boolean json) +void MGC3130_show(bool json) { if (!MGC3130_type) { return; } @@ -576,7 +574,7 @@ void MGC3130_show(boolean json) bool MGC3130CommandSensor() { - boolean serviced = true; + bool serviced = true; switch (XdrvMailbox.payload) { case 0: // cycle through the modes @@ -602,9 +600,9 @@ bool MGC3130CommandSensor() * Interface \*********************************************************************************************/ -boolean Xsns36(byte function) +bool Xsns36(uint8_t function) { - boolean result = false; + bool result = false; if (i2c_flg) { if ((FUNC_INIT == function) && (pin[GPIO_MGC3130_XFER] < 99) && (pin[GPIO_MGC3130_RESET] < 99)) { @@ -615,7 +613,7 @@ boolean Xsns36(byte function) case FUNC_EVERY_50_MSECOND: MGC3130_loop(); break; - case FUNC_COMMAND: + case FUNC_COMMAND_SENSOR: if (XSNS_36 == XdrvMailbox.index) { result = MGC3130CommandSensor(); } diff --git a/sonoff/xsns_37_rfsensor.ino b/sonoff/xsns_37_rfsensor.ino index efb864924..efb6ded06 100644 --- a/sonoff/xsns_37_rfsensor.ino +++ b/sonoff/xsns_37_rfsensor.ino @@ -1,7 +1,7 @@ /* xsns_37_rfsensor.ino - RF sensor receiver for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -49,10 +49,10 @@ typedef struct RawSignalStruct // Variabelen geplaatst in struct zodat deze later eenvoudig kunnen worden weggeschreven naar SDCard { int Number; // aantal bits, maal twee omdat iedere bit een mark en een space heeft. - byte Repeats; // Aantal maal dat de pulsreeks verzonden moet worden bij een zendactie. - byte Multiply; // Pulses[] * Multiply is de echte tijd van een puls in microseconden + uint8_t Repeats; // Aantal maal dat de pulsreeks verzonden moet worden bij een zendactie. + uint8_t Multiply; // Pulses[] * Multiply is de echte tijd van een puls in microseconden unsigned long Time; // Tijdstempel wanneer signaal is binnengekomen (millis()) - byte Pulses[RFSNS_RAW_BUFFER_SIZE+2]; // Tabel met de gemeten pulsen in microseconden gedeeld door rfsns_raw_signal->Multiply. Dit scheelt helft aan RAM geheugen. + uint8_t Pulses[RFSNS_RAW_BUFFER_SIZE+2]; // Tabel met de gemeten pulsen in microseconden gedeeld door rfsns_raw_signal->Multiply. Dit scheelt helft aan RAM geheugen. // Om legacy redenen zit de eerste puls in element 1. Element 0 wordt dus niet gebruikt. } raw_signal_t; @@ -65,7 +65,7 @@ uint8_t rfsns_any_sensor = 0; * Fetch signals from RF pin \*********************************************************************************************/ -bool RfSnsFetchSignal(byte DataPin, bool StateSignal) +bool RfSnsFetchSignal(uint8_t DataPin, bool StateSignal) { uint8_t Fbit = digitalPinToBitMask(DataPin); uint8_t Fport = digitalPinToPort(DataPin); @@ -179,17 +179,17 @@ void RfSnsAnalyzeTheov2(void) { if (rfsns_raw_signal->Number != RFSNS_THEOV2_PULSECOUNT) { return; } - byte Checksum; // 8 bits Checksum over following bytes - byte Channel; // 3 bits channel - byte Type; // 5 bits type - byte Voltage; // 8 bits Vcc like 45 = 4.5V, bit 8 is batt low + uint8_t Checksum; // 8 bits Checksum over following bytes + uint8_t Channel; // 3 bits channel + uint8_t Type; // 5 bits type + uint8_t Voltage; // 8 bits Vcc like 45 = 4.5V, bit 8 is batt low int Payload1; // 16 bits int Payload2; // 16 bits - byte b, bytes, bits, id; + uint8_t b, bytes, bits, id; - byte idx = 3; - byte chksum = 0; + uint8_t idx = 3; + uint8_t chksum = 0; for (bytes = 0; bytes < 7; bytes++) { b = 0; for (bits = 0; bits <= 7; bits++) @@ -251,9 +251,8 @@ void RfSnsAnalyzeTheov2(void) break; } - snprintf_P(log_data, sizeof(log_data), PSTR("RFS: TheoV2, ChkCalc %d, Chksum %d, id %d, Type %d, Ch %d, Volt %d, BattLo %d, Pld1 %d, Pld2 %d"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RFS: TheoV2, ChkCalc %d, Chksum %d, id %d, Type %d, Ch %d, Volt %d, BattLo %d, Pld1 %d, Pld2 %d"), chksum, Checksum, id, Type, Channel +1, Payload3, (Voltage & 0x80) >> 7, Payload1, Payload2); - AddLog(LOG_LEVEL_DEBUG); } void RfSnsTheoV2Show(bool json) @@ -438,23 +437,23 @@ void RfSnsAnalyzeAlectov2() if (!(((rfsns_raw_signal->Number >= RFSNS_ACH2010_MIN_PULSECOUNT) && (rfsns_raw_signal->Number <= RFSNS_ACH2010_MAX_PULSECOUNT)) || (rfsns_raw_signal->Number == RFSNS_DKW2012_PULSECOUNT))) { return; } - byte c = 0; - byte rfbit; - byte data[9] = { 0 }; - byte msgtype = 0; - byte rc = 0; + uint8_t c = 0; + uint8_t rfbit; + uint8_t data[9] = { 0 }; + uint8_t msgtype = 0; + uint8_t rc = 0; int temp; - byte checksum = 0; - byte checksumcalc = 0; - byte maxidx = 8; + uint8_t checksum = 0; + uint8_t checksumcalc = 0; + uint8_t maxidx = 8; unsigned long atime; float factor; char buf1[16]; if (rfsns_raw_signal->Number > RFSNS_ACH2010_MAX_PULSECOUNT) { maxidx = 9; } // Get message back to front as the header is almost never received complete for ACH2010 - byte idx = maxidx; - for (byte x = rfsns_raw_signal->Number; x > 0; x = x-2) { + uint8_t idx = maxidx; + for (uint8_t x = rfsns_raw_signal->Number; x > 0; x = x-2) { if (rfsns_raw_signal->Pulses[x-1] * rfsns_raw_signal->Multiply < 0x300) { rfbit = 0x80; } else { @@ -507,9 +506,8 @@ void RfSnsAnalyzeAlectov2() rfsns_alecto_v2->wdir = data[8] & 0xf; } - snprintf_P(log_data, sizeof(log_data), PSTR("RFS: " D_ALECTOV2 ", ChkCalc %d, Chksum %d, rc %d, Temp %d, Hum %d, Rain %d, Wind %d, Gust %d, Dir %d, Factor %s"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RFS: " D_ALECTOV2 ", ChkCalc %d, Chksum %d, rc %d, Temp %d, Hum %d, Rain %d, Wind %d, Gust %d, Dir %d, Factor %s"), checksumcalc, checksum, rc, ((data[1] & 0x3) * 256 + data[2]) - 400, data[3], (data[6] * 256) + data[7], data[4], data[5], data[8] & 0xf, dtostrfd(factor, 3, buf1)); - AddLog(LOG_LEVEL_DEBUG); } void RfSnsAlectoResetRain(void) @@ -627,8 +625,7 @@ void RfSnsInit(void) void RfSnsAnalyzeRawSignal(void) { - snprintf_P(log_data, sizeof(log_data), PSTR("RFS: Pulses %d"), (int)rfsns_raw_signal->Number); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RFS: Pulses %d"), (int)rfsns_raw_signal->Number); #ifdef USE_THEO_V2 RfSnsAnalyzeTheov2(); @@ -659,7 +656,7 @@ void RfSnsShow(bool json) * Interface \*********************************************************************************************/ -boolean Xsns37(byte function) +bool Xsns37(uint8_t function) { bool result = false; diff --git a/sonoff/xsns_38_az7798.ino b/sonoff/xsns_38_az7798.ino index f909bb061..3ec73085e 100644 --- a/sonoff/xsns_38_az7798.ino +++ b/sonoff/xsns_38_az7798.ino @@ -1,7 +1,7 @@ /* xsns_38_az7798.ino - AZ_Instrument 7798 CO2/temperature/humidity meter support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends + Copyright (C) 2019 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -107,9 +107,7 @@ * * : responds with : T19.9C:C2167ppm:H57.4% * This one gives the current readings. - ********************************************************************************************** - -/*********************************************************************************************/ +\*********************************************************************************************/ #include @@ -160,7 +158,7 @@ void AzEverySecond(void) } } while(((millis() - start) < AZ_READ_TIMEOUT) && (counter < sizeof(az_response)) && !az_received); - AddLogSerial(LOG_LEVEL_DEBUG_MORE, az_response, counter); + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, az_response, counter); if (!az_received) { AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 comms timeout")); @@ -252,7 +250,7 @@ void AzInit(void) } } -void AzShow(boolean json) +void AzShow(bool json) { char temperature[33]; dtostrfd(az_temperature, Settings.flag2.temperature_resolution, temperature); @@ -277,9 +275,9 @@ void AzShow(boolean json) * Interface \*********************************************************************************************/ -boolean Xsns38(byte function) +bool Xsns38(uint8_t function) { - boolean result = false; + bool result = false; if(az_type){ switch (function) { diff --git a/sonoff/xsns_39_max31855.ino b/sonoff/xsns_39_max31855.ino new file mode 100644 index 000000000..10630e171 --- /dev/null +++ b/sonoff/xsns_39_max31855.ino @@ -0,0 +1,176 @@ +/* + xsns_39_max31855.ino - MAX31855 thermocouple sensor support for Sonoff-Tasmota + + Copyright (C) 2019 Markus Past + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_MAX31855 + +#define XSNS_39 39 + +bool initialized = false; + +struct MAX31855_ResultStruct{ + uint8_t ErrorCode; // Error Codes: 0 = No Error / 1 = TC open circuit / 2 = TC short to GND / 4 = TC short to VCC + float ProbeTemperature; // Measured temperature of the 'hot' TC junction (probe temp) + float ReferenceTemperature; // Measured temperature of the 'cold' TC junction (reference temp) +} MAX31855_Result; + +void MAX31855_Init(void){ + if(initialized) + return; + + // Set GPIO modes for SW-SPI + pinMode(pin[GPIO_MAX31855CS], OUTPUT); + pinMode(pin[GPIO_MAX31855CLK], OUTPUT); + pinMode(pin[GPIO_MAX31855DO], INPUT); + + // Chip not selected / Clock low + digitalWrite(pin[GPIO_MAX31855CS], HIGH); + digitalWrite(pin[GPIO_MAX31855CLK], LOW); + + initialized = true; +} + +/* +* MAX31855_GetResult(void) +* Acquires the raw data via SPI, checks for MAX31855 errors and fills result structure +*/ +void MAX31855_GetResult(void){ + int32_t RawData = MAX31855_ShiftIn(32); + uint8_t probeerror = RawData & 0x7; + + MAX31855_Result.ErrorCode = probeerror; + MAX31855_Result.ReferenceTemperature = MAX31855_GetReferenceTemperature(RawData); + if(probeerror) + MAX31855_Result.ProbeTemperature = NAN; // Return NaN if MAX31855 reports an error + else + MAX31855_Result.ProbeTemperature = MAX31855_GetProbeTemperature(RawData); +} + + +/* +* MAX31855_GetProbeTemperature(int32_t RawData) +* Decodes and returns the temperature of TCs 'hot' junction from RawData +*/ +float MAX31855_GetProbeTemperature(int32_t RawData){ + if(RawData & 0x80000000) + RawData = (RawData >> 18) | 0xFFFFC000; // Negative value - Drop lower 18 bits and extend to negative number + else + RawData >>= 18; // Positiv value - Drop lower 18 bits + + float result = (RawData * 0.25); // MAX31855 LSB resolution is 0.25°C for probe temperature + + return (Settings.flag.temperature_conversion) ? ConvertTemp(result) : result; // Check if we have to convert to Fahrenheit +} + +/* +* MAX31855_GetReferenceTemperature(int32_t RawData) +* Decodes and returns the temperature of TCs 'cold' junction from RawData +*/ +float MAX31855_GetReferenceTemperature(int32_t RawData){ + if(RawData & 0x8000) + RawData = (RawData >> 4) | 0xFFFFF000; // Negative value - Drop lower 4 bits and extend to negative number + else + RawData = (RawData >> 4) & 0x00000FFF; // Positiv value - Drop lower 4 bits and mask out remaining bits (probe temp, error bit, etc.) + + float result = (RawData * 0.0625); // MAX31855 LSB resolution is 0.0625°C for reference temperature + + return (Settings.flag.temperature_conversion) ? ConvertTemp(result) : result; // Check if we have to convert to Fahrenheit +} + +/* +* MAX31855_ShiftIn(uint8_t Length) +* Communicates with MAX31855 via SW-SPI and returns the raw data read from the chip +*/ +int32_t MAX31855_ShiftIn(uint8_t Length){ + int32_t dataIn = 0; + + digitalWrite(pin[GPIO_MAX31855CS], LOW); // CS = LOW -> Start SPI communication + delayMicroseconds(1); // CS fall to output enable = max. 100ns + + for(uint8_t i = 0; i < Length; i++) + { + digitalWrite(pin[GPIO_MAX31855CLK], LOW); + delayMicroseconds(1); // CLK pulse width low = min. 100ns / CLK fall to output valid = max. 40ns + dataIn <<= 1; + if(digitalRead(pin[GPIO_MAX31855DO])) + dataIn |= 1; + digitalWrite(pin[GPIO_MAX31855CLK], HIGH); + delayMicroseconds(1); // CLK pulse width high = min. 100ns + } + + digitalWrite(pin[GPIO_MAX31855CS], HIGH); // CS = HIGH -> End SPI communication + digitalWrite(pin[GPIO_MAX31855CLK], LOW); + return dataIn; +} + +void MAX31855_Show(bool Json){ + char probetemp[33]; + char referencetemp[33]; + dtostrfd(MAX31855_Result.ProbeTemperature, Settings.flag2.temperature_resolution, probetemp); + dtostrfd(MAX31855_Result.ReferenceTemperature, Settings.flag2.temperature_resolution, referencetemp); + + if(Json){ + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_PROBETEMPERATURE "\":%s,\"" D_JSON_REFERENCETEMPERATURE "\":%s,\"" D_JSON_ERROR "\":%d}"), \ + mqtt_data, "MAX31855", probetemp, referencetemp, MAX31855_Result.ErrorCode); +#ifdef USE_DOMOTICZ + if (0 == tele_period) { + DomoticzSensor(DZ_TEMP, probetemp); + } +#endif // USE_DOMOTICZ +#ifdef USE_KNX + if (0 == tele_period) { + KnxSensor(KNX_TEMPERATURE, MAX31855_Result.ProbeTemperature); + } +#endif // USE_KNX + } else { +#ifdef USE_WEBSERVER + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, "MAX31855", probetemp, TempUnit()); +#endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns39(uint8_t function) +{ + bool result = false; + if((pin[GPIO_MAX31855CS] < 99) && (pin[GPIO_MAX31855CLK] < 99) && (pin[GPIO_MAX31855DO] < 99)){ + + switch (function) { + case FUNC_INIT: + MAX31855_Init(); + break; + case FUNC_EVERY_SECOND: + MAX31855_GetResult(); + break; + case FUNC_JSON_APPEND: + MAX31855_Show(true); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_APPEND: + MAX31855_Show(false); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_MAX31855 \ No newline at end of file diff --git a/sonoff/xsns_40_pn532.ino b/sonoff/xsns_40_pn532.ino new file mode 100644 index 000000000..0bfa8bda1 --- /dev/null +++ b/sonoff/xsns_40_pn532.ino @@ -0,0 +1,606 @@ +/* + xsns_40_pn532.ino - Support for PN532 (HSU) NFC Tag Reader + + Copyright (C) 2019 Andre Thomas and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_PN532_HSU + +#define XSNS_40 40 + +#include + +TasmotaSerial *PN532_Serial; + +#define PN532_INVALID_ACK -1 +#define PN532_TIMEOUT -2 +#define PN532_INVALID_FRAME -3 +#define PN532_NO_SPACE -4 + +#define PN532_PREAMBLE 0x00 +#define PN532_STARTCODE1 0x00 +#define PN532_STARTCODE2 0xFF +#define PN532_POSTAMBLE 0x00 + +#define PN532_HOSTTOPN532 0xD4 +#define PN532_PN532TOHOST 0xD5 + +#define PN532_ACK_WAIT_TIME 0x0A + +#define PN532_COMMAND_GETFIRMWAREVERSION 0x02 +#define PN532_COMMAND_SAMCONFIGURATION 0x14 +#define PN532_COMMAND_RFCONFIGURATION 0x32 +#define PN532_COMMAND_INDATAEXCHANGE 0x40 +#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A + +#define PN532_MIFARE_ISO14443A 0x00 +#define MIFARE_CMD_READ 0x30 +#define MIFARE_CMD_AUTH_A 0x60 +#define MIFARE_CMD_AUTH_B 0x61 +#define MIFARE_CMD_WRITE 0xA0 + +uint8_t pn532_model = 0; // Used to maintain detection flag +uint8_t pn532_command = 0; // Used to carry command code between functions +uint8_t pn532_scantimer = 0; // Used to prevent multiple successful reads within 2 second window + +uint8_t pn532_packetbuffer[64]; // Global buffer used to store packet + +#ifdef USE_PN532_DATA_FUNCTION +uint8_t pn532_function = 0; +uint8_t pn532_newdata[16]; +uint8_t pn532_newdata_len = 0; +#endif // USE_PN532_DATA_FUNCTION + +void PN532_Init(void) +{ + if ((pin[GPIO_PN532_RXD] < 99) && (pin[GPIO_PN532_TXD] < 99)) { + PN532_Serial = new TasmotaSerial(pin[GPIO_PN532_RXD], pin[GPIO_PN532_TXD], 1); + if (PN532_Serial->begin(115200)) { + if (PN532_Serial->hardwareSerial()) { ClaimSerial(); } + PN532_wakeup(); + uint32_t ver = PN532_getFirmwareVersion(); + if (ver) { + PN532_setPassiveActivationRetries(0xFF); + PN532_SAMConfig(); + pn532_model = 1; + AddLog_P2(LOG_LEVEL_INFO,"NFC: PN532 NFC Reader detected (V%u.%u)",(ver>>16) & 0xFF, (ver>>8) & 0xFF); + } + } + } +} + +int8_t PN532_receive(uint8_t *buf, int len, uint16_t timeout) +{ + int read_bytes = 0; + int ret; + unsigned long start_millis; + while (read_bytes < len) { + start_millis = millis(); + do { + ret = PN532_Serial->read(); + if (ret >= 0) { + break; + } + } while((timeout == 0) || ((millis()- start_millis ) < timeout)); + + if (ret < 0) { + if (read_bytes) { + return read_bytes; + } else { + return PN532_TIMEOUT; + } + } + buf[read_bytes] = (uint8_t)ret; + read_bytes++; + } + return read_bytes; +} + +int8_t PN532_readAckFrame(void) +{ + const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; + uint8_t ackBuf[sizeof(PN532_ACK)]; + + if (PN532_receive(ackBuf, sizeof(PN532_ACK), PN532_ACK_WAIT_TIME) <= 0) { + return PN532_TIMEOUT; + } + + if (memcmp(&ackBuf, &PN532_ACK, sizeof(PN532_ACK))) { + return PN532_INVALID_ACK; + } + return 0; +} + +int8_t PN532_writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) +{ + // Clear the serial buffer just in case + PN532_Serial->flush(); + + pn532_command = header[0]; + PN532_Serial->write((uint8_t)PN532_PREAMBLE); + PN532_Serial->write((uint8_t)PN532_STARTCODE1); + PN532_Serial->write(PN532_STARTCODE2); + + uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA + PN532_Serial->write(length); + PN532_Serial->write(~length + 1); // checksum of length + + PN532_Serial->write(PN532_HOSTTOPN532); + uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA + + PN532_Serial->write(header, hlen); + for (uint8_t i = 0; i < hlen; i++) { + sum += header[i]; + } + + PN532_Serial->write(body, blen); + for (uint8_t i = 0; i < blen; i++) { + sum += body[i]; + } + + uint8_t checksum = ~sum + 1; // checksum of TFI + DATA + PN532_Serial->write(checksum); + PN532_Serial->write((uint8_t)PN532_POSTAMBLE); + + return PN532_readAckFrame(); +} + +int16_t PN532_readResponse(uint8_t buf[], uint8_t len, uint16_t timeout = 50) +{ + uint8_t tmp[3]; + + // Read preamble and start code + if (PN532_receive(tmp, 3, timeout)<=0) { + return PN532_TIMEOUT; + } + if (0 != tmp[0] || 0!= tmp[1] || 0xFF != tmp[2]) { + return PN532_INVALID_FRAME; + } + + // Get length of data to be received + uint8_t length[2]; + if (PN532_receive(length, 2, timeout) <= 0) { + return PN532_TIMEOUT; + } + // Validate that frame is valid + if (0 != (uint8_t)(length[0] + length[1])) { + return PN532_INVALID_FRAME; + } + length[0] -= 2; + if (length[0] > len) { // If this happens, then pn532_packetbuffer is not large enough + return PN532_NO_SPACE; + } + + // Get the command byte + uint8_t cmd = pn532_command + 1; + if (PN532_receive(tmp, 2, timeout) <= 0) { // Time out while receiving + return PN532_TIMEOUT; + } + if (PN532_PN532TOHOST != tmp[0] || cmd != tmp[1]) { // Invalid frame received + return PN532_INVALID_FRAME; + } + + if (PN532_receive(buf, length[0], timeout) != length[0]) { // Timed out + return PN532_TIMEOUT; + } + + uint8_t sum = PN532_PN532TOHOST + cmd; + for (uint8_t i=0; i status) { + return 0; + } + + response = pn532_packetbuffer[0]; + response <<= 8; + response |= pn532_packetbuffer[1]; + response <<= 8; + response |= pn532_packetbuffer[2]; + response <<= 8; + response |= pn532_packetbuffer[3]; + + return response; +} + +void PN532_wakeup(void) +{ + uint8_t wakeup[5] = {0x55, 0x55, 0, 0, 0 }; + PN532_Serial->write(wakeup,sizeof(wakeup)); + + // Flush the serial buffer just in case there's garbage in there + PN532_Serial->flush(); +} + +bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout = 50) +{ + pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; + pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later) + pn532_packetbuffer[2] = cardbaudrate; + if (PN532_writeCommand(pn532_packetbuffer, 3)) { + return 0x0; // command failed + } + // read data packet + if (PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) { + return 0x0; + } + + /* Check some basic stuff + b0 Tags Found + b1 Tag Number (only one used in this example) + b2..3 SENS_RES + b4 SEL_RES + b5 NFCID Length + b6..NFCIDLen NFCID + */ + + if (pn532_packetbuffer[0] != 1) { + return 0; + } + + uint16_t sens_res = pn532_packetbuffer[2]; + sens_res <<= 8; + sens_res |= pn532_packetbuffer[3]; + + /* Card appears to be Mifare Classic */ + *uidLength = pn532_packetbuffer[5]; + + for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) { + uid[i] = pn532_packetbuffer[6 + i]; + } + + return 1; +} + +bool PN532_setPassiveActivationRetries(uint8_t maxRetries) +{ + pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION; + pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries) + pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF) + pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01) + pn532_packetbuffer[4] = maxRetries; + if (PN532_writeCommand(pn532_packetbuffer, 5)) { + return 0; // no ACK + } + return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); +} + +bool PN532_SAMConfig(void) +{ + pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION; + pn532_packetbuffer[1] = 0x01; // normal mode + pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second + pn532_packetbuffer[3] = 0x00; // we don't need the external IRQ pin + if (PN532_writeCommand(pn532_packetbuffer, 4)) { + return false; + } + return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); +} + +#ifdef USE_PN532_DATA_FUNCTION + +uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) +{ + uint8_t i; + uint8_t _key[6]; + uint8_t _uid[7]; + uint8_t _uidLen; + + // Hang on to the key and uid data + memcpy(&_key, keyData, 6); + memcpy(&_uid, uid, uidLen); + _uidLen = uidLen; + + // Prepare the authentication command // + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */ + pn532_packetbuffer[1] = 1; /* Max card numbers */ + pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A; + pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */ + memcpy(&pn532_packetbuffer[4], &_key, 6); + for (i = 0; i < _uidLen; i++) { + pn532_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */ + } + + if (PN532_writeCommand(pn532_packetbuffer, 10 + _uidLen)) { return 0; } + + // Read the response packet + PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer)); + + // Check if the response is valid and we are authenticated??? + // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00 + // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good + if (pn532_packetbuffer[0] != 0x00) { + // Authentification failed + return 0; + } + + return 1; +} + +uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) +{ + /* Prepare the command */ + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = 1; /* Card number */ + pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ + + /* Send the command */ + if (PN532_writeCommand(pn532_packetbuffer, 4)) { + return 0; + } + + /* Read the response packet */ + PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer)); + + /* If byte 8 isn't 0x00 we probably have an error */ + if (pn532_packetbuffer[0] != 0x00) { + return 0; + } + + /* Copy the 16 data bytes to the output buffer */ + /* Block content starts at byte 9 of a valid response */ + memcpy (data, &pn532_packetbuffer[1], 16); + + return 1; +} + +uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) +{ + /* Prepare the first command */ + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = 1; /* Card number */ + pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */ + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ + memcpy(&pn532_packetbuffer[4], data, 16); /* Data Payload */ + + /* Send the command */ + if (PN532_writeCommand(pn532_packetbuffer, 20)) { + return 0; + } + + /* Read the response packet */ + return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); +} + +#endif // USE_PN532_DATA_FUNCTION + +void PN532_ScanForTag(void) +{ + if (!pn532_model) { return; } + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; + uint8_t uid_len = 0; + uint8_t card_data[16]; + bool erase_success = false; + bool set_success = false; + if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uid_len)) { + char uids[15]; + +#ifdef USE_PN532_DATA_FUNCTION + char card_datas[34]; +#endif // USE_PN532_DATA_FUNCTION + + sprintf(uids,""); + for (uint8_t i = 0;i < uid_len;i++) { + sprintf(uids,"%s%02X",uids,uid[i]); + } + +#ifdef USE_PN532_DATA_FUNCTION + if (uid_len == 4) { // Lets try to read block 1 of the mifare classic card for more information + uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + if (mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) { + if (mifareclassic_ReadDataBlock(1, card_data)) { +#ifdef USE_PN532_DATA_RAW + memcpy(&card_datas,&card_data,sizeof(card_data)); +#else + for (uint8_t i = 0;i < sizeof(card_data);i++) { + if ((isalpha(card_data[i])) || ((isdigit(card_data[i])))) { + card_datas[i] = char(card_data[i]); + } else { + card_datas[i] = '\0'; + } + } +#endif // USE_PN532_DATA_RAW + } + if (pn532_function == 1) { // erase block 1 of card + for (uint8_t i = 0;i<16;i++) { + card_data[i] = 0x00; + } + if (mifareclassic_WriteDataBlock(1, card_data)) { + erase_success = true; + AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Erase success")); + memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string + } + } + if (pn532_function == 2) { +#ifdef USE_PN532_DATA_RAW + memcpy(&card_data,&pn532_newdata,sizeof(card_data)); + if (mifareclassic_WriteDataBlock(1, card_data)) { + set_success = true; + AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data write successful")); + memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string + } +#else + bool IsAlphaNumeric = true; + for (uint8_t i = 0;i < pn532_newdata_len;i++) { + if ((!isalpha(pn532_newdata[i])) && (!isdigit(pn532_newdata[i]))) { + IsAlphaNumeric = false; + } + } + if (IsAlphaNumeric) { + memcpy(&card_data,&pn532_newdata,pn532_newdata_len); + card_data[pn532_newdata_len] = '\0'; // Enforce null termination + if (mifareclassic_WriteDataBlock(1, card_data)) { + set_success = true; + AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data write successful")); + memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string + } + } else { + AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data must be alphanumeric")); + } +#endif // USE_PN532_DATA_RAW + } + } else { + sprintf(card_datas,"AUTHFAIL"); + } + } + switch (pn532_function) { + case 0x01: + if (!erase_success) { + AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Erase fail - exiting erase mode")); + } + break; + case 0x02: + if (!set_success) { + AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Write failed - exiting set mode")); + } + default: + break; + } + pn532_function = 0; +#endif // USE_PN532_DATA_FUNCTION + + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); + +#ifdef USE_PN532_DATA_FUNCTION + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\", \"DATA\":\"%s\"}}"), mqtt_data, uids, card_datas); +#else + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\"}}"), mqtt_data, uids); +#endif // USE_PN532_DATA_FUNCTION + + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); + +#ifdef USE_PN532_CAUSE_EVENTS + + char command[71]; +#ifdef USE_PN532_DATA_FUNCTION + sprintf(command,"backlog event PN532_UID=%s;event PN532_DATA=%s",uids,card_datas); +#else + sprintf(command,"event PN532_UID=%s",uids); +#endif // USE_PN532_DATA_FUNCTION + ExecuteCommand(command, SRC_RULE); +#endif // USE_PN532_CAUSE_EVENTS + + pn532_scantimer = 7; // Ignore tags found for two seconds + } +} + +#ifdef USE_PN532_DATA_FUNCTION + +bool PN532_Command(void) +{ + bool serviced = true; + uint8_t paramcount = 0; + if (XdrvMailbox.data_len > 0) { + paramcount=1; + } else { + serviced = false; + return serviced; + } + char sub_string[XdrvMailbox.data_len]; + char sub_string_tmp[XdrvMailbox.data_len]; + for (uint8_t ca=0;ca 1) { + if (XdrvMailbox.data[XdrvMailbox.data_len-1] == ',') { + serviced = false; + return serviced; + } + sprintf(sub_string_tmp,subStr(sub_string, XdrvMailbox.data, ",", 2)); + pn532_newdata_len = strlen(sub_string_tmp); + if (pn532_newdata_len > 15) { pn532_newdata_len = 15; } + memcpy(&pn532_newdata,&sub_string_tmp,pn532_newdata_len); + pn532_newdata[pn532_newdata_len] = 0x00; // Null terminate the string + pn532_function = 2; + AddLog_P2(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Next scanned tag data block 1 will be set to '%s'"), pn532_newdata); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"COMMAND\":\"S\"\"}}"), mqtt_data); + return serviced; + } + } +} + +#endif // USE_PN532_DATA_FUNCTION + +bool Xsns40(uint8_t function) +{ + bool result = false; + + switch (function) { + case FUNC_INIT: + PN532_Init(); + result = true; + break; + case FUNC_EVERY_50_MSECOND: + break; + case FUNC_EVERY_100_MSECOND: + break; + case FUNC_EVERY_250_MSECOND: + if (pn532_scantimer > 0) { + pn532_scantimer--; + } else { + PN532_ScanForTag(); + } + break; + case FUNC_EVERY_SECOND: + break; +#ifdef USE_PN532_DATA_FUNCTION + case FUNC_COMMAND_SENSOR: + if (XSNS_40 == XdrvMailbox.index) { + result = PN532_Command(); + } + break; +#endif + } + return result; +} + +#endif // USE_PN532_HSU diff --git a/sonoff/xsns_41_max44009.ino b/sonoff/xsns_41_max44009.ino new file mode 100644 index 000000000..1cb0e97a7 --- /dev/null +++ b/sonoff/xsns_41_max44009.ino @@ -0,0 +1,179 @@ +/* + xsns_41_max44009.ino - MAX44009 ambient light sensor support for Sonoff-Tasmota + + Copyright (C) 2019 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_MAX44009 +/*********************************************************************************************\ + * MAX44009 - Ambient Light Intensity + * + * I2C Address: 0x4a or 0x4b +\*********************************************************************************************/ + +#define XSNS_41 41 + +#define MAX44009_ADDR1 0x4A +#define MAX44009_ADDR2 0x4B +#define MAX44009_NO_REGISTERS 8 +#define REG_CONFIG 0x02 +#define REG_LUMINANCE 0x03 +#define REG_LOWER_THRESHOLD 0x06 +#define REG_THRESHOLD_TIMER 0x07 + +#define MAX44009_CONTINUOUS_AUTO_MODE 0x80 // Start measurement in automatic, continous mode + +uint8_t max44009_address; +uint8_t max44009_addresses[] = { MAX44009_ADDR1, MAX44009_ADDR2, 0 }; //0 terminated list +uint8_t max44009_found = 0; +uint8_t max44009_valid = 0; +float max44009_illuminance = 0; +char max44009_types[] = "MAX44009"; + +bool Max4409Read_lum(void) +{ + max44009_valid = 0; + uint8_t regdata[2]; + + /* Read 2 bytes luminance */ + if (I2cValidRead16((uint16_t *)®data, max44009_address, REG_LUMINANCE)) { + int exponent = (regdata[0] & 0xF0) >> 4; + int mantissa = ((regdata[0] & 0x0F) << 4) | (regdata[1] & 0x0F); + max44009_illuminance = (float)(((0x00000001 << exponent) * (float)mantissa) * 0.045); + max44009_valid = 1; + return true; + } else { + return false; + } +} + +/********************************************************************************************/ + +void Max4409Detect(void) +{ + uint8_t reg[8]; + bool failed = false; + + if (max44009_found) { + return; + } + + uint8_t buffer1; + uint8_t buffer2; + for (uint8_t i = 0; 0 != max44009_addresses[i]; i++) { + + max44009_address = max44009_addresses[i]; + + if ((I2cValidRead8(&buffer1, max44009_address, REG_LOWER_THRESHOLD)) && + (I2cValidRead8(&buffer2, max44009_address, REG_THRESHOLD_TIMER))) { + //snprintf(log_data, sizeof(log_data), "MAX44009 %x: %x, %x", max44009_address, (int)buffer1, (int)buffer2); + //AddLog(LOG_LEVEL_DEBUG_MORE); + if ((0x00 == buffer1) && + (0xFF == buffer2)) { + + // looks like a MAX44009, try to initialize + + Wire.beginTransmission(max44009_address); + + // select configuration register and set mode + Wire.write(REG_CONFIG); + Wire.write(MAX44009_CONTINUOUS_AUTO_MODE); + if (0 == Wire.endTransmission()) { + max44009_found = 1; + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, max44009_types, max44009_address); + break; + } + } + } + } +} + +void Max4409EverySecond(void) +{ + if (max44009_found) { + Max4409Read_lum(); + } +} + +void Max4409Show(bool json) +{ + char illum_str[8]; + + if (max44009_valid) { + + /* convert illuminance to string with suitable accuracy */ + + uint8_t prec = 0; + if (10 > max44009_illuminance ) { + prec = 3; + } else if (100 > max44009_illuminance) { + prec = 2; + } else if (1000 > max44009_illuminance) { + prec = 1; + } + dtostrf(max44009_illuminance, sizeof(illum_str) -1, prec, illum_str); + + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), + PSTR("%s,\"%s\":{\"" D_JSON_ILLUMINANCE "\":%s}"), + mqtt_data, max44009_types, illum_str); +#ifdef USE_DOMOTICZ + if (0 == tele_period) { + DomoticzSensor(DZ_ILLUMINANCE, illum_str); + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + // show integer value for lx on web-server + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ILLUMINANCE, + mqtt_data, max44009_types, (int)max44009_illuminance); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns41(uint8_t function) +{ + bool result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_INIT: + Max4409Detect(); + break; + case FUNC_EVERY_SECOND: + Max4409EverySecond(); + break; + case FUNC_JSON_APPEND: + Max4409Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_APPEND: + Max4409Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_MAX44009 +#endif // USE_I2C diff --git a/sonoff/xsns_42_scd30.ino b/sonoff/xsns_42_scd30.ino new file mode 100644 index 000000000..c62df4d25 --- /dev/null +++ b/sonoff/xsns_42_scd30.ino @@ -0,0 +1,494 @@ +/* + xsns_42_scd30.ino - SC30 CO2 sensor support for Sonoff-Tasmota + + Copyright (C) 2019 Frogmore42 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ +#ifdef USE_I2C +#ifdef USE_SCD30 + +#define XSNS_42 42 + +#define SCD30_MAX_MISSED_READS 3 +#define SONOFF_SCD30_STATE_NO_ERROR 0 +#define SONOFF_SCD30_STATE_ERROR_DATA_CRC 1 +#define SONOFF_SCD30_STATE_ERROR_READ_MEAS 2 +#define SONOFF_SCD30_STATE_ERROR_SOFT_RESET 3 +#define SONOFF_SCD30_STATE_ERROR_I2C_RESET 4 +#define SONOFF_SCD30_STATE_ERROR_UNKNOWN 5 + +#include "Arduino.h" +#include + +#define D_CMND_SCD30 "SCD30" + +const char S_JSON_SCD30_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_SCD30 "%s\":%d}"; +const char S_JSON_SCD30_COMMAND_NFW_VALUE[] PROGMEM = "{\"" D_CMND_SCD30 "%s\":%d.%d}"; +const char S_JSON_SCD30_COMMAND[] PROGMEM = "{\"" D_CMND_SCD30 "%s\"}"; +const char kSCD30_Commands[] PROGMEM = "Alt|Auto|Cal|FW|Int|Pres|TOff"; + +/*********************************************************************************************\ + * enumerationsines +\*********************************************************************************************/ + +enum SCD30_Commands { // commands useable in console or rules + CMND_SCD30_ALTITUDE, + CMND_SCD30_AUTOMODE, + CMND_SCD30_CALIBRATE, + CMND_SCD30_FW, + CMND_SCD30_INTERVAL, + CMND_SCD30_PRESSURE, + CMND_SCD30_TEMPOFFSET +}; + + + +FrogmoreScd30 scd30; + +bool scd30Found = false; +bool scd30IsDataValid = false; +int scd30ErrorState = SONOFF_SCD30_STATE_NO_ERROR; +uint16_t scd30Interval_sec; +int scd30Loop_count = 0; +int scd30DataNotAvailable_count = 0; +int scd30GoodMeas_count = 0; +int scd30Reset_count = 0; +int scd30CrcError_count = 0; +int scd30Co2Zero_count = 0; +int i2cReset_count = 0; +uint16_t scd30_CO2 = 0; +uint16_t scd30_CO2EAvg = 0; +float scd30_Humid = 0.0; +float scd30_Temp = 0.0; + +bool Scd30Init() +{ + int error; + bool i2c_flg = ((pin[GPIO_I2C_SCL] < 99) && (pin[GPIO_I2C_SDA] < 99)); + if (i2c_flg) + { + uint8_t major = 0; + uint8_t minor = 0; + uint16_t interval_sec; + scd30.begin(); + error = scd30.getFirmwareVersion(&major, &minor); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: did not find an SCD30: 0x%lX", error); + AddLog(LOG_LEVEL_DEBUG); +#endif + return false; + } + else + { +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: found an SCD30: FW v%d.%d", major, minor); + AddLog(LOG_LEVEL_INFO); +#endif + } + + error = scd30.getMeasurementInterval(&scd30Interval_sec); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: error getMeasurementInterval: 0x%lX", error); + AddLog(LOG_LEVEL_ERROR); +#endif + return false; + } + + error = scd30.beginMeasuring(); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "Error: Scd30BeginMeasuring: 0x%lX", error); + AddLog(LOG_LEVEL_ERROR); +#endif + return false; + } + + return true; + } +} + +// gets data from the sensor every 3 seconds or so to give the sensor time to gather new data +int Scd30Update() +{ + int error = 0; + int16_t delta = 0; + scd30Loop_count++; + + if (!scd30Found) + { + scd30Found = Scd30Init(); +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "Scd30Update: found: %d ", scd30Found); + AddLog(LOG_LEVEL_INFO); +#endif + if (!scd30Found) + { +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "Scd30Update: found: %d ", scd30Found); + AddLog(LOG_LEVEL_INFO); +#endif + return (ERROR_SCD30_NOT_FOUND_ERROR); + } + } + else + { + if (scd30Loop_count > (scd30Interval_sec - 1)) + { + switch (scd30ErrorState) + { + case SONOFF_SCD30_STATE_NO_ERROR: + { + error = scd30.readMeasurement(&scd30_CO2, &scd30_CO2EAvg, &scd30_Temp, &scd30_Humid); + switch (error) + { + case ERROR_SCD30_NO_ERROR: + scd30Loop_count = 0; + scd30IsDataValid = true; + scd30GoodMeas_count++; + break; + + case ERROR_SCD30_NO_DATA: + scd30DataNotAvailable_count++; + break; + + case ERROR_SCD30_CRC_ERROR: + scd30ErrorState = SONOFF_SCD30_STATE_ERROR_DATA_CRC; + scd30CrcError_count++; +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: CRC error, CRC error: %ld, CO2 zero: %ld, good: %ld, no data: %ld, sc30_reset: %ld, i2c_reset: %ld", scd30CrcError_count, scd30Co2Zero_count, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); + AddLog(LOG_LEVEL_ERROR); +#endif + break; + + case ERROR_SCD30_CO2_ZERO: + scd30Co2Zero_count++; +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: CO2 zero, CRC error: %ld, CO2 zero: %ld, good: %ld, no data: %ld, sc30_reset: %ld, i2c_reset: %ld", scd30CrcError_count, scd30Co2Zero_count, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); + AddLog(LOG_LEVEL_ERROR); +#endif + break; + + default: + { + scd30ErrorState = SONOFF_SCD30_STATE_ERROR_READ_MEAS; +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: Update: ReadMeasurement error: 0x%lX, counter: %ld", error, scd30Loop_count); + AddLog(LOG_LEVEL_ERROR); +#endif + return (error); + } + break; + } + } + break; + + case SONOFF_SCD30_STATE_ERROR_DATA_CRC: + { + //scd30IsDataValid = false; +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: in error state: %d, good: %ld, no data: %ld, sc30 reset: %ld, i2c reset: %ld", scd30ErrorState, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); + AddLog(LOG_LEVEL_ERROR); + snprintf_P(log_data, sizeof(log_data), "SCD30: got CRC error, try again, counter: %ld", scd30Loop_count); + AddLog(LOG_LEVEL_ERROR); +#endif + scd30ErrorState = ERROR_SCD30_NO_ERROR; + } + break; + + case SONOFF_SCD30_STATE_ERROR_READ_MEAS: + { + //scd30IsDataValid = false; +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: in error state: %d, good: %ld, no data: %ld, sc30 reset: %ld, i2c reset: %ld", scd30ErrorState, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); + AddLog(LOG_LEVEL_ERROR); + snprintf_P(log_data, sizeof(log_data), "SCD30: not answering, sending soft reset, counter: %ld", scd30Loop_count); + AddLog(LOG_LEVEL_ERROR); +#endif + scd30Reset_count++; + error = scd30.softReset(); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: resetting got error: 0x%lX", error); + AddLog(LOG_LEVEL_ERROR); +#endif + error >>= 8; + if (error == 4) + { + scd30ErrorState = SONOFF_SCD30_STATE_ERROR_SOFT_RESET; + } + else + { + scd30ErrorState = SONOFF_SCD30_STATE_ERROR_UNKNOWN; + } + } + else + { + scd30ErrorState = ERROR_SCD30_NO_ERROR; + } + } + break; + + case SONOFF_SCD30_STATE_ERROR_SOFT_RESET: + { + //scd30IsDataValid = false; +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: in error state: %d, good: %ld, no data: %ld, sc30 reset: %ld, i2c reset: %ld", scd30ErrorState, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); + AddLog(LOG_LEVEL_ERROR); + snprintf_P(log_data, sizeof(log_data), "SCD30: clearing i2c bus"); + AddLog(LOG_LEVEL_ERROR); +#endif + i2cReset_count++; + error = scd30.clearI2CBus(); + if (error) + { + scd30ErrorState = SONOFF_SCD30_STATE_ERROR_I2C_RESET; +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: error clearing i2c bus: 0x%lX", error); + AddLog(LOG_LEVEL_ERROR); +#endif + } + else + { + scd30ErrorState = ERROR_SCD30_NO_ERROR; + } + } + break; + + default: + { + //scd30IsDataValid = false; +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: unknown error state: 0x%lX", scd30ErrorState); + AddLog(LOG_LEVEL_ERROR); +#endif + scd30ErrorState = SONOFF_SCD30_STATE_ERROR_SOFT_RESET; // try again + } + } + + if (scd30Loop_count > (SCD30_MAX_MISSED_READS * scd30Interval_sec)) + { + scd30IsDataValid = false; + } + } + } + return (ERROR_SCD30_NO_ERROR); +} + + +int Scd30GetCommand(int command_code, uint16_t *pvalue) +{ + switch (command_code) + { + case CMND_SCD30_ALTITUDE: + return scd30.getAltitudeCompensation(pvalue); + break; + + case CMND_SCD30_AUTOMODE: + return scd30.getCalibrationType(pvalue); + break; + + case CMND_SCD30_CALIBRATE: + return scd30.getForcedRecalibrationFactor(pvalue); + break; + + case CMND_SCD30_INTERVAL: + return scd30.getMeasurementInterval(pvalue); + break; + + case CMND_SCD30_PRESSURE: + return scd30.getAmbientPressure(pvalue); + break; + + case CMND_SCD30_TEMPOFFSET: + return scd30.getTemperatureOffset(pvalue); + break; + + default: + // else for Unknown command + break; + } +} + +int Scd30SetCommand(int command_code, uint16_t value) +{ + switch (command_code) + { + case CMND_SCD30_ALTITUDE: + return scd30.setAltitudeCompensation(value); + break; + + case CMND_SCD30_AUTOMODE: + return scd30.setCalibrationType(value); + break; + + case CMND_SCD30_CALIBRATE: + return scd30.setForcedRecalibrationFactor(value); + break; + + case CMND_SCD30_INTERVAL: + { + int error = scd30.setMeasurementInterval(value); + if (!error) + { + scd30Interval_sec = value; + } + + return error; + } + break; + + case CMND_SCD30_PRESSURE: + return scd30.setAmbientPressure(value); + break; + + case CMND_SCD30_TEMPOFFSET: + return scd30.setTemperatureOffset(value); + break; + + default: + // else for Unknown command + break; + } +} +/*********************************************************************************************\ + * Command Sensor92 +\*********************************************************************************************/ + +bool Scd30CommandSensor() +{ + char command[CMDSZ]; + bool serviced = true; + uint8_t prefix_len = strlen(D_CMND_SCD30); + + if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_SCD30), prefix_len)) { // prefix + int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + prefix_len, kSCD30_Commands); + + switch (command_code) { + case CMND_SCD30_ALTITUDE: + case CMND_SCD30_AUTOMODE: + case CMND_SCD30_CALIBRATE: + case CMND_SCD30_INTERVAL: + case CMND_SCD30_PRESSURE: + case CMND_SCD30_TEMPOFFSET: + { + uint16_t value = 0; + if (XdrvMailbox.data_len > 0) + { + value = XdrvMailbox.payload16; + Scd30SetCommand(command_code, value); + } + else + { + Scd30GetCommand(command_code, &value); + } + + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SCD30_COMMAND_NVALUE, command, value); + } + break; + + case CMND_SCD30_FW: + { + uint8_t major = 0; + uint8_t minor = 0; + int error; + error = scd30.getFirmwareVersion(&major, &minor); + if (error) + { +#ifdef SCD30_DEBUG + snprintf_P(log_data, sizeof(log_data), "SCD30: error getting FW version: 0x%lX", error); + AddLog(LOG_LEVEL_ERROR); +#endif + serviced = false; + } + else + { + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SCD30_COMMAND_NFW_VALUE, command, major, minor); + } + } + break; + + default: + // else for Unknown command + serviced = false; + break; + } + } + return serviced; +} + +void Scd30Show(bool json) +{ + char humidity[10]; + char temperature[10]; + + if (scd30Found && scd30IsDataValid) + { + dtostrfd(scd30_Humid, Settings.flag2.humidity_resolution, humidity); + dtostrfd(ConvertTemp(scd30_Temp), Settings.flag2.temperature_resolution, temperature); + if (json) { + //snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SCD30\":{\"" D_JSON_CO2 "\":%d,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s}"), mqtt_data, scd30_CO2, temperature, humidity); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SCD30\":{\"" D_JSON_CO2 "\":%d,\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s}"), mqtt_data, scd30_CO2, scd30_CO2EAvg, temperature, humidity); +#ifdef USE_DOMOTICZ + if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, scd30_CO2); +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CO2EAVG, mqtt_data, "SCD30", scd30_CO2EAvg); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CO2, mqtt_data, "SCD30", scd30_CO2); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, "SCD30", temperature, TempUnit()); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, "SCD30", humidity); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns42(byte function) +{ + bool result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_EVERY_SECOND: + Scd30Update(); + break; + case FUNC_COMMAND: + result = Scd30CommandSensor(); + break; + case FUNC_JSON_APPEND: + Scd30Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_APPEND: + Scd30Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_SCD30 +#endif // USE_I2C diff --git a/sonoff/xsns_interface.ino b/sonoff/xsns_interface.ino index d39995be9..fdb947bfb 100644 --- a/sonoff/xsns_interface.ino +++ b/sonoff/xsns_interface.ino @@ -1,7 +1,7 @@ /* xsns_interface.ino - Sensor interface support for Sonoff-Tasmota - Copyright (C) 2018 Theo Arends inspired by ESPEasy + Copyright (C) 2019 Theo Arends inspired by ESPEasy This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,9 +18,9 @@ */ #ifdef XFUNC_PTR_IN_ROM -boolean (* const xsns_func_ptr[])(byte) PROGMEM = { // Sensor Function Pointers for simple implementation of sensors +bool (* const xsns_func_ptr[])(uint8_t) PROGMEM = { // Sensor Function Pointers for simple implementation of sensors #else -boolean (* const xsns_func_ptr[])(byte) = { // Sensor Function Pointers for simple implementation of sensors +bool (* const xsns_func_ptr[])(uint8_t) = { // Sensor Function Pointers for simple implementation of sensors #endif #ifdef XSNS_01 @@ -268,7 +268,7 @@ const uint8_t xsns_present = sizeof(xsns_func_ptr) / sizeof(xsns_func_ptr[0]); * Function call to all xsns \*********************************************************************************************/ -boolean XsnsNextCall(byte Function, uint8_t &xsns_index) +bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index) { xsns_index++; if (xsns_index == xsns_present) { xsns_index = 0; } @@ -282,15 +282,15 @@ boolean XsnsNextCall(byte Function, uint8_t &xsns_index) return xsns_func_ptr[xsns_index](Function); } -boolean XsnsCall(byte Function) +bool XsnsCall(uint8_t Function) { - boolean result = false; + bool result = false; #ifdef PROFILE_XSNS_EVERY_SECOND uint32_t profile_start_millis = millis(); #endif // PROFILE_XSNS_EVERY_SECOND - for (byte x = 0; x < xsns_present; x++) { + for (uint8_t x = 0; x < xsns_present; x++) { #ifdef USE_DEBUG_DRIVER if (XsnsEnabled(x)) { #endif @@ -305,13 +305,16 @@ boolean XsnsCall(byte Function) uint32_t profile_millis = millis() - profile_start_millis; if (profile_millis) { if (FUNC_EVERY_SECOND == Function) { - snprintf_P(log_data, sizeof(log_data), PSTR("PRF: At %08u XsnsCall %d to Sensor %d took %u mS"), uptime, Function, x, profile_millis); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PRF: At %08u XsnsCall %d to Sensor %d took %u mS"), uptime, Function, x, profile_millis); } } #endif // PROFILE_XSNS_SENSOR_EVERY_SECOND - if (result) break; + if (result && ((FUNC_COMMAND == Function) || + (FUNC_COMMAND_SENSOR == Function) + )) { + break; + } #ifdef USE_DEBUG_DRIVER } #endif @@ -321,8 +324,7 @@ boolean XsnsCall(byte Function) uint32_t profile_millis = millis() - profile_start_millis; if (profile_millis) { if (FUNC_EVERY_SECOND == Function) { - snprintf_P(log_data, sizeof(log_data), PSTR("PRF: At %08u XsnsCall %d took %u mS"), uptime, Function, profile_millis); - AddLog(LOG_LEVEL_DEBUG); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PRF: At %08u XsnsCall %d took %u mS"), uptime, Function, profile_millis); } } #endif // PROFILE_XSNS_EVERY_SECOND diff --git a/sonoff/zzzz_debug.ino b/sonoff/zzzz_debug.ino new file mode 100644 index 000000000..e0618b6ab --- /dev/null +++ b/sonoff/zzzz_debug.ino @@ -0,0 +1,309 @@ +/* + zzzz_debug.ino - debug support for Sonoff-Tasmota + + Copyright (C) 2019 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_DEBUG_DRIVER +/*********************************************************************************************\ + * Virtual debugging support - Part 2 + * + * Needs to be the last alphabetical file due to DEFINE compile order +\*********************************************************************************************/ + +/*********************************************************************************************\ + * Xsns available list +\*********************************************************************************************/ + +#ifdef XFUNC_PTR_IN_ROM +const uint8_t kXsnsList[] PROGMEM = { +#else +const uint8_t kXsnsList[] = { +#endif + +#ifdef XSNS_01 + XSNS_01, +#endif + +#ifdef XSNS_02 + XSNS_02, +#endif + +#ifdef XSNS_03 + XSNS_03, +#endif + +#ifdef XSNS_04 + XSNS_04, +#endif + +#ifdef XSNS_05 + XSNS_05, +#endif + +#ifdef XSNS_06 + XSNS_06, +#endif + +#ifdef XSNS_07 + XSNS_07, +#endif + +#ifdef XSNS_08 + XSNS_08, +#endif + +#ifdef XSNS_09 + XSNS_09, +#endif + +#ifdef XSNS_10 + XSNS_10, +#endif + +#ifdef XSNS_11 + XSNS_11, +#endif + +#ifdef XSNS_12 + XSNS_12, +#endif + +#ifdef XSNS_13 + XSNS_13, +#endif + +#ifdef XSNS_14 + XSNS_14, +#endif + +#ifdef XSNS_15 + XSNS_15, +#endif + +#ifdef XSNS_16 + XSNS_16, +#endif + +#ifdef XSNS_17 + XSNS_17, +#endif + +#ifdef XSNS_18 + XSNS_18, +#endif + +#ifdef XSNS_19 + XSNS_19, +#endif + +#ifdef XSNS_20 + XSNS_20, +#endif + +#ifdef XSNS_21 + XSNS_21, +#endif + +#ifdef XSNS_22 + XSNS_22, +#endif + +#ifdef XSNS_23 + XSNS_23, +#endif + +#ifdef XSNS_24 + XSNS_24, +#endif + +#ifdef XSNS_25 + XSNS_25, +#endif + +#ifdef XSNS_26 + XSNS_26, +#endif + +#ifdef XSNS_27 + XSNS_27, +#endif + +#ifdef XSNS_28 + XSNS_28, +#endif + +#ifdef XSNS_29 + XSNS_29, +#endif + +#ifdef XSNS_30 + XSNS_30, +#endif + +#ifdef XSNS_31 + XSNS_31, +#endif + +#ifdef XSNS_32 + XSNS_32, +#endif + +#ifdef XSNS_33 + XSNS_33, +#endif + +#ifdef XSNS_34 + XSNS_34, +#endif + +#ifdef XSNS_35 + XSNS_35, +#endif + +#ifdef XSNS_36 + XSNS_36, +#endif + +#ifdef XSNS_37 + XSNS_37, +#endif + +#ifdef XSNS_38 + XSNS_38, +#endif + +#ifdef XSNS_39 + XSNS_39, +#endif + +#ifdef XSNS_40 + XSNS_40, +#endif + +#ifdef XSNS_41 + XSNS_41, +#endif + +#ifdef XSNS_42 + XSNS_42, +#endif + +#ifdef XSNS_43 + XSNS_43, +#endif + +#ifdef XSNS_44 + XSNS_44, +#endif + +#ifdef XSNS_45 + XSNS_45, +#endif + +#ifdef XSNS_46 + XSNS_46, +#endif + +#ifdef XSNS_47 + XSNS_47, +#endif + +#ifdef XSNS_48 + XSNS_48, +#endif + +#ifdef XSNS_49 + XSNS_49, +#endif + +#ifdef XSNS_50 + XSNS_50, +#endif + +// Optional user defined sensors in range 91 - 99 + +#ifdef XSNS_91 + XSNS_91, +#endif + +#ifdef XSNS_92 + XSNS_92, +#endif + +#ifdef XSNS_93 + XSNS_93, +#endif + +#ifdef XSNS_94 + XSNS_94, +#endif + +#ifdef XSNS_95 + XSNS_95 +#endif +}; + +/*********************************************************************************************\ + * Xsns sensor control +\*********************************************************************************************/ + +bool XsnsEnabled(uint8_t sns_index) +{ + if (sns_index < sizeof(kXsnsList)) { +#ifdef XFUNC_PTR_IN_ROM + uint8_t index = pgm_read_byte(kXsnsList + sns_index); +#else + uint8_t index = kXsnsList[sns_index]; +#endif + return bitRead(Settings.sensors[index / 32], index % 32); + } + return true; +} + +bool XsnsPresent(uint8_t sns_index) +{ + uint8_t index = 0; + for (uint8_t i = 0; i < sizeof(kXsnsList); i++) { +#ifdef XFUNC_PTR_IN_ROM + index = pgm_read_byte(kXsnsList + i); +#else + index = kXsnsList[i]; +#endif + if (index == sns_index) { return true; } + } + return false; +} + +String XsnsGetSensors(void) +{ + char state[2] = { 0 }; + + String data = F("["); + for (uint8_t i = 0; i < MAX_XSNS_DRIVERS; i++) { + if (i && (!(i % 16))) { data += F(","); } + if (!(i % 16)) { data += F("\""); } + state[0] = '-'; + if (XsnsPresent(i)) { state[0] = bitRead(Settings.sensors[i / 32], i % 32) ? '1' : '0'; } + data += String(state); + if (i && (!((i +1) % 16))) { data += F("\""); } + } + data += F("]"); + + return data; +} + +#endif // USE_DEBUG_DRIVER \ No newline at end of file diff --git a/tools/decode-config.html b/tools/decode-config.html index dd24495b7..68968f00d 100644 --- a/tools/decode-config.html +++ b/tools/decode-config.html @@ -1,10 +1,10 @@

decode-config.py

decode-config.py is able to backup and restore Sonoff-Tasmota configuration.

-

In contrast to the Tasmota build-in "Backup/Restore Configuration" function,

+

In comparison with the Tasmota build-in "Backup/Restore Configuration" function decode-config.py

    -
  • decode-config.py uses human readable and editable JSON-format for backup/restore,
  • -
  • decode-config.py can restore previous backuped and changed JSON-format files,
  • -
  • decode-config.py is able to create Tasmota commands based on given configuration
  • +
  • uses human readable and editable JSON-format for backup/restore,
  • +
  • can restore previously backup and changed JSON-format files,
  • +
  • is able to create Tasmota compatible command list with related config parameter

Comparing backup files created by decode-config.py and *.dmp files created by Tasmota "Backup/Restore Configuration":

@@ -38,7 +38,7 @@
-

decode-config.py is able to handle Tasmota configurations for release version starting from 5.10.0 up to now.

+

decode-config.py is compatible with Tasmota version from v5.10.0 up to now.

Content

Prerequisite

    -
  • Python)
    This program is written in Python) so you need to install a python environment (for details see Python Setup and Usage)

    +
  • Python)
    This program is written in Python) so you need to install a working python environment (for details see Python Setup and Usage)

  • Sonoff-Tasmota Firmware with Web-Server enabled:

      -
    • To backup or restore configurations from/to a Sonoff-Tasmota device you need a firmare with enabled web-server in admin mode (command WebServer 2).
    • +
    • To backup or restore configurations from or to a Sonoff-Tasmota device you need a firmare with enabled web-server in admin mode (command WebServer 2). This is the Tasmota default.
    • If using your own compiled firmware be aware to enable the web-server (#define USE_WEBSERVER and #define WEB_SERVER 2).
  • @@ -89,19 +89,20 @@

    .dmp Format

    Configuration data as used by Tasmota "Backup/Restore Configuration" web interface.
    This format is binary and encrypted.

    .json Format

    -

    Configuration data in JSON-format.
    This format is decrypted, human readable and editable and can also be used for the --restore-file command.
    This file will becreated by decode-config.py using --backup-file with --backup-type json parameter (default).

    +

    Configuration data in JSON-format.
    This format is decrypted, human readable and editable and can also be used for the --restore-file parameter.
    This file will be created by decode-config.py using the --backup-file with --backup-type json parameter, this is the default.

    .bin Format

    -

    Configuration data in binary format.
    This format is binary decryptet, editable (e.g. using a hex editor) and can also be used for --restore-file command.
    It will be created by decode-config.py using --backup-file with --backup-type bin.
    Note:
    This file is 4 byte longer than an original .dmp file due to an prefix header at the beginning. The file data starting at address position 4 are containing the same as the struct SYSCFG from Tasmota settings.h in decrypted format.

    +

    Configuration data in binary format.
    This format is binary decryptet, editable (e.g. using a hex editor) and can also be used for --restore-file command.
    It will be created by decode-config.py using --backup-file with --backup-type bin.
    Note:
    The .bin file contains the same information as the original .dmp file from Tasmota "Backup/Restore Configuration" but it is decrpted and 4 byte longer than an original (it is a prefix header at the beginning). .bin file data starting at address 4 contains the same as the struct SYSCFG from Tasmota settings.h in decrypted format.

    File extensions

    -

    decode-config.py uses auto extension as default for backup filenames; you don't need to append extensions to your backup file, it will be selected based on --backup-type argument.
    If you want using your own extension use the --no-extension argument.

    +

    You don't need to append exensions for your file name as decode-config.py uses auto extension as default. The extension will be choose based on file contents and --backup-type parameter. +If you do not want using auto extensions use the --no-extension parameter.

    Usage

    -

    After download don't forget to set exec flag under linux with chmod +x decode-config.py or call the program using python decode-config.py....

    +

    After download don't forget to set the executable flag under linux with chmod +x decode-config.py or call the program using python decode-config.py....

    Basics

    At least pass a source where you want to read the configuration data from using -f <filename> or -d <host>:

    The source can be either

      -
    • a Tasmota device hostname or IP by passing it using the -d <host> arg
    • -
    • or a previously stored Tasmota *.dmp configuration file by passing the filename using -f <filename> arg
    • +
    • a Tasmota device hostname or IP using the -d <host> parameter
    • +
    • a Tasmota *.dmp configuration file using -f <filename> parameter

    Example:

    decode-config.py -d sonoff-4281
    @@ -119,22 +120,22 @@
       ]
     }
     

    Save backup file

    -

    To save the output as backup file --backup-file <filename>, you can use placeholder for Version, Friendlyname and Hostname:

    +

    To save the output as backup file use --backup-file <filename>, you can use placeholder for Version, Friendlyname and Hostname:

    decode-config.py -d sonoff-4281 --backup-file Config_@f_@v
     

    If you have setup a WebPassword within Tasmota, use

    decode-config.py -d sonoff-4281 -p <yourpassword> --backup-file Config_@f_@v
    -

    will create a file like Config_Sonoff_x.x.x.json. Because it is in JSON format, you can read and edit the file with any raw text editor.

    +

    will create a file like Config_Sonoff_6.4.0.json (the part Sonoff and 6.4.0 will choosen related to your device configuration). Because the default backup file format is JSON, you can read and change it with any raw text editor.

    Restore backup file

    -

    Reading back a saved (and possible changed) backup file use the --restore-file <filename> arg. This will read the (changed) configuration data from this file and send it back to the source device or filename.

    +

    Reading back a saved (and possible changed) backup file use the --restore-file <filename> parameter. This will read the (changed) configuration data from this file and send it back to the source device or filename.

    To restore the previously save backup file Config_Sonoff_6.2.1.json to device sonoff-4281 use:

    decode-config.py -d sonoff-4281 --restore-file Config_Sonoff_6.2.1.json
     

    with password set by WebPassword:

    decode-config.py -d sonoff-4281 -p <yourpassword> --restore-file Config_Sonoff_6.2.1.json
     

    Output to screen

    -

    Output to screen is default enabled when calling the program with a source arg but without a backup or restore arg.

    -

    --output arg will force screen output even if you use backup or restore arg.

    +

    To force screen output use the --output parameter.

    +

    Output to screen is default enabled when calling the program with a source parameter (-f or -d) but without any backup or restore parameter.

    JSON output

    -

    The default output format is JSON. You can force JSON output with --output-format json arg.

    +

    The default output format is JSON. You can force JSON output using the --output-format json parameter.

    Example:

    decode-config.py -d sonoff-4281 -c my.conf -x Wifi --output-format json
     
    diff --git a/tools/decode-config.md b/tools/decode-config.md
    index 97978114a..ca70d36e9 100644
    --- a/tools/decode-config.md
    +++ b/tools/decode-config.md
    @@ -1,10 +1,10 @@
     # decode-config.py
     _decode-config.py_ is able to backup and restore Sonoff-Tasmota configuration.
     
    -In contrast to the Tasmota build-in "Backup/Restore Configuration" function,
    -* _decode-config.py_ uses human readable and editable [JSON](http://www.json.org/)-format for backup/restore,
    -* _decode-config.py_ can restore previous backuped and changed [JSON](http://www.json.org/)-format files,
    -* _decode-config.py_ is able to create Tasmota commands based on given configuration
    +In comparison with the Tasmota build-in "Backup/Restore Configuration" function _decode-config.py_
    +* uses human readable and editable [JSON](http://www.json.org/)-format for backup/restore,
    +* can restore previously backup and changed [JSON](http://www.json.org/)-format files,
    +* is able to create Tasmota compatible command list with related config parameter
     
     Comparing backup files created by *decode-config.py* and *.dmp files created by Tasmota "Backup/Restore Configuration":  
     
    @@ -15,7 +15,7 @@ Comparing backup files created by *decode-config.py* and *.dmp files created by
     | Simply editable         |               Yes               |                  No                 |
     | Simply batch processing |               Yes               |                  No                 |
     
    -_decode-config.py_ is able to handle Tasmota configurations for release version starting from 5.10.0 up to now.
    +_decode-config.py_ is compatible with Tasmota version from v5.10.0 up to now.
     
     # Content
     * [Prerequisite](decode-config.md#prerequisite)
    @@ -42,10 +42,10 @@ _decode-config.py_ is able to handle Tasmota configurations for release version
     
     ## Prerequisite
     * [Python](https://en.wikipedia.org/wiki/Python_(programming_language))  
    -  This program is written in [Python](https://en.wikipedia.org/wiki/Python_(programming_language)) so you need to install a python environment (for details see [Python Setup and Usage](https://docs.python.org/2.7/using/index.html))
    +  This program is written in [Python](https://en.wikipedia.org/wiki/Python_(programming_language)) so you need to install a working python environment (for details see [Python Setup and Usage](https://docs.python.org/2.7/using/index.html))
     
     * [Sonoff-Tasmota](https://github.com/arendst/Sonoff-Tasmota) [Firmware](https://github.com/arendst/Sonoff-Tasmota/releases) with Web-Server enabled:
    -  * To backup or restore configurations from/to a Sonoff-Tasmota device you need a firmare with enabled web-server in admin mode (command [WebServer 2](https://github.com/arendst/Sonoff-Tasmota/wiki/Commands#wifi)).
    +  * To backup or restore configurations from or to a Sonoff-Tasmota device you need a firmare with enabled web-server in admin mode (command [WebServer 2](https://github.com/arendst/Sonoff-Tasmota/wiki/Commands#wifi)). This is the Tasmota default.
       * If using your own compiled firmware be aware to enable the web-server (`#define USE_WEBSERVER` and `#define WEB_SERVER 2`).
     
     ## File Types
    @@ -55,28 +55,28 @@ Configuration data as used by Tasmota "Backup/Restore Configuration" web interfa
     This format is binary and encrypted.
     ### .json Format
     Configuration data in [JSON](http://www.json.org/)-format.  
    -This format is decrypted, human readable and editable and can also be used for the `--restore-file` command.  
    -This file will becreated by _decode-config.py_ using `--backup-file` with `--backup-type json` parameter (default).
    +This format is decrypted, human readable and editable and can also be used for the `--restore-file` parameter.  
    +This file will be created by _decode-config.py_ using the `--backup-file` with `--backup-type json` parameter, this is the default.
     ### .bin Format
     Configuration data in binary format.  
     This format is binary decryptet, editable (e.g. using a hex editor) and can also be used for `--restore-file` command.  
     It will be created by _decode-config.py_ using `--backup-file` with `--backup-type bin`.  
     Note:  
    -This file is 4 byte longer than an original .dmp file due to an prefix header at the beginning. The file data starting at address position 4 are containing the same as the **struct SYSCFG** from Tasmota [settings.h](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/settings.h) in decrypted format.
    +The .bin file contains the same information as the original .dmp file from Tasmota "Backup/Restore Configuration" but it is decrpted and  4 byte longer than an original (it is a prefix header at the beginning). .bin file data starting at address 4 contains the same as the **struct SYSCFG** from Tasmota [settings.h](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/settings.h) in decrypted format.
     
     #### File extensions
    -_decode-config.py_ uses auto extension as default for backup filenames; you don't need to append extensions to your backup file, it will be selected based on `--backup-type` argument.  
    -If you want using your own extension use the `--no-extension` argument.
    +You don't need to append exensions for your file name as _decode-config.py_ uses auto extension as default. The extension will be choose based on file contents and `--backup-type` parameter.
    +If you do not want using auto extensions use the `--no-extension` parameter.
     
     ## Usage
    -After download don't forget to set exec flag under linux with `chmod +x decode-config.py` or call the program using `python decode-config.py...`.
    +After download don't forget to set the executable flag under linux with `chmod +x decode-config.py` or call the program using `python decode-config.py...`.
     
     ### Basics
     At least pass a source where you want to read the configuration data from using `-f ` or `-d `:
     
     The source can be either 
    -* a Tasmota device hostname or IP by passing it using the `-d ` arg
    -* or a previously stored Tasmota `*.dmp` configuration file by passing the filename using `-f ` arg
    +* a Tasmota device hostname or IP using the `-d ` parameter
    +* a Tasmota `*.dmp` configuration file using `-f ` parameter
     
     Example:  
     
    @@ -99,7 +99,7 @@ will output a human readable configuration in [JSON](http://www.json.org/)-forma
     
     
     ### Save backup file
    -To save the output as backup file `--backup-file `, you can use placeholder for Version, Friendlyname and Hostname:  
    +To save the output as backup file use `--backup-file `, you can use placeholder for Version, Friendlyname and Hostname:  
     
         decode-config.py -d sonoff-4281 --backup-file Config_@f_@v
         
    @@ -107,10 +107,10 @@ If you have setup a WebPassword within Tasmota, use
     
         decode-config.py -d sonoff-4281 -p  --backup-file Config_@f_@v
     
    -will create a file like `Config_Sonoff_x.x.x.json`. Because it is in JSON format, you can read and edit the file with any raw text editor.
    +will create a file like `Config_Sonoff_6.4.0.json` (the part `Sonoff` and `6.4.0` will choosen related to your device configuration). Because the default backup file format is JSON, you can read and change it with any raw text editor.
     
     ### Restore backup file
    -Reading back a saved (and possible changed) backup file use the `--restore-file ` arg. This will read the (changed) configuration data from this file and send it back to the source device or filename.
    +Reading back a saved (and possible changed) backup file use the `--restore-file ` parameter. This will read the (changed) configuration data from this file and send it back to the source device or filename.
     
     To restore the previously save backup file `Config_Sonoff_6.2.1.json` to device `sonoff-4281` use:  
     
    @@ -121,12 +121,12 @@ with password set by WebPassword:
         decode-config.py -d sonoff-4281 -p  --restore-file Config_Sonoff_6.2.1.json
     
     ### Output to screen
    -Output to screen is default enabled when calling the program with a source arg but without a backup or restore arg.
    +To force screen output use the `--output` parameter.
     
    -`--output` arg will force screen output even if you use backup or restore arg.
    +Output to screen is default enabled when calling the program with a source parameter (-f or -d) but without any backup or restore parameter.
     
     #### JSON output
    -The default output format is JSON. You can force JSON output with `--output-format json` arg.
    +The default output format is [JSON](decode-config.md#-json-format). You can force JSON output using the `--output-format json` parameter.
     
     Example:
     
    diff --git a/tools/decode-config.py b/tools/decode-config.py
    index d1daccf22..0b76ece85 100644
    --- a/tools/decode-config.py
    +++ b/tools/decode-config.py
    @@ -1,11 +1,11 @@
     #!/usr/bin/env python
     # -*- coding: utf-8 -*-
    -VER = '2.1.0015'
    +VER = '2.1.0021'
     
     """
         decode-config.py - Backup/Restore Sonoff-Tasmota configuration data
     
    -    Copyright (C) 2018 Norbert Richter 
    +    Copyright (C) 2019 Norbert Richter 
     
         This program is free software: you can redistribute it and/or modify
         it under the terms of the GNU General Public License as published by
    @@ -814,7 +814,73 @@ Setting_6_3_0_16['flag3'][0].update ({
     Setting_6_4_0_2 = copy.deepcopy(Setting_6_3_0_16)
     Setting_6_4_0_2['flag3'][0].pop('hass_short_discovery_msg',None)
     # ======================================================================
    +Setting_6_4_1_4 = copy.deepcopy(Setting_6_4_0_2)
    +Setting_6_4_1_4['flag3'][0].update ({
    +        'mdns_enabled':             (' 0 and len(obj["StatusLOG"]["SetOption"]) == 2: # old firmware: array consisted only of SetOptions 0..31 and resolution
    +                    break
     
    -                option = obj["StatusLOG"]["SetOption"][o]
    -                i_option = int(option,16)
    -                for i in range(len(a_setoption[f])):
    -                    if (a_setoption[f][i]):
    -                        state = (i_option >> i) & 1
    -                        options.append(str("{0:2d} ({1}) {2}".format(i + p, a_on_off[state], a_setoption[f][i])))
    +                if r == 1:
    +                    if len(register) == 8:            # pre 6.1.1.14: array consisted of SetOptions 0..31, resolution, and SetOptions 50..81
    +                        i += 18                       # adjust option index and skip 2nd register
    +                        continue
    +
    +                    elif len(register) == 36:         # 6.1.1.14: array consists of SetOptions 0..31, SetOptions 32..49, and SetOptions 50..81
    +                        split_register = [int(register[opt*2:opt*2+2],16) for opt in range(18)] # split register into 18 values
    +
    +                        for opt_idx, option in enumerate(opt_group):
    +                            options.append(str("{0:2d} ({1:3d}) {2}".format(i, split_register[opt_idx], option)))
    +                            i += 1
    +
    +                if r in (0, 2): #registers 1 and 3 hold binary values
    +                    for opt_idx, option in enumerate(opt_group):
    +                        i_register = int(register,16)
    +                        state = (i_register >> opt_idx) & 1
    +                        options.append(str("{0:2d} ({1}) {2}".format(i, a_on_off[state], option)))
    +                        i += 1
     
                 print("\nOptions")
    -            for i in range(len(options)):
    -                print("  {}".format(options[i]))
    +            for o in options:
    +                print("  {}".format(o))
     
    -    if ("StatusMEM" in obj):
    -        if ("Features" in obj["StatusMEM"]):
    +    if "StatusMEM" in obj:
    +        if "Features" in obj["StatusMEM"]:
                 features = []
                 for f in range(5):
                     feature = obj["StatusMEM"]["Features"][f]
                     i_feature = int(feature,16)
    -                if (f == 0):
    +                if f == 0:
                         features.append(str("Language LCID = {}".format(i_feature & 0xFFFF)))
                     else:
                         for i in range(len(a_features[f -1])):
    -                        if ((i_feature >> i) & 1):
    +                        if (i_feature >> i) & 1:
                                 features.append(a_features[f -1][i])
     
                 features.sort()
                 print("\nFeatures")
    -            for i in range(len(features)):
    -                print("  {}".format(features[i]))
    +            for f in features:
    +                print("  {}".format(f))
     
     if __name__ == "__main__":
         try:
    diff --git a/tools/fw_server/fw-server.py b/tools/fw_server/fw-server.py
    index 536c76785..4d70f0f5e 100644
    --- a/tools/fw_server/fw-server.py
    +++ b/tools/fw_server/fw-server.py
    @@ -3,7 +3,7 @@
     """
     fw-server.py - firmware server for Sonoff-Tasmota OTA upgrade
     
    -Copyright (C) 2018 Gennaro Tortone
    +Copyright (C) 2019 Gennaro Tortone
     
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
    @@ -24,7 +24,8 @@ Requirements:
        - pip install netifaces flask
     
     Instructions:
    -    Copy Sonoff-Tasmota firmware binary files in 'fw' directory.
    +    Copy Sonoff-Tasmota firmware binary files in 'fw' directory or
    +    specify a different directory with -f parameter.
         A set of prebuilt files can be downloaded by Sonoff-Tasmota release page:
             https://github.com/arendst/Sonoff-Tasmota/releases
     
    @@ -51,7 +52,6 @@ from sys import exit
     from flask import Flask, send_file
     import netifaces as ni
     
    -
     usage = "usage: fw-server {-d | -i} arg"
     
     parser = OptionParser(usage)
    @@ -59,6 +59,8 @@ parser.add_option("-d", "--dev", action="store", type="string",
                       dest="netdev", default="eth0", help="network interface (default: eth0)")
     parser.add_option("-i", "--ip", action="store", type="string",
                       dest="ip", help="IP address to bind")
    +parser.add_option("-f", "--fwdir", action="store", type="string",
    +                  dest="fwdir", help="firmware absolute path directory (default: fw/ directory)")
     (options, args) = parser.parse_args()
     
     netip = None
    @@ -72,14 +74,24 @@ if options.ip is None:
     else:
         netip = options.ip
     
    +if options.fwdir is None:
    +    fwdir = os.path.dirname(os.path.realpath(__file__)) + "/fw/"
    +else:
    +    if os.path.isdir(options.fwdir):
    +        fwdir = options.fwdir
    +    else:
    +        print("E: directory " + options.fwdir + " not available")
    +        exit(1)
    +
    +print(" * Directory: " + fwdir)
     
     app = Flask(__name__)
     
     
     @app.route('/')
     def fw(filename):
    -    if os.path.exists("fw/" + str(filename)):
    -        return send_file("fw/" + str(filename),
    +    if os.path.exists(fwdir + str(filename)):
    +        return send_file(fwdir + str(filename),
                              attachment_filename=filename,
                              mimetype='application/octet-stream')